//+------------------------------------------------------------------+
//| EA MQ5.mq5 |
//| Copyright 2024,SMFX Investments LTD |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024,SMFX Investments LTD"
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
//| Inputs |
//+------------------------------------------------------------------+
static input long InpMagicnumber = 837462; // magic number
static input double InpLotSize = 0.01; // lot size
input int InpPeriod = 21; // period
input double InpDeviation = 2.0; // deviation
input int InpRSIPeriod = 21; // rsi period
input int InpRSILevel = 70; // rsi level (upper)
input int InpMAPeriod = 21; // ma period
input ENUM_TIMEFRAMES InpMATimeframe = PERIOD_H1; // ma timeframe
input int InpStoploss = 100; // stoploss in points (0=off)
input int InpTakeProfit = 200; // take profit in points (0=off)
input bool InpCloseSignal = false; // close trades by opposite signal
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
int handle;
int handleRSI;
int handleMA;
double upperBuffer[];
double baseBuffer[];
double lowerBuffer[];
double bufferRSI[];
double bufferMA[];
MqlTick currentTick;
CTrade trade;
datetime OpenTimeBuy = 0;
datetime OpenTimeSell = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
// check inputs
if(InpMagicnumber<=0) {
Alert("Magicnumber <= 0");
return INIT_PARAMETERS_INCORRECT;
if(InpLotSize<=0 || InpLotSize>10) {
Alert("Lot size <= 0 or >10");
return INIT_PARAMETERS_INCORRECT;
if(InpPeriod<=1) {
Alert("Period <= 1");
return INIT_PARAMETERS_INCORRECT;
}
if(InpDeviation<=0) {
Alert("DEVIATION <= 0");
return INIT_PARAMETERS_INCORRECT;
if(InpRSIPeriod<=1) {
Alert("RSI period <= 1");
return INIT_PARAMETERS_INCORRECT;
if(InpRSILevel>=100 || InpRSILevel<=50) {
Alert("RSI level >= 100 or <= 50");
return INIT_PARAMETERS_INCORRECT;
if(InpMAPeriod<=1) {
Alert("MA period <= 1");
return INIT_PARAMETERS_INCORRECT;
if(InpStoploss<0) {
Alert("Stop loss < 0");
return INIT_PARAMETERS_INCORRECT;
if(InpTakeProfit<0) {
Alert("Take profit < 0");
return INIT_PARAMETERS_INCORRECT;
// set magicnumber to trade object
trade.SetExpertMagicNumber(InpMagicnumber);
// create indicator handles
handle = iBands(_Symbol,PERIOD_CURRENT,InpPeriod,1,InpDeviation,PRICE_CLOSE);
if(handle == INVALID_HANDLE) {
Alert("Failed to create indicator handle");
return INIT_FAILED;
handleRSI = iRSI(_Symbol,PERIOD_CURRENT,InpRSIPeriod,PRICE_OPEN);
if(handleRSI == INVALID_HANDLE) {
Alert("Failed to create indicator handleRSI");
return INIT_FAILED;
handleMA = iMA(_Symbol,InpMATimeframe,InpMAPeriod,0,MODE_SMA,PRICE_OPEN);
if(handleMA == INVALID_HANDLE) {
Alert("Failed to create indicator handleMA");
return INIT_FAILED;
// set buffers as series
ArraySetAsSeries(upperBuffer,true);
ArraySetAsSeries(baseBuffer,true);
ArraySetAsSeries(lowerBuffer,true);
ArraySetAsSeries(bufferRSI,true);
ArraySetAsSeries(bufferMA,true);
return(INIT_SUCCEEDED);
//+-----------------------------------------------------------------+
//| Expert deinitialization function |
//+-----------------------------------------------------------------+
void OnDeinit(const int reason) {
//release indicator handle
if(handle!=INVALID_HANDLE) {IndicatorRelease(handle);}
if(handleRSI!=INVALID_HANDLE) {IndicatorRelease(handleRSI);}
if(handleMA!=INVALID_HANDLE) {IndicatorRelease(handleMA);}
//+-----------------------------------------------------------------+
//| Expert tick function |
//+-----------------------------------------------------------------+
void OnTick() {
// check if current tick is a new bar open tick
if(!IsNewBar()) {return;}
// get current tick
if(!SymbolInfoTick(_Symbol,currentTick)) {
Print("Failed to get current tick");
return;
// get indicator values
int values = CopyBuffer(handle,0,0,1,baseBuffer)
+ CopyBuffer(handle,1,0,1,upperBuffer)
+ CopyBuffer(handle,2,0,1,lowerBuffer);
if(values!=3) {
Print("Failed to get indicator values");
return;
Comment("up[0]:",upperBuffer[0],
"\nbase[0]:",baseBuffer[0],
"\nlow[0]:",lowerBuffer[0]);
// count open positions
int countBuy, countSell;
if(!CountOpenPositions(countBuy,countSell)) {return;}
//check for lower band cross to open a buy position
if(countBuy==0 && currentTick.ask<=lowerBuffer[0] && OpenTimeBuy!
=iTime(_Symbol,PERIOD_CURRENT,0)) {
OpenTimeBuy = iTime(_Symbol,PERIOD_CURRENT,0);
double sl = currentTick.bid - InpStoploss * _Point;
double tp = InpTakeProfit==0 ? 0 : currentTick.bid + InpTakeProfit * _Point;
if(!NormalizePrice(sl,sl)) {return;}
if(!NormalizePrice(tp,tp)) {return;}
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,InpLotSize,currentTick.ask,sl,tp,"Bollinger band
EA");
// check for upper band cross to open a sell position
if(countSell==0 && currentTick.bid>=upperBuffer[0] && OpenTimeSell!
=iTime(_Symbol,PERIOD_CURRENT,0)) {
OpenTimeSell = iTime(_Symbol,PERIOD_CURRENT,0);
double sl = currentTick.ask + InpStoploss * _Point;
double tp = InpTakeProfit==0 ? 0 : currentTick.ask - InpTakeProfit * _Point;
if(!NormalizePrice(sl,sl)) {return;}
if(!NormalizePrice(tp,tp)) {return;}
trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,InpLotSize,currentTick.bid,sl,tp,"Bollinger band
EA");
// check for close at cross with base band
if(!CountOpenPositions(countBuy,countSell)) {return;}
if(countBuy>0 && currentTick.bid>=baseBuffer[0]) {ClosePositions(1);}
if(countSell>0 && currentTick.ask<=baseBuffer[0]) {ClosePositions(2);}
// get rsi values
values = CopyBuffer(handleRSI,0,0,2,bufferRSI);
if(values!=2) {
Print("Failed to get rsi values");
return;
// get ma value
values = CopyBuffer(handleMA,0,0,1,bufferMA);
if(values!=1) {
Print("Failed to get ma value");
return;
Comment("bufferRSI[0]:",bufferRSI[0],
"\nbufferRSI[1]:",bufferRSI[1],
"\nbufferMA[0]:",bufferMA[0]);
// count open positions
if(!CountOpenPositions(countBuy,countSell)) {return;}
// check for buy position
if(countBuy==0 && bufferRSI[1]>=(100-InpRSILevel) && bufferRSI[0]<(100-InpRSILevel) &&
currentTick.ask>bufferMA[0]) {
if(InpCloseSignal) {if(!ClosePositions(2)) {return;}}
double sl = InpStoploss==0 ? 0 : currentTick.bid - InpStoploss * _Point;
double tp = InpTakeProfit==0 ? 0 : currentTick.bid + InpTakeProfit * _Point;
if(!NormalizePrice(sl,sl)) {return;}
if(!NormalizePrice(tp,tp)) {return;}
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,InpLotSize,currentTick.ask,sl,tp,"RSI MA filter
EA");
}
// check for sell position
if(countSell==0 && bufferRSI[1]<=InpRSILevel && bufferRSI[0]>InpRSILevel &&
currentTick.bid<bufferMA[0]) {
if(InpCloseSignal) {if(!ClosePositions(1)) {return;}}
double sl = InpStoploss==0 ? 0 : currentTick.ask + InpStoploss * _Point;
double tp = InpTakeProfit==0 ? 0 : currentTick.ask - InpTakeProfit * _Point;
if(!NormalizePrice(sl,sl)) {return;}
if(!NormalizePrice(tp,tp)) {return;}
trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,InpLotSize,currentTick.bid,sl,tp,"RSI MA filter
EA");
//+-------------------------------------------------------------------+
//| Custom functions |
//+-------------------------------------------------------------------+
// check if we have a bar open tick
bool IsNewBar() {
static datetime previousTime = 0;
datetime currentTime = iTime(_Symbol,PERIOD_CURRENT,0);
if(previousTime!=currentTime) {
previousTime=currentTime;
return true;
return false;
// count open positions
bool CountOpenPositions(int &countBuy, int &countSell) {
countBuy = 0;
countSell = 0;
int total = PositionsTotal();
for(int i=total-1; i>=0; i--) {
ulong positionTicket = PositionGetTicket(i);
if(positionTicket<=0) {
Print("Failed to get position ticket");
return false;
if(!PositionSelectByTicket(positionTicket)) {
Print("Failed to select position");
return false;
long magic;
if(!PositionGetInteger(POSITION_MAGIC,magic)) {
Print("Failed to get position magicnumber");
return false;
if(magic==InpMagicnumber) {
long type;
if(!PositionGetInteger(POSITION_TYPE,type)) {
Print("Failed to get position type");
return false;
if(type==POSITION_TYPE_BUY) {countBuy++;}
if(type==POSITION_TYPE_SELL) {countSell++;}
return true;
// normalize price
bool NormalizePrice(double &price, double &normalizedPrice) {
double tickSize=0;
if(!SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE,tickSize)) {
Print("Failed to get tick size");
return false;
normalizedPrice = NormalizeDouble(MathRound(price/tickSize)*tickSize,_Digits);
return true;
// close positions
bool ClosePositions(int all_buy_sell) {
int total = PositionsTotal();
for(int i=total-1; i>=0; i--) {
ulong positionTicket = PositionGetTicket(i);
if(positionTicket<=0) {
Print("Failed to get position ticket");
return false;
if(!PositionSelectByTicket(positionTicket)) {
Print("Failed to select position");
return false;
long magic;
if(!PositionGetInteger(POSITION_MAGIC,magic)) {
Print("Failed to get position magicnumber");
return false;
if(magic==InpMagicnumber) {
long type;
if(!PositionGetInteger(POSITION_TYPE,type)) {
Print("Failed to get position type");
return false;
if(all_buy_sell==1 && type==POSITION_TYPE_SELL) {continue;}
if(all_buy_sell==2 && type==POSITION_TYPE_BUY) {continue;}
trade.PositionClose(positionTicket);
if(trade.ResultRetcode() !=TRADE_RETCODE_DONE) {
Print("Failed to close position ticket:",(string)positionTicket,
" result:",(string)trade.ResultRetcode()+":",trade.ResultRetcode());
return false;
return true;