feat(DATA-004): add underlying instrument selector
This commit is contained in:
@@ -7,13 +7,16 @@ import pytest
|
||||
|
||||
from app.domain.backtesting_math import AssetQuantity, PricePerAsset
|
||||
from app.domain.instruments import (
|
||||
GC_F_OUNCES_PER_CONTRACT,
|
||||
GLD_EXPENSE_DECAY_RATE,
|
||||
GLD_INITIAL_OUNCES_PER_SHARE,
|
||||
GLD_LAUNCH_YEAR,
|
||||
Underlying,
|
||||
asset_quantity_from_weight,
|
||||
gld_ounces_per_share,
|
||||
instrument_metadata,
|
||||
price_per_weight_from_asset_price,
|
||||
supported_underlyings,
|
||||
weight_from_asset_quantity,
|
||||
)
|
||||
from app.domain.units import BaseCurrency, Weight, WeightUnit
|
||||
@@ -117,3 +120,65 @@ def test_instrument_conversions_fail_closed_for_unsupported_symbols() -> None:
|
||||
|
||||
with pytest.raises(ValueError, match="Unsupported instrument metadata"):
|
||||
asset_quantity_from_weight("SLV", Weight(amount=Decimal("1"), unit=WeightUnit.OUNCE_TROY))
|
||||
|
||||
|
||||
# DATA-004: Underlying Instrument Selector tests
|
||||
|
||||
|
||||
def test_underlying_enum_has_gld_and_gc_f() -> None:
|
||||
"""Verify Underlying enum contains GLD and GC=F."""
|
||||
assert Underlying.GLD.value == "GLD"
|
||||
assert Underlying.GC_F.value == "GC=F"
|
||||
|
||||
|
||||
def test_underlying_display_names() -> None:
|
||||
"""Verify Underlying display names are descriptive."""
|
||||
assert Underlying.GLD.display_name() == "SPDR Gold Shares ETF"
|
||||
assert Underlying.GC_F.display_name() == "Gold Futures (COMEX)"
|
||||
|
||||
|
||||
def test_underlying_descriptions() -> None:
|
||||
"""Verify Underlying descriptions indicate data source status."""
|
||||
assert Underlying.GLD.description() == "SPDR Gold Shares ETF (live data via yfinance)"
|
||||
assert Underlying.GC_F.description() == "Gold Futures (coming soon)"
|
||||
|
||||
|
||||
def test_supported_underlyings_returns_all() -> None:
|
||||
"""Verify supported_underlyings() returns all available choices."""
|
||||
underlyings = supported_underlyings()
|
||||
assert len(underlyings) == 2
|
||||
assert Underlying.GLD in underlyings
|
||||
assert Underlying.GC_F in underlyings
|
||||
|
||||
|
||||
def test_gc_f_metadata() -> None:
|
||||
"""Verify GC=F instrument metadata is correct."""
|
||||
gc_f_meta = instrument_metadata("GC=F")
|
||||
|
||||
assert gc_f_meta.symbol == "GC=F"
|
||||
assert gc_f_meta.quote_currency is BaseCurrency.USD
|
||||
assert gc_f_meta.weight_per_share == Weight(amount=GC_F_OUNCES_PER_CONTRACT, unit=WeightUnit.OUNCE_TROY)
|
||||
assert gc_f_meta.weight_per_share.amount == Decimal("100") # 100 troy oz per contract
|
||||
|
||||
|
||||
def test_gc_f_contract_specs() -> None:
|
||||
"""Verify GC=F contract specifications."""
|
||||
assert GC_F_OUNCES_PER_CONTRACT == Decimal("100")
|
||||
|
||||
# 1 contract = 100 oz
|
||||
one_contract = AssetQuantity(amount=Decimal("1"), symbol="GC=F")
|
||||
weight = weight_from_asset_quantity(one_contract)
|
||||
assert weight == Weight(amount=Decimal("100"), unit=WeightUnit.OUNCE_TROY)
|
||||
|
||||
|
||||
def test_gc_f_price_per_weight_conversion() -> None:
|
||||
"""Verify GC=F price converts correctly to price per weight."""
|
||||
# GC=F quoted at $2700/oz (already per ounce)
|
||||
quote = PricePerAsset(amount=Decimal("270000"), currency=BaseCurrency.USD, symbol="GC=F") # $2700/oz * 100 oz
|
||||
|
||||
spot = price_per_weight_from_asset_price(quote, per_unit=WeightUnit.OUNCE_TROY)
|
||||
|
||||
# Should be $2700/oz
|
||||
assert spot.amount == Decimal("2700")
|
||||
assert spot.currency is BaseCurrency.USD
|
||||
assert spot.per_unit is WeightUnit.OUNCE_TROY
|
||||
|
||||
Reference in New Issue
Block a user