# Dual Moving Average Crossover EA - MQL4 Source Code
Strategy Overview
This Expert Advisor (EA) implements a classic dual moving average crossover strategy, one of the most reliable trend-following systems in forex trading. When the fast moving average crosses above the slow moving average, a buy position is opened. When the fast crosses below the slow, a sell position is opened.
The EA is designed for MT4 (MetaTrader 4) and can be compiled directly in MetaEditor without any external dependencies.
Key Features
| Feature | Description |
|---------|-------------|
| Strategy Type | Trend-following (MA crossover) |
| Platform | MT4 (MQL4) |
| Trading Direction | Long and Short |
| Money Management | Fixed lot with optional stop loss/take profit |
| Customizable Parameters | Fast MA period, Slow MA period, Lot size, SL, TP |
Complete Source Code
Copy the code below, open MetaEditor in MT4 (Tools > MetaQuotes Language Editor), create a new Expert Advisor, and paste the code.
```mql4
//+------------------------------------------------------------------+
//| DualMACrossoverEA.mq4 |
//| |
//| |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict
// --- Input Parameters ---
input double LotSize = 0.1; // Lot size per trade
input int FastMAPeriod = 5; // Fast MA period
input int SlowMAPeriod = 20; // Slow MA period
input int MAPriceType = MODE_SMA; // MA type: MODE_SMA, MODE_EMA, etc.
input int StopLoss = 50; // Stop loss in points (0 = disabled)
input int TakeProfit = 100; // Take profit in points (0 = disabled)
input int MagicNumber = 12345; // Unique EA identifier
// --- Global Variables ---
double lastFastMA = 0;
double lastSlowMA = 0;
bool isBusy = false;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(FastMAPeriod >= SlowMAPeriod)
{
Print("Error: Fast MA period must be less than Slow MA period");
return(INIT_PARAMETERS_INCORRECT);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(isBusy) return;
isBusy = true;
// Calculate moving averages
double currentFastMA = iMA(NULL, 0, FastMAPeriod, 0, MAPriceType, PRICE_CLOSE, 1);
double currentSlowMA = iMA(NULL, 0, SlowMAPeriod, 0, MAPriceType, PRICE_CLOSE, 1);
double previousFastMA = iMA(NULL, 0, FastMAPeriod, 0, MAPriceType, PRICE_CLOSE, 2);
double previousSlowMA = iMA(NULL, 0, SlowMAPeriod, 0, MAPriceType, PRICE_CLOSE, 2);
// Check for existing positions with this MagicNumber
int totalPositions = OrdersTotal();
bool hasBuy = false;
bool hasSell = false;
for(int i = 0; i < totalPositions; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
if(OrderType() == OP_BUY) hasBuy = true;
if(OrderType() == OP_SELL) hasSell = true;
}
}
}
// --- Buy Signal: Fast MA crosses above Slow MA ---
if(previousFastMA <= previousSlowMA && currentFastMA > currentSlowMA)
{
if(!hasBuy)
{
CloseAllOrders(); // Close opposite positions first
OpenBuy();
}
}
// --- Sell Signal: Fast MA crosses below Slow MA ---
if(previousFastMA >= previousSlowMA && currentFastMA < currentSlowMA)
{
if(!hasSell)
{
CloseAllOrders();
OpenSell();
}
}
isBusy = false;
}
//+------------------------------------------------------------------+
//| Open buy position |
//+------------------------------------------------------------------+
void OpenBuy()
{
double slippage = 3;
double price = Ask;
double sl = (StopLoss > 0) ? price - StopLoss * Point : 0;
double tp = (TakeProfit > 0) ? price + TakeProfit * Point : 0;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, price, slippage, sl, tp, "MA Crossover Buy", MagicNumber, 0, clrGreen);
if(ticket < 0)
Print("Buy order failed: ", GetLastError());
else
Print("Buy order opened. Ticket: ", ticket);
}
//+------------------------------------------------------------------+
//| Open sell position |
//+------------------------------------------------------------------+
void OpenSell()
{
double slippage = 3;
double price = Bid;
double sl = (StopLoss > 0) ? price + StopLoss * Point : 0;
double tp = (TakeProfit > 0) ? price - TakeProfit * Point : 0;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, price, slippage, sl, tp, "MA Crossover Sell", MagicNumber, 0, clrRed);
if(ticket < 0)
Print("Sell order failed: ", GetLastError());
else
Print("Sell order opened. Ticket: ", ticket);
}
//+------------------------------------------------------------------+
//| Close all positions with this MagicNumber |
//+------------------------------------------------------------------+
void CloseAllOrders()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
bool closed = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrWhite);
if(!closed)
Print("Failed to close order ", OrderTicket(), ", Error: ", GetLastError());
}
}
}
}
//+------------------------------------------------------------------+
```
Parameter Explanation
| Parameter | Default | Description |
|-----------|---------|-------------|
| `LotSize` | 0.1 | Volume per trade. Adjust based on account balance (1% risk per trade recommended) |
| `FastMAPeriod` | 5 | Fast moving average period. Lower values increase sensitivity |
| `SlowMAPeriod` | 20 | Slow moving average period. Higher values filter noise |
| `MAPriceType` | MODE_SMA | MA calculation: MODE_SMA (simple), MODE_EMA (exponential), MODE_SMMA, MODE_LWMA |
| `StopLoss` | 50 | Stop loss in points (1 point = 0.0001 for 4-digit brokers) |
| `TakeProfit` | 100 | Take profit in points |
| `MagicNumber` | 12345 | Unique identifier to separate this EA's trades from manual trades |
How to Install and Test
1. Open MetaEditor: In MT4, press `F4` or go to Tools > MetaQuotes Language Editor
2. Create new EA: File > New > Expert Advisor > Next > Name it "DualMACrossover" > Finish
3. Paste the code: Replace all default code with the source above
4. Compile: Press `F7` or click the Compile button
5. Attach to chart: In MT4, drag the EA onto a chart (EURUSD or GBPUSD recommended)
6. Run backtest: Open Strategy Tester (Ctrl+R), select the EA, set date range, and click Start
Backtest Recommendations
Optimization Tips
1. Avoid curve-fitting: Optimize on 6 months of data, validate on the next 3 months
2. EMA for faster signals: Change `MODE_SMA` to `MODE_EMA` for more responsive crossovers
3. Add a filter: Consider adding an ADX filter (value > 25) to avoid ranging markets
Final Notes
This EA is intended for educational purposes. Always backtest thoroughly before live deployment. The strategy works best in trending markets and will generate losses during sideways consolidation.
Want more advanced EAs? Subscribe to our newsletter to receive weekly free source codes and exclusive access to our premium Gold trading EA.
---
References:
1. MQL5 Documentation – Technical Indicators (iMA)
2. MetaQuotes – MQL4 OrderSend Function Reference
3. Self-compiled source code for educational purposes