Huge performance issues, context switching, how indicators are being dealt with internally

 

During coding and testing of my software I hit some issues with performance and wasn't able to find suitable answers here on the forum. Maybe the one or other could explain the behaviours that I run into:

  1. Say I have written an indicator that does XYZ. What happens usually is the well known experience:
    1. OnInit(); where you do all initialization stuff.
    2. OnCalculate(); basicly your main loop.
    3. OnDeinit(); your deinitialization stuff.
    4. OnTimer(); left out for the following explaination.
  2. You load your indicator into your base pair (say EURUSD) and it runs.
  3. Now when you switch the time frame from say H1 to H4, then - so from my own experiences - the indicator is being re-initialized once again. OnInit(); is being called. This leads to the assumption that all time frames will run a separate process of the indicator on it's own. If you cycle through M1 -> MN1 for example then everytime the OnInit(); is being called during the cycling process.
    1. The question here (which is no where written or being answered before):
      1. Is the indicator running 9 times per base pair (once I cycle through the context of time frame from M1 -> NM1) ?
      2. If this is the case, what happens with the frozen in (or hidden) indicator that ran e.g. in H1 (while we might have switched to H4) ?
  4. I am missing a huge chunk of "documentation" in how metatrader deals with the internal processes of indicators. Informations like:
    1. "context switching". What happens with the indicator once I switch the time frame. Will a separate indicator process being started ? If so, is the indicator in the now hidden time frame on "freeze" or does it continue running "hidden" in the background (I am not speaking about spearate chart windows here).
  5. I find it quite annoying that - by switching time frames - that the indicator re-run's the OnInit(); function once again. If you take into account that the indicator might do some "heavier" tasks during that initialization process that could cause the chart window to freeze for the time of it's re-initialization process.
Any answers or hints to already written documentation is well appreciated. Please no "reduce visible candles on chart" answers. I've been through that already.

 

Using a moving average indicator as an example

If it is on a H1 chart, it does its calculations using data from the H1 chart

If the chart is chaged to H4, it will do the same calculations but using the data from the H4 chart

The indicator is no longer doing anything with the H1 data. 

 

Thank you for your explaination. Though I wish this would have been officially written down somewhere. The performance bottlenecks could be avoided that way. Because of lack of information and documentation of this "situation" leads into misbehaviour of the indicator, missunderstanding of the initialization / deinitialization process etc. (Well I know what initialization and deinitialization is, but in the context to time frame switches and Metatrader this was unclear).

It was not known to me, that by switching the time frame, that a whole "new" initialization process is being started. I assumed that the indicator is valid "per chart". E.g. If I open EURUSD (as special example) that the indicator is valid for this chart over all time frames. I assumed that once the indicator is loaded that it get's initialized, loops through the main process and during removal being deinitialized. So from what I learn now ist this: EURUSD -> H1 -> OnInit(H1); -> OnCalculate(H1); -> (switching to H4) -> OnDeinit(H1); -> OnInit(H4); -> OnCalculate(H4); -> (switching to any other time frame) -> OnDeinit(H4); ... and so on ... This certainly is the MT4 programmed behaviour but not the - for me - expected behaviour.

Of course I understand that by using a different time frame that the "moving average indicator" will take e.g. H1 values for the H1 chart and H4 values for the H4 chart. But then this is why one uses 0 as 2nd parameter of the iMA function, so when the time frame is switched that it receives the correct values. 

I wonder what happens if you switch TABS (charts bar). Running the chart window in full screen and then switching from one currency pair to another one takes another huge amount of CPU load AND time for the switch itself. It's unknown what Metatrader does interally. Refresh ? Re-Inizialize ? etc.

For my "performance" issues I might think about an alternative approach to come over these bottlenecks. Solutions would be:

  1. Check whether the Objects for this chart has been created already. If this is the case skip OnInit(); also skip OnDeinit(); in case of time frame switching. E.g. some sort of "locking" mechanism. That prevents the indicator from causing heavy CPU usage.
  2. Using "if (isWindowVisible == 0) return 0;" or something to have the indicator only run on the "visible" chart window. This would save a lot of performance and CPU load in case of 10 and more currency pairs. Since my indicators have informal purposes rather than notifiying ones, this might make sense.
  3. Create some sort of interprocess communication (IPC) to have the indicators communicate to each other so data is being shared rather than re-calculated (specially for constant informative values like times, news etc).
  4. Write some RPC backend (the usual stuff everyone else does) and have the *.ex4 file communicate calculations to the outside. So an external application can be written that receives and visually prepare the data. That way even news, times and other constant stuff can be entirely removed from the indicators itself which makes the indicator become an RPC data provider only.

... hrmmm not my day today ...

 

Hello,

 1. Regarding  OnInit(), you can have a boolean flag so that initialization will not take place each time you change a timeframe or similar. For example, when you load your program, flag can start with 0 (zero) and after initialization finishes, you turn it to 1. At that point, each successive OnInit() call will be directed to another part of OnInit(), presumably simpler than the initial one.

 2. Regarding optimizations, OnCalculate() will normally run on every tick; my question is, do you really need to calculate in every single tick? I believe the answer is "usually I do not". So you can either use OnTimer() for your work, or put a Sleep() inside OnCalculate(). That way, your program can become orders of magnitude more efficient and without sacrificing a big part of your powers :) Normally, indicators would not need much time to calculate on today's computers, so even half a second should be much more than enough for most of them. In any case, you are possibly having the option to purchase a faster computer - unless of course you do have that one already :)

 

best regards 

 

