diff --git a/fin_defs/__init__.py b/fin_defs/__init__.py index 50865cf..620e136 100644 --- a/fin_defs/__init__.py +++ b/fin_defs/__init__.py @@ -45,6 +45,11 @@ class Asset: return COMMON_NAMES.get(self, []) def to_polygon_id(self) -> str: + """Formats this asset to the [`polygon.io`](https://polygon.io) + identifier format. + + Inverse of `from_polygon_id`. + """ # TODO: Support currency pairs not involving USD. if isinstance(self, Stock): return f'{self.ticker}' @@ -61,6 +66,11 @@ class Asset: @staticmethod def from_polygon_id(polygon_id: str) -> 'Asset': + """Parses an asset from the [`polygon.io`](https://polygon.io) + identifier format. + + Inverse of `to_polygon_id`. + """ if polygon_id.startswith('I:'): return Index(polygon_id.removeprefix('I:')) if polygon_id.startswith('X:'): @@ -72,6 +82,46 @@ class Asset: return FiatCurrency(polygon_id.removeprefix('C:').removesuffix('USD')) return Stock.from_polygon_id(polygon_id) + def to_string_id(self) -> str: + """Formats the asset id using the fin_defs asset format.""" + if isinstance(self, Stock): + return f'stock:{self}' + if isinstance(self, FiatCurrency): + return f'fiat:{self}' + if isinstance(self, CryptoCurrency): + return f'crypto:{self}' + if isinstance(self, Index): + return f'index:{self}' + + raise NotImplementedError('Unsupported asset type: ' + str(self)) + + @staticmethod + def from_string_id(asset_id: str) -> 'Asset': + """Parses an `Asset` using the fin_defs asset format.""" + if ':' in asset_id: + prefix, ticker = asset_id.split(':') + else: + prefix, ticker = None, asset_id + + if known_symbol := WELL_KNOWN_SYMBOLS.get(ticker, None): + return known_symbol + + if prefix == 'stock': + if m := re.match(r'^(\w+)(?:\.(\w+))?$', ticker): + exchange = EXCHANGES_BY_IDS[m.group(2) or 'NYSE'] # TODO? + return Stock(m.group(1), exchange) + if prefix == 'currency': + return FiatCurrency(ticker) + if prefix == 'fiat': + return FiatCurrency(ticker) + if prefix == 'index': + return Index(ticker) + if prefix == 'crypto': + return CryptoCurrency(ticker, None) # TODO + + msg = f'Unsupported asset format: {asset_id}' + raise NotImplementedError(msg) + @enforce_typing.enforce_types @dataclasses.dataclass(frozen=True)