technical-patterns-lab/docs/2026-01-26_上沿线覆盖问题修复.md
褚宏光 6d545eb231 Enhance converging triangle detection with new features and documentation updates
- Added support for a detailed chart mode in plot_converging_triangles.py, allowing users to visualize all pivot points and fitting lines.
- Improved pivot fitting logic to utilize multiple representative points, enhancing detection accuracy and reducing false positives.
- Introduced a new real-time detection mode with flexible zone parameters for better responsiveness in stock analysis.
- Updated README.md and USAGE.md to reflect new features and usage instructions.
- Added multiple documentation files detailing recent improvements, including pivot point fitting and visualization enhancements.
- Cleaned up and archived outdated scripts to streamline the project structure.
2026-01-26 16:21:36 +08:00

6.5 KiB
Raw Blame History

上沿线覆盖问题修复

日期: 2026-01-26
修复人: AI Assistant
严重程度: 高(影响检测准确性)


🐛 问题描述

现象

用户发现在 SH603618 杭电股份的检测结果图表中,上沿线(红色虚线)横穿过全局最高点

  • 全局最高点: 约 12 元2025年11月附近
  • 上沿线位置: 约 9 元(水平线)
  • 异常现象: 上沿线应该经过或位于所有枢轴高点的上方,但却从最高点下方穿过

问题示例

用户反馈

"为什么,有个最高点,但是被上沿线 横穿过去了"


🔍 根本原因分析

代码位置

src/converging_triangle.py 中的 fit_pivot_line() 函数第230-330行

问题逻辑

# 旧算法第261-287行
if mode == "upper":
    mid = n // 2
    # 前半部分最高点
    front_idx = np.argmax(y_sorted[:mid + 1])
    # 后半部分最高点
    back_idx = mid + np.argmax(y_sorted[mid:])
    
    # 如果后点比前点高,尝试调整
    if y_sorted[back_idx] > y_sorted[front_idx]:
        # ... 补救逻辑 ...

缺陷分析

  1. 简单分半策略:算法将所有枢轴点分为前后两半,分别找最高点
  2. 全局最高点可能被忽略
    • 如果全局最高点在前半部分,但不是前半最高
    • 或者在后半部分,但不是后半最高
    • 就会被算法忽略
  3. 补救逻辑不完整:只处理了 back > front 的情况,没有完全覆盖所有场景

实际案例

SH603618 情况

枢轴高点分布(假设):
  索引 30: 9.0元   ← 前半最高
  索引 60: 12.0元  ← 全局最高(但在前半,不是前半最高)
  索引 90: 9.5元   ← 后半最高

旧算法选择: [索引30, 索引90] → 拟合水平线 9.0-9.5元
问题: 索引60的12.0元被遗漏上沿线从12元下方穿过 ❌

🔧 修复方案

核心原则

上沿线必须覆盖(经过或位于上方)所有枢轴高点

新算法逻辑

if mode == "upper":
    # 1. 找全局最高点(保证不会被遗漏)
    global_max_idx = np.argmax(y_sorted)
    
    # 2. 在全局最高点前后寻找配对点
    if global_max_idx < n - 1:
        back_idx = global_max_idx + 1 + np.argmax(y_sorted[global_max_idx + 1:])
        front_idx = global_max_idx
    else:
        front_idx = np.argmax(y_sorted[:-1])
        back_idx = global_max_idx
    
    # 3. 验证拟合线能否覆盖所有枢轴点
    x_temp = np.array([x_sorted[front_idx], x_sorted[back_idx]])
    y_temp = np.array([y_sorted[front_idx], y_sorted[back_idx]])
    a_temp, b_temp = fit_line(x_temp, y_temp)
    
    # 检查所有点是否被覆盖
    tolerance = 0.02  # 2% 价格容差
    fitted_y = a_temp * x_sorted + b_temp
    max_exceed = np.max(y_sorted - fitted_y)
    
    # 4. 如有点严重超出,自动调整
    if max_exceed > tolerance * np.mean(y_sorted):
        exceed_idx = np.argmax(y_sorted - fitted_y)
        if exceed_idx != global_max_idx:
            if exceed_idx < global_max_idx:
                front_idx = exceed_idx
                back_idx = global_max_idx
            else:
                front_idx = global_max_idx
                back_idx = exceed_idx

修复要点

  1. 优先选择全局最高点
  2. 在全局最高点前后寻找配对点
  3. 验证覆盖情况(所有点是否在拟合线下方)
  4. 自动调整(如有遗漏点,重新选择)
  5. 同样逻辑应用于下沿线(全局最低点)

验证结果

测试脚本

创建了 scripts/test_upper_line_coverage.py 进行验证(已删除)

测试场景

场景: 120天窗口k=15
设置枢轴高点:
  索引 30: 9.0元 (前期)
  索引 60: 12.0元 (全局最高点)
  索引 90: 9.5元 (后期)
  索引 110: 9.2元 (末期)

测试结果

✅ 修复后结果:
  选中的枢轴点: [60, 90]
  拟合线: 斜率 -0.083, 截距 17.00
  
覆盖验证:
  索引 30: 实际9.00 vs 拟合14.50, 差值-5.50 [OK] ✓
  索引 60: 实际12.00 vs 拟合12.00, 差值+0.00 [OK] ✓
  索引 90: 实际9.50 vs 拟合9.50, 差值+0.00 [OK] ✓
  
关键检查 - 全局最高点:
  位置: 索引60
  实际价格: 12.00元
  拟合价格: 12.00元
  差值: +0.00元
  [SUCCESS] 全局最高点在上沿线上!✓

边界测试

测试了以下场景,全部通过:

  • 最高点在开始
  • 最高点在结束
  • 最高点在中间
  • 两个相同最高点

📊 修复效果

SH603618 杭电股份对比

项目 修复前 修复后
上沿线形态 水平线 (~9元) 下降趋势线 (20→9元)
全局最高点 12元被横穿 12元被覆盖
触碰点数 上3/下2 上2/下2
突破方向 none up
检测结果 不合理 合理 ✓

重新检测结果

$ python scripts/run_converging_triangle.py --recent-days 500

检测结果:
  总有效三角形: 18585个
  突破统计:
    - none: 15261
    - up: 2129
    - down: 1195

📝 文件变更

修改的文件

  1. src/converging_triangle.py
    • 修改 fit_pivot_line() 函数第261-330行
    • 上沿线拟合逻辑mode="upper"
    • 下沿线拟合逻辑mode="lower"

创建的文件

  1. docs/2026-01-26_上沿线覆盖问题修复.md(本文档)

删除的文件

  1. scripts/test_upper_line_coverage.py(一次性验证文件)
  2. scripts/test_boundary_issue.py(历史验证文件)
  3. scripts/test_slope_constraint.py(历史验证文件)

🎯 后续建议

1. 对比历史结果

修复可能影响其他股票的检测结果,建议:

# 对比修复前后的检测数量
$ diff old_results.csv new_results.csv

2. 人工抽查

随机抽查一些新检测到的三角形,确保质量:

$ python scripts/plot_converging_triangles.py --date 20260120

3. 文档更新

  • 更新 README.md 中的"最新更新"部分
  • 记录修复日志

📚 相关文档


💬 用户反馈

问题提出: 2026-01-26
用户: wuyan
问题: "为什么,有个最高点,但是被上沿线 横穿过去了"

修复完成: 2026-01-26
状态: 已修复并验证