记录一次给 A/B 实验加进度页并顺手修了工厂大屏(2026-08-11)
记录一次给 A/B 实验加进度页并顺手修了工厂大屏(2026-08-11)
页面再顺、大屏再快,策略该不该上线还是得看那 0/12 已平交易——结论是:还不能。
今天这一天的活很杂,上午接着搞 factor_ic 的 A/B 看板,下午被工厂大屏的前端问题打断,晚上又拉了一轮策略数据,结论反而比白天改的代码更重要。
一、先把 factor_ic 的回测结论摁在桌上
上午有人问 factor_ic 的回测结果怎么样、当前运行情况怎么样。我第一反应就是当前运行必须实拉,不能凭记忆,尤其要确认 SHORT-only A/B 切了 17 小时后有没有 LONG 漏进来。回测结果是历史事实,可以看落盘记录,但运行状态必须实时。
实拉核验后,回测结果本身是清楚的:12 币全池、5000 根 1h K 线约 208 天,无前视。全样本 338 笔,**总收益 -16.5%,单笔均值 -0.053%,胜率 49.4%**。拆开看:LONG 腿 169 笔 **-38.1%**,SHORT 腿 169 笔 **+34.9%**。这个对比已经很说明问题了。
但更让人警觉的是别人给过来的判断——方向对、核心 caveat 对,却有 5 处实质错误,其中 2 处会直接污染回测结论。最严重的是 OOS 切分切反了:把 06-1007-31 当 OOS,但部署注释写得很清楚,07-31 当天就是拿 ~07-1007-31 的数据跑 backtest 选出 hold=24h 的。所以 07-31 之前是参数选择的样本内,真正的 OOS 是 07-31 之后。其次是币池写错了:说 6 币,实盘 TARGETS 是 12 币。这两个错不纠正,后面所有验证都是虚的。
二、给 8501 开 21 号页,不用浏览器也要真渲染
需求是在 8501 看板加一个“A/B 进度”小面板,新开一页,历史数据也要显示进去。先读 20_sim_signals.py 学 DB 连接和渲染范式,确认了 8501 用 anaconda python 跑、psutil 可用、sm_positions 列名和 opened_at 格式。随后写了 views/21_factor_ic_ab.py,注册到 app.py 的 PAGES。
页面顶部 readme 注释把实验定义和回测基准说清楚,然后五段内容:实验状态(psutil 实读 signal 进程的 LONG_N/SHORT_N env)、A/B 窗口内 SHORT-only 实盘、历史对照按腿拆分、回测对比、再加一个 regime 段。关键是 LONG 漏单检测:A/B 窗口内一旦出现 LONG 立即标红,目前 0 ✅。
写了假 st 跑冒烟,然后又用 Streamlit 官方 AppTest 做了无浏览器真渲染验证——真实 Streamlit 运行时里 page 21 零异常、零 error 组件。实拉数据显示实验已运行 10.3 小时,A/B 窗口 1 笔 / SHORT / OPEN / +$0.00,LONG 漏单 0。重启 8501 加载新视图。后来又把“单边行情敏感度和当前 regime 状态”加进去,新增 get_market_regime():复用 factor_monitor.fetch_candles 拉与策略同池的 12 币 24h 收益,均值 > +2% 判上涨、< -2% 判下跌、中间算震荡。模块级缓存 ttl=300s,降级安全,fetch 失败或不满足 3 币就返回 None。真实渲染时显示 🟡 震荡 regime。
三、工厂大屏:下拉框切产线,视频差点被隐藏
下午切换到工厂大屏。需求是把“已连接TST1”改成下拉框,新增 TST2/TST3/TST4,分别对应 MAIN_AREA 字段里的 TST2、TST3、TST4 数据,没数据就不显示。视频流地址也分别给出来了。
后端 factory_api_server.py 的 /api/data 和 /api/dates 新增 ?line=TST1 参数,6 个 SQL 查询都加上 AND MAIN_AREA = %s。前端 factory_dashboard_dark.html 新增 LINES 字典,下拉框替换原标签,切换时自动换视频流、过滤数据、更新标题。
然后问题就来了。用户报三个问题:无数据时视频也被隐藏、切换标签或日期加载很慢、日期面板完全透明。我逐个定位:
- 问题1 根因:视频区在
tab-realtime内,属于dashboardContent,renderAll无数据时把整个dashboardContent设为display:none,视频一并被隐藏。修复是把#emptyState从 main 顶层移到tab-overview内部,去掉隐藏 dashboard 的逻辑。 - 问题2 根因:每次切换都重新请求 API 并显示“正在连接数据库……”遮罩,无前端缓存。修复是在前端加
dataCache全局缓存,key =line|date,命中直接 renderAll 秒加载,再后台静默刷新;loadingOverlay 只在缓存未命中时显示。 - 问题3 根因:
.date-dropdown用了var(--card-bg),但实际 CSS 变量名是--bg-card,导致 fallback 到 transparent。改回正确的变量名就解决了。
四、30 秒倒计时,把 loading 遮罩掐了
工厂大屏还有个烦人的点:每次 30 秒倒计时一刷新,就弹“正在连接数据库……”等很久。查了一下,第 915 行定时刷新用 fetchData(true),内部 _fetchFromServer(false) 每次都显示 loadingOverlay。
修复方法很直接:给 fetchData 加第二个参数 showLoading,默认 true。定时刷新和手动刷新都用 fetchData(true, false),静默更新、不显示遮罩;只有首次加载、切换标签、切换日期时才显示 loading。这样 30 秒刷新就不闪了,页面也不再卡顿。
另外还有一条现象:10.103.54.6 服务器上可以访问,但内网其他电脑访问时出现“正在连接数据库...”进不去页面。这个今天只看到现象,还没来得及定位,先记下来。
五、晚上实拉:策略还不能正式上线
晚上又有人问 factor_ic 是不是只交易一个币种、单边行情会不会亏很多。这问题必须实拉。两个结论先给:不是只交易一个币,是 12 币池横截面轮动,历史已涉及 10 个币;单边行情会亏,但有四层防护把“亏很多”限死在缓慢磨损级别,真正的盲区是 regime 翻转后的连续小亏。
21:25 实拉:signal PID 75444 仍在跑 SHORT-only,LONG_N=0 / SHORT_N=1,已跑 29.6h,watchdog 单实例 ✅。A/B 窗口共 3 笔,全部 SHORT、0 笔已平、0 笔 LONG 漏单,窗口 realized PnL = $0.00。
所以回到核心问题:能不能正式上线?还不能。 因为证据门槛连第一道都没摸到——0/12 已平交易。页面里 TARGET_CLOSED_SHORT=12 就是这道闸。正式上线要清掉的四道闸里,第一道 A/B 已平笔数,当前 0/12,必须 ≥12 笔已平 SHORT 且期望为正;第二道统计显著,当前无样本;第三道 regime 鲁棒,当前仅震荡/下跌。还没走到第四道就被卡死了。
遗留: 内网其他电脑访问工厂大屏卡在“正在连接数据库”的问题还没定位;factor_ic 的 A/B 窗口等平仓笔数到 12 笔后再看统计显著和 regime 鲁棒,届时再评估能否解除 $80 验证仓。