创建一个基于日波动区间突破策略的 MQL5 EA·进阶篇
📈

创建一个基于日波动区间突破策略的 MQL5 EA·进阶篇

(2/3)· 接上篇策略原型,本篇把突破判定、止损布防与回测优化逐行落进 MQL5 代码

含代码示例实战向 第 2/3 篇
不少交易者把前一日高低点直接当硬突破线,却忽略了亚洲时段噪声与假突破的过滤。本篇从 EA 设计层面补上这道防线,让你在 MT5 里跑的不再是裸策略。

◍ 日内区间突破 EA 的变量与时段骨架

做日线区间突破,第一步不是画突破线,而是把当天的基准区间和允许突破的窗口先钉死。下面这段初始化代码把最高/最低价存成极端初值,并定义了矩形与上下边界的命名前缀,方便后续在图表上自动标识。 关键时间点用静态变量算清楚:以当日 0 点(D1 第 0 根)为基准,加 6 小时得到早上 6 点,再顺延一根当前周期 bar 作为扫描起点;有效突破窗口被锁在 6 点后那根 bar 到 11 点(即 0 点 + 11 小时)之间,共 5 小时。 isNewDay() 靠 MqlDateTime 的 day 字段比对前后日,静态 prevDay 初值为 0,跨日才翻 newDay。外汇和贵金属波动受时段流动性影响大,这种 6–11 点窗口在伦敦盘前概率上更可能出现假突破,实盘前务必在 MT5 策略测试器用真实点差回测。

MQL5 / C++
class="macro">#class="kw">property description "Daily Range Breakout Expert Advisor"
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#include <Trade/Trade.mqh>
CTrade obj_Trade;
class="type">class="kw">double maximum_price = -DBL_MAX;    class=class="str">"cmt">//--- Initialize the maximum price with the smallest possible value
class="type">class="kw">double minimum_price = DBL_MAX;     class=class="str">"cmt">//--- Initialize the minimum price with the largest possible value
class="type">class="kw">datetime maximum_time, minimum_time;  class=class="str">"cmt">//--- Declare variables to store the time of the highest and lowest prices
class="type">bool isHaveDailyRange_Prices = false; class=class="str">"cmt">//--- Boolean flag to check if daily range prices are extracted
class="type">bool isHaveRangeBreak = false;        class=class="str">"cmt">//--- Boolean flag to check if a range breakout has occurred

class="macro">#define RECTANGLE_PREFIX "RANGE RECTANGLE " class=class="str">"cmt">//--- Prefix for naming range rectangles
class="macro">#define UPPER_LINE_PREFIX "UPPER LINE "     class=class="str">"cmt">//--- Prefix for naming upper range line
class="macro">#define LOWER_LINE_PREFIX "LOWER LINE "     class=class="str">"cmt">//--- Prefix for naming lower range line

class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick(){
class=class="str">"cmt">//---
}
  class="kw">static class="type">class="kw">datetime midnight = iTime(_Symbol,PERIOD_D1,class="num">0);  class=class="str">"cmt">//--- Get the time of midnight(start of the day) for daily chart
  class="kw">static class="type">class="kw">datetime sixAM = midnight + class="num">6 * class="num">3600;            class=class="str">"cmt">//--- Calculate class="num">6 AM based on midnight time
  class="kw">static class="type">class="kw">datetime scanBarTime = sixAM + class="num">1 * PeriodSeconds(_Period); class=class="str">"cmt">//--- Set scan time for the next bar after class="num">6 AM

  class="kw">static class="type">class="kw">datetime validBreakTime_start = scanBarTime;     class=class="str">"cmt">//--- Set the start of valid breakout time
  class="kw">static class="type">class="kw">datetime validBreakTime_end = midnight + (class="num">6+class="num">5) * class="num">3600; class=class="str">"cmt">//--- Set the end of valid breakout time to class="num">11 AM

  if (isNewDay()){
    class=class="str">"cmt">//---
  }
class="type">bool isNewDay() {
  class=class="str">"cmt">//--- Flag to indicate if a new day has started
  class="type">bool newDay = false;

  class=class="str">"cmt">//--- Structure to hold the current date and time
  class="type">MqlDateTime Str_DateTime;

