首页 / 交易学院 / MQL5 新柱检测:从静态函数到 CisNewBar 类
MQL5 新柱检测:从静态函数到 CisNewBar 类
🧩

MQL5 新柱检测:从静态函数到 CisNewBar 类

MQL5 编程 难度 · 进阶 2013 10 分钟阅读
新柱检测事件处理MQL5

为什么需要检测新柱

指标重算、信号触发、交易动作通常只在柱收盘/开盘时发生一次。如果每 tick 都跑完整计算,既浪费 CPU 又会让信号在柱内反复触发。检测“新柱出现”是限制计算循环、让逻辑只在新柱执行一次的标准手段。

早期静态函数的做法与缺陷

最常见的原型是用静态变量记住上一根柱的开盘时间,与当前 SERIES_LASTBAR_DATE 比较:

bool isNewBar()
  {
   static datetime last_time=0;
   datetime t=SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);
   if(last_time==0){ last_time=t; return(false); }
   if(last_time!=t){ last_time=t; return(true); }
   return(false);
  }

它的问题很多:静态变量在 OnInit 前只初始化一次,同一循环里多次调用除首次外都返回 false;硬编码 Symbol()/Period() 不能监控别的品种/周期;数据未就绪时 SeriesInfoInteger 可能返回 0 或拒绝;若两次调用间跨了多根柱只报 true 不知几根;时间倒退也无报错。

CisNewBar 类的完整设计

用面向对象去掉静态限制:每个实例用自己的 m_lastbar_time 跨调用保持状态,支持 SetSymbol/SetPeriod 监控任意品种周期,并通过 m_new_bars/m_retcode/m_comment 暴露更多信息。核心判断:

bool CisNewBar::isNewBar(datetime newbar_time)
  {
   m_new_bars=0; m_retcode=0;
   if(m_lastbar_time>newbar_time){ m_retcode=-1; return(false); } // 同步错误
   if(m_lastbar_time==0){ m_lastbar_time=newbar_time; return(false); }
   if(m_lastbar_time<newbar_time){ m_new_bars=1; m_lastbar_time=newbar_time; return(true); }
   return(false);
  }

int CisNewBar::isNewBar() // 无参重载,内部取 SERIES_LASTBAR_DATE
  {
   datetime nt; ResetLastError();
   if(!SeriesInfoInteger(m_symbol,m_period,SERIES_LASTBAR_DATE,nt))
     { m_retcode=GetLastError(); return(0); }
   if(!isNewBar(nt)) return(0);
   m_new_bars=Bars(m_symbol,m_period,m_lastbar_time,nt)-1;
   return(m_new_bars);
  }

在 EA / 指标里调用

全局声明实例 current_chart; 在 OnTick 里直接用无参重载即可。想要新柱事件化处理,可用 TimeCurrent() 算出当前柱开盘时间再调带参重载,封装成 OnNewBar():

#include <Lib CisNewBar.mqh>
CisNewBar current_chart;
void OnTick()
  {
   if(current_chart.isNewBar()>0)
      PrintFormat("新柱线: %s", TimeToString(TimeCurrent(),TIME_SECONDS));
  }

相比静态函数的优势

使用注意事项

⚠ 易错点
1) 实例在 OnInit 前构造,若用户改图表周期/品种,已附实例的 m_symbol/m_period 不变,需在 OnInit 用 SetSymbol/SetPeriod 重设。2) 小周期改大周期时 m_lastbar_time 可能晚于新周期柱时间,触发“同步错误”,应在 OnInit 用 SetLastBarTime 妥善初始化。3) 若 isNewBar() 返回 ≤0,应检查 GetRetCode() 与 GetComment() 排查数据未就绪。

常见问题

prev_calculated 只能反映当前图表指标自身的重算进度,且只在指标里可用、无法在 EA 的 OnTick 中用,也不能跨品种/周期。CisNewBar 用 SERIES_LASTBAR_DATE 对任意品种周期判断,EA 和指标都能用,还能返回遗漏柱数。
因为静态变量 last_time 在第一次调用时就被改写成当前柱时间,第二次调用看到 last_time==当前柱,自然返回 false。这在“想在同一根柱里多处判断是否新柱”时会误判。CisNewBar 用实例变量且只在真正新柱时更新,避免此问题。
断网或跨周期后可能一次漏掉多根柱。静态函数只返回 true 不告之几根,指标会漏算;CisNewBar 用 Bars() 算出新柱数,指标可据此补算遗漏的柱,保证历史数据完整。