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"); }
问题根源
- 对象名称重复:每次创建垂直线都使用固定名称
"Long",MQL5中同名对象会被直接覆盖,导致旧线条被新线条替换。 - 数组存储逻辑错误:
Sig_L_Pos设置为倒序存储(ArraySetAsSeries(true)),但添加新信号时却往数组末尾写入,导致索引混乱,部分信号时间无法被正确读取绘制。 - 信号时间不准确:用
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
相关产品推荐
相关产品推荐

