Commit Graph

26 Commits

Author SHA1 Message Date
claude_dev 4ad505434b feat(backtest): 个股回测接入费用(cfg通道)+slippage+benchmark放宽至4基准 [vps]
CI/CD / test (push) Successful in 11s
CI/CD / nas-deploy (push) Successful in 25s
CI/CD / nas-verify (push) Successful in 9s
2026-08-12 23:56:14 +08:00
claude_dev b66a6c5958 fix(ashare_engine): load_data 直查 dbbardata 绕 vnpy peewee(治 CTA 死算)
CI/CD / test (push) Successful in 11s
CI/CD / nas-deploy (push) Successful in 29s
CI/CD / nas-verify (push) Successful in 4m11s
根因:vnpy 父类 load_data 走 get_database().load_bar_data()(peewee ORM),
get_database init 时 create_indexes 对 26G dbbardata 库 → spawn 建 26G
索引 CPU 死算 1:27+ / web 并发 database is locked(2026-08-02 根因,
vnpy_db 指向 v2 大库 2cb2ab0 后触发)。load_data 读 0 bars → 回测空/卡。

修复:load_data 统一直查 dbbardata(原仅 5m/15m 走 _load_intraday_data,
扩展到日线 d),绕 vnpy peewee get_database。sqlite3 busy_timeout=30s
防并发锁。d → BarData(interval=Interval.DAILY)。

验证:日线 600519 2024H1 load_data 0.1s bars=116(was database locked
5.2s/0 bars) interval=DAILY;run_backtesting 5.6s(was 死算 1:27+);
000001 compute_metrics 完成 daily_df=(116,25) benchmark=116(5图metrics恢复)。
2026-08-02 21:48:33 +08:00
claude_dev c263aa14ab chore(cta_engine): 加 load_data bar数+run_backtesting logging(确诊卡点)
CI/CD / test (push) Successful in 9s
CI/CD / nas-deploy (push) Successful in 27s
CI/CD / nas-verify (push) Successful in 3s
cta_6f7e8036 日线卡 run_backtesting(CPU85%,read_index_daily 前即卡),日线111bar该秒级→疑似 load_data 读多了(vnpy_db 2cb2ab0修复后读真实dbbardata,区间过滤/interval疑失效)。加 load_data history bars 数 + run_backtesting 完成 logging,重跑看 bar 数确诊。
2026-08-02 21:21:42 +08:00
claude_dev 3d934f5fa6 chore(cta_engine): 加阶段 logging(治 spawn 子进程黑盒,定位卡死)
CI/CD / test (push) Successful in 12s
CI/CD / nas-deploy (push) Successful in 30s
CI/CD / nas-verify (push) Successful in 7s
CTA 回测走 ProcessPool spawn 子进程,cta_engine 没配 basicConfig → 回测日志不进 docker logs(卡死看不到卡哪行,反复诊断障碍)。加模块级 basicConfig + read_index_daily/compute_metrics 阶段 logging + daily_df shape。下次卡死 docker logs 可见卡段(同 portfolio_worker)。诊断 cta_8aab3823 日线卡(rolling 已修非根因)。
2026-08-02 21:14:40 +08:00
claude_dev 2ff8ecaf52 perf(metrics): rolling alpha/beta 向量化(O(n²)→O(n),治分钟级卡死)
CI/CD / test (push) Successful in 10s
CI/CD / nas-deploy (push) Successful in 29s
CI/CD / nas-verify (push) Successful in 5s
compute_metrics rolling alpha/beta 原 for 循环每点 iloc[:i+1].cov/var = O(n²)。日线 111 天没事,分钟级 daily_df(万行)卡死(cta_c287f4b5 卡 5min CPU88%)。改 pandas expanding 向量化(cov/var/mean O(n)),数值与原循环一致(beta/alpha diff<1e-15,NaN 位置匹配)。pytest 6 绿。触发:b2c41c7 降级让 compute_metrics 首次在 benchmark 有数据时真跑(此前 benchmark 空被 skip),暴露 rolling O(n²) 性能 bug。
2026-08-02 20:54:50 +08:00
claude_dev b2c41c73b8 fix(backtest): CTA metrics benchmark 缺失降级(不阻塞整组指标图)
CI/CD / test (push) Successful in 10s
CI/CD / nas-deploy (push) Successful in 42s
CI/CD / nas-verify (push) Successful in 5s
benchmark 数据缺失时原实现 if 跳过整段 compute_metrics → {task_id}_metrics.json 不写 → 策略净值/回撤/波动图也空(不只基准图)。改为:benchmark 空时传空 Series + log WARN,compute_metrics 内部 reindex→fillna(0) 容空(基准类指标 NaN→None,策略指标正常),metrics.json 照写。效果:策略图照常出,只基准/Alpha/Beta 图空(前端 benchmark-curve/risk-series 已容错)。加测试 test_run_cta_backtest_benchmark_missing_degrades(mock read_index_daily 返空 → 验 compute_metrics 仍 called + metrics.json 仍写 + 策略指标有值)。6 测试全绿(Mac pytest)。
2026-08-02 20:37:50 +08:00
claude_dev 43b6a58ba7 feat(backtest): 支持5m/15m周期回测(ashare适配绕vnpy Interval enum)
ashare_engine override load_data: 5m/15m 直查 dbbardata 转 BarData(MINUTE),
绕过 vnpy Interval enum 限制(原生只认 d/1h/1m)。cta_engine +interval 参数,
5m/15m 映射 MINUTE 过父类校验。api(schema/routes)+orchestrator 透传 interval。
顺带修 cta_engine DB路径污染(yaml NAS路径在Win VPS误解析→改读vt_setting.json)。

