全系统key配对升级 bug4

全系统 Pair-Key 重构后缺陷分析报告

分析日期: 2026-02-19
分析范围: 全系统 Key 改为配对维度 (symbol, base_symbol) 后的完整状态评估


一、已修复项确认 ✅

# Bug 文件 状态
1 平仓失败路径无锁保护 position_manager.py:527 ✅ 已修复 with self._lock
2 配对级参数不继承币种级 config.py:362-404 ✅ 已修复,传入 symbol_overrides
3 就绪阈值过低 (25%→50%) strategy.py:134,141,386 ✅ 已修复 // 4// 2
4 新币黑名单仅 symbol 维度 realtime_kline_service_base.py:244 ✅ 已改为 set[tuple[str, str]]
5 数据自愈 zscore 查询缺 base_symbol orchestrator.py:466-467 ✅ 已添加 AND base_symbol = %s
6 数据自愈触发列表仅枚举 symbol realtime_kline_service_base.py:1690 ✅ 已改为 SELECT DISTINCT symbol, base_symbol

二、仍存在的缺陷

缺陷 A (高):symbol_blacklistclose_disabled_symbols 未配对化

文件: src/trading/config.py:69,71,259,265-270

现状:

symbol_blacklist: set[str]           # 仅存储 coin name,如 "PURR"
close_disabled_symbols: set[str]     # 仅存储 coin name

问题: 这两个集合以 coin 维度工作,无法区分同一 symbol 的不同配对。例如 PURR|HYPE 需要禁止平仓而 PURR|BTC 不需要时,当前设计无法处理。

影响范围:

  • config.py:259is_symbol_allowed() 只检查 coin,无法按配对区分
  • config.py:265-270is_close_disabled() 只检查 coin
  • position_manager.py:243close_position() 调用 is_close_disabled(symbol) 不传 base_symbol
  • position_manager.py:1021_collect_orphan_candidates()coin in close_disabled_symbols

严重程度: 🟡 中等 — 当前系统实际运行的是单 base_symbol 模式,短期不会触发;但与系统设计目标(配对维度独立)不一致,扩展到多 base 时会暴露。


缺陷 B (中):_pair_cache 无动态刷新机制

文件: src/services/realtime_kline_service_base.py:206-209

现状:

self._pair_cache: Dict[str, List[str]] = {}
self._load_pair_cache()  # 仅在 __init__ 时加载一次

问题: 配对关系缓存仅在服务启动时从 DB 加载。如果运行期间 cointegrated_pairs 表中新增了配对关系,服务无法感知,新配对不会被分析。

影响: 需要重启服务才能识别新配对。在系统需要动态添加配对时是瓶颈。


缺陷 C (中):_execute_close 中 position 字段修改在锁外

文件: src/trading/position_manager.py:358-361

现状:

# 这段代码在 _execute_close() 内,此时锁已在 close_position() 入口处释放
position.status = PositionStatus.CLOSED   # ← 无锁保护
position.close_time = now                 # ← 无锁保护
position.realized_pnl = realized_pnl      # ← 无锁保护
position.alt_current_price = alt_exit_price

with self._lock:
    self._positions.pop(key, None)        # ← 只有 pop 有锁

问题: position 对象是共享引用。在 status 被设为 CLOSED 之前,其他线程(如同步线程、止损检查线程)可以通过 self._positions[key] 访问到同一个对象,读到不一致的中间状态(status=CLOSING 但 pnl 已更新)。

对比: 已修复的 Bug #1(line 527)是同类问题。此处是成功路径上的同类遗漏。

缓解因素: Python GIL 使得实际 data race 概率极低,但设计上不一致。


缺陷 D (低):脚本文件 SQL 查询未配对化(~18 处)

影响文件:

  • src/scripts/backtest_base.py
  • src/scripts/optimize_adaptive_zscore.py
  • src/scripts/optimize_adaptive_zscore_v2.py
  • src/scripts/fix_buffer_loading.py
  • src/scripts/backfill_all_data.py
  • src/scripts/validate_multicoin_btc_base.py
  • src/scripts/validate_ema_std_decouple.py
  • src/scripts/query_analyze_result/check_missing_purr_zscore.py
  • src/scripts/query_analyze_result/check_buffer_continuity.py
  • src/scripts/query_analyze_result/query_eth_zscore.py
  • src/scripts/query_analyze_result/query_purr_zscore.py
  • src/scripts/query_analyze_result/query_purr_zscore_beyond2_5.py
  • src/scripts/query_analyze_result/compute_multi_timeframe_zscore.py

模式: WHERE symbol = %s 缺少 AND base_symbol = %s

影响: 脚本仅用于调试/回测,不影响生产。但当 DB 中同一 symbol 存在多个 base_symbol 的记录时,查询结果会混合不同配对的数据,导致回测/分析结论不准确。


缺陷 E (低):历史数据压缩策略不一致

问题: 数据库迁移只对 新建的压缩段 使用 (symbol, base_symbol) 作为分段键。已有的历史压缩块仍使用旧的 symbol-only 压缩策略。两种压缩策略共存于同一张表。

影响: 不影响查询正确性(WHERE 过滤在压缩之上),但增加了运维理解成本,且查询性能在历史区间可能略有差异。


三、设计层面的不足

不足 1:黑名单机制碎片化

系统存在 三套 独立的黑名单机制,职责边界模糊:

