I see a lot of questions popping up around trailing stops in cTrader. While cTrader has a built-in server-side trailing stop (which you can trigger natively via ModifyPosition), it’s pretty basic. It starts trailing immediately based on the distance.
If you want real control—like only activating the trail after reaching a certain profit threshold—you have to code it yourself inside the OnTick() method.
I’ve put together a clean, optimized boilerplate cBot template for an advanced trailing stop. Feel free to copy this into your Automate workspace and tweak it.
The Strategy Logic:
This code doesn't just blindly trail price. It waits until your trade is safely in profit (the ActivationThreshold), and then it starts trailing behind the current price by your defined TrailingDistance.
Code: Select all
using System;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class AdvancedTrailingStop : Robot
{
// Parameters exposed to the cTrader UI
[Parameter("Activation Threshold (Pips)", Group = "Trailing Stop", DefaultValue = 15)]
public double ActivationThreshold { get; set; }
[Parameter("Trailing Distance (Pips)", Group = "Trailing Stop", DefaultValue = 10)]
public double TrailingDistance { get; set; }
[Parameter("Bot Label", Group = "Trade Management", DefaultValue = "MyStrategy")]
public string BotLabel { get; set; }
protected override void OnTick()
{
// BEST PRACTICE: Only iterate through positions managed by THIS specific bot on THIS symbol
foreach (var position in Positions.FindAll(BotLabel, SymbolName))
{
ManageTrailingStop(position);
}
}
private void ManageTrailingStop(Position position)
{
double newStopLoss;
if (position.TradeType == TradeType.Buy)
{
// Calculate current floating profit in pips
double profitInPips = (Symbol.Bid - position.EntryPrice) / Symbol.PipSize;
if (profitInPips >= ActivationThreshold)
{
// Calculate where the new SL should be
newStopLoss = Symbol.Bid - (TrailingDistance * Symbol.PipSize);
// CRITICAL: Ensure we only move the SL UP for a Buy trade, never backwards
if (position.StopLoss == null || newStopLoss > position.StopLoss)
{
// Use Async to avoid blocking the main OnTick thread during fast markets
ModifyPositionAsync(position, newStopLoss, position.TakeProfit);
}
}
}
else if (position.TradeType == TradeType.Sell)
{
// Calculate current floating profit in pips for a short
double profitInPips = (position.EntryPrice - Symbol.Ask) / Symbol.PipSize;
if (profitInPips >= ActivationThreshold)
{
newStopLoss = Symbol.Ask + (TrailingDistance * Symbol.PipSize);
// CRITICAL: Ensure we only move the SL DOWN for a Sell trade
if (position.StopLoss == null || newStopLoss < position.StopLoss)
{
ModifyPositionAsync(position, newStopLoss, position.TakeProfit);
}
}
}
}
}
}If you are new to the cTrader API, here are a few reasons why this code is structured the way it is:
Positions.FindAll() Filter: You should never just use foreach (var position in Positions). If you are running multiple bots or manual trades, a generic loop will grab everything and apply this trailing stop to trades it shouldn't touch. Passing your bot's specific label prevents cross-contamination.
Bid vs. Ask Math: Notice how we use Symbol.Bid for calculating Buy profit and Symbol.Ask for Sell profit. Because you close a Buy at the Bid price and close a Sell at the Ask price, you must calculate your floating pips using the correct side of the spread.
The Directional Check (newStopLoss > position.StopLoss): A trailing stop should only ever lock in more profit. Without this check, every time price ticks against you, your stop loss would widen. This simple if statement ensures the SL operates like a one-way ratchet.
ModifyPositionAsync: Notice the Async suffix. Modifying a position requires a server round-trip. If you use the standard synchronous ModifyPosition() inside OnTick(), a volatile market could freeze your bot while it waits for server confirmation. Async fires the request to the server and immediately continues executing your code.
Hope this helps some of the newer devs out there! Let me know if you want to see how to add a "Step" function to this so the server isn't spammed with modification requests on every micro-pip movement.
Happy coding, and may the spread be with you.