Save this as NewsFadeSpike.mq4 in your MQL4/Experts directory. It uses standard MQL4 order routing and tracking functions.
Code: Select all
//+------------------------------------------------------------------+
//| NewsFadeSpike_MT4.mq4 |
//| Copyright 2026, Quant Dev Lab |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
extern string Separator1 = "=== Strategy Settings ===";
extern int InpAtrPeriod = 14; // ATR Period
extern double InpSpikeMultiplier = 3.5; // Spike Multiplier (x ATR)
extern int InpMaxBarsToHold = 3; // Max Bars to Hold Position
extern string Separator2 = "=== Risk Settings ===";
extern double InpLotSize = 0.10; // Lot Size
extern int InpStopLossPoints = 1000; // Stop Loss (Points)
extern int InpTakeProfitPoints = 1500; // Take Profit (Points)
extern int InpMaxSpreadPoints = 500; // Max Allowed Spread (Points)
extern int InpSlippage = 50; // Allowed Slippage (Points)
extern int InpMagicNumber = 102030; // Magic Number
//--- Global Variables
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Time-based exits run on tick
ManageTimeExits();
// 2. Bar-close execution check
datetime currentBarTime = Time[0];
if(currentBarTime == lastBarTime)
return;
lastBarTime = currentBarTime;
// 3. Ensure no open position already exists
if(HasOpenPosition())
return;
// 4. Spread filter
long spread = (long)MarketInfo(Symbol(), MODE_SPREAD);
if(spread > InpMaxSpreadPoints)
{
Print("Spread exceeds limit: ", spread, " points. Entry bypassed.");
return;
}
// 5. Evaluate Completed Bar (Bar 1)
double barAtr = iATR(Symbol(), 0, InpAtrPeriod, 1);
double barOpen = Open[1];
double barClose = Close[1];
double bodySize = MathAbs(barClose - barOpen);
double threshold = barAtr * InpSpikeMultiplier;
// 6. Signal Evaluation
// Bullish Spike -> SELL
if(barClose > barOpen && bodySize > threshold)
{
double sl = (InpStopLossPoints > 0) ? NormalizeDouble(Bid + InpStopLossPoints * Point, Digits) : 0;
double tp = (InpTakeProfitPoints > 0) ? NormalizeDouble(Bid - InpTakeProfitPoints * Point, Digits) : 0;
int ticket = OrderSend(Symbol(), OP_SELL, InpLotSize, Bid, InpSlippage, sl, tp, "Spike Fade Short", InpMagicNumber, 0, clrRed);
if(ticket < 0)
Print("OrderSend Sell Error: ", GetLastError());
}
// Bearish Spike -> BUY
else if(barClose < barOpen && bodySize > threshold)
{
double sl = (InpStopLossPoints > 0) ? NormalizeDouble(Ask - InpStopLossPoints * Point, Digits) : 0;
double tp = (InpTakeProfitPoints > 0) ? NormalizeDouble(Ask + InpTakeProfitPoints * Point, Digits) : 0;
int ticket = OrderSend(Symbol(), OP_BUY, InpLotSize, Ask, InpSlippage, sl, tp, "Spike Fade Long", InpMagicNumber, 0, clrGreen);
if(ticket < 0)
Print("OrderSend Buy Error: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Check open positions |
//+------------------------------------------------------------------+
bool HasOpenPosition()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Manage Exits Based on Bar Duration |
//+------------------------------------------------------------------+
void ManageTimeExits()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
int barsHeld = iBarShift(Symbol(), 0, OrderOpenTime());
if(barsHeld >= InpMaxBarsToHold)
{
bool closed = false;
if(OrderType() == OP_BUY)
closed = OrderClose(OrderTicket(), OrderLots(), Bid, InpSlippage, clrGray);
else if(OrderType() == OP_SELL)
closed = OrderClose(OrderTicket(), OrderLots(), Ask, InpSlippage, clrGray);
if(closed)
Print("Closed trade #", OrderTicket(), " by time limit (Held ", barsHeld, " bars).");
}
}
}
}
}