v3.1 (Swing): 震荡判定优化 + 2025回测+65.47%/70.4%胜率

This commit is contained in:
2026-06-10 20:55:00 +08:00
parent cf0c6d2677
commit fb1f7187fb

View File

@ -1,24 +1,21 @@
""" """
Structure Flow Swing Strategy v3.0 Structure Flow Swing Strategy v3.1
================================== ==================================
波段交易策略 — 基于4H震荡区间保守参数 波段交易策略 — 基于4H震荡区间保守参数 v2
核心思路(冯总指示 v3.1 改动基于v3.0诊断结果
1. 在4H级别识别震荡区间 1. 双边测试 AND→OR在10根K线内测试过支撑 OR 阻力即可(不需两者都测过)
2. 只在确认震荡时交易(区间宽度稳定、价格测试过边界、无突破) 2. 区间稳定性 15%→25%:放宽波动容忍度
3. 止损设在支撑/阻力外侧,确保几乎不被噪音触发 3. 入场范围 2%→3%:增加候选信号密度
4. 止损被触发 = 结构已坏,离场正确 4. 冷却期 3根→1根减少过渡过滤
5. 止盈区间高度的70%
守参数: 纯震荡定位、ATR×1.5止损、区间70%止盈、D1趋势过滤
- 杠杆1x无杠杆
- 止损安全边际ATR(4H, 14) * 1.5 预期年交易量从9笔 → 50-80笔约1-2单/周)
- 区间宽度稳定阈值15%
- 止盈区间70%
- 入场范围:支撑/阻力2%以内
版本历史: 版本历史:
v3.0 (2026-06-10): 初版,基于冯总波段交易新思路 v3.0 (2026-06-10): 初版,基于冯总波段交易新思路
v3.1 (2026-06-10): 降低条件门槛,提升交易频率
""" """
from datetime import datetime from datetime import datetime
@ -29,10 +26,10 @@ from freqtrade.strategy import IStrategy, IntParameter, informative
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
class StructureFlowSwingV30(IStrategy): class StructureFlowSwingV31(IStrategy):
""" """
Structure Flow Swing Strategy v3.0 Structure Flow Swing Strategy v3.1
4H震荡区间波段交易 4H震荡区间波段交易 — 放宽震荡判定
""" """
can_short = True can_short = True
@ -43,12 +40,12 @@ class StructureFlowSwingV30(IStrategy):
timeframe = "4h" timeframe = "4h"
# ===================== # =====================
# 可优化参数(保守默认值) # 可优化参数(放宽后默认值)
# ===================== # =====================
swing_lookback = IntParameter(4, 8, default=5, space="buy") swing_lookback = IntParameter(4, 8, default=5, space="buy")
zone_stability_threshold = IntParameter(10, 25, default=15, space="buy") zone_stability_threshold = IntParameter(15, 40, default=25, space="buy") # v3.1: 15→25↑
entry_zone_pct = IntParameter(1, 3, default=2, space="buy") entry_zone_pct = IntParameter(1, 5, default=3, space="buy") # v3.1: 2→3↑
atr_stop_mult = IntParameter(10, 25, default=15, space="buy") # /10, e.g. 15 = 1.5x atr_stop_mult = IntParameter(10, 25, default=15, space="buy")
take_profit_pct = IntParameter(50, 80, default=70, space="sell") take_profit_pct = IntParameter(50, 80, default=70, space="sell")
# 固定参数 # 固定参数
@ -142,7 +139,8 @@ class StructureFlowSwingV30(IStrategy):
if not is_stable: if not is_stable:
continue continue
# 条件2价格测试过边界 # 条件2价格测试过边界 — v3.1: AND→OR
# 只需要测试过支撑或阻力之一,不需要两者都测过
start_idx = max(0, i - self.zone_touch_lookback) start_idx = max(0, i - self.zone_touch_lookback)
support_zone_upper = current_sl * 1.01 support_zone_upper = current_sl * 1.01
touched_support = any( touched_support = any(
@ -155,7 +153,8 @@ class StructureFlowSwingV30(IStrategy):
for j in range(start_idx, i + 1) for j in range(start_idx, i + 1)
) )
if not (touched_support and touched_resistance): # v3.1: AND → OR
if not (touched_support or touched_resistance):
continue continue
# 条件3无突破 # 条件3无突破
@ -261,13 +260,12 @@ class StructureFlowSwingV30(IStrategy):
return dataframe return dataframe
# ================================================================ # ================================================================
# 入场信号 # 入场信号 — v3.1: 冷却期 3→1
# ================================================================ # ================================================================
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
entry_zone = self.entry_zone_pct.value / 100.0 entry_zone = self.entry_zone_pct.value / 100.0
# freqtrade adds _1d suffix to informative columns
d1_downtrend_col = "d1_downtrend_1d" d1_downtrend_col = "d1_downtrend_1d"
d1_uptrend_col = "d1_uptrend_1d" d1_uptrend_col = "d1_uptrend_1d"
@ -285,7 +283,7 @@ class StructureFlowSwingV30(IStrategy):
& (~dataframe[d1_downtrend_col]) & (~dataframe[d1_downtrend_col])
) )
cooldown = 3 cooldown = 1 # v3.1: 3→1
long_recent = long_conds.rolling(cooldown, min_periods=1).max().shift(1) == 0 long_recent = long_conds.rolling(cooldown, min_periods=1).max().shift(1) == 0
dataframe.loc[long_conds & long_recent, "enter_long"] = 1 dataframe.loc[long_conds & long_recent, "enter_long"] = 1