Compare commits
No commits in common. "1c5df0dfe386c54658ac4db1b8d6a19ef6cb1baa" and "47260a7ba3e57bb8ffa37fefd902d711d7ac56dd" have entirely different histories.
1c5df0dfe3
...
47260a7ba3
13
README.md
13
README.md
|
@ -6,19 +6,6 @@
|
||||||
|
|
||||||
Python library defining base types for financial processing.
|
Python library defining base types for financial processing.
|
||||||
|
|
||||||
Defines a base `Asset` type, and various subtypes, for universal representation
|
|
||||||
of these assets.
|
|
||||||
|
|
||||||
Defined hierarchy:
|
|
||||||
|
|
||||||
* `Asset`
|
|
||||||
- `Currency`
|
|
||||||
+ `FiatCurrency`
|
|
||||||
+ `CryptoCurrency`
|
|
||||||
- `Stock`
|
|
||||||
- `Index`
|
|
||||||
- `Commodity`
|
|
||||||
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,6 @@
|
||||||
"""# Finance Definitions.
|
"""# Finance Definitions.
|
||||||
|
|
||||||
Python library defining base types for financial processing.
|
Python library defining base types for financial processing.
|
||||||
|
|
||||||
Defines a base `Asset` type, and various subtypes, for universal representation
|
|
||||||
of these assets.
|
|
||||||
|
|
||||||
Defined hierarchy:
|
|
||||||
|
|
||||||
* `Asset`
|
|
||||||
- `Currency`
|
|
||||||
+ `FiatCurrency`
|
|
||||||
+ `CryptoCurrency`
|
|
||||||
- `Stock`
|
|
||||||
- `Index`
|
|
||||||
- `Commodity`
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
@ -35,16 +22,7 @@ RE_CRYPTO_TICKER_FORMAT = r'^\S+$'
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class StockExchange:
|
class StockExchange:
|
||||||
"""Unified Stock Exchange identifiers.
|
"""Unified Stock Exchange identifiers."""
|
||||||
|
|
||||||
Fields:
|
|
||||||
- `name`: Human-readable name.
|
|
||||||
- `mic`: Official MIC identifier.
|
|
||||||
- `bloomberg_id`: Identifier for lookup on Bloomberg.
|
|
||||||
- `crunchbase_id`: Identifier for lookup on Crunchbase.
|
|
||||||
- `yahoo_id`: Identifier for lookup on Yahoo! Finance.
|
|
||||||
- `eod_id`: Identifier for lookup on EOD.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
mic: str
|
mic: str
|
||||||
|
@ -64,15 +42,9 @@ class Asset:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def names(self) -> list[str]:
|
def names(self) -> list[str]:
|
||||||
"""Returns a list of human readable names for this `Asset`."""
|
|
||||||
return COMMON_NAMES.get(self, [])
|
return COMMON_NAMES.get(self, [])
|
||||||
|
|
||||||
def to_polygon_id(self) -> str:
|
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.
|
# TODO: Support currency pairs not involving USD.
|
||||||
if isinstance(self, Stock):
|
if isinstance(self, Stock):
|
||||||
return f'{self.ticker}'
|
return f'{self.ticker}'
|
||||||
|
@ -89,11 +61,6 @@ class Asset:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_polygon_id(polygon_id: str) -> 'Asset':
|
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:'):
|
if polygon_id.startswith('I:'):
|
||||||
return Index(polygon_id.removeprefix('I:'))
|
return Index(polygon_id.removeprefix('I:'))
|
||||||
if polygon_id.startswith('X:'):
|
if polygon_id.startswith('X:'):
|
||||||
|
@ -105,51 +72,6 @@ class Asset:
|
||||||
return FiatCurrency(polygon_id.removeprefix('C:').removesuffix('USD'))
|
return FiatCurrency(polygon_id.removeprefix('C:').removesuffix('USD'))
|
||||||
return Stock.from_polygon_id(polygon_id)
|
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.ticker}.{self.exchange.mic}'
|
|
||||||
if isinstance(self, FiatCurrency):
|
|
||||||
return f'fiat:{self.iso_code}'
|
|
||||||
if isinstance(self, CryptoCurrency):
|
|
||||||
return f'crypto:{self.ccxt_symbol}'
|
|
||||||
if isinstance(self, Index):
|
|
||||||
return f'index:{self.ticker}'
|
|
||||||
if isinstance(self, Commodity):
|
|
||||||
return f'commodity:{self.alpha_vantage_id}'
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.to_string_id()
|
|
||||||
|
|
||||||
|
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
|
@ -167,6 +89,9 @@ class FiatCurrency(Currency):
|
||||||
msg = f'iso_code was not in correct format: {self.iso_code}'
|
msg = f'iso_code was not in correct format: {self.iso_code}'
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.iso_code
|
||||||
|
|
||||||
|
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True, eq=True)
|
@dataclasses.dataclass(frozen=True, eq=True)
|
||||||
|
@ -181,6 +106,10 @@ class CryptoCurrency(Currency):
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.ccxt_symbol
|
||||||
|
|
||||||
|
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True, eq=True)
|
@dataclasses.dataclass(frozen=True, eq=True)
|
||||||
class Stock(Asset):
|
class Stock(Asset):
|
||||||
|
@ -193,6 +122,9 @@ class Stock(Asset):
|
||||||
msg = f'ticker was not in correct format: {self.ticker}'
|
msg = f'ticker was not in correct format: {self.ticker}'
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.ticker}.{self.exchange.mic}'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_polygon_id(polygon_id: str, stock_exchange: StockExchange) -> 'Stock':
|
def from_polygon_id(polygon_id: str, stock_exchange: StockExchange) -> 'Stock':
|
||||||
return Stock(polygon_id, stock_exchange)
|
return Stock(polygon_id, stock_exchange)
|
||||||
|
@ -208,6 +140,9 @@ class Index(Asset):
|
||||||
msg = f'ticker was not in correct format: {self.ticker}'
|
msg = f'ticker was not in correct format: {self.ticker}'
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.ticker
|
||||||
|
|
||||||
|
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True, eq=True)
|
@dataclasses.dataclass(frozen=True, eq=True)
|
||||||
|
@ -219,6 +154,9 @@ class Commodity(Asset):
|
||||||
msg = f'alpha_vantage_id was not in correct format: {self.alpha_vantage_id}'
|
msg = f'alpha_vantage_id was not in correct format: {self.alpha_vantage_id}'
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.alpha_vantage_id
|
||||||
|
|
||||||
|
|
||||||
Commodity.CRUDE_OIL_WTI = Commodity('WTI')
|
Commodity.CRUDE_OIL_WTI = Commodity('WTI')
|
||||||
Commodity.CRUDE_OIL_BRENT = Commodity('BRENT')
|
Commodity.CRUDE_OIL_BRENT = Commodity('BRENT')
|
||||||
|
@ -239,7 +177,7 @@ BTC = CryptoCurrency('BTC', coingecko_id='bitcoin')
|
||||||
MPC = CryptoCurrency('MPC', coingecko_id='partisia-blockchain')
|
MPC = CryptoCurrency('MPC', coingecko_id='partisia-blockchain')
|
||||||
SPX = Index('SPX')
|
SPX = Index('SPX')
|
||||||
NDX = Index('NDX')
|
NDX = Index('NDX')
|
||||||
USDT = CryptoCurrency('USDT', coingecko_id='tether')
|
USDT = CryptoCurrency('USDT', 'tether')
|
||||||
|
|
||||||
COMMON_NAMES: dict[Asset, list[str]] = {
|
COMMON_NAMES: dict[Asset, list[str]] = {
|
||||||
FiatCurrency('USD'): ['U.S. Dollar'],
|
FiatCurrency('USD'): ['U.S. Dollar'],
|
||||||
|
@ -258,15 +196,15 @@ COMMON_NAMES: dict[Asset, list[str]] = {
|
||||||
NDX: ['Nasdaq 100'],
|
NDX: ['Nasdaq 100'],
|
||||||
BTC: ['Bitcoin BTC'],
|
BTC: ['Bitcoin BTC'],
|
||||||
MPC: ['Partisia Blockchain MPC Token'],
|
MPC: ['Partisia Blockchain MPC Token'],
|
||||||
CryptoCurrency('ETH', coingecko_id='ethereum'): ['Ethereum Ether'],
|
CryptoCurrency('ETH', 'ethereum'): ['Ethereum Ether'],
|
||||||
CryptoCurrency('DOGE', coingecko_id='dogecoin'): ['Dogecoin'],
|
CryptoCurrency('DOGE', 'dogecoin'): ['Dogecoin'],
|
||||||
CryptoCurrency('SOL', coingecko_id='solana'): ['Solana SOL'],
|
CryptoCurrency('SOL', 'solana'): ['Solana SOL'],
|
||||||
CryptoCurrency('ADA', coingecko_id='cardano'): ['Cardano ADA'],
|
CryptoCurrency('ADA', 'cardano'): ['Cardano ADA'],
|
||||||
CryptoCurrency('BNB', coingecko_id='bnb'): ['Binance BNB'],
|
CryptoCurrency('BNB', 'bnb'): ['Binance BNB'],
|
||||||
CryptoCurrency('MATIC', coingecko_id='polygon'): ['Polygon MATIC'],
|
CryptoCurrency('MATIC', 'polygon'): ['Polygon MATIC'],
|
||||||
# Stable-coins
|
# Stable-coins
|
||||||
CryptoCurrency('DAI', coingecko_id='dai'): ['DAI'],
|
CryptoCurrency('DAI', 'dai'): ['DAI'],
|
||||||
CryptoCurrency('USDC', coingecko_id='usdc'): ['USD Coin'],
|
CryptoCurrency('USDC', 'usdc'): ['USD Coin'],
|
||||||
USDT: ['Tether USDT'],
|
USDT: ['Tether USDT'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,12 +334,7 @@ class AssetInformation:
|
||||||
@enforce_typing.enforce_types
|
@enforce_typing.enforce_types
|
||||||
@dataclasses.dataclass(frozen=True, eq=True, slots=True)
|
@dataclasses.dataclass(frozen=True, eq=True, slots=True)
|
||||||
class AssetAmount:
|
class AssetAmount:
|
||||||
"""Decimal with associated asset unit.
|
"""Decimal with associated asset unit."""
|
||||||
|
|
||||||
Fields:
|
|
||||||
- `asset`: Asset unit of amount.
|
|
||||||
- `amount`: Amount of given asset.
|
|
||||||
"""
|
|
||||||
|
|
||||||
asset: Asset
|
asset: Asset
|
||||||
amount: Decimal
|
amount: Decimal
|
||||||
|
@ -464,7 +397,6 @@ class ExchangeRateSample(Asset):
|
||||||
"""Single exchange rate sample with a timestamp and various stats."""
|
"""Single exchange rate sample with a timestamp and various stats."""
|
||||||
|
|
||||||
timestamp: datetime.date | datetime.datetime
|
timestamp: datetime.date | datetime.datetime
|
||||||
base_asset: Asset
|
|
||||||
_average: Decimal | None = None
|
_average: Decimal | None = None
|
||||||
last: Decimal | None = None
|
last: Decimal | None = None
|
||||||
open: Decimal | None = None
|
open: Decimal | None = None
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = '0.1.31'
|
__version__ = '0.1.30'
|
||||||
|
|
13
setup.py
13
setup.py
|
@ -15,19 +15,6 @@ PACKAGE_DESCRIPTION = """
|
||||||
|
|
||||||
Python library defining base types for financial processing.
|
Python library defining base types for financial processing.
|
||||||
|
|
||||||
Defines a base `Asset` type, and various subtypes, for universal representation
|
|
||||||
of these assets.
|
|
||||||
|
|
||||||
Defined hierarchy:
|
|
||||||
|
|
||||||
* `Asset`
|
|
||||||
- `Currency`
|
|
||||||
+ `FiatCurrency`
|
|
||||||
+ `CryptoCurrency`
|
|
||||||
- `Stock`
|
|
||||||
- `Index`
|
|
||||||
- `Commodity`
|
|
||||||
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
import pytest
|
|
||||||
|
|
||||||
import fin_defs
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('asset', fin_defs.WELL_KNOWN_SYMBOLS.values())
|
|
||||||
def test_to_from_string_id(asset: fin_defs.Asset):
|
|
||||||
assert fin_defs.Asset.from_string_id(asset.to_string_id()) == asset
|
|
||||||
import fin_defs
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('asset', fin_defs.WELL_KNOWN_SYMBOLS.values())
|
|
||||||
def test_to_from_polygon_id(asset: fin_defs.Asset):
|
|
||||||
assert fin_defs.Asset.from_polygon_id(asset.to_polygon_id()) == asset
|
|
Loading…
Reference in New Issue
Block a user