Quick Answer
Cannot call 'ta.ema' with argument 'length'='len'. An argument of 'series int' type was used but a 'simple int' is expected means a function needs a length that is fixed for the whole run of the script, and you passed a length that can change from bar to bar.
A simple int is known when the script starts: a number you typed, an input.int, or a value built only from those. A series int can be different on every bar: anything that depends on close, bar_index, an indicator or a condition. To fix the error, make the length constant, or rebuild the calculation so that it does not need a changing length.
Key Facts
| Cause | Example | Fix |
|---|---|---|
| Length chosen by a condition | len = close > open ? 10 : 20 | Calculate both EMAs with fixed lengths and choose the result |
| Length from another indicator | len = int(ta.atr(14)) | Rebuild the EMA with a changing smoothing factor |
| Length from bar_index or time | len = bar_index % 20 + 5 | Same as above, or use a fixed length |
| Length from a variable you change | len := 20 after len = 10 | Use an input.int or a constant |
| Length from request.security | len = request.security(...) | Calculate on the chart, or use a fixed length |
What Simple and Series Mean
Pine Script gives every value a qualifier. The ones that matter here are:
- const: known when the script is compiled, such as
14or"EMA". - input: set by the user in the settings, such as
input.int(14). - simple: known on the first bar and the same on all bars.
- series: can be different on every bar, such as
closeorta.atr(14).
A value with a lower qualifier can go where a higher one is expected, but not the other way. A const or input int works where a simple int is expected. A series int does not. Some functions accept a series int length and some require a simple int; the reference page of each function lists the type of every argument, and the error message names the one that is wrong.
The Pine Script Version That Fails
//@version=5
strategy("Adaptive EMA", overlay = true)
len = close > open ? 10 : 20 // a different value on different bars: series int
ma = ta.ema(close, len) // error: simple int expected
if ta.crossover(close, ma)
strategy.entry("Long", strategy.long)
len depends on close and open, so it is a series int. ta.ema keeps a running value from the previous bar, and a length that changes under it has no clear meaning, which is why Pine asks for a fixed one.
Fix 1: Use a Fixed Length
If the length does not need to change, make it an input:
//@version=5
strategy("EMA", overlay = true)
len = input.int(14, "EMA length", minval = 1)
ma = ta.ema(close, len)
input.int is available to the function as a simple int, and the user can still change it in the settings.
Fix 2: Calculate Both and Choose
If the idea is "use a fast EMA in one case and a slow EMA in another", calculate both with fixed lengths on every bar and pick the value:
//@version=5
strategy("Choose EMA", overlay = true)
fastEma = ta.ema(close, 10)
slowEma = ta.ema(close, 20)
ma = close > open ? fastEma : slowEma
Both EMAs are calculated on every bar. Do not put ta.ema inside the ?: or an if, because Pine functions that keep state need to run on every bar to be correct.
Fix 3: Rebuild the EMA With a Changing Length
If the length really has to change, write the EMA yourself. An EMA is a running average with a smoothing factor alpha = 2 / (length + 1), and alpha can be a series:
//@version=5
strategy("Adaptive EMA", overlay = true)
len = close > open ? 10 : 20
alpha = 2.0 / (len + 1.0)
var float ma = na
ma := na(ma) ? close : alpha * close + (1.0 - alpha) * ma
The first bar starts at close, and every later bar blends the new close into the previous value. The values are close to ta.ema but not identical in the first bars, because ta.ema starts from a simple average of the first values. Compare a few bars if the exact numbers matter.
Port It to MQL5
MQL5 has no simple or series qualifiers, but it has the same underlying rule in another form: an indicator handle is created once with a fixed period. To "change the length", create one handle per length and choose the value:
int fastHandle = INVALID_HANDLE;
int slowHandle = INVALID_HANDLE;
int OnInit()
{
fastHandle = iMA(_Symbol, _Period, 10, 0, MODE_EMA, PRICE_CLOSE);
slowHandle = iMA(_Symbol, _Period, 20, 0, MODE_EMA, PRICE_CLOSE);
if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
return INIT_FAILED;
return INIT_SUCCEEDED;
}
// Like: ma = close > open ? fastEma : slowEma, evaluated on the bar at 'shift'.
bool GetChosenEma(int shift, double &ma)
{
double fast[1], slow[1];
if(CopyBuffer(fastHandle, 0, shift, 1, fast) != 1) return false;
if(CopyBuffer(slowHandle, 0, shift, 1, slow) != 1) return false;
double open = iOpen(_Symbol, _Period, shift);
double close = iClose(_Symbol, _Period, shift);
if(open == 0.0 || close == 0.0)
return false;
ma = (close > open) ? fast[0] : slow[0];
return true;
}
Do not create a new handle on every tick to change the period. Create the handles in OnInit() and release them in OnDeinit(). The handle and CopyBuffer rules are explained in MQL5 CopyBuffer guide.
Full MQL5 Example
This EA picks the fast or slow EMA on each closed bar and prints a cross of the close above it. It does not place trades.
input int FastPeriod = 10;
input int SlowPeriod = 20;
int fastHandle = INVALID_HANDLE;
int slowHandle = INVALID_HANDLE;
datetime g_lastBarTime = 0;
int OnInit()
{
fastHandle = iMA(_Symbol, _Period, FastPeriod, 0, MODE_EMA, PRICE_CLOSE);
slowHandle = iMA(_Symbol, _Period, SlowPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
return INIT_FAILED;
g_lastBarTime = iTime(_Symbol, _Period, 0);
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(fastHandle != INVALID_HANDLE) IndicatorRelease(fastHandle);
if(slowHandle != INVALID_HANDLE) IndicatorRelease(slowHandle);
}
bool IsNewBar()
{
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime == 0 || currentBarTime == g_lastBarTime)
return false;
g_lastBarTime = currentBarTime;
return true;
}
bool GetChosenEma(int shift, double &ma, double &close)
{
double fast[1], slow[1];
if(CopyBuffer(fastHandle, 0, shift, 1, fast) != 1) return false;
if(CopyBuffer(slowHandle, 0, shift, 1, slow) != 1) return false;
double open = iOpen(_Symbol, _Period, shift);
close = iClose(_Symbol, _Period, shift);
if(open == 0.0 || close == 0.0)
return false;
ma = (close > open) ? fast[0] : slow[0];
return true;
}
void OnTick()
{
if(!IsNewBar())
return;
double ma1, close1, ma2, close2;
// shift 1 = last closed bar, shift 2 = the bar before it
if(!GetChosenEma(1, ma1, close1)) return;
if(!GetChosenEma(2, ma2, close2)) return;
// ta.crossover(close, ma) on the closed bar
if(close1 > ma1 && close2 <= ma2)
PrintFormat("Close crossed above the chosen EMA. Close %.5f, EMA %.5f", close1, ma1);
}
The cross rule is explained in Pine Script ta.crossover in MQL5. One thing to know about this example: the chosen line switches between two EMAs from bar to bar, so the value on the previous bar (ma2) can come from a different EMA than ma1. That matches the Pine version in Fix 2, and it is worth checking against TradingView.
Common Mistakes
- Passing a calculated length. Any length built from price, an indicator or
bar_indexis aseries int. - Putting
ta.*inside a condition. Calculate the function on every bar and choose the result afterwards. - Forcing the type with
int().int(x)changes the number to an integer, not the qualifier. - Changing the length with
:=. A variable you reassign is a series, even when it looks constant. - Using
request.securityfor the length. The returned value is a series. - Creating an MQL5 handle on every tick. Create it once and read it with
CopyBuffer. - Expecting the rebuilt EMA to match from bar one. The first values differ, so compare after the warm-up.
FAQ
Related Guides
- Pine Script Could Not Find Function Error (ta.cmf): another Pine error that comes from a function the script cannot use.
- Pine Script ta.rsi and ta.ema vs MQL5: why EMA values differ between platforms.
- Pine Script ta.crossover in MQL5: detect a cross on closed bars.
- Pine Script var and varip in MQL5: keep a running value between bars, as the rebuilt EMA does.
- Pine Script input.* in MQL5: inputs and fixed settings.
- MQL5 CopyBuffer guide: read indicator buffers safely.
- Pine Script v6 to MQL5: version differences and how to convert them.
- Why a Pine Script Strategy Gives Different Results in MQL5: indicator differences are one of the causes.
Convert Pine Script With Changing Lengths
A length that changes from bar to bar has no direct MQL5 copy, so a converter has to rebuild the logic. CodeFlowOS translates Pine Script into MQL5 and lets you 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. For the full process, see the Pine Script to MQL5 guide, or try the converter page. If the code does not compile, the Error Fixer can suggest a fix, and the free early-bird Code Review checks an EA for common mistakes.
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.