From 309b91676d8472272d6a71f0bdde835d3dc045bc Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 7 Jul 2023 13:31:43 -0400 Subject: [PATCH] Finally, support full `MktPair` + `Asset` msgs Previously we weren't necessarily serializing mkt pairs (for IPC msging) entirely bc the assets `.src/.dst` were being sent just by their str-names. This now properly supports fully serializing `Asset`s as `dict`-msgs such that use of `MktPair.to_dict()` can be transmitted over `tractor.MsgStream`s and deserialized entirely back to struct from on the receiver end. Deats: - implement `Asset.to_dict()` and `.from_msg()` - adjust `MktPair.to_dict()` and `.from_msg()` to use these methods. - drop all the hacky "if .src/.dst is str" handling. - add better `MktPair.from_fqme()` input handling for expiry and venue; ensure that either can be extracted from passed fqme *and* if so they are also popped from any duplicate passed in `**kwargs**`. --- piker/accounting/_mktinfo.py | 82 ++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/piker/accounting/_mktinfo.py b/piker/accounting/_mktinfo.py index 6cab676b..4532de6a 100644 --- a/piker/accounting/_mktinfo.py +++ b/piker/accounting/_mktinfo.py @@ -130,8 +130,26 @@ class Asset(Struct, frozen=True): # should not be explicitly required in our generic API. info: dict | None = None - # TODO? - # _to_dict_skip = {'info'} + # `None` is not toml-compat so drop info + # if no extra data added.. + def to_dict(self) -> dict: + dct = super().to_dict() + if (info := dct.pop('info', None)): + dct['info'] = info + + assert dct['tx_tick'] + return dct + + @classmethod + def from_msg( + cls, + msg: dict[str, Any], + ) -> Asset: + return Asset( + tx_tick=Decimal(str(msg.pop('tx_tick'))), + info=msg.pop('info', None), + **msg, + ) def __str__(self) -> str: return self.name @@ -288,6 +306,8 @@ class MktPair(Struct, frozen=True): # strike price, call or put, swap type, exercise model, etc. contract_info: list[str] | None = None + # TODO: rename to sectype since all of these can + # be considered "securities"? _atype: str = '' # allow explicit disable of the src part of the market @@ -298,6 +318,18 @@ class MktPair(Struct, frozen=True): def __str__(self) -> str: return self.fqme + def to_dict(self) -> dict: + d = super().to_dict() + d['src'] = self.src.to_dict() + d['dst'] = self.dst.to_dict() + + if self.contract_info is None: + d.pop('contract_info') + + # d.pop('_fqme_without_src') + + return d + @classmethod def from_msg( cls, @@ -309,35 +341,20 @@ class MktPair(Struct, frozen=True): ''' dst_asset_msg = msg.pop('dst') + dst = Asset.from_msg(dst_asset_msg) # .copy() + src_asset_msg = msg.pop('src') + src = Asset.from_msg(src_asset_msg) # .copy() - if isinstance(dst_asset_msg, str): - src: str = str(src_asset_msg) - assert isinstance(src, str) - return cls.from_fqme( - dst_asset_msg, - src=src, - **msg, - ) - - else: - # NOTE: we call `.copy()` here to ensure - # type casting! - dst = Asset(**dst_asset_msg).copy() - if not isinstance(src_asset_msg, str): - src = Asset(**src_asset_msg).copy() - else: - src = str(src_asset_msg) - - return cls( - dst=dst, - src=src, - **msg, # XXX NOTE: ``msgspec`` can encode `Decimal` # but it doesn't decide to it by default since # we aren't spec-cing these msgs as structs, SO # we have to ensure we do a struct type case (which `.copy()` # does) to ensure we get the right type! + return cls( + dst=dst, + src=src, + **msg, ).copy() @property @@ -365,7 +382,20 @@ class MktPair(Struct, frozen=True): ): _fqme = f'{fqme}.{broker}' - broker, mkt_ep_key, venue, suffix = unpack_fqme(_fqme) + broker, mkt_ep_key, venue, expiry = unpack_fqme(_fqme) + + kven: str = kwargs.pop('venue', venue) + if venue: + assert venue == kven + else: + venue = kven + + exp: str = kwargs.pop('expiry', expiry) + if expiry: + assert exp == expiry + else: + expiry = exp + dst: Asset = Asset.guess_from_mkt_ep_key( mkt_ep_key, atype=kwargs.get('_atype'), @@ -384,7 +414,7 @@ class MktPair(Struct, frozen=True): venue=venue, # XXX NOTE: we presume this token # if the expiry for now! - expiry=suffix, + expiry=expiry, price_tick=price_tick, size_tick=size_tick,