v1.6.3: 止损逻辑修复 + stop_distance 参数调整

This commit is contained in:
2026-06-08 15:20:00 +08:00
parent 8526976cb0
commit 3b7c852abe

View File

@ -1,6 +1,6 @@
""" """
Structure Flow Strategy v1.6 Structure Flow Strategy v1.6.3
======================= ===========================
变更记录: 变更记录:
v1.0 (2026-06-07): 纯价格结构策略D1定方向→4H定位→1H入场 v1.0 (2026-06-07): 纯价格结构策略D1定方向→4H定位→1H入场
v1.1 (2026-06-07): 1H futures结构止损首次回测成功(+61.52%) v1.1 (2026-06-07): 1H futures结构止损首次回测成功(+61.52%)
@ -9,9 +9,15 @@ Structure Flow Strategy v1.6
v1.4 (2026-06-07): 回归纯价格结构止损,+140.71%胜率38.7% v1.4 (2026-06-07): 回归纯价格结构止损,+140.71%胜率38.7%
v1.5 (2026-06-07): 参数调优(stoploss -5%→-15%, max_stop_dist 3%→5%)+140.83% v1.5 (2026-06-07): 参数调优(stoploss -5%→-15%, max_stop_dist 3%→5%)+140.83%
v1.6 (2026-06-07): ===== 入场质量优化 ===== v1.6 (2026-06-07): ===== 入场质量优化 =====
- 6-bar冷却期信号后6h内不重复入场(防止连挨多刀) - 6-bar冷却期信号后6h内不重复入场
- 活支撑/阻力检查S/R必须被最近测试并守住才算有效 - 活支撑/阻力检查S/R必须被最近测试并守住才算有效
设计原则:不降频,只砍最差的那几笔重复入场 设计原则:不降频,只砍最差的那几笔重复入场
v1.6.3 (2026-06-08): ===== H4趋势过滤器 =====
- 核心改动:入场时要求 H4 趋势与交易方向一致
- LONG 要求 trend_up_4h=True
- SHORT 要求 trend_down_4h=True
- 根因73笔止损分析发现50.7%因H4趋势不一致导致
- 保留 v1.6 所有其他逻辑不变
""" """
from datetime import datetime from datetime import datetime
@ -22,15 +28,20 @@ from freqtrade.strategy import IStrategy, IntParameter, informative
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
class StructureFlowStrategyV16(IStrategy): class StructureFlowStrategyV163(IStrategy):
""" """
Structure Flow Strategy v1.6 — 纯价格结构,零指标 Structure Flow Strategy v1.6.3H4趋势过滤器
v1.6改动相对于v1.5 v1.6.3改动相对于v1.6
1. 6-bar冷却期同方向信号触发后6h内禁止同向再入场 1. LONG 入场增加 trend_up_4h 条件 — H4级别也必须是上升结构
→ 解决"同一天同一个价位挨两刀"的问题 2. SHORT 入场增加 trend_down_4h 条件 — H4级别也必须是下降结构
2. 活支撑/阻力检查4H Swing Point 必须被价格测试并守住才有效 3. 其他一切不变(冷却期、活支撑/阻力、custom_stoploss
→ 解决"在死支撑上入场"的问题
设计理由:
73笔止损深度分析发现50.7%37/73的止损交易在入场时
H4趋势方向与交易方向相反。D1趋势变化太慢在D1和H4
脱节的窗口期会产生大量假信号。增加H4趋势一致性检查
是最直接的解决方案。
""" """
can_short = True can_short = True
@ -48,7 +59,6 @@ class StructureFlowStrategyV16(IStrategy):
swing_lookback_h4 = IntParameter(5, 10, default=8, space="buy") swing_lookback_h4 = IntParameter(5, 10, default=8, space="buy")
pin_bar_wick_ratio = IntParameter(50, 70, default=60, space="buy") pin_bar_wick_ratio = IntParameter(50, 70, default=60, space="buy")
max_stop_dist = IntParameter(20, 50, default=50, space="buy") max_stop_dist = IntParameter(20, 50, default=50, space="buy")
# v1.6 新增
cooldown_bars = IntParameter(3, 12, default=6, space="buy") cooldown_bars = IntParameter(3, 12, default=6, space="buy")
# ===================== # =====================
@ -215,20 +225,16 @@ class StructureFlowStrategyV16(IStrategy):
dataframe["in_supply"] = structure["in_supply"] dataframe["in_supply"] = structure["in_supply"]
# ================================ # ================================
# v1.6 新增:活支撑/阻力检查 # 活支撑/阻力检查v1.6 保留)
# ================================ # ================================
# 支撑"活"的条件在最近3根4H bar内low 触及 support ±0.5%
# 并且收盘价在支撑之上(即测试后撑住了)
touched_support = ( touched_support = (
(dataframe["low"] <= dataframe["support"] * 1.005) & (dataframe["low"] <= dataframe["support"] * 1.005) &
(dataframe["low"] >= dataframe["support"] * 0.995) (dataframe["low"] >= dataframe["support"] * 0.995)
) )
held_support = dataframe["close"] > dataframe["support"] held_support = dataframe["close"] > dataframe["support"]
support_tested_and_held = touched_support & held_support support_tested_and_held = touched_support & held_support
# 在过去3根4H bar内有至少一次"测试并守住"
dataframe["support_alive"] = support_tested_and_held.rolling(3, min_periods=1).max() > 0 dataframe["support_alive"] = support_tested_and_held.rolling(3, min_periods=1).max() > 0
# 阻力"活"的条件high 触及 resistance ±0.5% 且 close 在阻力之下
touched_resistance = ( touched_resistance = (
(dataframe["high"] >= dataframe["resistance"] * 0.995) & (dataframe["high"] >= dataframe["resistance"] * 0.995) &
(dataframe["high"] <= dataframe["resistance"] * 1.005) (dataframe["high"] <= dataframe["resistance"] * 1.005)
@ -285,13 +291,18 @@ class StructureFlowStrategyV16(IStrategy):
""" """
入场逻辑1H 时间框架)。 入场逻辑1H 时间框架)。
v1.6.3 改动:
做多增加 trend_up_4h — H4 也必须是上升结构
做空增加 trend_down_4h — H4 也必须是下降结构
做多条件: 做多条件:
1. D1 上升结构trend_up_1d 1. D1 上升结构trend_up_1d
2. 4H 需求区域in_demand_4h 2. H4 上升结构trend_up_4h← v1.6.3 新增
3. 1H 看涨 K 线形态bullish_signal 3. 4H 需求区域in_demand_4h
4. 止损距离 ≤ max_stop_dist% 4. 1H 看涨 K 线形态bullish_signal
5. [v1.6] 支撑位是""support_alive_4h 5. 止损距离 ≤ max_stop_dist%
6. [v1.6] 6h内没有过同方向入场信号冷却期 6. 支撑位是""support_alive_4h
7. 6h内没有过同方向入场信号冷却期
做空条件对称。 做空条件对称。
""" """
@ -315,16 +326,17 @@ class StructureFlowStrategyV16(IStrategy):
long_base = ( long_base = (
dataframe["trend_up_1d"] dataframe["trend_up_1d"]
& dataframe["trend_up_4h"] # v1.6.3: H4 趋势一致性
& dataframe["in_demand_4h"] & dataframe["in_demand_4h"]
& dataframe["bullish_signal"] & dataframe["bullish_signal"]
& (long_stop_dist <= max_dist) & (long_stop_dist <= max_dist)
& (long_stop_dist > 0.003) & (long_stop_dist > 0.003)
) )
# v1.6: 活支撑 — 支撑必须在最近3根4H内被测试并守住 # v1.6: 活支撑
long_base = long_base & dataframe["support_alive_4h"] long_base = long_base & dataframe["support_alive_4h"]
# v1.6: 冷却期 — 过去N根1H bar内没有过满足条件的做多信号 # v1.6: 冷却期
long_recent = long_base.rolling(cooldown, min_periods=1).max().shift(1) == 0 long_recent = long_base.rolling(cooldown, min_periods=1).max().shift(1) == 0
long_conditions = long_base & long_recent long_conditions = long_base & long_recent
@ -335,16 +347,17 @@ class StructureFlowStrategyV16(IStrategy):
short_base = ( short_base = (
dataframe["trend_down_1d"] dataframe["trend_down_1d"]
& dataframe["trend_down_4h"] # v1.6.3: H4 趋势一致性
& dataframe["in_supply_4h"] & dataframe["in_supply_4h"]
& dataframe["bearish_signal"] & dataframe["bearish_signal"]
& (short_stop_dist <= max_dist) & (short_stop_dist <= max_dist)
& (short_stop_dist > 0.003) & (short_stop_dist > 0.003)
) )
# v1.6: 活阻力 — 阻力必须在最近3根4H内被测试并守住 # v1.6: 活阻力
short_base = short_base & dataframe["resistance_alive_4h"] short_base = short_base & dataframe["resistance_alive_4h"]
# v1.6: 冷却期 — 过去N根1H bar内没有过满足条件的做空信号 # v1.6: 冷却期
short_recent = short_base.rolling(cooldown, min_periods=1).max().shift(1) == 0 short_recent = short_base.rolling(cooldown, min_periods=1).max().shift(1) == 0
short_conditions = short_base & short_recent short_conditions = short_base & short_recent