Yes I am aware of the "locking" system (Singleton). This will work perfectly at 1st time initialization. But my use case is this:

OnInit(); -> Create 35 Labels in a for loop.

OnDeinit(); -> Delete 35 Labels in a for loop (Or deletall).

Right now in my mind is this. If I use the Singleton to prevent Objects from being re-created within the OnInit(); function when I switch time-frame. But switching the time-frame will call the OnDeinit(); function. What I can do is, check for the Singleton there as well and prevent the objects from being deleted (or have the entire deleting mechanism removed). But this leads that the objects are being stored in the *.chr files in the profiles directory once I exit metatrader. Storing the information there is what I don't want. I can use the Singleton, which clearly saves a shitload of time when switching time-frames (since it doesn't need to remove and recreate the objects over and over again). But I need to think of a way - I haven't looked at it right now - to receive a signal for metatrader termination, so OnDeinit(); receives the flag and deletes the objects. I am still making up my mind to seek a different approach.

Yes the data visualization doesn't need to happen within Ticks. Some stuff is being laid out into OnTimer(); (clock, news) some in OnCalculate(); (atr, ema calculations etc). This luckely isn't the problem. The problem was that I wasn't aware of the context switching (e.g. new Init and Deinit) once you switch time-frames. I thought that init/deinit happens only once for the entire chart.

I have written a small context tester that proves this (attachment). Nothing special but ok for the needs.

Coming back to the point of "do I need the information all the time (tick)". The question should be rephrased to "do I need that information on all charts (running in the background to some degree)". Therefore it might be an exercise to outsource the entire indicator into a separate application by creating an RPC including socket communication. So whenever I switch time-frame data only is being sent. No need to deal with objects and other stuff. No need to use windows api to load external resources etc. This will make "my special requirements" less dependant to metatrader at the end (in case the entire MT4 API is being trashed once again or in case I need to switch to another charting software). An external GUI application (which I can program native on Linux using GTK+ for example) that listens to a socket (which will be opened through the *.mq4 file) and then sents all data.

Files:
context.mq4  3 kb
 

Ok, you may want to look out for _StopFlag. I have not done it my self, but it seems it can be useful ; I suppose you can leave the OnDeinit() free of having to delete the labels and perform your own deinitialization logic inside  OnTimer(), OnCalculate() or wherever 

 

edit. I wish to correct my self. You can not propably check for _StopFlag inside OnTimer() or the others, but only inside OnDeinit(). It should be so because when you are closing the program, Metatrader calls OnDeinit; so, by checking for _StopFlag inside there you can understand if OnDeinit was called by a e.g. timeframe change or because of unloading or exiting

 
Tried _StopFlag already but it doesn't work. Testing with UnitializeReason == REASON_CLOSE now. I have some code in mind that I am testing right now. Will report back with a "hack" solution in a couple of moments. Yeah REASON_CLOSE did it. Hang on.
 

Yep, I tried UninitReason as well and it seems to do the trick , unlike StopFlag (which is strange , by the way - i mean , it should work), and in addition it gives some more options

 

best regards 

 

Please find attached a code fragment, that helps you to boost up your indicators. The code example is neither perfect nor do I claim it to be the "best" solution.

Use cases:

As explained above, the use case was as follows. Let's assume you have 10 currency pairs open in metatrader. Each chart window (where a currency pair will be made visible) is running one or more indicators. In my case it's an information provider. This information provider creates say 35 Labels and fills the values with information that I think I need. On exit (metatrader being closed) these 35 Labels should be removed once again because I dislike having them in the *.chr files.

The problem:

The indicator does various "time consuming" tasks and with 10 currency pairs open, all these tasks run simultaneously. No matter whether you pay attention to all chart windows at a time or not. In most cases you focus your attention to one or two chart windows at a time. Both chart windows might show similar information. But in the background all indicators are operating and updating their visible data. This of course drains CPU performance.

Another issue is, that while we all happily switching time frames from H1 to H4 to M1 to M5 to MN1 and so on, the internal mechanism of metatrader happily runs OnInit();, OnDeinit(); creating and trashing all objects that we previously build up. Now imagine that your OnInit(); might also initially load up files, pulls information from a webpage and so on. Now each time you switch the time frame all this stuff happens over and over again. This of course drains CPU performance once again.

Another issue is, in case you have your charts running in full screen is the question whether updating the other indicators (in the hidden window) is necessary ? Sure, if you have an indicator that needs to "alert" you a state, then this is of course a must. But if you have an indicator that shows you the time and some news, then this is not really necessary. Running tasks in hidden windows of course drains CPU performance. 

A possible solution would be to install a Singleton, that only creates the objects on program launch and removes the objects on program termination (but not during change of time frames). Another solution (basicly an add on) would be to offer the possibility to update the indicator contents - only - if the window has the focus.

The Boost.mq4 skeleton could come handy here. I hacked this together because I need to solve a quick scene, to get my things going on, until I figure out a different approach or way of handling all this. I will now adopt this to two of my own indicators and see how things progress.

Update 1: Code slightly modified.

Update 2: While the previous update required an explicit window focus to do some tasks, this version checks if the window is the top most window in the Z axis. So the top ancestor window will be updated all the time. This makes sense, in case you switch to another program (e.g. browser, mailer, editor etc.) while still being able to keep an eye on the charts and still have it updating.

Files:
boost_1.mq4  4 kb
boost_2.mq4  4 kb
 
Termeinal.exe from 80%-90% CPU down to 30%-50% (10 open currency pairs / chart windows). Quite an improvement. Still not optimal :)