Page 1 of 1

[CODE SHARE Pt. 3] Bulletproofing execution: Handling Async Server Errors

Posted: Tue Aug 11, 2026 10:12 pm
by PTScalper
Hi scalpers,

Let's dive into execution safety.

Using ModifyPositionAsync is fantastic for performance because it’s a "fire-and-forget" command that doesn't freeze your OnTick thread. But that’s also its biggest danger: if you just fire and forget, you have no idea if the broker actually accepted the modification.

During high-impact news, spreads widen rapidly and price gaps occur. Your cBot might calculate a perfectly valid Stop Loss locally, but by the time the request hits the broker's server 50 milliseconds later, the price has gapped, making your Stop Loss invalid (usually triggering an InvalidStopLoss error).

To catch this, we use a Callback via the Action<TradeResult> parameter that cTrader provides in its async methods.

The Code Implementation
You don't need to rewrite the whole bot. You just need to update the lines where we call ModifyPositionAsync and add a lambda expression to handle the server's response.

Here is how you update the modification logic inside your ManageTrailingStop and CheckBreakEven methods:

Code: Select all

// Inside your Buy/Sell logic where you calculate newStopLoss...

if (position.StopLoss == null || newStopLoss >= position.StopLoss + (TrailStep * Symbol.PipSize))
{
    // We add a lambda callback (result => { ... }) to read the broker's response
    ModifyPositionAsync(position, newStopLoss, position.TakeProfit, result =>
    {
        if (result.IsSuccessful)
        {
            // Optional: Log success for your own tracking
            Print("✅ SUCCESS: Position {0} SL moved to {1}", position.Id, newStopLoss);
        }
        else
        {
            // The broker rejected the request. We catch the exact error code.
            Print("🚨 ERROR: Failed to modify SL for Position {0}. Reason: {1}", position.Id, result.Error);
            
            // Example of how to handle specific critical errors
            if (result.Error == ErrorCode.InvalidStopLoss)
            {
                Print("⚠️ The requested SL of {0} is too close to current price or on the wrong side.", newStopLoss);
            }
            else if (result.Error == ErrorCode.MarketClosed)
            {
                Print("⚠️ Market is closed, modification rejected.");
            }
            
            // Advanced: You could trigger an email or push notification to your phone here
            // Notifications.SendEmail("you@email.com", "you@email.com", "cBot Error", result.Error.ToString());
        }
    });
}
Expert Notes on TradeResult
When you pass that callback function into the async request, cTrader hands you back a TradeResult object once the server replies. Here is why this is so powerful:

result.IsSuccessful: This boolean is your first line of defense. If it’s false, something went wrong on the broker's end.

result.Error: This returns an ErrorCode enum. In automated trading, not all errors are created equal. An InvalidStopLoss usually just means the market moved faster than your code, and the bot will naturally try again on the next tick. However, an error like Disconnected or NoMoney requires immediate human intervention.

No Thread Blocking: Because the callback is handled asynchronously, checking for these errors and printing them to the log does not slow down your OnTick method. The main thread keeps processing live price data.

Push Notifications: The else block of an async failure is the perfect place to drop in cTrader's native Notifications.SendPushNotification() method, so your phone buzzes instantly if the broker starts rejecting your stop-loss updates during a volatile session.

Take a care, bye bye, have a great trades.