  class=class="str">"cmt">//--- Convert the current time to a structured format
  TimeToStruct(TimeCurrent(), Str_DateTime);

  class=class="str">"cmt">//--- Static variable to store the previous day
  class="kw">static class="type">int prevDay = class="num">0;

  class=class="str">"cmt">//--- Get the current day from the structured time
  class="type">int currDay = Str_DateTime.day;

  class=class="str">"cmt">//--- If the previous day is the same as the current day, we&class="macro">#x27;re still on the same day
  if (prevDay == currDay) {
    newDay = false;
  }
  class=class="str">"cmt">//--- If the current day differs from the previous one, we have a new day
  else if (prevDay != currDay) {
    class=class="str">"cmt">//--- Print a message indicating the new day
    Print("WE HAVE A NEW DAY WITH DATE ", currDay);

「日内分界与新K线的状态重置逻辑」

日内策略最怕把昨天的极值带到今天。这段逻辑在识别到新一天开始时,先把 prevDay 指向 currDay,再把 newDay 置真,相当于给扫描模块发一个「换日信号」,后续才允许重新抓取当日的波动边界。 换日瞬间要重算几个关键时间戳:midnight 取 D1 周期 0 号 K 线开盘时间;sixAM 是 midnight 加 6×3600 秒;scanBarTime 再往后推一个当前周期秒数。validBreakTime_end 被钉在 midnight 加 11 小时,也就是上午 11 点前都算有效突破窗口。 极值与标志位必须清零:maximum_price 设 -DBL_MAX、minimum_price 设 DBL_MAX,isHaveDailyRange_Prices 与 isHaveRangeBreak 都归 false。不这么做,上一日的突破状态会污染新一天的判断。 新 K 线检测靠 isNewBar():用静态变量 prevBars 存上次 K 线数,iBars 返回的 currBars 与之不等才返回 true。实测在 M1 图表上,若行情清淡导致某分钟无 tick,可能延迟一两根才触发,属正常。 到了 scanBarTime 且尚未提取当日区间时,代码会 Print 提示并开始计算 midnight 到 sixAM 的总 bar 数:total_bars = (sixAM-midnight)/PeriodSeconds(_Period)+1。比如 M5 下这段是 72 根(360 分钟 ÷ 5 + 1),开 MT5 用「查看→EA 交易测试器」跑一遍就能核对这个数。

MQL5 / C++
class=class="str">"cmt">//--- Update the previous day to the current day
prevDay = currDay;

class=class="str">"cmt">//--- Set the flag to true, indicating a new day has started
newDay = true;
 }

 class=class="str">"cmt">//--- Return whether a new day has started
 class="kw">return (newDay);
}

class=class="str">"cmt">//--- Reset values for the new day
midnight = iTime(_Symbol,PERIOD_D1,class="num">0); class=class="str">"cmt">//--- Get the new midnight time
sixAM = midnight + class="num">6 * class="num">3600; class=class="str">"cmt">//--- Recalculate class="num">6 AM
scanBarTime = sixAM + class="num">1 * PeriodSeconds(_Period); class=class="str">"cmt">//--- Recalculate the scan bar time
validBreakTime_start = scanBarTime; class=class="str">"cmt">//--- Update valid breakout start time
validBreakTime_end = midnight + (class="num">6+class="num">5) * class="num">3600; class=class="str">"cmt">//--- Update valid breakout end time to class="num">11 AM
maximum_price = -DBL_MAX; class=class="str">"cmt">//--- Reset the maximum price for the new day
minimum_price = DBL_MAX; class=class="str">"cmt">//--- Reset the minimum price for the new day

isHaveDailyRange_Prices = false; class=class="str">"cmt">//--- Reset the daily range flag for the new day
isHaveRangeBreak = false; class=class="str">"cmt">//--- Reset the breakout flag for the new day

 if (isNewBar()){
 class=class="str">"cmt">//---
 }
class="type">bool isNewBar() {
 class=class="str">"cmt">//--- Static variable to hold the previous number of bars
 class="kw">static class="type">int prevBars = class="num">0;

 class=class="str">"cmt">//--- Get the current number of bars on the chart
 class="type">int currBars = iBars(_Symbol, _Period);