测试: 15m 600519一年 3888bars total_return-0.22 sharpe-2.04; 5m 11664bars; 日线未回归(237bars)。
2026-07-18 18:45:24 +08:00
claude_dev f465756499 fix(optimize): 不再为每个 combo 存独立记录,避免污染历史任务列表
cta_optimizer 每跑一个 combo 就 save_result 存一条 type=optimize 记录
(statistics 是单 combo stats,无 combos key)。每次优化额外产生 N 条子记录,
历史任务列表全是这些,点开后 optimization-results endpoint 查 combos 找不到
→ 空页面。实证 142 条 optimize 里 137 条是这种空子记录(12/12 匹配主任务 combo)。

combo 结果只在内存聚合,由 aggregate 主任务统一存 {combos:[...]}。
2026-07-17 16:01:01 +08:00
claude_dev 6ed71ed8cf fix(optimize): 参数优化端到端修复(空statistics/500/不跳页)
根因: vnpy run_optimization 孙进程 spawn re-import setting.py 重置 DB → load 0根 → 空 statistics;连带 task_id 不一致 + statistics 含 date/numpy 序列化失败 + 前端单页轮询 180s 超时。
修复(不动 vnpy 源码):
- cta_optimizer: vt_setting.json 适配(vnpy 原生机制 setting.py:43 load_json,孙进程拿到正确 DB) + task_id 贯通 + 主聚合持久化(combos) + 过滤空 statistics 记录
- result_store: _json_default(date→isoformat + numpy→原生),save_result 两处 json.dumps 加 default
- routes: optimization-results 改读 DB 主聚合, fallback 内存(重启不丢)
- runner: _opt_worker 加 task_id 参数 + submit_optimize 传递(对齐 _cta_worker)
- 前端: Optimize 提交后跳 progress;Progress 用 opt_ 前缀判断跳 optimize-result;新建 OptimizeResult 参数表格页;router 加路由
验证: 端到端 optimization-results http=200 + 4组合非空 statistics + 浏览器提交→跳 optimize-result 页表格渲染。
2026-07-17 10:58:49 +08:00
claude_dev 7fe3fb0844 fix(backtest): 结果页垃圾值/无图表端到端修复(empyrical×numpy2.0根因)
根因: empyrical 0.5.5 引用 numpy2.0 已移除的 np.NINF → compute_metrics 静默崩 → _metrics.json 不生成 → 结果页回退 vnpy 原始字段(单位混乱: total_return当百分数、max_drawdown当元 → 前端×100显 3305%/-50M%)。
- metrics.py: 导入 empyrical 前补回 np 别名(NINF/Inf/PINF/NaN/NAN/infty)
- routes.py: benchmark-curve/risk-series 缺 metrics 文件时返空200(不再404拖垮整页); get_result 从 statistics 抽 relative_metrics
- cta_engine.py: bench_df 日期 strip tz 防 pct_change 崩; metrics 块加 traceback 日志
- Result.vue: onMounted 用 Promise.allSettled 隔离7端点, 单接口失败不拖垮整页
- result_store.py: _safe_read_json 容错迁移后残留 NAS 绝对路径, stale path 不崩 list_results
- datareader.py: read_index_daily 改从 vnpy DB 读 + 前缀解析交易所(sh→SSE, 避免 000300 被 guess_exchange 误判 SZSE)
2026-07-17 08:24:01 +08:00
claude_dev b322f4e07b fix(backtest): degenerate改status=done+flag—前端status map兼容
degenerate 原为独立 status 值,但前端 statusLabelMap 只认 done/failed/running/pending,
21个零成交结果在 Dashboard 计数/History 筛选/chip 标签消失或空白。改 status='done'+
statistics.degenerate=True+reason,结果页诚实显示 0+空成交,列表/计数正常。
2026-07-13 11:56:23 +08:00
claude_dev 8d55e414fa fix(backtest): A股适配层—定寸/做空拦截/真实费用/口径统一(Phase1+2)
审计发现包装层系统性失真(2 CRITICAL+7 HIGH),vnpy底座可信但A股场景未适配:
- C1 定寸: engine.size=N(满仓手数),策略volume=1手=N股,开平对称(pos归零)
- C2 做空拦截: SHORT+OPEN拒单,long-only,SHORT+CLOSE平多允许
- H3 A股费用: AShareDailyResult重算(佣金保底5元/印花税卖方/过户费沪市)
- H4 收益口径: simple return从balance算(不再用vnpy log return喂empyrical)
- H5+口径: benchmark ffill对齐不缩样本; sizing_shares_per_lot暴露
- H7 退化检测: 零成交/空数据标degenerate不静默done
- H8 task_id: optimize/factor用uuid4(原id()内存地址)
- 静默except改warning

