v1.6: 结构突破回测验证版 + 6条件入场体系
This commit is contained in:
105
strategy.py
105
strategy.py
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Structure Flow Strategy v1.5
|
||||
Structure Flow Strategy v1.6
|
||||
=======================
|
||||
变更记录:
|
||||
v1.0 (2026-06-07): 纯价格结构策略,D1定方向→4H定位→1H入场
|
||||
@ -7,10 +7,11 @@ Structure Flow Strategy v1.5
|
||||
v1.2 (2026-06-07): Entry Candle止损,bug导致50笔硬止损全亏
|
||||
v1.3 (2026-06-07): ATR动态止损,结果-63.72%,胜率20.2%
|
||||
v1.4 (2026-06-07): 回归纯价格结构止损,+140.71%,胜率38.7%
|
||||
v1.5 (2026-06-07): ===== 参数调优 =====
|
||||
- stoploss -5% → -15%,释放结构止损空间
|
||||
- max_stop_dist 3% → 5%,增加交易频率
|
||||
其他逻辑与v1.4完全相同
|
||||
v1.5 (2026-06-07): 参数调优(stoploss -5%→-15%, max_stop_dist 3%→5%),+140.83%
|
||||
v1.6 (2026-06-07): ===== 入场质量优化 =====
|
||||
- 6-bar冷却期:信号后6h内不重复入场(防止连挨多刀)
|
||||
- 活支撑/阻力检查:S/R必须被最近测试并守住才算有效
|
||||
设计原则:不降频,只砍最差的那几笔重复入场
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
@ -21,17 +22,19 @@ from freqtrade.strategy import IStrategy, IntParameter, informative
|
||||
from freqtrade.persistence import Trade
|
||||
|
||||
|
||||
class StructureFlowStrategyV15(IStrategy):
|
||||
class StructureFlowStrategyV16(IStrategy):
|
||||
"""
|
||||
Structure Flow Strategy v1.5 — 纯价格结构,零指标
|
||||
Structure Flow Strategy v1.6 — 纯价格结构,零指标
|
||||
|
||||
v1.5改动(相对于v1.4):
|
||||
- stoploss -5% → -15%(硬止损放宽,让结构止损真正生效)
|
||||
- max_stop_dist 3% → 5%(增加交易频率)
|
||||
v1.6改动(相对于v1.5):
|
||||
1. 6-bar冷却期:同方向信号触发后,6h内禁止同向再入场
|
||||
→ 解决"同一天同一个价位挨两刀"的问题
|
||||
2. 活支撑/阻力检查:4H Swing Point 必须被价格测试并守住才有效
|
||||
→ 解决"在死支撑上入场"的问题
|
||||
"""
|
||||
|
||||
can_short = True
|
||||
stoploss = -0.15 # v1.5: -5% → -15%
|
||||
stoploss = -0.15
|
||||
use_custom_stoploss = True
|
||||
minimal_roi = {"0": 100}
|
||||
max_open_trades = 1
|
||||
@ -44,8 +47,9 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
swing_lookback_d1 = IntParameter(8, 14, default=10, space="buy")
|
||||
swing_lookback_h4 = IntParameter(5, 10, default=8, space="buy")
|
||||
pin_bar_wick_ratio = IntParameter(50, 70, default=60, space="buy")
|
||||
# v1.5: 默认值从30→50(3%→5%)
|
||||
max_stop_dist = IntParameter(20, 50, default=50, space="buy")
|
||||
# v1.6 新增
|
||||
cooldown_bars = IntParameter(3, 12, default=6, space="buy")
|
||||
|
||||
# =====================
|
||||
# 工具:Swing Point 检测
|
||||
@ -209,6 +213,30 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
dataframe["resistance"] = structure["resistance"]
|
||||
dataframe["in_demand"] = structure["in_demand"]
|
||||
dataframe["in_supply"] = structure["in_supply"]
|
||||
|
||||
# ================================
|
||||
# v1.6 新增:活支撑/阻力检查
|
||||
# ================================
|
||||
# 支撑"活"的条件:在最近3根4H bar内,low 触及 support ±0.5%
|
||||
# 并且收盘价在支撑之上(即测试后撑住了)
|
||||
touched_support = (
|
||||
(dataframe["low"] <= dataframe["support"] * 1.005) &
|
||||
(dataframe["low"] >= dataframe["support"] * 0.995)
|
||||
)
|
||||
held_support = dataframe["close"] > dataframe["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
|
||||
|
||||
# 阻力"活"的条件:high 触及 resistance ±0.5% 且 close 在阻力之下
|
||||
touched_resistance = (
|
||||
(dataframe["high"] >= dataframe["resistance"] * 0.995) &
|
||||
(dataframe["high"] <= dataframe["resistance"] * 1.005)
|
||||
)
|
||||
held_resistance = dataframe["close"] < dataframe["resistance"]
|
||||
resistance_tested_and_held = touched_resistance & held_resistance
|
||||
dataframe["resistance_alive"] = resistance_tested_and_held.rolling(3, min_periods=1).max() > 0
|
||||
|
||||
return dataframe
|
||||
|
||||
# ================================================================
|
||||
@ -240,6 +268,7 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
"trend_up_1d", "trend_down_1d",
|
||||
"trend_up_4h", "trend_down_4h",
|
||||
"in_demand_4h", "in_supply_4h",
|
||||
"support_alive_4h", "resistance_alive_4h",
|
||||
"bullish_signal", "bearish_signal",
|
||||
]
|
||||
for col in bool_cols:
|
||||
@ -257,24 +286,24 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
入场逻辑(1H 时间框架)。
|
||||
|
||||
做多条件:
|
||||
1. D1 上升结构(trend_up_1d)— 宏观方向
|
||||
2. 4H 需求区域(in_demand_4h)— 在支撑附近
|
||||
1. D1 上升结构(trend_up_1d)
|
||||
2. 4H 需求区域(in_demand_4h)
|
||||
3. 1H 看涨 K 线形态(bullish_signal)
|
||||
4. 止损距离 ≤ max_stop_dist% — 赔率过滤(v1.5: 默认5%)
|
||||
|
||||
做空条件:
|
||||
1. D1 下降结构(trend_down_1d)
|
||||
2. 4H 供给区域(in_supply_4h)
|
||||
3. 1H 看跌 K 线形态(bearish_signal)
|
||||
4. 止损距离 ≤ max_stop_dist%
|
||||
5. [v1.6] 支撑位是"活"的(support_alive_4h)
|
||||
6. [v1.6] 6h内没有过同方向入场信号(冷却期)
|
||||
|
||||
做空条件对称。
|
||||
"""
|
||||
max_dist = self.max_stop_dist.value / 100.0
|
||||
cooldown = self.cooldown_bars.value
|
||||
|
||||
# NaN 安全处理
|
||||
bool_cols = [
|
||||
"trend_up_1d", "trend_down_1d",
|
||||
"trend_up_4h", "trend_down_4h",
|
||||
"in_demand_4h", "in_supply_4h",
|
||||
"support_alive_4h", "resistance_alive_4h",
|
||||
"bullish_signal", "bearish_signal",
|
||||
]
|
||||
for col in bool_cols:
|
||||
@ -284,25 +313,41 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
# ── 做多 ──
|
||||
long_stop_dist = (dataframe["open"] - dataframe["support_4h"]) / dataframe["open"]
|
||||
|
||||
long_conditions = (
|
||||
long_base = (
|
||||
dataframe["trend_up_1d"]
|
||||
& dataframe["in_demand_4h"]
|
||||
& dataframe["bullish_signal"]
|
||||
& (long_stop_dist <= max_dist)
|
||||
& (long_stop_dist > 0.003) # 至少0.3%距离(避免support就在眼前)
|
||||
& (long_stop_dist > 0.003)
|
||||
)
|
||||
|
||||
# v1.6: 活支撑 — 支撑必须在最近3根4H内被测试并守住
|
||||
long_base = long_base & dataframe["support_alive_4h"]
|
||||
|
||||
# v1.6: 冷却期 — 过去N根1H bar内没有过满足条件的做多信号
|
||||
long_recent = long_base.rolling(cooldown, min_periods=1).max().shift(1) == 0
|
||||
long_conditions = long_base & long_recent
|
||||
|
||||
dataframe.loc[long_conditions, "enter_long"] = 1
|
||||
|
||||
# ── 做空 ──
|
||||
short_stop_dist = (dataframe["resistance_4h"] - dataframe["open"]) / dataframe["open"]
|
||||
|
||||
short_conditions = (
|
||||
short_base = (
|
||||
dataframe["trend_down_1d"]
|
||||
& dataframe["in_supply_4h"]
|
||||
& dataframe["bearish_signal"]
|
||||
& (short_stop_dist <= max_dist)
|
||||
& (short_stop_dist > 0.003)
|
||||
)
|
||||
|
||||
# v1.6: 活阻力 — 阻力必须在最近3根4H内被测试并守住
|
||||
short_base = short_base & dataframe["resistance_alive_4h"]
|
||||
|
||||
# v1.6: 冷却期 — 过去N根1H bar内没有过满足条件的做空信号
|
||||
short_recent = short_base.rolling(cooldown, min_periods=1).max().shift(1) == 0
|
||||
short_conditions = short_base & short_recent
|
||||
|
||||
dataframe.loc[short_conditions, "enter_short"] = 1
|
||||
|
||||
return dataframe
|
||||
@ -344,8 +389,6 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
|
||||
support_4h / resistance_4h 随新Swing Point自动更新,
|
||||
天然形成追踪止损效果。
|
||||
|
||||
v1.5: 硬止损从-5%放宽到-15%,让结构止损真正生效。
|
||||
"""
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
if dataframe is None or len(dataframe) == 0:
|
||||
@ -356,20 +399,16 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
if not trade.is_short:
|
||||
support = last.get("support_4h", np.nan)
|
||||
if pd.isna(support) or support <= 0:
|
||||
return -0.02 # fallback
|
||||
# 止损 = support_4h 下方 0.1%
|
||||
return -0.02
|
||||
sl_price = support * 0.999
|
||||
sl_ratio = (sl_price / current_rate) - 1.0
|
||||
# v1.5: 硬止损从-5% → -15%
|
||||
return max(sl_ratio, -0.15)
|
||||
else:
|
||||
resistance = last.get("resistance_4h", np.nan)
|
||||
if pd.isna(resistance) or resistance <= 0:
|
||||
return 0.02 # fallback
|
||||
# 止损 = resistance_4h 上方 0.1%
|
||||
return 0.02
|
||||
sl_price = resistance * 1.001
|
||||
sl_ratio = 1.0 - (sl_price / current_rate)
|
||||
# v1.5: 硬止损从+5% → +15%
|
||||
return min(sl_ratio, 0.15)
|
||||
|
||||
# =====================
|
||||
@ -388,5 +427,9 @@ class StructureFlowStrategyV15(IStrategy):
|
||||
"bullish_pinbar": {"color": "green", "type": "scatter"},
|
||||
"bearish_pinbar": {"color": "red", "type": "scatter"},
|
||||
},
|
||||
"filters": {
|
||||
"support_alive_4h": {"color": "green", "type": "line"},
|
||||
"resistance_alive_4h": {"color": "red", "type": "line"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user