 class=class="str">"cmt">//--- If the number of bars hasn&class="macro">#x27;t changed, class="kw">return false
 if (prevBars == currBars) class="kw">return (false);

 class=class="str">"cmt">//--- Update the previous bar count with the current one
 prevBars = currBars;

 class=class="str">"cmt">//--- Return true if a new bar has been formed
 class="kw">return (true);
}

class=class="str">"cmt">//--- If a new bar has been formed, process the data
 class="type">class="kw">datetime currentBarTime = iTime(_Symbol,_Period,class="num">0); class=class="str">"cmt">//--- Get the time of the current bar

 if (currentBarTime == scanBarTime && !isHaveDailyRange_Prices){
 class=class="str">"cmt">//--- If it&class="macro">#x27;s time to scan and the daily range is not yet extracted
 Print("WE HAVE ENOUGH BARS DATA FOR DOCUMENTATION. MAKE THE EXTRACTION"); class=class="str">"cmt">//--- Log the extraction process
 class="type">int total_bars = class="type">int((sixAM - midnight)/PeriodSeconds(_Period)) + class="num">1; class=class="str">"cmt">//--- Calculate total bars between midnight and class="num">6 AM
 Print("Total Bars for scan = ",total_bars); class=class="str">"cmt">//--- Log the total number of bars for scanning

用开收盘极值圈定区间高低点

这段逻辑不碰上下影线,只拿每根 K 线的开盘价与收盘价的较大者去比最高、较小者去比最低,等于把区间高低点的判定收窄到实体博弈范围。外汇与贵金属的影线常由流动性扫单造成,实体极值更能反映该周期多空真实交战价位,但这类过滤在窄幅震荡里可能漏掉关键刺透。 循环从 i=1 跑满 total_bars,每根都重算 open_i、close_i,再借三元表达式落定 highest_price_i 与 lowest_price_i。一旦刷新纪录就同步写回 maximum_price、highest_price_bar_index、maximum_time,最低点同理。 下面五个小函数是直接包了 iOpen/iHigh/iLow/iClose/iTime 的薄封装,调用时传 _Symbol 与 _Period,省得在主循环里反复写长参数。你可以把这段原样贴进 MT5 的 EA 或脚本,把 total_bars 设成 500,跑一遍 EURUSD 的 H1,肉眼核对 highest_price_bar_index 落点是不是实体顶。

MQL5 / C++
class="type">int highest_price_bar_index = -class="num">1;   class=class="str">"cmt">//--- Variable to store the bar index of the highest price
class="type">int lowest_price_bar_index = -class="num">1;     class=class="str">"cmt">//--- Variable to store the bar index of the lowest price
class=class="str">"cmt">//--- 
}
   for (class="type">int i=class="num">1; i<=total_bars ; i++){ class=class="str">"cmt">//--- Loop through all bars within the defined time range
         class="type">class="kw">double open_i = open(i);          class=class="str">"cmt">//--- Get the opening price of the i-th bar
         class="type">class="kw">double close_i = close(i);        class=class="str">"cmt">//--- Get the closing price of the i-th bar
         
         class="type">class="kw">double highest_price_i = (open_i > close_i) ? open_i : close_i; class=class="str">"cmt">//--- Determine the highest price between open and close
         class="type">class="kw">double lowest_price_i = (open_i < close_i) ? open_i : close_i;  class=class="str">"cmt">//--- Determine the lowest price between open and close
         
         if (highest_price_i > maximum_price){
            class=class="str">"cmt">//--- If the current highest price is greater than the recorded maximum price
            maximum_price = highest_price_i; class=class="str">"cmt">//--- Update the maximum price
            highest_price_bar_index = i;      class=class="str">"cmt">//--- Update the index of the highest price bar
            maximum_time = time(i);           class=class="str">"cmt">//--- Update the time of the highest price
         }
         if (lowest_price_i < minimum_price){
            class=class="str">"cmt">//--- If the current lowest price is lower than the recorded minimum price
            minimum_price = lowest_price_i;   class=class="str">"cmt">//--- Update the minimum price
            lowest_price_bar_index = i;       class=class="str">"cmt">//--- Update the index of the lowest price bar
            minimum_time = time(i);           class=class="str">"cmt">//--- Update the time of the lowest price
         }
   }
