fix(CORE-001D3A): accept decimal boundary inputs
This commit is contained in:
@@ -7,9 +7,9 @@ from decimal import Decimal
|
||||
from typing import Mapping
|
||||
|
||||
from app.domain.portfolio_math import build_alert_context
|
||||
from app.domain.units import decimal_from_float
|
||||
from app.models.alerts import AlertEvent, AlertHistoryRepository, AlertStatus
|
||||
from app.models.portfolio import PortfolioConfig
|
||||
from app.services.boundary_values import boundary_decimal
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@@ -22,48 +22,25 @@ class AlertEvaluationInput:
|
||||
email_alerts_enabled: bool
|
||||
|
||||
|
||||
def _decimal_from_boundary_value(value: object, *, field_name: str, default: float = 0.0) -> Decimal:
|
||||
if value is None:
|
||||
return decimal_from_float(float(default))
|
||||
if isinstance(value, bool):
|
||||
raise TypeError(f"{field_name} must be numeric, got bool")
|
||||
if isinstance(value, int):
|
||||
parsed = float(value)
|
||||
elif isinstance(value, float):
|
||||
parsed = value
|
||||
elif isinstance(value, str):
|
||||
stripped = value.strip()
|
||||
if not stripped:
|
||||
parsed = float(default)
|
||||
else:
|
||||
try:
|
||||
parsed = float(stripped)
|
||||
except ValueError as exc:
|
||||
raise ValueError(f"{field_name} must be numeric, got {value!r}") from exc
|
||||
else:
|
||||
raise TypeError(f"{field_name} must be numeric, got {type(value)!r}")
|
||||
return decimal_from_float(float(parsed))
|
||||
|
||||
|
||||
def _normalize_alert_evaluation_input(
|
||||
config: PortfolioConfig,
|
||||
portfolio: Mapping[str, object],
|
||||
) -> AlertEvaluationInput:
|
||||
return AlertEvaluationInput(
|
||||
ltv_ratio=_decimal_from_boundary_value(
|
||||
portfolio.get("ltv_ratio", 0.0),
|
||||
ltv_ratio=boundary_decimal(
|
||||
portfolio.get("ltv_ratio"),
|
||||
field_name="portfolio.ltv_ratio",
|
||||
),
|
||||
spot_price=_decimal_from_boundary_value(
|
||||
portfolio.get("spot_price", 0.0),
|
||||
spot_price=boundary_decimal(
|
||||
portfolio.get("spot_price"),
|
||||
field_name="portfolio.spot_price",
|
||||
),
|
||||
updated_at=str(portfolio.get("quote_updated_at", "")),
|
||||
warning_threshold=_decimal_from_boundary_value(
|
||||
warning_threshold=boundary_decimal(
|
||||
config.ltv_warning,
|
||||
field_name="config.ltv_warning",
|
||||
),
|
||||
critical_threshold=_decimal_from_boundary_value(
|
||||
critical_threshold=boundary_decimal(
|
||||
config.margin_threshold,
|
||||
field_name="config.margin_threshold",
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user