Allt du behöver för att komma igång med automatiserade handelsalgoritmer i C# för cTrader-plattformen - från grunden till färdig kod.
Att bygga en cTrader-bot är mer tillgängligt än det låter. Du behöver grundläggande C#-kunskaper och några gratis verktyg - det är allt.
Öppna ett gratis demokonto hos en cTrader-kompatibel mäklare. Pepperstone, IC Markets och Skilling stöder alla cTrader. Ingen insättning krävs för utveckling.
Ladda ner cTrader-desktopappen. Den inbyggda cTrader Automate IDE:n låter dig skriva, kompilera och backtesta bots utan några andra verktyg.
Du behöver inte vara en erfaren utvecklare. Att förstå klasser, metoder, variabler och villkor räcker för att komma igång. cTrader API hanterar det svåra.
De bästa botarna kommer från tydliga, testbara regler: "köp när X, sälj när Y, stop loss vid Z." Ju tydligare regler, desto enklare implementering.
En cBot är en C#-klass som ärver från Robot. cTrader anropar dina metoder automatiskt när marknaden rör sig. Här är de viktigaste byggstenarna.
En Bar är ett avslutat ljus (OHLCV). En Tick är varje prisuppdatering. Använd OnBar() för ljusbaserad logik, OnTick() för prisbaserad logik.
Bars.ClosePrices.Last(1)
Indikatorer returnerar DataSeries - arrayer med värden, ett per ljus. Kom åt dem med .Last(n) där 1 är det senast avslutade ljuset.
Indicators.MovingAverage(...)
Öppna affärer är Positions. Du kan filtrera på label, symbol och riktning. Använd ExecuteMarketOrder() för att öppna, ClosePosition() för att stänga.
Positions.FindAll("label", ...)
Limit- och stop-ordrar som ännu inte utlösts. Placera dem med PlaceLimitOrder() eller PlaceStopOrder(). De blir positioner när de fylls.
PlaceLimitOrder(TradeType.Buy, ...)
Dekorera egenskaper med [Parameter] för att exponera dem i cTrader UI. Användare kan konfigurera värden utan att röra koden. Viktigt för backtesting.
[Parameter("Period", DefaultValue = 14)]
Symbol.Bid och Symbol.Ask är aktuella priser. Symbol.PipSize konverterar pips till prisenheter. Symbol.QuantityToVolumeInUnits() konverterar lot.
Symbol.QuantityToVolumeInUnits(0.01)
// ── Minimal cBot skeleton ────────────────────────────────────────────── using cAlgo.API; using cAlgo.API.Indicators; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class MyBot : Robot { [Parameter("Volume (lots)", Group = "Settings", DefaultValue = 0.01)] public double Volume { get; set; } // Called once when the bot starts protected override void OnStart() { // Initialize indicators and state here Print("Bot started"); } // Called on every completed bar (candle) protected override void OnBar() { // Your strategy logic goes here } // Called on every price tick (optional) protected override void OnTick() { // Use for tick-level management, trailing stops, etc. } // Called when the bot stops protected override void OnStop() { Print("Bot stopped"); } }
Varje exempel är komplett, kompilerbar C#-kod. Klistra in den i cTrader Automate, tryck kompilera och kör den på ett demokonto.
Boten använder två exponentiella glidande medelvärden: ett snabbt (standard 10) och ett långsamt (standard 50). En korsning detekteras genom att jämföra förhållandet mellan de två MA:erna på de senaste två avslutade ljusen. Bara en position i varje riktning är öppen åt gången.
using cAlgo.API; using cAlgo.API.Indicators; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class MACrossoverBot : Robot { [Parameter("Fast MA Period", Group = "Settings", DefaultValue = 10)] public int FastPeriod { get; set; } [Parameter("Slow MA Period", Group = "Settings", DefaultValue = 50)] public int SlowPeriod { get; set; } [Parameter("Volume (lots)", Group = "Settings", DefaultValue = 0.01)] public double Volume { get; set; } [Parameter("Stop Loss (pips)", Group = "Risk", DefaultValue = 30)] public double StopLossPips { get; set; } [Parameter("Take Profit (pips)", Group = "Risk", DefaultValue = 60)] public double TakeProfitPips { get; set; } private MovingAverage _fastMa; private MovingAverage _slowMa; protected override void OnStart() { _fastMa = Indicators.MovingAverage(Bars.ClosePrices, FastPeriod, MovingAverageType.Exponential); _slowMa = Indicators.MovingAverage(Bars.ClosePrices, SlowPeriod, MovingAverageType.Exponential); } protected override void OnBar() { var fast = _fastMa.Result; var slow = _slowMa.Result; bool crossedAbove = fast.Last(1) > slow.Last(1) && fast.Last(2) <= slow.Last(2); bool crossedBelow = fast.Last(1) < slow.Last(1) && fast.Last(2) >= slow.Last(2); if (crossedAbove) { CloseAll(TradeType.Sell); if (Positions.FindAll("MA", SymbolName, TradeType.Buy).Length == 0) ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "MA", StopLossPips, TakeProfitPips); } if (crossedBelow) { CloseAll(TradeType.Buy); if (Positions.FindAll("MA", SymbolName, TradeType.Sell).Length == 0) ExecuteMarketOrder(TradeType.Sell, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "MA", StopLossPips, TakeProfitPips); } } private void CloseAll(TradeType type) { foreach (var p in Positions.FindAll("MA", SymbolName, type)) ClosePosition(p); } }
RSI (Relative Strength Index) oscillerar mellan 0 och 100. Under 30 anses traditionellt översålt, över 70 överköpt. Boten går in när något av ytterligheterna nås och avslutar vid take profit-nivån. Justera nivåerna baserat på instrumentets volatilitet.
using cAlgo.API; using cAlgo.API.Indicators; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class RSIMeanReversionBot : Robot { [Parameter("RSI Period", Group = "Settings", DefaultValue = 14)] public int RsiPeriod { get; set; } [Parameter("Oversold Level", Group = "Settings", DefaultValue = 30)] public double OversoldLevel { get; set; } [Parameter("Overbought Level", Group = "Settings", DefaultValue = 70)] public double OverboughtLevel { get; set; } [Parameter("Volume (lots)", Group = "Settings", DefaultValue = 0.01)] public double Volume { get; set; } [Parameter("Stop Loss (pips)", Group = "Risk", DefaultValue = 40)] public double StopLossPips { get; set; } [Parameter("Take Profit (pips)", Group = "Risk", DefaultValue = 80)] public double TakeProfitPips { get; set; } private RelativeStrengthIndex _rsi; protected override void OnStart() { _rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, RsiPeriod); } protected override void OnBar() { double rsi = _rsi.Result.LastValue; if (rsi < OversoldLevel && Positions.FindAll("RSI", SymbolName, TradeType.Buy).Length == 0) { ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "RSI", StopLossPips, TakeProfitPips); } if (rsi > OverboughtLevel && Positions.FindAll("RSI", SymbolName, TradeType.Sell).Length == 0) { ExecuteMarketOrder(TradeType.Sell, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "RSI", StopLossPips, TakeProfitPips); } } }
Bollingerbanden placerar ett övre och nedre intervall runt ett glidande medelvärde baserat på standardavvikelse. När priset berör det nedre bandet är det statistiskt sett utdraget nedåt; boten köper och förväntar sig ett återhopp. Banden vidgas automatiskt under perioder med hög volatilitet, vilket gör dem mer adaptiva än fasta nivåer.
using cAlgo.API; using cAlgo.API.Indicators; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class BollingerBandsBot : Robot { [Parameter("Periods", Group = "Settings", DefaultValue = 20)] public int Periods { get; set; } [Parameter("Standard Deviations", Group = "Settings", DefaultValue = 2.0)] public double StdDev { get; set; } [Parameter("Volume (lots)", Group = "Settings", DefaultValue = 0.01)] public double Volume { get; set; } [Parameter("Stop Loss (pips)", Group = "Risk", DefaultValue = 50)] public double StopLossPips { get; set; } [Parameter("Take Profit (pips)", Group = "Risk", DefaultValue = 50)] public double TakeProfitPips { get; set; } private BollingerBands _bb; protected override void OnStart() { _bb = Indicators.BollingerBands(Bars.ClosePrices, Periods, StdDev, MovingAverageType.Simple); } protected override void OnBar() { double close = Bars.ClosePrices.Last(1); double upper = _bb.Top.Last(1); double lower = _bb.Bottom.Last(1); // Buy when price touches or breaks below the lower band if (close <= lower && Positions.FindAll("BB", SymbolName, TradeType.Buy).Length == 0) { ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "BB", StopLossPips, TakeProfitPips); } // Sell when price touches or breaks above the upper band if (close >= upper && Positions.FindAll("BB", SymbolName, TradeType.Sell).Length == 0) { ExecuteMarketOrder(TradeType.Sell, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "BB", StopLossPips, TakeProfitPips); } } }
Boten spårar det högsta högt och lägsta lågt under de senaste N ljusen (Donchian-kanalen). När priset stänger ovanför den övre kanalen köper den utbrottet. När priset stänger under den nedre kanalen säljer den. Insikten är att nya höga och låga nivåer indikerar potentiell momentumkontinuation.
using cAlgo.API; using System; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class BreakoutBot : Robot { [Parameter("Lookback Bars", Group = "Settings", DefaultValue = 20)] public int Lookback { get; set; } [Parameter("Volume (lots)", Group = "Settings", DefaultValue = 0.01)] public double Volume { get; set; } [Parameter("Stop Loss (pips)", Group = "Risk", DefaultValue = 30)] public double StopLossPips { get; set; } [Parameter("Take Profit (pips)", Group = "Risk", DefaultValue = 90)] public double TakeProfitPips { get; set; } protected override void OnBar() { double channelHigh = double.MinValue; double channelLow = double.MaxValue; // Start from bar[2] - bar[1] is the bar that just closed, // we want the channel formed BEFORE it to detect a breakout for (int i = 2; i <= Lookback + 1; i++) { channelHigh = Math.Max(channelHigh, Bars.HighPrices.Last(i)); channelLow = Math.Min(channelLow, Bars.LowPrices.Last(i)); } double close = Bars.ClosePrices.Last(1); if (close > channelHigh && Positions.FindAll("BO", SymbolName, TradeType.Buy).Length == 0) { CloseAll(TradeType.Sell); ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "BO", StopLossPips, TakeProfitPips); } if (close < channelLow && Positions.FindAll("BO", SymbolName, TradeType.Sell).Length == 0) { CloseAll(TradeType.Buy); ExecuteMarketOrder(TradeType.Sell, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "BO", StopLossPips, TakeProfitPips); } } private void CloseAll(TradeType type) { foreach (var p in Positions.FindAll("BO", SymbolName, type)) ClosePosition(p); } }
Boten förankrar sig vid aktuellt pris vid start och placerar N köplimitordrar under (varje steg isär) och N säljlimitordrar ovanför. När en order fylls har den sin egen take profit. När alla ordrar på en sida konsumeras återställer boten rutnätet från det nya priset. <strong>Obs:</strong> grid-strategier har betydande risk i starkt trendande marknader - sätt alltid ett stop loss på kontonivå.
using cAlgo.API; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class SimpleGridBot : Robot { [Parameter("Grid Step (pips)", Group = "Grid", DefaultValue = 10)] public double GridStepPips { get; set; } [Parameter("Max Levels", Group = "Grid", DefaultValue = 5)] public int MaxLevels { get; set; } [Parameter("Volume per Level (lots)", Group = "Grid", DefaultValue = 0.01)] public double VolumePerLevel { get; set; } [Parameter("Take Profit (pips)", Group = "Grid", DefaultValue = 10)] public double TakeProfitPips { get; set; } private double _anchor; private double _step; private long _vol; protected override void OnStart() { _anchor = Symbol.Bid; _step = GridStepPips * Symbol.PipSize; _vol = Symbol.QuantityToVolumeInUnits(VolumePerLevel); PlaceGrid(); } private void PlaceGrid() { for (int i = 1; i <= MaxLevels; i++) { double buyPrice = _anchor - i * _step; double sellPrice = _anchor + i * _step; PlaceLimitOrder(TradeType.Buy, SymbolName, _vol, buyPrice, $"Grid_B{i}", null, TakeProfitPips); PlaceLimitOrder(TradeType.Sell, SymbolName, _vol, sellPrice, $"Grid_S{i}", null, TakeProfitPips); } } protected override void OnTick() { int buysRemaining = PendingOrders.FindAll("Grid_B", SymbolName).Length; int sellsRemaining = PendingOrders.FindAll("Grid_S", SymbolName).Length; // Reset grid if one side is fully consumed if (buysRemaining == 0 || sellsRemaining == 0) { foreach (var order in PendingOrders) CancelPendingOrder(order); _anchor = Symbol.Bid; PlaceGrid(); } } }
Boten adderar en ny position i samma riktning varje gång RSI bekräftar en extrem - med ett minimalt stegavstånd mellan positioner för att undvika att stapla för tätt. Kombinationen av liten TP (ta hem snabbt vid reversion) och stor SL (ge utrymme för fortsatt rörelse) är logiken bakom strategin. MaxPositions sätter ett hårt tak på exponeringen.
using cAlgo.API; using cAlgo.API.Indicators; [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class ScalingReversionBot : Robot { [Parameter("RSI Period", Group = "Signal", DefaultValue = 14)] public int RsiPeriod { get; set; } [Parameter("Oversold Level", Group = "Signal", DefaultValue = 35)] public double OversoldLevel { get; set; } [Parameter("Overbought Level", Group = "Signal", DefaultValue = 65)] public double OverboughtLevel { get; set; } [Parameter("Min Step Between Entries (pips)", Group = "Signal", DefaultValue = 15)] public double MinStepPips { get; set; } [Parameter("Max Positions", Group = "Risk", DefaultValue = 5)] public int MaxPositions { get; set; } [Parameter("Volume (lots)", Group = "Risk", DefaultValue = 0.01)] public double Volume { get; set; } [Parameter("Take Profit (pips)", Group = "Risk", DefaultValue = 10)] public double TakeProfitPips { get; set; } [Parameter("Stop Loss (pips)", Group = "Risk", DefaultValue = 150)] public double StopLossPips { get; set; } private RelativeStrengthIndex _rsi; protected override void OnStart() { _rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, RsiPeriod); } protected override void OnBar() { double rsi = _rsi.Result.LastValue; TryScale(TradeType.Buy, rsi < OversoldLevel, Symbol.Ask); TryScale(TradeType.Sell, rsi > OverboughtLevel, Symbol.Bid); } private void TryScale(TradeType direction, bool signal, double currentPrice) { if (!signal) return; var positions = Positions.FindAll("SR", SymbolName, direction); if (positions.Length >= MaxPositions) return; // Require minimum price distance from every existing entry double minStep = MinStepPips * Symbol.PipSize; foreach (var p in positions) { if (Math.Abs(currentPrice - p.EntryPrice) < minStep) return; } ExecuteMarketOrder(direction, SymbolName, Symbol.QuantityToVolumeInUnits(Volume), "SR", StopLossPips, TakeProfitPips); } }
Bygg fritt - koppla upp när du är redo. Novalgo-plattformen ger dig två saker: skarpare signaler för din egen handel, och hela infrastrukturen för att sälja din bot till andra.
Koppla din bot mot Novalgo och få tillgång till riktningssignaler och ekonomiska kalenderhändelser i realtid - utan att ändra din kärnlogik.
Kräver aktiv Novalgo-licens.
Hela infrastrukturen för att leverera, skydda och tjäna pengar på din bot - utan att du behöver bygga något av det själv.
Tillgängligt på Platform-planen. Kontakta oss för detaljer.
Redo att koppla upp? Hör av dig så berättar vi mer om hur integrationen ser ut och vad en licens kostar.