🧩
MQL5 新柱检测:从静态函数到 CisNewBar 类
新柱检测事件处理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));
}
相比静态函数的优势
- 多周期/多品种:SetSymbol/SetPeriod 或传任意 datetime,可同时监控 EURUSD M1、GBPUSD M1 等。
- 无调用次数限制:实例变量替代静态变量,多处调用各自维护状态。
- 错误捕获与同步检测:m_retcode/m_comment 暴露运行错误,时间倒退能被捕获。
- 返回新柱数量:断网后也能知道漏了几根,便于指标重算。
- 支持非标准图(Renko/Kagi):传入自定义开盘时间即可。
使用注意事项
⚠ 易错点
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() 算出新柱数,指标可据此补算遗漏的柱,保证历史数据完整。