"""Position cost calculations for premium, spread, and storage costs.""" from __future__ import annotations from decimal import Decimal from typing import Any from app.models.position import Position def calculate_effective_entry( entry_price: Decimal, purchase_premium: Decimal | None = None, ) -> Decimal: """Calculate effective entry cost including dealer premium. Args: entry_price: Spot price at entry (per unit) purchase_premium: Dealer markup over spot as percentage (e.g., 0.04 for 4%) Returns: Effective entry cost per unit """ if purchase_premium is None or purchase_premium == 0: return entry_price return entry_price * (Decimal("1") + purchase_premium) def calculate_effective_exit( current_spot: Decimal, bid_ask_spread: Decimal | None = None, ) -> Decimal: """Calculate effective exit value after bid/ask spread. Args: current_spot: Current spot price (per unit) bid_ask_spread: Expected sale discount below spot as percentage (e.g., 0.03 for 3%) Returns: Effective exit value per unit """ if bid_ask_spread is None or bid_ask_spread == 0: return current_spot return current_spot * (Decimal("1") - bid_ask_spread) def calculate_true_pnl( position: Position, current_spot: Decimal, ) -> dict[str, Any]: """Calculate true P&L accounting for premium and spread. Args: position: Position to calculate P&L for current_spot: Current spot price per unit Returns: Dict with paper_pnl, realized_pnl, effective_entry, effective_exit, entry_value, exit_value """ # Effective entry cost (includes premium) effective_entry = calculate_effective_entry(position.entry_price, position.purchase_premium) # Effective exit value (after spread) effective_exit = calculate_effective_exit(current_spot, position.bid_ask_spread) # Paper P&L (without premium/spread) paper_pnl = (current_spot - position.entry_price) * position.quantity # True P&L (with premium/spread) true_pnl = (effective_exit - effective_entry) * position.quantity # Entry and exit values entry_value = position.entry_price * position.quantity exit_value = current_spot * position.quantity return { "paper_pnl": float(paper_pnl), "true_pnl": float(true_pnl), "effective_entry": float(effective_entry), "effective_exit": float(effective_exit), "entry_value": float(entry_value), "exit_value": float(exit_value), "premium_impact": float((position.purchase_premium or 0) * entry_value), "spread_impact": float((position.bid_ask_spread or 0) * exit_value), } def get_default_premium_for_product( underlying: str, product_type: str = "default" ) -> tuple[Decimal | None, Decimal | None]: """Get default premium/spread for common gold products. Args: underlying: Underlying instrument ("GLD", "GC=F", "XAU") product_type: Product type ("default", "coin_1oz", "bar_1kg", "allocated") Returns: Tuple of (purchase_premium, bid_ask_spread) or None if not applicable """ # GLD/GLDM: ETF is liquid, minimal spread if underlying in ("GLD", "GLDM"): # ETF spread is minimal, premium is 0 return Decimal("0"), Decimal("0.001") # 0% premium, 0.1% spread # GC=F: Futures roll costs are handled separately (GCF-001) if underlying == "GC=F": return None, None # XAU: Physical gold if underlying == "XAU": defaults = { "default": (Decimal("0.04"), Decimal("0.03")), # 4% premium, 3% spread "coin_1oz": (Decimal("0.04"), Decimal("0.03")), # 1oz coins: 4% premium, 3% spread "bar_1kg": (Decimal("0.015"), Decimal("0.015")), # 1kg bars: 1.5% premium, 1.5% spread "allocated": (Decimal("0.001"), Decimal("0.003")), # Allocated: 0.1% premium, 0.3% spread } return defaults.get(product_type, defaults["default"]) # Unknown underlying return None, None