feat: add Portfolio Value, Option Value, and Contracts columns to daily results
- Add option_contracts field to BacktestDailyPoint (number of contracts held) - Update engine to calculate total option contracts from positions - Update job serialization to include underlying_value, option_market_value, net_portfolio_value, option_contracts - Update both render_result and render_job_result tables to show: - Low, High, Close (from previous commit) - Portfolio value (net_portfolio_value) - Option value (option_market_value) - Contracts (option_contracts) - LTV hedged - Margin call status
This commit is contained in:
@@ -87,6 +87,9 @@ class SyntheticBacktestEngine:
|
|||||||
ltv_unhedged_worst = scenario.initial_portfolio.loan_amount / underlying_value_worst
|
ltv_unhedged_worst = scenario.initial_portfolio.loan_amount / underlying_value_worst
|
||||||
ltv_hedged_worst = scenario.initial_portfolio.loan_amount / net_portfolio_value_worst
|
ltv_hedged_worst = scenario.initial_portfolio.loan_amount / net_portfolio_value_worst
|
||||||
|
|
||||||
|
# Total option contracts held
|
||||||
|
option_contracts = sum(p.quantity for p in open_positions)
|
||||||
|
|
||||||
daily_points.append(
|
daily_points.append(
|
||||||
BacktestDailyPoint(
|
BacktestDailyPoint(
|
||||||
date=day.date,
|
date=day.date,
|
||||||
@@ -103,6 +106,7 @@ class SyntheticBacktestEngine:
|
|||||||
ltv_hedged=ltv_hedged,
|
ltv_hedged=ltv_hedged,
|
||||||
margin_call_unhedged=ltv_unhedged_worst >= scenario.initial_portfolio.margin_call_ltv,
|
margin_call_unhedged=ltv_unhedged_worst >= scenario.initial_portfolio.margin_call_ltv,
|
||||||
margin_call_hedged=ltv_hedged_worst >= scenario.initial_portfolio.margin_call_ltv,
|
margin_call_hedged=ltv_hedged_worst >= scenario.initial_portfolio.margin_call_ltv,
|
||||||
|
option_contracts=option_contracts,
|
||||||
active_position_ids=tuple(active_position_ids),
|
active_position_ids=tuple(active_position_ids),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -97,10 +97,12 @@ class BacktestDailyPoint:
|
|||||||
ltv_hedged: float
|
ltv_hedged: float
|
||||||
margin_call_unhedged: bool
|
margin_call_unhedged: bool
|
||||||
margin_call_hedged: bool
|
margin_call_hedged: bool
|
||||||
|
active_position_ids: tuple[str, ...] = field(default_factory=tuple)
|
||||||
# Optional OHLC fields for worst-case margin call evaluation
|
# Optional OHLC fields for worst-case margin call evaluation
|
||||||
spot_low: float | None = None # Day's low for margin call evaluation
|
spot_low: float | None = None # Day's low for margin call evaluation
|
||||||
spot_high: float | None = None # Day's high
|
spot_high: float | None = None # Day's high
|
||||||
active_position_ids: tuple[str, ...] = field(default_factory=tuple)
|
# Option position info
|
||||||
|
option_contracts: float = 0.0 # Number of option contracts held
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -154,3 +156,22 @@ class EventComparisonReport:
|
|||||||
scenario: BacktestScenario
|
scenario: BacktestScenario
|
||||||
rankings: tuple[EventComparisonRanking, ...]
|
rankings: tuple[EventComparisonRanking, ...]
|
||||||
run_result: BacktestRunResult
|
run_result: BacktestRunResult
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BacktestPortfolioPreset:
|
||||||
|
"""User-facing preset for quick scenario configuration."""
|
||||||
|
|
||||||
|
preset_id: str
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
underlying_symbol: str
|
||||||
|
start_date: date
|
||||||
|
end_date: date
|
||||||
|
entry_spot: float | None = None # If None, derive from historical data
|
||||||
|
underlying_units: float = 1000.0
|
||||||
|
loan_amount: float = 50000.0
|
||||||
|
margin_call_ltv: float = 0.80
|
||||||
|
template_slug: str = "protective-put-atm-12m"
|
||||||
|
# Event-specific overrides
|
||||||
|
scenario_overrides: dict[str, object] | None = None
|
||||||
|
|||||||
@@ -659,6 +659,24 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
{"name": "low", "label": "Low", "field": "low", "align": "right"},
|
{"name": "low", "label": "Low", "field": "low", "align": "right"},
|
||||||
{"name": "high", "label": "High", "field": "high", "align": "right"},
|
{"name": "high", "label": "High", "field": "high", "align": "right"},
|
||||||
{"name": "close", "label": "Close", "field": "close", "align": "right"},
|
{"name": "close", "label": "Close", "field": "close", "align": "right"},
|
||||||
|
{
|
||||||
|
"name": "portfolio_value",
|
||||||
|
"label": "Portfolio",
|
||||||
|
"field": "portfolio_value",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "option_value",
|
||||||
|
"label": "Option value",
|
||||||
|
"field": "option_value",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "contracts",
|
||||||
|
"label": "Contracts",
|
||||||
|
"field": "contracts",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "ltv_hedged",
|
"name": "ltv_hedged",
|
||||||
"label": "LTV hedged",
|
"label": "LTV hedged",
|
||||||
@@ -678,6 +696,9 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
"low": f"${point.spot_low:,.2f}",
|
"low": f"${point.spot_low:,.2f}",
|
||||||
"high": f"${point.spot_high:,.2f}",
|
"high": f"${point.spot_high:,.2f}",
|
||||||
"close": f"${point.spot_close:,.2f}",
|
"close": f"${point.spot_close:,.2f}",
|
||||||
|
"portfolio_value": f"${point.net_portfolio_value:,.0f}",
|
||||||
|
"option_value": f"${point.option_market_value:,.0f}",
|
||||||
|
"contracts": f"{point.option_contracts:,.0f}",
|
||||||
"ltv_hedged": f"{point.ltv_hedged:.1%}",
|
"ltv_hedged": f"{point.ltv_hedged:.1%}",
|
||||||
"margin_call": "Yes" if point.margin_call_hedged else "No",
|
"margin_call": "Yes" if point.margin_call_hedged else "No",
|
||||||
}
|
}
|
||||||
@@ -991,6 +1012,24 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
{"name": "low", "label": "Low", "field": "low", "align": "right"},
|
{"name": "low", "label": "Low", "field": "low", "align": "right"},
|
||||||
{"name": "high", "label": "High", "field": "high", "align": "right"},
|
{"name": "high", "label": "High", "field": "high", "align": "right"},
|
||||||
{"name": "close", "label": "Close", "field": "close", "align": "right"},
|
{"name": "close", "label": "Close", "field": "close", "align": "right"},
|
||||||
|
{
|
||||||
|
"name": "portfolio_value",
|
||||||
|
"label": "Portfolio",
|
||||||
|
"field": "portfolio_value",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "option_value",
|
||||||
|
"label": "Option value",
|
||||||
|
"field": "option_value",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "contracts",
|
||||||
|
"label": "Contracts",
|
||||||
|
"field": "contracts",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "ltv_hedged",
|
"name": "ltv_hedged",
|
||||||
"label": "LTV hedged",
|
"label": "LTV hedged",
|
||||||
@@ -1010,6 +1049,9 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
"low": f"${dp.get('spot_low', dp.get('spot_close', 0)):,.2f}",
|
"low": f"${dp.get('spot_low', dp.get('spot_close', 0)):,.2f}",
|
||||||
"high": f"${dp.get('spot_high', dp.get('spot_close', 0)):,.2f}",
|
"high": f"${dp.get('spot_high', dp.get('spot_close', 0)):,.2f}",
|
||||||
"close": f"${dp.get('spot_close', 0):,.2f}",
|
"close": f"${dp.get('spot_close', 0):,.2f}",
|
||||||
|
"portfolio_value": f"${dp.get('net_portfolio_value', 0):,.0f}",
|
||||||
|
"option_value": f"${dp.get('option_market_value', 0):,.0f}",
|
||||||
|
"contracts": f"{dp.get('option_contracts', 0):,.0f}",
|
||||||
"ltv_hedged": f"{dp.get('ltv_hedged', 0):.1%}",
|
"ltv_hedged": f"{dp.get('ltv_hedged', 0):.1%}",
|
||||||
"margin_call": "Yes" if dp.get("margin_call_hedged") else "No",
|
"margin_call": "Yes" if dp.get("margin_call_hedged") else "No",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ def run_backtest_job(
|
|||||||
"underlying_value": dp.underlying_value,
|
"underlying_value": dp.underlying_value,
|
||||||
"option_market_value": dp.option_market_value,
|
"option_market_value": dp.option_market_value,
|
||||||
"net_portfolio_value": dp.net_portfolio_value,
|
"net_portfolio_value": dp.net_portfolio_value,
|
||||||
|
"option_contracts": dp.option_contracts,
|
||||||
"ltv_hedged": dp.ltv_hedged,
|
"ltv_hedged": dp.ltv_hedged,
|
||||||
"ltv_unhedged": dp.ltv_unhedged,
|
"ltv_unhedged": dp.ltv_unhedged,
|
||||||
"margin_call_hedged": dp.margin_call_hedged,
|
"margin_call_hedged": dp.margin_call_hedged,
|
||||||
|
|||||||
Reference in New Issue
Block a user