1.Open cTrader Automate:
Switch to the Automate tab in the left-hand navigation menu of cTrader.
2.Create a new cBot: Right-click on the cBots folder and select New cBot. Name it EmergencyFlatten.
3.Paste and Build: Replace the default template code with the C# code above. Press Ctrl + B (or click the Build icon) to compile it.
4.Execute the Flat: Add it to a chart to keep it ready.
To use it, add the cBot to any chart. When an emergency happens, simply click the Play (Start) button on the cBot instance. It will run instantly, close everything, and then turn itself back off.
Broker apps: usable for emergency flat only?
Re: Broker apps: usable for emergency flat only?
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Broker apps: usable for emergency flat only?
To elevate this to an enterprise-grade execution tool, we need to account for real-world market microstructure problems. During high-volatility events—exactly when you need an emergency flatten—broker APIs frequently reject requests, connections drop, or liquidity gaps cause partial fills.
A professional "kill switch" requires retry logic, execution telemetry, and defensive array handling to prevent collection-modified exceptions as trades close out.
Here is the refactored, robust C# implementation for cTrader:
A professional "kill switch" requires retry logic, execution telemetry, and defensive array handling to prevent collection-modified exceptions as trades close out.
Here is the refactored, robust C# implementation for cTrader:
Code: Select all
using System;
using System.Linq;
using System.Diagnostics;
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ProEmergencyFlatten : Robot
{
[Parameter("Scope: All Symbols", DefaultValue = true, Group = "Targeting")]
public bool CloseAllSymbols { get; set; }
[Parameter("Max Retries", DefaultValue = 3, MinValue = 1, Group = "Execution")]
public int MaxRetries { get; set; }
[Parameter("Log Level", DefaultValue = LogLevel.Detailed, Group = "Diagnostics")]
public LogLevel LoggingLevel { get; set; }
public enum LogLevel { Standard, Detailed }
protected override void OnStart()
{
Print("[Emergency Flatten] Initiating protocol...");
var stopwatch = Stopwatch.StartNew();
// Execute closures using a generalized retry wrapper
int positionsClosed = ExecuteWithRetry(CloseTargetPositions, "Positions");
int ordersCancelled = ExecuteWithRetry(CancelTargetOrders, "Pending Orders");
stopwatch.Stop();
Print($"[Emergency Flatten] Execution completed in {stopwatch.ElapsedMilliseconds}ms.");
Print($"[Emergency Flatten] Summary: {positionsClosed} Positions Closed | {ordersCancelled} Orders Cancelled.");
// Terminate instantly after execution
Stop();
}
/// <summary>
/// Wraps execution logic in a retry loop to handle broker rejections during high volatility.
/// </summary>
private int ExecuteWithRetry(Func<int> executionFunc, string operationName)
{
int successCount = 0;
for (int attempt = 1; attempt <= MaxRetries; attempt++)
{
successCount += executionFunc();
// Re-evaluate remaining targets dynamically
int remaining = operationName == "Positions" ? GetTargetPositions().Length : GetTargetOrders().Length;
if (remaining == 0)
{
if (attempt > 1 && LoggingLevel == LogLevel.Detailed)
Print($"[{operationName}] Successfully cleared all targets on attempt {attempt}.");
break;
}
Print($"[{operationName}] Attempt {attempt} finished with {remaining} remaining targets. Retrying...");
// 200ms backoff to allow the broker's order queue to process state
System.Threading.Thread.Sleep(200);
}
return successCount;
}
private int CloseTargetPositions()
{
var targets = GetTargetPositions();
int closed = 0;
foreach (var position in targets)
{
var result = ClosePosition(position);
if (result.IsSuccessful)
{
closed++;
if (LoggingLevel == LogLevel.Detailed)
Print($"[Success] Closed Position {position.Id} ({position.SymbolName})");
}
else
{
Print($"[Error] Failed to close Position {position.Id}: {result.Error}");
}
}
return closed;
}
private int CancelTargetOrders()
{
var targets = GetTargetOrders();
int cancelled = 0;
foreach (var order in targets)
{
var result = CancelPendingOrder(order);
if (result.IsSuccessful)
{
cancelled++;
if (LoggingLevel == LogLevel.Detailed)
Print($"[Success] Cancelled Order {order.Id} ({order.SymbolName})");
}
else
{
Print($"[Error] Failed to cancel Order {order.Id}: {result.Error}");
}
}
return cancelled;
}
// Materializing queries to arrays prevents InvalidOperationException
// if the collection changes while we are iterating over it.
private Position[] GetTargetPositions() =>
CloseAllSymbols ? Positions.ToArray() : Positions.Where(p => p.SymbolName == SymbolName).ToArray();
private PendingOrder[] GetTargetOrders() =>
CloseAllSymbols ? PendingOrders.ToArray() : PendingOrders.Where(o => o.SymbolName == SymbolName).ToArray();
}
}Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Re: Broker apps: usable for emergency flat only?
Key Engineering Upgrades
Idempotent Retry Wrapper: High-volatility moments often trigger "Server Busy" or "Off Quotes" errors. The ExecuteWithRetry method accepts a delegate (Func<int>), wrapping the closure logic in a loop with a hard limit and a 200ms thread block to respect API limits before hammering the broker again.
State Freezing: Standard LINQ queries on live collections (Positions and PendingOrders) will throw an exception if a position closes mid-iteration. GetTargetPositions() materializes the query to an array (.ToArray()) first, ensuring memory safety.
Execution Telemetry: Implements Stopwatch to log exact execution latency. This gives you tangible data on how fast your broker is actually processing API requests during chaotic market conditions.
Defensive Error Handling: Surfaces exact error codes from the cTrader API rather than silently failing, controlled by a customizable logging enum to keep the terminal clean unless you need granular debugging.
Idempotent Retry Wrapper: High-volatility moments often trigger "Server Busy" or "Off Quotes" errors. The ExecuteWithRetry method accepts a delegate (Func<int>), wrapping the closure logic in a loop with a hard limit and a 200ms thread block to respect API limits before hammering the broker again.
State Freezing: Standard LINQ queries on live collections (Positions and PendingOrders) will throw an exception if a position closes mid-iteration. GetTargetPositions() materializes the query to an array (.ToArray()) first, ensuring memory safety.
Execution Telemetry: Implements Stopwatch to log exact execution latency. This gives you tangible data on how fast your broker is actually processing API requests during chaotic market conditions.
Defensive Error Handling: Surfaces exact error codes from the cTrader API rather than silently failing, controlled by a customizable logging enum to keep the terminal clean unless you need granular debugging.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.