The Analytical Edge with cAlgo
cTrader generally routes through superior liquidity hubs compared to vanilla MT4 servers, meaning your limit orders and take-profits should logically experience a higher frequency of positive slippage.
When you parse this generated CSV for your Q4 scorecard update, run a quick pivot table comparing Latency_ms against Slippage_Pips. If you detect a structural correlation—for example, latency spiking from 30ms to 400ms exclusively when adverse slippage exceeds 0.5 pips—it provides empirical proof that the liquidity provider is employing a "last look" latency plugin to front-run your M1 sweeps.
Broker scorecard quarterly update: spreads, rejects, and uptime
Re: Broker scorecard quarterly update: spreads, rejects, and uptime
To elevate this to an institutional standard, we must address a critical architectural flaw present in most retail execution trackers: I/O thread blocking.
Writing synchronously to a disk (File.AppendAllText) immediately after an order execution pollutes the hardware timer and locks the primary trading thread. In an M1 scalping environment where microstructure edges are measured in milliseconds, executing I/O operations on the hot path artificially inflates latency metrics and delays subsequent algorithmic logic.
A production-grade solution decouples the execution event from the logging mechanism. We achieve this by pushing execution telemetry into a thread-safe ConcurrentQueue on the main thread, and asynchronously flushing it to disk via an independent timer loop.
Writing synchronously to a disk (File.AppendAllText) immediately after an order execution pollutes the hardware timer and locks the primary trading thread. In an M1 scalping environment where microstructure edges are measured in milliseconds, executing I/O operations on the hot path artificially inflates latency metrics and delays subsequent algorithmic logic.
A production-grade solution decouples the execution event from the logging mechanism. We achieve this by pushing execution telemetry into a thread-safe ConcurrentQueue on the main thread, and asynchronously flushing it to disk via an independent timer loop.
Re: Broker scorecard quarterly update: spreads, rejects, and uptime
Enterprise Microstructure Auditor (C# cAlgo)
This architecture ensures zero latency drag on the execution thread, utilizes high-resolution hardware timers, and formats output for immediate parsing into a quantitative scorecard.
This architecture ensures zero latency drag on the execution thread, utilizes high-resolution hardware timers, and formats output for immediate parsing into a quantitative scorecard.
Code: Select all
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Collections.Concurrent;
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FileSystem)]
public class InstitutionalExecutionAuditor : Robot
{
[Parameter("Audit Log Filename", DefaultValue = "cTrader_Microstructure_Audit.csv")]
public string LogFileName { get; set; }
private string _filePath;
private readonly ConcurrentQueue<string> _telemetryQueue = new ConcurrentQueue<string>();
// Timer for high-resolution profiling
private readonly Stopwatch _executionTimer = new Stopwatch();
protected override void OnStart()
{
string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
_filePath = Path.Combine(docPath, LogFileName);
InitializeScorecardEngine();
// Offload disk I/O to a background timer (every 2 seconds)
Timer.Start(2);
Print($"[ENGINE] Microstructure Auditor active. I/O decoupled.");
}
private void InitializeScorecardEngine()
{
if (!File.Exists(_filePath))
{
string header = "Timestamp_UTC,Symbol,Type,Latency_ms,Intended_Px,Filled_Px,Slip_Pips,Spread_Pips,Order_State\n";
File.WriteAllText(_filePath, header);
}
}
// =========================================================================
// HOT PATH: SYNCHRONOUS EXECUTION WRAPPER
// =========================================================================
public void ExecuteAuditedOrder(TradeType direction, double volume)
{
// 1. Capture snapshot of liquidity strictly prior to FIX dispatch
double intendedPx = direction == TradeType.Buy ? Symbol.Ask : Symbol.Bid;
double spreadPips = (Symbol.Ask - Symbol.Bid) / Symbol.PipSize;
// 2. Hardware-level latency profiling
_executionTimer.Restart();
// 3. Dispatch to Liquidity Provider
TradeResult result = ExecuteMarketOrder(direction, SymbolName, volume, "Inst_Audit");
_executionTimer.Stop();
double latencyMs = _executionTimer.Elapsed.TotalMilliseconds;
// 4. Calculate Execution Drag
if (result.IsSuccessful)
{
double filledPx = result.Position.EntryPrice;
double slipPips = direction == TradeType.Buy
? (filledPx - intendedPx) / Symbol.PipSize
: (intendedPx - filledPx) / Symbol.PipSize;
QueueTelemetry(direction, latencyMs, intendedPx, filledPx, slipPips, spreadPips, "FILLED");
}
else
{
QueueTelemetry(direction, latencyMs, intendedPx, 0, 0, spreadPips, $"REJECT_{result.Error}");
}
}
// =========================================================================
// TELEMETRY QUEUEING (NON-BLOCKING)
// =========================================================================
private void QueueTelemetry(TradeType dir, double lat, double req, double fill, double slip, double spread, string state)
{
string record = $"{Server.Time:yyyy-MM-dd HH:mm:ss.fff},{SymbolName},{dir},{lat:F2},{req},{fill},{slip:F2},{spread:F2},{state}";
_telemetryQueue.Enqueue(record);
}
// =========================================================================
// BACKGROUND I/O FLUSH
// =========================================================================
protected override void OnTimer()
{
if (_telemetryQueue.IsEmpty) return;
var sb = new StringBuilder();
while (_telemetryQueue.TryDequeue(out string record))
{
sb.AppendLine(record);
}
try
{
File.AppendAllText(_filePath, sb.ToString());
}
catch (Exception ex)
{
Print($"[I/O FAULT] Failed to flush telemetry: {ex.Message}");
}
}
// =========================================================================
// LIGHTWEIGHT TERMINAL UI
// =========================================================================
protected override void OnTick()
{
double spread = (Symbol.Ask - Symbol.Bid) / Symbol.PipSize;
Chart.DrawStaticText("micro_dash",
$"INSTITUTIONAL AUDITOR\nSpread: {spread:F1} pips\nQueue Depth: {_telemetryQueue.Count}",
VerticalAlignment.Top, HorizontalAlignment.Right, Color.DimGray);
}
}
}Re: Broker scorecard quarterly update: spreads, rejects, and uptime
Analyzing the Microstructure Data
Once this runs through a quarter of high-volume overlaps, you bypass traditional platform analytics and construct a rigid scatter plot: Execution Latency (X-axis) vs. Adverse Slippage (Y-axis).
The "Last Look" Signature: If you observe a cluster of rejected orders or heavy negative slippage exclusively when Latency_ms exceeds ~150-200ms, the broker's liquidity provider is utilizing a "last look" holding window. They are pausing the execution to verify if the M1 price action moves against them before confirming your fill.
The True DMA Profile: A genuine STP/ECN environment will exhibit sub-50ms execution times regardless of market volatility, and the slippage distribution will resemble a standard bell curve (equal occurrences of positive and negative slippage).
Once this runs through a quarter of high-volume overlaps, you bypass traditional platform analytics and construct a rigid scatter plot: Execution Latency (X-axis) vs. Adverse Slippage (Y-axis).
The "Last Look" Signature: If you observe a cluster of rejected orders or heavy negative slippage exclusively when Latency_ms exceeds ~150-200ms, the broker's liquidity provider is utilizing a "last look" holding window. They are pausing the execution to verify if the M1 price action moves against them before confirming your fill.
The True DMA Profile: A genuine STP/ECN environment will exhibit sub-50ms execution times regardless of market volatility, and the slippage distribution will resemble a standard bell curve (equal occurrences of positive and negative slippage).
-
LondonScalper
- Posts: 770
- Joined: Sat Sep 05, 2026 7:54 am
Re: Broker scorecard quarterly update: spreads, rejects, and uptime
That’s exactly why raw median spread loses the scorecard. Missed or skewed fills on the overlap cost more EV than a few tenths of advertised spread.FTtrader wrote:The broker-choice breaker was asymmetric slippage during the London/NY overlap: one broker had a 0.2-pip median spread but 0.8-pip p95 slippage and 8% rejects, while a 0.5-pip DMA broker had about 0.1-pip p95 slippage and positive slippage.
My quarterly sheet weights p95 market-order slippage and reject/requote rate ahead of median spread. Fill feel and outage minutes sit next. A tight top-of-book that rejects 8% of tickets is a marketing quote, not an execution venue.
Desk process: I sample the same 20–30 overlap tickets per broker each quarter, side-aware, and tag positive versus adverse slip separately. Asymmetry shows up fast once you stop averaging the good fills with the bad ones.
Rule: all-in cost = p95 slip + rejects; median spread is a footnote. How many overlap samples do you need before you kill a broker on the scorecard — one bad week, or a full quarter of skewed p95?
-
LondonNewsTrader
- Posts: 80
- Joined: Mon Sep 21, 2026 9:30 am
Re: Broker scorecard quarterly update: spreads, rejects, and uptime
This is how broker talk should sound — logs, not slogans.FTtrader wrote:I stopped arguing about brokers from memory. Once a quarter I update a simple scorecard from my logs. Columns that matter for scalping • Median spread by pair + session (London / overlap) • p95 slippage on market orders • Reject / requote count
I keep the same quarterly habit, with one extra cut: scorecard rows split calm London hours versus the first five minutes after Tier-1 US data. A house that looks pristine on a quiet Tuesday can still be unusable on CPI. p95 slip versus median spread is the right comparison; if slip dominates, your "tight spread" marketing is theatre.
Rejects and time-to-fill into red folders decide whether I even leave working orders up. Argument-from-memory is how people stay loyal to a venue that has been taxing them for months.
Are you weighting London and overlap separately for each pair, or rolling one session average that hides the Friday cross problem?
-
PropScalpDesk
- Posts: 364
- Joined: Sat Sep 19, 2026 7:50 pm
Re: Broker scorecard quarterly update: spreads, rejects, and uptime
Broker scorecards are quarterly work here: spread, reject, slip into London and into red folders. Marketing averages are not a scorecard.FTtrader wrote:Moving this execution tracker into cTrader provides a massive architectural advantage. Because cAlgo runs natively on the .NET framework, you can bypass proprietary platform timers entirely and utilize OS-level hardware counters for high-resolution latency tracking. By leveraging System.Diagnostics.
Prop execution quality is part of edge.
What three numbers make your shortlist?
I also log refused tickets so flat time counts as work — otherwise the desk invents activity.
I would rather log a refused ticket than invent activity for the journal.
I write the walk-away before London so it is not negotiated mid-tape.
If the idea needs a story longer than one line, it waits for another window.
Topic note from my sheet for t=12325: keep risk unchanged until the sample says otherwise.