Advertisement IC Markets

XAUUSD M1 vs M5: when I switch primary mid-session

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: 2197
Joined: Mon Jul 20, 2026 1:28 pm

Re: XAUUSD M1 vs M5: when I switch primary mid-session

Post by PTScalper »

API Implementation Details

Bars.Count - 2 Target: In cTrader, Bars.Count - 1 is the current, active, forming tick data. By locking the evaluation to Bars.Count - 2, you guarantee the mathematical integrity of the Close price against the MidPoint.

State Isolation: The for loops explicitly carve out the historical subsets. Pine Script handles historical indexing arrays implicitly behind the scenes, but doing it explicitly in C# guarantees memory safety and prevents IndexOutOfRangeException errors during rapid tick execution.

Execution Efficiency: Bypassing Bars.Maximum() or LINQ aggregations in favor of raw for loops against the primitive arrays (Bars.HighPrices) ensures this cBot operates entirely in the L1/L2 cache footprint, introducing zero latency overhead on the main thread if you eventually wire it to execute automated orders.
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: 2197
Joined: Mon Jul 20, 2026 1:28 pm

Re: XAUUSD M1 vs M5: when I switch primary mid-session

Post by PTScalper »

Here is the exact microstructure and liquidity sweep logic implemented as Expert Advisors for both MetaTrader platforms.

By executing this inside OnTick() and restricting evaluation to the most recently closed bar (when a new candle opens), we sidestep the overhead of indicator buffers and ensure execution remains extremely fast.

MQL4 Implementation (MicrostructureFilter.mq4)

MQL4 natively handles historical arrays (Open, Close, High, Low) in reverse chronological order, making the loop logic nearly identical to the C# implementation.

Code: Select all

//+------------------------------------------------------------------+
//|                                       MicrostructureFilter.mq4   |
//+------------------------------------------------------------------+
#property strict

input int OverlapBars = 4;       // Chop: Overlap Bars
input int SweepLookback = 10;    // Sweep: Pivot Lookback

datetime lastBarTime = 0;

