diff --git a/20260516-突破策略/20260516_Breakout.mq5 b/20260516-突破策略/20260516_Breakout.mq5 index ffbebaa..7d82780 100644 --- a/20260516-突破策略/20260516_Breakout.mq5 +++ b/20260516-突破策略/20260516_Breakout.mq5 @@ -14,12 +14,14 @@ input group "=== 波段识别参数 ===" input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M1; // K线周期 input int InpMAPeriod = 14; // MA周期 -input double InpWavePercent = 0.1; // 波段阈值百分比(%) +input double InpMinWavePercent = 0.1; // 最小波段阈值百分比(%) +input double InpMaxWavePercent = 1.0; // 最大波段阈值百分比(%) input double InpPullbackTolerance = 0.0; // 反向突破容忍度(%) 0=不容忍 input group "=== 风险管理参数 ===" input double InpStopLossPercent = 0.05; // 止损百分比(%) input double InpRiskRewardRatio = 1.5; // 盈亏比 +input bool InpUseTrailingStop = true; // 使用移动止损 input int InpMaxHoldingMinutes = 5; // 最大持仓时间(分钟) input group "=== 仓位管理参数 ===" @@ -102,12 +104,13 @@ int OnInit() Print("品种:", _Symbol); Print("K线周期:", EnumToString(InpTimeframe)); Print("MA周期:", InpMAPeriod); - Print("波段阈值: ", InpWavePercent, "%"); + Print("波段阈值范围: ", InpMinWavePercent, "% - ", InpMaxWavePercent, "%"); if(InpPullbackTolerance > 0) Print("反向突破容忍度: ", DoubleToString(InpPullbackTolerance, 1), "% (启用)"); else Print("反向突破容忍度: 0% (禁用 - 保持原有逻辑)"); - Print("止损:", InpStopLossPercent, "% | 盈亏比:", InpRiskRewardRatio); + Print("止损:", InpStopLossPercent, "% (最小1美元) | 盈亏比:", InpRiskRewardRatio); + Print("移动止损:", (InpUseTrailingStop ? "启用" : "禁用")); Print("最大持仓时间:", InpMaxHoldingMinutes, "分钟"); Print("最大开仓手数:", InpMaxPositions); Print("手数模式:", (InpUseCompounding ? "复利" : "固定"), @@ -354,9 +357,11 @@ void UpdateLatestValidWave() // 计算阈值(百分比模式:以前一个极值点价格为基准计算百分比) double base_price = extremes[i-1].price; - double threshold = (base_price * InpWavePercent / 100.0) / _Point; + double min_threshold = (base_price * InpMinWavePercent / 100.0) / _Point; + double max_threshold = (base_price * InpMaxWavePercent / 100.0) / _Point; - if(price_diff_points >= threshold) { + // 波段必须在最小和最大阈值之间才是有效波段 + if(price_diff_points >= min_threshold && price_diff_points <= max_threshold) { extremes[i-1].is_valid = true; extremes[i].is_valid = true; } @@ -374,9 +379,11 @@ void UpdateLatestValidWave() // 计算阈值(百分比模式) double base_price = extremes[i-1].price; - double threshold = (base_price * InpWavePercent / 100.0) / _Point; + double min_threshold = (base_price * InpMinWavePercent / 100.0) / _Point; + double max_threshold = (base_price * InpMaxWavePercent / 100.0) / _Point; - if(price_diff_points >= threshold) { + // 波段必须在最小和最大阈值之间才是有效波段 + if(price_diff_points >= min_threshold && price_diff_points <= max_threshold) { // 找到最新的有效波段 double high = MathMax(extremes[i].price, extremes[i-1].price); double low = MathMin(extremes[i].price, extremes[i-1].price); @@ -405,7 +412,8 @@ void UpdateLatestValidWave() Print("更新最新有效波段 - 高:", DoubleToString(high, _Digits), " 低:", DoubleToString(low, _Digits), " 价差:", (int)price_diff_points, "点", - " 阈值:", StringFormat("%.2f%% (%.0f点)", InpWavePercent, threshold)); + " 阈值范围:", StringFormat("%.2f%%-%.2f%% (%.0f-%.0f点)", + InpMinWavePercent, InpMaxWavePercent, min_threshold, max_threshold)); } } break; @@ -559,7 +567,7 @@ void CheckOpenSignals() // 计算当前波段的实际阈值(百分比模式:取高低点的平均值作为基准) double base_price = (latest_wave.high_price + latest_wave.low_price) / 2.0; - double wave_threshold_points = (base_price * InpWavePercent / 100.0) / _Point; + double wave_threshold_points = (base_price * InpMinWavePercent / 100.0) / _Point; // 检查多单信号:突破高点(且该高点未使用过) if(!latest_wave.high_used && current_price > latest_wave.high_price) { @@ -715,6 +723,10 @@ void ManagePositions() //+------------------------------------------------------------------+ void CheckTrailingStop(ulong ticket) { + // 如果未开启移动止损,直接返回 + if(!InpUseTrailingStop) + return; + if(!PositionSelectByTicket(ticket)) return; diff --git a/20260516-突破策略/README.md b/20260516-突破策略/README.md index 9b69330..ba60f95 100644 --- a/20260516-突破策略/README.md +++ b/20260516-突破策略/README.md @@ -27,12 +27,15 @@ ### 波段识别参数 - K线周期:支持参数设置,不跟随图表,默认 **1 Minute** - MA周期:默认 **14** -- 波段阈值百分比:默认 **0.1%** +- **最小波段阈值百分比:默认 0.1%**(波段必须 >= 此值才可能是有效波段) +- **最大波段阈值百分比:默认 1.0%**(波段必须 <= 此值才可能是有效波段) +- **有效波段范围:0.1% - 1.0%**(只交易此范围内的波段) - **反向突破容忍度:默认0.0%(新功能 - 详见下方说明)** ### 风险管理参数 - 止损百分比:默认 **0.05%**(基于开仓价计算,最小1美元/100点) - 盈亏比:默认 **1.5**(止盈 = 止损金额 × 盈亏比) +- 使用移动止损:默认 **true**(启用移动止损功能) - 最大持仓时间:默认 **5分钟** ### 仓位管理参数 @@ -89,12 +92,41 @@ 3. 建议先回测不同容忍度,找到最适合的数值 4. 容忍度只影响波段识别,不影响止损止盈等其他逻辑 -### 波段阈值说明 -本策略使用**百分比模式**计算波段阈值: -- 以前一个极值点价格为基准,按百分比计算阈值 +### 波段阈值范围说明 +本策略使用**波段范围筛选**机制,只交易特定大小的波段: + +#### 为什么需要波段范围? +- **单一阈值的问题**:传统策略只设置最小阈值(如0.1%),导致0.1%的小波段和5%的大波段都交易,风险收益特征差异巨大 +- **范围筛选的优势**:通过设置最小和最大阈值,只交易特定大小的波段,风险更可控 + +#### 计算方式 +- 以前一个极值点价格为基准,按百分比计算阈值范围 - 动态适应不同价格水平 -- 例如:设置0.1%,价格2600时阈值为2.6美元(260点),价格4700时阈值为4.7美元(470点) -- 百分比模式能够根据价格水平自动调整,更好地适应市场变化 + +#### 示例说明 +假设设置: +- 最小阈值:0.1% +- 最大阈值:1.0% +- 当前价格:2600 + +**价格2600时的阈值范围:** +- 最小阈值 = 2600 × 0.1% = 2.6美元(260点) +- 最大阈值 = 2600 × 1.0% = 26美元(2600点) + +**波段筛选结果:** +- 波段 2.0美元(200点):< 最小阈值 → ❌ 不交易(波段太小) +- 波段 5.2美元(520点):在范围内 → ✅ 有效波段,可交易 +- 波段 15美元(1500点):在范围内 → ✅ 有效波段,可交易 +- 波段 30美元(3000点):> 最大阈值 → ❌ 不交易(波段太大) + +**价格4700时的阈值范围:** +- 最小阈值 = 4700 × 0.1% = 4.7美元(470点) +- 最大阈值 = 4700 × 1.0% = 47美元(4700点) + +#### 参数调整建议 +- **保守型**:0.15% - 0.5%(只交易中小波段) +- **标准型**:0.1% - 1.0%(默认,覆盖大多数波段) +- **激进型**:0.08% - 2.0%(交易范围更广) ### 止损止盈说明 本策略使用**百分比模式**计算止损和止盈: @@ -115,6 +147,18 @@ - 多单止盈价 = 1500 + 1.5 = 1501.5 - 空单止盈价 = 1500 - 1.5 = 1498.5 -- **移动止损**:当浮盈达到止损金额时,自动将止损移至成本价(开仓价) +- **移动止损**(可选功能,默认启用): + - **触发条件**:当浮盈 >= 止损金额时触发 + - **移动目标**:将止损移至成本价(开仓价) + - **移动次数**:仅移动一次(保本策略) + - **示例**:开仓价2603.24,止损金额1.30美元 + - 当价格涨至2604.54(浮盈1.30)时,止损从2601.94移至2603.24 + - 之后价格无论涨到多高,止损都保持在2603.24 + - 即使回调至成本价,也能保本离场,不会亏损 + - **开关控制**:可通过参数"使用移动止损"关闭此功能 - **最小止损保护**:无论百分比设置多小,止损金额始终不低于1美元(100点),避免止损过小导致频繁触发 + +- **移动止损的作用**: + - ✅ 启用时:浮盈达标后锁定盈亏平衡,避免盈利单变亏损 + - ❌ 禁用时:止损始终保持在初始位置,追求更高止盈,但风险更大