This is an example of writing an expert advisor using a very basic strategy. The key information here is the comparison of 2 indicators which occur at different times.

The strategy and detail about the code are explained fully in the video.

This covers both MT4 and MT5, there are some sections that are modified between MT4 and MT5.

Begin by using the wizard to create the expert outline.

For MQL5 begin by including the CTrade and CPositionInfo classes and create variables to use them

#include <Trade/Trade.mqh>
CTrade			Trade;
CPositionInfo	PositionInfo;

Then add inputs for the CCI and moving averages and the basic information for the expert. This is common between MQL4 and MQL5.

//	CCI Inputs
input	int						InpCCIPeriod		=	14;      		// CCI Period
input	ENUM_APPLIED_PRICE	InpCCIPrice			=	PRICE_CLOSE;	//	CCI Applied price

//	Fast MA Inputs
input	int						InpFastMAPeriods	=	14;       		// Fast MA periods
input	ENUM_MA_METHOD			InpFastMAMethod	=	MODE_EMA;		//	Fast MA Method
input	ENUM_APPLIED_PRICE	InpFastMAPrice		=	PRICE_CLOSE;	//	Fast MA Price

//	Slow MA Inputs
input	int						InpSlowMAPeriods	=	28;       		// Slow MA periods
input	ENUM_MA_METHOD			InpSlowMAMethod	=	MODE_EMA;		//	Slow MA Method
input	ENUM_APPLIED_PRICE	InpSlowMAPrice		=	PRICE_CLOSE;	//	Slow MA Price

//	Standard trading inputs
input	double					InpVolume			=	0.01;				//	Volume
input	int						InpMagicNumber		=	212121;			//	Magic Number
input	string					InpTradeComment	=	"CCI2MA";		//	Trade comment

Now for MQL5 add handles and buffers for the CCI and 2 moving average indicators.

// Indicator handles and buffers
int		HandleFastMA;
int		HandleSlowMA;
int		HandleCCI;

double	BufferFastMA[];
double	BufferSlowMA[];
double	BufferCCI[];

Also only for MQL5 add the following inside the OnInit section to initialise the indicator handles, set the buffers as series, and add the magic number to the Trade object

	HandleFastMA	=	iMA(Symbol(), Period(), InpFastMAPeriods, 0, InpFastMAMethod, InpFastMAPrice);
	HandleSlowMA	=	iMA(Symbol(), Period(), InpSlowMAPeriods, 0, InpSlowMAMethod, InpSlowMAPrice);
	HandleCCI		=	iCCI(Symbol(), Period(), InpCCIPeriod, InpCCIPrice);
	
	if (HandleFastMA==INVALID_HANDLE || HandleSlowMA==INVALID_HANDLE || HandleCCI==INVALID_HANDLE) {
		Print("Failed to initialise indicator buffers");
		return(INIT_FAILED);
	}
	
	ArraySetAsSeries(BufferFastMA, true);
	ArraySetAsSeries(BufferSlowMA, true);
	ArraySetAsSeries(BufferCCI, true);
	
	Trade.SetExpertMagicNumber(InpMagicNumber);

and also for MQL5 remove the handles in the OnDeinit function

	IndicatorRelease(HandleFastMA);
	IndicatorRelease(HandleSlowMA);
	IndicatorRelease(HandleCCI);

For both MQL4 and MQL5 add the NewBar, SymbolAsk and SymbolBid functions. I mention them here because they will be used in the OnTick section next but I also keep them at the end of the code because they are trivial utility functions

bool	NewBar() {

   static datetime	current	=	0;
   datetime				now		=	iTime(Symbol(), Period(), 0);
   if (now == current)	return(false);
   current	=	now;
   return(true);

}

double	SymbolAsk()							{	return(SymbolInfoDouble(Symbol(), SYMBOL_ASK));	}
double	SymbolBid()							{	return(SymbolInfoDouble(Symbol(), SYMBOL_BID));	}

Back to the OnTick function, the structure is the same for MQL4 and MQL5 but there are differences in the way the indicator values are retrieved. First for MQL4

