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;
}