|
7 | 7 | """ |
8 | 8 |
|
9 | 9 | import os |
| 10 | +from concurrent.futures import ThreadPoolExecutor, as_completed |
10 | 11 | from operator import itemgetter |
| 12 | +from json import JSONDecodeError |
| 13 | +from urllib.error import HTTPError |
11 | 14 |
|
12 | 15 | import requests |
13 | 16 | from foil.formatters import format_repr_info |
@@ -130,10 +133,14 @@ def get(self, ticker): |
130 | 133 | return self.get_results(ticker, response, retrieved_at) |
131 | 134 |
|
132 | 135 | def get_results(self, ticker, response, retrieved_at): |
133 | | - updated_at, timezone = self.transform_meta_data(response['Meta Data']) |
| 136 | + updated_at, timezone, is_intraday = self.transform_meta_data(response['Meta Data']) |
134 | 137 | records = self.transform_records(response[self.data_key]) |
135 | 138 | records = self.sort_records(self.convert_timezones(records, timezone)) |
136 | 139 |
|
| 140 | + # remove intraday record in daily series |
| 141 | + if is_intraday: |
| 142 | + records = records[0:-1] |
| 143 | + |
137 | 144 | return Results(ticker, records, timezone, |
138 | 145 | updated_at=updated_at, retrieved_at=retrieved_at) |
139 | 146 |
|
@@ -182,10 +189,23 @@ def transform_meta_data(self, response_meta): |
182 | 189 | tz_key = next( |
183 | 190 | key for key in response_meta if key.endswith('Time Zone') |
184 | 191 | ) |
185 | | - updated_at = self.parse_time(response_meta[refresh_key]) |
| 192 | + updated_at, is_intraday = self.parse_refresh_time( |
| 193 | + response_meta[refresh_key] |
| 194 | + ) |
186 | 195 | timezone = response_meta[tz_key] |
187 | 196 |
|
188 | | - return updated_at, timezone |
| 197 | + return updated_at, timezone, is_intraday |
| 198 | + |
| 199 | + def parse_refresh_time(self, dt): |
| 200 | + is_intraday = False |
| 201 | + |
| 202 | + try: |
| 203 | + updated_at = self.parse_time(dt) |
| 204 | + except ValueError: |
| 205 | + updated_at = self.parse_time(dt[0:10]) |
| 206 | + is_intraday = True |
| 207 | + |
| 208 | + return updated_at, is_intraday |
189 | 209 |
|
190 | 210 |
|
191 | 211 | class AdjustedPriceHistory(PriceHistory): |
@@ -236,12 +256,12 @@ def convert_timezones(self, records, timezone): |
236 | 256 | yield record |
237 | 257 |
|
238 | 258 | def transform_meta_data(self, response_meta): |
239 | | - updated_at, timezone = super().transform_meta_data(response_meta) |
| 259 | + updated_at, timezone, _ = super().transform_meta_data(response_meta) |
240 | 260 |
|
241 | 261 | if self.utc: |
242 | 262 | updated_at = convert_to_utc(updated_at, timezone) |
243 | 263 |
|
244 | | - return updated_at, timezone |
| 264 | + return updated_at, timezone, None |
245 | 265 |
|
246 | 266 |
|
247 | 267 | def get_time_series_function(period, adjusted=False): |
@@ -280,3 +300,21 @@ def filter_dividends(records): |
280 | 300 | for record in records: |
281 | 301 | if record[DIVIDEND] != 0: |
282 | 302 | yield record[DATE], record[DIVIDEND] |
| 303 | + |
| 304 | + |
| 305 | +def get_results(cls: PriceHistory, tickers: list, parameters: dict): |
| 306 | + """Return multiple results using threads.""" |
| 307 | + |
| 308 | + with ThreadPoolExecutor(max_workers=4) as executor: |
| 309 | + future_to_ticker = { |
| 310 | + executor.submit(cls(**parameters).get, ticker): ticker |
| 311 | + for ticker in tickers |
| 312 | + } |
| 313 | + |
| 314 | + for future in as_completed(future_to_ticker): |
| 315 | + ticker = future_to_ticker[future] |
| 316 | + |
| 317 | + try: |
| 318 | + yield ticker, future.result() |
| 319 | + except (HTTPError, JSONDecodeError, KeyError): |
| 320 | + pass |
0 commit comments