Download MetaTrader 5

Zero Divide error on terminal start up if indicator is left running

To add comments, please log in or register
Alexander Martinez
162
Alexander Martinez  

Hi everyone,

‌I'm getting a zero divide error if I leave an indicator running, close the terminal, then start it back up. The end result is that the indicator doesn't load up properly when I open the terminal.‌

Upon checking the 'Experts' tab, it told me which line in the code is causing the problem.

‌Here's the‌ code in question. The variable that is getting a value of zero, according to the entry in the 'Experts' tab, is 'tickValue'.

double tickValue      = MarketInfo(Symbol(),MODE_TICKVALUE)*10; // Global Variable


double calcLots(double slPips, double riskPct, double accSize){
   double dollarRisk    = accSize*(riskPct*.01);
   double lots          = (dollarRisk/tickValue)/slPips;
  
   return (lots);
}

‌My guess is that the Terminal is trying to send a request to the server for MarketInfo(Symbol(),MODE_TICKVALUE), but since the connection hasn't been established, it returns a value of '0'. I'm not 100% sure, but it's the only thing that would make sense to me. Edit: I confirmed that this is the problem.  I closed the Terminal, set up a breakpoint to the next line of code after the tickValue variable initialization, set up a Watch for the tickValue variable, then started the terminal back up through debugger. It is getting a value of zero.

I've tried the following, but it doesn't work: if (!IsConnected()) Sleep (10000);

Other than on Terminal start up, the indicator works perfectly fine.

whroeder1
16574
whroeder1  
  1. double tickValue      = MarketInfo(Symbol(),MODE_TICKVALUE)*10; // Global Variable

    Initialize global variables with constants only.‌

    • Terminal starts
    • Empty charts are created.
    • EA is loaded, there may be no values for MarketInfo yet; you get zero.
    • OnInit is loaded, there may be no values for MarketInfo yet.
    • Terminal connects to broker, downloads market data.
    • OnTick is called. Now you can get tickValue.
    • You place the stop where it needs to be - where the reason for the trade is no longer valid. E.g. trading a support bounce the stop goes below the support.
    • Account Balance * percent/100 = RISK = OrderLots * (|OrderOpenPrice - OrderStopLoss| * DeltaPerLot + CommissionPerLot) (Note OOP-OSL includes the SPREAD, and DeltaPerLot is usually around $10/pip but it takes account of the exchange rates of the pair vs. your account currency.)
    • Do NOT use TickValue by itself - DeltaPerLot
    • You must normalize lots properly and check against min and max.
    • You must also check FreeMargin to avoid stop out

  2. Drop that *10. You are trying to get PipVaue. You are not adjusting SL, TP, and slippage; for 4/5 digit brokers and for JPY pairs.
    double   pip          = StringFind(_Symbol,"JPY") < 0 ? 0.01 : 0.0001;
    int      pipDigits    = (int)MathLog10(pip/_Point);
    int      pipsToPoints = int(pip / _Point);
    int      slippage     = 3 * pipsToPoints;
Alexander Martinez
162
Alexander Martinez  

Thanks for the help. I'll certainly look into the other concerns you mentioned, but I want to address the zero divide issue first, if that's okay with you.

‌So‌ I'm reading the part of your response that pertains to the zero divide, and I noticed you mentioned "OnTick". Since this is an indicator that I'm ‌programming, and not an EA, the equivalent function of OnTick would be OnCalculate.

I moved the variable initialization of tickValue (and all relevant function calls that make use of tickValue) over to OnCalculate. While the indicator loads up properly now when the terminal is started, the zero divide error still occurs.

I take it when you said OnTick, you literally meant OnTick, and thus, it will still give me a zero divide if the indicator starts up with the terminal unless I convert this indicator into an EA. Is that correct?‌

whroeder1
16574
whroeder1  
  1. If it's an indicator, there is no OnTick, must be OnCalculate.
  2. Print out your variables, and find out why.
Alexander Martinez
162
Alexander Martinez  

I printed out the value of tickValue, and it was still 0 despite being in the OnCalculate scope.‌

So here's what I did to resolve the issue:

‌‌

// OnCalculate Scope
   if (tickValue == 0){
      tickValue = MarketInfo(Symbol(),MODE_TICKVALUE)*10;
   }
   if (tickValue > 0 && !firstRun){
      Comment(DoubleToStr(tickValue,Digits));
      createObjects();
   }

I'm not an expert on how the process works, but it seems there are multiple passes of OnCalculate during startup, so as long as I only create the objects and run the functions that use tickValue when tickValue > 0, the indicator loads up fine and works properly without having to re-initialize.

Fernando Carreiro
3598
Fernando Carreiro  
user3822:

I printed out the value of tickValue, and it was still 0 despite being in the OnCalculate scope.‌

So here's what I did to resolve the issue:

I'm not an expert on how the process works, but it seems there are multiple passes of OnCalculate during startup, so as long as I only create the objects and run the functions that use tickValue when tickValue > 0, the indicator loads up fine and works properly without having to re-initialize.
I use "MarketInfo(Symbol(),MODE_TICKVALUE)" in some of my Indicators, some of which I use all the time on most of my Charts, and I have never once had them give me a "0.0" value that would cause a "Zero-Divide" error, so maybe there is something else in your code that is contributing to it.
Alexander Martinez
162
Alexander Martinez  
Fernando Carreiro:
I use "MarketInfo(Symbol(),MODE_TICKVALUE)" in some of my Indicators, some of which I use all the time on most of my Charts, and I have never once had them give me a "0.0" value that would cause a "Zero-Divide" error, so maybe there is something else in your code that is contributing to it.

