Generate code in 3 minutes
Enter your idea and AI generates runnable code.
Here is a complete, robust, and well-commented MQL4 trading strategy based on the Momentum Indicator.
This Expert Advisor (EA) uses a classic Momentum crossover strategy filtered by a Moving Average to determine the trend direction.
//+------------------------------------------------------------------+
//| MomentumStrategy.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input string StrategySettings = "--- Strategy Settings ---";
input double LotSize = 0.1; // Fixed Lot Size
input int MomentumPeriod = 14; // Period for Momentum Indicator
input int MAPeriod = 50; // Period for Trend Filter (SMA)
input int StopLoss = 50; // Stop Loss in pips
input int TakeProfit = 100; // Take Profit in pips
input int TrailingStop = 30; // Trailing Stop in pips (0 to disable)
input int MagicNumber = 123456; // Unique ID for this EA
input int Slippage = 3; // Max slippage allowed
//--- Global Variables
double pPoint; // Adjusted point value for 3/5 digit brokers
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust point for 5-digit brokers (0.00001) vs 4-digit (0.0001)
if(Digits == 3 || Digits == 5) pPoint = Point * 10;
else pPoint = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check for Open Orders and Manage Trailing Stop
if(OrdersTotal() > 0)
{
ManageTrailingStop();
}
// 2. Check if we already have a position open for this symbol/magic number
if(CountTrades() > 0) return; // We only allow one trade at a time per chart
// 3. Define Indicator Values
// We use shift 1 (previous closed bar) and shift 2 to detect the crossover
// This prevents "repainting" issues on the current forming bar
// Momentum Values
double momCurrent = iMomentum(NULL, 0, MomentumPeriod, PRICE_CLOSE, 1);
double momPrevious = iMomentum(NULL, 0, MomentumPeriod, PRICE_CLOSE, 2);
// Moving Average Value (Trend Filter)
double maValue = iMA(NULL, 0, MAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
// Previous Close Price (to compare with MA)
double closePrice = iClose(NULL, 0, 1);
// 4. Trading Logic
// --- BUY SIGNAL ---
// Momentum crosses UP over 100 AND Price is ABOVE Moving Average
if(momPrevious < 100 && momCurrent > 100 && closePrice > maValue)
{
double sl = Ask - (StopLoss * pPoint);
double tp = Ask + (TakeProfit * pPoint);
// Send Order
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, Slippage, sl, tp, "MomBuy", MagicNumber, 0, clrGreen);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
// --- SELL SIGNAL ---
// Momentum crosses DOWN under 100 AND Price is BELOW Moving Average
if(momPrevious > 100 && momCurrent < 100 && closePrice < maValue)
{
double sl = Bid + (StopLoss * pPoint);
double tp = Bid - (TakeProfit * pPoint);
// Send Order
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, Slippage, sl, tp, "MomSell", MagicNumber, 0, clrRed);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Helper: Count open trades for this EA |
//+------------------------------------------------------------------+
int CountTrades()
{
int count = 0;
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 || OrderType() == OP_SELL)
count++;
}
}
}
return(count);
}
//+------------------------------------------------------------------+
//| Helper: Manage Trailing Stop |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
if(TrailingStop == 0) return; // Exit if disabled
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
// Logic for BUY orders
if(OrderType() == OP_BUY)
{
// If price has moved in our favor by TrailingStop amount
if(Bid - OrderOpenPrice() > TrailingStop * pPoint)
{
// If current SL is lower than (Bid - TrailingStop), move it up
if(OrderStopLoss() < Bid - (TrailingStop * pPoint))
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), Bid - (TrailingStop * pPoint), OrderTakeProfit(), 0, clrBlue))
Print("Error modifying Buy Trailing Stop: ", GetLastError());
}
}
}
// Logic for SELL orders
if(OrderType() == OP_SELL)
{
// If price has moved in our favor by TrailingStop amount
if(OrderOpenPrice() - Ask > TrailingStop * pPoint)
{
// If current SL is higher than (Ask + TrailingStop) or is 0, move it down
if(OrderStopLoss() > Ask + (TrailingStop * pPoint) || OrderStopLoss() == 0)
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), Ask + (TrailingStop * pPoint), OrderTakeProfit(), 0, clrBlue))
Print("Error modifying Sell Trailing Stop: ", GetLastError());
}
}
}
}
}
}
}
F4 to open the MetaEditor.MomentumStrategy and click Next/Finish.F7 or click Compile. Ensure there are no errors in the "Errors" tab at the bottom.MomentumStrategy in the Navigator panel under "Expert Advisors".iMA) to ensure you aren't buying into a downtrend or selling into an uptrend.shift 1) against the bar before that (shift 2). This ensures the signal is confirmed by a closed candle, preventing the signal from flickering (repainting).Q: Why do we use shift 1 and shift 2 instead of shift 0?
A: shift 0 refers to the current candle, which is still forming. The Momentum value can jump above and below 100 multiple times before the candle closes. Using shift 1 ensures we only trade based on confirmed, closed candles.
Q: What is the standard level for the Momentum indicator?
A: The standard centerline for Momentum in MetaTrader 4 is 100. Values above 100 indicate price is higher than it was n periods ago (uptrend momentum), and values below 100 indicate the opposite.
Q: Can I optimize the parameters?
A: Yes. Because we defined the variables (like MomentumPeriod, StopLoss, MAPeriod) as input, you can use the MT4 Strategy Tester to run optimizations and find the best settings for specific currency pairs.
Q: How does the Trailing Stop work in this code?
A: The trailing stop activates immediately. If you set it to 30 pips, once the price moves 31 pips in profit, the Stop Loss will move to +1 pip profit. It will continue to follow the price at a distance of 30 pips.