Summary: EuroStable EA is a low-risk MQL4 expert advisor for EURUSD. It uses Bollinger Bands mean reversion with RSI filter and strict money management. Suitable for M15 timeframe.




EuroStable EA is designed specifically for EURUSD with a low-risk, stable operational approach. It uses Bollinger Bands (20,2) to identify mean reversion opportunities when price touches the outer band and RSI (14) confirms non-extreme conditions. Each trade has a fixed stop loss and take profit, with a daily equity protection and maximum spread filter. The EA trades only one position at a time and avoids news periods using a simple time filter.

Recommended Timeframe: M15
Trading Logic:
1. Bollinger Bands (20,2): Price touches upper band -> potential sell; touches lower band -> potential buy.
2. RSI(14) confirmation: For buy, RSI < 70; for sell, RSI > 30 (avoid overbought/oversold extremes).
3. Entry: Wait for price to close beyond the band, then enter on next bar open.
4. Risk Control: Fixed SL 25 pips, TP 40 pips. Max 1 trade at a time, daily loss limit 4%, max spread 20 points.

```mql4
//+------------------------------------------------------------------+
//| EuroStableEA.mq4 |
//| |
//| |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict

//--- input parameters with comments
input double LotSize = 0.01; // Fixed lot size (0.01 for EURUSD ~$1 per pip)
input int StopLossPips = 25; // Stop loss in pips (25 pips)
input int TakeProfitPips = 40; // Take profit in pips (risk-reward 1:1.6)
input int BandsPeriod = 20; // Bollinger Bands period
input double BandsDeviation = 2.0; // Bollinger Bands deviation multiplier
input int RSIPeriod = 14; // RSI period
input int RSIUpperThreshold= 70; // RSI upper threshold (sell signal below this when at upper band)
input int RSILowerThreshold= 30; // RSI lower threshold (buy signal above this when at lower band)
input int MagicNumber = 202412; // Unique EA identifier
input int MaxSpread = 20; // Maximum allowed spread (in points)
input double DailyLossLimit = 4.0; // Daily loss limit in percentage of balance (4%)
input bool UseTimeFilter = true; // Filter out high impact news times (13:30-15:30 GMT)
input int StartHourBlock = 13; // Block start hour (GMT)
input int EndHourBlock = 16; // Block end hour (GMT)

//--- global variables
double dailyStartBalance = 0;
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
dailyStartBalance = AccountBalance();
lastBarTime = 0;
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Daily equity protection
double currentEquity = AccountEquity();
double lossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance * 100;
if(lossPercent >= DailyLossLimit)
{
Comment("Daily loss limit reached. No new trades.");
return;
}

// Spread filter
if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
{
Comment("Spread too high: ", MarketInfo(Symbol(), MODE_SPREAD));
return;
}

// Time filter (avoid news)
if(UseTimeFilter)
{
datetime currentTime = TimeCurrent();
int currentHour = TimeHour(currentTime);
if(currentHour >= StartHourBlock && currentHour < EndHourBlock)
{
Comment("News time block. No new trades.");
return;
}
}

// New bar logic (M15)
if(Time[0] == lastBarTime)
return;
lastBarTime = Time[0];

// Check for existing position
if(CountPositions() > 0)
return;

// Get Bollinger Bands values on completed bar (index 1)
double upperBand = iBands(Symbol(), PERIOD_M15, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
double lowerBand = iBands(Symbol(), PERIOD_M15, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
double close1 = iClose(Symbol(), PERIOD_M15, 1);

// Get RSI value on completed bar
double rsi = iRSI(Symbol(), PERIOD_M15, RSIPeriod, PRICE_CLOSE, 1);

// Entry conditions
bool buySignal = false;
bool sellSignal = false;

// Price touches or closes below lower band -> potential buy
if(close1 <= lowerBand && rsi > RSILowerThreshold)
{
buySignal = true;
}
// Price touches or closes above upper band -> potential sell
else if(close1 >= upperBand && rsi < RSIUpperThreshold)
{
sellSignal = true;
}

double sl = 0, tp = 0;
int cmd = -1;

if(buySignal)
{
cmd = OP_BUY;
sl = SymbolInfoDouble(Symbol(), SYMBOL_BID) - StopLossPips * Point * 10; // 10 points per pip
tp = SymbolInfoDouble(Symbol(), SYMBOL_BID) + TakeProfitPips * Point * 10;
}
else if(sellSignal)
{
cmd = OP_SELL;
sl = SymbolInfoDouble(Symbol(), SYMBOL_ASK) + StopLossPips * Point * 10;
tp = SymbolInfoDouble(Symbol(), SYMBOL_ASK) - TakeProfitPips * Point * 10;
}

if(cmd != -1)
{
int ticket = OrderSend(Symbol(), cmd, LotSize, (cmd==OP_BUY?Ask:Bid), 3, sl, tp, "EuroStable EA", MagicNumber, 0, clrNONE);
if(ticket < 0)
Print("OrderSend failed: ", GetLastError());
}
}

//+------------------------------------------------------------------+
//| Count open positions with this MagicNumber |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
```
Reference: Original MQL4 code for educational purposes.
Disclaimer: Trading Forex involves substantial risk of loss. This EA is provided as-is without any guarantee. Test thoroughly on a demo account before live trading. Past performance does not guarantee future results.