Problem Description
Solution
Here is a complete, fully functional Expert Advisor (EA) for MetaTrader 4 based on the Elder-Ray Impulse System. This strategy utilizes both Bulls Power and Bears Power indicators in conjunction with an Exponential Moving Average (EMA) to identify trend direction and entry points.
Strategy Logic
- Trend Identification: Uses a 13-period EMA.
- Uptrend: Price Close > EMA.
- Downtrend: Price Close < EMA.
- Buy Signal:
- Market is in an Uptrend.
- Bears Power is below zero (indicating a price dip/pullback).
- Bears Power is rising (current bar > previous bar), indicating sellers are losing strength.
- Sell Signal:
- Market is in a Downtrend.
- Bulls Power is above zero (indicating a price rally/pullback).
- Bulls Power is falling (current bar < previous bar), indicating buyers are losing strength.
MQL4 Code
//+------------------------------------------------------------------+
//| BullsBearsPower_Strategy.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 string Inp_Settings = "--- Strategy Settings ---"; // Strategy Settings
input int Inp_Period = 13; // Indicator Period (EMA, Bulls, Bears)
input double Inp_LotSize = 0.1; // Fixed Lot Size
input int Inp_StopLoss = 50; // Stop Loss (in pips)
input int Inp_TakeProfit = 100; // Take Profit (in pips)
input int Inp_MagicNum = 123456; // Magic Number
input int Inp_Slippage = 3; // Max Slippage (pips)
input bool Inp_UseTrailing = true; // Use Trailing Stop
input int Inp_TrailDist = 30; // Trailing Distance (pips)
//--- Global Variables
double m_point;
int m_digits;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust point for 3/5 digit brokers
if(Digits == 3 || Digits == 5)
{
m_point = Point * 10;
m_digits = Digits;
}
else
{
m_point = Point;
m_digits = Digits;
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Basic Checks
if(Bars < Inp_Period + 2) return; // Not enough history
if(!IsTradeAllowed()) return; // Trading not allowed
// 2. Manage Open Trades (Trailing Stop)
if(Inp_UseTrailing) ManageTrailingStop();
// 3. Check for New Entry Signals only if we have no open trades
// (Simple logic: one trade at a time per symbol/magic number)
if(CountOpenTrades() == 0)
{
// Get Indicator Values for Bar 1 (Closed Bar) and Bar 2 (Previous)
// We use closed bars to avoid repainting
// EMA for Trend Direction
double ema1 = iMA(NULL, 0, Inp_Period, 0, MODE_EMA, PRICE_CLOSE, 1);
// Bulls Power
double bulls1 = iBullsPower(NULL, 0, Inp_Period, PRICE_CLOSE, 1);
double bulls2 = iBullsPower(NULL, 0, Inp_Period, PRICE_CLOSE, 2);
// Bears Power
double bears1 = iBearsPower(NULL, 0, Inp_Period, PRICE_CLOSE, 1);
double bears2 = iBearsPower(NULL, 0, Inp_Period, PRICE_CLOSE, 2);
// Close Prices
double close1 = iClose(NULL, 0, 1);
// --- BUY SIGNAL LOGIC ---
// 1. Trend is UP (Close > EMA)
// 2. Bears Power is negative (Price dipped below EMA)
// 3. Bears Power is rising (bears1 > bears2) - Momentum turning up
if(close1 > ema1 && bears1 < 0 && bears1 > bears2)
{
OpenTrade(OP_BUY);
}
// --- SELL SIGNAL LOGIC ---
// 1. Trend is DOWN (Close < EMA)
// 2. Bulls Power is positive (Price rallied above EMA)
// 3. Bulls Power is falling (bulls1 < bulls2) - Momentum turning down
if(close1 < ema1 && bulls1 > 0 && bulls1 < bulls2)
{
OpenTrade(OP_SELL);
}
}
}
//+------------------------------------------------------------------+
//| Helper: Open Order |
//+------------------------------------------------------------------+
void OpenTrade(int type)
{
double price, sl, tp;
color clr;
if(type == OP_BUY)
{
price = Ask;
sl = (Inp_StopLoss > 0) ? price - Inp_StopLoss * m_point : 0;
tp = (Inp_TakeProfit > 0) ? price + Inp_TakeProfit * m_point : 0;
clr = clrBlue;
}
else
{
price = Bid;
sl = (Inp_StopLoss > 0) ? price + Inp_StopLoss * m_point : 0;
tp = (Inp_TakeProfit > 0) ? price - Inp_TakeProfit * m_point : 0;
clr = clrRed;
}
// Normalize prices
price = NormalizeDouble(price, Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), type, Inp_LotSize, price, Inp_Slippage, sl, tp, "BullsBears EA", Inp_MagicNum, 0, clr);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Helper: Count Open Trades for this EA |
//+------------------------------------------------------------------+
int CountOpenTrades()
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == Inp_MagicNum)
{
count++;
}
}
}
return(count);
}
//+------------------------------------------------------------------+
//| Helper: Trailing Stop Logic |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == Inp_MagicNum)
{
if(OrderType() == OP_BUY)
{
if(Bid - OrderOpenPrice() > Inp_TrailDist * m_point)
{
double newSL = NormalizeDouble(Bid - Inp_TrailDist * m_point, Digits);
if(newSL > OrderStopLoss())
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
Print("Error modifying Buy Trailing Stop: ", GetLastError());
}
}
}
else if(OrderType() == OP_SELL)
{
if(OrderOpenPrice() - Ask > Inp_TrailDist * m_point)
{
double newSL = NormalizeDouble(Ask + Inp_TrailDist * m_point, Digits);
if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
Print("Error modifying Sell Trailing Stop: ", GetLastError());
}
}
}
}
}
}
}
Q&A: Strategy Details
Q: Why are both Bulls Power and Bears Power used?
A: This strategy implements the "Elder-Ray" approach. The Bulls Power indicator measures the ability of buyers to push prices above the average consensus (EMA), while Bears Power measures the ability of sellers to push prices below it. Using both allows us to detect when the dominant market force (Trend) is temporarily weakening (Pullback) before resuming.
Q: Why does the code use shift 1 and shift 2 instead of 0?
A: In MQL4, index 0 represents the currently forming bar. The High, Low, and Close of the current bar change with every tick. If we trade based on index 0, the signal might appear and disappear within the same candle (repainting). Using index 1 ensures the candle has closed and the signal is confirmed and permanent.
Q: How does the Trailing Stop work in this code?
A: The trailing stop activates once the price moves in your favor by the Inp_TrailDist amount. It then moves the Stop Loss to maintain that distance behind the current price (Bid for Buys, Ask for Sells), locking in profits as the trend continues.
Q: Can I use this on any timeframe?
A: Yes, the logic is timeframe-independent. However, the Elder-Ray system is traditionally most effective on H1 (1-Hour) and D1 (Daily) charts. You may need to adjust Inp_StopLoss and Inp_TakeProfit depending on the volatility of the timeframe chosen.