Rejig option chain schema to capture all contracts
							parent
							
								
									368f21d8d6
								
							
						
					
					
						commit
						d145a5a219
					
				|  | @ -60,6 +60,17 @@ async def stocks_quote( | |||
|         return results | ||||
| 
 | ||||
| 
 | ||||
| async def option_chain( | ||||
|     brokermod: ModuleType, | ||||
|     symbol: str, | ||||
| ) -> Dict[str, Dict[str, Dict[str, Any]]]: | ||||
|     """Return option chain (all expiries) for ``symbol``. | ||||
|     """ | ||||
|     async with brokermod.get_client() as client: | ||||
|         return await client.option_chains( | ||||
|             await client.get_contracts([symbol])) | ||||
| 
 | ||||
| 
 | ||||
| async def wait_for_network(net_func: Callable, sleep: int = 1) -> dict: | ||||
|     """Wait until the network comes back up. | ||||
|     """ | ||||
|  |  | |||
|  | @ -78,8 +78,7 @@ class _API: | |||
| 
 | ||||
|     async def option_quotes( | ||||
|         self, | ||||
|         ids: List[int], | ||||
|         expiry: str, | ||||
|         contracts: Dict[int, Dict[str, dict]], | ||||
|         option_ids: List[int] = [],  # if you don't want them all | ||||
|     ) -> dict: | ||||
|         "Retrieve option chain quotes for all option ids or by filter(s)." | ||||
|  | @ -87,14 +86,17 @@ class _API: | |||
|             { | ||||
|                 "underlyingId": int(symbol_id), | ||||
|                 "expiryDate": str(expiry), | ||||
|             } for symbol_id in ids | ||||
|             } | ||||
|             # every expiry per symbol id | ||||
|             for symbol_id, expiries in contracts.items() | ||||
|             for expiry in expiries | ||||
|         ] | ||||
| 
 | ||||
|         resp = await self._sess.post( | ||||
|             path=f'/markets/quotes/options', | ||||
|             json={'filters': filters, 'optionIds': option_ids} | ||||
|         ) | ||||
|         return resproc(resp, log) | ||||
|         return resproc(resp, log)['optionQuotes'] | ||||
| 
 | ||||
| 
 | ||||
| class Client: | ||||
|  | @ -263,37 +265,41 @@ class Client: | |||
|             item for item in contracts | ||||
|         } | ||||
| 
 | ||||
|     async def max_contract_expiry( | ||||
|     async def get_contracts( | ||||
|         self, | ||||
|         symbols: List[str] | ||||
|     ) -> Tuple[List[int], datetime]: | ||||
|         # {symbol_id: {dt_iso_contract: {strike_price: {contract_id: id}}}} | ||||
|     ) -> Dict[int, Dict[str, Dict[int, Any]]]: | ||||
|         """Look up all contracts for each symbol in ``symbols`` and return the | ||||
|         list of symbol ids as well as the maximum possible option contract | ||||
|         expiry out of the bunch. | ||||
|         of symbol ids to contracts by further organized by expiry and strike | ||||
|         price. | ||||
| 
 | ||||
|         This routine is a bit slow doing all the contract lookups (a request | ||||
|         per symbol) and thus the return values should be cached for use with | ||||
|         ``option_chains()``. | ||||
|         """ | ||||
|         batch = {} | ||||
|         by_id = {} | ||||
|         for symbol in symbols: | ||||
|             id, contracts = await self.option_contracts(symbol) | ||||
|             batch[id] = max(contracts) | ||||
| 
 | ||||
|         return tuple(batch.keys()), max(batch.values()) | ||||
|             by_id[id] = { | ||||
|                 dt.isoformat(timespec='microseconds'): { | ||||
|                     item['strikePrice']: item for item in | ||||
|                     byroot['chainPerRoot'][0]['chainPerStrikePrice'] | ||||
|                 } | ||||
|                 for dt, byroot in  sorted( | ||||
|                     # sort by datetime | ||||
|                     contracts.items(), key=lambda item: item[0] | ||||
|                 ) | ||||
|             } | ||||
|         return by_id | ||||
| 
 | ||||
|     async def option_chains( | ||||
|         self, | ||||
|         symbol_ids: List[int], | ||||
|         max_expiry: str  # iso format datetime (microseconds) | ||||
|         contracts: dict,  # see ``get_contracts()`` | ||||
|     ) -> Dict[str, Dict[str, Dict[str, Any]]]: | ||||
|         """Return option chain snap quote for each ticker in ``symbols``. | ||||
|         """ | ||||
|         quotes = (await self.api.option_quotes( | ||||
|             ids=symbol_ids, | ||||
|             expiry=max_expiry.isoformat(timespec='microseconds') | ||||
|         ))['optionQuotes'] | ||||
| 
 | ||||
|         quotes = await self.api.option_quotes(contracts) | ||||
|         batch = {} | ||||
|         for quote in quotes: | ||||
|             batch.setdefault(quote['underlying'], {})[quote['symbol']] = quote | ||||
|  | @ -416,6 +422,7 @@ async def quoter(client: Client, tickers: List[str]): | |||
|                         # `client.ensure_access()` locally thus blocking until | ||||
|                         # the user provides an API key on the "client side" | ||||
|                         await client.ensure_access(force_refresh=True) | ||||
|                         quotes_resp = await client.api.quotes(ids=ids) | ||||
|             else: | ||||
|                 raise | ||||
| 
 | ||||
|  | @ -449,7 +456,6 @@ _qt_keys = { | |||
|     'askPrice': 'ask', | ||||
|     'bidPrice': 'bid', | ||||
|     'lastTradeSize': 'size', | ||||
|     'lastTradeTime': ('time', datetime.fromisoformat), | ||||
|     'bidSize': 'bsize', | ||||
|     'askSize': 'asize', | ||||
|     'VWAP': ('VWAP', partial(round, ndigits=3)), | ||||
|  | @ -463,6 +469,7 @@ _qt_keys = { | |||
|     # 'low52w': 'low52w',  # put in info widget | ||||
|     # 'high52w': 'high52w', | ||||
|     # "lastTradePriceTrHrs": 7.99, | ||||
|     # 'lastTradeTime': ('time', datetime.fromisoformat), | ||||
|     # "lastTradeTick": "Equal", | ||||
|     # "symbolId": 3575753, | ||||
|     # "tier": "", | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue