Quick Answer
CS0266: Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?) means you tried to store a double (a number with decimals) in an int (a whole number) variable. C# refuses to do this silently, because the decimals would be cut off and the value could change.
In a cBot almost every trading number is a double: prices, pips, profit, balance, volume in units. The error appears when a double result is assigned to an int variable, for example int pips = position.Pips; or int volume = Symbol.NormalizeVolumeInUnits(...);. The best fix is usually to declare the variable as a double. If you really need a whole number, convert on purpose, and decide how to round.
The related error CS1503 is about an argument of the wrong type in a method call: cTrader C# error CS1503. CS0266 is about an assignment.
From the author: I build cBots in cTrader Automate and convert strategies from Pine Script and MQL5 to C#. CS0266 is a common error after a hand conversion, because Pine Script and MQL5 are more relaxed about number types. The fix looks trivial, but a careless cast can change the volume of a trade, so this guide shows the safe choice for each case.
Key Facts
| What you see | Usual cause | Fix |
|---|---|---|
| int pips = position.Pips; | Pips is a double | double pips = position.Pips; |
| int volume = Symbol.NormalizeVolumeInUnits(units, ...); | The volume is a double | double volume = ... |
| int bars = Math.Round(x); | Math.Round returns a double | int bars = (int)Math.Round(x); |
| int shift = someDouble; then Last(shift) | A double shift | Declare the shift as int from the start |
| int period = EmaPeriod * 1.5; | A whole number times a decimal is a double | (int)Math.Round(EmaPeriod * 1.5) |
| float f = someDouble; | double to float has the same rule | Use double |
What the Compiler Is Telling You
CS0266: Cannot implicitly convert type 'double' to 'int'.
An explicit conversion exists (are you missing a cast?)
- The first type is the type of the value on the right of the
=. - The second type is the type of the variable on the left.
- "An explicit conversion exists" means the conversion is allowed, but you must write it yourself, with a cast, so that you decide about the lost decimals.
The Broken cBot
This cBot reads a few values once per bar and prints them. It does not place trades. Each marked line gives CS0266:
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BrokenBot : Robot
{
[Parameter("SMA period", DefaultValue = 20, MinValue = 1)]
public int SmaPeriod { get; set; }
[Parameter("Risk %", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 5.0)]
public double RiskPercent { get; set; }
private SimpleMovingAverage _sma;
protected override void OnStart()
{
_sma = Indicators.SimpleMovingAverage(Bars.ClosePrices, SmaPeriod);
}
protected override void OnBar()
{
int close = Bars.ClosePrices.Last(1); // CS0266
int slowPeriod = SmaPeriod * 1.5; // CS0266
int riskMoney = Account.Balance * RiskPercent / 100.0; // CS0266
int volume = Symbol.NormalizeVolumeInUnits(1000, RoundingMode.Down); // CS0266
Print("{0} {1} {2} {3}", close, slowPeriod, riskMoney, volume);
}
}
}
All four lines try to put a double into an int. They have different right answers, which is why a quick cast on every line is not a good fix.
Why Trading Numbers Are Doubles
| Value | Type | Why |
|---|---|---|
| Price (Bars.ClosePrices.Last(1), Symbol.Bid) | double | Prices have decimals |
| Pips (position.Pips, StopLossPips) | double | A stop can be 12.5 pips |
| Account values (Account.Balance, Account.Equity) | double | Money has decimals |
| Volume in units (Symbol.NormalizeVolumeInUnits(...)) | double | The volume step of a symbol can be fractional |
| A count (Positions.Count) | int | Whole numbers only |
| A shift for Last(n) | int | A bar index |
| An indicator period | int | A number of bars |
The rule that follows: if the value is a price, a distance, money or a volume, declare the variable as a double. If it is a count or an index, use an int.
Fix 1: Declare the Variable as a double
For prices, pips and money, change the variable type. There is nothing to convert:
double close = Bars.ClosePrices.Last(1);
double riskMoney = Account.Balance * RiskPercent / 100.0;
double volume = Symbol.NormalizeVolumeInUnits(1000, RoundingMode.Down);
Do not cast a volume to int to silence the error. A volume that is cut to a whole number can be smaller than the minimum step of the symbol, or different from what you calculated from your risk, and the order can then be rejected or sized wrongly. Let NormalizeVolumeInUnits do the rounding to the symbol's step, and keep the result as a double. The sizing rules are in Pine Script strategy.entry to cTrader C#.
Fix 2: Convert on Purpose When You Need a Whole Number
For a value that really must be a whole number, such as a period, write the cast and choose the rounding:
int slowPeriod = (int)Math.Round(SmaPeriod * 1.5); // 1.5 times the period, rounded to the nearest whole number
A plain cast (int)x cuts the decimals toward zero: (int)1.9 is 1 and (int)-1.9 is -1. Math.Round rounds to the nearest whole number (and, by default, rounds a value that ends exactly in .5 to the nearest even number, so Math.Round(2.5) is 2). Math.Floor rounds down and Math.Ceiling rounds up. Pick the one that matches what you want, and write it, because the compiler cannot know.
Math needs using System; at the top. Without it you get an error on Math, explained in cTrader C# error CS0103.
Fix 3: Keep an int Where the API Expects One
Some members only accept an int, for example the shift in Last(n). Declare that value as an int from the start, instead of converting a double back:
int shift = 1;
double close = Bars.ClosePrices.Last(shift);
If a double shift is passed instead, the error is CS1503 (a wrong argument type), which is explained in cTrader C# error CS1503.
The Fixed cBot
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class FixedBot : Robot
{
[Parameter("SMA period", DefaultValue = 20, MinValue = 1)]
public int SmaPeriod { get; set; }
[Parameter("Risk %", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 5.0)]
public double RiskPercent { get; set; }
private SimpleMovingAverage _sma;
protected override void OnStart()
{
_sma = Indicators.SimpleMovingAverage(Bars.ClosePrices, SmaPeriod);
}
protected override void OnBar()
{
double close = Bars.ClosePrices.Last(1);
int slowPeriod = (int)Math.Round(SmaPeriod * 1.5);
double riskMoney = Account.Balance * RiskPercent / 100.0;
double volume = Symbol.NormalizeVolumeInUnits(1000, RoundingMode.Down);
Print("Close {0}, slow period {1}, risk money {2}, volume {3}",
close, slowPeriod, riskMoney, volume);
}
}
}
The bot only prints, so you can check each number before you add any trading logic.
CS0266 and Similar Errors
| Error | Message | What it means | |---|---|---| | CS0266 | Cannot implicitly convert type 'A' to 'B'. An explicit conversion exists | The conversion is allowed with a cast | | CS0029 | Cannot implicitly convert type 'A' to 'B' | There is no conversion at all, for example text to a number | | CS1503 | Argument N: cannot convert from 'A' to 'B' | The same problem inside a method call | | CS0165 | Use of unassigned local variable 'x' | A variable is read before it has a value |
Checklist: What to Check When You See CS0266
- Read both types in the message: the value on the right, the variable on the left.
- Ask what the number means. A price, a distance, money or a volume stays a
double. - Change the variable type to
doubleif the value has decimals. - Need a whole number? Use
(int)Math.Round(x),Math.FloororMath.Ceilingand choose the rounding yourself. - Never cast a volume to
intto silence the error. - Check
using System;when you useMath. - Build again and print the value to see that it is what you expect.
- Test on a demo account before the cBot trades with real money.
Common Mistakes
- Casting everything with
(int)until the error is gone. - Casting a volume to
int. - Expecting
(int)xto round. It cuts the decimals. - Storing a price or a pip distance in an
int. - Forgetting
using System;forMath. - Using
floatfor prices. Usedouble, as the API does.
FAQ
Related Guides
- cTrader C# error CS1503: an argument of the wrong type in a call.
- cTrader C# error CS1061: the object is found, the member is not.
- cTrader C# error CS0103: the name does not exist in the current context.
- Pine Script strategy.entry to cTrader C#: risk-based volume with
NormalizeVolumeInUnits. - MQL5 lot size calculation: the same sizing idea for MetaTrader.
- MQL5 possible loss of data due to type conversion: the MetaEditor warning for the same kind of conversion.
- What to check in a trading bot before going live: a pre-live checklist for stops, lot size, spread and trade results.
- cTrader C# errors CS7036 and CS1501: the call has the wrong number of arguments.
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.