diff --git a/fin_defs/__init__.py b/fin_defs/__init__.py index ab9c79c..12228dd 100644 --- a/fin_defs/__init__.py +++ b/fin_defs/__init__.py @@ -184,7 +184,7 @@ class Asset: if m := re.match(r'^(\w+)(?:\.(\w+))?$', ticker): exchange = EXCHANGES_BY_IDS[m.group(2) or 'NYSE'] # TODO? return Stock(m.group(1), exchange, **attrs) - if prefix in {'currency','fiat'}: + if prefix in {'currency', 'fiat'}: return FiatCurrency(ticker, **attrs) if prefix == 'index': return Index(ticker, **attrs) @@ -211,6 +211,7 @@ class UnknownAsset(Asset): def raw_short_name(self) -> str: return '???' + @enforce_typing.enforce_types @dataclasses.dataclass(frozen=True) class Currency(Asset): @@ -278,7 +279,7 @@ class Stock(Asset): @staticmethod def from_polygon_id(polygon_id: str) -> 'Stock': - return Stock(polygon_id, NYSE) # TODO: Add support for non-NYSE exchanges. + return Stock(polygon_id, NYSE) # TODO: Add support for non-NYSE exchanges. def raw_short_name(self) -> str: return self.ticker diff --git a/test/test_asset_amount.py b/test/test_asset_amount.py index 0ba5155..c10982a 100644 --- a/test/test_asset_amount.py +++ b/test/test_asset_amount.py @@ -1,7 +1,7 @@ -import pytest - from decimal import Decimal +import pytest + import fin_defs USD_0 = fin_defs.AssetAmount(fin_defs.USD, Decimal(0)) @@ -13,80 +13,106 @@ USD_21 = fin_defs.AssetAmount(fin_defs.USD, Decimal(21)) DKK_0 = fin_defs.AssetAmount(fin_defs.DKK, Decimal(0)) DKK_21 = fin_defs.AssetAmount(fin_defs.DKK, Decimal(21)) + def test_add_asset(): assert USD_10 + USD_11 == USD_21 assert USD_10 + USD_0 == USD_10 assert DKK_0 + USD_10 == USD_10 + def test_sub_asset(): assert USD_21 - USD_10 == USD_11 assert USD_10 - USD_0 == USD_10 assert DKK_0 - USD_10 == -USD_10 + def test_div_asset(): assert USD_20 / USD_10 == 2 assert USD_10 / USD_10 == 1 assert USD_10 / USD_20 == 0.5 + def test_div_amount(): assert USD_20 / Decimal(2) == USD_10 + def test_mult(): assert USD_10 * Decimal(2) == USD_20 + def test_negate(): assert USD_20 + (-USD_10) == USD_10 + def test_compare(): assert USD_10 < USD_20 assert USD_10 <= USD_20 assert not (USD_10 > USD_20) assert not (USD_10 >= USD_20) + def test_compare_zero(): assert DKK_0 < USD_20 assert DKK_0 <= USD_20 assert not (DKK_0 > USD_20) assert not (DKK_0 >= USD_20) + def test_is_zero(): assert USD_0.is_zero() assert not USD_10.is_zero() + def test_str(): assert str(USD_0) == '$0.000 USD' assert str(USD_10) == '$10.00 USD' assert str(USD_11) == '$11.00 USD' assert str(-USD_10) == '-$10.00 USD' + def test_mul_wrong(): with pytest.raises(TypeError, match='other must be Decimal, but was AssetAmount'): assert USD_20 * USD_10 + def test_add_wrong_type(): with pytest.raises(TypeError, match='other must be AssetAmount, but was Decimal'): assert USD_20 + Decimal(1) + def test_add_wrong_asset(): - with pytest.raises(ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK'): + with pytest.raises( + ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK', + ): assert USD_20 + DKK_21 + def test_sub_wrong_type(): with pytest.raises(TypeError, match='other must be AssetAmount, but was Decimal'): assert USD_20 - Decimal(1) + def test_sub_wrong_asset(): - with pytest.raises(ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK'): + with pytest.raises( + ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK', + ): assert USD_20 - DKK_21 + def test_cmp_wrong_type(): with pytest.raises(TypeError, match='other must be AssetAmount, but was Decimal'): - assert USD_20 < Decimal(1) + assert Decimal(1) > USD_20 + def test_cmp_wrong_asset(): - with pytest.raises(ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK'): + with pytest.raises( + ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK', + ): assert USD_20 < DKK_21 -def test_div_wrong_asset (): - with pytest.raises(ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK'): + +def test_div_wrong_asset(): + with pytest.raises( + ValueError, match='AssetAmount must have same asset, but: fiat:USD != fiat:DKK', + ): assert USD_21 / DKK_21 diff --git a/test/test_currency.py b/test/test_currency.py index 247e17b..e941eae 100644 --- a/test/test_currency.py +++ b/test/test_currency.py @@ -1,11 +1,11 @@ -import pytest import fin_defs + def test_from_currency_symbol(): assert fin_defs.FiatCurrency.from_currency_symbol('$') == fin_defs.USD assert fin_defs.FiatCurrency.from_currency_symbol('TEST') is None + def test_currency_symbol(): assert fin_defs.USD.to_currency_symbol() == '$' - diff --git a/test/test_data.py b/test/test_data.py index 94dbc21..f54c256 100644 --- a/test/test_data.py +++ b/test/test_data.py @@ -13,7 +13,6 @@ def test_valid_tickers(ticker: str): assert asset.to_polygon_id() is not None - @pytest.mark.parametrize('ticker', BAD_STOCK_TICKERS) def test_bad_tickers(ticker: str): with pytest.raises(ValueError, match='ticker was not in correct format:.*'): diff --git a/test/test_exchange_rate_sample.py b/test/test_exchange_rate_sample.py index 2769aa8..b3b43b8 100644 --- a/test/test_exchange_rate_sample.py +++ b/test/test_exchange_rate_sample.py @@ -1,19 +1,23 @@ -import pytest import datetime from decimal import Decimal + import fin_defs NOW = datetime.datetime.now() THEN = NOW - datetime.timedelta(days=1) -SAMPLE_AVERAGE = fin_defs.ExchangeRateSample(NOW, - (fin_defs.FiatCurrency.DKK,fin_defs.FiatCurrency.USD), - _average = Decimal(1)) +SAMPLE_AVERAGE = fin_defs.ExchangeRateSample( + NOW, (fin_defs.FiatCurrency.DKK, fin_defs.FiatCurrency.USD), _average=Decimal(1), +) + +SAMPLE_HIGH_LOW = fin_defs.ExchangeRateSample( + NOW, + (fin_defs.FiatCurrency.DKK, fin_defs.FiatCurrency.USD), + high=Decimal(1), + low=Decimal('0.5'), +) -SAMPLE_HIGH_LOW = fin_defs.ExchangeRateSample(NOW, - (fin_defs.FiatCurrency.DKK,fin_defs.FiatCurrency.USD), - high = Decimal(1), low=Decimal('0.5')) def test_sample_average(): assert SAMPLE_AVERAGE.average == 1 @@ -22,7 +26,7 @@ def test_sample_average(): def test_invert_sample(): inverted = SAMPLE_HIGH_LOW.invert_exchange_rate() - assert inverted.asset_pair == (fin_defs.FiatCurrency.USD,fin_defs.FiatCurrency.DKK) + assert inverted.asset_pair == (fin_defs.FiatCurrency.USD, fin_defs.FiatCurrency.DKK) assert inverted.high == 2 assert inverted.low == 1 assert inverted.average == 1.5 diff --git a/test/test_ids.py b/test/test_ids.py index c254b46..8872de0 100644 --- a/test/test_ids.py +++ b/test/test_ids.py @@ -20,13 +20,18 @@ VALID_IDS = [ ] -ASSETS = list(fin_defs.WELL_KNOWN_SYMBOLS.values()) + [fin_defs.Asset.from_string_id(vid) for vid in VALID_IDS] +ASSETS = list(fin_defs.WELL_KNOWN_SYMBOLS.values()) + [ + fin_defs.Asset.from_string_id(vid) for vid in VALID_IDS +] -ASSETS_POLYGON_PRESERVES_FULL_ID = frozenset(a for a in ASSETS if not isinstance(a, - fin_defs.CryptoCurrency - | fin_defs.Commodity - | fin_defs.UnknownAsset)) - frozenset([NVO]) +ASSETS_POLYGON_PRESERVES_FULL_ID = frozenset( + a + for a in ASSETS + if not isinstance( + a, fin_defs.CryptoCurrency | fin_defs.Commodity | fin_defs.UnknownAsset, + ) +) - frozenset([NVO]) INVALID_IDS = [ 'NVO', @@ -89,14 +94,17 @@ def test_to_from_polygon_id_works(asset: fin_defs.Asset): return assert fin_defs.Asset.from_polygon_id(asset.to_polygon_id()) is not None + @pytest.mark.parametrize('asset', ASSETS_POLYGON_PRESERVES_FULL_ID) def test_to_from_polygon_id_preserves_id(asset: fin_defs.Asset): assert fin_defs.Asset.from_polygon_id(asset.to_polygon_id()) == asset + def test_to_polygon_id_fail_for_commodity(): with pytest.raises(TypeError, match='Unknown type: Commodity'): assert fin_defs.Commodity.CORN.to_polygon_id() + def test_to_string_id_wrong_type(): with pytest.raises(TypeError, match='Unsupported asset type: int'): assert fin_defs.Asset.to_string_id(1)