Advertisement IC Markets

How many fills do you need before ranking two brokers?

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

Here is the C# cAlgo implementation. It calculates the structural vacuums programmatically and plots heavy data points right at the sweep extremes.

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class LiquiditySweepRisk : Indicator
    {
        [Parameter("ATR & SMA Lookback", DefaultValue = 20)]
        public int Lookback { get; set; }

        [Parameter("Slippage Risk Multiplier", DefaultValue = 1.5)]
        public double SlipMultiplier { get; set; }

        [Parameter("Enable Terminal Print Alerts", DefaultValue = true)]
        public bool EnableAlerts { get; set; }

        [Output("Upper Risk Band", LineColor = "Gray", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries UpperBand { get; set; }

        [Output("Lower Risk Band", LineColor = "Gray", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries LowerBand { get; set; }

        [Output("Bull Sweep Risk", LineColor = "Red", PlotType = PlotType.Points, Thickness = 4)]
        public IndicatorDataSeries BullSweep { get; set; }

        [Output("Bear Sweep Risk", LineColor = "Red", PlotType = PlotType.Points, Thickness = 4)]
        public IndicatorDataSeries BearSweep { get; set; }

        private AverageTrueRange _atr;
        private SimpleMovingAverage _sma;
        private DateTime _lastAlertTime;

        protected override void Initialize()
        {
            _atr = Indicators.AverageTrueRange(Lookback, MovingAverageType.Simple);
            _sma = Indicators.SimpleMovingAverage(Bars.ClosePrices, Lookback);
        }

        public override void Calculate(int index)
        {
            if (index < Lookback)
                return;

            double atrValue = _atr.Result[index];
            double smaValue = _sma.Result[index];

            // Map stable execution zones
            UpperBand[index] = smaValue + (atrValue * SlipMultiplier);
            LowerBand[index] = smaValue - (atrValue * SlipMultiplier);

            double lowestLow = double.MaxValue;
            double highestHigh = double.MinValue;

            // Define the structural boundaries
            for (int i = 1; i <= Lookback; i++)
            {
                if (Bars.LowPrices[index - i] < lowestLow)
                    lowestLow = Bars.LowPrices[index - i];

                if (Bars.HighPrices[index - i] > highestHigh)
                    highestHigh = Bars.HighPrices[index - i];
            }

            // Identify structural sweeps (Liquidity vacuums)
            bool bullSweep = Bars.LowPrices[index] < lowestLow && Bars.ClosePrices[index] > Bars.OpenPrices[index];
            bool bearSweep = Bars.HighPrices[index] > highestHigh && Bars.ClosePrices[index] < Bars.OpenPrices[index];

            if (bullSweep)
                BullSweep[index] = Bars.LowPrices[index] - (atrValue * 0.5);

            if (bearSweep)
                BearSweep[index] = Bars.HighPrices[index] + (atrValue * 0.5);

            // Log high-risk environments directly to the cTrader journal
            if (IsLastBar && EnableAlerts && (bullSweep || bearSweep) && Bars.OpenTimes[index] != _lastAlertTime)
            {
                Print("Liquidity Sweep Detected on {0} - LP withdrawal imminent. High slippage risk.", SymbolName);
                _lastAlertTime = Bars.OpenTimes[index];
            }
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

If you are running automated rejection trackers in a separate cBot, you can initialize this indicator inside your bot using Indicators.GetIndicator<LiquiditySweepRisk>(). When the BullSweep or BearSweep output is not double.NaN, you know you are executing during a high-risk structural sweep.

By logging the exact millisecond latency of ExecuteMarketOrder against these specific red sweep markers, you will immediately expose whether your broker is routing your trades to a genuine dark pool or simply holding the order artificially during volatility to pass negative slippage onto you.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

To make this professional, the architecture needs three upgrades:

State Exposure: Exposing the microstructure state via public enum properties so an execution cBot can read the environment in $O(1)$ time without interrogating data arrays.

Memory Optimization: Using cTrader’s native DataSeries extension methods (Maximum, Minimum) instead of manual for loops to offload calculations to the optimized engine and avoid heap allocations during high-tick-rate volatility sweeps.

Structured Logging: Stripping out string allocations in the main Calculate method to prevent GC pauses right when you need maximum execution velocity.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

Here is the optimized C# implementation designed to feed directly into a high-frequency cBot latency tracker.

Code: Select all

using System;
using System.Diagnostics;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Indicators
{
    public enum LiquidityRegime
    {
        Stable,
        BullishSweep,
        BearishSweep
    }

    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class MicrostructureSweepRisk : Indicator
    {
        [Parameter("Structural Lookback", DefaultValue = 20, MinValue = 5)]
        public int Lookback { get; set; }

        [Parameter("Risk Multiplier (ATR)", DefaultValue = 1.5, MinValue = 0.1)]
        public double SlipMultiplier { get; set; }

        [Parameter("Enable Console Logging", DefaultValue = false)]
        public bool EnableLogging { get; set; }

        [Output("Upper Risk Boundary", LineColor = "DimGray", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries UpperBoundary { get; set; }

        [Output("Lower Risk Boundary", LineColor = "DimGray", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries LowerBoundary { get; set; }

        [Output("Sell-Side Sweep (Bullish)", LineColor = "Red", PlotType = PlotType.Points, Thickness = 5)]
        public IndicatorDataSeries BullSweepMarker { get; set; }

        [Output("Buy-Side Sweep (Bearish)", LineColor = "Red", PlotType = PlotType.Points, Thickness = 5)]
        public IndicatorDataSeries BearSweepMarker { get; set; }

        // Public state exposed for O(1) access by execution cBots
        public LiquidityRegime CurrentRegime { get; private set; }

        private AverageTrueRange _atr;
        private SimpleMovingAverage _sma;
        private DateTime _lastLogTime;

        protected override void Initialize()
        {
            // Initialize unmanaged indicator components
            _atr = Indicators.AverageTrueRange(Lookback, MovingAverageType.Simple);
            _sma = Indicators.SimpleMovingAverage(Bars.ClosePrices, Lookback);
            
            CurrentRegime = LiquidityRegime.Stable;
        }

        public override void Calculate(int index)
        {
            if (index <= Lookback) return;

            // Cache current references to avoid repeated array lookups
            double currentClose = Bars.ClosePrices[index];
            double currentOpen = Bars.OpenPrices[index];
            double currentLow = Bars.LowPrices[index];
            double currentHigh = Bars.HighPrices[index];
            
            double atrVal = _atr.Result[index];
            double smaVal = _sma.Result[index];

            // Define dynamic risk boundaries
            UpperBoundary[index] = smaVal + (atrVal * SlipMultiplier);
            LowerBoundary[index] = smaVal - (atrVal * SlipMultiplier);

            // Utilize native cAlgo DataSeries extensions (avoids manual loops & allocations)
            double structuralLow = Bars.LowPrices.Minimum(Lookback, index - 1);
            double structuralHigh = Bars.HighPrices.Maximum(Lookback, index - 1);

            // Boolean structural evaluation
            bool isBullSweep = currentLow < structuralLow && currentClose > currentOpen;
            bool isBearSweep = currentHigh > structuralHigh && currentClose < currentOpen;

            // State management and rendering
            if (isBullSweep)
            {
                CurrentRegime = LiquidityRegime.BullishSweep;
                BullSweepMarker[index] = currentLow - (atrVal * 0.4);
                LogSweep(index, "Sell-side liquidity vacuum");
            }
            else if (isBearSweep)
            {
                CurrentRegime = LiquidityRegime.BearishSweep;
                BearSweepMarker[index] = currentHigh + (atrVal * 0.4);
                LogSweep(index, "Buy-side liquidity vacuum");
            }
            else
            {
                CurrentRegime = LiquidityRegime.Stable;
                BullSweepMarker[index] = double.NaN;
                BearSweepMarker[index] = double.NaN;
            }
        }

        /// <summary>
        /// Structurally isolates string allocations to prevent GC spikes on stable ticks.
        /// </summary>
        private void LogSweep(int index, string sweepType)
        {
            if (!EnableLogging || !IsLastBar || Bars.OpenTimes[index] == _lastLogTime) return;

            Print($"[Microstructure Warning] {SymbolName} | {sweepType} detected. High probability of asymmetric slippage.");
            _lastLogTime = Bars.OpenTimes[index];
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

Implementing the Execution Diagnostic Bot

Because the indicator now exposes a LiquidityRegime enum, your cBot does not need to waste CPU cycles scanning the indicator's data arrays. You instantiate the indicator inside the bot and query the regime directly before routing the order.

By wrapping your execution command in a Stopwatch, you can track the exact millisecond delay between the terminal requesting a fill on a 15-minute sweep and the broker’s server returning the confirmation.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

C# Code:

Code: Select all

// Inside your Execution cBot:
private MicrostructureSweepRisk _sweepRisk;
private Stopwatch _latencyTracker = new Stopwatch();

protected override void OnStart()
{
    _sweepRisk = Indicators.GetIndicator<MicrostructureSweepRisk>(20, 1.5, false);
}

private void ExecuteDiagnosticTrade(TradeType tradeType, double volume)
{
    if (_sweepRisk.CurrentRegime == LiquidityRegime.Stable) return; // Only test during stress events

    _latencyTracker.Restart();
    var result = ExecuteMarketOrder(tradeType, SymbolName, volume, "Execution_Diagnostic");
    _latencyTracker.Stop();

    double latencyMs = _latencyTracker.Elapsed.TotalMilliseconds;
    double slippageTicks = Math.Abs(result.Position.EntryPrice - Symbol.Ask) / Symbol.TickSize;

    Print($"[Execution Log] {tradeType} | Regime: {_sweepRisk.CurrentRegime} | Latency: {latencyMs}ms | Slippage: {slippageTicks} ticks");
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: How many fills do you need before ranking two brokers?

Post by PTScalper »

This setup completely removes the "feel" aspect from broker evaluation. When a broker claims superior aggregation, this combination of C# scripts will definitively prove whether their B-book plugin is intentionally stalling fills during structural liquidity sweeps to force negative slippage.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

Re: How many fills do you need before ranking two brokers?

Post by LondonScalper »

PTScalper wrote:I look for at least 200-300 live market orders executed specifically during high-volume windows.
I can live with 200 to 300 if they are genuinely your hours, not a quiet overnight grind padded to look large. The comparison still has to be the same order type, size band and session on both accounts. A fast EURUSD book and a poor gold book can sit in the same shop, so testing them apart is right. A tidy euro sample does not licence a metals ranking. I still want the ranking from the fill log: median spread, signed slip, rejects, and the time of day.

A chart script that paints risk zones from volatility is a hypothesis about when the book might thin. It is not a broker sample. Checking those markers against actual rejects is the useful half. Posting several versions of the same marker is not. I re-run after a high-impact week because calm tape flatters everyone. If the sample is still thin, I say so. Under-claiming has saved me more than any brochure.
PropScalpDesk
Posts: 273
Joined: Sat Sep 19, 2026 7:50 pm

Re: How many fills do you need before ranking two brokers?

Post by PropScalpDesk »

PTScalper wrote:MQL5: Liquidity Sweep & Execution Risk Place this in MQL5\Indicators. MQL5 handles arrays differently, so this implementation forces ArraySetAsSeries and uses CopyBuffer to pull indicator handles smoothly without memory leaks. Code: Select all //+------------------------------------------------------------------+ //| Liquidity_Sweep_Risk_MT5.
I want a real sample of fills before I rank brokers — not a morning of screenshots. Reject rate and slip into London open matter more than the marketing spread.

For prop execution, a “cheap” book that rejects at the open is expensive.

How many fills do you require per session hour before you trust a comparison?

I also log refused tickets so flat time counts as work — otherwise the desk invents activity.

If the idea needs a story longer than one line, it waits for another window.

Topic note from my sheet for t=12529: keep risk unchanged until the sample says otherwise.
LondonNewsTrader
Posts: 79
Joined: Mon Sep 21, 2026 9:30 am

Re: How many fills do you need before ranking two brokers?

Post by LondonNewsTrader »

PTScalper wrote:MQL5: Liquidity Sweep & Execution Risk Place this in MQL5\Indicators. MQL5 handles arrays differently, so this implementation forces ArraySetAsSeries and uses CopyBuffer to pull indicator handles smoothly without memory leaks. Code: Select all //+------------------------------------------------------------------+ //| Liquidity_Sweep_Risk_MT5.
The bands are a reasonable way to flag when price is stretched, but for the question in this thread I'm not sure they help directly. ATR and SMA are computed from each broker's own price feed, and two ECN feeds on EURUSD will produce almost identical bands. The indicator can't show that broker A slipped you half a pip more than broker B at 08:00; only the fill records can.

Where it could earn its place is as a tagging tool. If each fill is stamped with whether price was outside the 1.5 × ATR band at the time, the comparison splits into normal and stretched conditions. That matters because a broker can look fine on calm fills and fall apart when price is extended, which is exactly when a scalper needs it. A few hundred fills might only contain thirty stretched ones, so that bucket takes longer to mean anything, but it's the one I'd care about most.

On the code: the input is called InpSlipMultiplier, yet it scales volatility, not slippage. Renaming it would avoid confusion later when someone assumes it models execution cost.

I'd also add a flag for fills within a few minutes of scheduled releases, since those are driven by the calendar rather than the band.
Post Reply