Problem Description
Solution
Here is a complete, fully functional Expert Advisor (EA) for MetaTrader 4 based on the Force Index indicator.
Strategy Logic
This algorithm uses a classic trend-following approach combined with the Force Index for entry timing.
- Trend Filter: It uses a 200-period Exponential Moving Average (EMA).
- Bullish: Price is above the 200 EMA.
- Bearish: Price is below the 200 EMA.
- Entry Signal (Force Index):
- Buy: Trend is Bullish AND Force Index crosses above the Zero line.
- Sell: Trend is Bearish AND Force Index crosses below the Zero line.
- Risk Management: Includes Stop Loss, Take Profit, and a Trailing Stop to lock in profits.
MQL4 Code
//+------------------------------------------------------------------+
//| ForceIndexStrategy.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 StrategySettings = "--- Strategy Settings ---";
input int MagicNumber = 123456; // Unique ID for this EA
input double LotSize = 0.1; // Fixed Lot Size
input int Slippage = 3; // Max Slippage in pips
input string IndicatorSettings = "--- Indicator Settings ---";
input int ForcePeriod = 13; // Force Index Period
input ENUM_MA_METHOD ForceMethod = MODE_EMA; // Force Index Smoothing Method
input ENUM_APPLIED_PRICE ForcePrice = PRICE_CLOSE; // Force Index Applied Price
input int TrendMAPeriod = 200; // Trend Filter MA Period
input string RiskSettings = "--- Risk Management ---";
input int StopLoss = 50; // Stop Loss in pips (0 = none)
input int TakeProfit = 100; // Take Profit in pips (0 = none)
input bool UseTrailing = true; // Enable Trailing Stop
input int TrailingStop = 30; // Trailing Stop distance in pips
input int TrailingStep = 5; // Trailing Step in pips
//--- Global Variables
double pipValue;
int pipMultiplier;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust pips for 3/5 digit brokers
if(Digits == 3 || Digits == 5)
{
pipMultiplier = 10;
pipValue = Point * 10;
}
else
{
pipMultiplier = 1;
pipValue = Point;
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if we have open orders for this symbol/magic number
if(CountOpenTrades() == 0)
{
// 2. Calculate Indicator Values
// We look at closed bars (index 1 and 2) to avoid repainting
double fi1 = iForce(NULL, 0, ForcePeriod, ForceMethod, ForcePrice, 1); // Previous bar
double fi2 = iForce(NULL, 0, ForcePeriod, ForceMethod, ForcePrice, 2); // Bar before previous
double maTrend = iMA(NULL, 0, TrendMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double closePrice = iClose(NULL, 0, 1);
// 3. Check Buy Conditions
// Trend is UP (Price > MA) AND Force Index crosses 0 from below
if(closePrice > maTrend && fi2 <= 0 && fi1 > 0)
{
OpenTrade(OP_BUY);
}
// 4. Check Sell Conditions
// Trend is DOWN (Price < MA) AND Force Index crosses 0 from above
else if(closePrice < maTrend && fi2 >= 0 && fi1 < 0)
{
OpenTrade(OP_SELL);
}
}
else
{
// 5. Manage Open Trades (Trailing Stop)
if(UseTrailing) ManageTrailingStop();
}
}
//+------------------------------------------------------------------+
//| Function to Open Trades |
//+------------------------------------------------------------------+
void OpenTrade(int type)
{
double sl = 0, tp = 0;
double price = 0;
color cmdColor = clrNONE;
if(type == OP_BUY)
{
price = Ask;
if(StopLoss > 0) sl = price - (StopLoss * pipValue);
if(TakeProfit > 0) tp = price + (TakeProfit * pipValue);
cmdColor = clrBlue;
}
else if(type == OP_SELL)
{
price = Bid;
if(StopLoss > 0) sl = price + (StopLoss * pipValue);
if(TakeProfit > 0) tp = price - (TakeProfit * pipValue);
cmdColor = clrRed;
}
int ticket = OrderSend(Symbol(), type, LotSize, price, Slippage * pipMultiplier, sl, tp, "ForceIndex EA", MagicNumber, 0, cmdColor);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Function to 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() == MagicNumber)
{
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Function to Manage Trailing Stop |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
// Buy Order Trailing
if(OrderType() == OP_BUY)
{
if(Bid - OrderOpenPrice() > TrailingStop * pipValue)
{
if(OrderStopLoss() < Bid - (TrailingStop * pipValue))
{
// Only modify if the change is larger than the step
if(Bid - (TrailingStop * pipValue) - OrderStopLoss() >= TrailingStep * pipValue || OrderStopLoss() == 0)
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(Bid - (TrailingStop * pipValue), Digits), OrderTakeProfit(), 0, clrGreen))
Print("Error modifying Buy Trailing Stop: ", GetLastError());
}
}
}
}
// Sell Order Trailing
else if(OrderType() == OP_SELL)
{
if(OrderOpenPrice() - Ask > TrailingStop * pipValue)
{
if(OrderStopLoss() > Ask + (TrailingStop * pipValue) || OrderStopLoss() == 0)
{
// Only modify if the change is larger than the step
if(OrderStopLoss() - (Ask + (TrailingStop * pipValue)) >= TrailingStep * pipValue || OrderStopLoss() == 0)
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(Ask + (TrailingStop * pipValue), Digits), OrderTakeProfit(), 0, clrGreen))
Print("Error modifying Sell Trailing Stop: ", GetLastError());
}
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
How to Install and Run
- Open MetaTrader 4.
- Press
F4to open the MetaEditor. - Click New -> Expert Advisor (template) -> Name it "ForceIndexStrategy".
- Delete everything in the new file and paste the code provided above.
- Press
F7to Compile. Ensure there are no errors in the "Errors" tab at the bottom. - Go back to the main MT4 window.
- Find "ForceIndexStrategy" in the Navigator panel under Expert Advisors.
- Drag it onto a chart (e.g., EURUSD H1).
- Ensure the "Allow live trading" checkbox is ticked in the Common tab.
Q&A: Force Index Strategy
Q: Why is a Moving Average (MA) included in this code?
A: The Force Index is a very sensitive oscillator. Using it alone often generates false signals during choppy markets. The 200-period EMA acts as a "regime filter," ensuring you only take Buy signals when the long-term trend is up, and Sell signals when the trend is down.
Q: Does this EA work on 5-digit brokers?
A: Yes. The OnInit function automatically detects if the broker uses 3 or 5 decimal places (points) and adjusts the pipValue variable accordingly. This ensures that a 50 pip Stop Loss is calculated correctly as 500 points on a 5-digit broker.
Q: Why does the code use iForce(..., 1) and iForce(..., 2) instead of 0?
A: Index 0 represents the current, forming bar. The data on this bar changes with every tick (repainting). To ensure the signal is valid and permanent, the EA checks indices 1 (the last closed bar) and 2 (the bar before that) to confirm a crossover has actually completed.
Q: Can I optimize the parameters?
A: Yes. You can use the MT4 Strategy Tester (Ctrl+R) to optimize inputs like ForcePeriod, StopLoss, and TakeProfit. A common variation is changing the ForcePeriod to 2 for short-term scalping or keeping it at 13 for standard swing trading.