feat: 第四类买卖点(B4/S4)融入缠论引擎与 web 展示

研究侧的 fast_bsp3 一直只活在 research/lib/ 里,web 端看不到,回测与目视
两条线对不上。这次把它搬进引擎,作为独立的第四类买卖点。

之所以单独立类而不是当作 B3/S3 的低滞后版:step30/31 显示引擎原生的
B3/S3 统计上呈逆势、显著亏损(胜率 27.4%、PF 0.66、t −18.76),而同一组
过滤器把 B4 从 PF 1.59 提到 2.26 却对它无效(0.66→0.71)。两者选的是
不同的交易群体,不是同一信号的早晚两版。

- chanlun/analysis/fast_bsp.py 原样搬入 find_fast_bsp3 与 build_htf_zones,
  另加 add_zone_ladder / htf_fx_timeline / attach_htf_agree
- research/lib/ 两个模块改为转发,所有 step 脚本导入不变,信号逐条比对一致
- 大级别上下文用 resample 从同一份 df 构建,不额外拉数据,因此与界面上选的
  周期和时间范围无关
- 前端三个复选框 + 过滤模式下拉;未过滤的原始信号用浅色,避免与主口径混淆

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-28 00:05:26 +08:00
co-authored by Cursor
parent 7e339d2a54
commit 9b72173285
17 changed files with 702 additions and 209 deletions
+5 -1
View File
@@ -241,7 +241,9 @@ def analyze():
'is_sure': bool(bsp.is_sure),
'sure_time': format_time_safely(bsp.sure_time, client_tz) if bsp.sure_time else None,
'zs_count': int(bsp.zs_count) if hasattr(bsp, 'zs_count') else 0
} for bsp in analysis_result.get('bsp_list', [])]
} for bsp in analysis_result.get('bsp_list', [])],
# 添加主周期第四类买卖点(B4/S4,低滞后三类买卖点)
'fast_bsp_list': serialize_fast_bsp_list(analysis_result.get('fast_bsp_list', []), client_tz)
})
@@ -425,6 +427,7 @@ def analyze():
'sure_time': format_time_safely(bsp.sure_time, client_tz) if bsp.sure_time else None,
'zs_count': int(bsp.zs_count) if hasattr(bsp, 'zs_count') else 0
} for bsp in element_analysis.get('bsp_list', [])]
result['element_fast_bsp_list'] = serialize_fast_bsp_list(element_analysis.get('fast_bsp_list', []), client_tz)
# 次次周期:仅当已指定次周期且次次周期有效时获取
if sub_sub_timeframe and is_smaller_or_equal_timeframe(sub_sub_timeframe, element_timeframe):
@@ -526,6 +529,7 @@ def analyze():
'sure_time': format_time_safely(bsp.sure_time, client_tz) if bsp.sure_time else None,
'zs_count': int(bsp.zs_count) if hasattr(bsp, 'zs_count') else 0
} for bsp in sub_sub_analysis.get('bsp_list', [])]
result['sub_sub_fast_bsp_list'] = serialize_fast_bsp_list(sub_sub_analysis.get('fast_bsp_list', []), client_tz)
result['sub_sub_chan_macd'] = serialize_chan_macd_data(sub_sub_analysis.get('chan_macd', {}), client_tz)
try:
sub_sub_klc_trend = []