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
