Is there any workaround for drawing lines on multiple charts in the strategy tester? (Multisymbol EA related)

 
From my understanding ObjectCreate() can only draw lines on the chart_id which is always the current chart inside the strategy tester
bool CChartObjectVLine::Create(long chart_id,const string name,const int window,const datetime time)
  {
   if(!ObjectCreate(chart_id,name,OBJ_VLINE,window,time,0.0))
      return(false);
   if(!Attach(chart_id,name,window,1))
      return(false);
//--- successful
   return(true);
  }
However in my multisymbol EA since I want to be able to visually draw lines at news events on different charts so the beginnings of my OnTick() function look like this: 
void OnTick(){
   for(int SymbolLoop = 0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++){       // Loop Through all Symbols
      string CurrentSymbol = SymbolArray[SymbolLoop];
      
     // All trading logic under here
    }
}

So I identify the current symbol the trading logic should apply to here but doing thing like line.Create or even directly using ObjectCreate simply wont work because it doesn't take the chart symbol as a parameter from what I understand? 

Is there some work around for this that I am missing because I have searched the forum endlessly for this and can't find anything or I missed something obvious. 

Am I really going to have to code an indicator if I really want to be able to visually confirm news events across multiple charts? If so what is the best way to do that? Currently for news filters in the strategy tester I follow the traditional method of saving all the events once into a binary file and then reading it out with classes and stuff and drawling lines etc but I would like for it to be multisymbol capable. I have no experience coding indicators so any advice would be appreciated

The Fundamentals of Testing in MetaTrader 5
The Fundamentals of Testing in MetaTrader 5
  • www.mql5.com
What are the differences between the three modes of testing in MetaTrader 5, and what should be particularly looked for? How does the testing of an EA, trading simultaneously on multiple instruments, take place? When and how are the indicator values calculated during testing, and how are the events handled? How to synchronize the bars from different instruments during testing in an "open prices only" mode? This article aims to provide answers to these and many other questions.
 
hmm... I haven't thought about it and unfortunately I don't know the solution.
Anyway, this is interesting topic to look into. Therefor I'll put a sign down here... 
 
Imre Sopp #:
... I haven't thought about it and unfortunately I don't know the solution.
Anyway, this is interesting topic to look into. Therefor I'll put a sign down here... 

First thought that comes to mind...Is there a way to capture the times of news events and put them in one container? Then use these times to create visual objects on the current active chart_id? this is not possible?

 
Imre Sopp #:

First thought that comes to mind...Is there a way to capture the times of news events and put them in one container? Then use these times to create visual objects on the current active chart_id? this is not possible?

Currently the way I do it is I read the binary file of news events inside an indicator and then that indicator draws as a histogram in a separate chart window. It works for live but not inside the strategy tester and it throws error code 4002 because it thinks it cannot find the binary file of news events. I'm not sure why I have literally copy and pasted the file into Common folder, the Files folder, the agent's Files folder and I cannot create it still for some reason in either multisymbol or single symbol scenarios. So Instead I have resorted to a check at the start of each day that displays all the news events per symbol using Comment, with the option to turn it on and off because from what I understand is that it eats memory in the strategy tester. 

You can do the visual objects thing very easily for a live account/chart because you can actually switch chartIDs and use ObjectCreate but these things seem to not be possible in the strategy tester from what I understand. 

 

aa that's the thing... Like i said, I haven't delved deeper into this topic, but I started the strategy tester to try it out. My objects aren't displayed either... It seems you're right and that means that default ObjectCreate objects aren't displayed during optimization?

I believe that's for a reason, because managing objects is expensive. Especially considering that many people don't know how to manage memory correctly and leave old objects lying around. Then the forum would probably soon be full of complaints that the strategy tester is slowing down. Besides, the goal of optimization is not visualization... but well, you know that yourself. Now arises the question, is there any way to get around this limitation?  I took a peek and found an article about visualizing results, but that's probably not what you want...

Can you tell more about why you want to visualize the strategy tester? If you want to use visualization to confirm the effectiveness of your algorithms and analyze parameters, then there is a problem here, of course...

