Advertisement IC Markets

What a clean abort looks like mid-trade when the tape goes thin

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
LondonScalper
Posts: 701
Joined: Sat Sep 05, 2026 7:54 am

What a clean abort looks like mid-trade when the tape goes thin

Post by LondonScalper »

Process for killing a live scalp when conditions change — not an entry method.

Most of my bad days weren’t bad entries. They were good-enough entries I refused to abandon when the tape went thin, the book stepped back, or the move stalled into lunch chop.

Abort cues I honour
• Spread jumps beyond my pre-set max for that pair/session
• Quote freezes or updates in lumps instead of a steady tape
• My level is still “valid” on the chart but order flow feels empty (subjective — so I pair it with spread/time rules)
• Time stop hit: if the idea hasn’t paid or failed within N minutes, I’m wrong about urgency

Clean abort means
Flatten at market (or working limit if the book is orderly), tag abort_thin_tape, and do not re-enter the same idea for a cooling period. The cooling period is the hard part. Aborting then immediately reloading is just denial with extra steps.

I practice the abort on small size when the session is quiet so the button sequence isn’t novel under stress. Chart validity without tradable liquidity is not a setup — it’s a screenshot for later.

How do you distinguish “hold through noise” from “get out, the market left”? I need both rules written down or I always pick hold.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3027
Joined: Mon Jul 20, 2026 1:28 pm

Re: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

LondonScalper wrote: Sat Sep 12, 2026 8:52 pm Process for killing a live scalp when conditions change — not an entry method.

Most of my bad days weren’t bad entries. They were good-enough entries I refused to abandon when the tape went thin, the book stepped back, or the move stalled into lunch chop.

Abort cues I honour
• Spread jumps beyond my pre-set max for that pair/session
• Quote freezes or updates in lumps instead of a steady tape
• My level is still “valid” on the chart but order flow feels empty (subjective — so I pair it with spread/time rules)
• Time stop hit: if the idea hasn’t paid or failed within N minutes, I’m wrong about urgency

Clean abort means
Flatten at market (or working limit if the book is orderly), tag abort_thin_tape, and do not re-enter the same idea for a cooling period. The cooling period is the hard part. Aborting then immediately reloading is just denial with extra steps.

I practice the abort on small size when the session is quiet so the button sequence isn’t novel under stress. Chart validity without tradable liquidity is not a setup — it’s a screenshot for later.

How do you distinguish “hold through noise” from “get out, the market left”? I need both rules written down or I always pick hold.
Hi LondonScalper,

That line right there should be framed above every short-term trader's desk. You’ve already identified the hardest part of scalping: recognizing when the trade premise has evaporated, even if the price hasn't explicitly hit your hard stop yet.

To answer your core question: How do you distinguish “hold through noise” from “get out, the market left”?

The difference lies entirely in velocity and participation.

Holding through noise: The tape is still active. Orders are crossing, volume is consistent with the session average, and price is just digesting a recent thrust. It’s two-way action, but there's liquidity. The market is breathing.

The market left: The tape goes lumpy. You see gaps between prints. Volume dries up entirely, and price drifts rather than drives. If you entered for a momentum scalp and the momentum vanishes, your premise is dead. You aren't holding through noise; you're holding a bag of hope.

If your entry thesis was "I expect immediate continuation," then a stall is an invalidation. "Chart validity" means nothing on a scalp if the liquidity vacuum isn't pushing price in your direction.
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

Writing Your Rules into Pine Script

Since you need the rules written down to avoid holding, I built your abort logic and cooling period into a Pine Script strategy.

Note on limitations: Pine Script doesn't natively expose live Level 2 spread data or tick-by-tick "lumpiness" for historical backtesting. To solve this, the script uses a Volume Drop Multiplier and ATR compression as programmable proxies for "thin tape," alongside your exact Time Stop and Cooling Period rules.

Code: Select all

//@version=5
strategy("Scalp Abort & Cooling Manager", overlay=true, calc_on_every_tick=true, initial_capital=1000)

