No description
Find a file
2026-07-12 07:09:23 +00:00
README.mdMTF_Pullback_Strategy_v2.mq5 Update README.mdMTF_Pullback_Strategy_v2.mq5 2026-07-12 07:09:23 +00:00

//+------------------------------------------------------------------+
//|                                    MTF_Pullback_Strategy_v2.mq5 |
//|                                  Copyright 2026, AlgoTrader peer |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, AlgoTrader peer"
#property link      "https://www.mql5.com"
#property version   "2.00"

#include <Trade\Trade.mqh>
CTrade trade;

//--- Input parameters
input group "---- Risk Management ----"
input double    InpLotSize        = 0.1;       // Lot Size
input int       InpStopLossPips   = 20;        // Stop Loss in Pips
input int       InpTakeProfitPips = 40;        // Take Profit in Pips
input ulong     InpMagicNumber    = 123456;    // EA Magic Number

input group "---- Filter Settings ----"
input int       InpADXPeriod      = 14;        // ADX Period
input int       InpADXThreshold   = 25;        // Ignore markets if ADX is below this
input int       InpEMAPeriod      = 200;       // Trend Filter EMA Period

//--- Global variables
double pipsMultiplier;
datetime lastBarTime;
int adxHandle;                                 // Handle for the ADX indicator
int emaHandle;                                 // Handle for the H4 EMA indicator

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   if(_Digits == 3 || _Digits == 5) pipsMultiplier = 10 * _Point;
   else                             pipsMultiplier = _Point;

   trade.SetExpertMagicNumber(InpMagicNumber);
   lastBarTime = 0;

   // Initialize the ADX indicator on the M15 timeframe to spot local choppiness
   adxHandle = iADX(_Symbol, PERIOD_M15, InpADXPeriod);
   if(adxHandle == INVALID_HANDLE)
   {
      Print("Failed to create ADX indicator handle.");
      return(INIT_FAILED);
   }

   // Initialize the 200 EMA on the H4 timeframe to capture the macro trend direction
   emaHandle = iMA(_Symbol, PERIOD_H4, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(emaHandle == INVALID_HANDLE)
   {
      Print("Failed to create H4 EMA indicator handle.");
      return(INIT_FAILED);
   }

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Release indicator handles to free up system memory
   IndicatorRelease(adxHandle);
   IndicatorRelease(emaHandle);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1. New Candle Filter (M15)
   datetime currentBarTime = iTime(_Symbol, PERIOD_M15, 0);
   if(currentBarTime == lastBarTime) return; 
   
   // 2. Check open positions
   if(PositionsTotal() > 0)
   {
      for(int i=PositionsTotal()-1; i>=0; i--)
      {
         if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
         {
            return; 
         }
      }
   }

   // 3. Choppy Market Filter (Fetch current ADX values)
   double adxValues[];
   ArraySetAsSeries(adxValues, true);
   if(CopyBuffer(adxHandle, MAIN_LINE, 1, 1, adxValues) < 1) return; // Read last closed M15 bar value
   
   // If ADX is below our threshold (e.g. 25), market is ranging/choppy. Do not trade.
   if(adxValues[0] < InpADXThreshold) return;

   // 4. Macro Trend Filter (Fetch H4 200 EMA and Price)
   double emaValues[];
   MqlRates ratesH4Trend[];
   ArraySetAsSeries(emaValues, true);
   ArraySetAsSeries(ratesH4Trend, true);
   
   if(CopyBuffer(emaHandle, 0, 1, 1, emaValues) < 1) return;
   if(CopyRates(_Symbol, PERIOD_H4, 1, 1, ratesH4Trend) < 1) return;

   bool isAbove200EMA = (ratesH4Trend[0].close > emaValues[0]);

   // 5. Fetch Multi-Timeframe Candle Directions
   MqlRates ratesH4[], ratesH1[], ratesM15[];
   ArraySetAsSeries(ratesH4, true);
   ArraySetAsSeries(ratesH1, true);
   ArraySetAsSeries(ratesM15, true);

   if(CopyRates(_Symbol, PERIOD_H4, 1, 1, ratesH4) < 1) return;
   if(CopyRates(_Symbol, PERIOD_H1, 1, 1, ratesH1) < 1) return;
   if(CopyRates(_Symbol, PERIOD_M15, 1, 1, ratesM15) < 1) return;

   bool isH4Bullish  = (ratesH4[0].close > ratesH4[0].open);
   bool isH1Bullish  = (ratesH1[0].close > ratesH1[0].open);
   bool isM15Bullish = (ratesM15[0].close > ratesM15[0].open);

   // 6. Strategy Rules (Now incorporating the 200 EMA filter)
   // BUY: H4 Bullish, H1 Bearish Pullback, M15 Bullish Trigger AND Price must be above H4 200 EMA
   bool buyCondition  = (isH4Bullish && !isH1Bullish && isM15Bullish && isAbove200EMA);
   
   // SELL: H4 Bearish, H1 Bullish Pullback, M15 Bearish Trigger AND Price must be below H4 200 EMA
   bool sellCondition = (!isH4Bullish && isH1Bullish && !isM15Bullish && !isAbove200EMA);

   // 7. Execution
   if(buyCondition)
   {
      double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      double sl = askPrice - (InpStopLossPips * pipsMultiplier);
      double tp = askPrice + (InpTakeProfitPips * pipsMultiplier);
      
      if(trade.Buy(InpLotSize, _Symbol, askPrice, sl, tp, "Filtered Buy"))
      {
         lastBarTime = currentBarTime;
      }
   }
   else if(sellCondition)
   {
      double bidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double sl = bidPrice + (InpStopLossPips * pipsMultiplier);
      double tp = bidPrice - (InpTakeProfitPips * pipsMultiplier);
      
      if(trade.Sell(InpLotSize, _Symbol, bidPrice, sl, tp, "Filtered Sell"))
      {
         lastBarTime = currentBarTime;
      }
   }
}