Quick Answer
Two C# compile errors say that you used the same variable name twice in a way the compiler does not allow:
CS0128: A local variable named 'x' is already defined in this scopemeans you declaredxtwice in the same block.CS0136: A local variable named 'x' cannot be declared in this scope because it would give a different meaning to 'x', which is used in a parent or current scopemeans you declaredxinside a nested block (a loop, anif, a lambda) while the outer block also has a variablex, declared before or after the nested block.
C# does not let an inner variable hide an outer local variable of the same name. This is different from Pine Script, where a name in a nested block can shadow an outer one, and it is a frequent surprise after a conversion. The fix is to give each variable its own name, or to reuse the first variable with a plain assignment (x = ..., without the type in front of it).
From the author: I build cBots in cTrader Automate and convert strategies from Pine Script and MQL5 to C#. These two errors show up when a long
OnBarmethod grows by copy and paste: the samevar close = ...orint iappears in several places. This guide shows the cases and a safe way to fix each one.
Key Facts
| What you see | Usual cause | Fix |
|---|---|---|
| CS0128 on a second double ema = ... | Same name declared twice in one block | Assign instead: ema = ... |
| CS0136 on a variable inside a for | The outer block already has a variable with that name | Rename one of them |
| CS0136 on a variable in an if block | An outer variable of that name is declared later in the method | Rename, or move the declaration |
| CS0136 in a lambda | The lambda parameter has the name of a local variable | Rename the lambda parameter |
| Two loops that both use int i side by side | This is allowed | No fix needed |
| An outer int i and a loop for (int i ... | Conflict | Rename the loop counter |
Read the Message
CS0128: A local variable named 'close' is already defined in this scope
CS0136: A local variable or function named 'i' cannot be declared in this scope
because that name is used in an enclosing local scope to define a local
or function (the exact wording can differ between compiler versions)
- The name is the variable that is declared twice.
- The line points to the second declaration, which is not always the one you should change. Look at both places and decide which one gets a new name.
The Broken cBot
This cBot reads a few values on every bar and prints them. It does not trade. Three declarations conflict:
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BrokenBot : Robot
{
private ExponentialMovingAverage _ema;
protected override void OnStart()
{
_ema = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 20);
}
protected override void OnBar()
{
double close = Bars.ClosePrices.Last(1);
double ema = _ema.Result.Last(1);
double close = Bars.ClosePrices.Last(2); // CS0128
double sum = 0;
for (int i = 1; i <= 5; i++)
{
double close = Bars.ClosePrices.Last(i); // CS0136
sum += close;
}
int i = 0; // CS0136 for the loop counter above
Print("Close {0}, EMA {1}, sum of 5 closes {2}, i {3}", close, ema, sum, i);
}
}
}
Cause 1: The Same Name Twice in One Block (CS0128)
A second declaration with a type in front of it is a new variable, and a block cannot have two variables with the same name. If you want to change the value, assign it without the type:
double close = Bars.ClosePrices.Last(1);
close = Bars.ClosePrices.Last(2); // assignment, not a new variable
If you need both values, use two names that say what each one is:
double lastClose = Bars.ClosePrices.Last(1);
double previousClose = Bars.ClosePrices.Last(2);
Names such as lastClose and previousClose also make the later conditions easier to read than close and close2. The Pine Script close[1] idea and the closed-bar rule are explained in Pine Script strategy.entry to cTrader C#.
Cause 2: A Loop or if Block Reuses an Outer Name (CS0136)
A nested block can read an outer variable, but it cannot declare a new variable with the same name. The compiler also looks at declarations below the block: in the example above, int i = 0; at the end of OnBar belongs to the whole method body, so the i of the for loop conflicts with it even though it comes later:
for (int i = 1; i <= 5; i++) { ... } // conflicts with the "int i" declared further down
int i = 0;
The fix is to rename one of them. Use a loop counter name for the loop and a different name for the other value:
for (int bar = 1; bar <= 5; bar++)
{
double barClose = Bars.ClosePrices.Last(bar);
sum += barClose;
}
int signalCount = 0;
Cause 3: A Lambda Parameter With the Name of a Local Variable
A lambda parameter is a variable too. If a local variable with the same name exists in the enclosing method, you get CS0136:
var position = Positions.Find("Label"); // a local named position
bool any = Positions.Any(position => position.Pips > 0); // conflict: the lambda parameter is also position
Rename the lambda parameter. A short, different name is the usual style:
using System.Linq;
var position = Positions.Find("Label");
bool any = Positions.Any(p => p.Pips > 0);
Any needs using System.Linq;, and without it the error is CS1061 (cTrader C# error CS1061).
Cause 4: Copy and Paste of a Block
When you copy a block of a cBot that declares variables, for example the code of a buy signal, and paste it below for the sell signal in the same method, every declaration is now there twice. Put each block in its own method, so that each has its own scope:
private void CheckBuy()
{
double close = Bars.ClosePrices.Last(1);
double ema = _ema.Result.Last(1);
// ...
}
private void CheckSell()
{
double close = Bars.ClosePrices.Last(1); // allowed: another method, another scope
double ema = _ema.Result.Last(1);
// ...
}
Two separate methods can reuse the same names without a conflict, and a short method is easier to test than a long OnBar.
What Is Allowed
| Code | Allowed? |
|---|---|
| Two for (int i ...) loops one after the other | Yes, each i has its own scope |
| A local variable and a class field with the same name | Yes, but it hides the field and is confusing; rename it |
| A local variable x in CheckBuy and another x in CheckSell | Yes |
| A nested block that reads an outer variable | Yes |
| A nested block that declares a variable with an outer name | No: CS0136 |
The Fixed cBot
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class FixedBot : Robot
{
private ExponentialMovingAverage _ema;
protected override void OnStart()
{
_ema = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 20);
}
protected override void OnBar()
{
double lastClose = Bars.ClosePrices.Last(1);
double previousClose = Bars.ClosePrices.Last(2);
double ema = _ema.Result.Last(1);
if (double.IsNaN(lastClose) || double.IsNaN(previousClose) || double.IsNaN(ema))
return;
double sum = 0;
for (int bar = 1; bar <= 5; bar++)
{
double barClose = Bars.ClosePrices.Last(bar);
sum += barClose;
}
int signalCount = 0;
Print("Last close {0}, previous close {1}, EMA {2}, sum of 5 closes {3}, signals {4}",
lastClose, previousClose, ema, sum, signalCount);
}
}
}
The bot only prints, so you can compare the numbers with the chart before you add trade logic.
Similar Errors
| Error | Message | What it means | |---|---|---| | CS0128 | A local variable is already defined in this scope | Two declarations in one block | | CS0136 | A local variable cannot be declared in this scope | A nested block reuses an outer name | | CS0103 | The name 'x' does not exist in the current context | The name is used outside the block where it was declared | | CS0165 | Use of unassigned local variable 'x' | A variable is read before it has a value | | CS0246 | The type or namespace name could not be found | A type name is unknown |
Checklist: What to Check When You See CS0128 or CS0136
- Read the name in the message and search for it in the method.
- Find every declaration, including the ones below the line with the error.
- Same block? Replace the second declaration with an assignment, or rename it.
- Nested block? Rename the inner variable or the outer one.
- Lambda? Rename the lambda parameter.
- Pasted block? Move it into its own method.
- Use names that say what the value is (
lastClose,fastEma), notx,i2orclose2. - Build again after each rename and compare the printed values with the chart.
Common Mistakes
- Writing the type again when you only want to change a value.
- Reusing
iin a loop when anotheriis declared in the method. - Reusing a variable name as a lambda parameter.
- Pasting the buy block and the sell block into one method.
- A rename that misses one use, which then gives CS0103. Rename all uses.
- Naming everything
close,emaorvalue.
FAQ
Related Guides
- cTrader C# error CS0103: the name does not exist in the current context.
- cTrader C# error CS1061: the object is found, the member is not.
- cTrader C# error CS1503: an argument of the wrong type in a call.
- cTrader C# error CS0246: a type name the compiler does not know.
- Pine Script strategy.entry to cTrader C#: closed-bar values and order calls in C#.
- Pine Script to cTrader C# cBot: the full conversion process.
- What to check in a trading bot before going live: a pre-live checklist for stops, lot size, spread and trade results.
- cTrader C# error CS0161: a method that does not return a value on every path.
Fix Compile Errors Without Guessing
If a cBot or an Expert Advisor does not build, paste the code and the error message into the CodeFlowOS Error Fixer. It suggests a minimal fix, explains each error and shows what changed. A fix uses 1 credit, with up to 3 attempts included, and the compiler check is optional. Outputs are not guaranteed, and code that compiles can still have wrong trading logic, so always review the result. Before a bot goes live, the Code Review is free during the early-bird period. CodeFlowOS also converts strategies between Pine Script, MQL5 and cTrader C#: try the converter page.
This article is educational. It does not describe trading performance and is not financial advice. Always build the code in cTrader Automate and backtest it before using it on a live account.