feat(DATA-DB-002): add BacktestSettings model and repository
- BacktestSettings dataclass with all configuration fields - BacktestSettingsRepository for persistence per workspace - Settings independent of portfolio configuration - Full validation for dates, symbols, LTV, etc. - 16 comprehensive tests Fields: - settings_id, name: identification - data_source: databento|yfinance|synthetic - dataset, schema: Databento configuration - start_date, end_date: date range - underlying_symbol, start_price, underlying_units: position config - loan_amount, margin_call_ltv: LTV analysis - template_slugs: strategies to test - cache_key, data_cost_usd: caching metadata - provider_ref: provider configuration
This commit is contained in:
88
app/models/backtest_settings.py
Normal file
88
app/models/backtest_settings.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""Backtest settings model for configuring backtest scenarios independently of portfolio settings."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import date
|
||||
from typing import Literal
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
# Self type annotation
|
||||
from app.models.backtest import ProviderRef
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BacktestSettings:
|
||||
"""Configuration for running backtests independent of portfolio settings.
|
||||
|
||||
These settings determine what data to fetch and how to run backtests,
|
||||
separate from the actual portfolio configurations being tested.
|
||||
"""
|
||||
|
||||
settings_id: UUID
|
||||
name: str
|
||||
data_source: Literal["databento", "yfinance", "synthetic"]
|
||||
dataset: str
|
||||
schema: str
|
||||
start_date: date
|
||||
end_date: date
|
||||
underlying_symbol: Literal["GLD", "GC", "XAU"]
|
||||
start_price: float
|
||||
underlying_units: float
|
||||
loan_amount: float
|
||||
margin_call_ltv: float
|
||||
template_slugs: tuple[str, ...]
|
||||
cache_key: str
|
||||
data_cost_usd: float
|
||||
provider_ref: ProviderRef
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not self.settings_id:
|
||||
raise ValueError("settings_id is required")
|
||||
if not self.name:
|
||||
raise ValueError("name is required")
|
||||
if self.start_date > self.end_date:
|
||||
raise ValueError("start_date must be on or before end_date")
|
||||
if self.data_source not in ("databento", "yfinance", "synthetic"):
|
||||
raise ValueError("data_source must be 'databento', 'yfinance', or 'synthetic'")
|
||||
if self.underlying_symbol not in ("GLD", "GC", "XAU"):
|
||||
raise ValueError("underlying_symbol must be 'GLD', 'GC', or 'XAU'")
|
||||
if self.start_price < 0:
|
||||
raise ValueError("start_price must be non-negative")
|
||||
if self.underlying_units <= 0:
|
||||
raise ValueError("underlying_units must be positive")
|
||||
if self.loan_amount < 0:
|
||||
raise ValueError("loan_amount must be non-negative")
|
||||
if not 0 < self.margin_call_ltv < 1:
|
||||
raise ValueError("margin_call_ltv must be between 0 and 1")
|
||||
if not self.template_slugs:
|
||||
raise ValueError("at least one template slug is required")
|
||||
if self.data_cost_usd < 0:
|
||||
raise ValueError("data_cost_usd must be non-negative")
|
||||
|
||||
@classmethod
|
||||
def create_default(cls, name: str = "Default Backtest Settings") -> BacktestSettings:
|
||||
"""Create default backtest settings configuration."""
|
||||
return cls(
|
||||
settings_id=uuid4(),
|
||||
name=name,
|
||||
data_source="databento",
|
||||
dataset="XNAS.BASIC",
|
||||
schema="ohlcv-1d",
|
||||
start_date=date(2020, 1, 1),
|
||||
end_date=date(2023, 12, 31),
|
||||
underlying_symbol="GLD",
|
||||
start_price=0.0,
|
||||
underlying_units=1000.0,
|
||||
loan_amount=0.0,
|
||||
margin_call_ltv=0.75,
|
||||
template_slugs=("default-template",),
|
||||
cache_key="",
|
||||
data_cost_usd=0.0,
|
||||
provider_ref=ProviderRef(provider_id="default", pricing_mode="standard"),
|
||||
)
|
||||
|
||||
|
||||
# For backward compatibility - alias to existing models
|
||||
BacktestScenario = "app.models.backtest.BacktestScenario"
|
||||
# TemplateRef and ProviderRef imported from app.models.backtest
|
||||
Reference in New Issue
Block a user