Page 1 of 1

Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Posted: Sat Jul 25, 2026 9:34 pm
by PTScalper
Hi traders,

i would like to share with you one of my favorite setup.
I love Fibonacci and Fibonacci retracement, especially in longer term charts like H4 and D1.

Here is the complete, single-file MQL4 source code combining the Volume-Weighted OTE setup, the in-memory dynamic Fibonacci calculation, and the real-time ATR trailing stop.
You can copy and paste this directly into MT4's MetaEditor (F4), compile it, and attach it to your chart.

Code: Select all

//+------------------------------------------------------------------+
//|                                     VolumeWeightedOTE_EA.mq4     |
//|                                     Dynamic Fib OTE + MFI Scalper|
//+------------------------------------------------------------------+
#property copyright "Forex Scalping EA"
#property link      ""
#property version   "1.00"
#property strict

//--- General Inputs
input double LotSize          = 0.1;
input int    Slippage         = 3;
input int    MagicNumber      = 888888;

//--- Indicator Inputs
input int    SwingLookback    = 40;     // Bars scanned for dynamic impulse swing
input int    EmaPeriod        = 200;    // Macro trend filter
input int    MfiPeriod        = 3;      // Fast tick volume tracking
input double StopLossBuffer   = 2.0;    // Initial SL buffer in pips beyond swing high/low

//--- Trailing Stop Inputs
input bool   UseAtrTrailing   = true;   // Enable ATR Trailing Stop
input int    AtrPeriod        = 14;     // ATR calculation period
input double AtrMultiplier     = 2.0;    // Multiplier for trailing distance

//--- Global Variables
datetime lastBarTime = 0;
double   Pips;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // Standardize pip values for 4-digit and 5-digit brokers
    Pips = Point;
    if(Digits == 3 || Digits == 5) Pips = Point * 10;

    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 1. Manage existing trades on EVERY tick (Dynamic ATR Trailing)
    ManageTrailingStop();

    // 2. Bar Close Lock: Pause entry execution until the current candle closes
    if(Time[0] == lastBarTime) return; 

    // 3. Fetch Indicator Data from the last completed bar (shift = 1)
    double ema200_1 = iMA(NULL, 0, EmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
    double mfi1     = iMFI(NULL, 0, MfiPeriod, 1);
    double mfi2     = iMFI(NULL, 0, MfiPeriod, 2);

    // 4. Locate Dynamic Swing High and Low over the Lookback Window
    int highestIndex = iHighest(NULL, 0, MODE_HIGH, SwingLookback, 1);
    int lowestIndex  = iLowest(NULL, 0, MODE_LOW, SwingLookback, 1);
    
    double swingHigh = High[highestIndex];
    double swingLow  = Low[lowestIndex];
    double swingRange= swingHigh - swingLow;

    if(swingRange == 0) return; // Prevent division by zero if market is dead flat

    // Setup Flags
    bool isBuySetup  = false;
    bool isSellSetup = false;
    
    double initialSL = 0;
    double initialTP = 0;

    // --- BUY SETUP EVALUATION ---
    // Rule A: Macro Uptrend (Price > 200 EMA)
    // Rule B: Valid upward impulse leg (Lowest low formed BEFORE Highest high in history)
    if(Close[1] > ema200_1 && lowestIndex > highestIndex)
    {
        double fib618 = swingHigh - (swingRange * 0.618);
        double fib786 = swingHigh - (swingRange * 0.786);
        
        // Rule C: Price retraced into the Optimal Trade Entry (OTE) Kill Zone
        bool inKillZone = (Close[1] <= fib618) && (Close[1] >= fib786);
        
        // Rule D: Volume Exhaustion (MFI dipped below 20 and turned back up)
        bool mfiTrigger = (mfi2 <= 20) && (mfi1 > 20);

        if(inKillZone && mfiTrigger)
        {
            isBuySetup = true;
            initialSL  = swingLow - (StopLossBuffer * Pips); 
            initialTP  = swingHigh; // Primary target at impulse high
        }
    }

    // --- SELL SETUP EVALUATION ---
    // Rule A: Macro Downtrend (Price < 200 EMA)
    // Rule B: Valid downward impulse leg (Highest high formed BEFORE Lowest low in history)
    if(Close[1] < ema200_1 && highestIndex > lowestIndex)
    {
        double fib618 = swingLow + (swingRange * 0.618);
        double fib786 = swingLow + (swingRange * 0.786);
        
        // Rule C: Price retraced into the Optimal Trade Entry (OTE) Kill Zone
        bool inKillZone = (Close[1] >= fib618) && (Close[1] <= fib786);
        
        // Rule D: Volume Exhaustion (MFI spiked above 80 and turned back down)
        bool mfiTrigger = (mfi2 >= 80) && (mfi1 < 80);

        if(inKillZone && mfiTrigger)
        {
            isSellSetup = true;
            initialSL   = swingHigh + (StopLossBuffer * Pips);
            initialTP   = swingLow; // Primary target at impulse low
        }
    }

    // 5. Order Execution Engine
    if(CountOpenPositions() == 0) 
    {
        if(isBuySetup)
        {
            int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, Slippage, initialSL, initialTP, "OTE-MFI-Buy", MagicNumber, 0, clrDodgerBlue);
            if(ticket > 0) lastBarTime = Time[0];
        }
        else if(isSellSetup)
        {
            int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, Slippage, initialSL, initialTP, "OTE-MFI-Sell", MagicNumber, 0, clrCrimson);
            if(ticket > 0) lastBarTime = Time[0];
        }
    }
}

//+------------------------------------------------------------------+
//| Helper: Dynamic ATR Trailing Stop Engine                         |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
    if(!UseAtrTrailing) return;
    
    // Calculate ATR distance from closed bar
    double atr = iATR(NULL, 0, AtrPeriod, 1); 
    double trailDistance = atr * AtrMultiplier;
    
    // Respect broker minimum stop level distance
    double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;

    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                if(OrderType() == OP_BUY)
                {
                    double newSL = NormalizeDouble(Bid - trailDistance, Digits);
                    
                    // Trail up only when new SL is higher than current SL
                    if(newSL > OrderStopLoss() || OrderStopLoss() == 0)
                    {
                        if((Bid - newSL) >= stopLevel)
                        {
                            bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
                        }
                    }
                }
                else if(OrderType() == OP_SELL)
                {
                    double newSL = NormalizeDouble(Ask + trailDistance, Digits);
                    
                    // Trail down only when new SL is lower than current SL
                    if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
                    {
                        if((newSL - Ask) >= stopLevel)
                        {
                            bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrRed);
                        }
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Helper: Count open positions belonging to this Magic Number      |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            {
                count++;
            }
        }
    }
    return count;
}

Re: Forex scalping indicator - Fibonacci + Volume-Weighted OTE

Posted: Sat Jul 25, 2026 9:35 pm
by PTScalper
Do you like it? Or do you use slightly different setup? You can share with us :-)