Utvecklarresurser

Bygg din egna
cTrader-bot

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.

C# / .NET cTrader API Strategiexempel Ingen erfarenhet krävs
Kom igång

Vad du behöver

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.

1

cTrader-konto

Ö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.

2

cTrader Desktop

Ladda ner cTrader-desktopappen. Den inbyggda cTrader Automate IDE:n låter dig skriva, kompilera och backtesta bots utan några andra verktyg.

3

Grundläggande C#

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.

4

En handelsidé

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.

Grundläggande koncept

Hur en cBot fungerar

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.

📊

Bars och Ticks

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)
📈

Indikatorserie

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(...)
💼

Positioner

Ö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", ...)
📋

Väntande ordrar

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, ...)
⚙️

Parametrar

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)]
🔒

Symbolinformation

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");
    }
}
Strategiexempel

5 strategier, redo att köra

Varje exempel är komplett, kompilerbar C#-kod. Klistra in den i cTrader Automate, tryck kompilera och kör den på ett demokonto.

📉

Moving Average Crossover

En av de mest klassiska trendföljande strategierna. Köper när den snabba EMA korsar över den långsamma EMA, säljer när den korsar under. Enkel, transparent och ett utmärkt startpunkt.

Trendföljande OnBar Nybörjare

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.

MACrossoverBot.cs C#
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 Mean Reversion

Handlar mot extrema RSI-värden och satsar på att priset återvänder mot medelvärdet. Köper översålda förhållanden, säljer överköpta. Fungerar bäst i sidorörliga marknader med låg volatilitet.

Medelvärdesåtergång OnBar Nybörjare

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.

RSIMeanReversionBot.cs C#
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);
        }
    }
}
📐

Bollinger Bands Reversal

Går in när priset berör det övre eller nedre Bollinger-bandet och satsar på en återgång till glidande medelvärdet. Kombinerar volatilitetsmedvetenhet med medelvärdesåtergångs-tajming.

Medelvärdesåtergång Volatilitetsmedveten OnBar Medel

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.

BollingerBandsBot.cs C#
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);
        }
    }
}
💥

Donchian Channel Breakout

Handlar utbrott ovanför N-ljusets högsta eller under N-ljusets lägsta - samma princip som bakom klassiska trendföljande system som Turtle Trading-strategin.

Trendföljande Utbrott OnBar Medel

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.

BreakoutBot.cs C#
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);
    }
}
🔲

Enkel Grid-bot

Placerar ett symmetriskt rutnät av limitordrar ovanför och under aktuellt pris. Tjänar på oscillerande prisrörelser utan att förutsäga riktning. Grunden för mer komplexa grid-strategier.

Grid OnTick Avancerad

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å.

SimpleGridBot.cs C#
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();
        }
    }
}
📥

Scaling Reversion

Skalas in i samma riktning varje gång signalen upprepas. Liten TP fångar snabba reversioner; stor SL absorberar fortsatt rörelse mot positionen.

Medelvärdesåtergång OnBar Avancerad

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.

ScalingReversionBot.cs C#
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);
    }
}

Redo att ta din bot till nästa nivå?

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.

Steg 1 - Förbättra din trading
AI-signaler & Nyhetsfilter

Koppla din bot mot Novalgo och få tillgång till riktningssignaler och ekonomiska kalenderhändelser i realtid - utan att ändra din kärnlogik.

  • 🤖
    AI-riktningsbias Lång, Kort eller Neutral - levereras via WebSocket. Använd som ett top-down-filter för att bara ta trades i bias-riktningen.
  • 📰
    Nyhetsfilter Pausa automatiskt nya positioner inför högrisk-events. Plattformen prenumererar på ekonomisk kalenderfeed och pushar blocksignaler i realtid.
  • Enkel integration En WebSocket-anslutning och ett API-nyckel. Signalerna är valfria - boten fungerar utan dem, men presterar bättre med.

Kräver aktiv Novalgo-licens.

Redo att koppla upp? Hör av dig så berättar vi mer om hur integrationen ser ut och vad en licens kostar.