Quick Answer
zero divide in 'MyEA.mq5' (87,23) is an MQL5 runtime error. Your code divided a number by zero, and the terminal stops the program. It shows up in the Experts tab while the EA runs, not when you compile, so the EA can build with no warning and still stop later on a live chart or in the Strategy Tester.
The fix has two steps. Open the file at the line and column in the message to see which division it is, and then check the value you divide by before you divide. In an EA the divisor is usually a symbol property that is 0 when the symbol data is not ready, a count of zero items, or a price range of zero.
Key Facts
| What you see | What it means | What to do |
|---|---|---|
| zero divide in 'MyEA.mq5' (87,23) | A division by zero at line 87, column 23 | Open the file, go to that line and column |
| Happens right after attaching the EA | Symbol data was not ready, so a property like tick value or volume step was 0 | Check the property before you use it |
| Happens on some symbols only | The symbol has a different tick size, volume step or no history | Read the properties from the symbol, do not hard-code them |
| Happens on one bar only | A bar with high == low, or a count of 0 | Check the range or the count |
| Compiles with no warning | The compiler cannot know the value at run time | Guard every division whose divisor can be 0 |
Read the Experts Log
The message in the Experts tab has the same shape every time:
zero divide in 'MyEA.mq5' (87,23)
The two numbers are the line and the column. Open the file in MetaEditor, press Ctrl+G to go to the line, and look at the / or % on it. The divisor is the value to the right. Print it just before the line to see what it holds. The same log format is used for the array error explained in MQL5 Array Out of Range Error.
The Four Usual Causes
This EA contains four divisions that can fail. Each marked line can raise the error depending on the symbol, the moment and the history:
input double RiskMoney = 50.0;
input double SlPoints = 200.0;
void OnTick()
{
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
// 1. tickValue is 0 when the symbol data is not ready
double lots = RiskMoney / (SlPoints * tickValue);
// 2. volumeStep is 0 when the symbol data is not ready
double steps = lots / volumeStep;
// 3. count is 0 when no bar was copied
double sum = 0.0;
int count = 0;
// ... a loop that may add nothing ...
double avg = sum / count;
// 4. high == low on a bar with no range
double high = iHigh(_Symbol, _Period, 1);
double low = iLow(_Symbol, _Period, 1);
double close = iClose(_Symbol, _Period, 1);
double ratio = (close - low) / (high - low);
}
- Tick value is 0.
SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE)can return 0 when the symbol is not selected in Market Watch or its data is not loaded yet. A position size built on it divides by zero. - Volume step is 0. The same applies to
SYMBOL_VOLUME_STEP. Lot rounding such aslots / volumeStepfails when it is 0. The rounding itself is explained in MQL5 Lot Size Calculation. - An empty average.
sum / countfails when the loop added nothing, for example whenCopyBuffercopied no bars. See MQL5 CopyBuffer guide for how to check the copied count. - A price range of zero. Stochastic-style and money-flow formulas divide by
high - low. A bar with the same high and low gives 0.
A stop distance of 0 is a fifth cause of the same kind: risk-based sizing divides by it, and a stop of 0 means no stop at all.
Add Safe Checks
Check each divisor before the division, and decide what the EA should do when the check fails. Usually the right answer is to skip this tick, not to use a made-up number.
// Divide a by b. Returns false and leaves 'result' untouched when b is (almost) zero.
bool SafeDivide(double a, double b, double &result)
{
if(MathAbs(b) <= DBL_EPSILON)
return false;
result = a / b;
return true;
}
// Lots for a given money risk and stop distance in points.
// Returns 0.0 when anything needed is not ready, so the caller can skip the trade.
double LotsForRisk(double riskMoney, double slPoints)
{
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
if(tickValue <= 0.0 || tickSize <= 0.0 || step <= 0.0)
return 0.0; // symbol data not ready
if(riskMoney <= 0.0 || slPoints <= 0.0)
return 0.0; // no valid risk or no stop
double slPrice = slPoints * _Point;
double moneyPerLot = slPrice / tickSize * tickValue; // loss per 1.0 lot at the stop
if(moneyPerLot <= 0.0)
return 0.0;
double lots = riskMoney / moneyPerLot;
lots = MathFloor(lots / step) * step; // round down to the volume step
if(lots < minLot)
return 0.0; // risk too small for the minimum lot
if(lots > maxLot)
lots = maxLot;
return NormalizeDouble(lots, 8);
}
The function returns 0.0 and does not force the minimum lot, because forcing it would raise the risk above what the input says. How to turn the result into a valid order volume is covered in MQL5 Lot Size Calculation. A stop that is too close or invalid has its own error in MQL5 Invalid Stops Error 10016.
Full MQL5 Example
This EA runs once per closed bar. It calculates a safe average, a safe close position inside the bar range and the risk-based lots, and prints them. It does not place trades.
input double RiskMoney = 50.0;
input double SlPoints = 200.0;
input int AvgBars = 10;
datetime g_lastBarTime = 0;
int OnInit()
{
g_lastBarTime = iTime(_Symbol, _Period, 0);
return INIT_SUCCEEDED;
}
bool IsNewBar()
{
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == 0 || currentBarTime == g_lastBarTime)
return false;
g_lastBarTime = currentBarTime;
return true;
}
bool SafeDivide(double a, double b, double &result)
{
if(MathAbs(b) <= DBL_EPSILON)
return false;
result = a / b;
return true;
}
double LotsForRisk(double riskMoney, double slPoints)
{
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
if(tickValue <= 0.0 || tickSize <= 0.0 || step <= 0.0)
return 0.0;
if(riskMoney <= 0.0 || slPoints <= 0.0)
return 0.0;
double slPrice = slPoints * _Point;
double moneyPerLot = slPrice / tickSize * tickValue;
if(moneyPerLot <= 0.0)
return 0.0;
double lots = riskMoney / moneyPerLot;
lots = MathFloor(lots / step) * step;
if(lots < minLot)
return 0.0;
if(lots > maxLot)
lots = maxLot;
return NormalizeDouble(lots, 8);
}
void OnTick()
{
if(!IsNewBar())
return;
// 1. Average of the last AvgBars closes, only over the bars that exist
double sum = 0.0;
int count = 0;
for(int i = 1; i <= AvgBars; i++)
{
double c = iClose(_Symbol, _Period, i);
if(c == 0.0)
continue; // bar not available
sum += c;
count++;
}
double avg = 0.0;
if(!SafeDivide(sum, (double)count, avg))
return; // no bars yet
// 2. Close position inside the last closed bar (0 = low, 1 = high)
double high = iHigh(_Symbol, _Period, 1);
double low = iLow(_Symbol, _Period, 1);
double close = iClose(_Symbol, _Period, 1);
if(high == 0.0 || low == 0.0 || close == 0.0)
return;
double position = 0.5; // a bar with no range sits in the middle
if(!SafeDivide(close - low, high - low, position))
position = 0.5;
// 3. Lots for the risk, or 0.0 when the symbol data is not ready
double lots = LotsForRisk(RiskMoney, SlPoints);
PrintFormat("avg(%d) %.5f | close position in bar %.2f | lots for risk %.2f",
count, avg, position, lots);
}
The new-bar check is explained in Pine Script barstate.isnew in MQL5, and the shift 1 rule in Pine Script close[1] in MQL5.
Common Mistakes
- Fixing the symptom with a tiny number. Adding
+ 0.0000001to the divisor hides the problem and returns a huge, wrong value. Skip the calculation instead. - Comparing a double with
== 0.0only. A value that is almost zero can still give a huge result. Compare with a small threshold. - Trusting symbol properties on the first tick. Read tick value, tick size and volume step when you need them, and check them each time.
- Hard-coding tick values. They change by symbol and by account currency. Read them from the symbol.
- Dividing by a count without checking it. An average over zero bars is undefined. Check the count first.
- Forgetting
high == low. Formulas that divide by a bar's range need a check, and the same applies to Pine'snacases described in Pine Script ta.barssince in MQL5. - Testing only on one symbol. Run the EA on a forex pair, an index and a metal. Their tick sizes and volume steps differ.
FAQ
Related Guides
- MQL5 Array Out of Range Error: another runtime error that stops the EA, and how to read its log line.
- MQL5 Lot Size Calculation: turn a risk amount into a valid order volume.
- MQL5 CopyBuffer guide: check how many values were copied before you average them.
- MQL5 Invalid Stops Error 10016: when the stop distance is wrong.
- MQL5 Wrong Parameters Count Error: the compile error you meet when you move MT4 code to MT5.
- MQL5 Trade Return Codes: read the result of an order request.
- What to check in a trading bot before going live: a pre-live checklist for stops, lot size, spread and trade results.
- Why a Pine Script Strategy Gives Different Results in MQL5: missing-value handling is one of the causes.
Check Your EA for Common Mistakes
A division on a value that can be 0 is easy to miss in a long EA. The free early-bird Code Review checks an EA for common mistakes, and CodeFlowOS translates Pine Script into MQL5 so you can review the generated code before you test it in the MT5 Strategy Tester. The platform compile check is optional, and outputs are not guaranteed, so always review the result. If the code does not compile, the Error Fixer can suggest a fix. For the full conversion process, see the Pine Script to MQL5 guide, or try the converter page.
This article is educational. It does not describe trading performance and is not financial advice. Always compile and test code in MetaEditor and the Strategy Tester before using it on a live account.