class=class="str">"cmt">//--- Utility functions to retrieve price and time data for a given bar index
class="type">class="kw">double open(class="type">int index){class="kw">return (iOpen(_Symbol,_Period,index));}   class=class="str">"cmt">//--- Get the opening price
class="type">class="kw">double high(class="type">int index){class="kw">return (iHigh(_Symbol,_Period,index));}   class=class="str">"cmt">//--- Get the highest price
class="type">class="kw">double low(class="type">int index){class="kw">return (iLow(_Symbol,_Period,index));}     class=class="str">"cmt">//--- Get the lowest price
class="type">class="kw">double close(class="type">int index){class="kw">return (iClose(_Symbol,_Period,index));} class=class="str">"cmt">//--- Get the closing price
class="type">class="kw">datetime time(class="type">int index){class="kw">return (iTime(_Symbol,_Period,index));} class=class="str">"cmt">//--- Get the time of the bar
         class=class="str">"cmt">//--- Log the maximum and minimum prices, along with their respective bar indices and times

◍ 把高低点区间画成可视矩形

提取完当日极值后,先把结果打到日志里备查:最高价、对应 K 线序号、时间,以及最低价、最低点序号、时间,随后把 isHaveDailyRange_Prices 置真,告诉后续逻辑「今天的高低范围已经算好了」。 真正把数据落到图表上,靠的是 create_Rectangle 这个函数。它先 ObjectFind 查重名对象,不存在才建;用 OBJ_RECTANGLE 在 0 号子窗口按 time1/price1 到 time2/price2 拉出矩形,再逐点设 OBJPROP_TIME、OBJPROP_PRICE,开 OBJPROP_FILL 填色、关 OBJPROP_BACK 保证不沉底,最后 ChartRedraw 刷新。 矩形坐标来自前一步算出的 maximum_time / minimum_time 与对应价格,颜色由调用方传 clr 决定。你在 MT5 里跑这段,若没看到色块,八成是 time1/time2 传反了或价格超出可见范围——外汇与贵金属波动剧烈,这类对象容易被快速影线扫掉,属高风险品种下的常见现象。 create_Line 的声明紧接着出现,接收宽度、颜色与文字标签,用于画趋势线标注极值连线;本节原文在参数注释处截断,下一段会接着写查重与创建逻辑。

MQL5 / C++
Print("Maximum Price = ",maximum_price,", Bar index = ",highest_price_bar_index,", Time = ",maximum_time);
Print("Minimum Price = ",minimum_price,", Bar index = ",lowest_price_bar_index,", Time = ",minimum_time);
isHaveDailyRange_Prices = true; class=class="str">"cmt">//--- Set the flag indicating daily range prices have been extracted

