Commit Graph

55 Commits

Author SHA1 Message Date
claude_dev 31596f58f9 fix(shadow): 双轨对账count_match改按票+方向聚合总量——QMT部分成交拆行致27vs5恒False纯计数噪音 [vps]
CI/CD / test (push) Successful in 14s
CI/CD / nas-deploy (push) Successful in 24s
CI/CD / nas-verify (push) Successful in 1s
08-24实录: momentum一笔3800股被QMT拆19笔fill,对账27vs5恒count_match=False,总量却分毫不差。旧口径按原始行数比(注释自称'差异如实呈现待归因',实则部分成交属成交粒度非分歧)。修=按聚合桶live_volume==shadow_volume判;原始行数保留在live_count/shadow_count供归因。真量差仍判False(新增测试钉死)。trader 254绿。
2026-08-24 23:07:12 +08:00
claude_dev e2dc473682 fix(shadow): 影子市价单成交基准改实时行情——旧按委托保护价记账恒差1.5%,08-24双轨4/6红根因 [vps]
根因(代码级实锤): broker._ref_price 优先用下单传入price,而市价单的price是保护性委托上限(策略侧行情×1.015,BrokerBase契明文'可用作保护价/参考价'非期望成交价)→影子每笔买入虚高~1.5%,卖侧对称低~1.5%。08-24证据三连:momentum/small_cap首次真实成交日25票价差紧聚-150bps(-112~-189);卖侧510500同样-1.54%(排除'晚一根bar随行情'解释);级联=虚价吃掉影子现金6k+→002038买第6只差1678元资金不足拒单(shadow_60日志)。排除用户初判的滑点/费率参数不一致(影子账户slippage=0.0费率正常)。回测/实走无此问题(matcher.py按bar开收价,另一套)。
修: _ref_price(security,price,market)——市价单成交基准=price_getter实时行情,行情不可得退回委托价(告警,可用性优先);限价单沿用传入价(触价语义,旧行为);buy/sell补市价转限价封顶(行情超保护上限按上限成交不追高,卖侧对称)。
+5测试(市价买卖按行情/超上限封顶/无行情退委托价/限价语义不变),trader 254绿+api 171绿。
2026-08-24 23:07:12 +08:00
claude_dev f214e2f0e4 fix(live): max_pool 全链默认 30→0(0=不限)——08-24巡检定罪MVP限流泄漏生产,选股池=代码序前30只失真 [vps]
CI/CD / test (push) Failing after 12m2s
CI/CD / nas-deploy (push) Has been skipped
CI/CD / nas-verify (push) Has been skipped
根因(策略session 08-24 午休探针实证):runtime/live_strategy.py SANGUO_LIVE_MAX_POOL
默认30经env注入全部实盘+影子+paper实例,_stock_pool截断成份池为「代码序前30只」:
small_cap「全市场最小市值」实际在000001平安银行等30只固定代码里选(平安银行≈3800亿
出现在小市值买入=market_cap开盘NaN排序失效叠bug);momentum每行业RPS只在代码序前
30里排;value 0/30+零委托史同源。注释自曝「MVP验证用」=限流遗留泄漏生产,上线
首日起全部选股失真。

改动(9处默认位一致30→0;语义0=不限,与策略层max_pool>0才截断一致):
- sanguo_portfolio/live_strategy.py 适配器env默认+docstring
- sanguo_live/runner.py _portfolio_env_for(存量DB显式值不篡改,缺列/0→"0")
- sanguo_trader/shadow/supervisor.py 影子env默认
- sanguo_portfolio/runner_live.py live_env默认
- sanguo_trader/portfolio_paper.py + sanguo_api/routes_paper.py paper默认
- sanguo_api/routes_live.py create setdefault
- frontend live/paper New.vue 表单默认

