Unify contract->fqsn translation with new cached-helper

fix_forex
Tyler Goodlet 2022-07-19 16:54:45 -04:00
parent 070b9f3dc1
commit a27431c34f
2 changed files with 72 additions and 55 deletions

View File

@ -424,23 +424,15 @@ class Client:
# one set per future result
details = {}
for details_set in results:
# XXX: if there is more then one entry in the details list
# then the contract is so called "ambiguous".
for d in details_set:
con = d.contract
key = '.'.join([
con.symbol,
con.primaryExchange or con.exchange,
])
expiry = con.lastTradeDateOrContractMonth
if expiry:
key += f'.{expiry}'
# nested dataclass we probably don't need and that
# won't IPC serialize..
# nested dataclass we probably don't need and that won't
# IPC serialize..
d.secIdList = ''
key, calc_price = con2fqsn(d.contract)
details[key] = d
return details
@ -470,7 +462,7 @@ class Client:
self,
pattern: str,
# how many contracts to search "up to"
upto: int = 3,
upto: int = 6,
asdicts: bool = True,
) -> dict[str, ContractDetails]:
@ -522,10 +514,14 @@ class Client:
elif sectype == 'CASH':
dst, src = tract.localSymbol.split('.')
pair_key = "/".join([dst, src])
tract.exchange = 'FOREX'
results[f'{pair_key}.forex'] = tract
exch = tract.exchange.lower()
results[f'{pair_key}.{exch}'] = tract
results.pop(key)
# XXX: again seems to trigger the weird tractor
# bug with the debugger..
# assert 0
return results
async def get_fute(
@ -595,12 +591,11 @@ class Client:
# another hack for forex pairs lul.
if (
'.forex' in symbol
# and not '.ib' in pattern
'.idealpro' in symbol
# or '/' in symbol
):
exch = 'FOREX'
symbol = symbol.removesuffix('.forex')
exch = 'IDEALPRO'
symbol = symbol.removesuffix('.idealpro')
if '/' in symbol:
symbol, currency = symbol.split('/')
@ -665,7 +660,7 @@ class Client:
)
elif (
exch in ('FOREX')
exch in ('IDEALPRO')
or sectype == 'CASH'
):
# if '/' in symbol:
@ -948,6 +943,58 @@ class Client:
return self.ib.positions(account=account)
def con2fqsn(
con: Contract,
_cache: dict[int, (str, bool)] = {}
) -> tuple[str, bool]:
'''
Convert contracts to fqsn-style strings to be used both in symbol-search
matching and as feed tokens passed to the front end data deed layer.
Previously seen contracts are cached by id.
'''
# should be real volume for this contract by default
calc_price = False
if con.conId:
try:
return _cache[con.conId]
except KeyError:
pass
suffix = con.primaryExchange or con.exchange
symbol = con.symbol
expiry = con.lastTradeDateOrContractMonth or ''
match con:
case ibis.Commodity():
# commodities and forex don't have an exchange name and
# no real volume so we have to calculate the price
suffix = con.secType
# no real volume on this tract
calc_price = True
case ibis.Forex() | ibis.Contract(secType='CASH'):
dst, src = con.localSymbol.split('.')
symbol = ''.join([dst, src])
suffix = con.exchange
# no real volume on forex feeds..
calc_price = True
# append a `.<suffix>` to the returned symbol
# key for derivatives that normally is the expiry
# date key.
if expiry:
suffix += f'.{expiry}'
fqsn_key = '.'.join((symbol, suffix)).lower()
_cache[con.conId] = fqsn_key, calc_price
return fqsn_key, calc_price
# per-actor API ep caching
_client_cache: dict[tuple[str, int], Client] = {}
_scan_ignore: set[tuple[str, int]] = set()

View File

@ -42,6 +42,7 @@ from piker.data._sharedmem import ShmArray
from .._util import SymbolNotFound, NoData
from .api import (
# _adhoc_futes_set,
con2fqsn,
log,
load_aio_clients,
ibis,
@ -559,47 +560,18 @@ async def open_aio_quote_stream(
# TODO: cython/mypyc/numba this!
# or we can at least cache a majority of the values
# except for the ones we expect to change?..
def normalize(
ticker: Ticker,
calc_price: bool = False
) -> dict:
# should be real volume for this contract by default
calc_price = False
# check for special contract types
con = ticker.contract
symbol = con.symbol
if type(con) in (
ibis.Commodity,
):
# commodities and forex don't have an exchange name and
# no real volume so we have to calculate the price
suffix = con.secType
# no real volume on this tract
calc_price = True
elif type(con) in (
ibis.Forex,
):
suffix = 'forex'
symbol = con.pair()
# no real volume on forex feeds..
calc_price = True
else:
suffix = con.primaryExchange
if not suffix:
suffix = con.exchange
# append a `.<suffix>` to the returned symbol
# key for derivatives that normally is the expiry
# date key.
expiry = con.lastTradeDateOrContractMonth
if expiry:
suffix += f'.{expiry}'
fqsn, calc_price = con2fqsn(con)
# convert named tuples to dicts so we send usable keys
new_ticks = []
@ -631,9 +603,7 @@ def normalize(
# generate fqsn with possible specialized suffix
# for derivatives, note the lowercase.
data['symbol'] = data['fqsn'] = '.'.join(
(symbol, suffix)
).lower()
data['symbol'] = data['fqsn'] = fqsn
# convert named tuples to dicts for transport
tbts = data.get('tickByTicks')