I don't think that's the case and, for the sake of anyone wishing to understand more, I'll explain why:

‌As pointed out by whoroeder1, when you launch MT4, the data from MarketInfo(Symbol(),MODE_TICKVALUE) isn't available until after certain processes have taken place. Therefore, it will be a 0 until those processes take place. This is can be proven by creating and initializing a global variable with MarketInfo(Symbol(),MODE_TICKVALUE), then using the print(DoubleToString(variable,number)) function in OnInit and OnCalculate.

If it were something wrong with the code, it would be reproducible outside of the launching the program at startup. Outside of this one instance, the indicator works perfectly fine and even fixes itself once I switch the timeframe on the chart that it's loaded.

Lastly, as I described in my last post, it's easily fixed by an if statement that waits for the variable 'tickValue' to be greater than 0.

Carl Schreiber
7679
Carl Schreiber  
user3822:

Hi everyone,

‌I'm getting a zero divide error if I leave an indicator running, close the terminal, then start it back up. The end result is that the indicator doesn't load up properly when I open the terminal.‌

Upon checking the 'Experts' tab, it told me which line in the code is causing the problem.

‌Here's the‌ code in question. The variable that is getting a value of zero, according to the entry in the 'Experts' tab, is 'tickValue'.

double tickValue      = MarketInfo(Symbol(),MODE_TICKVALUE)*10; // Global Variable


double calcLots(double slPips, double riskPct, double accSize){
   double dollarRisk    = accSize*(riskPct*.01);
   double lots          = (dollarRisk/tickValue)/slPips;
  
   return (lots);
}

‌My guess is that the Terminal is trying to send a request to the server for MarketInfo(Symbol(),MODE_TICKVALUE), but since the connection hasn't been established, it returns a value of '0'. I'm not 100% sure, but it's the only thing that would make sense to me. Edit: I confirmed that this is the problem.  I closed the Terminal, set up a breakpoint to the next line of code after the tickValue variable initialization, set up a Watch for the tickValue variable, then started the terminal back up through debugger. It is getting a value of zero.

I've tried the following, but it doesn't work: if (!IsConnected()) Sleep (10000);

Other than on Terminal start up, the indicator works perfectly fine.

I experienced that OnTick() and OnCalculate() start running even though not all data have yet arrived the terminal - so just try:‌

double tickValue      = MarketInfo(Symbol(),MODE_TICKVALUE)*10; // Global Variable
if (tickValue <= 0.0) return(0) // should work for EA and indicators where you don't have any sleep(..), so skip this tick and use the next one.

Alexander Martinez
162
Alexander Martinez  
Carl Schreiber:

I experienced that OnTick() and OnCalculate() start running even though not all data have yet arrived the terminal - so just try:‌

double tickValue      = MarketInfo(Symbol(),MODE_TICKVALUE)*10; // Global Variable
if (tickValue <= 0.0) return(0) // should work for EA and indicators where you don't have any sleep(..), so skip this tick and use the next one.

The solution I have going now works fine, but I'm always interested in something better. I just have one question. Where would you place‌

if (tickValue <= 0.0) return(0)

‌In OnInit, it still divides by zero.

‌In OnCalculate, it doesn't divide by zero, but the program doesn't continue forward (i.e., none of the objects are created). Also, when I switch timeframes, the objects are created, but the calculations for the lot size are way, way off.

Carl Schreiber
7679
Carl Schreiber  

If you need this or another value that might be zero due to a 'lost' thread-race you have to put all that into OnStart() or OnCalculate() like: if (prev_calculated==0) {...

I had just a similar problem that drove my crazy for a while as I got occasionally (there is nothing worse than occasional errors) array out of ranges right after I switched the timeframe. After a simple recompile without any change everything was fine.

The problem was/is that OnCalculate starts calculating based on the local existing data ‌even though the most recent data still haven't arrived yet - array out of range.

I do now:‌

if ( TimeCurrent()-rPer[AllPer-1].time > PeriodSeconds() ) return(0)

‌But with this I am now in trouble with e.g. the DAX which closes 16:30.

I haven't tried it yet but I think and hope‌

if ( AllPer < 2 || ((bool)MarketInfo(_Symbol,MODE_TRADEALLOWED) &&  (TimeCurrent()-rPer[AllPer-1].time) > PeriodSeconds() ) ) return(0);

‌will do the trick.

Keith Watford
Moderator
10541
Keith Watford  
user3822:

The solution I have going now works fine, but I'm always interested in something better. I just have one question. Where would you place‌

if (tickValue <= 0.0) return(0)

‌In OnInit, it still divides by zero.

‌In OnCalculate, it doesn't divide by zero, but the program doesn't continue forward (i.e., none of the objects are created). Also, when I switch timeframes, the objects are created, but the calculations for the lot size are way, way off.


It will in Oninit for the reasons already established.

It doesn't continue in OnCalculate because it is the weekend so there is only the initial "tick". There is not a 2nd tick to execute OnCalculate again‌

12
To add comments, please log in or register