Custom symbols
The custom symbol API enables you to create and manage your own symbols in cTrader. These symbols can represent synthetic assets, external datasets, derived metrics or completely offline instruments. Each custom symbol can be defined using one or two assets and supports full integration with timeframes, charting, indicators, backtesting and real-time updates.
Key types and methods for custom symbols include:
CustomSymbols.Add(name, baseSymbol) or CustomSymbols.Add(name, baseAsset, quoteAsset) to create a new custom symbol. CustomSymbol.BarsNeeded to supply OHLC data for the symbol on demand. CustomSymbol.UpdateQuote(bid, ask) to feed live prices to the symbol. CustomBars.AppendBars(), UpdateLastBar() and PrependBars() to manage bar data dynamically. Each CustomBar stores Time, Open, High, Low, Close and Volume.
Additionally, developers can define swap rates, commissions, leverage tiers, sentiment, futures settings and even market hours or holidays for custom symbols. Once created, custom symbols are fully interactive and can be viewed in charts or used programmatically in cBots, indicators and plugins.
Tip
Use custom symbols to visualise external data, simulate spreads or correlations, test strategies on proprietary datasets or combine multiple assets into synthetic instruments.
Custom symbol API objects can be used to do the following:
| Feature or operation | Examples |
| Simulating synthetic assets | Build a spread symbol (e.g. UKOIL - USOIL) Create equity or currency baskets |
| Visualising offline datasets | Load CSV data for markets Plot historical interest rates or economic indices |
| Live charting from APIs | Feed external real-time prices Stream calculated fair value or risk metrics |
| Strategy testing on custom data | Backtest on fundamental or alt datasets Simulate legacy market environments |
| Generating synthetic quotes | Derive custom prices from existing symbols Inject quotes into custom instruments |
| Trading constraints modeling | Apply custom sessions, holidays, futures expiry, swap structure or leverage tiers |
| Strategy metrics visualisation | Plot equity curve, drawdown or signals as price series for in-strategy analysis |
Basic operations
Create a new custom symbol with base symbol
| var baseSymbol = Symbols.GetSymbol("EURUSD");
var customSymbol = CustomSymbols.Add("MyCustomSymbol1", baseSymbol);
customSymbol.Description = "Synthetic EURUSD Tracker";
customSymbol.UpdateQuote(baseSymbol.Bid, baseSymbol.Ask);
|
Create a custom symbol with assets (no base symbol)
| var baseAsset = Assets.GetAsset("XAU");
var quoteAsset = Assets.GetAsset("USD");
var customSymbol = CustomSymbols.Add("GoldIndex", baseAsset, quoteAsset);
customSymbol.UpdateQuote(1923.5, 1923.8);
|
Define the static instrument properties
| customSymbol.LotSize = 100000;
customSymbol.PipDigits = 2;
customSymbol.TickDigits = 3;
customSymbol.Commission = 3.5;
customSymbol.SwapLong = -0.2;
customSymbol.SwapShort = 0.1;
|
Assign a quote feed (live or simulated)
| var tracking = Symbols.GetSymbol("GBPUSD");
tracking.Tick += e => customSymbol.UpdateQuote(e.Symbol.Bid, e.Symbol.Ask);
|
Handle bars request for synthetic data
| customSymbol.BarsNeeded = args =>
{
var baseBars = MarketData.GetBars(args.CustomBars.TimeFrame, "EURUSD");
var newBars = baseBars.Select(b => new CustomBar(b.OpenTime, b.Open, b.High, b.Low, b.Close, b.TickVolume));
args.CustomBars.AppendBars(newBars);
};
|
Append real-time bar on tick
| tracking.Tick += _ =>
{
var last = MarketData.GetBars(TimeFrame.Minute, tracking.Name).LastBar;
customSymbol.CustomBars.UpdateLastBar(last.Open, last.High, last.Low, last.Close, last.TickVolume);
};
|
Add custom trading session
| customSymbol.MarketHours.Sessions.Add(new CustomSymbolTradingSession(
DayOfWeek.Monday, DayOfWeek.Friday,
new TimeSpan(8, 0, 0), new TimeSpan(16, 30, 0)
));
|
Define futures settings
| customSymbol.FuturesSettings = new CustomSymbolFuturesSettings(
DateTime.UtcNow.AddDays(20),
DateTime.UtcNow.AddDays(30),
0.15 // maintenance margin
);
|
Add dynamic leverage tiers
| customSymbol.DynamicLeverage.Add(new CustomSymbolLeverageTier(100000, 100));
customSymbol.DynamicLeverage.Add(new CustomSymbolLeverageTier(500000, 50));
|
Create and add custom period
| var customTF = TimeFrameManager.Custom.Add("MyCustomH1");
customTF.BarsNeeded = args =>
{
var hourly = MarketData.GetBars(TimeFrame.Hour, args.CustomBars.Symbol.Name);
args.CustomBars.AppendBars(hourly.Select(b => new CustomBar(b.OpenTime, b.Open, b.High, b.Low, b.Close, b.TickVolume)));
};
|
Import data from CSV
1
2
3
4
5
6
7
8
9
10
11
12 | var lines = File.ReadAllLines("data.csv");
var bars = lines.Skip(1).Select(line =>
{
var parts = line.Split(',');
return new CustomBar(DateTime.Parse(parts[0]),
double.Parse(parts[1]), double.Parse(parts[2]),
double.Parse(parts[3]), double.Parse(parts[4]),
int.Parse(parts[5]));
});
customSymbol.BarsNeeded = args => args.CustomBars.AppendBars(bars);
|
Remove a custom symbol
| var cs = CustomSymbols.Get("MyCustomSymbol1");
CustomSymbols.Remove(cs);
|
Practical integration examples
Track fundamental data over time
Display macroeconomic indicators such as CPI, unemployment rate or GDP as synthetic OHLC bars. This approach enables strategy overlay, divergence analysis, and historical pattern tracking using structured economic data.
1
2
3
4
5
6
7
8
9
10
11
12
13 | var macroSymbol = CustomSymbols.Add("US_MacroIndex", Assets.GetAsset("USD"), Assets.GetAsset("USD"));
macroSymbol.BarsNeeded = args =>
{
var csvData = LoadCustomCsv("us_macro.csv"); // contains OpenTime, Open, High, Low, Close, Volume
args.CustomBars.AppendBars(csvData.Select(row => new CustomBar(
DateTime.Parse(row[0]),
double.Parse(row[1]),
double.Parse(row[2]),
double.Parse(row[3]),
double.Parse(row[4]),
int.Parse(row[5])
)));
};
|
Create a weighted asset basket
Combine multiple equities into a custom symbol that reflects a weighted portfolio. This setup allows you to track performance, apply indicators and backtest strategies on a synthetic equity index built from selected components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | var customIndex = CustomSymbols.Add("MyAssetBasket", Assets.GetAsset("USD"), Assets.GetAsset("USD"));
customIndex.BarsNeeded = args =>
{
var eurusdBars = MarketData.GetBars(TimeFrame.Daily, "EURUSD");
var gbpusdBars = MarketData.GetBars(TimeFrame.Daily, "GBPUSD");
var usdjpyBars = MarketData.GetBars(TimeFrame.Daily, "USDJPY");
var indexBars = Enumerable.Range(0, Math.Min(eurusdBars.Count, Math.Min(gbpusdBars.Count, usdjpyBars.Count)))
.Select(i =>
{
var time = eurusdBars[i].OpenTime;
var weightedClose = eurusdBars[i].Close * 0.4 + gbpusdBars[i].Close * 0.35 + usdjpyBars[i].Close * 0.25;
return new CustomBar(time, weightedClose, weightedClose, weightedClose, weightedClose, 0);
});
args.CustomBars.AppendBars(indexBars);
};
|
Track commodity price differentials
Consider creating a custom symbol that represents the price spread between gold and silver (XAUUSD - XAGUSD). This custom symbol may help with spread trading strategies, divergence detection and intermarket analysis on precious metals.
By analysing the difference in price movements between gold and silver, traders can identify relative strength, potential arbitrage opportunities or hedge one position against the other.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | var spreadSymbol = CustomSymbols.Add("Gold_Silver_Spread", Assets.GetAsset("USD"), Assets.GetAsset("USD"));
spreadSymbol.BarsNeeded = args =>
{
var gold = MarketData.GetBars(TimeFrame.Hour, "XAUUSD");
var silver = MarketData.GetBars(TimeFrame.Hour, "XAGUSD");
var spread = gold.Zip(silver, (g, s) => new CustomBar(
g.OpenTime,
g.Close - s.Close,
g.Close - s.Close,
g.Close - s.Close,
g.Close - s.Close,
g.TickVolume + s.TickVolume
));
args.CustomBars.AppendBars(spread);
};
|
Stream a live FX spread symbol
Create a real-time synthetic instrument by subtracting prices of two forex pairs.
This custom symbol enables charting and trading of the spread directly, supporting mean-reversion strategies, visual tracking and spread-based hedging.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | private CustomSymbol _eurGbpSpread;
private Symbol _eurusd, _gbpusd;
protected override void OnStart()
{
_eurusd = Symbols.GetSymbol("EURUSD");
_gbpusd = Symbols.GetSymbol("GBPUSD");
_eurGbpSpread = CustomSymbols.Add("EUR‑GBP Spread",
_eurusd.QuoteAsset, // both legs already trade in USD
_eurusd.QuoteAsset);
// propagate tick updates
_eurusd.Tick += OnLegTick;
_gbpusd.Tick += OnLegTick;
}
private void OnLegTick(SymbolTickEventArgs _)
{
var mid = _eurusd.Bid - _gbpusd.Bid; // naïve spread
_eurGbpSpread.UpdateQuote(mid, mid + 0.00001); // 0.1 pip synthetic spread
}
|