// =====================================================================
// INPUTS: ABORT RULES & COOLING
// =====================================================================
grp_abort = "Abort Mechanics"
timeStopMins  = input.int(5, title="Time Stop (Minutes)", group=grp_abort, tooltip="Max minutes to hold if trade goes nowhere.")
thinVolMult   = input.float(0.4, title="Thin Tape Volume Multiplier", group=grp_abort, tooltip="If current volume drops below this fraction of the MA, the tape is dead.")
coolingMins   = input.int(10, title="Cooling Period (Minutes)", group=grp_abort, tooltip="Time to lock out re-entries after an abort.")

// =====================================================================
// TIME CONVERSIONS
// =====================================================================
// Convert user minutes to chart bars (works best on 1m, 3m, 5m charts)
barsPerMin   = 1 / timeframe.multiplier
timeStopBars = math.max(1, math.round(timeStopMins * barsPerMin))
coolingBars  = math.max(1, math.round(coolingMins * barsPerMin))

// =====================================================================
// STATE TRACKING
// =====================================================================
var int lastAbortBar = -9999
inTrade = strategy.position_size != 0

// Calculate if we are currently in a cooling period
isCooling = (bar_index - lastAbortBar) <= coolingBars

// Visual warning when cooling period is active
bgcolor(isCooling ? color.new(color.red, 90) : na, title="Cooling Penalty Box")

// =====================================================================
// ENTRY LOGIC (PLACEHOLDER)
// =====================================================================
// Replace this with your actual entry criteria. 
// The crucial part is adding "and not isCooling" to prevent denial re-entries.
longCondition = ta.crossover(ta.sma(close, 5), ta.sma(close, 20))

if longCondition and not inTrade and not isCooling
    strategy.entry("Scalp Entry", strategy.long)

// =====================================================================
// ABORT LOGIC (THE "GET OUT" RULES)
// =====================================================================
// 1. Time Stop Check
barsInTrade = inTrade ? (bar_index - strategy.opentrades.entry_bar_index(0)) : 0
hitTimeStop = inTrade and (barsInTrade >= timeStopBars)

// 2. Thin Tape Check (Proxy for "Book stepped back")
// Compares current volume to a 20-bar average. 
avgVol = ta.sma(volume, 20)
isThinTape = inTrade and (volume < (avgVol * thinVolMult))

// Combined Abort Cue
abortTrade = hitTimeStop or isThinTape

// =====================================================================
// EXECUTE CLEAN ABORT
// =====================================================================
if abortTrade
    // Flatten at market
    strategy.close("Scalp Entry", comment="ABORT: Dead Tape/Time")
    // Tag the abort bar to start the cooling period penalty box
    lastAbortBar := bar_index

// Standard exit for a winning trade (placeholder)
if inTrade and ta.crossunder(ta.sma(close, 5), ta.sma(close, 20))
    strategy.close("Scalp Entry", comment="Standard Exit")
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

The distinction between holding through structural noise and recognizing a liquidity vacuum comes down to measuring statistical anomalies in participation, not just price action. When you are scalping the 1-minute or 5-minute charts, price can stall because orders are actively absorbing at a level (noise/accumulation) or because the participants have simply stepped away (invalidation).

Here is the mechanical differentiation:

Structural Noise (Hold): The asset is breathing. Volume remains within 1 standard deviation of the session mean. Price may retrace, but tick velocity remains constant, and the lower-timeframe order flow shows active two-way interaction.

Liquidity Withdrawal (Abort): The tape goes lumpy. You see a statistically significant drop in volume (a negative Z-score anomaly). The spread widens, causing erratic, low-volume wicks without body displacement. If your premise was immediate momentum and the order book thins out, your edge has evaporated. You are no longer trading a setup; you are holding a directional bias in a random-walk environment.

To codify this professionally, static multipliers are insufficient. We need dynamic thresholds that adapt to the current session's volatility.
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

This Pine Script v5 architecture utilizes custom data types, a rolling Z-score for volume anomaly detection, and an ATR-based stall metric. It implements a strict state-machine approach to enforce your circuit breaker (cooling period) and flatten the position when the statistical environment degrades.

Code: Select all

//@version=5
strategy("Execution Engine: Microstructure Abort & Circuit Breaker", overlay=true, calc_on_every_tick=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10)