验证: 容器内真实vnpy DoubleMa 600000 2022-2024, total_return 1e-6→42.3%,
end_balance 100万→142万, SHORT+OPEN成交0笔, N=7800股/手.
22 backtest测试全绿(含集成测试), API健康200.
2026-07-12 23:39:45 +08:00
claude_dev 10508db11d fix(backtest): 结果页4个显示bug—成交枚举/时间/浮点精度/日志空
1. 交易详情方向/开平显原始枚举: Direction.LONG/Offset.OPEN → 买/卖、开仓/平仓/平今/平昨
   (TradesTable 加 fmtDir/fmtOff, 方向带涨跌色)
2. 交易详情时间 2024-06-25T00:00:00+08:00 → 2024-06-25 (日内带时分则保留)
3. 每日收益浮点精度 0.6533000000054017 → 0.65 (toFixed2, 涨跌色), 日期去 00:00:00
4. 日志tab硬编码"暂无日志数据": 前端接 getLog(/task/:id/log) + 后端 cta_engine 加
   stdout tee 把引擎 load/run/stats 输出落盘到 {task_id}.log (worker 进程内隔离)
   → 新回测日志 tab 显示真实引擎输出(2117字)

验证: 交易 买/开仓/2024-06-25, 收益 0.15, 日志 2117字真实内容
2026-07-11 23:31:50 +08:00
claude_dev 59da65b839 fix(backtest): 结果页指标全显"—" + 任务重启后404
两个根因:

1. relative_metrics 缺字段(routes.py): get_result 的 relative_fields 列表
   漏了 total_return/annual_return/sharpe_ratio/max_drawdown 4 个字段, 导致
   这 4 个指标永远进不了响应 → 前端 MetricCards 显"—"。补全为 11 字段。

2. 任务 task_id 不持久(runner/cta_engine): submit_cta 用 cta_{symbol}_{id(params)}
   (内存地址) 作 runner id, 而 run_cta_backtest 内部另生成 cta_{uuid} 存 DB,
   两者持久层不相交 → 重启后 pool 内存映射丢失, get_result(runner_id) 的
   load_result_by_task_id 查不到 → /result 404 → 前端指标全 0 + 图表无数据。
   改为 submit 前置生成稳定 uuid, 透传给 run_cta_backtest 复用, 使
   runner-id == DB task_id (单一 id, 重启可查)。