Fortunately, I am used to optimizing without a strategy tester and therefore I can use visuals simply as confirmation when building algorithms. You can build your own dedicated small purpose-built optimizer into the MQL EA and then run it through history when starting the program. Or as scheduled tasks once a day, week or month. This is much more faster and convenient to use, because you do not have to run the strategy tester and everything happens at runtime... Now it depends on how serious your goal is, whether you take such a journey...

But it would be clever to visualize the strategy tester itself, of course, if that way you can get the desired result with less effort, if possible... please let me know what solution you found or didn't find, because I'm also probably a bit interested in this topic myself.

 
Imre Sopp #:

aa that's the thing... Like i said, I haven't delved deeper into this topic, but I started the strategy tester to try it out. My objects aren't displayed either... It seems you're right and that means that default ObjectCreate objects aren't displayed during optimization?

I believe that's for a reason, because managing objects is expensive. Especially considering that many people don't know how to manage memory correctly and leave old objects lying around. Then the forum would probably soon be full of complaints that the strategy tester is slowing down. Besides, the goal of optimization is not visualization... but well, you know that yourself. Now arises the question, is there any way to get around this limitation?  I took a peek and found an article about visualizing results, but that's probably not what you want...

Can you tell more about why you want to visualize the strategy tester? If you want to use visualization to confirm the effectiveness of your algorithms and analyze parameters, then there is a problem here, of course...

Fortunately, I am used to optimizing without a strategy tester and therefore I can use visuals simply as confirmation when building algorithms. You can build your own dedicated small purpose-built optimizer into the MQL EA and then run it through history when starting the program. Or as scheduled tasks once a day, week or month. This is much more faster and convenient to use, because you do not have to run the strategy tester and everything happens at runtime... Now it depends on how serious your goal is, whether you take such a journey...

But it would be clever to visualize the strategy tester itself, of course, if that way you can get the desired result with less effort, if possible... please let me know what solution you found or didn't find, because I'm also probably a bit interested in this topic myseI just

I just wanted to visually confirm my news filter was working by drawing a line on the chart for multisymbol EAs and then seeing if it closed x min/hours before and after. I do it with the Comment function now so at the beginning of the day I put the news events inside a comment and it gets displayed until the next day. For a live account I won't need to do this since I can draw stuff on the chart. So in my EA I have functions like this: 

if(UseNewsFilter && NewsFilterType != NO_FILTER){               // This function inside the OnInit to load calendar entries from Rene Balke's CalendarHistory.mqh file
      CCalendarHistory cal;
      datetime backtestStart = D'2024.01.01'; // Hardcoded start
      datetime backtestEnd = D'2025.04.01';   // Hardcoded end
      for(int SymbolLoop = 0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++){
         string CurrentSymbol = SymbolArray[SymbolLoop];
         string currencies = GetSymbolCurrencies(CurrentSymbol);
         if(!cal.LoadCalendarEntriesFromFile("CalendarHistory2.bin", entries[SymbolLoop], backtestStart, backtestEnd, true)){
            Print("Error: Failed to load CalendarHistory2.bin for ", CurrentSymbol);
            return INIT_FAILED;
         }
         entries[SymbolLoop].Filter(currencies, CALENDAR_IMPORTANCE_HIGH, backtestStart, backtestEnd);
         Print("Loaded ", entries[SymbolLoop].Total(), " calendar events for ", currencies);
      }
      NewsLoaded = true;
   }