void OnTick()
{
    // Ensure we only evaluate once per newly opened bar
    if (Time[0] == lastBarTime) return;
    
    // Ensure enough historical data exists
    int requiredBars = MathMax(OverlapBars, SweepLookback) + 2;
    if (Bars < requiredBars) return;
    
    lastBarTime = Time[0];
    
    // Index 1 is the most recently closed candle
    int evalIndex = 1;

    // --- 1. Microstructure Consolidation (Chop) Detection ---
    double maxBody = 0.0;
    double minBody = 9999999.0;
    double sumWickSize = 0;
    
    for (int i = 0; i < OverlapBars; i++)
    {
        int curr = evalIndex + i; 
        double bodyTop = MathMax(Open[curr], Close[curr]);
        double bodyBottom = MathMin(Open[curr], Close[curr]);
        
        if (bodyTop > maxBody) maxBody = bodyTop;
        if (bodyBottom < minBody) minBody = bodyBottom;
        
        double bodySize = bodyTop - bodyBottom;
        double totalSize = High[curr] - Low[curr];
        sumWickSize += (totalSize - bodySize);
    }
    
    double bodyRange = maxBody - minBody;
    double avgWickSize = sumWickSize / OverlapBars;
    
    bool isChop = bodyRange < avgWickSize;
    
    // --- 2. Liquidity Sweep Detection ---
    double localHigh = 0.0;
    double localLow = 9999999.0;
    
    // Calculate local extremes EXCLUDING the evaluation bar
    for (int i = 1; i <= SweepLookback; i++)
    {
        int curr = evalIndex + i;
        if (High[curr] > localHigh) localHigh = High[curr];
        if (Low[curr] < localLow) localLow = Low[curr];
    }
    
    double barHigh = High[evalIndex];
    double barLow = Low[evalIndex];
    double barClose = Close[evalIndex];
    double midPoint = barLow + (barHigh - barLow) * 0.5;
    
    bool bearishSweep = (barHigh > localHigh) && (barClose < localHigh) && (barClose < midPoint);
    bool bullishSweep = (barLow < localLow) && (barClose > localLow) && (barClose > midPoint);
    
    // --- 3. Logging and Visual Outputs ---
    if (bullishSweep && !isChop)
    {
        PrintFormat("Bullish Sweep at %f. Swept liquidity below %f.", barLow, localLow);
        string objName = "SweepBull_" + TimeToString(Time[evalIndex]);
        ObjectCreate(0, objName, OBJ_ARROW_BUY, 0, Time[evalIndex], barLow - 5 * Point);
        ObjectSetInteger(0, objName, OBJPROP_COLOR, clrMediumSeaGreen);
    }
    else if (bearishSweep && !isChop)
    {
        PrintFormat("Bearish Sweep at %f. Swept liquidity above %f.", barHigh, localHigh);
        string objName = "SweepBear_" + TimeToString(Time[evalIndex]);
        ObjectCreate(0, objName, OBJ_ARROW_SELL, 0, Time[evalIndex], barHigh + 5 * Point);
        ObjectSetInteger(0, objName, OBJPROP_COLOR, clrCrimson);
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 2197
Joined: Mon Jul 20, 2026 1:28 pm

Re: XAUUSD M1 vs M5: when I switch primary mid-session

Post by PTScalper »

MQL5 Implementation (MicrostructureFilter.mq5)

Because MQL5 arrays index left-to-right by default, this version utilizes CopyRates coupled with ArraySetAsSeries(true). This dynamically forces the MQL5 struct array to mirror MQL4's right-to-left index mapping (where rates[1] is safely the most recently closed bar), completely avoiding messy compatibility wrappers.

Code: Select all

//+------------------------------------------------------------------+
//|                                       MicrostructureFilter.mq5   |
//+------------------------------------------------------------------+
#property strict

input int OverlapBars = 4;       // Chop: Overlap Bars
input int SweepLookback = 10;    // Sweep: Pivot Lookback

datetime lastBarTime = 0;

void OnTick()
{
    datetime timeArray[];
    if(CopyTime(_Symbol, _Period, 0, 1, timeArray) <= 0) return;
    
    if(timeArray[0] == lastBarTime) return;
    
    int requiredBars = MathMax(OverlapBars, SweepLookback) + 2;
    if(Bars(_Symbol, _Period) < requiredBars) return;
    
    lastBarTime = timeArray[0];
    
    // Copy struct data and map index chronologically backwards
    MqlRates rates[];
    ArraySetAsSeries(rates, true);
    if(CopyRates(_Symbol, _Period, 0, requiredBars, rates) < requiredBars) return;
    
    int evalIndex = 1;
    
    // --- 1. Microstructure Consolidation (Chop) Detection ---
    double maxBody = 0.0;
    double minBody = 9999999.0;
    double sumWickSize = 0;
    
    for(int i = 0; i < OverlapBars; i++)
    {
        int curr = evalIndex + i;
        double bodyTop = MathMax(rates[curr].open, rates[curr].close);
        double bodyBottom = MathMin(rates[curr].open, rates[curr].close);
        
        if(bodyTop > maxBody) maxBody = bodyTop;
        if(bodyBottom < minBody) minBody = bodyBottom;
        
        double bodySize = bodyTop - bodyBottom;
        double totalSize = rates[curr].high - rates[curr].low;
        sumWickSize += (totalSize - bodySize);
    }
    
    double bodyRange = maxBody - minBody;
    double avgWickSize = sumWickSize / OverlapBars;
    
    bool isChop = bodyRange < avgWickSize;
    
    // --- 2. Liquidity Sweep Detection ---
    double localHigh = 0.0;
    double localLow = 9999999.0;
    
    for(int i = 1; i <= SweepLookback; i++)
    {
        int curr = evalIndex + i;
        if(rates[curr].high > localHigh) localHigh = rates[curr].high;
        if(rates[curr].low < localLow) localLow = rates[curr].low;
    }
    
    double barHigh = rates[evalIndex].high;
    double barLow = rates[evalIndex].low;
    double barClose = rates[evalIndex].close;
    double midPoint = barLow + (barHigh - barLow) * 0.5;
    
    bool bearishSweep = (barHigh > localHigh) && (barClose < localHigh) && (barClose < midPoint);
    bool bullishSweep = (barLow < localLow) && (barClose > localLow) && (barClose > midPoint);
    
    // --- 3. Logging and Visual Outputs ---
    if(bullishSweep && !isChop)
    {
        PrintFormat("Bullish Sweep at %f. Swept liquidity below %f.", barLow, localLow);
        string objName = "SweepBull_" + TimeToString(rates[evalIndex].time);
        ObjectCreate(0, objName, OBJ_ARROW_BUY, 0, rates[evalIndex].time, barLow - 5 * _Point);
        ObjectSetInteger(0, objName, OBJPROP_COLOR, clrMediumSeaGreen);
    }
    else if(bearishSweep && !isChop)
    {
        PrintFormat("Bearish Sweep at %f. Swept liquidity above %f.", barHigh, localHigh);
        string objName = "SweepBear_" + TimeToString(rates[evalIndex].time);
        ObjectCreate(0, objName, OBJ_ARROW_SELL, 0, rates[evalIndex].time, barHigh + 5 * _Point);
        ObjectSetInteger(0, objName, OBJPROP_COLOR, clrCrimson);
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
LondonScalper
Posts: 622
Joined: Sat Sep 05, 2026 7:54 am

Re: XAUUSD M1 vs M5: when I switch primary mid-session

Post by LondonScalper »

PTScalper wrote:If M1 starts looking like a barcode — overlapping dojis, wicks in both directions without displacement — I immediately step back to M5. If M1 is not cleanly respecting M5 POIs, the micro-structure is broken.
That matches my mid-session switch on gold. Timeframe is a tool, not an identity. Two scratches on M1 still mean I zoom out; your POI-respect filter is a clean second veto. Volume and cost matter as much as noise: London/NY overlap can make M1 usable; as the afternoon thins and spreads stick, paying the spread on a tiny M1 move is mathematically worse than taking the same idea on M5.

I keep the rule dull and written: M5 for bias, M1 for entry only while displacement and spread both clear. When the tape turns into overlapping noise, M1 is retired for the rest of that session — no "one more micro attempt." Chart overlays that align the two timeframes are optional; the fill log and the spread gate do the real work. I would rather miss a barcode scalp than invent structure that is not there.

On your overlap days, do you hard-switch back to M5 at a fixed wall-clock, or only when sticky spreads and barcode prints show up together?
Post Reply