附: Dashboard 最近任务"策略/因子"列 min-width 150→190(长策略名不再截断)
测试: test_runner task_id 断言同步新格式
2026-07-11 22:10:48 +08:00
claude_dev f1fc18bc86 feat(backtest): 补全第5图VolatilityChart—metrics加rolling波动率时序+risk-series端点+前端接入(凑齐聚宽5图全套) 2026-07-11 15:03:30 +08:00
claude_dev 3c6f25d1b0 fix(backtest): NaN/Inf浮点→None消毒(vnpy统计+empyrical指标+时序)修JSON序列化500 2026-07-11 14:33:41 +08:00
claude_dev f7c2e2eea3 fix(backtest): benchmark全链路透传(API→runner→engine) + metrics分支用_dcfg修cfg=None导致relative_metrics空 2026-07-11 14:27:19 +08:00
claude_dev b9197a8889 feat(backtest): 回测流程集成基准对比—产出相对指标+时序json 2026-07-11 13:44:27 +08:00
claude_dev b50a0f97be feat(backtest): metrics模块—empyrical算10指标+5时序(聚宽同源口径) 2026-07-11 13:27:44 +08:00
claude_dev 54fc1b656f feat(s3): 历史任务 + 参数优化端到端跑通
- result_store.load_result_by_task_id + orchestrator.get_result DB 兜底(历史回看)
- GET /task 列表、GET /task/{id}/optimization-results
- Task.raw_result 存优化结果 list(内存)
- cta_optimizer 修同款 bug(interval d / capital 1M / vnpy DB SETTINGS)
- get_status 返回 error_msg(str 守卫)
- 前端 优化页(网格输入+轮询+结果表)、历史页(任务列表+回看)、侧栏子菜单
- 修 5 个旧 test_routes 回归;73 tests passed
- 冒烟:历史 3 任务 + 优化 9 组合
2026-07-07 06:35:54 +08:00
claude_dev 28aea67232 feat(s1): 回测核心端到端跑通(vnpy client 对齐)
- 修 submit_cta/optimize 策略字符串→类解析(get_strategy_class)
- cta_engine: worker 进程设 vnpy DB→quant_trading.db(修 0 根数据)
- equity_curve 取自 calculate_result 的 daily_df(修 get_all_daily_results 对象问题)
- kline 补 cfg(find_config_path 共享)
- 端到端冒烟通过:DoubleMaStrategy 600000 → equity111/pnl111/trades1/kline117
2026-07-07 06:21:17 +08:00
claude_dev 510f77e6ea fix(backtest): result_id 用 DB 行 id + equity/trades 落 JSON(S1.1+S1.2)
- BacktestResult 加 id;save_result 设 result.id=lastrowid(修 get_result bug)
- runner._on_done 用 result.id(getattr 兜底 FactorReport)
- cta_engine 构建 equity_curve/trades DataFrame;save 传 file_dir
- result_store parquet→JSON(去 pyarrow 依赖,本机/容器都稳)
- 16 tests passed
2026-07-07 06:06:10 +08:00
claude_dev cb220619ef feat(backtest): 接真实 CTA 策略跑通端到端回测(DoubleMaStrategy on 600000)
修复 cta_engine 在真数据上的多个 bug(Phase 2 未在真数据验证):
- interval "1d" -> "d"(vnpy Interval.DAILY.value)
- capital 0 -> 1_000_000(0 致首笔交易即爆仓,统计全 0)
- statistics 改用 calculate_statistics(df)(旧代码误用 calculate_result 拿 DataFrame)
- statistics JSON-safe(vnpy 可能含 Timestamp)
- test_cta_engine mock 匹配新流程(calculate_statistics 返回统计字典)

验证:diag_cta.py 真实回测 DoubleMaStrategy on 600000 (2024H1, 111 天)
→ 真实统计 total_return -0.017% / sharpe -1.03 / max_drawdown -2.17 / 1 trade
容器 79 tests passed。
2026-07-06 23:33:24 +08:00
claude_dev 0b86ac294d feat(backtest): cta_optimizer run_optimization wrapper 2026-07-06 11:11:32 +08:00
claude_dev a4ce3aed85 feat(backtest): cta_engine BacktestingEngine wrapper 2026-07-06 10:57:29 +08:00
claude_dev e95ab91526 feat(backtest): result_store SQLite+parquet 结果存储 2026-07-06 10:43:41 +08:00