// =====================================================================
// STRUCTURAL CONFIGURATION
// =====================================================================
type ExecutionParams
    int   timeStopBars
    float volZScoreThreshold
    float atrStallThreshold
    int   circuitBreakerBars

var ExecutionParams config = ExecutionParams.new(
      timeStopBars       = input.int(5, "Time Stop (Bars)", group="Execution Rules"),
      volZScoreThreshold = input.float(-1.5, "Volume Z-Score Abort", group="Microstructure", tooltip="Statistical drop in volume (e.g., -1.5 StdDev below mean)."),
      atrStallThreshold  = input.float(0.3, "ATR Stall Threshold", group="Microstructure", tooltip="If price moves less than this fraction of ATR, it's dead."),
      circuitBreakerBars = input.int(10, "Circuit Breaker Lockout (Bars)", group="Risk Controls")
  )

// =====================================================================
// STATE MANAGEMENT & MICROSTRUCTURE METRICS
// =====================================================================
var int lastAbortBar = -9999
bool isFlat          = strategy.position_size == 0
bool isCooling       = (bar_index - lastAbortBar) <= config.circuitBreakerBars

// 1. Volume Z-Score (Detecting statistical liquidity withdrawal)
float volMean   = ta.sma(volume, 20)
float volStdDev = ta.stdev(volume, 20)
float volZScore = volStdDev == 0 ? 0 : (volume - volMean) / volStdDev

// 2. ATR Stall Detection (Is the market actually moving?)
float currentATR = ta.atr(14)
float barRange   = high - low
bool  isStalled  = barRange < (currentATR * config.atrStallThreshold)

// =====================================================================
// ENTRY LOGIC (PLACEHOLDER ARCHITECTURE)
// =====================================================================
// In production, inject your raw price action / liquidity sweep logic here.
bool triggerLong = ta.crossover(ta.ema(close, 9), ta.ema(close, 21)) 

if triggerLong and isFlat and not isCooling
    strategy.entry("Long_Scalp", strategy.long)

// =====================================================================
// DYNAMIC ABORT LOGIC
// =====================================================================
int barsInTrade = isFlat ? 0 : (bar_index - strategy.opentrades.entry_bar_index(strategy.opentrades.count - 1))

bool hitTimeStop = not isFlat and (barsInTrade >= config.timeStopBars)
bool tapeDied    = not isFlat and (volZScore <= config.volZScoreThreshold) and isStalled

bool triggerAbort = hitTimeStop or tapeDied

if triggerAbort
    strategy.close("Long_Scalp", comment="ABORT: Liquidity/Time")
    lastAbortBar := bar_index // Engage circuit breaker

// =====================================================================
// UI / HUD
// =====================================================================
bgcolor(isCooling ? color.new(color.maroon, 85) : na, title="Circuit Breaker Active")

var table executionHUD = table.new(position.bottom_right, 2, 4, border_width = 1)
if barstate.islast
    table.cell(executionHUD, 0, 0, "Tape Status", text_color=color.white, bgcolor=color.gray)
    table.cell(executionHUD, 1, 0, tapeDied ? "DEAD" : "ACTIVE", text_color=color.white, bgcolor=tapeDied ? color.red : color.green)
    
    table.cell(executionHUD, 0, 1, "Vol Z-Score", text_color=color.white, bgcolor=color.gray)
    table.cell(executionHUD, 1, 1, str.tostring(volZScore, "#.##"), text_color=color.white, bgcolor=volZScore < config.volZScoreThreshold ? color.red : color.black)
    
    table.cell(executionHUD, 0, 2, "State", text_color=color.white, bgcolor=color.gray)
    table.cell(executionHUD, 1, 2, isCooling ? "LOCKED" : (isFlat ? "FLAT" : "IN TRADE"), text_color=color.white, bgcolor=isCooling ? color.orange : color.black)
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

