When I make videos about writing experts or indicators I usually make them for both MQL4 and MQL5. This naturally leads to some code that has to be conditional due to the differences. The conditional code that bothers me most is the difference in the way technical indicators are handled and I think dealing with the difference makes the videos more complicated.

I decided to create a toolbox, starting with the technical indicators, that would allow me to mostly write indicators and experts without worrying about the 4/5 differences.

This video introduces a base class to handle the inbuilt technical indicators and 2 child classes, MA and MACD.

Here is the code for the CIndicatorBase class used in the tutorial

/*

	IndicatorBase.mqh
	Copyright 2021, Orchard Forex 
	https://orchardforex.com 

*/

#property copyright "Copyright 2021, Orchard Forex"
#property link      "https://orchardforex.com"
#property version   "1.00"

class CIndicatorBase {

private:

protected:

	//	Values used by MQL4
	string	mSymbol;
	int		mTimeframe;

	//	Handle and buffer used by MQL5	
	int		mHandle;
	double	mBuffer[];

public:

   CIndicatorBase();
   ~CIndicatorBase();
   
   bool		IsValid()	{	return(mHandle!=INVALID_HANDLE);	}
	int		GetArray(int bufferNumber, int start, int count, double &arr[]);	//	Retrieve an array of values
	virtual double	GetValue(int bufferNumber, int index);								//	Retrieve a single value
	virtual double	GetValue(int index)	{	return(GetValue(0,index));	}			//	Some indicators have only 1 buffer

   
};

CIndicatorBase::CIndicatorBase() {

	//	child classes will set the handle
	mHandle	=	0;
	ArraySetAsSeries(mBuffer, true);
	
}

CIndicatorBase::~CIndicatorBase() {

	#ifdef __MQL5__
		IndicatorRelease(mHandle);
	#endif 
	
}

#ifdef __MQL4__

	//	Just a blank function for the base class
	double	CIndicatorBase::GetValue(int bufferNumber, int index) {
		return(0);
	}

	//	For mql4 we have to build up the array from individual calls
	int		CIndicatorBase::GetArray(int bufferNumber,int start,int count,double &arr[]) {
	
		ArraySetAsSeries(arr, true);
		ArrayResize(arr, count);
		for (int i=0; i<count; i++) {
			arr[i]	=	GetValue(bufferNumber, i+start);
		}
		return(count);
		
	}

#endif

#ifdef __MQL5__

	//	In mql5 get the array first then pull a single value
	//	Could be done by calling GetArray but there is no need
	double	CIndicatorBase::GetValue(int bufferNumber, int index) {
	
		int	result	=	CopyBuffer(mHandle, bufferNumber, index, 1, mBuffer);
		if (result<1) return(0);
		return(mBuffer[0]);
		
	}

	//	For mql5 the array is the natural return	
	int		CIndicatorBase::GetArray(int bufferNumber,int start,int count,double &arr[]) {
	
		ArraySetAsSeries(arr, true);
		int	result	=	CopyBuffer(mHandle, bufferNumber, start, count, arr);
		return(result);
		
	}

#endif

This is the MACD class which can be used as a template for other indicator classes

/*

	IndicatorMACD.mqh
	Copyright 2021, Orchard Forex 
	https://orchardforex.com 

*/

#property copyright "Copyright 2021, Orchard Forex"
#property link      "https://orchardforex.com"
#property version   "1.00"

#include "IndicatorBase.mqh"

/*
	CIndicatorMACD
	Usage: CIndicatorMACD MACD = new CIndicatorMACD(symbol, timeframe, fastPeriod, slowPeriod, signalPeriod, appliedPrice)
*/
class CIndicatorMACD : public CIndicatorBase {

private:

protected:

	int	mFastPeriod;
	int	mSlowPeriod;
	int	mSignalPeriod;
	int	mAppliedPrice;
	
public:

	CIndicatorMACD(string symbol, int timeframe, int fastPeriod, int slowPeriod, int signalPeriod, int appliedPrice);
	~CIndicatorMACD();
	
	#ifdef __MQL4__
		double	GetValue(int bufferNumber, int index);
	#endif
	
};

CIndicatorMACD::CIndicatorMACD(string symbol, int timeframe, int fastPeriod, int slowPeriod, int signalPeriod, int appliedPrice)
		: CIndicatorBase() {

	//	Only needed for mql4 but no harm for mql5
	mSymbol			=	symbol;
	mTimeframe		=	timeframe;
	mFastPeriod	=	fastPeriod;
	mSlowPeriod	=	slowPeriod;
	mSignalPeriod	=	signalPeriod;
	mAppliedPrice	=	appliedPrice;
	
	#ifdef __MQL5__
		mHandle	=	iMACD(symbol, (ENUM_TIMEFRAMES)timeframe, fastPeriod, slowPeriod, signalPeriod, appliedPrice);
	#endif
	
}

CIndicatorMACD::~CIndicatorMACD() {
}

#ifdef __MQL4__
	double	CIndicatorMACD::GetValue(int bufferNumber, int index) {
		double	result	=	iMACD(mSymbol, mTimeframe, mFastPeriod, mSlowPeriod, mSignalPeriod, mAppliedPrice, bufferNumber, index);
		return(result);
	}
#endif 


This Post Has 3 Comments

  1. young chee

    hi, if i need my EA to trade only once per candle like when it reaches 10 points above / below open[0], how can i make that function because the newbar() function only work at the beginning of new candle not on my condition.

  2. Anil Varma

    Hi
    How can I get a premium membership? How much is it cost / month and what are the benefits I will get from it ?
    I am trying to look at the Subscription button, but it does not open any links for membership.
    Thanks

    1. ajm

      The button to subscribe to premium membership is on the page https://orchardforex.com/orchard-forex-discord/
      That page also describes the subscription cost and what we offer.
      If the upgrade button is not working (perhaps a popup blocker or similar) use https://upgrade.chat/orchard-forex-server

Leave a Reply