// Rest of code are custom functions 
void DisplayUpcomingNewsEvents(datetime timeFrom, datetime timeTo) {
   if(!NewsLoaded || !UseNewsFilter || NewsFilterType == NO_FILTER) {
      Print("News events not loaded or news filter disabled.");
      return;
   }

   string output = "Upcoming News Events (" + TimeToString(timeFrom) + " to " + TimeToString(timeTo) + "):\n\r";
   bool hasEvents = false;
   
   // Lopp through All Symbols
   for(int SymbolLoop = 0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++) {
      string CurrentSymbol = SymbolArray[SymbolLoop];
      string currencies = GetSymbolCurrencies(CurrentSymbol);
      string symbolEvents = CurrentSymbol + " (" + currencies + "):\n\r";

      // Debug: Check array size
      int totalEntries = entries[SymbolLoop].Total();
      Print("Symbol: ", CurrentSymbol, ", Total entries: ", totalEntries);

      int eventCount = 0;
      for(int i = 0; i < totalEntries; i++) {
         CCalendarEntry* entry = entries[SymbolLoop].At(i);
         if(entry == NULL) {
            Print("Null entry at index ", i, " for ", CurrentSymbol);
            continue;
         }
         // Debug: Log event details
         Print("Event ", i, ": Time=", TimeToString(entry.value_time), ", Importance=", EnumToString(entry.event_importance), 
               ", Currency=", entry.country_currency, ", Name=", entry.event_name);
         // Check if event is within time window and meets importance
         if(entry.value_time >= timeFrom && entry.value_time <= timeTo && 
            entry.event_importance >= CALENDAR_IMPORTANCE_MODERATE) {
            symbolEvents += "  " + entry.ToString() + "\n\r";
            eventCount++;
            hasEvents = true;
         } else {
            // Debug: Why is this event skipped?
            if(entry.value_time < timeFrom) {
               Print("Event skipped: Time ", TimeToString(entry.value_time), " is before ", TimeToString(timeFrom));
            } else if(entry.value_time > timeTo) {
               Print("Event skipped: Time ", TimeToString(entry.value_time), " is after ", TimeToString(timeTo));
            } else if(entry.event_importance < CALENDAR_IMPORTANCE_MODERATE) {
               Print("Event skipped: Importance ", EnumToString(entry.event_importance), " is below MODERATE");
            }
         }
      }

      if(eventCount > 0) {
         output += symbolEvents;
      } else {
         output += CurrentSymbol + " (" + currencies + "): No upcoming events.\n\r";
      }
   }

   if(!hasEvents) {
      output += "No events found in the specified time range.\n\r";
   }

   Print(output);
   Comment(output);
}

bool IsNewDay(const MqlDateTime &time) {
   static int Dateprev = 0;
   int Datenow = time.day;
   if(Dateprev != Datenow) {
      Dateprev = Datenow;
      Print("It is a new day");
      datetime currentTime = TimeCurrent();
      // Set time window to current day (midnight to 23:59:59)
      MqlDateTime currentStruct;
      TimeToStruct(currentTime, currentStruct);
      currentStruct.hour = 0;
      currentStruct.min = 0;
      currentStruct.sec = 0;
      datetime dayStart = StructToTime(currentStruct);
      datetime dayEnd = dayStart + 86399; // 23:59:59 (24 hours - 1 second)
      if(DisplayNewsComment) DisplayUpcomingNewsEvents(dayStart, dayEnd);
      
      return true;
   }
   return false;
}

Then I call IsNewDay before everything else in the OnTick and so far it works perfectly. Only thing I would add is that I had to hardcode a DST offset into the CalendarHistory.mqh file. Its not perfect yet and I plan on adding bank holidays to my news filter after today lol. Also this version is only for the strategy tester, in a live account you can just use the regular MqlCalendarValue stuff

 
Casey Courtney #:

I just wanted to visually confirm my news filter was working by drawing a line on the chart for multisymbol EAs and then seeing if it closed x min/hours before and after. I do it with the Comment function now so at the beginning of the day I put the news events inside a comment and it gets displayed until the next day. For a live account I won't need to do this since I can draw stuff on the chart. So in my EA I have functions like this: 

Then I call IsNewDay before everything else in the OnTick and so far it works perfectly. Only thing I would add is that I had to hardcode a DST offset into the CalendarHistory.mqh file. Its not perfect yet and I plan on adding bank holidays to my news filter after today lol. Also this version is only for the strategy tester, in a live account you can just use the regular MqlCalendarValue stuff

Yes, just to get confirmation, it is of course reasonable to simply print out the necessary data if the goal is just confirmation. It is a bit more cumbersome to track and read the print statements, but it probably can't be done better with a simple effort... i think, if it could, then the mql5 gurus would have already suggested something...