Problem Description
Solution
Here is a complete, fully functional Expert Advisor (EA) for MetaTrader 4 written in MQL4.
I have selected the Commodity Channel Index (CCI) for this strategy, as it is the standard oscillator that utilizes the +100 and -100 levels specifically.
Strategy Logic
- Buy Signal: The CCI line crosses below the -100 level (Momentum/Breakout entry).
- Sell Signal: The CCI line crosses above the +100 level.
- Execution: The strategy checks for crosses on closed bars (Bar 1 and Bar 2) to prevent "repainting" signals where the indicator changes while the candle is still forming.
MQL4 Code
//+------------------------------------------------------------------+
//| CCI_Breakout_EA.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 InpLots = 0.1; // Lot size
input int InpStopLoss = 50; // Stop Loss in points (0 = no SL)
input int InpTakeProfit = 100; // Take Profit in points (0 = no TP)
input int InpMagicNumber = 12345; // Magic Number to identify orders
input int InpSlippage = 3; // Maximum slippage in points
//--- Oscillator Settings (CCI)
input int InpCCIPeriod = 14; // CCI Period
input int InpCCIPrice = PRICE_TYPICAL; // CCI Applied Price
input double InpLevelHigh = 100.0; // Upper Trigger Level
input double InpLevelLow = -100.0; // Lower Trigger Level
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Basic validation
if(InpCCIPeriod <= 0)
{
Print("Error: CCI Period must be greater than 0");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Cleanup if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if we are allowed to trade
if(!IsTradeAllowed() || IsStopped()) return;
// 2. Check if we already have an open position for this symbol and magic number
if(CountOpenPositions() > 0) return; // Simple logic: only one trade at a time
// 3. Calculate Indicator Values
// We look at Bar 1 (just closed) and Bar 2 (previous) to detect a confirmed cross
double cci_curr = iCCI(_Symbol, _Period, InpCCIPeriod, InpCCIPrice, 1);
double cci_prev = iCCI(_Symbol, _Period, InpCCIPeriod, InpCCIPrice, 2);
// 4. Check for Buy Signal (Cross Below -100)
// Logic: Previous value was ABOVE or EQUAL to -100, Current value is BELOW -100
if(cci_prev >= InpLevelLow && cci_curr < InpLevelLow)
{
OpenTrade(OP_BUY);
}
// 5. Check for Sell Signal (Cross Above +100)
// Logic: Previous value was BELOW or EQUAL to 100, Current value is ABOVE 100
if(cci_prev <= InpLevelHigh && cci_curr > InpLevelHigh)
{
OpenTrade(OP_SELL);
}
}
//+------------------------------------------------------------------+
//| Helper: Open a Trade |
//+------------------------------------------------------------------+
void OpenTrade(int type)
{
double price, sl, tp;
color clr;
if(type == OP_BUY)
{
price = Ask;
clr = clrBlue;
// Calculate SL/TP for Buy
double point = Point;
if(Digits == 3 || Digits == 5) point *= 10; // Adjust for 5-digit brokers
sl = (InpStopLoss > 0) ? price - InpStopLoss * point : 0;
tp = (InpTakeProfit > 0) ? price + InpTakeProfit * point : 0;
}
else // OP_SELL
{
price = Bid;
clr = clrRed;
// Calculate SL/TP for Sell
double point = Point;
if(Digits == 3 || Digits == 5) point *= 10; // Adjust for 5-digit brokers
sl = (InpStopLoss > 0) ? price + InpStopLoss * point : 0;
tp = (InpTakeProfit > 0) ? price - InpTakeProfit * point : 0;
}
// Normalize prices to prevent Error 130 (Invalid Stops)
price = NormalizeDouble(price, Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
// Send Order
int ticket = OrderSend(_Symbol, type, InpLots, price, InpSlippage, sl, tp, "CCI Cross Strategy", InpMagicNumber, 0, clr);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
else
{
Print("Order opened successfully. Ticket: ", ticket);
}
}
//+------------------------------------------------------------------+
//| Helper: Count Open Positions for this EA |
//+------------------------------------------------------------------+
int CountOpenPositions()
{
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() == OP_BUY || OrderType() == OP_SELL)
{
count++;
}
}
}
}
return count;
}
//+------------------------------------------------------------------+
How to Install and Use
- Open MetaTrader 4.
- Press F4 to open the MetaEditor.
- Click New -> Expert Advisor (template) -> Name it "CCI_Breakout".
- Delete everything in the new file and paste the code above.
- Press F7 or click Compile. Ensure there are no errors in the "Errors" tab at the bottom.
- Go back to the main MT4 window.
- Find "CCI_Breakout" in the Navigator panel under Expert Advisors.
- Drag it onto a chart.
Key Features of This Code
- Cross Detection: It uses
cci_prev(Bar 2) andcci_curr(Bar 1) to detect the exact moment the line crosses the level. This ensures the signal is confirmed (the candle is closed). - Risk Management: Includes inputs for Stop Loss and Take Profit.
- 5-Digit Broker Support: Automatically adjusts points calculation for brokers using 5 decimal places (e.g., EURUSD at 1.12345).
- Order Management: The
CountOpenPositionsfunction ensures the EA only opens one trade at a time per symbol to prevent over-trading.
Q&A: Strategy Details
Q: Why did you choose CCI?
A: The prompt specified levels of +100 and -100. The Commodity Channel Index (CCI) is the standard technical indicator designed specifically around these levels. RSI usually uses 30/70, and Stochastic uses 20/80.
Q: Can I use this for Mean Reversion (Buying when it crosses back UP above -100)?
A: The current code is a Momentum/Breakout logic (Buying as it plunges below -100). If you want a Mean Reversion strategy (Buying when it recovers from oversold), you simply need to swap the logic in the OnTick function:
- Change:
if(cci_prev < InpLevelLow && cci_curr >= InpLevelLow)for Buy. - Change:
if(cci_prev > InpLevelHigh && cci_curr <= InpLevelHigh)for Sell.
Q: Why does the EA not trade immediately?
A: The EA waits for a specific "Cross" event. If the CCI is already below -100 when you attach the EA, it will wait until it goes back above -100 and crosses down again before trading. This prevents entering stale signals.