机制 位置 维度 生命周期
symbol_blacklist (config) config.py:69 coin 静态(env 变量)
new_coin_blacklist (runtime) realtime_kline_service_base.py:244 (symbol, base_symbol) ✅ 运行时(重启清零)
DB 黑名单 (_blacklist_cache) realtime_kline_service_base.py:249 (symbol, base_symbol) ✅ 持久化(24h TTL)

其中 config 层的 symbol_blacklist 是唯一未配对化的。建议:要么统一为配对维度,要么明确文档化其 "coin 级全局禁止" 的语义。

不足 2:_execute_close 锁策略不对称

close_position() 方法中的三条退出路径锁行为不一致:

路径 锁状态 状态
成功(line 358-366) 字段修改无锁,仅 pop 有锁 ⚠️ 不一致
异常(line 284-287) with self._lock 恢复 ✅ 有锁
正常失败(line 527) with self._lock 恢复 ✅ 已修复

理想状态应统一:所有 position 状态字段的修改都在锁内完成。


四、总结与优先级建议

优先级 缺陷 建议
🔴 无 核心生产路径已完整
🟡 高 缺陷 A: 黑名单/禁止平仓未配对化 扩展到多 base 前必须修复
🟡 中 缺陷 B: _pair_cache 无刷新 添加定时刷新(如 5min 周期)或 DB 变更通知
🟡 中 缺陷 C: 成功路径 position 字段无锁 将 status/pnl 修改移入 with self._lock
🟢 低 缺陷 D: 脚本 SQL 未配对化 批量添加 AND base_symbol = %s
🟢 低 缺陷 E: 历史压缩策略不一致 文档化或安排重压缩窗口

总体评估: 核心生产路径(策略 → 信号 → 仓位管理 → 交易执行 → 数据自愈)的配对维度重构 已基本完成(~95%),3 个关键 Bug 已修复。剩余问题主要集中在:(1) config 层黑名单的配对化设计债务,(2) 辅助设施(缓存刷新、脚本)的配套更新,(3) 锁策略的一致性打磨。在当前单 base_symbol 运行模式下,这些问题不会触发实际故障,但在扩展到多 base 场景前需要逐步清理。

Read more

跑步的技巧(滚动落地)

“滚动落地(rolling contact / rolling foot strike)”不是一种教条式的“脚法”,而是一种 让冲击沿着整只脚、整条后链逐级传递的落地机制。 它的核心不是“你先用哪儿着地”,而是: 你的脚落地之后,冲击是不是像轮子一样滚过去,而不是像锤子一样砸下去。 这就是滚动落地的本质。 一、什么叫“滚动落地”? 你可以把它理解成两种完全不同的落地方式: 1. 砸地(撞击式) 脚像锤子一样拍到地上: * 要么后跟先砸 * 要么前掌先戳 * 冲击集中在一个点 * 一个结构瞬间吃掉大部分载荷 结果就是: * 后跟砸 → 膝盖难受 * 前掌戳 → 前脚掌磨烂 * 都不是长跑友好模式 这叫 撞击式着地(impact strike)。 2. 滚地(滚动式) 脚像轮胎一样“滚”过地面: * 不是某一点硬砸 * 而是外侧中足先轻触 * 再向前滚到前掌 * 最后从大脚趾蹬离

By SHI XIAOLONG

AMI的优越性

世界模型(World Models)的具体例子 如下,我按类型分类,便于理解。每类都附带实际实现、演示效果和应用场景。 1. Yann LeCun / Meta 的 JEPA 系列(最直接对应“世界模型”概念) 这些是 LeCun 主张的非生成式抽象预测世界模型代表。 * I-JEPA(Image JEPA,2023) 输入一张图像,模型把不同区域(context 和 target)编码成抽象表示,然后预测 target 的表示(不在像素级别重建)。 例子:给定一张遮挡了部分物体的图片,模型能预测“被遮挡物体的大致位置和属性”,构建对物体持久性和空间关系的理解。 这是一个“原始世界模型”,能学习物理常识(如物体不会凭空消失)。 * V-JEPA / V-JEPA 2(Video JEPA,

By SHI XIAOLONG

什么是:“世界模型(World Models)”

世界模型(World Models) 是人工智能领域的一个核心概念,尤其在 Yann LeCun 等研究者推动的下一代 AI 架构中占据中心位置。它指的是 AI 系统在内部构建的对现实世界的抽象模拟或内部表示,让机器能够像人类或动物一样“理解”物理世界、预测未来、规划行动。 简单比喻 想象你闭上眼睛也能“看到”房间里的物体会如何移动、碰撞或掉落——这就是你大脑里的世界模型。AI 的世界模型就是类似的“数字孪生”(digital twin)或“内部模拟器”:它不是简单记住数据,而是学习世界的动态、因果关系和物理直觉(如重力、物体持久性、遮挡、因果等)。 为什么需要世界模型? 当前主流的大型语言模型(LLM) 擅长处理文本(统计模式预测),但存在根本局限: * 缺乏对物理世界的真正理解 → 容易“幻觉”、无法可靠规划。 * 样本效率低 → 人类/

By SHI XIAOLONG

K线周期可配置化设计方案

K线周期可配置化设计方案 1. 背景与目标 当前 Beta 套利策略的 K 线周期硬编码为 "1h",分散在多个文件中。需要: 1. 将 K 线周期从 1h 改为 2h 2. 提取为环境变量 BETA_ARB_KLINE_INTERVAL,使其可在 .env 中配置 2. 影响范围分析 2.1 需要修改的文件(共 6 个) 文件 硬编码位置 修改内容 src/trading/config.py BetaArbConfig dataclass 新增 kline_interval 字段,

By SHI XIAOLONG