void OnTick() {

	if (!(bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return;
	
	static int	maCross	=	0;
	static int	cciCross	=	0;
	
   bool	newBar	=	NewBar();

   if (newBar)	{
   	double	cci1		=	iCCI(Symbol(), Period(), InpCCIPeriod, InpCCIPrice, 1);
   	double	cci2		=	iCCI(Symbol(), Period(), InpCCIPeriod, InpCCIPrice, 2);
   	
      if (cci1>0 && cci2<=0)	cciCross	=	1;
      if (cci1<0 && cci2>=0)	cciCross	=	-1;

      double	fastMa1	=	iMA(Symbol(), Period(), InpFastMAPeriods, 0, InpFastMAMethod, InpFastMAPrice, 1);
      double	fastMa2	=	iMA(Symbol(), Period(), InpFastMAPeriods, 0, InpFastMAMethod, InpFastMAPrice, 2);
      double	slowMa1	=	iMA(Symbol(), Period(), InpSlowMAPeriods, 0, InpSlowMAMethod, InpSlowMAPrice, 1);
      double	slowMa2	=	iMA(Symbol(), Period(), InpSlowMAPeriods, 0, InpSlowMAMethod, InpSlowMAPrice, 2);

      if (fastMa1>slowMa1 && fastMa2<=slowMa2) {
      	maCross	=	1;
      	CloseTrades(ORDER_TYPE_SELL);
      }
      
      if (fastMa1<slowMa1 && fastMa2>=slowMa2) {
      	maCross	=	-1;
      	CloseTrades(ORDER_TYPE_BUY);
      }

		if (maCross!=0 && maCross==cciCross) {
			if (OpenTrade(maCross)>0) {
				maCross	=	0;
				cciCross	=	0;
	      }
	   }

   }

}

and now the MQL5 version

void OnTick() {

	if (!(bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return;
	
	static int	maCross	=	0;
	static int	cciCross	=	0;
	
   bool	newBar	=	NewBar();

   if (newBar)	{
   	CopyBuffer(HandleCCI, 0, 0, 3, BufferCCI);
   	double	cci1		=	BufferCCI[1];
   	double	cci2		=	BufferCCI[2];
   	
      if (cci1>0 && cci2<=0)	cciCross	=	1;
      if (cci1<0 && cci2>=0)	cciCross	=	-1;

		CopyBuffer(HandleFastMA, 0, 0, 3, BufferFastMA);
		CopyBuffer(HandleSlowMA, 0, 0, 3, BufferSlowMA);
      double	fastMa1	=	BufferFastMA[1];
      double	fastMa2	=	BufferFastMA[2];
      double	slowMa1	=	BufferSlowMA[1];
      double	slowMa2	=	BufferSlowMA[2];

      if (fastMa1>slowMa1 && fastMa2<=slowMa2) {
      	maCross	=	1;
      	CloseTrades(POSITION_TYPE_SELL);
      }
      
      if (fastMa1<slowMa1 && fastMa2>=slowMa2) {
      	maCross	=	-1;
      	CloseTrades(POSITION_TYPE_BUY);
      }

		if (maCross!=0 && maCross==cciCross) {
			if (OpenTrade(maCross)>0) {
				maCross	=	0;
				cciCross	=	0;
	      }
	   }

   }

}

In MQL5 the indicators are already established so the code is to retrieve the values into the buffer arrays and get the needed values there

That completes the expert except for the 2 functions Close Trades and OpenTrade

For MQL4

bool	CloseTrades(ENUM_ORDER_TYPE type) {

	bool		result			=	true;
	double	closingPrice	=	(type==ORDER_TYPE_BUY) ? SymbolBid() : SymbolAsk();
	
   int	cnt					=	OrdersTotal();
   for(int i = cnt - 1; i >= 0; i--) {

      if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
      	result	=	false;
      	continue;
      }
      if (OrderSymbol()!=Symbol() || OrderMagicNumber()!=InpMagicNumber)	continue;

      if ( OrderType()==type) {
         result	&=	OrderClose(OrderTicket(), OrderLots(), closingPrice, 0);
      }

   }
   
   return(result);
   
}

int	OpenTrade(int maCross) {

   if ( maCross<0 ) {
		return(OrderSend(Symbol(), ORDER_TYPE_SELL, InpVolume, SymbolBid(), 0, 0, 0, InpTradeComment, InpMagicNumber));
	}

   if ( maCross>0 ) {
      return(OrderSend(Symbol(), ORDER_TYPE_BUY, InpVolume, SymbolAsk(), 0, 0, 0, InpTradeComment, InpMagicNumber));
   }
   
   return(0);

}

and for MQL5

bool	CloseTrades(ENUM_POSITION_TYPE type) {

	bool		result			=	true;
	
   int	cnt					=	PositionsTotal();
   for(int i = cnt - 1; i >= 0; i--) {

		ulong	ticket	=	PositionGetTicket(i);
		if (ticket<=0) {
      	result	=	false;
      	continue;
      }
      if (PositionInfo.Symbol()!=Symbol() || PositionInfo.Magic()!=InpMagicNumber)	continue;

      if (PositionInfo.PositionType()==type) {
      	result	&=	Trade.PositionClose(ticket);
      }

   }
   
   return(result);
   
}

bool	OpenTrade(int maCross) {

   if ( maCross<0 ) {
		return(Trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, InpVolume, SymbolBid(), 0, 0, InpTradeComment));
	}

   if ( maCross>0 ) {
		return(Trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, InpVolume, SymbolAsk(), 0, 0, InpTradeComment));
   }
   
   return(true);

}

 

Leave a Reply