What a clean abort looks like mid-trade when the tape goes thin
-
LondonScalper
- Posts: 701
- Joined: Sat Sep 05, 2026 7:54 am
What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
Hi LondonScalper,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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.
Re: What a clean abort looks like mid-trade when the tape goes thin
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.
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.