测试:env mapping三态断言(缺列/0→"0",显式30不篡改)+live_env默认"0"
(RED→GREEN);CI范围642绿。存量实例DB仍存显式30,激活需配套DB迁移,必须与数据
session的get_security_info_batch SQL治本(101s→亚秒)同车部署——池放大×慢SQL=更糟。
2026-08-24 13:34:01 +08:00
claude_dev ed15c24db8 feat(trader): B5对账恒等式优先——15:10日终报表加『全账户=Σ实例账本+未归因』层(spec§B5)——①build_identity_report:每QMT账号一行,快照市值vs Σ实例账本市值(live_balance最新,dae56e2起=实例视图),未归因MV+占比,容差0.5%(价格时点差);逐票未归因=快照持仓−Σ实例持仓(6位码对齐)单列(重建后应≈0,大数=遗留/手动仓)②状态四态:pass/no_instances(重建期无实例=恒等式成立)/snapshot_missing(如实FAIL)/unattributed_over_tol(旧全账户行叠加期呈现大额负未归因)③save/load落库identity_reconcile(account+date主键)④15:10调度(_maybe_daily_reconcile)与CLI恒等式先行,再逐对live↔shadow(配对v2不变);+7测试(容差内过/未归因票单列/负未归因/无快照/无实例/多实例Σ不串账号/落库回读);trader 248绿 [vps]
CI/CD / test (push) Successful in 18s
CI/CD / nas-deploy (push) Successful in 58s
CI/CD / nas-verify (push) Successful in 11s
2026-08-19 22:32:00 +08:00
claude_dev c9a3b0eb4f fix(shadow): 影子账本接通引擎账户同步+净值as_of+重启恢复三连修 [vps]
CI/CD / test (push) Successful in 14s
CI/CD / nas-deploy (push) Successful in 39s
CI/CD / nas-verify (push) Successful in 14s
三日体检(2026-08-19)实锤三 bug,影子账户第1天后永久卡死:
①账本断连:supports_account_sync=False→引擎context.portfolio永远停在
初始100万/0持仓→8-19轮换零卖出+买单六连拒资金不足(账上真剩15.6万);
修=sync_account按_apply_account_snapshot契约推{cash,total,positions
[closeable_amount=T+1 held-今日买]}(引擎60s拉一次,策略从此看得见真实账本)
②净值断供(#88回归):get_account_info无as_of键→_should_write_balance恒
False→paper_daily_balance影子一行不写=前端模拟盘无收益率直接原因;
修=有持仓或有成交→as_of=今天,空账户→''不写垃圾行
③重启失忆:账本全内存,重启重置1M/0持仓与已落库成交断层;
修=restore_from_trades逐笔重放(cash=initial-Σ买-Σ费+Σ卖/持仓加权成本/
当日买入补T+1锁)+runner经_hist_trades_for_restore(list_trades)接线

+4回归(sync契约与T1两日/asof三态/重放手算基准996683/offset→side映射);
833绿 [vps]
2026-08-19 10:27:58 +08:00
claude_dev 5211d5a6ed fix(reconcile+ci): 双轨配对按instance_id精确配对+部署API等待帽10→20分钟——①配对v2:v1按策略名dict收敛,同策略多live(live#10/#11都是channel_test)后者覆盖前者→live#10漏配live#11双配,15:10日终对账配错对(VPS 8对舰队实测:live#11↔shadow#44/45两行,live#10无);修为instance_id+周期精确优先→同实例退而求其次→无instance回退策略名唯一/周期一致,宁缺毋错;+2回归测试(复刻VPS实况/同实例不同周期)②vps-deploy API监听等待60→120次(run681实录:19常驻进程负载下API启动>10分钟,workflow 10分钟帽误杀放弃,API最终正常起服——但跳过了常驻重启/tag/关issue三步);938绿 [vps]
CI/CD / test (push) Successful in 9s
CI/CD / nas-deploy (push) Successful in 24s
CI/CD / nas-verify (push) Successful in 8s
2026-08-16 22:45:42 +08:00
claude_dev 3f6b681d0f fix(shadow): 多账户worker不抢全局solo锁——根因实锤:__main__对--account N也走~/.sanguo_shadow_desk.lock全局锁,全机只放行一个影子worker(谁先抢到谁活),supervisor多账户并存时其余全部'锁占用'rc=0优雅退出→每60s重拉秒退循环;VPS实录40/41反复退出+42抢到锁独活(shadow_41.log一击定位);单账户时代从未暴露,2026-08-16用户建三影子账户即炸。修:--account分支跳过全局锁直进run_shadow(同账户防重复由bullet_trade runtime/shadow_{aid}实例锁+supervisor children表兜底);solo模式(无--account)维持全局锁防双开;+3路由测试(account跳锁/solo持锁/auto不碰柜台);936绿 [vps]
CI/CD / test (push) Successful in 8s
CI/CD / nas-deploy (push) Successful in 25s
CI/CD / nas-verify (push) Successful in 13s
2026-08-16 18:51:07 +08:00
claude_dev 886438fc92 fix(vps验收五问题之四): ①#84个股回测/回放提交秒败——L2校验end>latest且end<=today(周末/节假日/当日未灌)不再400,引擎区间过滤自然截到latest;新增start>latest仍400(必空跑);VPS实况=结束默认今天周日>最新周五,首提即败 ②#85组合任务标的列永远000300.XSHG——worker symbol=benchmark改pool(spec透传,benchmark已在params);内存任务两处symbol回退symbol→pool→benchmark ③#42影子拉起即崩——live_strategy工厂表补4个TET副本映射(all_weather_ex等,01184c2改名后回测认得但影子/实盘runner不认,VPS shadow#42实录) ④#88影子快照刷垃圾行——_snapshot_loop每30s无条件写date=''行(40号半天97行),改_should_write_balance同日一行+空行情不写(+3测试) ⑤可观测性——supervisor子进程stdout/stderr落logs/shadow_{aid}.log(>5MB重置)+主管自身日志落logs/shadow_supervisor.log(原schtask控制台=黑洞,41/42崩因至今零线索);933绿 [vps]
CI/CD / test (push) Successful in 10s
CI/CD / nas-deploy (push) Successful in 26s
CI/CD / nas-verify (push) Successful in 11s
2026-08-16 18:28:18 +08:00
claude_dev 6b07389c85 feat(strategy): 代码版本快照(§12.6补,方案B发起时快照·QuantConnect轻量版)——用户拍板:解决「实例参数有快照但代码没有,历史运行无法回溯当时跑的哪版代码」——①sanguo_api/code_versions.py:发起时全文落盘data/strategy_code_versions/{file}.{hash8}.py(md5内容寻址天然去重,原子替换防并发坏);发起四入口(paper/live/CTA/组合回测)全快照,账户加code_hash列(ALTER迁移),回测经spec→run_meta.code_hash落档案②查看:GET /strategy/code-versions列表+单版本全文;代码编辑页「版本历史」抽屉(MonacoDiff左右对比当前,主题同款)③「代码已变更」角标:策略库档案行(enriched code_changed)+全景每run标v哈希·一致/已变更④双轨对账加「代码版本一致」第五指标(对账FAIL先查这行,两边代码不同价差必然大);路径穿越防护(版本号只认8位hex)+6测试;927绿+build绿;「用当时代码重跑」留P2 [vps]
CI/CD / test (push) Successful in 13s
CI/CD / nas-deploy (push) Successful in 1m1s
CI/CD / nas-verify (push) Successful in 19s
2026-08-15 23:38:07 +08:00
claude_dev 256820d36f feat(strategy): 策略实例做实P0+P1+策略库A+B混合布局(spec§12.6定稿)——实例=策略档案:①绑定:paper/live账户+回测任务加instance_id(paper_accounts/live_accounts ALTER迁移),发起即建档(无档案自动建),绑已有档案时D1发起快照(账户用档案参数复印件)②回写:事件型(回测_on_done/回放线程)落盘update_instance_run;持续型(实走/影子/实盘)读时聚合_instance_runtime(四格覆盖+在跑账户+漂移检测)③D2/D3同步:POST /paper/sync/{id}批量刷运行中模拟账户(实走+影子锁死一致),实盘不在线改参④D5删除保护409⑤P1全景:GET instances/{id}/overview(全部运行账户+净值尾部+合并持仓归因)收编挂起项「按实例归因持仓」⑥前端:策略库重做A+B混合(统计条+在跑巡检模式+左栏代码树中文主显/文件副行+档案区漂移角标/同步/全景;STRATEGY_LABELS抽共享常量),InstanceOverview抽屉(echarts净值对比+归因持仓表),模拟盘/实盘表单加实例档案下拉(选中预填+绑定,路由?instance=直进);mock层enriched/sync/overview(路由序enriched先于{id});+7绑定测试,921绿,build绿,dev浏览器验收过 [vps]
CI/CD / test (push) Successful in 14s
CI/CD / nas-deploy (push) Successful in 52s
CI/CD / nas-verify (push) Successful in 17s
2026-08-15 22:39:05 +08:00
claude_dev 534a06aad7 feat(shadow-desk): 双轨日终对账报表(影子P3前半,设计§8.2)—reconcile_report四指标(成交笔数全同/每笔价差vwap对比<10bps带符号供滑点重标/收盘持仓逐只数量/净值月偏差<0.5%)+find_dual_track_pairs自动配对(shadow策略名↔live strategy_class,live#5↔shadow#39实证)+dual_track_reconcile落库upsert;API GET /paper/reconcile(+单配对refresh);CLI python -m;supervisor auto轮询挂15:10后每日一次兜底;14新测试(符号口径SH/XSHG归一/影子拒单不计/部分成交如实报笔数异) [vps]
CI/CD / test (push) Successful in 11s
CI/CD / nas-deploy (push) Successful in 33s
CI/CD / nas-verify (push) Successful in 12s
2026-08-14 23:18:07 +08:00
claude_dev 61cc01efbe feat(portfolio): P1.3涨跌停/停牌过滤批量化双端—①all_weather monthly_adjustment三filter接线_get_limit_status批量预取(原不传status_map/date走无数据保留死分支,照买涨停照交易停牌;同small_cap等三策略) ②ShadowBroker涨跌停拒单(买撞涨停/卖撞跌停/停牌双向拒;limit_getter注入,未注入/异常/无状态降级放行等价旧行为) ③runner build_limit_getter(优先miniQMT实时tick lastPrice vs UpStop/DownStop与实盘同源,回退get_limit_status_batch日线口径);9新测试 [vps]
CI/CD / test (push) Successful in 15s
CI/CD / nas-deploy (push) Successful in 40s
CI/CD / nas-verify (push) Successful in 13s
2026-08-14 23:04:15 +08:00
claude_dev b27c3b479c fix(live/shadow): 实例锁第二层——按账户复制策略适配文件(live_3/live_5共用QMT账号被误判重复实例拒启);bullet_trade实例锁判重键=主机+strategy_path+broker+account_identity,同账号多策略是合法场景须路径互异 [vps]
CI/CD / test (push) Successful in 18s
CI/CD / nas-deploy (push) Successful in 26s
CI/CD / nas-verify (push) Successful in 13s
2026-08-14 20:28:14 +08:00
claude_dev e1cafac451 fix(live/shadow): bullet_trade单实例runtime锁按账户分目录(live_{id}/shadow_{id});VPS实况=影子进程持默认./runtime锁,两个组合实盘LiveLockBusyError起不来;多实盘并行+双轨§8的前提 [vps]
CI/CD / test (push) Successful in 14s
CI/CD / nas-deploy (push) Successful in 27s
CI/CD / nas-verify (push) Successful in 16s
2026-08-14 20:14:23 +08:00
claude_dev ea736acb29 fix(shadow): ShadowBroker补LiveEngine 0.9.2协议方法(supports_account_sync/cleanup等5个);VPS实况=影子进程启动即崩进崩溃循环(引擎_start_background_jobs无条件调supports_account_sync);加协议完整性防回归测试 [vps]
CI/CD / test (push) Successful in 15s
CI/CD / nas-deploy (push) Successful in 30s
CI/CD / nas-verify (push) Successful in 12s
2026-08-14 20:04:59 +08:00
claude_dev f00730482f feat(shadow-desk): P1-d 影子主管+通路策略增强(用户拍板): channel_test universe分6类资产各3只(宽基/行业/跨境商品ETF/主板蓝筹/中盘/创业板,个股只主板+创业板无科创北交铁律)hold 6只每日跨类型轮换;盘中4时点场景(9:35主调仓卖全买等权/10:45部分加减仓/13:45卖后买资金复用/14:30 T+1拒单探针)每天全场景,适配15m; shadow supervisor --auto轮询paper库自动拉起/停止/重启影子账户子进程(env映射SANGUO_LIVE_+SANGUO_SHADOW_契约); 11新测试 [vps]
CI/CD / test (push) Successful in 12s
CI/CD / nas-deploy (push) Successful in 32s
CI/CD / nas-verify (push) Successful in 15s
2026-08-14 19:14:13 +08:00
claude_dev 8e7e7282de feat(shadow-desk): P1-b/c 影子柜台常驻进程+本地撮合broker+前端引擎选择: ShadowBroker(实时价±滑点即时成交/佣金印花最低佣金/A股整手/T+1日锁/资金不足拒单/均价加权/duck-typed BrokerBase协议); runner挂bullet_trade LiveEngine同实盘唯一差=broker_factory换影子(双轨对账基础),成交落paper_trades+30s快照落持仓净值; CLI单实例文件锁(python -m sanguo_trader.shadow); paper_accounts加engine列(eod_replay/shadow迁移); 前端:模拟盘新建组合卡撮合引擎单选+列表影子/日终徽标; 10 broker单测 [vps]
CI/CD / test (push) Successful in 12s
CI/CD / nas-deploy (push) Successful in 25s
CI/CD / nas-verify (push) Successful in 9s
2026-08-14 12:16:05 +08:00
claude_dev d030cfc91f feat(paper): 组合策略接入模拟盘实走(E1+E2): paper_accounts加strategy_type列(含迁移); portfolio_paper每晚20:30全量重放→当日成交/末日持仓/净值落paper表(幂等,回测引擎为单一真相源); run_live_step按类型分流; create支持portfolio(仅live); 前端新建模拟盘策略类型选择+组合字段(策略/池/上限/基准) [vps]
CI/CD / test (push) Successful in 11s
CI/CD / nas-deploy (push) Failing after 11s
CI/CD / nas-verify (push) Has been skipped
2026-08-13 18:32:09 +08:00
claude_dev d8c156e6de feat(strategy): 策略库灌入vnpy内置8策略模板(DoubleMa/AtrRsi/BollChannel/DualThrust/KingKeltner/MultiSignal/MultiTimeframe/TurtleSignal); registry自研目录优先加载(编辑副本即刻生效,pip兜底); 分类器识别vnpy_ctastrategy import风格 [vps]
CI/CD / test (push) Successful in 10s
CI/CD / nas-deploy (push) Failing after 12s
CI/CD / nas-verify (push) Has been skipped
2026-08-13 18:24:40 +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 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 8c06ef1e53 feat(bridge): 补 /orders+/cancel 端点与客户端(实盘查委托/撤单)
bridge.py: POST /cancel + GET /orders; xt_gateway: query_orders/cancel_order(含xtquant状态映射50挂单/56已成/57拒单/54撤单); bridge_client: get_orders/cancel_order. 已在 VPS 生产验证.
2026-07-15 07:12:46 +08:00
claude_dev 0761342baf feat(trader): live bridge token 改从 config 读取,免容器重建
容器 docker run(非 compose)注入 BRIDGE_TOKEN env 需重建容器,风险大。改为 live_cfg.bridge_token 优先、fallback BRIDGE_TOKEN env。run_live_step 每次 load_config,改 config 免重启即生效。

- _shadow_trades_to_bridge + reconcile_from_bridge 两处 token 读取
- config: live.bridge_token 占位空值(真实值填 NAS gitignored config,不入库)
- tests: +6 测试(config优先/env fallback/都无跳过),191 passed
2026-07-13 19:30:58 +08:00
claude_dev e77c9df0d4 feat(live): D-4c模式B reconcile—bridge回报驱动账本(真桥验证通过)
- bridge_client: from_bridge_code(sh/sz→纯数字码, to_bridge_code逆函数)
- live_orchestrator: reconcile_from_bridge 读bridge /account /positions校正account现金+持仓+持久化, 默认mode_b=false
- live_step step8: 影子后调reconcile(mode_b=true生效, mode_b=false跳过)
- config: live.mode_b开关(默认false模式A)
- test_reconcile: 10例(cash/positions校正+code转换+失败降级+mode_b跳过)
- NAS环境15 passed(reconcile10+shadow5无回归)
- 真桥集成: live_step mode_b=true → reconcile读bridge → account校正(1000万/空仓=bridge真实账本)+持久化
安全: mode_b默认关+bridge失败降级不阻断+token走env
2026-07-11 06:30:08 +08:00
claude_dev ff84b3d4b0 feat(live): D-3 sanguo实盘分支(影子下单)+D期设计文档
D-3 模式A影子下单(spec §5):
- bridge_client.py: QMT bridge HTTP客户端(urllib, X-Bridge-Token, 失败不抛返回None)
- live_orchestrator: _shadow_trades_to_bridge 当日成交POST bridge(默认enabled=false)
- persistence: paper_shadow_orders幂等表+save_shadow_order/is_trade_shadowed
- config: data_platform.yaml加live段, token走env(BRIDGE_TOKEN)
- to_bridge_code symbol转换与guess_exchange一致(2位前缀)
安全: enabled=false默认关+token走env+幂等防重复+影子失败不阻断live_step

docs: phase3d-live-trading-design.md(D期完整设计)
2026-07-11 00:03:46 +08:00
claude_dev 0656108b9e fix(live): live_step传qfq_bars对齐step双源签名(端到端跑通)
live_step当日补fetch_day qfq + step(today,raw,qfq,prev,pending)5参数对齐.
修前 step5参数 vs live_step4参数 missing pending(预存, c6b19f4双源后未对齐).
容器verify_live_step端到端跑通(live_step@2026-07-07, _restore_ledger不崩,
分红/占用成本加载OK). 139 passed.
2026-07-10 08:49:58 +08:00
claude_dev 164690373f feat(trader): C期分期项收尾—资金占用成本+分红送股+_restore_ledger修复
- 资金占用成本(spec§195): StrategyRunner.daily_borrow_cost(used×risk_free/365)
  归因per_strategy_pnl(不碰account总账, account.equity真实净值不变);
  config risk_free_rate=0.02; engine.step mark_to_market后计扣; =0向后兼容跳过
- 分红送股(spec§295): dividend_source.py(akshare stock_history_dividend_detail,
  实测600000/000001纯现金分红); PositionLedger.apply_split(volume×factor/avg÷factor);
  Account.apply_cash_dividend; engine._apply_dividends(除权日调整,现金先split后);
  mark_to_market停牌prev_close兜底(今收→前收→均价); _run_replay注入dividends日历
- 修_restore_ledger预存bug: PositionLedger.__init__加volume/frozen/avg_price参数
  (原只symbol, live_orchestrator跨日恢复4参数调用会TypeError, 首次step空仓未暴露)
- 139 passed(119基准+20分红+3占用成本), 无回归
- live_step dividends注入待分期项(每日拉全市场分红慢, 需run_daily_update预拉日历)
2026-07-10 08:44:35 +08:00
claude_dev 193064c953 feat(trader): 软限额max_allocation(分期项)—每策略资金额度消除顺序依赖
spec §195: 多策略并发下单"先到后到"不可复现 → 每策略独立max_allocation
- StrategyRunner: max_allocation字段(默认inf) + used_allocation(持仓市值)
- engine._match: BUY cash_enough后查 used+成交额>max_allocation → 拒单max_allocation_exceeded
- live_orchestrator: runner传max_allocation(默认initial_capital)
- routes_paper: StrategyCfg加max_allocation(API→DB→live_step数据流)
- test_soft_limit: 3测试(累计超限拒单/默认不限/SELL不受限)

116 passed(113旧+3新), 无回归.
2026-07-09 22:05:35 +08:00
claude_dev 0810259911 feat(data): 15min双源集成(data_source路由 + baostock格式适配)
- _resolve_dir_key: 15min支持raw/qfq双源(移除raw15min抛错)
- _check_adjust_cfg: 按interval查dir(minute_15_raw_dir/qfq_dir)
- read_parquet_15min: datetime列优先(baostock时分,旧date兼容)
- config: 加 minute_15_qfq_dir/minute_15_raw_dir
- test: 更新raw15min路由断言(6 passed)

实测容器: 600000 15min qfq 336bars close6.1977 / raw 336bars close6.6200,
datetime时分正确(09:45:00). 15min双源分期项落地.
2026-07-09 19:34:43 +08:00
claude_dev c6b19f4244 feat(data): 恢复双源(task#79)—撮合raw+策略qfq, 分红除权准确
用户要模拟=回测准确: raw除权缺口致MA假信号, 必须双源。
- data_source: qfq→qfq_dir(干净qfq), raw→raw_dir; _check_adjust_cfg(cfg提供才校验)
- engine 双bar流: step(raw_bars,qfq_bars)撮合/盯市raw+策略on_bar qfq; run zip(raw,qfq)
- live_orchestrator: warmup用qfq(信号am); 去adjust参数(双源固定)
- raw_redownload --adjust(''raw/'qfq'); config qfq_dir
- 113/113通过
2026-07-08 07:21:33 +08:00
claude_dev ab703e93ba feat(matcher): 集合竞价CALL_AUCTION撮合(分期项)—开盘价(最大成交量原则→open)
CALL_AUCTION枚举原拒单(unsupported), 现撮合用开盘价(open, 集合竞价确定开盘价).
当前定价同NEXT_OPEN(均为open); 未来区分开盘/尾盘集合竞价需扩枚举.
test: call_auction fills@open(原rejected用例改).
2026-07-08 07:02:51 +08:00
claude_dev 7eec983164 fix(live): C-S3实走warmup(am跨日)+fetch_day wrapper+端到端验证
- live_orchestrator warmup: 重放start~昨日raw到策略am使其inited(实走每日单根, 不warmup则ArrayManager永不inited→策略无信号)
- routes _DataSourceWrapper 加 fetch_day(给 live_step 拉当日raw)
- verify_live_step 容器端到端: 创建live account+live_step(07-07 warmup+step)+存pending, 跑通(pending=0系DoubleMa当日无交叉, 撮合/存已单测)
2026-07-08 06:59:24 +08:00
claude_dev 6931a7b541 feat(trader): C-S3实走后端骨架—live_orchestrator+全局scheduler job+routes live
架构(简化,避per-account闭包注入):
- live_orchestrator live_step(account_id)自包含: 恢复cash/positions/pending→fetch_day raw当日→engine.step→存状态
- run_live_step(db)遍历live accounts调live_step; scheduler register_live_step_job全局20:30 job
- app startup注册全局job; routes create mode=live存account running(不跑回放)
- TODO(分期项): prev_close昨日raw/listing_days IPO算/realized_pnl恢复
- 113/113通过, live_orchestrator import OK
2026-07-08 06:49:31 +08:00
claude_dev 20bdd689af feat(persistence): C-S3实走跨日状态—paper_pending_orders+positions/last_balance存取 2026-07-08 06:46:57 +08:00
claude_dev 3aca14f723 refactor(engine): 抽出step()单根推进(C-S3实走入口,task2基础)
run()循环体抽为step(bar_date,bars,prev_close,pending)→(pending,closes);
run()改为调step。实走scheduler每日喂当日bar调step单步推进。
- 回放行为不变(test_engine原3用例pass)
- 加test_engine_step_single_bar_advances: day1信号缓冲/day2撮合
- trader全量111/111通过
2026-07-07 23:41:18 +08:00
claude_dev 05dba7fe46 feat(trader): 科创板200股最小手数(分期项切片)—lot_size_for+matcher板块取整
科创板(688/689)最小200股1股递增(不整倍); 主板/创业/北交100整倍; 卖出不取整。
- limit.py 加 lot_size_for(symbol)
- matcher cross_order 买入取整按板块(star≥200不取整, 其余100整倍)
- routes_paper cta size=lot_size_for(symbol)
- test: 688981 买150拒/买250不取整; 主板用例不变; 63/63通过
2026-07-07 23:37:50 +08:00
claude_dev 1ed7b72aca feat(data): raw真实价数据源(task#79)—raw_dir+dir_key路由+新浪源重下
根因: daily_dir mixed-adjust(hfq bulk+akshare raw tail)致3-30 -94%假跌。
方案(Linus三问简化单raw, 除权留分期项#3):
- datareader read_parquet_daily/15min 加 dir_key 参数
- data_source iter_bars/fetch_day: adjust=raw→raw_dir(缺配置报错防混源), qfq→daily_dir
- engine PaperEngine 默认 adjust=raw
- config 加 raw_dir; scripts/raw_redownload.py 新浪源adjust='' 直连+单线程限速
- 验证: 浦发606行close 6.5/14.6 mean10.08 0跳变, 撮合成交价9.71-10.25真实
- 测试9/9+trader全量108/108通过
2026-07-07 22:19:11 +08:00
claude_dev 0543154a62 fix(paper): save_account 兼容 start/end → start_date/end_date 字段映射 2026-07-07 17:45:43 +08:00
claude_dev ba2138e1cf fix(trader): volume×size(A股1手=100股) — DoubleMa 真策略回放 filled=3 跑通 2026-07-07 15:15:27 +08:00
claude_dev 17a4801450 fix(trader): vnpy 桥接(am/trading/cancel_all/__getattr__兜底) + create 异步回放 2026-07-07 15:03:57 +08:00
claude_dev cacdb5ae24 feat(trader): C-S3 scheduler(APScheduler定时+启动恢复live job) 2026-07-07 12:48:24 +08:00
claude_dev 14088eac13 feat(paper): C-S2 分策略归因(/strategies 聚合成交/拒单/费用) 2026-07-07 12:07:37 +08:00
claude_dev 42877213ae feat(trader): PaperEngine 主循环(逐bar重放/next_open缓冲/current_close/双层记账/持久化)
- run(): T+1解冻→撮合上根pending(用当前bar)→喂策略收单→current_close当根/next_open缓冲→盯市入库
- 双层记账一致性(总账=分户之和), checkpoint续跑字段
- StrategyRunner +symbol 字段 3 tests passed.
2026-07-07 12:01:37 +08:00
claude_dev f0d8fd2a03 feat(trader): PaperCtaEngine 策略适配器(拦截send_order→PaperOrder) 2026-07-07 12:00:14 +08:00
claude_dev b2c5d8fd79 feat(data): read_parquet_15min + trader data_source(qfq/raw双源)
- datareader: +read_parquet_15min(sh/sz前缀+15min.parquet), get_database lazy(去tzlocal等依赖)
- data_source: iter_bars cross-section yield(date,{symbol:Bar}), raw首版fallback qfq+warning(spec§17)
- 本机 mock _read_fn 测调度逻辑, read_parquet_15min 容器冒烟 4 tests passed.
2026-07-07 11:57:16 +08:00
claude_dev 308d36f2b6 feat(trader): persistence 4表+checkpoint+WAL(spec§8/§9.1)
paper_accounts(含owner_id/checkpoint_date/scheduler_job_id/match_session)
paper_trades(rejected/reject_reason/blocked_by) paper_positions(scope)
paper_daily_balance(is_checkpoint) WAL多进程读写 5 tests passed.
2026-07-07 11:52:11 +08:00
claude_dev e5e4eef807 feat(trader): Account总账+StrategyRunner分户(双层记账/资金T0/股票T1)
- Account: cash资金T0/合并持仓/equity盯市/cash_enough买单检查
- StrategyRunner: 分户持仓+realized_pnl归因/unrealized_pnl
- transfer_fee 直接用(matcher已双向,不再×2,review H3)
- unfreeze_all 对称(总账+分户,T+1每日解冻)
7 tests passed.
2026-07-07 11:50:40 +08:00
claude_dev 05d74fc2c1 fix(trader): M+L 接口校验 (listing_days/NaN/输入校验/类型注数) review
M1: PaperOrder+limit+matcher 加 listing_days(创业/科创/北交所前5日不锁,0=已过)
M3: is_locked_for_*_symbol cfg 注解 AccountConfig
M4: matcher NaN bar 拒单 bar_missing
L3: PositionLedger price/volume 正数校验
L5: PaperOrder __post_init__ volume 类型校验(拒 float/bool)
M5: current_close 契约 docstring + H3 残留注释修正(transfer_fee 双向)
79 tests passed.
2026-07-07 11:23:16 +08:00
claude_dev b874be1d84 fix(trader): matcher slippage/过户费双向/限价超涨停拒单 (H2/H3/H4)
H2: fill_price 应用 slippage(买+/卖-,默认0不影响)
H3: 过户费改双向(matcher 直接×2,Account 不再×2,删单边注释)
H4: 限价单超涨停价拒单(price_above_limit/price_below_limit)
69 tests passed.
2026-07-07 11:15:19 +08:00
claude_dev f940841a9a fix(trader): 价格精度 _price_eq + Decimal ROUND_HALF_UP (C1/H1)
C1 CRITICAL: is_one_word_lock/is_t_lock 用 == 比较价格,浮点尾数差
(5.5600000000000005 vs 5.56) 导致一字板当可成交。改用 math.isclose
容差比较 (pricetick/2)。新增 _price_eq(),所有价格 == 改用之;
相对比较 (low<open, high>open) 保留原语义。

H1 HIGH: limit_up/down_price 用 Python round() 是 banker's rounding
(round(610.5)=610),导致 5.55×1.10→6.10 而非 6.11。改用
decimal.Decimal(str(x)) + ROUND_HALF_UP。

测试:
- 5.05 一字涨停 (浮点尾数差 case)
- 9.99×1.2 创业板一字板
- 0.35×1.05 ST T 字板
- 5.55×1.10 → 6.11 (banker's 消除)
- 4.45×0.90 → 4.01

60 tests pass, 100% cov 保持。

Refs: Phase 3c C-S0 review findings [C1][H1]
2026-07-07 10:47:39 +08:00