fix(backtest): ensure data_source is passed through all validation calls
- Pass data_source to derive_entry_spot in backtests.py - Remove default 'synthetic' value for data_source in derive_entry_spot and validate_preview_inputs - Update all tests to explicitly pass data_source parameter - Improve error message with helpful suggestion for Databento/Yahoo Finance
This commit is contained in:
@@ -260,6 +260,7 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
"GLD",
|
"GLD",
|
||||||
date.fromisoformat(DEFAULT_BACKTEST_START),
|
date.fromisoformat(DEFAULT_BACKTEST_START),
|
||||||
date.fromisoformat(DEFAULT_BACKTEST_END),
|
date.fromisoformat(DEFAULT_BACKTEST_END),
|
||||||
|
data_source="databento", # Use databento for default dates
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Fixture source may not support the default date range
|
# Fixture source may not support the default date range
|
||||||
@@ -510,6 +511,7 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
symbol,
|
symbol,
|
||||||
parse_iso_date(start_input.value, "Start date"),
|
parse_iso_date(start_input.value, "Start date"),
|
||||||
parse_iso_date(end_input.value, "End date"),
|
parse_iso_date(end_input.value, "End date"),
|
||||||
|
data_source=str(data_source_select.value),
|
||||||
)
|
)
|
||||||
except (ValueError, KeyError) as exc:
|
except (ValueError, KeyError) as exc:
|
||||||
return None, str(exc)
|
return None, str(exc)
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ class BacktestPageService:
|
|||||||
for template in self.template_service.list_active_templates(symbol)
|
for template in self.template_service.list_active_templates(symbol)
|
||||||
]
|
]
|
||||||
|
|
||||||
def derive_entry_spot(self, symbol: str, start_date: date, end_date: date, data_source: str = "synthetic") -> float:
|
def derive_entry_spot(self, symbol: str, start_date: date, end_date: date, data_source: str) -> float:
|
||||||
history = self.get_historical_prices(symbol, start_date, end_date, data_source)
|
history = self.get_historical_prices(symbol, start_date, end_date, data_source)
|
||||||
if not history:
|
if not history:
|
||||||
raise ValueError("No historical prices found for scenario window")
|
raise ValueError("No historical prices found for scenario window")
|
||||||
@@ -251,7 +251,7 @@ class BacktestPageService:
|
|||||||
loan_amount: float,
|
loan_amount: float,
|
||||||
margin_call_ltv: float,
|
margin_call_ltv: float,
|
||||||
entry_spot: float | None = None,
|
entry_spot: float | None = None,
|
||||||
data_source: str = "synthetic",
|
data_source: str,
|
||||||
) -> float:
|
) -> float:
|
||||||
normalized_symbol = symbol.strip().upper()
|
normalized_symbol = symbol.strip().upper()
|
||||||
if not normalized_symbol:
|
if not normalized_symbol:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def test_backtest_page_service_accepts_decimal_boundary_values() -> None:
|
|||||||
def test_backtest_page_service_uses_fixture_window_for_deterministic_run() -> None:
|
def test_backtest_page_service_uses_fixture_window_for_deterministic_run() -> None:
|
||||||
service = BacktestPageService()
|
service = BacktestPageService()
|
||||||
|
|
||||||
entry_spot = service.derive_entry_spot("GLD", date(2024, 1, 2), date(2024, 1, 8))
|
entry_spot = service.derive_entry_spot("GLD", date(2024, 1, 2), date(2024, 1, 8), data_source="synthetic")
|
||||||
result = service.run_read_only_scenario(
|
result = service.run_read_only_scenario(
|
||||||
symbol="GLD",
|
symbol="GLD",
|
||||||
start_date=date(2024, 1, 2),
|
start_date=date(2024, 1, 2),
|
||||||
@@ -41,6 +41,7 @@ def test_backtest_page_service_uses_fixture_window_for_deterministic_run() -> No
|
|||||||
underlying_units=1000.0,
|
underlying_units=1000.0,
|
||||||
loan_amount=68000.0,
|
loan_amount=68000.0,
|
||||||
margin_call_ltv=0.75,
|
margin_call_ltv=0.75,
|
||||||
|
data_source="synthetic",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert entry_spot == 100.0
|
assert entry_spot == 100.0
|
||||||
@@ -180,15 +181,15 @@ def test_backtest_page_service_fails_closed_outside_seeded_fixture_window() -> N
|
|||||||
|
|
||||||
# Wrong symbol raises error (fixture only supports GLD)
|
# Wrong symbol raises error (fixture only supports GLD)
|
||||||
with pytest.raises(ValueError, match="deterministic fixture data only supports GLD"):
|
with pytest.raises(ValueError, match="deterministic fixture data only supports GLD"):
|
||||||
service.derive_entry_spot("AAPL", date(2024, 1, 2), date(2024, 1, 8))
|
service.derive_entry_spot("AAPL", date(2024, 1, 2), date(2024, 1, 8), data_source="synthetic")
|
||||||
|
|
||||||
# Dates before window start raises error
|
# Dates before window start raises error
|
||||||
with pytest.raises(ValueError, match="deterministic fixture data only supports the seeded"):
|
with pytest.raises(ValueError, match="deterministic fixture data only supports the seeded"):
|
||||||
service.derive_entry_spot("GLD", date(2024, 1, 1), date(2024, 1, 5))
|
service.derive_entry_spot("GLD", date(2024, 1, 1), date(2024, 1, 5), data_source="synthetic")
|
||||||
|
|
||||||
# Dates after window end raises error
|
# Dates after window end raises error
|
||||||
with pytest.raises(ValueError, match="deterministic fixture data only supports the seeded"):
|
with pytest.raises(ValueError, match="deterministic fixture data only supports the seeded"):
|
||||||
service.derive_entry_spot("GLD", date(2024, 1, 5), date(2024, 1, 10))
|
service.derive_entry_spot("GLD", date(2024, 1, 5), date(2024, 1, 10), data_source="synthetic")
|
||||||
|
|
||||||
|
|
||||||
def test_backtest_preview_validation_requires_supported_fixture_window_even_with_supplied_entry_spot() -> None:
|
def test_backtest_preview_validation_requires_supported_fixture_window_even_with_supplied_entry_spot() -> None:
|
||||||
@@ -206,6 +207,7 @@ def test_backtest_preview_validation_requires_supported_fixture_window_even_with
|
|||||||
loan_amount=68000.0,
|
loan_amount=68000.0,
|
||||||
margin_call_ltv=0.75,
|
margin_call_ltv=0.75,
|
||||||
entry_spot=100.0,
|
entry_spot=100.0,
|
||||||
|
data_source="synthetic",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -221,6 +223,7 @@ def test_backtest_preview_validation_accepts_close_supplied_entry_spot() -> None
|
|||||||
loan_amount=68000.0,
|
loan_amount=68000.0,
|
||||||
margin_call_ltv=0.75,
|
margin_call_ltv=0.75,
|
||||||
entry_spot=100.005,
|
entry_spot=100.005,
|
||||||
|
data_source="synthetic",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert entry_spot == 100.0
|
assert entry_spot == 100.0
|
||||||
@@ -239,6 +242,7 @@ def test_backtest_preview_validation_rejects_mismatched_supplied_entry_spot() ->
|
|||||||
loan_amount=68000.0,
|
loan_amount=68000.0,
|
||||||
margin_call_ltv=0.75,
|
margin_call_ltv=0.75,
|
||||||
entry_spot=99.0,
|
entry_spot=99.0,
|
||||||
|
data_source="synthetic",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user