claude_dev
|
e807bed09c
|
fix(portfolio): all_weather 小盘池码 + fq 口径 + stop_loss 日志
- all_weather:
- s_stocks 399101.XSHE → 000852.XSHG(中证1000)。旧码在 constituent_unified
无数据,分支C(小盘轮动)完全 dead(S_mean 恒 0)= 业绩差主因。
- stop_loss -8% logger.debug → info(原 INFO 不可见,无法验收该分支)。
- big/bm/small 阈值验证用放宽(适配年报口径+中证1000,最终业务决策再说):
small roe>0.15&roa>0.10 → roe>0.05&roa>0.02(原 roa>0.10 命中仅~5%)。
- runner_backtest: build_broker_facade_inner 注入 set_option 委托 bullet_trade
settings + initialize 顺序改(先注入 broker 再 initialize)。修 fq 口径不一致
(engine fq_mode=none raw vs get_current_data fq=pre)致大盘市价保护价<当前价不成交。
修后 all_weather 2022-2024 全量验证(726交易日,max-pool 50):
总收益 0.82%→15.48%,夏普 -0.16→+0.04,回撤 -27%→-23%。
全分支跑通:月度调仓36 / 分支A无敌行情2月 / 分支C小盘活了(末日全仓小盘) /
stop_loss -8% 触发111次。
|
2026-07-24 11:27:25 +08:00 |
|
claude_dev
|
0ef0cadaff
|
fix(portfolio): provider 基本面前视偏差修复 + ETF paused + roic 接入
- local_parquet_provider: 新增 _latest_published_annual(NOTICE_DATE<=date +
年报口径),替旧 _latest_row_before(REPORT_DATE)。修复两个 bug:
1) 前视偏差:旧按报告期过滤会用未披露年报(如 3/31 取上年报,4 月才披露);
2) 周期错配:income/balance 各自取最新致 NP(年)÷权益(季)垃圾值。
income/balance 统一走该 helper → 同报告期 + 无前视。
另:roic 接 calc_roic,_num(v==v)排 NaN 修 g() 对 NaN truthy 问题。
- local_unified_provider: get_price 缺失字段 paused 补 False / high·low_limit
按 close±10% 估,修 bool(NaN)=True 被 bullet_trade get_current_data 误判
停牌致 _process_orders cancel 所有 ETF 订单(0 交易)。
实证:roe/roa 跨时点一致(p50 从 0.016/0.064 不一致 → 0.074/0.070/0.065)。
|
2026-07-24 11:26:56 +08:00 |
|
claude_dev
|
e7465c342f
|
feat(data): 中证1000/2000 定期更新 schtask + schtask 路径坑修复
sanguo-index 增强: index_monthly_wrapper 加 STEP0 parse_csindex_announce
(治偏差全集, 月度16号自动刷新 constituent_unified)
register_akshare_schtasks 修 PowerShell schtasks /tr 反斜杠路径丢前缀坑:
$ws 变量在双引号被原生命令解析吃掉 -> Arguments 存成 \xxx.ps1 ->
schtasks /run 返回成功但 wrapper 静默不跑从不写日志。改全路径硬编码 + --%。
ak-* 5 schtask 路径全坏已批量修(register_akshare 旧版"已部署Ready"是假成功)。
诊断: Get-ScheduledTask 中文Win报 0x80070057 无用, 改 schtasks /query /xml
看 Arguments 才发现丢前缀。
schtask 全链路验证 STEP0-3 exit=0, constituent_unified
000852=1672(was_removed=672) / 932000=2684(684) 治偏差保持。
|
2026-07-24 00:20:36 +08:00 |
|
claude_dev
|
d5582fd6f2
|
fix(migrate): deep glob 排除 *_announce_union.parquet(不同 schema)
deep union 段 glob '*_union.parquet' 误匹配 000852_announce_union.parquet/
932000_announce_union.parquet, 它们无 in_current/was_removed 列(用 adjust_type)
-> KeyError 崩溃。显式 skip _announce_union.parquet 文件。
VPS 验证通过:
- 000852: 1672 rows (in_current=1000, was_removed=672)
- 932000: 2684 rows (in_current=2000, was_removed=684)
- 000300/000905/000016/399001 行数不变(回归 OK)
|
2026-07-23 23:50:03 +08:00 |
|
claude_dev
|
b237c2d7e7
|
fix(data): 中证1000/2000 历史成份股补全(parse+migrate 聚合)
parse_csindex_announce.py 3 处修复:
- 932000 launch xlsx header 定位"证券代码"列(原 row[0]=指数代码 bug, distinct=1)
- 000852 列表搜索用 indexCode payload 精准拉(28 -> 96 公告, 回溯到 2016)
- akshare current snapshot header 定位"成分券代码"列(原 iloc[0]=日期 bug, current=0)
migrate_constituent.py:
- 加 _read_announce_union_aggregated(): 000852/932000 用 announce_union 全集
替换原 snapshot-only 路径, was_removed 治幸存者偏差
- 缺 announce_union 时回退旧 snapshot 逻辑(向后兼容)
TDD: tests/portfolio/test_migrate_announce_union.py 7 测全过(5 unit + 2 integration)
Mac 产出验证:
- 000852: distinct 1220 -> 1672, was_removed 0 -> 672
- 932000: distinct 1 -> 2684(launch 修复), was_removed 0 -> 684
|
2026-07-23 23:45:55 +08:00 |
|
claude_dev
|
114a69e997
|
fix(data): dbbardata 日线双行根治(统一纯日期+helper,留ROWID max去重)
根因: dbbardata UNIQUE(symbol,exchange,interval,datetime) 按字符串字面比较,
多写入路径混用 'YYYY-MM-DD' 与 'YYYY-MM-DD 00:00:00' -> 同一交易日双行,
INSERT OR REPLACE 不去重 -> 回测交易日翻倍/pivot duplicate/信号异常。
方案A (统一纯日期, 详见 Main Agent 诊断):
- 新增 scripts/data_platform/dbbardata_utils.py: normalize_daily_dt(s)
取前 10 字符, None/短串安全
- 4 个日线写入脚本写入前调 helper:
- bs_eod.py (sanguo-bs-eod 个股日线 baostock)
- migrate_daily_baostock.py (历史迁移)
- xt_eod.py (sanguo-xt-eod ETF/基金 xtata)
- import_vnpy_daily_fast.py (NAS 日线 parquet 导入, 加防御)
- TDD: tests/data_platform/test_dbbardata_utils.py 9 cases 全过
- 回归: tests/data_platform + tests/portfolio 199 passed 12 skipped
peewee DateTimeField formats 含 '%Y-%m-%d' (阶段0 VPS 实测确认),
读纯日期不崩, 方案A 前提成立。
15min 干净, 不动 (分钟必须带时分)。只改日线 interval='d'。
数据层根治, 不在 provider 适配兜底 (用户铁律)。
|
2026-07-23 12:18:41 +08:00 |
|
claude_dev
|
4c2af8ff00
|
fix(data): verify_akshare_e2e 修正事件类路径(data/static/<type> 非 events/)
akshare_static_download 全类型(含 per-date 龙虎榜/大宗/两融/解禁 + per-period 预告/快报)
都落 data/static/<type>/, 非 data/events/; 合并为单一 static 检查(13 类型)
|
2026-07-23 09:06:00 +08:00 |
|
claude_dev
|
28d1606947
|
feat(data): akshare 低频 5 schtask wrapper+register+verify(spec §14.5 A+B/C)
5 wrapper(ak_eod daily19:00估值+财务摘要/ak_quarter财报季三表+预告快报/
ak_events daily19:30龙虎榜+大宗+两融+解禁 per-date当日/ak_stock weekly周六
北向+股本+十大股东/index_monthly 16号成份股3源+migrate+merge)+register_akshare
_schtasks(/m APR,MAY,SEP,NOV财报季)+verify_akshare_e2e; 均unset proxy+夜间避封IP
|
2026-07-23 09:04:01 +08:00 |
|
claude_dev
|
48c67d05d2
|
fix(data): 成份股 merge/migrate pipeline 可重跑(idempotent, 读 bs_index_constituent_old)
|
2026-07-23 09:04:00 +08:00 |
|
claude_dev
|
ae3a768091
|
docs(data): akshare 低频 schtask plan(spec §14.5 A+B+C)
spec §14.5 akshare/index 低频 schtask 部署 plan, 待 compact 后新 session 执行:
- A 三表/估值增量(sanguo-ak-eod 日频 + ak-quarter 季频, --force 全量夜间慢跑)
- B 成份股月度(sanguo-index, 改 merge_constituent 可重跑 DROP/REPLACE + 3源wrapper + TDD)
- C 事件类 7 种(ak-events per-date 日频 + ak-stock per-stock 周频)
实测现状: static 停 7/22 18:25(provider依赖) / events 全空(从未采集) /
constituent_unified 7110 静态 / 旧 schtask 全无(方案A stop_all 清了)
关键约束: akshare marker symbol级→三表/估值必须--force更新 / per-stock全量慢+东财限流→夜间 /
merge_constituent RENAME不可重跑→改幂等
plan 自包含(fresh agent 可执行), 关联 memory akshare-low-freq-plan
|
2026-07-23 08:49:56 +08:00 |
|
claude_dev
|
41cc6d13bf
|
feat(portfolio): LocalUnifiedProvider spec §6 使用层落地 + VPS E2E(Task6)
spec §6 使用层 provider — 读方案A 权威数据层, 零 online, 治幸存者偏差:
- get_price: dbbardata('d') raw + bs_adjust_factor 前复权(asof, qfq[t]=raw[t]*factor[t])
- get_index_stocks/get_constituent: constituent_unified 并集治偏差(300=940含被踢, 无date时点)
- get_fundamentals_df: baostock pe/pb/ps/pcf + akshare 市值 + 三表委托 LocalParquetProvider
- 辅助: trade_days/security_info/current_tick/split_dividend/all_securities
VPS E2E 实证修复(Mac fixture 盲区):
- dbbardata datetime 混合格式("2024-09-26" vs "2024-09-26 00:00:00")
→ pd.to_datetime format='mixed' + SQL substr(datetime,1,10) 比日期(字符串比漏边界)
- 补 TestMixedDatetimeFormat 单测覆盖
验证: VPS 真数据 E2E 全通过(600519在市raw/qfq复权/000005退市治偏差/510300ETF/
fundamentals市值+pe+eps全字段/辅助方法); Mac 37单测+149回归绿
交付: 使用说明 docs/portfolio_local_unified_provider.md(其他 session 直用)+
plan+probe+E2E 脚本
|
2026-07-23 08:25:44 +08:00 |
|
claude_dev
|
b89eb0f941
|
feat(portfolio): 接线 LocalUnifiedProvider 到 runner(Task5)
|
2026-07-23 08:13:32 +08:00 |
|
claude_dev
|
9243f86773
|
feat(portfolio): LocalUnifiedProvider 辅助方法(Task4)
|
2026-07-23 08:12:34 +08:00 |
|
claude_dev
|
011c9d4ddb
|
feat(portfolio): LocalUnifiedProvider fundamentals baostock估值+akshare市值(Task3)
|
2026-07-23 08:11:35 +08:00 |
|
claude_dev
|
b46a0c26c8
|
feat(portfolio): LocalUnifiedProvider 成份股并集治偏差(Task2)
|
2026-07-23 08:07:37 +08:00 |
|
claude_dev
|
4b4dca2f44
|
feat(portfolio): LocalUnifiedProvider get_price+前复权(Task1)
|
2026-07-23 08:06:45 +08:00 |
|
claude_dev
|
e12c66acd5
|
feat(portfolio): LocalUnifiedProvider 代码转换+复权因子(Task0)
|
2026-07-23 08:05:09 +08:00 |
|
claude_dev
|
c2a89d01a4
|
feat(data): 方案A 数据层落地(spec §14)— DB唯一表+治幸存者偏差+权威源
spec §14 方案A 数据层迁移完成 + E2E 验证(read_db_daily: 在市/退市治偏差/ETF 全OK):
- dbbardata('d') 1826万含退市(治回测幸存者偏差, INSERT OR REPLACE staging迁移, WHERE OHLC NOT NULL+COALESCE)
- constituent_unified 7110行/9指数(300/500/50 baostock全集 + 深证4指 akshare cni union + 中证1000/2000 snapshot)
- pe/pb 不进DB -> valuation_baostock/<year>.parquet 按年宽表(2003-2026)
- 废弃 daily_baostock_full/bs_index_constituent(rename _old 保留); 旧4 schtask disabled
- 新 schtask sanguo-bs-eod 18:05(baostock个股日线+15min+拆pe/pb DAILY_LIMIT 48000) + sanguo-xt-eod 18:40(ETF/基金xtata)
- 权威源: baostock个股日线+估值+15min+复权+300/500/50 / xtata ETF+基金+当天实时 / akshare三表+事件+深证中证成份股
- 全程备份+staging+_old保留可回滚; 脚本 audit/probe/migrate/merge/cleanup/fix_config/verify/bs_eod/xt_eod/wrapper/register_schtasks
- 待办(spec §6 使用层): LocalParquetProvider 接 constituent_unified+valuation_baostock + 实时拼接
|
2026-07-23 07:20:34 +08:00 |
|
claude_dev
|
b270faf4b9
|
feat(portfolio): 本地数据 provider 层(baostock/local_parquet)
- BaostockProvider: 读 VPS daily_baostock_full(本地,不调online,守 provider-local-data-only 铁律)
- LocalParquetProvider: 读 parquet 兜底,回测117交易日0.4s/月出JSON
- all_weather 策略 + runner_backtest 适配
- 数据源融合使用层(单 Provider 内部路由,见 data-fusion spec §6)
|
2026-07-22 10:35:23 +08:00 |
|
claude_dev
|
774170ec05
|
feat(data): 数据源融合 P0 补全 + 每日增量脚本
采集层(多源各下):
- baostock: 日线全字段全量(baostock_daily_fullmarket) + 15min全市场 + 静态(基础/复权/分红/季频/三表) + 成份股
- akshare: 静态(估值/龙虎榜/大宗/融资融券/北向/指数成分/行业/股本/解禁/业绩预告)
- xtdata(miniQMT): build_daily_from_xtdata + daily_update_xtdata
数据补全 P0:
- ETF全市场: universe 扩展 沪深A股∪ETF∪基金(7414), dividend_type='front' 前复权
- 历史成份股(治幸存者偏差): index_const_hist_download 深证/国证 adjust_cni 4指数 + 中证1000/2000快照 + 新浪交叉校验
- 退市K线: baostock_delisted_download + import_delisted_to_db(实证 Day1 fetch_all_stocks 已含退市)
灌库:
- import_baostock_to_db: daily_baostock_full(5537股/1826万行,18字段)+ bs_index_constituent + bs_adjust_factor
- INSERT OR REPLACE 幂等, WAL+busy_timeout, dbbardata 不碰
每日增量 #7(用户决策A: VPS直跑):
- daily_update_static: login探针防黑名单graceful skip + LOOKBACK7 + query_stock_basic含退市 + INSERT OR REPLACE + QUERY_COUNT守48000/天
设计文档: spec(13节三层融合) + P0 plan + 数据gap设计
|
2026-07-22 10:34:22 +08:00 |
|
claude_dev
|
c4042a50d1
|
fix(portfolio): routes_portfolio 本地/SSH 自动检测(VPS后端405修复)
VPS 后端(schtasks sanguo-api → run_web.py)独立部署,之前没同步 routes_portfolio
致前端调 /api/v1/portfolio/backtest 报 405 Method Not Allowed。
- routes_portfolio 加本地/SSH 自动检测:os.path.isdir(_VPS_WORKDIR) 判定
(VPS 有 C:\sanguo_vnpy_v2 → 本地直接 subprocess 跑 runner;Mac 无 → SSH 到 VPS)
避免 VPS 后端 SSH 自连外网 IP 绕路,无需 env 配置同源两端自适应
- VPS 端同步 routes_portfolio.py + app.py 注册 portfolio_router + 重启 schtasks
- 验证:POST /api/v1/portfolio/backtest 从 405 → 401(路由注册成功,verify_token 生效)
|
2026-07-19 08:18:53 +08:00 |
|
claude_dev
|
f074a6b420
|
fix(portfolio): provider download加threading超时防御+Layer1链路闭环
xtdata.download_financial_data 阻塞无超时,休市/服务不响应卡死整个回测
(实证:周六休市HS300全成分首次download卡死,已缓存股票0.5s)。
包threading+join(120s)超时跳过读缓存(数据不全但回测不卡死)。
Layer1 MVP链路完整闭环:runner→BulletTrade engine→AllWeather策略→miniQMT→JSON
(7.49%收益/37交易日/选股5只ETF/净值37点/指标total_return+sharpe+max_drawdown全有)。
休市致股票财务空走ETF兜底,策略数值无意义但链路100%通;周一download恢复走真实选股。
|
2026-07-18 22:31:58 +08:00 |
|
claude_dev
|
b38ac3efd1
|
fix(portfolio): 前端回测MVP链路5处bug(VPS同步/routes命令/max-pool/filter/日期)
Layer1-3 链路验证发现并修复:
1. VPS runner_backtest旧版(tar同步,修 from bullet_trade.core import BacktestEngine ImportError)
2. routes shlex.quote对Windows路径产POSIX单引号cmd不认 -> 手动拼远端命令
3. routes 'set X=Y &&' 尾空格进value致bullet_trade provider名匹配失败 -> 删set(runner自带setdefault)
4. 加 --max-pool 参数(默认前端30)避免HS300+中小综指1258只基本面下载超时
5. filter_st/filter_new对全成分逐只 -> max_pool slice提前到filter前;
_coerce_datetime加YYYYMMDD解析(原fromisoformat不认miniQMT日期格式)
|
2026-07-18 22:16:08 +08:00 |
|
claude_dev
|
96b1924fd5
|
feat: 实盘模拟(live) + 组合回测MVP(portfolio)
[live] 实盘模拟 vnpy+miniQMT 直连(supervisor 轮询, 前后端):
- sanguo_live: LiveTradingEngine + AShareCtaTemplate(定寸/禁做空) + runner_supervisor(DB驱动) + persistence(4表WAL)
- sanguo_api/routes_live: 9路由(create/start/stop/positions/trades/account/status)
- frontend live: New/List/Monitor + api/live.ts; config/live.yaml
[portfolio] 组合回测 MVP(BulletTrade, 链路代码完成待验证):
- runner_backtest 加 JSON 入口(--json, BacktestEngine 顶层 import)
- sanguo_api/routes_portfolio: POST /portfolio/backtest SSH 触发 VPS 跑
- frontend PortfolioBacktest.vue + api/portfolio.ts: 表单+结果+净值曲线
- 路由/菜单注册(/backtest/portfolio 组合回测)
- 已知: MVP 链路未端到端验证, agent 改至中途被停; 待 Mac 起服务联调
|
2026-07-18 20:04:16 +08:00 |
|
claude_dev
|
a68cf4905e
|
feat(portfolio): sanguo_portfolio 组合策略框架(BulletTrade+miniQMT,不用jqdatasdk)
把聚宽"全天候轮动"(post48819)搬到 BulletTrade。融合=pip+扩展点注入
(SanguoMiniQmtProvider 继承 MiniQMTProvider 只 override get_fundamentals,
set_data_provider 公开 API 注入, BulletTrade 源码 0 改动)。
- providers: SanguoMiniQmtProvider 补 get_fundamentals(PershareIndex+自算PE/PS/PB/PCF/市值/ROIC)
- strategies/all_weather: 4选股函数+大小盘轮动+ETF兜底+涨停止损(聚宽风格翻译)
- factors(估值/ROIC自算) + filters(ST/涨跌停/次新/停牌)
- 88/88 测试 Mac+VPS 双过; VPS 回测 pipeline 跑通(修9bug:Capital单位/日期格式/百分数口径/11字段alias)
- 实盘 runner_live+runbook 就绪等交易日; DEFAULT_DATA_PROVIDER=miniqmt env 不装 jqdatasdk
- 文档: sanguo_portfolio_plan / portfolio_backtest_result / portfolio_live_runbook
|
2026-07-18 19:08:18 +08:00 |
|
claude_dev
|
723e42ab36
|
feat(frontend): 回测页加K线周期选择器(日线/5m/15m)
New.vue 加K线周期radio(日线d/5m/15m,默认d),backtest.ts CtaSubmit加interval字段。
提交body传interval(后端已支持5m/15m回测)。默认d向后兼容。
|
2026-07-18 18:47:33 +08:00 |
|
claude_dev
|
ee27313644
|
feat(data): 全市场5m/15m下载+灌库+每日增量链
xtdata逐只下载(非批量download_history_data2,后者5201只触发xtquant死锁),
先5m后15m(15m依赖5m),看get bars判成败(ret=None正常非失败)。
download_15m_xtdata.py + relaunch_15m_wrapper.ps1(auto-restart兜底segfault)。
import_vnpy_minute_fast.py灌库(INSERT OR REPLACE,interval存5m/15m,8028万行)。
_run_daily.ps1加5m/15m增量段(每天16:30)。validate_import.py校验。
全市场5201只,5m 6020万/15m 2007万bar,2025-07-17~2026-07-17。
|
2026-07-18 18:45:24 +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
|
d6162d1928
|
fix(factor): 因子任务持久化到 backtest_results.db(type=factor)
此前 FactorReport 无 id,_on_done 不存 DB → 因子任务不进任务列表、重启丢失
(用户:历史任务列表看不到因子分析)。_on_done 现对 FactorReport 调
_persist_factor 存 backtest_stats(type=factor, strategy=因子名, symbol=标的池,
statistics={ic_summary, report_paths})。FactorReport 加 symbols/start/end 字段。
|
2026-07-17 17:06:57 +08:00 |
|
claude_dev
|
f4cf35a7d1
|
fix(history): optimize 任务查看跳 optimize-result 页(此前跳 CTA result 致指标全空)
Dashboard/History 的 open() 只区分 factor,optimize 任务也跳 /backtest/result/,
但优化任务无单一 metrics/equity → 指标卡片全显示 —。改为按 type 分流到
/backtest/optimize-result/(同 Progress.vue 已有逻辑)。
|
2026-07-17 16:48:12 +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
|
4f0e3162b3
|
fix(optimize): 策略切换时按策略参数自动填网格,避免 grid 不匹配
Optimize.vue 硬编码默认 grid 为 fast_window/slow_window(DoubleMa 参数),
切换策略不更新。选 DualThrust/AtrRsi 等策略时 grid 仍是 fast/slow_window,
参数对该策略无效 → 所有组合跑出完全相同结果(实证 opt_235fa738 DualThrust
24 组合 total_return 全=-0.0023, distinct=1/24)。
加 watch(form.strategy):切换时拉 /strategy/{name}/params,按 parameters+
defaults 以默认值为中心生成网格,保证参数名匹配策略。历史无效优化无法挽回。
|
2026-07-17 15:33:03 +08:00 |
|
claude_dev
|
65021bd32c
|
fix(factor): tears iframe 渲染——patch GridFigure.close 收集 figure 生成 HTML
alphalens-reloaded create_full_tear_sheet 内部每个 tear sheet 末尾调
GridFigure.close()→plt.close(fig),Agg 后端下 figure 被销毁,plt.savefig
只能拿到最后一个空占位 figure(实证 2.3KB 空 PNG);原代码 savefig 存
.png 却把 report_paths 记成 .html,report endpoint os.path.exists 失败
返回 404,iframe 加载空白(回退到 SPA 首页标题)。
monkey-patch GridFigure.close 收集 figure 而非销毁(同 empyrical/demean
适配思路,不改 alphalens 源码),跑完把所有 figure savefig 成 base64 嵌入
真 HTML 文件,report_paths 指向该 html。
浏览器端到端验证(VPS factor_2d01a718):report endpoint 404→200,iframe
渲染 4 张 tearsheet 图(returns/information/turnover/quantile table,2.4MB),
naturalWidth>0 确认非 broken,console 无报错。
|
2026-07-17 14:38:03 +08:00 |
|
claude_dev
|
3b116b63f9
|
fix(factor): patch alphalens demean 兼容 pandas2,tears 报告跑通
alphalens-reloaded 的 demean_forward_returns 用 groupby.transform(lambda x: x-x.mean()),pandas2 走 _transform_general → concat 空(No objects to concatenate),tears 崩。
monkey-patch alphalens.utils.demean_forward_returns:改 transform("mean") 走 _transform_fast(广播组均值不 concat)再相减,等价且兼容。不改 alphalens 源码(同 empyrical np.NINF 适配思路)。
验证: 单点 patch 无 cascade,tears create_full_tear_sheet 全链跑通,report 生成,IC + tears 报告都出。
|
2026-07-17 13:21:18 +08:00 |
|
claude_dev
|
b3ea8e7b04
|
fix(factor): 因子分析端到端修复(依赖缺失+vt_symbol+IC/tears解耦)
根因链:
1. alphalens + scikit-learn 没装 → analyzer:76 软错误 return {error:alphalens not installed}(已 pip 装 alphalens-reloaded 0.4.6 + scikit-learn 1.7.2,requirements-lock 已锁)。
2. symbols 传 vt_symbol(600000.SSE)但 read_db_daily 查 DB 用裸代码 → bars 空 → factor/prices 全空 → alphalens infer_trading_calendar weekmask 全零 → busdaycal 崩。
3. statistics 含 date/numpy(之前 optimize 已修 result_store _json_default)。
4. alphalens-reloaded × pandas2 的 groupby.transform 兼容:demean_forward_returns tears 崩 No objects to concatenate。
适配修复(不动 vnpy/alphalens 源码):
- symbols 归一:vt_symbol → 裸代码(split '.'),read_db_daily 能查到。
- IC/tears 解耦:IC 算完先存 ic_summary success,tears 独立 try(失败标 tears_error 不覆盖 IC)——IC 核心数值可用,tears 报告作为已知限制。
- error 加 traceback 字段(调试友好)。
验证: 3 symbol(600000/000001/600519) ma5 因子 IC 成功(1D/5D/10D mean/icir/t_stat count=49),浏览器 /factor/result 页表格渲染。单 symbol IC NaN 是截面用法(需≥2标的),非 bug。
|
2026-07-17 11:51:08 +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
|
799292d89c
|
chore: gitignore 补充 venv*/data_xtdata_stage/backup 模式
|
2026-07-17 08:24:01 +08:00 |
|
claude_dev
|
b966fce1e9
|
feat(data): 导入脚本 env 化 + xtdata 日线增量脚本
- import_vnpy_daily_fast.py: DB_PATH/DAILY_DIR 读 env(VNPY_DB_PATH/DAILY_DIR, Windows用正斜杠); amount 列缺失时容错填0
- daily_update_xtdata.py: 新增, 全市场日线从 miniQMT xtdata 本地缓存增量下载(零漂移), 部署文档 §4/§8 引用
|
2026-07-17 08:24:01 +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
|
37c850d0c5
|
docs(deploy): VPS统一部署权威文档(取代vps-native-brain,覆盖07-17全统一架构)
|
2026-07-17 08:10:04 +08:00 |
|
claude_dev
|
a75e094e7d
|
feat(data): build_daily_from_xtdata 全市场日线从xtdata重建到staging
miniQMT的xtdata作源(已证价格与parquet一致/T+0/深历史),重建VPS全市场日线。
- 只写 staging(DATA/_staging_xtdata),不动主库,验后再swap
- download一次raw,读两次(dividend_type none=raw/front=qfq,复权读时应用)
- volume×100(手→股),列 date/open/high/low/close/volume 对齐 datareader
- 单线程paced(分批200+sleep),per-stock写不全量进内存,避全市场崩
- 布局 {raw,qfq}/<year>/{sh|sz}{sym}_daily.parquet,沪深A股~5201只
|
2026-07-15 22:59:32 +08:00 |
|
claude_dev
|
346133415f
|
fix(data): run_daily_update 注入 homebrew PATH 修 launchd 下 timeout not found
launchd/cron 最小 env 不含 /opt/homebrew/bin,探针 'timeout 30 python3 ...'
报 command not found → 误判新浪源挂 → abort → 每日增量 07-14 起失效、生产数据
停在 07-13。脚本顶部 export homebrew+系统 PATH,兼容 launchd/cron/手动。
根因见 memory cron-python-env-gotchas(timeout 在 homebrew 不在 /usr/bin)。
|
2026-07-15 21:35:59 +08:00 |
|
claude_dev
|
dfa72e1440
|
fix(trader): cancel_order 补 symbol/exchange
vnpy 4.4.0 的 CancelRequest 必填 (orderid,symbol,exchange),原代码只传
orderid → TypeError → 撤单从不工作。改为从 _exec.orders 缓存查 OrderData
拿 symbol/exchange 一起传。E2E 实证 {ok:True} 无 TypeError(盘后 miniQMT
非交易时段不实际撤单,是另一回事)。
|
2026-07-15 21:28:19 +08:00 |
|
claude_dev
|
70d72f35bb
|
chore(vendor): vendor vnpy_qmt 0.3.3 源码自行维护
vnpy_qmt 是唯一券商交易 gateway(关键路径),社区包断更有风险。
按 vnpy_v4.4.0 同一套约定 vendor 源码、sys.path 引用、不 pip install。
- vnpy_qmt_v0.3.3/vnpy_qmt/ (5文件587行) + LICENSE(Apache-2.0) + README
- run_web.py 加 if-exists 路径块,import 方式不变 (from vnpy_qmt import QmtGateway)
Mac 验证: py_compile 全过 + import 解析到 vendor 副本(仅卡 xtquant Win-only,符合预期)
VPS 生产切换(Part B: rsync+pip uninstall+重启+实证) 待确认
|
2026-07-15 21:15:53 +08:00 |
|
claude_dev
|
992f53d4db
|
feat(trader): Phase2—vnpy_qmt 进程内执行客户端,替 HTTP bridge
- qmt_gateway_client.py: QmtGatewayClient(同 BridgeClient 接口 place_order/
get_account/get_positions/get_orders/cancel_order),底层进程内 QmtGateway 直连
miniQMT(单例 _QmtExec: EventEngine+QmtGateway+账本缓存,懒连接复用)。
实证:连真实 miniQMT 读账户(9997081)+持仓(600000/000001),place_order 落单 QMT.xxxxx#1。
- live_orchestrator.py: _make_exec_client 工厂,SANGUO_USE_QMT_GATEWAY=1 → QmtGatewayClient
(bridge 已退),否则 HTTP bridge 兼容。shadow + reconcile 两处替换。
同机部署后 HTTP 跳无必要,brain→vnpy_qmt→xtquant→miniQMT 零跳直链。
bridge+sanguo-caddy schtasks 可 disable(vnpy_qmt 路径已实证)。
|
2026-07-15 18:57:20 +08:00 |
|
claude_dev
|
2b26174977
|
feat(ops): NAS→VPS 数据同步脚本(Mac中继,符dev→prod)
sync_nas_to_vps.sh: 同步质量验证日线(raw+qfq parquet)NAS→VPS via Mac
(光猫拦直连)。符号可配置(默认模拟账户持仓600000/000001),幂等(rsync --update),
前缀规则对齐 bridge_client.to_bridge_code。已验证:24文件落地VPS结构正确。
验证通过→Mac cron每日收盘后跑=生产数据管道。
|
2026-07-15 13:56:23 +08:00 |
|
claude_dev
|
3ef8c617f0
|
feat(deploy): VPS原生大脑部署—env覆盖配置+部署文档(Option B落地)
- sanguo_data/config.py: load_config 加 env 覆盖(SANGUO_DATA_ROOT 重映射
daily/raw/qfq/15min/vnpy_db;SANGUO_LIVE_ENABLED/SANGUO_BRIDGE_URL 覆盖 live 段),
三机共用一份 git config 零漂移
- sanguo_api/main.py: build_app 加 SANGUO_DB_PATH/SANGUO_FILE_PATH env 覆盖
- docs/deployment/vps-native-brain.md: VPS原生部署全记录(安装/配置/服务/验证/
数据staging/Phase2暂缓理由)
实证:VPS vnpy4.4.0+vnpy_qmt0.3.3 连真实miniQMT读真实账户/持仓;
live_step全链路+影子transport(本机bridge)通过。详见文档。
|
2026-07-15 12:55:58 +08:00 |
|
claude_dev
|
c66f7cb14e
|
chore(deps): 锁三机统一依赖基线(Python3.10+pandas2.3/numpy2.2新稳定版, requirements-lock.txt)
依据:
- vnpy 4.4.0 pyproject: numpy>=2.2.3 / pandas>=2.2.3(均无上限,不钉<3)
- pandas 目标=2.3.3(2.x 稳定线顶端,3.0 破坏性变更未回归,按稳定优先不采用)
- numpy 目标=2.2.6(与 TA-Lib 0.6.8 在 NAS 生产容器实证兼容)
- 其余依赖==钉到 NAS 容器已验证可跑版本(fastapi 0.139/uvicorn 0.49/polars 1.42 等)
- Python 3.10 三机统一基线(xtquant 限 3.6-3.12,VPS 锁 3.10)
- 不含 vnpy(源码引用)/ xtquant(VPS Windows only)/ CUDA(torch 传递依赖)
- 矩阵文档新增「锁定决策(2026-07-15)」小节:依据+迁移步骤+验证前置
- 验证前置:落生产前须全套 pytest 0 回归 + 一个 CTA 回测冒烟
|
2026-07-15 08:12:40 +08:00 |
|
claude_dev
|
e3b688354f
|
fix(data): data_platform硬化(增量merge/verify+raw_redownload/run_daily_update)+测试
merge_increment/verify_increment 增量staging→验证→合并工具; raw_redownload/run_daily_update/import_vnpy_daily 强化; 补 data_platform 与 index_downloader 测试.
|
2026-07-15 07:12:46 +08:00 |
|
claude_dev
|
54f9ab4c4f
|
docs(deploy): VPS生产runbook+三机环境矩阵+NAS ops脚本+修rsync危险命令
vps-production-runbook(VPS运维一站式,已验证状态+拓扑+发布流水线+人类闸口+排障); env-version-matrix(三机Python/deps矩阵+Lock建议); scripts/ops(NAS bridge探针-容器无curl-+VPS→NAS备份脚本); nas-deploy-plan§3(修rsync --exclude语法,原会删万级staging parquet+破坏entrypoint启动).
|
2026-07-15 07:12:46 +08:00 |
|