from __future__ import annotations from dataclasses import dataclass from app.services.boundary_values import boundary_decimal @dataclass(frozen=True, slots=True) class NormalizedHistoricalScenarioInputs: underlying_units: float loan_amount: float margin_call_ltv: float currency: str = "USD" cash_balance: float = 0.0 financing_rate: float = 0.0 def normalize_historical_scenario_inputs( *, underlying_units: object, loan_amount: object, margin_call_ltv: object, currency: object = "USD", cash_balance: object = 0.0, financing_rate: object = 0.0, ) -> NormalizedHistoricalScenarioInputs: normalized_currency = str(currency).strip().upper() if not normalized_currency: raise ValueError("Currency is required") units = float(boundary_decimal(underlying_units, field_name="underlying_units")) normalized_loan_amount = float(boundary_decimal(loan_amount, field_name="loan_amount")) ltv = float(boundary_decimal(margin_call_ltv, field_name="margin_call_ltv")) normalized_cash_balance = float(boundary_decimal(cash_balance, field_name="cash_balance")) normalized_financing_rate = float(boundary_decimal(financing_rate, field_name="financing_rate")) if units <= 0: raise ValueError("Underlying units must be positive") if normalized_loan_amount < 0: raise ValueError("Loan amount must be non-negative") if not 0 < ltv < 1: raise ValueError("Margin call LTV must be between 0 and 1") return NormalizedHistoricalScenarioInputs( underlying_units=units, loan_amount=normalized_loan_amount, margin_call_ltv=ltv, currency=normalized_currency, cash_balance=normalized_cash_balance, financing_rate=normalized_financing_rate, )