Problem Description
Solution
To build a trading robot (Expert Advisor) using the Accumulation/Distribution (A/D) indicator, it is important to understand that A/D is primarily a volume-based trend confirmation tool. It is rarely used as a standalone trigger for entering trades.
A robust strategy usually combines a Trend Trigger (like a Moving Average crossover) with the A/D Indicator acting as a filter to confirm the volume supports the price movement.
The Strategy Logic
- Primary Trigger (Moving Average Crossover):
- Buy: Fast Moving Average crosses above Slow Moving Average.
- Sell: Fast Moving Average crosses below Slow Moving Average.
- Confirmation (Accumulation/Distribution):
- Buy Confirmation: The A/D line must be trending upwards (Current A/D > Previous A/D).
- Sell Confirmation: The A/D line must be trending downwards (Current A/D < Previous A/D).
- Risk Management:
- Fixed Stop Loss and Take Profit.
- One open trade at a time per symbol.
MQL4 Code Implementation
//+------------------------------------------------------------------+
//| AD_Trend_Confirm_Robot.mq4 |
//| Copyright 2023, Quantitative Trading AI |
//| 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 Lots = 0.1; // Trading volume
input int StopLoss = 50; // Stop Loss in pips
input int TakeProfit = 100; // Take Profit in pips
input int FastMAPeriod = 12; // Fast Moving Average Period
input int SlowMAPeriod = 26; // Slow Moving Average Period
input int MagicNumber = 123456; // Unique identifier for this EA
input int Slippage = 3; // Max slippage in pips
//--- Global Variables
double pipModifier;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust pips for 3 or 5 digit brokers (Jpy pairs vs others)
if(Digits == 3 || Digits == 5)
pipModifier = 10 * Point;
else
pipModifier = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if we already have an open position for this symbol
if(OrdersTotal() > 0)
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
return; // Exit if a trade is already active
}
}
}
// 2. Define Indicator Values
// Moving Averages (Shift 1 is the closed bar, Shift 2 is the bar before that)
double fastMA_Curr = iMA(NULL, 0, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double fastMA_Prev = iMA(NULL, 0, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 2);
double slowMA_Curr = iMA(NULL, 0, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowMA_Prev = iMA(NULL, 0, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 2);
// Accumulation/Distribution
double ad_Curr = iAD(NULL, 0, 1);
double ad_Prev = iAD(NULL, 0, 2);
// 3. Trading Logic
// BUY SIGNAL
// Logic: Fast MA crosses Above Slow MA AND A/D is rising
if(fastMA_Prev < slowMA_Prev && fastMA_Curr > slowMA_Curr)
{
if(ad_Curr > ad_Prev) // A/D Confirmation
{
OpenBuyOrder();
}
}
// SELL SIGNAL
// Logic: Fast MA crosses Below Slow MA AND A/D is falling
if(fastMA_Prev > slowMA_Prev && fastMA_Curr < slowMA_Curr)
{
if(ad_Curr < ad_Prev) // A/D Confirmation
{
OpenSellOrder();
}
}
}
//+------------------------------------------------------------------+
//| Function to Open Buy Order |
//+------------------------------------------------------------------+
void OpenBuyOrder()
{
double sl = 0, tp = 0;
if(StopLoss > 0) sl = Ask - (StopLoss * pipModifier);
if(TakeProfit > 0) tp = Ask + (TakeProfit * pipModifier);
int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, sl, tp, "AD Buy", MagicNumber, 0, clrGreen);
if(ticket < 0)
Print("OrderSend failed with error #", GetLastError());
}
//+------------------------------------------------------------------+
//| Function to Open Sell Order |
//+------------------------------------------------------------------+
void OpenSellOrder()
{
double sl = 0, tp = 0;
if(StopLoss > 0) sl = Bid + (StopLoss * pipModifier);
if(TakeProfit > 0) tp = Bid - (TakeProfit * pipModifier);
int ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, sl, tp, "AD Sell", MagicNumber, 0, clrRed);
if(ticket < 0)
Print("OrderSend failed with error #", GetLastError());
}
//+------------------------------------------------------------------+
Code Breakdown
-
Inputs:
FastMAPeriodandSlowMAPeriod: Define the sensitivity of the trend trigger.StopLossandTakeProfit: Standard risk management inputs defined in pips.
-
OnInit():
- Calculates
pipModifier. This ensures the Stop Loss and Take Profit are calculated correctly regardless of whether the broker uses 4-digit or 5-digit pricing (e.g., EURUSD at 1.1000 vs 1.10005).
- Calculates
-
OnTick() - The Main Logic:
- Order Check: The code loops through existing orders. If a trade with the specific
MagicNumberon the currentSymbolexists, the function returns immediately. This prevents the bot from opening multiple trades on the same signal. - Indicator Calculation:
iMA: Calculates the Moving Average. We retrieve values for shift1(the last closed candle) and shift2(the candle before that) to detect the "crossover" moment.iAD: Calculates the Accumulation/Distribution value.
- Signal Logic:
- Buy: We check if the Fast MA was previously below the Slow MA and is now above it (Crossover). We then check if
ad_Curr > ad_Prevto confirm that volume accumulation is supporting the move. - Sell: We check if the Fast MA was previously above the Slow MA and is now below it. We confirm this by checking if
ad_Curr < ad_Prev.
- Buy: We check if the Fast MA was previously below the Slow MA and is now above it (Crossover). We then check if
- Order Check: The code loops through existing orders. If a trade with the specific
-
Order Execution:
OpenBuyOrderandOpenSellOrderhandle the specificOrderSendcalls, calculating the correct SL and TP prices based on the current Ask/Bid prices.
How to Use This Robot
- Open MetaEditor in MT4 (Press F4).
- Create a new Expert Advisor, name it "AD_Trend_Confirm".
- Paste the code above into the file, replacing everything.
- Click Compile. Ensure there are no errors.
- Go back to the MT4 Terminal.
- Drag the EA from the Navigator onto a chart (e.g., EURUSD H1).
- Ensure "Allow Live Trading" is checked in the EA properties and the "AutoTrading" button at the top of MT4 is green.
Q&A: Quantitative Strategy Details
Q: Why use A/D instead of standard Volume?
A: Standard volume only tells you intensity. Accumulation/Distribution attempts to quantify the flow of money into or out of an asset by considering the close price relative to the high-low range. It provides a directional bias to the volume.
Q: Can I use A/D as the primary trigger?
A: It is not recommended. The A/D line is cumulative and unbounded. It does not oscillate between 0 and 100 like RSI. Therefore, it is difficult to define specific "overbought" or "oversold" levels to trigger a trade. It works best as a filter for price-action triggers.
Q: How can I reduce false signals with this bot?
A: Currently, the bot compares A/D of the current bar vs the previous bar. This can be noisy. To smooth this out, you could calculate a Moving Average of the A/D indicator itself and require the A/D line to be above its own Moving Average for a Buy, rather than just higher than the previous candle.