Further refinement and shimming of `MktPair`
Prepping to entirely replace `Symbol`; this adds a buncha docs/comments, better implementation for representing and parsing the FQME: "fully qualified market endpoint". Deatz: - make `.src` an optional field until we figure out how we're going to support loading source assets from all backends sensibly.. - implement `MktPair.fqme: str` (what was previously called `fqsn`) using a new util func: `maybe_cons_tokens()`. - `Symbol.brokers` and expect only `.broker` usage. - remap anything with `fqsn` in the name to `fqme` with aliases from the old name. - implement `unpack_fqme()` with `match:` syntax B) - add `MktPair.tick_size_digits`, `.lot_size_digits`, `.fqsn`, `.key` for backward compat. - make all fqme generation related fields empty `str`s by default. - add `MktPair.resolved: bool` a flag indicating whether or not `.dst` is an `Asset` instance or just a string and, `.bs_mktid` the field to hold the "backend system market id" per broker.pre_overruns_ctxcancelled
							parent
							
								
									2485bc803b
								
							
						
					
					
						commit
						e5eb317b47
					
				| 
						 | 
					@ -43,8 +43,8 @@ from ..data.types import Struct
 | 
				
			||||||
_underlyings: list[str] = [
 | 
					_underlyings: list[str] = [
 | 
				
			||||||
    'stock',
 | 
					    'stock',
 | 
				
			||||||
    'bond',
 | 
					    'bond',
 | 
				
			||||||
    'crypto_currency',
 | 
					    'crypto',
 | 
				
			||||||
    'fiat_currency',
 | 
					    'fiat',
 | 
				
			||||||
    'commodity',
 | 
					    'commodity',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,7 +102,8 @@ def digits_to_dec(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Asset(Struct, frozen=True):
 | 
					class Asset(Struct, frozen=True):
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Container type describing any transactable asset's technology.
 | 
					    Container type describing any transactable asset and its
 | 
				
			||||||
 | 
					    contract-like and/or underlying technology meta-info.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    name: str
 | 
					    name: str
 | 
				
			||||||
| 
						 | 
					@ -116,6 +117,9 @@ class Asset(Struct, frozen=True):
 | 
				
			||||||
    # should not be explicitly required in our generic API.
 | 
					    # should not be explicitly required in our generic API.
 | 
				
			||||||
    info: dict = {}  # make it frozen?
 | 
					    info: dict = {}  # make it frozen?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # TODO?
 | 
				
			||||||
 | 
					    # _to_dict_skip = {'info'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self) -> str:
 | 
					    def __str__(self) -> str:
 | 
				
			||||||
        return self.name
 | 
					        return self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,6 +141,18 @@ class Asset(Struct, frozen=True):
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def maybe_cons_tokens(
 | 
				
			||||||
 | 
					    tokens: list[Any],
 | 
				
			||||||
 | 
					    delim_char: str = '.',
 | 
				
			||||||
 | 
					) -> str:
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    Construct `str` output from a maybe-concatenation of input
 | 
				
			||||||
 | 
					    sequence of elements in ``tokens``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    return '.'.join(filter(bool, tokens)).lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MktPair(Struct, frozen=True):
 | 
					class MktPair(Struct, frozen=True):
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Market description for a pair of assets which are tradeable:
 | 
					    Market description for a pair of assets which are tradeable:
 | 
				
			||||||
| 
						 | 
					@ -144,52 +160,50 @@ class MktPair(Struct, frozen=True):
 | 
				
			||||||
        buy: source asset -> destination asset
 | 
					        buy: source asset -> destination asset
 | 
				
			||||||
        sell: destination asset -> source asset
 | 
					        sell: destination asset -> source asset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    The main intention of this type is for a cross-asset, venue, broker
 | 
					    The main intention of this type is for a **simple** cross-asset
 | 
				
			||||||
    normalized descriptive data type from which all market-auctions can
 | 
					    venue/broker normalized descrption type from which all
 | 
				
			||||||
    be mapped, simply.
 | 
					    market-auctions can be mapped from FQME identifiers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TODO: our eventual target fqme format/schema is:
 | 
				
			||||||
 | 
					    <dst>/<src>.<expiry>.<con_info_1>.<con_info_2>. -> .<venue>.<broker>
 | 
				
			||||||
 | 
					          ^ -- optional tokens ------------------------------- ^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    # "source asset" (name) used to buy *from*
 | 
					    dst: str | Asset
 | 
				
			||||||
    # (or used to sell *to*)
 | 
					 | 
				
			||||||
    src: str | Asset
 | 
					 | 
				
			||||||
    # "destination asset" (name) used to buy *to*
 | 
					    # "destination asset" (name) used to buy *to*
 | 
				
			||||||
    # (or used to sell *from*)
 | 
					    # (or used to sell *from*)
 | 
				
			||||||
    dst: str | Asset
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def key(self) -> str:
 | 
					 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        The "endpoint key" for this market.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        In most other tina platforms this is referred to as the
 | 
					 | 
				
			||||||
        "symbol".
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        return f'{self.src}{self.dst}'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    price_tick: Decimal  # minimum price increment
 | 
				
			||||||
 | 
					    size_tick: Decimal  # minimum size (aka vlm) increment
 | 
				
			||||||
    # the tick size is the number describing the smallest step in value
 | 
					    # the tick size is the number describing the smallest step in value
 | 
				
			||||||
    # available in this market between the source and destination
 | 
					    # available in this market between the source and destination
 | 
				
			||||||
    # assets.
 | 
					    # assets.
 | 
				
			||||||
    # https://en.wikipedia.org/wiki/Tick_size
 | 
					    # https://en.wikipedia.org/wiki/Tick_size
 | 
				
			||||||
    # https://en.wikipedia.org/wiki/Commodity_tick
 | 
					    # https://en.wikipedia.org/wiki/Commodity_tick
 | 
				
			||||||
    # https://en.wikipedia.org/wiki/Percentage_in_point
 | 
					    # https://en.wikipedia.org/wiki/Percentage_in_point
 | 
				
			||||||
    price_tick: Decimal  # minimum price increment value increment
 | 
					 | 
				
			||||||
    size_tick: Decimal  # minimum size (aka vlm) increment value increment
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # @property
 | 
					    # unique "broker id" since every market endpoint provider
 | 
				
			||||||
    # def size_tick_digits(self) -> int:
 | 
					    # has their own nomenclature and schema for market maps.
 | 
				
			||||||
    #     return float_digits(self.size_tick)
 | 
					    bs_mktid: str
 | 
				
			||||||
 | 
					    broker: str  # the middle man giving access
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    broker: str | None = None  # the middle man giving access
 | 
					    # NOTE: to start this field is optional but should eventually be
 | 
				
			||||||
    venue: str | None = None  # market venue provider name
 | 
					    # required; the reason is for backward compat since more positioning
 | 
				
			||||||
    expiry: str | None = None  # for derivs, expiry datetime parseable str
 | 
					    # calculations were not originally stored with a src asset..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    src: str | Asset | None = None
 | 
				
			||||||
 | 
					    # "source asset" (name) used to buy *from*
 | 
				
			||||||
 | 
					    # (or used to sell *to*).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    venue: str = ''  # market venue provider name
 | 
				
			||||||
 | 
					    expiry: str = ''  # for derivs, expiry datetime parseable str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # destination asset's financial type/classification name
 | 
					    # destination asset's financial type/classification name
 | 
				
			||||||
    # NOTE: this is required for the order size allocator system,
 | 
					    # NOTE: this is required for the order size allocator system,
 | 
				
			||||||
    # since we use different default settings based on the type
 | 
					    # since we use different default settings based on the type
 | 
				
			||||||
    # of the destination asset, eg. futes use a units limits vs.
 | 
					    # of the destination asset, eg. futes use a units limits vs.
 | 
				
			||||||
    # equities a $limit.
 | 
					    # equities a $limit.
 | 
				
			||||||
    dst_type: AssetTypeName | None = None
 | 
					    # dst_type: AssetTypeName | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # source asset's financial type/classification name
 | 
					    # source asset's financial type/classification name
 | 
				
			||||||
    # TODO: is a src type required for trading?
 | 
					    # TODO: is a src type required for trading?
 | 
				
			||||||
| 
						 | 
					@ -211,21 +225,101 @@ class MktPair(Struct, frozen=True):
 | 
				
			||||||
        Constructor for a received msg-dict normally received over IPC.
 | 
					        Constructor for a received msg-dict normally received over IPC.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '''
 | 
					        '''
 | 
				
			||||||
        ...
 | 
					        raise NotImplementedError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # fqa, fqma, .. etc. see issue:
 | 
					    @property
 | 
				
			||||||
    # https://github.com/pikers/piker/issues/467
 | 
					    def resolved(self) -> bool:
 | 
				
			||||||
 | 
					        return isinstance(self.dst, Asset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def from_fqme(
 | 
				
			||||||
 | 
					        cls,
 | 
				
			||||||
 | 
					        fqme: str,
 | 
				
			||||||
 | 
					        price_tick: float | str,
 | 
				
			||||||
 | 
					        size_tick: float | str,
 | 
				
			||||||
 | 
					        bs_mktid: str,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ) -> MktPair:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        broker, key, suffix = unpack_fqme(fqme)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # XXX: loading from a fqme string will
 | 
				
			||||||
 | 
					        # leave this pair as "un resolved" meaning
 | 
				
			||||||
 | 
					        # we don't yet have `.dst` set as an `Asset`
 | 
				
			||||||
 | 
					        # which we expect to be filled in by some
 | 
				
			||||||
 | 
					        # backend client with access to that data-info.
 | 
				
			||||||
 | 
					        return cls(
 | 
				
			||||||
 | 
					            dst=key,  # not resolved
 | 
				
			||||||
 | 
					            price_tick=price_tick,
 | 
				
			||||||
 | 
					            size_tick=size_tick,
 | 
				
			||||||
 | 
					            bs_mktid=bs_mktid,
 | 
				
			||||||
 | 
					            broker=broker,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def key(self) -> str:
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        The "endpoint key" for this market.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Eg. mnq/usd or btc/usdt or xmr/btc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        In most other tina platforms this is referred to as the
 | 
				
			||||||
 | 
					        "symbol".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        return maybe_cons_tokens([self.dst, self.src])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # NOTE: the main idea behind an fqme is to map a "market address"
 | 
				
			||||||
 | 
					    # to some endpoint from a transaction provider (eg. a broker) such
 | 
				
			||||||
 | 
					    # that we build a table of `fqme: str -> bs_mktid: Any` where any "piker
 | 
				
			||||||
 | 
					    # market address" maps 1-to-1 to some broker trading endpoint.
 | 
				
			||||||
 | 
					    # @cached_property
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def fqme(self) -> str:
 | 
					    def fqme(self) -> str:
 | 
				
			||||||
        '''
 | 
					        '''
 | 
				
			||||||
        Return the fully qualified market endpoint-address for the
 | 
					        Return the fully qualified market endpoint-address for the
 | 
				
			||||||
        pair of transacting assets.
 | 
					        pair of transacting assets.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Yes, you can pronounce it colloquially as "f#$%-me"..
 | 
					        fqme = "fully qualified market endpoint"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        And yes, you pronounce it colloquially as read..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Basically the idea here is for all client code (consumers of piker's
 | 
				
			||||||
 | 
					        APIs which query the data/broker-provider agnostic layer(s)) should be
 | 
				
			||||||
 | 
					        able to tell which backend / venue / derivative each data feed/flow is
 | 
				
			||||||
 | 
					        from by an explicit string-key of the current form:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <market-instrument-name>
 | 
				
			||||||
 | 
					            .<venue>
 | 
				
			||||||
 | 
					            .<expiry>
 | 
				
			||||||
 | 
					            .<derivative-suffix-info>
 | 
				
			||||||
 | 
					            .<brokerbackendname>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eg. for an explicit daq mini futes contract: mnq.cme.20230317.ib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TODO: I have thoughts that we should actually change this to be
 | 
				
			||||||
 | 
					        more like an "attr lookup" (like how the web should have done
 | 
				
			||||||
 | 
					        urls, but marketting peeps ruined it etc. etc.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <broker>.<venue>.<instrumentname>.<suffixwithmetadata>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TODO:
 | 
				
			||||||
 | 
					        See community discussion on naming and nomenclature, order
 | 
				
			||||||
 | 
					        of addressing hierarchy, general schema, internal representation:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        https://github.com/pikers/piker/issues/467
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '''
 | 
					        '''
 | 
				
			||||||
 | 
					        return maybe_cons_tokens([
 | 
				
			||||||
 | 
					            self.key,  # final "pair name" (eg. qqq[/usd], btcusdt)
 | 
				
			||||||
 | 
					            self.venue,
 | 
				
			||||||
 | 
					            self.expiry,
 | 
				
			||||||
 | 
					            self.broker,
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # fqsn = fqme
 | 
					    @property
 | 
				
			||||||
 | 
					    def fqsn(self) -> str:
 | 
				
			||||||
 | 
					        return self.fqme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def quantize(
 | 
					    def quantize(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
| 
						 | 
					@ -250,35 +344,27 @@ class MktPair(Struct, frozen=True):
 | 
				
			||||||
            rounding=ROUND_HALF_EVEN
 | 
					            rounding=ROUND_HALF_EVEN
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO: remove this?
 | 
					    # @property
 | 
				
			||||||
 | 
					    # def size_tick_digits(self) -> int:
 | 
				
			||||||
 | 
					    #     return float_digits(self.size_tick)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # TODO: BACKWARD COMPAT, TO REMOVE?
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def type_key(self) -> str:
 | 
					    def type_key(self) -> str:
 | 
				
			||||||
        return list(self.broker_info.values())[0]['asset_type']
 | 
					        return str(self.dst.atype)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # @classmethod
 | 
					    @property
 | 
				
			||||||
    # def from_fqme(
 | 
					    def tick_size_digits(self) -> int:
 | 
				
			||||||
    #     cls,
 | 
					        return float_digits(self.price_tick)
 | 
				
			||||||
    #     fqme: str,
 | 
					 | 
				
			||||||
    #     **kwargs,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ) -> MktPair:
 | 
					    @property
 | 
				
			||||||
    #     broker, key, suffix = unpack_fqme(fqme)
 | 
					    def lot_size_digits(self) -> int:
 | 
				
			||||||
 | 
					        return float_digits(self.size_tick)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def mk_fqsn(
 | 
					def unpack_fqme(
 | 
				
			||||||
    provider: str,
 | 
					    fqme: str,
 | 
				
			||||||
    symbol: str,
 | 
					) -> tuple[str, str, str]:
 | 
				
			||||||
 | 
					 | 
				
			||||||
) -> str:
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    Generate a "fully qualified symbol name" which is
 | 
					 | 
				
			||||||
    a reverse-hierarchical cross broker/provider symbol
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    return '.'.join([symbol, provider]).lower()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def unpack_fqsn(fqsn: str) -> tuple[str, str, str]:
 | 
					 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Unpack a fully-qualified-symbol-name to ``tuple``.
 | 
					    Unpack a fully-qualified-symbol-name to ``tuple``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -287,37 +373,38 @@ def unpack_fqsn(fqsn: str) -> tuple[str, str, str]:
 | 
				
			||||||
    suffix = ''
 | 
					    suffix = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO: probably reverse the order of all this XD
 | 
					    # TODO: probably reverse the order of all this XD
 | 
				
			||||||
    tokens = fqsn.split('.')
 | 
					    tokens = fqme.split('.')
 | 
				
			||||||
    if len(tokens) < 3:
 | 
					 | 
				
			||||||
        # probably crypto
 | 
					 | 
				
			||||||
        symbol, broker = tokens
 | 
					 | 
				
			||||||
        return (
 | 
					 | 
				
			||||||
            broker,
 | 
					 | 
				
			||||||
            symbol,
 | 
					 | 
				
			||||||
            '',
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    elif len(tokens) > 3:
 | 
					    match tokens:
 | 
				
			||||||
        symbol, venue, suffix, broker = tokens
 | 
					        case [mkt_ep, broker]:
 | 
				
			||||||
    else:
 | 
					            # probably crypto
 | 
				
			||||||
        symbol, venue, broker = tokens
 | 
					            # mkt_ep, broker = tokens
 | 
				
			||||||
        suffix = ''
 | 
					            return (
 | 
				
			||||||
 | 
					                broker,
 | 
				
			||||||
 | 
					                mkt_ep,
 | 
				
			||||||
 | 
					                '',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO: swap venue and suffix/deriv-info here?
 | 
				
			||||||
 | 
					        case [mkt_ep, venue, suffix, broker]:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case [mkt_ep, venue, broker]:
 | 
				
			||||||
 | 
					            suffix = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case _:
 | 
				
			||||||
 | 
					            raise ValueError(f'Invalid fqme: {fqme}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # head, _, broker = fqsn.rpartition('.')
 | 
					 | 
				
			||||||
    # symbol, _, suffix = head.rpartition('.')
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        broker,
 | 
					        broker,
 | 
				
			||||||
        '.'.join([symbol, venue]),
 | 
					        '.'.join([mkt_ep, venue]),
 | 
				
			||||||
        suffix,
 | 
					        suffix,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unpack_fqme = unpack_fqsn
 | 
					unpack_fqsn = unpack_fqme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# TODO: rework the below `Symbol` (which was originally inspired and
 | 
					 | 
				
			||||||
# derived from stuff in quantdom) into a simpler, ipc msg ready, market
 | 
					 | 
				
			||||||
# endpoint meta-data container type as per the drafted interace above.
 | 
					 | 
				
			||||||
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
 | 
				
			||||||
| 
						 | 
					@ -343,13 +430,8 @@ class Symbol(Struct):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Symbol(
 | 
					        return Symbol(
 | 
				
			||||||
            key=key,
 | 
					            key=key,
 | 
				
			||||||
 | 
					 | 
				
			||||||
            tick_size=tick_size,
 | 
					            tick_size=tick_size,
 | 
				
			||||||
            lot_tick_size=lot_size,
 | 
					            lot_tick_size=lot_size,
 | 
				
			||||||
 | 
					 | 
				
			||||||
            # tick_size_digits=float_digits(tick_size),
 | 
					 | 
				
			||||||
            # lot_size_digits=float_digits(lot_size),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            suffix=suffix,
 | 
					            suffix=suffix,
 | 
				
			||||||
            broker_info={broker: info},
 | 
					            broker_info={broker: info},
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -361,10 +443,6 @@ class Symbol(Struct):
 | 
				
			||||||
    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']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def brokers(self) -> list[str]:
 | 
					 | 
				
			||||||
        return list(self.broker_info.keys())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def tick_size_digits(self) -> int:
 | 
					    def tick_size_digits(self) -> int:
 | 
				
			||||||
        return float_digits(self.lot_tick_size)
 | 
					        return float_digits(self.lot_tick_size)
 | 
				
			||||||
| 
						 | 
					@ -379,23 +457,6 @@ class Symbol(Struct):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def fqsn(self) -> str:
 | 
					    def fqsn(self) -> str:
 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        fqsn = "fully qualified symbol name"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Basically the idea here is for all client-ish code (aka programs/actors
 | 
					 | 
				
			||||||
        that ask the provider agnostic layers in the stack for data) should be
 | 
					 | 
				
			||||||
        able to tell which backend / venue / derivative each data feed/flow is
 | 
					 | 
				
			||||||
        from by an explicit string key of the current form:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <instrumentname>.<venue>.<suffixwithmetadata>.<brokerbackendname>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        TODO: I have thoughts that we should actually change this to be
 | 
					 | 
				
			||||||
        more like an "attr lookup" (like how the web should have done
 | 
					 | 
				
			||||||
        urls, but marketting peeps ruined it etc. etc.):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <broker>.<venue>.<instrumentname>.<suffixwithmetadata>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        broker = self.broker
 | 
					        broker = self.broker
 | 
				
			||||||
        key = self.key
 | 
					        key = self.key
 | 
				
			||||||
        if self.suffix:
 | 
					        if self.suffix:
 | 
				
			||||||
| 
						 | 
					@ -410,14 +471,7 @@ class Symbol(Struct):
 | 
				
			||||||
    def quantize(
 | 
					    def quantize(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        size: float,
 | 
					        size: float,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ) -> Decimal:
 | 
					    ) -> Decimal:
 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        Truncate input ``size: float`` using ``Decimal``
 | 
					 | 
				
			||||||
        quantized form of the digit precision defined
 | 
					 | 
				
			||||||
        by ``self.lot_tick_size``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        digits = float_digits(self.lot_tick_size)
 | 
					        digits = float_digits(self.lot_tick_size)
 | 
				
			||||||
        return Decimal(size).quantize(
 | 
					        return Decimal(size).quantize(
 | 
				
			||||||
            Decimal(f'1.{"0".ljust(digits, "0")}'),
 | 
					            Decimal(f'1.{"0".ljust(digits, "0")}'),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue