Problem Description
Solution
Here is a complete, fully functional Expert Advisor (trading robot) for MetaTrader 4 based on the Bill Williams Accelerator/Decelerator Oscillator (AC).
Strategy Logic
This robot implements a momentum-based strategy using the AC indicator:
- Buy Signal: The AC indicator rises for two consecutive closed bars (showing increasing upward momentum).
- Sell Signal: The AC indicator falls for two consecutive closed bars (showing increasing downward momentum).
- Risk Management: It uses fixed Stop Loss and Take Profit levels, plus a Trailing Stop to lock in profits as the price moves in your favor.
MQL4 Code
//+------------------------------------------------------------------+
//| AC_Trader_Bot.mq4 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI Assistant"
#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 = no SL)
input int InpTakeProfit = 100; // Take Profit in pips (0 = no TP)
input int InpTrailingStop = 30; // Trailing Stop in pips (0 = disabled)
input int InpMagicNumber = 12345; // Magic Number to identify orders
input int InpSlippage = 3; // Maximum slippage in pips
//--- Global Variables
double m_pips;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Adjust pip size for 3/5 digit brokers
if(Digits == 3 || Digits == 5)
m_pips = Point * 10;
else
m_pips = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- 1. Check if we have enough bars to calculate
if(Bars < 100) return;
//--- 2. Define AC values (Shift 1 is the last closed bar, Shift 2 is the one before)
// We use closed bars to avoid "repainting" signals during the current candle
double ac1 = iAC(NULL, 0, 1); // AC of previous bar
double ac2 = iAC(NULL, 0, 2); // AC of 2 bars ago
double ac3 = iAC(NULL, 0, 3); // AC of 3 bars ago
//--- 3. Check for Open Positions
int openBuy = 0;
int openSell = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
if(OrderType() == OP_BUY) openBuy++;
if(OrderType() == OP_SELL) openSell++;
// Manage Trailing Stop while looping through orders
ManageTrailingStop();
}
}
}
//--- 4. Signal Logic
// Buy: AC is rising for 2 consecutive bars (Green bars)
bool buySignal = (ac1 > ac2) && (ac2 > ac3);
// Sell: AC is falling for 2 consecutive bars (Red bars)
bool sellSignal = (ac1 < ac2) && (ac2 < ac3);
//--- 5. Execution Logic
// Only open a trade if no trade is currently open in that direction
// (Simple one-trade-at-a-time logic per direction)
if(buySignal && openBuy == 0)
{
// Close opposite Sell positions if you want a reversal strategy (Optional)
// CloseAllSell();
double sl = (InpStopLoss > 0) ? Ask - InpStopLoss * m_pips : 0;
double tp = (InpTakeProfit > 0) ? Ask + InpTakeProfit * m_pips : 0;
// Normalize prices
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), OP_BUY, InpLots, Ask, InpSlippage, sl, tp, "AC Buy", InpMagicNumber, 0, clrGreen);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
if(sellSignal && openSell == 0)
{
// Close opposite Buy positions if you want a reversal strategy (Optional)
// CloseAllBuy();
double sl = (InpStopLoss > 0) ? Bid + InpStopLoss * m_pips : 0;
double tp = (InpTakeProfit > 0) ? Bid - InpTakeProfit * m_pips : 0;
// Normalize prices
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), OP_SELL, InpLots, Bid, InpSlippage, sl, tp, "AC Sell", InpMagicNumber, 0, clrRed);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Function to manage Trailing Stop |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
if(InpTrailingStop == 0) return;
// Order must be selected before calling this function logic inside the loop
// However, for safety, we usually pass the ticket or assume OrderSelect is active.
// Since this is called inside the OnTick loop where OrderSelect is active:
if(OrderType() == OP_BUY)
{
if(Bid - OrderOpenPrice() > InpTrailingStop * m_pips)
{
if(OrderStopLoss() < Bid - InpTrailingStop * m_pips)
{
double newSL = NormalizeDouble(Bid - InpTrailingStop * m_pips, Digits);
if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
Print("Error modifying Buy Trailing Stop: ", GetLastError());
}
}
}
else if(OrderType() == OP_SELL)
{
if(OrderOpenPrice() - Ask > InpTrailingStop * m_pips)
{
if(OrderStopLoss() == 0 || OrderStopLoss() > Ask + InpTrailingStop * m_pips)
{
double newSL = NormalizeDouble(Ask + InpTrailingStop * m_pips, Digits);
if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
Print("Error modifying Sell Trailing Stop: ", GetLastError());
}
}
}
}
//+------------------------------------------------------------------+
How to Install and Run
- Open MetaEditor: In MT4, press
F4or click the "MetaEditor" button. - Create New File: Click
New->Expert Advisor (template)->Next. - Name It: Name it
AC_Traderand clickNext->Finish. - Paste Code: Delete everything in the new file and paste the code provided above.
- Compile: Press
F7or click the "Compile" button. Check the "Errors" tab at the bottom to ensure there are 0 errors. - Run: Go back to the MT4 terminal. Find
AC_Traderin the "Navigator" window under "Expert Advisors". Drag it onto a chart.
Key Features Explained
- iAC Function: The code uses
iAC(NULL, 0, shift)to get the Accelerator Oscillator value.NULLmeans the current symbol,0means the current timeframe. - Shift 1, 2, 3: We analyze bars 1, 2, and 3 (historical bars). We do not use bar 0 (the current forming candle) to generate signals. This prevents the robot from opening a trade and then having the signal disappear before the candle closes (repainting).
- 4/5 Digit Broker Support: The
OnInitfunction automatically detects if your broker uses 5 decimal places (e.g., EURUSD 1.12345) and adjusts the pip calculations accordingly so that50pips equals 500 points. - Trailing Stop: If the price moves in your favor by the amount specified in
InpTrailingStop, the Stop Loss will follow the price to lock in profit.
Q&A
Q: Can I use this on any timeframe?
A: Yes, the code uses 0 in the iAC function, which automatically adapts to whatever timeframe (M15, H1, D1) the chart is currently set to.
Q: Why does it check Bars < 100?
A: The AC indicator requires historical data to calculate correctly. This check prevents the EA from crashing or calculating wrong values if you load it on a chart that hasn't downloaded history yet.
Q: How do I optimize the settings?
A: In MT4, go to View -> Strategy Tester. Select AC_Trader, choose a symbol and timeframe, and click "Expert properties". You can then test different values for Stop Loss and Take Profit to see what works best for your specific currency pair.