Moving from TradingView to a compiled environment like cAlgo (C#) or MT5 (C++) changes the execution paradigm entirely. You are no longer guessing at liquidity through volume proxies on a closed bar; you are reacting to actual Level 1 order book events as they happen.

The biggest architectural shift is moving your abort logic into the OnTick() event handler. This allows you to measure real-time spread expansion and absolute time decay, killing the trade the millisecond the book steps back, even if a bar hasn't closed.

Here is how that microstructure abort engine translates into a modern C# cAlgo structure.

Code: Select all

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

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class MicrostructureAbortEngine : Robot
    {
        [Parameter("Time Stop (Minutes)", Group = "Execution", DefaultValue = 5)]
        public int TimeStopMinutes { get; set; }

        [Parameter("Max Spread (Pips)", Group = "Microstructure", DefaultValue = 1.0)]
        public double MaxSpreadPips { get; set; }

        [Parameter("Tick Vol Z-Score Abort", Group = "Microstructure", DefaultValue = -1.5)]
        public double VolZScoreThreshold { get; set; }

        [Parameter("Cooling Period (Minutes)", Group = "Risk Controls", DefaultValue = 10)]
        public int CoolingMinutes { get; set; }

        private SimpleMovingAverage _tickVolSma;
        private DateTime _circuitBreakerEndTime = DateTime.MinValue;

        protected override void OnStart()
        {
            // Track previous closed bars to establish a baseline for current session liquidity
            _tickVolSma = Indicators.SimpleMovingAverage(Bars.TickVolumes, 20);
        }

        protected override void OnTick()
        {
            var position = Positions.Find("Scalp_01");
            if (position == null) return;

            // 1. Real-Time Spread Evaluation (Immediate abort if liquidity is pulled)
            double currentSpreadPips = Symbol.Spread / Symbol.PipSize;
            bool isSpreadSpiking = currentSpreadPips > MaxSpreadPips;

            // 2. Absolute Time Stop (Clock time, not bar time)
            bool hitTimeStop = (Server.Time - position.EntryTime).TotalMinutes >= TimeStopMinutes;

            // 3. Dynamic Tick Volume Anomaly
            // Evaluates the current bar's building tick volume against the moving average of closed bars
            double currentTickVol = Bars.TickVolumes.Last(0);
            double meanVol = _tickVolSma.Result.Last(1); 
            double stdDev = GetTickVolumeStdDev(20, meanVol);
            
            double zScore = stdDev == 0 ? 0 : (currentTickVol - meanVol) / stdDev;
            bool isTapeDead = zScore <= VolZScoreThreshold;

            if (isSpreadSpiking || hitTimeStop || isTapeDead)
            {
                ClosePosition(position);
                
                // Engage the penalty box using absolute server time
                _circuitBreakerEndTime = Server.Time.AddMinutes(CoolingMinutes);
                
                Print($"[ABORT] Spread: {currentSpreadPips:F1} | Time Stop: {hitTimeStop} | Tape Z-Score: {zScore:F2}");
            }
        }

        protected override void OnBar()
        {
            // Entry logic goes here. 
            // The strict lockout check prevents denial reloading.
            bool isCooling = Server.Time < _circuitBreakerEndTime;
            
            if (!isCooling /* && raw price action setup is valid */)
            {
                // Execute trade...
            }
        }

        private double GetTickVolumeStdDev(int periods, double mean)
        {
            double sumOfSquares = 0;
            // Iterate through historical closed bars to calculate variance
            for (int i = 1; i <= periods; i++)
            {
                double val = Bars.TickVolumes.Last(i);
                sumOfSquares += Math.Pow(val - mean, 2);
            }
            return Math.Sqrt(sumOfSquares / periods);
        }
    }
}
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

Key Differences from Pine Script

Absolute Time vs. Bar Counting: In Pine, time stops are clunky because they rely on bar index counts. In C#, (Server.Time - position.EntryTime).TotalMinutes gives you exact to-the-second time stops regardless of the chart timeframe you are viewing.

True Spread Defense: Symbol.Spread updates on every single incoming quote. If a macroeconomic event hits or the LP pulls their resting orders, the spread spikes, and the OnTick() loop traps it instantly and flattens your exposure.

Asynchronous Execution: In a live environment, you would swap ClosePosition(position) for ClosePositionAsync() to ensure your bot doesn't block the thread waiting for the server to acknowledge the kill order, allowing it to continue monitoring the tape.
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

