"""策略领域实体(M8.3,v2 §17/§5.3)。 Strategy = 完整策略定义(universe + factors + selection + rebalance + costs + portfolio,除回测区间 period 外),保存为命名资产;回测时补 period 展开为 ResearchSpec(v2 §18 Research Specification 为统一契约,策略是其持久化形态)。 """ from __future__ import annotations from datetime import date, datetime from pydantic import BaseModel, Field from app.domain.entities.research import ( CostSpec, FactorSpec, PortfolioSpec, SelectionSpec, UniverseSpec, ) class StrategyDefinition(BaseModel): id: str = "" name: str = Field(min_length=1, max_length=64) description: str = "" spec_type: str = Field(default="backtest", pattern="^(backtest|factor_test)$") universe: UniverseSpec = UniverseSpec() price_adjustment: str = Field(default="none", pattern="^(none|qfq)$") factors: list[FactorSpec] = Field(min_length=1) selection: SelectionSpec = SelectionSpec() rebalance: str = Field(default="monthly", pattern="^(weekly|monthly)$") costs: CostSpec = CostSpec() portfolio: PortfolioSpec = PortfolioSpec() version: str = "1" created_at: datetime | None = None def to_research_spec(self, period: tuple[date, date], initial_capital: float | None = None): """补全回测区间/资金后展开为标准 ResearchSpec(可在 Job/回测执行)。""" from app.domain.entities.research import ResearchSpec return ResearchSpec( type=self.spec_type, universe=self.universe, price_adjustment=self.price_adjustment, factors=self.factors, selection=self.selection, rebalance=self.rebalance, period=period, costs=self.costs, portfolio=self.portfolio, initial_capital=initial_capital if initial_capital else 1_000_000.0, )