feat(CORE-002): add GLD share quote conversion seam
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
from typing import Any, Mapping
|
||||
|
||||
from app.domain.backtesting_math import PricePerAsset
|
||||
from app.domain.instruments import instrument_metadata
|
||||
from app.domain.units import BaseCurrency, Money, PricePerWeight, Weight, WeightUnit, decimal_from_float
|
||||
from app.models.portfolio import PortfolioConfig
|
||||
|
||||
@@ -42,6 +44,44 @@ def _gold_weight(gold_ounces: float) -> Weight:
|
||||
return Weight(amount=decimal_from_float(gold_ounces), unit=WeightUnit.OUNCE_TROY)
|
||||
|
||||
|
||||
def _safe_quote_price(value: object) -> float:
|
||||
try:
|
||||
parsed = float(value)
|
||||
except (TypeError, ValueError):
|
||||
return 0.0
|
||||
if parsed <= 0:
|
||||
return 0.0
|
||||
return parsed
|
||||
|
||||
|
||||
def resolve_portfolio_spot_from_quote(
|
||||
config: PortfolioConfig,
|
||||
quote: Mapping[str, object],
|
||||
*,
|
||||
fallback_symbol: str | None = None,
|
||||
) -> tuple[float, str, str]:
|
||||
configured_price = float(config.entry_price or 0.0)
|
||||
quote_price = _safe_quote_price(quote.get("price"))
|
||||
quote_source = str(quote.get("source", "unknown"))
|
||||
quote_updated_at = str(quote.get("updated_at", ""))
|
||||
quote_symbol = str(quote.get("symbol", fallback_symbol or "")).strip().upper()
|
||||
quote_unit = str(quote.get("quote_unit", "")).strip().lower()
|
||||
|
||||
if quote_price <= 0 or not quote_symbol or quote_unit != "share":
|
||||
return configured_price, "configured_entry_price", ""
|
||||
|
||||
try:
|
||||
metadata = instrument_metadata(quote_symbol)
|
||||
except ValueError:
|
||||
return configured_price, "configured_entry_price", ""
|
||||
|
||||
converted_spot = metadata.price_per_weight_from_asset_price(
|
||||
PricePerAsset(amount=decimal_from_float(quote_price), currency=BaseCurrency.USD, symbol=quote_symbol),
|
||||
per_unit=WeightUnit.OUNCE_TROY,
|
||||
)
|
||||
return _decimal_to_float(converted_spot.amount), quote_source, quote_updated_at
|
||||
|
||||
|
||||
def portfolio_snapshot_from_config(config: PortfolioConfig | None = None) -> dict[str, float]:
|
||||
if config is None:
|
||||
gold_weight = Weight(amount=Decimal("1000"), unit=WeightUnit.OUNCE_TROY)
|
||||
|
||||
Reference in New Issue
Block a user