You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MQL5 EA绘制信号垂直线:旧线消失问题求助

MQL5 EA 信号垂直线绘制问题
  • 需求:每当收盘价上穿EMA出现新信号时,在图表上绘制垂直线,保留所有历史信号线条,而非仅显示最新一条。
  • 当前问题:尝试用datetime数组存储信号时间并循环绘制,但新信号出现时旧线条全部消失;若每次新K线重绘所有线条,效率较低。

用户提供的简化代码

//General variables
bool IsNewbar; //Bollean to do calcualtion only on new bar.
MqlRates Price[]; // to staore price data used in EMA cross over

// Moving average variables
int              MovAve_Handle;
double           MovAve_Buffer[]; 

//for marking signals as vertical lines
datetime TimeLong;
int NSignalsLongs=0;
datetime Sig_L_Pos[]; //Array to store datetimes in which signals where reported


int OnInit()
{
   ArraySetAsSeries(Sig_L_Pos,true);
   ArraySetAsSeries(Price,true);

      
   MovAve_Handle= iMA(_Symbol,PERIOD_M1, 100,0, MODE_SMA,PRICE_CLOSE);
   ArraySetAsSeries(MovAve_Buffer,true);
          
   return(INIT_SUCCEEDED);
}



void OnTick()
{
///---check for new bar
      static datetime StartTime;
      datetime ThisBarTime = iTime(_Symbol,PERIOD_M1,0);
      if(StartTime != ThisBarTime) {IsNewbar=true; StartTime = ThisBarTime; } else {IsNewbar=false;}

 
      if(IsNewbar==true){
         //Collect data of signal on new candle
               string SignalEntryType= GetSignal_BBCont_MA();
            
          //Check for signal type 
               if (SignalEntryType=="Long") {
                        NSignalsLongs=ArraySize(Sig_L_Pos);
                        ArrayResize(Sig_L_Pos,NSignalsLongs+1); 
                        Print(NSignalsLongs);
                        Sig_L_Pos[NSignalsLongs]=TimeCurrent();  //store time of signal into array
                        

                        Print(SignalEntryType);
               }
           //Draw vLines for each of the times in which signals arrived.
           for(int i = 0; i<=NSignalsLongs-1; i++){
                   TimeLong=Sig_L_Pos[i];
                   ObjectCreate(0,"Long", OBJ_VLINE,0, TimeLong ,0);
               }
      }   
}


///GETSIGNAL fucntion
string GetSignal_BBCont_MA(){
      
      // close price
            CopyRates(_Symbol,PERIOD_M1,1,2,Price);
            
      //Data from Moving Average
            CopyBuffer(MovAve_Handle,0,1,2,MovAve_Buffer);
               
      //GetSignal  Close Crossover EMA
         if (Price[0].close > MovAve_Buffer[0] && Price[1].close<=MovAve_Buffer[1]) {return("Long");} 
         
      return("None");
}

问题根源

  1. 对象名称重复:每次创建垂直线都使用固定名称"Long",MQL5中同名对象会被直接覆盖,导致旧线条被新线条替换。
  2. 数组存储逻辑错误:Sig_L_Pos设置为倒序存储(ArraySetAsSeries(true)),但添加新信号时却往数组末尾写入,导致索引混乱,部分信号时间无法被正确读取绘制。
  3. 信号时间不准确:用TimeCurrent()存储信号时间,该值是当前tick的实时时间,而非信号触发对应的K线开盘时间,会导致垂直线位置偏移。

修复方案

1. 生成唯一对象名称

为每条垂直线添加唯一标识(如索引、时间戳),避免同名覆盖,例如使用"Long_Signal_" + (string)i作为对象名。

2. 修正数组存储逻辑

取消Sig_L_Pos的倒序设置,按时间正序存储信号,确保新信号添加到数组末尾后能被正确遍历。

3. 存储正确的信号时间

使用新K线的开盘时间ThisBarTime作为信号时间,保证垂直线精准对应信号触发的K线。

修复后的完整代码

//General variables
bool IsNewbar; //Boolean to do calculation only on new bar.
MqlRates Price[]; // to store price data used in EMA cross over

// Moving average variables
int              MovAve_Handle;
double           MovAve_Buffer[]; 

//for marking signals as vertical lines
datetime TimeLong;
datetime Sig_L_Pos[]; //Array to store datetimes in which signals were reported


int OnInit()
{
    // 取消倒序,按时间正序存储信号
    ArraySetAsSeries(Price,true);

    MovAve_Handle= iMA(_Symbol,PERIOD_M1, 100,0, MODE_SMA,PRICE_CLOSE);
    ArraySetAsSeries(MovAve_Buffer,true);
            
    return(INIT_SUCCEEDED);
}

void OnTick()
{
    ///---check for new bar
    static datetime StartTime;
    datetime ThisBarTime = iTime(_Symbol,PERIOD_M1,0);
    IsNewbar = (StartTime != ThisBarTime);
    if(IsNewbar) StartTime = ThisBarTime;

    if(IsNewbar){
        //Collect data of signal on new candle
        string SignalEntryType= GetSignal_BBCont_MA();
        
        //Check for signal type 
        if (SignalEntryType=="Long") {
            int currentSize = ArraySize(Sig_L_Pos);
            ArrayResize(Sig_L_Pos,currentSize+1); 
            // 存储K线开盘时间作为信号时间
            Sig_L_Pos[currentSize] = ThisBarTime;  
            Print("New Long Signal at: ", TimeToString(ThisBarTime));
        }
        
        //Draw vLines for each of the times in which signals arrived.
        for(int i = 0; i < ArraySize(Sig_L_Pos); i++){
            TimeLong = Sig_L_Pos[i];
            // 生成唯一对象名称
            string objName = "Long_Signal_" + (string)i;
            // 检查对象是否已存在,避免重复创建
            if(!ObjectFind(0, objName)){
                ObjectCreate(0, objName, OBJ_VLINE, 0, TimeLong, 0);
                // 可选:设置线条样式
                ObjectSetInteger(0, objName, OBJPROP_COLOR, clrGreen);
                ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
            }
        }
    }   
}

///GETSIGNAL function
string GetSignal_BBCont_MA(){
    // close price
    CopyRates(_Symbol,PERIOD_M1,1,2,Price);
    
    //Data from Moving Average
    CopyBuffer(MovAve_Handle,0,1,2,MovAve_Buffer);
    
    //GetSignal  Close Crossover EMA
    if (Price[0].close > MovAve_Buffer[0] && Price[1].close <= MovAve_Buffer[1]) {
        return("Long");
    } 
    return("None");
}

额外优化建议

  • 加载历史信号:在OnInit()中遍历历史K线,提前检测并存储历史信号,避免仅显示EA启动后的新信号。
  • 减少重复操作:绘制前用ObjectFind()检查对象是否存在,已存在则跳过创建,提升运行效率。

内容的提问来源于stack exchange,提问作者Camilo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:00:42