Problem Description
Solution
Here is a complete, fully functional Expert Advisor (EA) for MetaTrader 4 that implements the Awesome Oscillator (AO) Zero-Line Cross strategy.
Strategy Logic
- Indicator: Awesome Oscillator (Standard Bill Williams settings: 34 SMA - 5 SMA).
- Buy Signal: The AO histogram crosses from below the zero line to above the zero line.
- Sell Signal: The AO histogram crosses from above the zero line to below the zero line.
- Execution: The strategy checks values on closed bars (Bar 1 and Bar 2) to ensure the signal is confirmed and does not "repaint" during the current candle.
MQL4 Code
//+------------------------------------------------------------------+
//| Awesome_ZeroCross_EA.mq4 |
//| Copyright 2023, MetaQuotes |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative Trading AI"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input double InpLots = 0.1; // Lot Size
input int InpStopLoss = 50; // Stop Loss in pips (0 = none)
input int InpTakeProfit = 100; // Take Profit in pips (0 = none)
input int InpMagicNumber = 889977; // Magic Number to identify orders
input int InpSlippage = 3; // Maximum Slippage in pips
//--- Global Variables
double m_adjusted_point;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust points for 3/5 digit brokers
if(Digits == 3 || Digits == 5)
m_adjusted_point = Point * 10;
else
m_adjusted_point = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// We only trade on a new bar open to ensure the signal is confirmed
static datetime last_bar_time = 0;
if(Time[0] == last_bar_time) return; // Same bar, exit
last_bar_time = Time[0];
//--- 1. Get Awesome Oscillator Data
// We check Bar 1 (previous closed candle) and Bar 2 (candle before that)
double ao_curr = iAO(NULL, 0, 1); // Value of closed bar
double ao_prev = iAO(NULL, 0, 2); // Value of bar before closed bar
//--- 2. Check for Buy Signal (Cross from Negative to Positive)
if(ao_prev < 0 && ao_curr > 0)
{
// Close existing Sell positions first (Reversal logic)
ClosePositions(OP_SELL);
// Check if we already have a Buy open
if(CountOrders(OP_BUY) == 0)
{
OpenTrade(OP_BUY);
}
}
//--- 3. Check for Sell Signal (Cross from Positive to Negative)
if(ao_prev > 0 && ao_curr < 0)
{
// Close existing Buy positions first (Reversal logic)
ClosePositions(OP_BUY);
// Check if we already have a Sell open
if(CountOrders(OP_SELL) == 0)
{
OpenTrade(OP_SELL);
}
}
}
//+------------------------------------------------------------------+
//| Helper: Open a Trade |
//+------------------------------------------------------------------+
void OpenTrade(int type)
{
double price, sl, tp;
color cmd_color;
if(type == OP_BUY)
{
price = Ask;
sl = (InpStopLoss > 0) ? price - InpStopLoss * m_adjusted_point : 0;
tp = (InpTakeProfit > 0) ? price + InpTakeProfit * m_adjusted_point : 0;
cmd_color = clrBlue;
}
else // OP_SELL
{
price = Bid;
sl = (InpStopLoss > 0) ? price + InpStopLoss * m_adjusted_point : 0;
tp = (InpTakeProfit > 0) ? price - InpTakeProfit * m_adjusted_point : 0;
cmd_color = clrRed;
}
// Normalize prices
price = NormalizeDouble(price, Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), type, InpLots, price, InpSlippage, sl, tp, "AO Zero Cross", InpMagicNumber, 0, cmd_color);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Helper: Close positions of specific type |
//+------------------------------------------------------------------+
void ClosePositions(int type)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
if(OrderType() == type)
{
bool result = false;
if(type == OP_BUY)
result = OrderClose(OrderTicket(), OrderLots(), Bid, InpSlippage, clrRed);
else if(type == OP_SELL)
result = OrderClose(OrderTicket(), OrderLots(), Ask, InpSlippage, clrBlue);
if(!result) Print("OrderClose failed: ", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
//| Helper: Count open orders of specific type |
//+------------------------------------------------------------------+
int CountOrders(int type)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
if(OrderType() == type) count++;
}
}
}
return(count);
}
//+------------------------------------------------------------------+
How to Install and Run
- Open MetaTrader 4.
- Press
F4to open the MetaEditor. - Click New -> Expert Advisor (template) -> Name it
Awesome_ZeroCross. - Delete everything in the new file and paste the code above.
- Press
F7to Compile. Ensure there are no errors. - Go back to the MT4 Terminal, find the EA in the Navigator window, and drag it onto a chart.
Key Features of This Code
- New Bar Logic: The code uses
static datetime last_bar_timeto ensure it only calculates and trades once per candle. This prevents the EA from opening multiple trades on the same signal tick and ensures the AO signal is "locked in." - 5-Digit Broker Support: The
m_adjusted_pointlogic automatically detects if your broker uses 5 decimal places (points) or 4 (pips) and adjusts the Stop Loss and Take Profit calculations accordingly. - Reversal Logic: If a Buy signal appears while a Sell trade is open, the EA will close the Sell trade immediately before opening the Buy trade. This keeps you in sync with the market momentum.
- Risk Management: Inputs for Stop Loss and Take Profit allow you to define your risk per trade.
Q&A: Awesome Oscillator Strategy
Q: Why do we use iAO(NULL, 0, 1) and iAO(NULL, 0, 2)?
A: In MQL4, index 0 is the current forming candle. Index 1 is the last completed candle. To confirm a "cross," we need to see that the bar before the last one (index 2) was on one side of the zero line, and the last completed bar (index 1) is on the other side.
Q: Can I use this on any timeframe?
A: Yes. The iAO function uses 0 as the timeframe parameter, which means "Current Timeframe." If you attach this EA to an H1 chart, it calculates based on H1 data. If you attach it to M15, it uses M15 data.
Q: What happens if I set StopLoss to 0?
A: The code checks if(InpStopLoss > 0). If you set it to 0, the order will be sent without a hard Stop Loss attached to the broker order. The trade will only close when a reversal signal occurs (the opposite cross).
Q: Does this strategy work in ranging markets?
A: The AO Zero-Line cross is a momentum strategy. Like most trend-following indicators, it performs well in trending markets but may generate false signals (whipsaws) in sideways/ranging markets. You might consider adding a filter (like a Moving Average) to only take Buy crosses when price is above the MA.