Quick Answer
Undeclared identifier 'x' means the Pine Script compiler reached the name x and has no variable, function or constant with that name at that place in the script. The words "at that place" matter. The name may exist, but in a different scope, or further down in the file, or in a different version of Pine Script.
The four usual causes are a variable declared inside an if block, a loop or a function and then used outside it, a typo or a wrong capital letter, a name from Pine Script version 4 that moved to a namespace in version 5 or 6 (for example tr became ta.tr), and a variable that is used before the line that declares it. Check them in that order; each takes a minute.
If the compiler says it cannot find a function, the message is different (Could not find function or function reference), and the causes are in Pine Script Error: Could Not Find Function or Function Reference 'ta.cmf'.
Key Facts
| Cause | Example | Fix |
|---|---|---|
| Declared in an if block, used outside | if cond then sig = 1, then plot(sig) | Declare the variable before the block and reassign with := |
| Loop variable used after the loop | for i = 0 to 9 then plot(i) | Keep the value in a variable declared before the loop |
| Typo or wrong case | Close, hight, barindex | Names are case-sensitive: close, high, bar_index |
| v4 name in v5 or v6 | tr, obv | ta.tr, ta.obv |
| Used before it is declared | plot(ma) on line 3, ma = ta.sma(close, 20) on line 5 | Move the declaration above the first use |
| Declared in a function, used outside | f() => y = close * 2 then plot(y) | Return the value from the function |
Read the Message
Undeclared identifier 'signal'
The name in quotes is the one the compiler could not resolve. The line number points to the use, not to the declaration you were expecting. So the first question is not "where is it declared", it is "can the compiler see that declaration from this line".
Cause 1: A Variable Declared Inside a Block
In Pine Script, a variable that you declare inside an if, a for loop, a while loop or a function belongs to that block only. After the block ends, the name does not exist:
//@version=5
indicator("Scope error", overlay = true)
if close > open
signal = 1 // exists only inside this if block
plot(signal) // Undeclared identifier 'signal'
There are two clean fixes. The first is to calculate the value with a conditional expression, which needs no block:
//@version=5
indicator("Scope fixed 1", overlay = true)
signal = close > open ? 1 : 0
plot(signal)
The second is to declare the variable before the block and change it inside, with := and not =:
//@version=5
indicator("Scope fixed 2", overlay = true)
int signal = 0
if close > open
signal := 1 // := reassigns the outer variable
plot(signal)
The difference between = and := is the key. = declares a new variable (and inside a block, that variable stays inside it). := assigns a new value to a variable that already exists. If you write signal = 1 inside the block, you do not change the outer signal, even when one exists; you make a second, local one.
Cause 2: A Loop Variable or Loop Result Used Outside
The counter of a for loop exists only inside the loop. A result that you want after the loop must be stored in a variable declared before it:
//@version=5
indicator("Loop scope", overlay = false)
float total = 0.0
for i = 0 to 4
total += close[i]
avg = total / 5
plot(avg)
total is declared outside, so the line plot(avg) can use it. If total were declared inside the loop, the line after the loop would fail with Undeclared identifier.
Cause 3: A Typo or the Wrong Case
Pine Script is case-sensitive, and built-in names are all lower case with underscores:
| Wrong | Correct |
|---|---|
| Close, CLOSE | close |
| hight | high |
| barindex, barIndex | bar_index |
| Volume | volume |
The same rule applies to your own names: fastMA and fastma are two different variables. A typo in the declaration is harder to see than a typo in the use, so check both lines.
Cause 4: A Name From Version 4
Pine Script version 5 moved many built-in functions and variables into namespaces. A script that starts with //@version=5 or //@version=6 but still uses the old short name fails:
//@version=5
indicator("Old names")
r = tr // Undeclared identifier: use ta.tr
o = obv // Undeclared identifier: use ta.obv
//@version=5
indicator("New names")
r = ta.tr
o = ta.obv
plot(r)
plot(o)
The same move happened to functions (sma became ta.sma), which gives the different "could not find function" message. The version line at the top of the script decides which names are valid, so a script that mixes both styles breaks. Version differences are covered in Pine Script v6 to MQL5. Check the migration guide of Pine Script for the full list of renamed variables before you convert a long v4 script by hand.
Cause 5: Use Before Declaration
A Pine script runs from the top to the bottom on every bar. A name must be declared on a line above its first use:
//@version=5
indicator("Order", overlay = true)
plot(ma) // Undeclared identifier 'ma'
ma = ta.sma(close, 20)
//@version=5
indicator("Order fixed", overlay = true)
ma = ta.sma(close, 20)
plot(ma)
User-defined functions follow the same rule: define a function above the line that calls it.
Cause 6: A Value Created Inside a Function
A variable created inside a function is local to it, so the caller cannot read it. Return the value instead:
//@version=5
indicator("Function scope", overlay = false)
double2(x) =>
y = x * 2 // y exists only inside double2
y // the last expression is the return value
plot(double2(close))
The last line of the function body is its return value, so y leaves the function as a result, not as a name.
Port It to MQL5
MQL5 has the same idea of scope, and the matching compile error is undeclared identifier. A variable declared inside a block { ... } or a function does not exist outside it. In an EA you often need a value to survive from one tick to the next, and that needs a global variable (declared outside every function), not a local one:
datetime g_lastBarTime = 0;
int g_signal = 0; // global: keeps its value between ticks
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;
}
void OnTick()
{
if(!IsNewBar())
return;
double open1 = iOpen(_Symbol, _Period, 1);
double close1 = iClose(_Symbol, _Period, 1);
if(open1 == 0.0 || close1 == 0.0)
return;
g_signal = (close1 > open1) ? 1 : 0; // like: signal = close > open ? 1 : 0
PrintFormat("Signal on the last closed bar: %d", g_signal);
}
In Pine, var keeps a value between bars. In MQL5 the same job is done by a global variable or a static local. The state rules are explained in Pine Script var and varip in MQL5, and the compile error in MQL5 undeclared identifier error.
How to Find the Cause
- Read the name and the line. Copy the name into the search of the editor and look at every place it appears.
- Find the declaration. Is it above the use? Is it inside an indented block that the use is not part of?
- Compare the indentation. In Pine Script, the indentation decides the scope. A line that is indented one level more belongs to the block above it.
- Check the version line.
//@version=5or//@version=6means the new names. - Check the spelling and the case in the declaration and in the use.
- Fix the first error first and run the script again, because one missing name can create several errors below it.
Common Mistakes
- Using
=inside a block and expecting the outer variable to change. Use:=. - Declaring a variable inside an
ifthat the rest of the script needs. - Using a loop counter after the loop.
- Mixing v4 and v5 names in one script.
- Typing a built-in name in the wrong case.
- Calling a variable or function above its declaration.
- Reading a local value of a function instead of returning it.
FAQ
Related Guides
- Pine Script Error: Could Not Find Function (ta.cmf): the matching error for a function name.
- Pine Script Error: 'series int' Used but 'simple int' Is Expected: another Pine compile error with a clear fix.
- Pine Script v6 to MQL5: version differences and how to convert them.
- Pine Script var and varip in MQL5: keep a value between bars.
- MQL5 undeclared identifier error: the MetaEditor version of the same error.
- Why a Pine Script Strategy Gives Different Results in MQL5: scope and state are among the causes.
- Pine Script Error: End of Line Without Line Continuation: a syntax error from a wrapped line.
Convert a Script That Does Not Compile
A script with scope or version problems cannot be converted by copying names. 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.