Porting this execution logic into MetaTrader requires splitting the architecture between MT5’s position-centric environment and MT4’s legacy order-centric structure. Because MetaTrader handles real-time data natively in the OnTick() loop, you can measure exact point-based spread expansion and absolute server time without relying on bar closes.

Here are the complete execution engines for both platforms, utilizing raw price action logic as the intended entry mechanism rather than lagging indicator crossovers.

The MQL5 Execution Engine (Modern, Position-Centric)

MQL5 uses CTrade for execution and treats trades as consolidated positions per symbol. We calculate the spread dynamically based on broker point digits to ensure pip accuracy across asset classes.

Code: Select all

//+------------------------------------------------------------------+
//| MQL5 Microstructure Abort Engine                                 |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

input int      InpTimeStopMinutes   = 5;      // Time Stop (Minutes)
input double   InpMaxSpreadPips     = 1.0;    // Max Spread (Pips)
input double   InpVolZScoreAbort    = -1.5;   // Tick Vol Z-Score Abort
input int      InpCoolingMinutes    = 10;     // Cooling Lockout (Minutes)
input ulong    InpMagicNumber       = 777777; // EA Magic Number

CTrade         trade;
datetime       circuitBreakerEndTime = 0;
double         pipMultiplier;

int OnInit()
{
    trade.SetExpertMagicNumber(InpMagicNumber);
    // Standardize pip size (handles 3 and 5 digit brokers)
    int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
    pipMultiplier = (digits == 3 || digits == 5) ? 10.0 : 1.0;
    return(INIT_SUCCEEDED);
}

void OnTick()
{
    bool isCooling = TimeCurrent() < circuitBreakerEndTime;

    // =====================================================================
    // 1. DYNAMIC ABORT LOGIC (Only runs if position is open)
    // =====================================================================
    if (PositionSelectByTicket(PositionGetInteger(POSITION_TICKET)))
    {
        if (PositionGetInteger(POSITION_MAGIC) == InpMagicNumber && PositionGetString(POSITION_SYMBOL) == _Symbol)
        {
            // Spread Spike Check
            double currentSpreadPoints = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
            double currentSpreadPips = (currentSpreadPoints * SymbolInfoDouble(_Symbol, SYMBOL_POINT)) / (SymbolInfoDouble(_Symbol, SYMBOL_POINT) * pipMultiplier);
            bool isSpreadSpiking = currentSpreadPips > InpMaxSpreadPips;

            // Absolute Time Stop
            datetime entryTime = (datetime)PositionGetInteger(POSITION_TIME);
            bool hitTimeStop = (TimeCurrent() - entryTime) >= (InpTimeStopMinutes * 60);

            // Volume Z-Score Anomaly
            double zScore = CalculateTickVolumeZScore(20);
            bool isTapeDead = zScore <= InpVolZScoreAbort;

            if (isSpreadSpiking || hitTimeStop || isTapeDead)
            {
                trade.PositionClose(_Symbol);
                circuitBreakerEndTime = TimeCurrent() + (InpCoolingMinutes * 60);
                PrintFormat("[ABORT] Spread: %.1f | Time: %s | Tape Z: %.2f", currentSpreadPips, hitTimeStop ? "True" : "False", zScore);
            }
        }
    }
    // =====================================================================
    // 2. ENTRY LOGIC 
    // =====================================================================
    else if (!isCooling)
    {
        // Placeholder: Insert your raw price action logic here (e.g., 15-minute 
        // structure sweeps, candlestick formations) ensuring no lagging indicators.
        // if (ValidPriceActionSetup()) { trade.Buy(0.1, _Symbol); }
    }
}