class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|      FUNCTION TO CREATE A RECTANGLE                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void create_Rectangle(class="type">class="kw">string objName, class="type">class="kw">datetime time1, class="type">class="kw">double price1, class="type">class="kw">datetime time2, class="type">class="kw">double price2, class="type">class="kw">color clr) {
  class=class="str">"cmt">//--- Check if the object already exists by finding it on the chart
  if (ObjectFind(class="num">0, objName) < class="num">0) {
    class=class="str">"cmt">//--- Create a rectangle object using the defined parameters: name, type, and coordinates
    ObjectCreate(class="num">0, objName, OBJ_RECTANGLE, class="num">0, time1, price1, time2, price2);
    class=class="str">"cmt">//--- Set the time for the first point of the rectangle(start point)
    ObjectSetInteger(class="num">0, objName, OBJPROP_TIME, class="num">0, time1);
    class=class="str">"cmt">//--- Set the price for the first point of the rectangle(start point)
    ObjectSetDouble(class="num">0, objName, OBJPROP_PRICE, class="num">0, price1);
    class=class="str">"cmt">//--- Set the time for the second point of the rectangle(end point)
    ObjectSetInteger(class="num">0, objName, OBJPROP_TIME, class="num">1, time2);
    class=class="str">"cmt">//--- Set the price for the second point of the rectangle(end point)
    ObjectSetDouble(class="num">0, objName, OBJPROP_PRICE, class="num">1, price2);
    class=class="str">"cmt">//--- Enable the fill class="kw">property for the rectangle, making it filled
    ObjectSetInteger(class="num">0, objName, OBJPROP_FILL, true);
    class=class="str">"cmt">//--- Set the class="type">class="kw">color for the rectangle
    ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clr);
    class=class="str">"cmt">//--- Set the rectangle to not appear behind other objects
    ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false);
    class=class="str">"cmt">//--- Redraw the chart to reflect the new changes
    ChartRedraw(class="num">0);
  }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|      FUNCTION TO CREATE A TREND LINE                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void create_Line(class="type">class="kw">string objName, class="type">class="kw">datetime time1, class="type">class="kw">double price1, class="type">class="kw">datetime time2, class="type">class="kw">double price2, class="type">int width, class="type">class="kw">color clr, class="type">class="kw">string text) {
  class=class="str">"cmt">//--- Check if the line object already exists by its name

「用代码把趋势线和标注钉在图上」

在 MT5 脚本里画趋势线,第一步永远是先用 ObjectFind 判断同名对象是否已存在;返回 -1 才进入创建分支,避免重复执行时堆叠一堆重叠线。 下面这段代码演示了从创建 OBJ_TREND 到逐项写入两端坐标、线宽、颜色以及前置显示属性的完整过程。注意 OBJPROP_BACK 设为 false,线会压在 K 线上方而不是被吞进背景。 [CODE] if(ObjectFind(0, objName) < 0) { ObjectCreate(0, objName, OBJ_TREND, 0, time1, price1, time2, price2); ObjectSetInteger(0, objName, OBJPROP_TIME, 0, time1); ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, price1); ObjectSetInteger(0, objName, OBJPROP_TIME, 1, time2); ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, price2); ObjectSetInteger(0, objName, OBJPROP_WIDTH, width); ObjectSetInteger(0, objName, OBJPROP_COLOR, clr); ObjectSetInteger(0, objName, OBJPROP_BACK, false); long scale = 0; if(!ChartGetInteger(0, CHART_SCALE, 0, scale)) { Print("UNABLE TO GET THE CHART SCALE. DEFAULT OF ", scale, " IS CONSIDERED"); } int fontsize = 11; if (scale == 0) { fontsize = 5; } else if (scale == 1) { fontsize = 6; } else if (scale == 2) { fontsize = 7; } else if (scale == 3) { fontsize = 9; } else if (scale == 4) { fontsize = 11; } else if (scale == 5) { fontsize = 13; } string txt = " Right Price"; string objNameDescr = objName + txt; ObjectCreate(0, objNameDescr, OBJ_TEXT, 0, time2, price2); [/CODE] 逐行拆解:ObjectCreate 的 OBJ_TREND 类型需要 4 个坐标参数(子窗口 0、起点时间/价格、终点时间/价格);随后 4 个 ObjectSet 调用把两端坐标再显式写一遍,属于 MT5 对象模型的冗余保险。 图表缩放级别通过 ChartGetInteger 取 CHART_SCALE,失败时在日志提示并沿用 scale=0。根据实测映射,scale 从 0 到 5 分别对应字号 5、6、7、9、11、13——缩放越小字号越小,避免在紧凑视图里把标注撑爆。 最后拼一个 " Right Price" 文本对象,锚在趋势线终点(time2, price2),用 OBJ_TEXT 把价格说明直接挂在线的右端。外汇和贵金属波动剧烈,这类手工线仅作辅助参考,实际进出场仍需结合实时结构,杠杆品种风险偏高。

