From b33be86b2fffa43d3171b38eab0cf37ede09d90a Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 25 Jul 2023 16:43:08 -0400 Subject: [PATCH] ib: fill out contract tables in `.get_mkt_info()` Since getting a global symcache result from the API is basically impossible, we ad-hoc fill out the needed client tables on demand per client code queries to the mkt info EP. Also, use `unpack_fqme()` in fqme (search) pattern parser instead of hacky `str.partition()`. --- piker/brokers/ib/symbols.py | 49 ++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/piker/brokers/ib/symbols.py b/piker/brokers/ib/symbols.py index 9a749179..c6492414 100644 --- a/piker/brokers/ib/symbols.py +++ b/piker/brokers/ib/symbols.py @@ -37,6 +37,7 @@ import trio from piker.accounting import ( Asset, MktPair, + unpack_fqme, ) from piker._cacheables import ( async_lifo_cache, @@ -49,6 +50,7 @@ from ._util import ( if TYPE_CHECKING: from .api import ( MethodProxy, + Client, ) _futes_venues = ( @@ -358,24 +360,23 @@ def parse_patt2fqme( # fqme parsing stage # ------------------ if '.ib' in pattern: - from piker.accounting import unpack_fqme _, symbol, venue, expiry = unpack_fqme(pattern) else: symbol = pattern expiry = '' - # another hack for forex pairs lul. - if ( - '.idealpro' in symbol - # or '/' in symbol - ): - exch = 'IDEALPRO' - symbol = symbol.removesuffix('.idealpro') - if '/' in symbol: - symbol, currency = symbol.split('/') + # # another hack for forex pairs lul. + # if ( + # '.idealpro' in symbol + # # or '/' in symbol + # ): + # exch: str = 'IDEALPRO' + # symbol = symbol.removesuffix('.idealpro') + # if '/' in symbol: + # symbol, currency = symbol.split('/') - else: + # else: # TODO: yes, a cache.. # try: # # give the cache a go @@ -387,9 +388,9 @@ def parse_patt2fqme( symbol, _, expiry = symbol.rpartition('.') # use heuristics to figure out contract "type" - symbol, exch = symbol.upper().rsplit('.', maxsplit=1) + symbol, venue = symbol.upper().rsplit('.', maxsplit=1) - return symbol, currency, exch, expiry + return symbol, currency, venue, expiry def con2fqme( @@ -406,9 +407,12 @@ def con2fqme( ''' # should be real volume for this contract by default - calc_price = False + calc_price: bool = False if con.conId: try: + # TODO: LOL so apparently IB just changes the contract + # ID (int) on a whim.. so we probably need to use an + # FQME style key after all... return _cache[con.conId] except KeyError: pass @@ -475,8 +479,9 @@ async def get_mkt_info( ) -> tuple[MktPair, ibis.ContractDetails]: - # XXX: we don't need to split off any fqme broker part? - # bs_fqme, _, broker = fqme.partition('.') + if '.ib' not in fqme: + fqme += '.ib' + broker, pair, venue, expiry = unpack_fqme(fqme) proxy: MethodProxy if proxy is not None: @@ -492,7 +497,7 @@ async def get_mkt_info( ( con, # Contract details, # ContractDetails - ) = await proxy.get_sym_details(symbol=fqme) + ) = await proxy.get_sym_details(fqme=fqme) except ConnectionError: log.exception(f'Proxy is ded {proxy._aio_ns}') raise @@ -558,4 +563,14 @@ async def get_mkt_info( _fqme_without_src=(atype != 'fiat'), ) + # if possible register the bs_mktid to the just-built + # mkt so that it can be retreived by order mode tasks later. + # TODO NOTE: this is going to be problematic if/when we split + # out the datatd vs. brokerd actors since the mktmap lookup + # table will now be inaccessible.. + if proxy is not None: + client: Client = proxy._aio_ns + client._contracts[mkt.bs_fqme] = con + client._cons2mkts[con] = mkt + return mkt, details