// Helper: Calculate standard deviation of tick volume for Z-Score
double CalculateTickVolumeZScore(int periods)
{
    long currentTickVol = 0;
    SymbolInfoInteger(_Symbol, SYMBOL_VOLUME, currentTickVol); // Current unclosed bar volume
    
    long tickVols[];
    if (CopyTickVolume(_Symbol, PERIOD_CURRENT, 1, periods, tickVols) != periods) return 0.0;

    double sum = 0.0, mean = 0.0, sumSq = 0.0, variance = 0.0, stdDev = 0.0;
    
    for (int i = 0; i < periods; i++) sum += (double)tickVols[i];
    mean = sum / periods;
    
    for (int i = 0; i < periods; i++) sumSq += MathPow((double)tickVols[i] - mean, 2);
    variance = sumSq / periods;
    stdDev = MathSqrt(variance);

    if (stdDev == 0.0) return 0.0;
    return ((double)currentTickVol - mean) / stdDev;
}
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

The MQL4 Legacy Adapter (Order-Centric)

MT4 requires looping through the global order pool utilizing OrderSelect(). We also rely on MarketInfo() and the built-in iVolume() array instead of MT5's copy functions.

Code: Select all

//+------------------------------------------------------------------+
//| MQL4 Microstructure Abort Engine                                 |
//+------------------------------------------------------------------+
extern int      InpTimeStopMinutes   = 5;      
extern double   InpMaxSpreadPips     = 1.0;    
extern double   InpVolZScoreAbort    = -1.5;   
extern int      InpCoolingMinutes    = 10;     
extern int      InpMagicNumber       = 777777; 

datetime circuitBreakerEndTime = 0;
double   pipMultiplier;

int OnInit()
{
    pipMultiplier = (Digits == 3 || Digits == 5) ? 10.0 : 1.0;
    return(INIT_SUCCEEDED);
}

void OnTick()
{
    bool isCooling = TimeCurrent() < circuitBreakerEndTime;
    bool hasOpenPosition = false;

    // =====================================================================
    // 1. DYNAMIC ABORT LOGIC
    // =====================================================================
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if (OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
            {
                hasOpenPosition = true;

                double currentSpreadPips = MarketInfo(Symbol(), MODE_SPREAD) / pipMultiplier;
                bool isSpreadSpiking = currentSpreadPips > InpMaxSpreadPips;

                bool hitTimeStop = (TimeCurrent() - OrderOpenTime()) >= (InpTimeStopMinutes * 60);

                double zScore = GetMQL4TickVolZScore(20);
                bool isTapeDead = zScore <= InpVolZScoreAbort;

                if (isSpreadSpiking || hitTimeStop || isTapeDead)
                {
                    double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
                    bool closed = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrRed);
                    
                    if (closed)
                    {
                        circuitBreakerEndTime = TimeCurrent() + (InpCoolingMinutes * 60);
                        Print("[ABORT] Executed market flatten due to degraded tape or time stop.");
                    }
                }
            }
        }
    }

    // =====================================================================
    // 2. ENTRY LOGIC
    // =====================================================================
    if (!hasOpenPosition && !isCooling)
    {
        // Insert raw price action entry conditions here.
    }
}

double GetMQL4TickVolZScore(int periods)
{
    double currentVol = Volume[0]; // Active building bar
    double sum = 0.0, mean = 0.0, sumSq = 0.0, stdDev = 0.0;

    for (int i = 1; i <= periods; i++) sum += Volume[i];
    mean = sum / periods;

    for (int i = 1; i <= periods; i++) sumSq += MathPow(Volume[i] - mean, 2);
    stdDev = MathSqrt(sumSq / periods);

    if (stdDev == 0.0) return 0.0;
    return (currentVol - mean) / stdDev;
}
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: What a clean abort looks like mid-trade when the tape goes thin

Post by PTScalper »

Logging slippage during an abort is the only way to audit your broker's execution quality and determine if a specific pair's liquidity is genuinely toxic during a stalled tape. When you punch out at market because the book thins out, you are demanding immediate liquidity exactly when the market makers are stepping back.

Since you work extensively in C# and .NET environments, the cAlgo implementation will look very familiar—it's just a matter of capturing the expected Bid/Ask prior to the execution call and comparing it to the resolved TradeResult. In MetaTrader, we pull the execution price from the CTrade result structure (MQL5) or the historical order pool (MQL4).

Here is the modular abort logic for all three platforms. Positive slippage means the execution hurt you (you got filled worse than expected); negative slippage means price improvement.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply