`.accounting._mktinfo`: better fqme `MktPair` handling

It needed some work..

- Make `unpack_fqme()` always return a 4-tuple handling the venue and
  suffix parts more generally.
- add `Asset.Asset.guess_from_mkt_ep_key()` a like-it-sounds hack at
  trying to render a `.dst: Asset` for most most purposes throughout the
  stack.
- always try to preprocess the input `fqme: str` with `unpack_fqme()` in
  `MktPair.from_fqme()` and use the new `Asset` method (above) to make
  up a `.dst: Asset` pulling as much meta-info we can from the caller.
- add `MktPair.bs_fqme` to get the thing without the broker part..
- add an `'unknown'` value to the `_derivs` def.
- drop `Symbol.from_fqsn()` and `unpack_fqsn()` more generally (yes
  BREAKING).
rekt_pps
Tyler Goodlet 2023-04-18 18:55:01 -04:00
parent 53a41ba93d
commit d4c8ba19a2
1 changed files with 89 additions and 15 deletions

View File

@ -54,6 +54,9 @@ _derivs: list[str] = [
'continuous_future', 'continuous_future',
'option', 'option',
'futures_option', 'futures_option',
# if we can't figure it out, presume the worst XD
'unknown',
] ]
# NOTE: a tag for other subsystems to try # NOTE: a tag for other subsystems to try
@ -143,6 +146,39 @@ class Asset(Struct, frozen=True):
rounding=ROUND_HALF_EVEN rounding=ROUND_HALF_EVEN
) )
@classmethod
def guess_from_mkt_ep_key(
cls,
mkt_ep_key: str,
atype: str | None = None,
) -> Asset:
'''
A hacky guess method for presuming a (target) asset's properties
based on either the actualy market endpoint key, or config settings
from the user.
'''
atype = atype or 'unknown'
# attempt to strip off any source asset
# via presumed syntax of:
# - <dst>/<src>
# - <dst>.<src>
# - etc.
for char in ['/', '.']:
dst, _, src = mkt_ep_key.partition(char)
if src:
if not atype:
atype = 'fiat'
break
return Asset(
name=dst,
atype=atype,
tx_tick=Decimal('0.01'),
)
def maybe_cons_tokens( def maybe_cons_tokens(
tokens: list[Any], tokens: list[Any],
@ -269,15 +305,28 @@ class MktPair(Struct, frozen=True):
def from_fqme( def from_fqme(
cls, cls,
fqme: str, fqme: str,
price_tick: float | str, price_tick: float | str,
size_tick: float | str, size_tick: float | str,
bs_mktid: str, bs_mktid: str,
broker: str | None = None,
**kwargs, **kwargs,
) -> MktPair: ) -> MktPair:
broker, key, suffix = unpack_fqme(fqme) _fqme: str = fqme
if (
broker
and broker not in fqme
):
_fqme = f'{fqme}.{broker}'
broker, mkt_ep_key, venue, suffix = unpack_fqme(_fqme)
dst: Asset = Asset.guess_from_mkt_ep_key(
mkt_ep_key,
atype=kwargs.get('_atype'),
)
# XXX: loading from a fqme string will # XXX: loading from a fqme string will
# leave this pair as "un resolved" meaning # leave this pair as "un resolved" meaning
@ -285,13 +334,21 @@ class MktPair(Struct, frozen=True):
# which we expect to be filled in by some # which we expect to be filled in by some
# backend client with access to that data-info. # backend client with access to that data-info.
return cls( return cls(
dst=key, # not resolved # XXX: not resolved to ``Asset`` :(
dst=dst,
broker=broker,
venue=venue,
# XXX NOTE: we presume this token
# if the expiry for now!
expiry=suffix,
price_tick=price_tick, price_tick=price_tick,
size_tick=size_tick, size_tick=size_tick,
bs_mktid=bs_mktid, bs_mktid=bs_mktid,
broker=broker,
**kwargs, **kwargs,
).copy() ).copy()
@property @property
@ -381,6 +438,14 @@ class MktPair(Struct, frozen=True):
self.broker, self.broker,
]) ])
@property
def bs_fqme(self) -> str:
'''
FQME sin broker part XD
'''
return self.fqme.rstrip(f'.{self.broker}')
@property @property
def fqsn(self) -> str: def fqsn(self) -> str:
return self.fqme return self.fqme
@ -428,7 +493,9 @@ class MktPair(Struct, frozen=True):
def unpack_fqme( def unpack_fqme(
fqme: str, fqme: str,
) -> tuple[str, str, str]: broker: str | None = None
) -> tuple[str, ...]:
''' '''
Unpack a fully-qualified-symbol-name to ``tuple``. Unpack a fully-qualified-symbol-name to ``tuple``.
@ -442,17 +509,26 @@ def unpack_fqme(
match tokens: match tokens:
case [mkt_ep, broker]: case [mkt_ep, broker]:
# probably crypto # probably crypto
# mkt_ep, broker = tokens
return ( return (
broker, broker,
mkt_ep, mkt_ep,
'', '',
'',
) )
# TODO: swap venue and suffix/deriv-info here? # TODO: swap venue and suffix/deriv-info here?
case [mkt_ep, venue, suffix, broker]: case [mkt_ep, venue, suffix, broker]:
pass pass
# handle `bs_mktid` + `broker` input case
case [
mkt_ep, venue, suffix
] if (
broker
and suffix != broker
):
pass
case [mkt_ep, venue, broker]: case [mkt_ep, venue, broker]:
suffix = '' suffix = ''
@ -461,14 +537,13 @@ def unpack_fqme(
return ( return (
broker, broker,
'.'.join([mkt_ep, venue]), mkt_ep,
venue,
# '.'.join([mkt_ep, venue]),
suffix, suffix,
) )
unpack_fqsn = unpack_fqme
class Symbol(Struct): class Symbol(Struct):
''' '''
I guess this is some kinda container thing for dealing with I guess this is some kinda container thing for dealing with
@ -485,27 +560,26 @@ class Symbol(Struct):
broker_info: dict[str, dict[str, Any]] = {} broker_info: dict[str, dict[str, Any]] = {}
@classmethod @classmethod
def from_fqsn( def from_fqme(
cls, cls,
fqsn: str, fqsn: str,
info: dict[str, Any], info: dict[str, Any],
) -> Symbol: ) -> Symbol:
broker, key, suffix = unpack_fqsn(fqsn) broker, mktep, venue, suffix = unpack_fqme(fqsn)
tick_size = info.get('price_tick_size', 0.01) tick_size = info.get('price_tick_size', 0.01)
lot_size = info.get('lot_tick_size', 0.0) lot_size = info.get('lot_tick_size', 0.0)
return Symbol( return Symbol(
key=key, broker=broker,
key=mktep,
tick_size=tick_size, tick_size=tick_size,
lot_tick_size=lot_size, lot_tick_size=lot_size,
venue=venue,
suffix=suffix, suffix=suffix,
broker_info={broker: info}, broker_info={broker: info},
) )
# compat name mapping
from_fqme = from_fqsn
@property @property
def type_key(self) -> str: def type_key(self) -> str:
return list(self.broker_info.values())[0]['asset_type'] return list(self.broker_info.values())[0]['asset_type']