diff --git a/docs/session_prompts/2026-08-26-数据session-smallcap-fundamentals-18min.md b/docs/session_prompts/2026-08-26-数据session-smallcap-fundamentals-18min.md new file mode 100644 index 0000000..99ff2b2 --- /dev/null +++ b/docs/session_prompts/2026-08-26-数据session-smallcap-fundamentals-18min.md @@ -0,0 +1,45 @@ +# 移交:策略 session(small_cap 选股 fundamentals 步骤 18 分钟瓶颈——08-26 巡检新发现) + +## 现象(VPS 实测,live_20.log 三日对照) + +| 日期 | 候选池 | 选股2/3 fundamentals | 下单时刻 | +|------|--------|---------------------|---------| +| 08-24 | 30 只(max_pool bug 日) | 13.6s | 09:30:14 | +| 08-25 | 3226 只 | 335.1s | 09:35:40 | +| 08-26 | 3226 只 | **1081.4s (18分钟)** | 09:48:04 | + +- 09:30:00 任务启动 → 09:48 才下单,`[delay=+1084s]`,开盘 18 分钟敞口 +- 每日 `download_financial_data 超时 120s (3226 只),跳过读缓存` 必现 +- shadow_61(影子侧同代码)同步 09:48 —— 双轨一致,纯属共同慢 + +## 根因(已定位,无需再查) + +`get_fundamentals_df(3226只)`(sanguo_portfolio/providers/sanguo_fundamentals.py:460-470): +1. `xt.download_financial_data(3226)` 卡满 120s 超时被弃(daemon 线程仍在后台抢 miniQMT 数据目录) +2. `xt.get_financial_data(3226)` 逐股读本地缓存 ≈0.3s/股 —— 3226×0.3 ≈ 16min 主体 +3. 08-25→08-26 从 335s 恶化到 1081s:疑与残留 download 线程争锁 + 开盘 miniQMT 客户端负载有关 + +## 关键事实:策略实际只用 2 个字段 + +`small_cap_ex.py` 选股2/3 全部消费 = **eps 过滤 + market_cap 升序排序取 top100**(:233-247)。 +而 **market_cap 已有本地 unified 估值 parquet 批量覆盖**(`_apply_local_market_caps`,:489,秒级、全池同口径)——08-24 P0 就是为绕开盘 Capital 下载加的。 + +## 建议方向(你们拍板) + +**先用本地 parquet 按 market_cap 全池升序 → 截 bottom ~300 → 只对这 300 只走 xt fundamentals(eps 过滤)→ 再取 top100**。 +- xt 查询量 3226→300,18min→~2min 内 +- 语义差异仅当 bottom300 中 >200 只 eps≤0 才可见(实际市场几乎不可能);如要保守可截 500 +- 动量评分(选股3/3)已经很快(2.8s)不用动 +- 备选:问数据 session unified parquet 有没有 eps/roe 列,有则整步全本地化 + +## 测试与验收 + +- 测试:bottom-N 截断后选股结果与全池版对齐(同一历史日 top100 集合 diff 应为空或个位数且可解释) +- 验收:明早 live_20 选股2/3 <180s,下单回到 09:3x +- commit 打 [vps],随下次同车上 VPS(当前 gap 里已有 919fa50 迟到成交根因修在等车) + +## 环境事实 + +- 昨日引擎 16s 同步等待弃跟踪导致迟到成交漏账(-18060)由前后端 session 今晚修账止血,你们已交的 919fa50(live_reconcile a+b)是根因修——两者不冲突 +- VPS 只读探针模板:`ssh 49.232.102.198 'C:\Python310\python.exe -X utf8 -' < script.py` +- 另请顺手确认:all_weather_ex(live#17)自 08-19 创建起零成交、常驻 500k 现金空仓——是择时门关着的预期行为还是配置问题?(非今日回归,不急) diff --git a/docs/session_prompts/2026-08-26-策略session-统一ex定寸口径.md b/docs/session_prompts/2026-08-26-策略session-统一ex定寸口径.md new file mode 100644 index 0000000..d165a43 --- /dev/null +++ b/docs/session_prompts/2026-08-26-策略session-统一ex定寸口径.md @@ -0,0 +1,35 @@ +# 移交:策略 session(定寸口径统一 _ex——用户 08-26 拍板「都要统一ex的」) + +## 拍板内容 + +用户 08-26 拍板:**回测与实盘定寸口径全部统一到 _ex 语义**(per_value = 总资产/N,即 JQ 原版 `stock_value/len` 语义)。 + +## 现状(已核实) + +| 文件 | 现口径 | 位置 | +|------|--------|------| +| momentum_timing.py | `cash = _available_cash(context); per_value = cash/target_num` | :229-232 | +| value_selection.py | 同上 | :200-203 | +| small_cap.py | 同上 | :385-388 | +| all_weather.py | `cash = _available_cash(context)/n_pick`(两处) | :204, :273 | + +- _ex 副本(841ea15 已上 VPS)已全部用 `_total_value`;helper 就在 `all_weather.py:587`(`_total_value(context)`,portfolio.total_value 优先,回退 cash+Σ持仓) +- 聚宽原版语义本来就是 stock_value/len(总资产口径)——统一同时对齐 JQ 原版 +- 前端无需动:PortfolioBacktest.vue `max_pool` 默认已是 0(=全市场不限,与实盘 env 一致;记忆里「默认30」已过时) + +## 要做的 + +1. 四个原版策略的 per_value 换 `_total_value`(带 _ex 同款 `total<=0` 守卫);all_weather 两处同改 +2. **顺手带上低优尾巴**:value_selection 选股 `set` → `sorted`(顺序确定化,你们 08-15 就记了待办) +3. 测试锚点可镜像 `tests/portfolio/test_sizing_total_value.py`(stale_cash=1000 vs total=10500 那组) +4. 注意:改完**历史回测结果会变**(这正是目的——回测↔实盘对齐);如果有对照基线需求跑一次前后对比留档 + +## 验收 + +- 回测侧同参数下原版与 _ex 副本选股+定寸一致(TET 副本对照天然就是验收) +- commit 打 [vps],随下次同车 + +## 环境事实 + +- VPS tag=vps-deployed@919fa50(08-26 19:50 推,含你们的 live_reconcile 根因修——**明天 15:05 EOD 对账首次实跑**,15:10 恒等式观察 #38 第 1 绿日) +- 08-26 恒等式已修账至 0.000%(当日买侧 4 笔迟到漏记也手动补齐,002159/002576/002633/002862 共 700 股)——此后同类由 live_reconcile 自动兜 diff --git a/frontend/src/api/paper.ts b/frontend/src/api/paper.ts index 487c953..7e30e59 100644 --- a/frontend/src/api/paper.ts +++ b/frontend/src/api/paper.ts @@ -222,3 +222,41 @@ export async function getReconcilePairs(date?: string): Promise '/paper/reconcile', { params: date ? { date } : {} }) return data.pairs } + +// ===== 账户恒等式(B5):全账户市值 = Σ实例账本市值 + 未归因(容忍 ≤0.5%) ===== + +export interface IdentityUnattrPosition { + symbol: string + snapshot_volume: number + instance_volume: number + diff: number +} + +export interface ReconcileIdentityRow { + account: string + date: string + status: string // pass | unattributed_over_tol | snapshot_missing | no_instances + snapshot_mv: number | null + instance_mv_total: number + unattributed_mv: number | null + unattributed_pct: number | null + tolerance_pct: number + instances: { id: number; name: string; mv: number }[] + unattributed_positions: IdentityUnattrPosition[] +} + +export interface ReconcileIdentityReport { + date: string + rows: ReconcileIdentityRow[] + identity_passed: boolean +} + +export async function getReconcileIdentity( + date?: string, + refresh = false, +): Promise { + const { data } = await apiClient.get( + '/paper/reconcile/identity', + { params: { ...(date ? { date } : {}), ...(refresh ? { refresh: true } : {}) } }) + return data +} diff --git a/frontend/src/views/Layout.vue b/frontend/src/views/Layout.vue index 9d40f26..d616761 100644 --- a/frontend/src/views/Layout.vue +++ b/frontend/src/views/Layout.vue @@ -37,7 +37,7 @@ const PAGE_TITLE: Array<{ match: RegExp; group: string; title: string }> = [ { match: /^\/paper\/new$/, group: '模拟盘', title: '新建模拟盘' }, { match: /^\/paper\/result\//, group: '模拟盘', title: '模拟盘结果' }, { match: /^\/paper\/live\//, group: '模拟盘', title: '实走监控' }, - { match: /^\/paper\/reconcile/, group: '模拟盘', title: '双轨对账' }, + { match: /^\/paper\/reconcile/, group: '模拟盘', title: '对账中心' }, { match: /^\/paper$/, group: '模拟盘', title: '模拟盘' }, { match: /^\/live\/new$/, group: '实盘', title: '新建实盘' }, { match: /^\/live\/monitor\//, group: '实盘', title: '实盘监控' }, @@ -73,7 +73,7 @@ const CMD_ITEMS: CmdItem[] = [ { label: '批量评估', group: '投研', path: '/factor/batch' }, { label: '因子分析', group: '投研', path: '/factor/new' }, { label: '模拟盘列表', group: '模拟', path: '/paper' }, - { label: '双轨对账', group: '模拟', path: '/paper/reconcile' }, + { label: '对账中心', group: '模拟', path: '/paper/reconcile' }, { label: '新建模拟盘', group: '模拟', path: '/paper/new' }, { label: '实盘列表', group: '实盘', path: '/live' }, { label: '新建实盘', group: '实盘', path: '/live/new' }, @@ -182,7 +182,7 @@ function onLogout(): void { 模拟盘列表 - 双轨对账 + 对账中心 新建模拟盘 diff --git a/frontend/src/views/paper/Reconcile.vue b/frontend/src/views/paper/Reconcile.vue index d569b8a..55ffa58 100644 --- a/frontend/src/views/paper/Reconcile.vue +++ b/frontend/src/views/paper/Reconcile.vue @@ -1,16 +1,27 @@