MQL5 / C++
if(ObjectFind(class="num">0, objName) < class="num">0) {
  class=class="str">"cmt">//--- Create a trendline object with the specified parameters
  ObjectCreate(class="num">0, objName, OBJ_TREND, class="num">0, time1, price1, time2, price2);
  
  class=class="str">"cmt">//--- Set the time for the first point of the trendline
  ObjectSetInteger(class="num">0, objName, OBJPROP_TIME, class="num">0, time1);
  
  class=class="str">"cmt">//--- Set the price for the first point of the trendline
  ObjectSetDouble(class="num">0, objName, OBJPROP_PRICE, class="num">0, price1);
  
  class=class="str">"cmt">//--- Set the time for the second point of the trendline
  ObjectSetInteger(class="num">0, objName, OBJPROP_TIME, class="num">1, time2);
  
  class=class="str">"cmt">//--- Set the price for the second point of the trendline
  ObjectSetDouble(class="num">0, objName, OBJPROP_PRICE, class="num">1, price2);
  
  class=class="str">"cmt">//--- Set the width for the line
  ObjectSetInteger(class="num">0, objName, OBJPROP_WIDTH, width);
  
  class=class="str">"cmt">//--- Set the class="type">class="kw">color of the trendline
  ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, clr);
  
  class=class="str">"cmt">//--- Set the trendline to not be behind other objects
  ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, false);
  
  class=class="str">"cmt">//--- Retrieve the current chart scale
  class="type">long scale = class="num">0;
  if(!ChartGetInteger(class="num">0, CHART_SCALE, class="num">0, scale)) {
    class=class="str">"cmt">//--- Print an error message if unable to retrieve the chart scale
    Print("UNABLE TO GET THE CHART SCALE. DEFAULT OF ", scale, " IS CONSIDERED");
  }
  class=class="str">"cmt">//--- Set a class="kw">default font size based on the chart scale
  class="type">int fontsize = class="num">11;
  if (scale == class="num">0) { fontsize = class="num">5; }
  else if (scale == class="num">1) { fontsize = class="num">6; }
  else if (scale == class="num">2) { fontsize = class="num">7; }
  else if (scale == class="num">3) { fontsize = class="num">9; }
  else if (scale == class="num">4) { fontsize = class="num">11; }
  else if (scale == class="num">5) { fontsize = class="num">13; }
  
  class=class="str">"cmt">//--- Define the description text to appear near the right price
  class="type">class="kw">string txt = " Right Price";
  class="type">class="kw">string objNameDescr = objName + txt;
  
  class=class="str">"cmt">//--- Create a text object next to the line to display the description
  ObjectCreate(class="num">0, objNameDescr, OBJ_TEXT, class="num">0, time2, price2);

把区间突破画成可见的箭头

前面把日波幅矩形和上下边界线都画出来了,但真正触发交易者动作的是收盘价对上沿的穿透。下面这段用前一根 bar 的收盘时间和价格做判定,只在允许的时间窗内(validBreakTime_start 到 validBreakTime_end)且此前没破过时才算数。 判定写法是 barClose > maximum_price 且 isHaveDailyRange_Prices 为真、isHaveRangeBreak 为假。一旦成立,Print 打出「CLOSE Price broke the HIGH range.」并置 isHaveRangeBreak = true,避免同一日重复报警。 破位点用 drawBreakPoint 画箭头标记,传入箭头代码 234(即 Wingdings 里的向下钩)、颜色 clrBlack、direction -1。函数先 ObjectFind 看同名对象在不在,不在才 ObjectCreate 建 OBJ_ARROW,这样重复刷图表不会叠一堆箭头。 开 MT5 把 arrCode 从 234 改成 225 或 233,能直接换箭头样式;若把 direction 传 1,可预留给下沿破位用,只是当前调用里下破分支没接进来。外汇与贵金属杠杆高,这类区间破位信号只是概率倾向,实盘须自担回撤风险。

MQL5 / C++
  class=class="str">"cmt">//--- Check if the arrow object already exists on the chart
  if (ObjectFind(class="num">0, objName) < class="num">0) {
    class=class="str">"cmt">//--- Create an arrow object with the specified time, price, and arrow code
    ObjectCreate(class="num">0, objName, OBJ_ARROW, class="num">0, time, price);
把重复劳动交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到日波动区间与突破预警,你专注决定是否手动接管 EA 的信号。

常见问题

概率上 4 小时能过滤更多短噪,但信号更少;1 小时假突破倾向更高,需在代码里加收盘确认。
可以,小布已内置区间突破品种页,展示前日高低与实时突破状态,省去你手动画线。
用 iHigh/iLow 配合 PERIOD_D1 与 shift=1 读取,注意跨周末的柱体偏移处理。
贵金属与直盘波动结构不同,分段样本外测试能降低过拟合概率,别只看全部历史拟合度。