fix(backtest): benchmark全链路透传(API→runner→engine) + metrics分支用_dcfg修cfg=None导致relative_metrics空
This commit is contained in:
@@ -75,7 +75,8 @@ async def submit_cta(req: CtaBacktestRequest):
|
||||
params=req.params,
|
||||
start=req.start,
|
||||
end=req.end,
|
||||
cfg=None
|
||||
cfg=None,
|
||||
benchmark=req.benchmark
|
||||
)
|
||||
return {"task_id": tid}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ def guess_exchange(symbol: str) -> Exchange:
|
||||
return Exchange("SSE")
|
||||
|
||||
|
||||
def run_cta_backtest(strategy_class, symbol: str, params: dict, start: str, end: str, cfg, db_path: str) -> BacktestResult:
|
||||
def run_cta_backtest(strategy_class, symbol: str, params: dict, start: str, end: str, cfg, db_path: str, benchmark: str = "hs300") -> BacktestResult:
|
||||
"""
|
||||
Run CTA strategy backtest using vnpy_ctastrategy BacktestingEngine.
|
||||
|
||||
@@ -98,6 +98,9 @@ def run_cta_backtest(strategy_class, symbol: str, params: dict, start: str, end:
|
||||
|
||||
# Configure vnpy DB → A-share quant_trading.db. Worker process (spawn)
|
||||
# doesn't inherit main-process SETTINGS, so set before engine.load_data.
|
||||
# _dcfg is also reused by the metrics branch (benchmark data_paths) since the
|
||||
# cfg param can be None when called via the API.
|
||||
_dcfg = None
|
||||
try:
|
||||
from vnpy.trader.setting import SETTINGS
|
||||
from sanguo_data.config import load_config, find_config_path
|
||||
@@ -129,16 +132,17 @@ def run_cta_backtest(strategy_class, symbol: str, params: dict, start: str, end:
|
||||
if not isinstance(daily_df.index, pd.DatetimeIndex):
|
||||
daily_df.index = pd.to_datetime(daily_df.index)
|
||||
|
||||
# Get benchmark config (default hs300)
|
||||
benchmark_key = getattr(cfg, "benchmark", "hs300") if hasattr(cfg, "benchmark") else "hs300"
|
||||
benchmark_code = BENCHMARK_SYMBOL.get(benchmark_key, "sh000300")
|
||||
# Get benchmark code (default hs300) + a cfg that has data_paths.
|
||||
# _dcfg is the loaded config; fall back to the passed cfg if loading failed.
|
||||
benchmark_code = BENCHMARK_SYMBOL.get(benchmark, "sh000300")
|
||||
bench_cfg = _dcfg if (_dcfg is not None and hasattr(_dcfg, "data_paths")) else cfg
|
||||
|
||||
# Load benchmark data
|
||||
start_date = start_dt if isinstance(start_dt, datetime) else datetime.strptime(start, "%Y-%m-%d")
|
||||
end_date = end_dt if isinstance(end_dt, datetime) else datetime.strptime(end, "%Y-%m-%d")
|
||||
|
||||
try:
|
||||
bench_df = read_index_daily(benchmark_code, start_date, end_date, cfg)
|
||||
bench_df = read_index_daily(benchmark_code, start_date, end_date, bench_cfg)
|
||||
if bench_df is not None and not bench_df.empty and "close" in bench_df.columns:
|
||||
# Calculate benchmark daily returns
|
||||
bench_df["date"] = pd.to_datetime(bench_df["date"])
|
||||
|
||||
@@ -30,7 +30,7 @@ class Orchestrator:
|
||||
await self._on_stage(task_id, stage)
|
||||
|
||||
async def submit_cta(self, strategy_class, symbol: str, params: dict,
|
||||
start: str, end: str, cfg) -> str:
|
||||
start: str, end: str, cfg, benchmark: str = "hs300") -> str:
|
||||
"""Submit a CTA backtesting task asynchronously"""
|
||||
task_id = f"cta_{symbol}_{id(params)}"
|
||||
self.pool.submit(task_id, "cta")
|
||||
@@ -40,14 +40,15 @@ class Orchestrator:
|
||||
params=params,
|
||||
start=start,
|
||||
end=end,
|
||||
cfg=cfg
|
||||
cfg=cfg,
|
||||
benchmark=benchmark
|
||||
)
|
||||
await self._notify_stage(task_id, "排队中")
|
||||
|
||||
spec = self._pending[task_id]
|
||||
fut: Future = self.pool.submit_work(
|
||||
task_id, _cta_worker, spec["strategy_class"], spec["symbol"],
|
||||
spec["params"], spec["start"], spec["end"], spec["cfg"], self.db_path
|
||||
spec["params"], spec["start"], spec["end"], spec["cfg"], spec["benchmark"], self.db_path
|
||||
)
|
||||
|
||||
task = self.pool.get_task(task_id)
|
||||
@@ -164,10 +165,10 @@ class Orchestrator:
|
||||
|
||||
|
||||
# Module-level worker functions (must be top-level for ProcessPoolExecutor pickle)
|
||||
def _cta_worker(strategy_class, symbol: str, params: dict, start: str, end: str, cfg, db_path: str) -> any:
|
||||
def _cta_worker(strategy_class, symbol: str, params: dict, start: str, end: str, cfg, benchmark: str, db_path: str) -> any:
|
||||
"""Worker for CTA backtest (lazy import, spawn-friendly)"""
|
||||
from sanguo_backtest.cta_engine import run_cta_backtest
|
||||
return run_cta_backtest(strategy_class, symbol, params, start, end, cfg, db_path)
|
||||
return run_cta_backtest(strategy_class, symbol, params, start, end, cfg, db_path, benchmark=benchmark)
|
||||
|
||||
|
||||
def _opt_worker(strategy_class, symbol: str, grid: dict, start: str, end: str, cfg, db_path: str) -> any:
|
||||
|
||||
Reference in New Issue
Block a user