Initial commit

This commit is contained in:
Nkondog Anselme
2021-11-14 05:36:01 +01:00
commit 407a205132
69 changed files with 5946 additions and 0 deletions
@@ -0,0 +1,16 @@
/*
All.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
Auto Generated at 2021-07-10 17:11:59
*/
//
// Extension go here
//
#include "AllIndicators.mqh"
#include "AllSignals.mqh"
#include "AllTPSL.mqh"
@@ -0,0 +1,6 @@
//
// Extension go here
//
#include "GridSignals.mqh"
#include "GridTPSL.mqh"
#include "GlobalEnumDefinitions.mqh"
@@ -0,0 +1,16 @@
/*
All.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
Auto Generated at 2021-07-10 17:11:59
*/
//
// Extension go here
//
#include "Indicators/IndicatorATR.mqh"
#include "Indicators/IndicatorMA.mqh"
#include "Indicators/IndicatorTemplate.mqh"
@@ -0,0 +1,17 @@
/*
All.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
Auto Generated at 2021-07-10 17:11:59
*/
//
// Extension go here
//
#include "Signals/SignalCombination.mqh"
#include "Signals/SignalCrossover.mqh"
#include "Signals/SignalTemplate.mqh"
#include "Signals/SignalGrid.mqh"
@@ -0,0 +1,15 @@
/*
All.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
Auto Generated at 2021-07-10 17:11:59
*/
//
// Extension go here
//
#include "TPSL/TPSLSimple.mqh"
#include "TPSL/TPSLTemplate.mqh"
@@ -0,0 +1,29 @@
//+------------------------------------------------------------------+
//| GlobalEnumDefinitions.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
enum ENUM_TRADING_SESSION
{
LONDON_SESSION=1,
NEWYORK_SESSION=2,
TOKYO_SESSION=3,
};
//Enumerative for the default risk size
enum ENUM_RISK_DEFAULT_SIZE
{
RISK_DEFAULT_FIXED=1, //FIXED SIZE
RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK
};
//Enumerative for the base used for risk calculation
enum ENUM_RISK_BASE
{
RISK_BASE_EQUITY=1, //EQUITY
RISK_BASE_BALANCE=2, //BALANCE
RISK_BASE_FREEMARGIN=3, //FREE MARGIN
};
@@ -0,0 +1,5 @@
//
// Extension go here
//
#include "Signals/SignalGrid.mqh"
@@ -0,0 +1,4 @@
//
// Extension go here
//
#include "TPSL/GridTPSL.mqh"
@@ -0,0 +1,77 @@
/*
IndicatorATR.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../../Framework.mqh"
class CIndicatorATR : public CIndicatorBase {
private:
protected: // member variables
int mPeriods;
public: // constructors
CIndicatorATR(int periods)
: CIndicatorBase()
{ Init(periods); }
CIndicatorATR(string symbol, ENUM_TIMEFRAMES timeframe,
int periods)
: CIndicatorBase(symbol, timeframe)
{ Init(periods); }
~CIndicatorATR();
virtual int Init(int periods);
public:
virtual double GetData(const int buffer_num,const int index);
};
CIndicatorATR::~CIndicatorATR() {
}
int CIndicatorATR::Init(int periods) {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mPeriods = periods;
#ifdef __MQL5__
mIndicatorHandle = iATR(mSymbol, mTimeframe, mPeriods);
if (mIndicatorHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED));
#endif
return(INIT_SUCCEEDED);
}
double CIndicatorATR::GetData(const int buffer_num,const int index) {
double value = 0;
#ifdef __MQL4__
value = iATR(mSymbol, mTimeframe, mPeriods, index);
#endif
#ifdef __MQL5__
double bufferData[];
ArraySetAsSeries(bufferData, true);
int cnt = CopyBuffer(mIndicatorHandle, buffer_num, index, 1, bufferData);
if (cnt>0) value = bufferData[0];
#endif
return(value);
}
@@ -0,0 +1,82 @@
/*
IndicatorMA.mqh
Updated - requires version 2.01 or later
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../../Framework.mqh"
class CIndicatorMA : public CIndicatorBase {
private:
protected: // member variables
int mPeriods;
int mShift;
ENUM_MA_METHOD mMethod;
ENUM_APPLIED_PRICE mAppliedPrice;
public: // constructors
CIndicatorMA(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice)
: CIndicatorBase()
{ Init(periods, shift, method, appliedPrice); }
CIndicatorMA(string symbol, ENUM_TIMEFRAMES timeframe,
int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice)
: CIndicatorBase(symbol, timeframe)
{ Init(periods, shift, method, appliedPrice); }
~CIndicatorMA();
virtual int Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice);
public:
virtual double GetData(const int buffer_num,const int index);
};
CIndicatorMA::~CIndicatorMA() {
}
int CIndicatorMA::Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mPeriods = periods;
mShift = shift;
mMethod = method;
mAppliedPrice = appliedPrice;
#ifdef __MQL5__
mIndicatorHandle = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice);
if (mIndicatorHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED));
#endif
return(INIT_SUCCEEDED);
}
double CIndicatorMA::GetData(const int buffer_num,const int index) {
double value = 0;
#ifdef __MQL4__
value = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice, index);
#endif
#ifdef __MQL5__
double bufferData[];
ArraySetAsSeries(bufferData, true);
int cnt = CopyBuffer(mIndicatorHandle, buffer_num, index, 1, bufferData);
if (cnt>0) value = bufferData[0];
#endif
return(value);
}
@@ -0,0 +1,91 @@
/*
IndicatorTemplate.mqh
Updated as of framework version 2.02
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
#include "../../Framework.mqh"
class CIndicatorTemplate : public CIndicatorBase {
private:
protected: // member variables
// Place any required member variables here
public: // constructors
// Add any required constructor arguments
// e.g. CIndicatorXYZ(int periods, double multiplier)
CIndicatorTemplate()
: CIndicatorBase()
{ Init(); }
// Same constructor with symbol and timeframe added
CIndicatorTemplate(string symbol, ENUM_TIMEFRAMES timeframe)
: CIndicatorBase(symbol, timeframe)
{ Init(); }
~CIndicatorTemplate();
// Include all arguments to match the constructor
virtual int Init();
public:
// Add this line to override the same function from the parent class
virtual double GetData(const int buffer_num,const int index);
};
CIndicatorTemplate::~CIndicatorTemplate() {
// Any destructors here
}
int CIndicatorTemplate::Init() {
// Checks if init has been set to fail by any parent class already
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
// Assign variables and do any other initialisation here
#ifdef __MQL5__
// Just using iMA as an example here, replace as necessary
// mIndicatorHandle = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice);
// if (mIndicatorHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED));
#endif
return(INIT_SUCCEEDED);
}
double CIndicatorTemplate::GetData(const int buffer_num,const int index) {
double value = 0;
#ifdef __MQL4__
// Next line is just an example using iMA
// value = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice, index);
#endif
#ifdef __MQL5__
// For MQL5 once indicator handle is set the code here should be common
// Declare a buffer to hold the data being retrieved
double bufferData[];
// Set as series so the sequence matches the chrt
ArraySetAsSeries(bufferData, true);
// Copy indicator data into the buffer and get the count of elements
int cnt = CopyBuffer(mIndicatorHandle, buffer_num, index, 1, bufferData);
// If not enough elements came back then don't use the data
if (cnt>0) value = bufferData[0];
#endif
return(value);
}
@@ -0,0 +1,86 @@
/*
SignalCombination.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../../Framework.mqh"
class CSignalCombination : public CSignalBase {
private:
protected: // member variables
CSignalBase *mSignals[];
public: // constructors
CSignalCombination(string symbol, ENUM_TIMEFRAMES timeframe)
: CSignalBase(symbol, timeframe)
{ Init(); }
CSignalCombination()
: CSignalBase()
{ Init(); }
~CSignalCombination() { }
int Init();
public:
virtual void AddSignal(CSignalBase *signal);
virtual void UpdateSignal();
};
int CSignalCombination::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
ArrayResize(mSignals, 0);
return(INIT_SUCCEEDED);
}
void CSignalCombination::UpdateSignal() {
int index = ArraySize(mSignals);
if (index<=0) {
mEntrySignal = OFX_SIGNAL_NONE;
mExitSignal = OFX_SIGNAL_NONE;
} else {
mSignals[0].UpdateSignal();
mEntrySignal = mSignals[0].EntrySignal();
mExitSignal = mSignals[0].ExitSignal();
for (int i = 1; i<index; i++) {
mSignals[i].UpdateSignal();
if (mSignals[i].EntrySignal()!=mEntrySignal) mEntrySignal = OFX_SIGNAL_NONE;
if (mSignals[i].ExitSignal()!=mExitSignal) mExitSignal = OFX_SIGNAL_NONE;
}
}
return;
}
void CSignalCombination::AddSignal(CSignalBase *signal) {
int index = ArraySize(mSignals);
ArrayResize(mSignals, index+1);
mSignals[index] = signal;
}
@@ -0,0 +1,78 @@
/*
SignalCrossover.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../../Framework.mqh"
class CSignalCrossover : public CSignalBase {
private:
protected: // member variables
int mIndex1;
int mIndex2;
public: // constructors
CSignalCrossover(string symbol, ENUM_TIMEFRAMES timeframe,
int index1=1, int index2=2)
: CSignalBase(symbol, timeframe)
{ Init(index1, index2); }
CSignalCrossover(int index1=1, int index2=2)
: CSignalBase()
{ Init(index1, index2); }
~CSignalCrossover() { }
int Init(int index1, int index2);
public:
virtual void UpdateSignal();
};
int CSignalCrossover::Init(int index1, int index2) {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mIndex1 = index1;
mIndex2 = index2;
return(INIT_SUCCEEDED);
}
void CSignalCrossover::UpdateSignal() {
double fast1 = GetIndicatorData(0, mIndex1);
double fast2 = GetIndicatorData(0, mIndex2);
double slow1 = GetIndicatorData(1, mIndex1);
double slow2 = GetIndicatorData(1, mIndex2);
// There is a less common condition where the fast
// indicator touches the slow indicator and then
// reverses. With the conditions below this would
// appear like a cross.
if ( (fast1>slow1) && !(fast2>slow2) ) { // Crossed up
mEntrySignal = OFX_SIGNAL_BUY;
mExitSignal = OFX_SIGNAL_SELL;
} else
if ( (fast1<slow1) && !(fast2<slow2) ) { // Crossed down
mEntrySignal = OFX_SIGNAL_SELL;
mExitSignal = OFX_SIGNAL_BUY;
} else {
mEntrySignal = OFX_SIGNAL_NONE;
mExitSignal = OFX_SIGNAL_NONE;
}
return;
}
@@ -0,0 +1,79 @@
//+------------------------------------------------------------------+
//| SignalGrid.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
#include "../../GridFramework.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CSignalGrid : public CSignalBase
{
private:
protected: // member variables
// Place any required member variables here
int m_magic;
public: // constructors
// Add any required constructor arguments
// e.g. CSignalXYZ(int periods, double multiplier)
CSignalGrid()
: CSignalBase()
{ Init(); }
// Same constructor with symbol and timeframe added
CSignalGrid(string symbol, ENUM_TIMEFRAMES timeframe)
: CSignalBase(symbol, timeframe)
{ Init(); }
~CSignalGrid() { }
// Include all arguments to match the constructor
int Init();
public:
// Add this line to override the same function from the parent class
virtual void UpdateSignal();
virtual void setMmagic(int magic) {m_magic = magic;}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CSignalGrid::Init()
{
// Checks if init has been set to fail by any parent class already
if(InitResult()!=INIT_SUCCEEDED)
return(InitResult());
// Assign variables and do any other initialisation here
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSignalGrid::UpdateSignal()
{
// Just gather data from the indicators and
// decide on a trade direction
// This is the trade decision logic
//CSignalBase signal = new CSignalBase();
}
//+------------------------------------------------------------------+
@@ -0,0 +1,68 @@
/*
SignalTemplate.mqh
Updated as of framework version 2.02
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
#include "../../Framework.mqh"
class CSignalTemplate : public CSignalBase {
private:
protected: // member variables
// Place any required member variables here
public: // constructors
// Add any required constructor arguments
// e.g. CSignalXYZ(int periods, double multiplier)
CSignalTemplate()
: CSignalBase()
{ Init(); }
// Same constructor with symbol and timeframe added
CSignalTemplate(string symbol, ENUM_TIMEFRAMES timeframe)
: CSignalBase(symbol, timeframe)
{ Init(); }
~CSignalTemplate() { }
// Include all arguments to match the constructor
int Init();
public:
// Add this line to override the same function from the parent class
virtual void UpdateSignal();
};
int CSignalTemplate::Init() {
// Checks if init has been set to fail by any parent class already
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
// Assign variables and do any other initialisation here
return(INIT_SUCCEEDED);
}
void CSignalTemplate::UpdateSignal() {
// Just gather data from the indicators and
// decide on a trade direction
// This is the trade decision logic
mExitSignal = OFX_SIGNAL_NONE; // This strategy has no exit signal
// Just set the buy or sell signals now
return;
}
@@ -0,0 +1,57 @@
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
#include "../../Framework.mqh"
class GridTPSL : public CTPSLBase {
private:
double GetValue();
protected: // member variables
// Place any required member variables here
public: // constructors
// Add any required constructor arguments
// e.g. CTPSLXYZ(int periods, double multiplier)
GridTPSL() : CTPSLBase() { Init(); }
// Same constructor with symbol and timeframe added
GridTPSL(string symbol, ENUM_TIMEFRAMES timeframe)
: CTPSLBase(symbol, timeframe) { Init(); }
~GridTPSL() { }
int Init();
public:
// Get and Set functions for additional parameters
// Override these from the parent class to get required values
// GetValue here is just an example
virtual double GetTakeProfit() { return(GetValue()); }
virtual double GetStopLoss() { return(GetValue()); }
};
int GridTPSL::Init() {
// Checks if init has been set to fail by any parent class already
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
// Assign variables and do any other initialisation here
return(INIT_SUCCEEDED);
}
// A simple example of a value function
double GridTPSL::GetValue() {
// Pulls data from an assigned indicator number 0 for bar 1 and multiplies by 2
double value = 0;//GetIndicatorData(0, 1)*2;
return(value);
}
@@ -0,0 +1,62 @@
/*
TPSLSimple.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../../Framework.mqh"
class CTPSLSimple : public CTPSLBase {
private:
double GetValue();
protected: // member variables
double mMultiplier;
int mIndex;
public: // constructors
CTPSLSimple() : CTPSLBase() { Init(); }
CTPSLSimple(string symbol, ENUM_TIMEFRAMES timeframe)
: CTPSLBase(symbol, timeframe) { Init(); }
~CTPSLSimple() { }
int Init();
public:
virtual void SetIndex(int index) { mIndex = index; }
virtual double GetIndex() { return(mIndex); }
virtual void SetMultiplier(double multiplier) { mMultiplier = multiplier; }
virtual double GetMultiplier() { return(mMultiplier); }
virtual double GetTakeProfit() { return(GetValue()); }
virtual double GetStopLoss() { return(GetValue()); }
};
int CTPSLSimple::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mMultiplier = 1.0;
return(INIT_SUCCEEDED);
}
double CTPSLSimple::GetValue() {
double value = 0;//GetIndicatorData(0, mIndex)*mMultiplier;
return(value);
}
@@ -0,0 +1,67 @@
/*
TPSLTemplate.mqh
Updated as of framework version 2.02
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
// Next line assumes this file is located in .../Frameworks/Extensions/someFolder
#include "../../Framework.mqh"
class CTPSLTemplate : public CTPSLBase {
private:
double GetValue();
protected: // member variables
// Place any required member variables here
public: // constructors
// Add any required constructor arguments
// e.g. CTPSLXYZ(int periods, double multiplier)
CTPSLTemplate() : CTPSLBase() { Init(); }
// Same constructor with symbol and timeframe added
CTPSLTemplate(string symbol, ENUM_TIMEFRAMES timeframe)
: CTPSLBase(symbol, timeframe) { Init(); }
~CTPSLTemplate() { }
int Init();
public:
// Get and Set functions for additional parameters
// Override these from the parent class to get required values
// GetValue here is just an example
virtual double GetTakeProfit() { return(GetValue()); }
virtual double GetStopLoss() { return(GetValue()); }
};
int CTPSLTemplate::Init() {
// Checks if init has been set to fail by any parent class already
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
// Assign variables and do any other initialisation here
return(INIT_SUCCEEDED);
}
// A simple example of a value function
double CTPSLTemplate::GetValue() {
// Pulls data from an assigned indicator number 0 for bar 1 and multiplies by 2
double value = 0;//GetIndicatorData(0, 1)*2;
return(value);
}
+21
View File
@@ -0,0 +1,21 @@
/*
Framework.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
//
// The only purpose of this mqh file is to provide a single
// point to change the current framework version
//
// If you place an include to this file in your code you
// will get the version framework defined in this file
// unless your code has already included another
// framework file
#ifndef _FRAMEWORK_VERSION_
#include "Framework_2.04/Framework.mqh"
#endif
@@ -0,0 +1,71 @@
/*
CommonBase.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
class CCommonBase {
private:
protected: // Members
int mDigits;
string mSymbol;
ENUM_TIMEFRAMES mTimeframe;
string mInitMessage;
int mInitResult;
protected: // Constructors
//
// Constructors
//
CCommonBase() { Init(_Symbol, (ENUM_TIMEFRAMES)_Period); }
CCommonBase(string symbol) { Init(symbol, (ENUM_TIMEFRAMES)_Period); }
CCommonBase(int timeframe) { Init(_Symbol, (ENUM_TIMEFRAMES)timeframe); }
CCommonBase(ENUM_TIMEFRAMES timeframe) { Init(_Symbol, timeframe); }
CCommonBase(string symbol, int timeframe) { Init(symbol, (ENUM_TIMEFRAMES)timeframe); }
CCommonBase(string symbol, ENUM_TIMEFRAMES timeframe) { Init(symbol, timeframe); }
//
// Destructors
//
~CCommonBase() {};
int Init(string symbol, ENUM_TIMEFRAMES timeframe);
protected: // Functions
int InitError(string initMessage, int initResult)
{ mInitMessage = initMessage;
mInitResult = initResult;
return(initResult); }
public: // Properties
int InitResult() { return(mInitResult); }
string InitMessage() { return(mInitMessage); }
public: // Functions
bool TradeAllowed() { return(SymbolInfoInteger(mSymbol, SYMBOL_TRADE_MODE)!=SYMBOL_TRADE_MODE_DISABLED); }
};
int CCommonBase::Init(string symbol, ENUM_TIMEFRAMES timeframe) {
InitError("", INIT_SUCCEEDED);
mSymbol = symbol;
mTimeframe = timeframe;
mDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,193 @@
/*
ExpertBase.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
#include "Signals/SignalBase.mqh"
#include "Trade/Trade.mqh"
class CExpertBase : public CCommonBase {
protected:
int mMagicNumber;
string mTradeComment;
double mVolume;
datetime mLastBarTime;
datetime mBarTime;
CSignalBase *mEntrySignal;
CSignalBase *mExitSignal;
CTradeCustom Trade;
private:
protected:
virtual bool LoopMain(bool newBar, bool firstTime);
protected:
int Init(int magicNumber, string tradeComment);
public:
//
// Constructors
//
CExpertBase() : CCommonBase()
{ Init(0, ""); }
CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment)
: CCommonBase(symbol, timeframe)
{ Init(magicNumber, tradeComment); }
CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment)
: CCommonBase(symbol, timeframe)
{ Init(magicNumber, tradeComment); }
CExpertBase(int magicNumber, string tradeComment)
: CCommonBase()
{ Init(magicNumber, tradeComment); }
//
// Destructors
//
~CExpertBase();
public: // Default properties
//
// Assign the default values to the expert
//
virtual void SetVolume(double volume) { mVolume = volume; }
virtual void SetTradeComment(string comment) { mTradeComment = comment; }
virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber;
Trade.SetExpertMagicNumber(magicNumber); }
public: // Setup
virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; }
virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; }
public: // Event handlers
virtual int OnInit() { return(InitResult()); }
virtual void OnTick();
virtual void OnTimer() { return; }
virtual double OnTester() { return(0.0); }
virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {};
#ifdef __MQL5__
virtual void OnTrade() { return; }
virtual void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{ return; }
virtual void OnTesterInit() { return; }
virtual void OnTesterPass() { return; }
virtual void OnTesterDeinit() { return; }
virtual void OnBookEvent() { return; }
#endif
};
CExpertBase::~CExpertBase() {
}
int CExpertBase::Init(int magicNumber, string tradeComment) {
if (mInitResult!=INIT_SUCCEEDED) return(mInitResult);
mTradeComment = tradeComment;
SetMagic(magicNumber);
mLastBarTime = 0;
return(INIT_SUCCEEDED);
}
void CExpertBase::OnTick(void) {
if (!TradeAllowed()) return;
mBarTime = iTime(mSymbol, mTimeframe, 0);
bool firstTime = (mLastBarTime==0);
bool newBar = (mBarTime!=mLastBarTime);
if (LoopMain(newBar, firstTime)) {
mLastBarTime = mBarTime;
}
return;
}
bool CExpertBase::LoopMain(bool newBar,bool firstTime) {
//
// To start I will only trade on a new bar
// and not on the first bar after start
//
if (!newBar) return(true);
if (firstTime) return(true);
//
// Update the signals
//
if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal();
if (mEntrySignal!=mExitSignal) {
if (mExitSignal!=NULL) mExitSignal.UpdateSignal();
}
//
// Should any trades be closed
//
if (mExitSignal!=NULL) {
if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) {
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
} else
if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) {
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
} else
if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) {
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
}
}
//
// Should a trade be opened
//
if (mEntrySignal!=NULL) {
if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) {
Trade.Buy(mVolume, mSymbol);
Trade.Sell(mVolume, mSymbol);
} else
if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) {
Trade.Buy(mVolume, mSymbol);
} else
if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) {
Trade.Sell(mVolume, mSymbol);
}
}
return(true);
}
@@ -0,0 +1,19 @@
/*
Framework_1.00.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#ifndef _FRAMEWORK_VERSION_
#define _FRAMEWORK_VERSION_ "1.00"
#include "CommonBase.mqh"
#include "Indicators/AllIndicators.mqh"
#include "Signals/AllSignals.mqh"
#include "ExpertBase.mqh"
#endif
@@ -0,0 +1,15 @@
/*
AllIndicators.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "IndicatorBase.mqh"
//
// Other signals go here
//
#include "Average/IndicatorMA.mqh"
@@ -0,0 +1,91 @@
/*
IndicatorMA.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../IndicatorBase.mqh"
class CIndicatorMA : public CIndicatorBase {
private:
protected: // member variables
int mPeriods;
int mShift;
ENUM_MA_METHOD mMethod;
ENUM_APPLIED_PRICE mAppliedPrice;
// Only used for MQL5
int mHandle;
public: // constructors
CIndicatorMA(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice)
: CIndicatorBase()
{ Init(periods, shift, method, appliedPrice); }
CIndicatorMA(string symbol, ENUM_TIMEFRAMES timeframe,
int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice)
: CIndicatorBase(symbol, timeframe)
{ Init(periods, shift, method, appliedPrice); }
~CIndicatorMA();
virtual int Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice);
public:
virtual double GetData(const int buffer_num,const int index);
};
CIndicatorMA::~CIndicatorMA() {
#ifdef __MQL5__
if (mHandle!=INVALID_HANDLE) IndicatorRelease(mHandle);
#endif
}
int CIndicatorMA::Init(int periods, int shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE appliedPrice) {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mPeriods = periods;
mShift = shift;
mMethod = method;
mAppliedPrice = appliedPrice;
#ifdef __MQL5__
mHandle = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice);
if (mHandle==INVALID_HANDLE) return(InitError("Failed to create indicator handle", INIT_FAILED));
#endif
return(INIT_SUCCEEDED);
}
double CIndicatorMA::GetData(const int buffer_num,const int index) {
double value = 0;
#ifdef __MQL4__
value = iMA(mSymbol, mTimeframe, mPeriods, mShift, mMethod, mAppliedPrice, index);
#endif
#ifdef __MQL5__
double bufferData[];
ArraySetAsSeries(bufferData, true);
int cnt = CopyBuffer(mHandle, buffer_num, index, 1, bufferData);
if (cnt>0) value = bufferData[0];
#endif
return(value);
}
@@ -0,0 +1,44 @@
/*
IndicatorBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../CommonBase.mqh"
class CIndicatorBase : public CCommonBase {
private:
protected: // member variables
public: // constructors
CIndicatorBase() : CCommonBase()
{ Init(); }
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
: CCommonBase(symbol, timeframe)
{ Init(); }
~CIndicatorBase() { }
int Init();
public:
virtual double GetData(const int index) { return(GetData(0,index)); }
virtual double GetData(const int bufferNum, const int index){ return (0); }
};
int CIndicatorBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,15 @@
/*
AllSignals.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "SignalBase.mqh"
//
// Other signals go here
//
#include "Crossover/SignalCrossover.mqh"
@@ -0,0 +1,78 @@
/*
SignalCrossover.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../SignalBase.mqh"
class CSignalCrossover : public CSignalBase {
private:
protected: // member variables
int mIndex1;
int mIndex2;
public: // constructors
CSignalCrossover(string symbol, ENUM_TIMEFRAMES timeframe,
int index1=1, int index2=2)
: CSignalBase(symbol, timeframe)
{ Init(index1, index2); }
CSignalCrossover(int index1=1, int index2=2)
: CSignalBase()
{ Init(index1, index2); }
~CSignalCrossover() { }
int Init(int index1, int index2);
public:
virtual void UpdateSignal();
};
int CSignalCrossover::Init(int index1, int index2) {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mIndex1 = index1;
mIndex2 = index2;
return(INIT_SUCCEEDED);
}
void CSignalCrossover::UpdateSignal() {
double fast1 = GetIndicatorData(0, mIndex1);
double fast2 = GetIndicatorData(0, mIndex2);
double slow1 = GetIndicatorData(1, mIndex1);
double slow2 = GetIndicatorData(1, mIndex2);
// There is a less common condition where the fast
// indicator touches the slow indicator and then
// reverses. With the conditions below this would
// appear like a cross.
if ( (fast1>slow1) && !(fast2>slow2) ) { // Crossed up
mEntrySignal = OFX_SIGNAL_BUY;
mExitSignal = OFX_SIGNAL_SELL;
} else
if ( (fast1<slow1) && !(fast2<slow2) ) { // Crossed down
mEntrySignal = OFX_SIGNAL_SELL;
mExitSignal = OFX_SIGNAL_BUY;
} else {
mEntrySignal = OFX_SIGNAL_NONE;
mExitSignal = OFX_SIGNAL_NONE;
}
return;
}
@@ -0,0 +1,85 @@
/*
SignalBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../CommonBase.mqh"
#include "../Indicators/IndicatorBase.mqh"
struct SIndicatorItem {
CIndicatorBase *indicator;
int bufferNum;
};
enum ENUM_OFX_SIGNAL_DIRECTION {
OFX_SIGNAL_NONE = 0,
OFX_SIGNAL_BUY = 1,
OFX_SIGNAL_SELL = 2,
OFX_SIGNAL_BOTH = 3
};
class CSignalBase : public CCommonBase {
private:
protected: // member variables
ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
SIndicatorItem mIndicatorList[];
public: // constructors
CSignalBase() : CCommonBase()
{ Init(); }
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
{ Init(); }
~CSignalBase() { }
int Init();
public:
virtual void UpdateSignal() { return; }
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mEntrySignal); }
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mExitSignal); }
virtual void AddIndicator(CIndicatorBase *indicator, int bufferNum);
virtual double GetIndicatorData(int indicatorNum, int index);
};
int CSignalBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mEntrySignal = OFX_SIGNAL_NONE;
mExitSignal = OFX_SIGNAL_NONE;
return(INIT_SUCCEEDED);
}
void CSignalBase::AddIndicator(CIndicatorBase *indicator, int bufferNum) {
SIndicatorItem indicatorItem = {NULL, 0};
indicatorItem.indicator = indicator;
indicatorItem.bufferNum = bufferNum;
int cnt = ArraySize(mIndicatorList);
ArrayResize(mIndicatorList, cnt+1);
mIndicatorList[cnt] = indicatorItem;
return;
}
double CSignalBase::GetIndicatorData(int indicatorNum,int index) {
return(mIndicatorList[indicatorNum].indicator.GetData(mIndicatorList[indicatorNum].bufferNum, index));
}
@@ -0,0 +1,14 @@
/*
Trade.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#ifdef __MQL4__
#include "Trade_mql4.mqh"
#endif
#ifdef __MQL5__
#include "Trade_mql5.mqh"
#endif
@@ -0,0 +1,83 @@
/*
Trade.mqh
(For MQL4)
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "../CommonBase.mqh"
enum ENUM_POSITION_TYPE {
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
POSITION_TYPE_SELL = ORDER_TYPE_SELL
};
class CTradeCustom : public CCommonBase {
private:
protected: // member variables
int mMagic; // expert magic number
public: // constructors
CTradeCustom();
~CTradeCustom();
public:
ulong RequestMagic() { return(mMagic); }
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
bool Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
};
CTradeCustom::CTradeCustom() {
mMagic = 0;
}
CTradeCustom::~CTradeCustom() {
}
bool CTradeCustom::Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") {
if (price==0.0) price = BuyPrice(symbol);
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
return(ticket>0);
}
bool CTradeCustom::Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") {
if (price==0.0) price = SellPrice(symbol);
int ticket = OrderSend(symbol, ORDER_TYPE_SELL, volume, price, 0, sl, tp, comment, mMagic);
return(ticket>0);
}
bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const int deviation=ULONG_MAX) {
int slippage = (deviation==ULONG_MAX) ? 0 : deviation;
bool result = true;
int cnt = OrdersTotal();
for (int i = cnt-1; i>=0; i--) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic && OrderType()==positionType) {
result &= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage);
}
}
}
return(result);
}
@@ -0,0 +1,44 @@
/*
Trade.mqh
(For MQL5)
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include <Trade/Trade.mqh>
class CTradeCustom : public CTrade {
private:
protected: // member variables
public: // constructors
public:
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const ulong deviation=ULONG_MAX);
};
bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const ulong deviation=ULONG_MAX) {
bool result = true;
int cnt = PositionsTotal();
for (int i = cnt-1; i>=0; i--) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_TYPE)==positionType && PositionGetInteger(POSITION_MAGIC)==m_magic) {
result &= PositionClose(ticket, deviation);
}
} else {
m_result.retcode=TRADE_RETCODE_REJECT;
result = false;
}
}
return(result);
}
@@ -0,0 +1,78 @@
/*
CommonBase.mqh
For framework version 1.0
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#define _INIT_CHECK_FAIL if (mInitResult!=INIT_SUCCEEDED) return(mInitResult);
#define _INIT_ERROR(msg) return(InitError(msg, INIT_PARAMETERS_INCORRECT));
#define _INIT_ASSERT(condition, msg) if (!condition) return(InitError(msg, INIT_FAILED));
class CCommonBase {
private:
protected: // Members
int mDigits;
string mSymbol;
ENUM_TIMEFRAMES mTimeframe;
string mInitMessage;
int mInitResult;
protected: // Constructors
//
// Constructors
//
CCommonBase() { Init(_Symbol, (ENUM_TIMEFRAMES)_Period); }
CCommonBase(string symbol) { Init(symbol, (ENUM_TIMEFRAMES)_Period); }
CCommonBase(int timeframe) { Init(_Symbol, (ENUM_TIMEFRAMES)timeframe); }
CCommonBase(ENUM_TIMEFRAMES timeframe) { Init(_Symbol, timeframe); }
CCommonBase(string symbol, int timeframe) { Init(symbol, (ENUM_TIMEFRAMES)timeframe); }
CCommonBase(string symbol, ENUM_TIMEFRAMES timeframe) { Init(symbol, timeframe); }
//
// Destructors
//
~CCommonBase() {};
int Init(string symbol, ENUM_TIMEFRAMES timeframe);
protected: // Functions
int InitError(string initMessage, int initResult)
{ mInitMessage = initMessage;
mInitResult = initResult;
if (initMessage!="") Print(initMessage);
return(initResult); }
double PointsToDouble(int points) { return(points*SymbolInfoDouble(mSymbol, SYMBOL_POINT)); }
public: // Properties
int InitResult() { return(mInitResult); }
string InitMessage() { return(mInitMessage); }
public: // Functions
bool TradeAllowed() { return(SymbolInfoInteger(mSymbol, SYMBOL_TRADE_MODE)!=SYMBOL_TRADE_MODE_DISABLED); }
};
int CCommonBase::Init(string symbol, ENUM_TIMEFRAMES timeframe) {
InitError("", INIT_SUCCEEDED);
mSymbol = symbol;
mTimeframe = timeframe;
mDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,380 @@
/*
ExpertBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
#include "SignalBase.mqh"
#include "TPSLBase.mqh"
#include "Trade/Trade.mqh"
class CExpertBase : public CCommonBase {
protected:
int mMagicNumber;
string mTradeComment;
double mVolume;
datetime mLastBarTime;
datetime mBarTime;
////Changed
// Arrays to hold the signal objects
CSignalBase *mEntrySignals[];
CSignalBase *mExitSignals[];
////CSignalBase *mEntrySignal;
////CSignalBase *mExitSignal;
double mTakeProfitValue;
double mStopLossValue;
CTPSLBase *mTakeProfitObj;
CTPSLBase *mStopLossObj;
CTradeCustom Trade;
private:
protected:
virtual bool LoopMain(bool newBar, bool firstTime);
protected:
int Init(int magicNumber, string tradeComment);
public:
//
// Constructors
//
CExpertBase() : CCommonBase()
{ Init(0, ""); }
CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment)
: CCommonBase(symbol, timeframe)
{ Init(magicNumber, tradeComment); }
CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment)
: CCommonBase(symbol, timeframe)
{ Init(magicNumber, tradeComment); }
CExpertBase(int magicNumber, string tradeComment)
: CCommonBase()
{ Init(magicNumber, tradeComment); }
//
// Destructors
//
~CExpertBase();
public: // Default properties
//
// Assign the default values to the expert
//
virtual void SetVolume(double volume) { mVolume = volume; }
virtual void SetTakeProfitValue(int takeProfitPoints)
{ mTakeProfitValue = PointsToDouble(takeProfitPoints); }
virtual void SetTakeProfitObj(CTPSLBase *takeProfitObj)
{ mTakeProfitObj = takeProfitObj; }
virtual void SetStopLossValue(int stopLossPoints)
{ mStopLossValue = PointsToDouble(stopLossPoints); }
virtual void SetStopLossObj(CTPSLBase *stopLossObj)
{ mStopLossObj = stopLossObj; }
virtual void SetTradeComment(string comment) { mTradeComment = comment; }
virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber;
Trade.SetExpertMagicNumber(magicNumber); }
public: // Setup
////Changed
virtual void AddEntrySignal(CSignalBase *signal) { AddSignal(signal, mEntrySignals); }
virtual void AddExitSignal(CSignalBase *signal) { AddSignal(signal, mExitSignals); }
virtual void AddSignal(CSignalBase *signal, CSignalBase* &signals[]);
////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; }
////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; }
public: // Event handlers
virtual int OnInit();
virtual void OnTick();
virtual void OnTimer() { return; }
virtual double OnTester() { return(0.0); }
virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {};
#ifdef __MQL5__
virtual void OnTrade() { return; }
virtual void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{ return; }
virtual int OnTesterInit() { return(INIT_SUCCEEDED); }
virtual void OnTesterPass() { return; }
virtual void OnTesterDeinit() { return; }
virtual void OnBookEvent() { return; }
#endif
public: // Functions
virtual void GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request);
////New
virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalBase* &signals[],
ENUM_OFX_SIGNAL_TYPE signalType);
};
CExpertBase::~CExpertBase() {
}
int CExpertBase::OnInit() {
int i = 0;
for (i=ArraySize(mEntrySignals)-1; i>=0; i--) {
if (mEntrySignals[i].InitResult()!=INIT_SUCCEEDED) return(mEntrySignals[i].InitResult());
}
for (i=ArraySize(mExitSignals)-1; i>=0; i--) {
if (mExitSignals[i].InitResult()!=INIT_SUCCEEDED) return(mExitSignals[i].InitResult());
}
if (mTakeProfitObj!=NULL) {
if (mTakeProfitObj.InitResult()!=INIT_SUCCEEDED) return(mTakeProfitObj.InitResult());
}
if (mStopLossObj!=NULL) {
if (mStopLossObj.InitResult()!=INIT_SUCCEEDED) return(mStopLossObj.InitResult());
}
return(INIT_SUCCEEDED);
}
int CExpertBase::Init(int magicNumber, string tradeComment) {
if (mInitResult!=INIT_SUCCEEDED) return(mInitResult);
mTradeComment = tradeComment;
SetMagic(magicNumber);
mTakeProfitValue = 0.0;
mStopLossValue = 0.0;
mLastBarTime = 0;
////New
ArrayResize(mEntrySignals, 0); // Just make sure these are initialised
ArrayResize(mExitSignals, 0);
return(INIT_SUCCEEDED);
}
void CExpertBase::OnTick(void) {
if (!TradeAllowed()) return;
mBarTime = iTime(mSymbol, mTimeframe, 0);
bool firstTime = (mLastBarTime==0);
bool newBar = (mBarTime!=mLastBarTime);
if (LoopMain(newBar, firstTime)) {
mLastBarTime = mBarTime;
}
return;
}
bool CExpertBase::LoopMain(bool newBar,bool firstTime) {
//
// To start I will only trade on a new bar
// and not on the first bar after start
//
if (!newBar) return(true);
if (firstTime) return(true);
//
// Update the signals
//
////Changed
ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL);
ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL);
////if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal();
////if (mEntrySignal!=mExitSignal) {
//// if (mExitSignal!=NULL) mExitSignal.UpdateSignal();
////}
//
// Should any trades be closed
//
////Changed
if (exitSignal==OFX_SIGNAL_BOTH) {
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
} else
if (exitSignal==OFX_SIGNAL_BUY) {
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
} else
if (exitSignal==OFX_SIGNAL_SELL) {
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
}
////if (mExitSignal!=NULL) {
//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) {
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
//// } else
//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) {
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
//// } else
//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) {
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
//// }
////}
//
// Should a trade be opened
//
MqlTradeRequest request = {}; // Just initialising
////Changed
if (entrySignal==OFX_SIGNAL_BOTH) {
GetMarketPrices(ORDER_TYPE_BUY, request);
Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp);
GetMarketPrices(ORDER_TYPE_SELL, request);
Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
} else
if (entrySignal==OFX_SIGNAL_BUY) {
GetMarketPrices(ORDER_TYPE_BUY, request);
Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp);
} else
if (entrySignal==OFX_SIGNAL_SELL) {
GetMarketPrices(ORDER_TYPE_SELL, request);
Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
}
//// if (mEntrySignal!=NULL) {
//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) {
////
//// GetMarketPrices(ORDER_TYPE_BUY, request);
//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// GetMarketPrices(ORDER_TYPE_SELL, request);
//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// } else
//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) {
////
//// GetMarketPrices(ORDER_TYPE_BUY, request);
//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// } else
//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) {
////
//// GetMarketPrices(ORDER_TYPE_SELL, request);
//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// }
//// }
return(true);
}
void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request) {
double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss();
double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit();
if (orderType==ORDER_TYPE_BUY) {
if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK);
request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits);
request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits);
}
if (orderType==ORDER_TYPE_SELL) {
if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID);
request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits);
request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits);
}
return;
}
////New
void CExpertBase::AddSignal(CSignalBase *signal, CSignalBase* &signals[]) {
int index = ArraySize(signals);
ArrayResize(signals, index+1);
signals[index] = signal;
}
////New
ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalBase* &signals[],
ENUM_OFX_SIGNAL_TYPE signalType) {
ENUM_OFX_SIGNAL_DIRECTION result = OFX_SIGNAL_NONE;
ENUM_OFX_SIGNAL_DIRECTION r2 = OFX_SIGNAL_NONE; // Just working value
int index = ArraySize(signals);
if (index<=0) {
return(result);
} else {
signals[0].UpdateSignal();
result = signals[0].GetSignal(signalType);
// I have chosen to update all signals in case there is some
// behavour that needs it. The penalty is some performance
// If performance is an issue just add an exit inside the loop
// as the commented line
for (int i = 1; i<index; i++) {
//if (result==OFX_SIGNAL_NONE) return(result);
signals[i].UpdateSignal();
r2 = signals[i].GetSignal(signalType);
// The logic here
// If the current result is both then just update to the r2
// because this allows for any value
// If r2 is both then this just leave the current result as is
// Last test, meaning result is already none or buy or sell
// If r2 is different then we cannot combine them
// so the result must be none
//
// or like this
//
// result r2 gives
// Both + Any = Any
// Any + Both = Any
// !Both + !Same = None
if (result==OFX_SIGNAL_BOTH) { result = r2; }
else if (r2==OFX_SIGNAL_BOTH) { }
else if (result!=r2) { result = OFX_SIGNAL_NONE; }
}
}
return(result);
}
@@ -0,0 +1,36 @@
/*
Framework_2.03.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
// History
// 1.00 - First version, not well version controlled
// 2.00 - Changed framework structure, functionally same as 1.00
// 2.01 - Added TP and SL
// 2.02 - Move compound signals into expertbase
// Templates now use common files between mq4 and mq5
// MakeMQH batch script also recreates framework.mqh
// 2.03 - Added macros to CommonBase to standardise init checking
// Moved base classes up one level and removed unnecessary folders
#ifndef _FRAMEWORK_VERSION_
#define _FRAMEWORK_VERSION_ "2.03"
#include "CommonBase.mqh"
#include "Trade/Trade.mqh"
#include "IndicatorBase.mqh"
#include "SignalBase.mqh"
#include "TPSLBase.mqh"
#include "ExpertBase.mqh"
#include "../Extensions/AllExtensions.mqh"
#endif
@@ -0,0 +1,59 @@
/*
IndicatorBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
class CIndicatorBase : public CCommonBase {
private:
protected: // member variables
// Only used for MQL5
int mIndicatorHandle;
public: // constructors
CIndicatorBase() : CCommonBase()
{ Init(); }
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
: CCommonBase(symbol, timeframe)
{ Init(); }
~CIndicatorBase();
int Init();
public:
virtual double GetData(const int index) { return(GetData(0,index)); }
virtual double GetData(const int bufferNum, const int index){ return (0); }
};
CIndicatorBase::~CIndicatorBase() {
#ifdef __MQL5__
if (mIndicatorHandle!=INVALID_HANDLE) IndicatorRelease(mIndicatorHandle);
#endif
}
int CIndicatorBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mIndicatorHandle = INVALID_HANDLE;
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,112 @@
/*
SignalBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
#include "IndicatorBase.mqh"
//// New
//// This is to maintain compatibility and allow sub classes to still
//// use mEntrySignal= or mExitSignal=
//// mEntrySignal and mExitSignal are effectively deprecated now
#define mEntrySignal mSignalValues[OFX_ENTRY_SIGNAL] // Deprecated
#define mExitSignal mSignalValues[OFX_EXIT_SIGNAL] // Deprecated
struct SIndicatorItem {
CIndicatorBase *indicator;
int bufferNum;
};
//// New
enum ENUM_OFX_SIGNAL_TYPE {
OFX_ENTRY_SIGNAL,
OFX_EXIT_SIGNAL
};
enum ENUM_OFX_SIGNAL_DIRECTION {
OFX_SIGNAL_NONE = 0,
OFX_SIGNAL_BUY = 1,
OFX_SIGNAL_SELL = 2,
OFX_SIGNAL_BOTH = 3
};
class CSignalBase : public CCommonBase {
private:
protected: // member variables
//// Replaced
ENUM_OFX_SIGNAL_DIRECTION mSignalValues[2];
////ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
////ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
SIndicatorItem mIndicatorList[];
public: // constructors
CSignalBase() : CCommonBase()
{ Init(); }
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
{ Init(); }
~CSignalBase() { }
int Init();
public:
virtual void UpdateSignal() { return; }
//// Changed - maintain backward compatibility
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mSignalValues[OFX_ENTRY_SIGNAL]); }
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mSignalValues[OFX_EXIT_SIGNAL]); }
//// New, and shows my lack of planning
virtual void SetSignal(ENUM_OFX_SIGNAL_TYPE type,
ENUM_OFX_SIGNAL_DIRECTION value)
{ mSignalValues[type] = value; }
virtual ENUM_OFX_SIGNAL_DIRECTION GetSignal(ENUM_OFX_SIGNAL_TYPE type)
{ return(mSignalValues[type]); }
virtual void AddIndicator(CIndicatorBase *indicator, int bufferNum);
virtual double GetIndicatorData(int indicatorNum, int index);
};
int CSignalBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
//// Replaced
ArrayInitialize(mSignalValues, OFX_SIGNAL_NONE);
////mEntrySignal = OFX_SIGNAL_NONE;
////mExitSignal = OFX_SIGNAL_NONE;
return(INIT_SUCCEEDED);
}
void CSignalBase::AddIndicator(CIndicatorBase *indicator, int bufferNum) {
SIndicatorItem indicatorItem = {NULL, 0};
indicatorItem.indicator = indicator;
indicatorItem.bufferNum = bufferNum;
int cnt = ArraySize(mIndicatorList);
ArrayResize(mIndicatorList, cnt+1);
mIndicatorList[cnt] = indicatorItem;
if (indicator.InitResult()!=INIT_SUCCEEDED) {
InitError("",indicator.InitResult());
}
return;
}
double CSignalBase::GetIndicatorData(int indicatorNum,int index) {
return(mIndicatorList[indicatorNum].indicator.GetData(mIndicatorList[indicatorNum].bufferNum, index));
}
@@ -0,0 +1,39 @@
/*
TPSLBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "Signalbase.mqh"
class CTPSLBase : public CSignalBase {
private:
public: // constructors
CTPSLBase() : CSignalBase() { Init(); }
CTPSLBase(string symbol, ENUM_TIMEFRAMES timeframe) : CSignalBase(symbol, timeframe) { Init(); }
~CTPSLBase() { }
int Init();
public:
virtual double GetTakeProfit() { return(0.0); }
virtual double GetStopLoss() { return(0.0); }
};
int CTPSLBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,16 @@
/*
Trade.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#ifdef __MQL4__
#include "Trade_mql4.mqh"
#endif
#ifdef __MQL5__
#include "Trade_mql5.mqh"
#endif
@@ -0,0 +1,123 @@
/*
Trade.mqh
(For MQL4)
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "..\CommonBase.mqh"
struct MqlTradeRequest {
int action; // Trade operation type (as int here)
ulong magic; // Expert Advisor ID (magic number)
ulong order; // Order ticket
string symbol; // Trade symbol
double volume; // Requested volume for a deal in lots
double price; // Price
double stoplimit; // StopLimit level of the order
double sl; // Stop Loss level of the order
double tp; // Take Profit level of the order
ulong deviation; // Maximal possible deviation from the requested price
ENUM_ORDER_TYPE type; // Order type
int type_filling; // Order execution type (int here)
int type_time; // Order expiration type (int here)
datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
string comment; // Order comment
ulong position; // Position ticket
ulong position_by; // The ticket of an opposite position
};
enum ENUM_POSITION_TYPE {
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
POSITION_TYPE_SELL = ORDER_TYPE_SELL
};
class CTradeCustom : public CCommonBase {
private:
protected: // member variables
int mMagic; // expert magic number
public: // constructors
CTradeCustom();
~CTradeCustom();
public:
ulong RequestMagic() { return(mMagic); }
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
bool Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
////New
void PositionCountByType(const string symbol, int &count[]);
};
CTradeCustom::CTradeCustom() {
mMagic = 0;
}
CTradeCustom::~CTradeCustom() {
}
bool CTradeCustom::Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") {
if (price==0.0) price = BuyPrice(symbol);
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
return(ticket>0);
}
bool CTradeCustom::Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") {
if (price==0.0) price = SellPrice(symbol);
int ticket = OrderSend(symbol, ORDER_TYPE_SELL, volume, price, 0, sl, tp, comment, mMagic);
return(ticket>0);
}
bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const int deviation=ULONG_MAX) {
int slippage = (deviation==ULONG_MAX) ? 0 : deviation;
bool result = true;
int cnt = OrdersTotal();
for (int i = cnt-1; i>=0; i--) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic && OrderType()==positionType) {
result &= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage);
}
}
}
return(result);
}
////New
void CTradeCustom::PositionCountByType(const string symbol, int &count[]) {
ArrayResize(count, 6);
ArrayInitialize(count, 0);
int cnt = OrdersTotal();
for (int i = cnt-1; i>=0; i--) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic) {
count[(int)OrderType()]++;
}
}
}
return;
}
@@ -0,0 +1,66 @@
/*
Trade.mqh
(For MQL5)
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include <Trade/Trade.mqh>
class CTradeCustom : public CTrade {
private:
protected: // member variables
public: // constructors
public:
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const ulong deviation=ULONG_MAX);
////New
void PositionCountByType(const string symbol, int &count[]);
};
bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const ulong deviation=ULONG_MAX) {
bool result = true;
int cnt = PositionsTotal();
for (int i = cnt-1; i>=0; i--) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_TYPE)==positionType && PositionGetInteger(POSITION_MAGIC)==m_magic) {
result &= PositionClose(ticket, deviation);
}
} else {
m_result.retcode=TRADE_RETCODE_REJECT;
result = false;
}
}
return(result);
}
////New
void CTradeCustom::PositionCountByType(const string symbol, int &count[]) {
ArrayResize(count, 6);
ArrayInitialize(count, 0);
int cnt = PositionsTotal();
for (int i = cnt-1; i>=0; i--) {
ulong ticket = PositionGetTicket(i);
if (PositionSelectByTicket(ticket)) {
if (PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_MAGIC)==m_magic) {
count[(int)PositionGetInteger(POSITION_TYPE)]++;
}
}
}
return;
}
@@ -0,0 +1,7 @@
Version 2.03
Added macros to CommonBase to standardise init checking
Moved base classes up one level and removed unnecessary folders
Updated framework number
@@ -0,0 +1,75 @@
/*
CommonBase.mqh
For framework version 1.0
*/
#define _INIT_CHECK_FAIL if (mInitResult!=INIT_SUCCEEDED) return(mInitResult);
#define _INIT_ERROR(msg) return(InitError(msg, INIT_PARAMETERS_INCORRECT));
#define _INIT_ASSERT(condition, msg) if (!condition) return(InitError(msg, INIT_FAILED));
class CCommonBase {
private:
protected: // Members
int mDigits;
string mSymbol;
ENUM_TIMEFRAMES mTimeframe;
string mInitMessage;
int mInitResult;
protected: // Constructors
//
// Constructors
//
CCommonBase() { Init(_Symbol, (ENUM_TIMEFRAMES)_Period); }
CCommonBase(string symbol) { Init(symbol, (ENUM_TIMEFRAMES)_Period); }
CCommonBase(int timeframe) { Init(_Symbol, (ENUM_TIMEFRAMES)timeframe); }
CCommonBase(ENUM_TIMEFRAMES timeframe) { Init(_Symbol, timeframe); }
CCommonBase(string symbol, int timeframe) { Init(symbol, (ENUM_TIMEFRAMES)timeframe); }
CCommonBase(string symbol, ENUM_TIMEFRAMES timeframe) { Init(symbol, timeframe); }
//
// Destructors
//
~CCommonBase() {};
int Init(string symbol, ENUM_TIMEFRAMES timeframe);
protected: // Functions
int InitError(string initMessage, int initResult)
{ mInitMessage = initMessage;
mInitResult = initResult;
if (initMessage!="") Print(initMessage);
return(initResult); }
double PointsToDouble(int points) { return(points*SymbolInfoDouble(mSymbol, SYMBOL_POINT)); }
public: // Properties
int InitResult() { return(mInitResult); }
string InitMessage() { return(mInitMessage); }
public: // Functions
bool TradeAllowed() { return(SymbolInfoInteger(mSymbol, SYMBOL_TRADE_MODE)!=SYMBOL_TRADE_MODE_DISABLED); }
};
int CCommonBase::Init(string symbol, ENUM_TIMEFRAMES timeframe) {
InitError("", INIT_SUCCEEDED);
mSymbol = symbol;
mTimeframe = timeframe;
mDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,812 @@
/*
ExpertBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
#include "Trade/Trade.mqh"
#include "../Extensions/AllGridExtensions.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CExpertBase : public CCommonBase
{
protected:
int mMagicNumber;
string mTradeComment;
double mVolume;
int GridNumber;
int mGridGap;
int mSlippage;
double mDefaultLotSize;
double mMaxLotSize;
double mMinLotSize;
double mMaxRiskPerTrade;
double lastBuyOrderPrice;
double lastSellOrderPrice;
double openedBuyPositionPrice;
double openedSellPositionPrice;
ENUM_TRADING_SESSION mUseTradingSession;
ENUM_RISK_DEFAULT_SIZE mRiskDefaultSize;
ENUM_RISK_BASE mRiskBase;
enum ENUM_NAV_SIGNAL_TYPE
{
NAV_ENTRY_SIGNAL,
NAV_EXIT_SIGNAL
};
ENUM_NAV_SIGNAL_TYPE signalType;
enum ENUM_NAV_SIGNAL_DIRECTION
{
NAV_SIGNAL_NONE = 0,
NAV_SIGNAL_BUY = 1,
NAV_SIGNAL_SELL = 2,
NAV_SIGNAL_BOTH = 3,
NAV_SIGNAL_ALL = 4
};
ENUM_NAV_SIGNAL_DIRECTION signalDirection;
datetime mLastBarTime;
datetime mBarTime;
bool mResetGrid;
////Changed
// Arrays to hold the signal objects
CSignalGrid *mEntrySignals[];
CSignalGrid *mExitSignals[];
////CSignalBase *mEntrySignal;
////CSignalBase *mExitSignal;
double mTakeProfitValue;
double mStopLossValue;
GridTPSL *mTakeProfitObj;
GridTPSL *mStopLossObj;
CTradeCustom Trade;
private:
protected:
virtual bool LoopMain(bool newBar, bool firstTime);
protected:
int Init(int magicNumber, string tradeComment);
public:
//
// Constructors
//
CExpertBase() : CCommonBase()
{ Init(0, ""); }
CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment)
: CCommonBase(symbol, timeframe)
{ Init(magicNumber, tradeComment); }
CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment)
: CCommonBase(symbol, timeframe)
{ Init(magicNumber, tradeComment); }
CExpertBase(int magicNumber, string tradeComment)
: CCommonBase()
{ Init(magicNumber, tradeComment); }
//
// Destructors
//
~CExpertBase();
public: // Default properties
//
// Assign the default values to the expert
//
virtual void SetVolume(double volume) { mVolume = volume; }
virtual void SetTakeProfitValue(int takeProfitPoints)
{ mTakeProfitValue = PointsToDouble(takeProfitPoints); }
virtual void SetTakeProfitObj(CTPSLBase *takeProfitObj)
{ mTakeProfitObj = takeProfitObj; }
virtual void SetStopLossValue(int stopLossPoints)
{ mStopLossValue = PointsToDouble(stopLossPoints); }
virtual void SetStopLossObj(CTPSLBase *stopLossObj)
{ mStopLossObj = stopLossObj; }
virtual void SetTradeComment(string comment) { mTradeComment = comment; }
virtual void SetMagic(int magicNumber)
{
mMagicNumber = magicNumber;
Trade.SetExpertMagicNumber(magicNumber);
}
virtual void SetGridNumber(int gNumber) {GridNumber = gNumber;}
virtual void SetGridGap(int gGap) {mGridGap = gGap;}
virtual void SetResetGrid() {mResetGrid = true;}
virtual void SetSlippage(int slippage) {mSlippage = slippage;}
virtual void SetDefaultLotSize(double defaultLotSize) {mDefaultLotSize = defaultLotSize;}
virtual void SetMaxLotSize(double maxLotSize) {mMaxLotSize = maxLotSize;}
virtual void SetMinLotSize(double minLotSize) {mMinLotSize = minLotSize;}
virtual void SetMaxRiskPerTrade(double maxRiskPerTrade) {mMaxRiskPerTrade = maxRiskPerTrade;}
virtual void SetUseTradingSession(ENUM_TRADING_SESSION useTradingSession) {mUseTradingSession = useTradingSession;}
virtual void SetRiskDefaultSize(ENUM_RISK_DEFAULT_SIZE riskDefaultSize) { mRiskDefaultSize = riskDefaultSize;}
virtual void SetRiskBase(ENUM_RISK_BASE riskBase) {mRiskBase=riskBase;}
public: // Setup
////Changed
virtual void AddEntrySignal(CSignalGrid *signal) { AddSignal(signal, mEntrySignals); }
virtual void AddExitSignal(CSignalGrid *signal) { AddSignal(signal, mExitSignals); }
virtual void AddSignal(CSignalGrid *signal, CSignalGrid* &signals[]);
virtual void LotSize(double SL);
virtual void TradeWatcher();
virtual bool IsTradingTime();
virtual bool CheckTradingSession();
virtual double getLastBuyOrderPrice() {return lastBuyOrderPrice;}
virtual double getLastSellOrderPrice() {return lastSellOrderPrice;}
virtual double getOpenedBuyPositionPrice() {return openedBuyPositionPrice;}
virtual double getOpenedSellPositionPrice() {return openedSellPositionPrice;}
////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; }
////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; }
public: // Event handlers
virtual int OnInit();
virtual void OnTick();
virtual void OnTimer() { return; }
virtual double OnTester() { return(0.0); }
virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {};
#ifdef __MQL5__
virtual void OnTrade() { return; }
virtual void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{ return; }
virtual int OnTesterInit() { return(INIT_SUCCEEDED); }
virtual void OnTesterPass() { return; }
virtual void OnTesterDeinit() { return; }
virtual void OnBookEvent() { return; }
#endif
public: // Functions
virtual void GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request);
////New
virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalGrid* &signals[],
ENUM_OFX_SIGNAL_TYPE signalType);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CExpertBase::~CExpertBase()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CExpertBase::OnInit()
{
int i = 0;
for(i=ArraySize(mEntrySignals)-1; i>=0; i--)
{
if(mEntrySignals[i].InitResult()!=INIT_SUCCEEDED)
return(mEntrySignals[i].InitResult());
}
for(i=ArraySize(mExitSignals)-1; i>=0; i--)
{
if(mExitSignals[i].InitResult()!=INIT_SUCCEEDED)
return(mExitSignals[i].InitResult());
}
if(mTakeProfitObj!=NULL)
{
if(mTakeProfitObj.InitResult()!=INIT_SUCCEEDED)
return(mTakeProfitObj.InitResult());
}
if(mStopLossObj!=NULL)
{
if(mStopLossObj.InitResult()!=INIT_SUCCEEDED)
return(mStopLossObj.InitResult());
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CExpertBase::Init(int magicNumber, string tradeComment)
{
if(mInitResult!=INIT_SUCCEEDED)
return(mInitResult);
mTradeComment = tradeComment;
SetMagic(magicNumber);
mTakeProfitValue = 0.0;
mStopLossValue = 0.0;
mLastBarTime = 0;
////New
ArrayResize(mEntrySignals, 0); // Just make sure these are initialised
ArrayResize(mExitSignals, 0);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CExpertBase::OnTick(void)
{
if(!TradeAllowed())
return;
mBarTime = iTime(mSymbol, mTimeframe, 0);
bool firstTime = (mLastBarTime==0);
bool newBar = (mBarTime!=mLastBarTime);
TradeWatcher();
Print("signalDirection after TradeWatcher ", signalDirection);
if(LoopMain(newBar, firstTime))
{
mLastBarTime = mBarTime;
}
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CExpertBase::LoopMain(bool newBar,bool firstTime)
{
//
// To start I will only trade on a new bar
// and not on the first bar after start
//
/*if(!newBar)
return(true);
if(firstTime)
return(true);*/
//
// Update the signals
//
////Changed
ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL);
ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL);
/*if(mEntrySignals[0]!=NULL)
mEntrySignals[0].UpdateSignal();
if(mEntrySignals[0]!=mExitSignals[0])
{
if(mEntrySignals[0]!=NULL)
mEntrySignals[0].UpdateSignal();
}*/
//
// Should any trades be closed
//
////Changed
/*
if(exitSignal==OFX_SIGNAL_BOTH)
{
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
}
else
if(exitSignal==OFX_SIGNAL_BUY)
{
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
}
else
if(exitSignal==OFX_SIGNAL_SELL)
{
Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
}
if(exitSignal==OFX_SIGNAL_ALL)
{
Trade.PositionCloseAll();
Trade.OrderCloseAll();
}
*/
////if (mExitSignal!=NULL) {
//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) {
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
//// } else
//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) {
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY);
//// } else
//// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) {
//// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL);
//// }
////}
//
// Should a trade be opened
//
MqlTradeRequest request = {}; // Just initialising
double buyPrice, sellPrice, SLPoints=0;
int GripPips = mGridGap;
double TakeProfitPoint = GripPips*_Point;
LotSize(GripPips);
////Changed
Print("Entry signal for Both ", NAV_SIGNAL_BOTH, " Entry for OFX_SIGNAL_BUY ", NAV_SIGNAL_BUY, " Actual ", signalDirection);
Print("signalDirection ", signalDirection);
if(signalDirection==NAV_SIGNAL_BOTH)
{
double AskPrice = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
double BidPrice = SymbolInfoDouble(Symbol(),SYMBOL_BID);
Print("m Grid pip ", GripPips, " Point ", _Point, " TP point ", TakeProfitPoint);
buyPrice = AskPrice + TakeProfitPoint;
sellPrice = BidPrice - TakeProfitPoint;
Print("m Grid pip ", GripPips, " Point ", _Point);
Print(" Buy price ", buyPrice, " TP normalized ", NormalizeDouble(buyPrice + TakeProfitPoint, mDigits));
//SLPoints=MathCeil(buyPrice-GripPips);
//GetMarketPrices(ORDER_TYPE_SELL, request);
//Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
GetMarketPrices(ORDER_TYPE_BUY, request);
request.tp = NormalizeDouble(request.price + TakeProfitPoint, mDigits);
Trade.Buy(mVolume, mSymbol, request.price, request.sl);
GetMarketPrices(ORDER_TYPE_SELL_STOP, request);
request.price = sellPrice;
request.tp = NormalizeDouble(sellPrice - TakeProfitPoint, mDigits);
Trade.SellStop(mVolume, request.price, mSymbol, request.sl);
}
else
if(signalDirection==NAV_SIGNAL_BUY)
{
//If there's a pending order, get the last order's price else get the position price
Print("Trying to open a buy");
buyPrice = getLastBuyOrderPrice()?getLastBuyOrderPrice():getOpenedBuyPositionPrice();
request.price = buyPrice+TakeProfitPoint;
request.sl = 0.0;
request.tp = NormalizeDouble(buyPrice + TakeProfitPoint, mDigits);
GetMarketPrices(ORDER_TYPE_BUY_STOP, request);
Trade.BuyStop(mVolume, request.price, mSymbol, request.sl);
}
else
if(signalDirection==NAV_SIGNAL_SELL)
{
Print("Trying to open a sell");
sellPrice = getLastSellOrderPrice()?getLastSellOrderPrice():getOpenedSellPositionPrice();
request.price = sellPrice-TakeProfitPoint;
request.sl = 0.0;
request.tp = NormalizeDouble(sellPrice - TakeProfitPoint, mDigits);
GetMarketPrices(ORDER_TYPE_SELL_STOP, request);
Trade.SellStop(mVolume, request.price, mSymbol, request.sl);
}
if(signalDirection==NAV_SIGNAL_ALL)
{
Trade.OrderCloseAll();
Trade.PositionCloseAll();
}
//// if (mEntrySignal!=NULL) {
//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) {
////
//// GetMarketPrices(ORDER_TYPE_BUY, request);
//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// GetMarketPrices(ORDER_TYPE_SELL, request);
//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// } else
//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) {
////
//// GetMarketPrices(ORDER_TYPE_BUY, request);
//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// } else
//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) {
////
//// GetMarketPrices(ORDER_TYPE_SELL, request);
//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp);
////
//// }
//// }
//mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_NONE);
//mEntrySignals[0].SetSignal(OFX_EXIT_SIGNAL, OFX_SIGNAL_NONE);
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request)
{
double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss();
double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit();
Trade.SetExpertMagicNumber(mMagicNumber);
if(orderType==ORDER_TYPE_BUY)
{
if(request.price==0.0)
request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK);
request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits);
request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits);
}
if(orderType==ORDER_TYPE_SELL)
{
if(request.price==0.0)
request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID);
request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits);
request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits);
}
return;
}
////New
void CExpertBase::AddSignal(CSignalGrid *signal, CSignalGrid* &signals[])
{
int index = ArraySize(signals);
ArrayResize(signals, index+1);
signals[index] = signal;
}
////New
ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalGrid* &signals[],
ENUM_OFX_SIGNAL_TYPE signalType)
{
ENUM_OFX_SIGNAL_DIRECTION result = OFX_SIGNAL_NONE;
ENUM_OFX_SIGNAL_DIRECTION r2 = OFX_SIGNAL_NONE; // Just working value
int index = ArraySize(signals);
if(index<=0)
{
return(result);
}
else
{
signals[0].UpdateSignal();
result = signals[0].GetSignal(signalType);
// I have chosen to update all signals in case there is some
// behavour that needs it. The penalty is some performance
// If performance is an issue just add an exit inside the loop
// as the commented line
for(int i = 1; i<index; i++)
{
if(result==OFX_SIGNAL_NONE)
return(result);
signals[i].UpdateSignal();
r2 = signals[i].GetSignal(signalType);
// The logic here
// If the current result is both then just update to the r2
// because this allows for any value
// If r2 is both then this just leave the current result as is
// Last test, meaning result is already none or buy or sell
// If r2 is different then we cannot combine them
// so the result must be none
//
// or like this
//
// result r2 gives
// Both + Any = Any
// Any + Both = Any
// !Both + !Same = None
if(result==OFX_SIGNAL_BOTH)
{
result = r2;
}
else
if(r2==OFX_SIGNAL_BOTH) { }
else
if(result!=r2)
{
result = OFX_SIGNAL_NONE;
}
}
}
return(result);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CExpertBase::CheckTradingSession()
{
string candles_times;
int time_to_string;
ushort a;
string result[];
//--- Get the separator code
a = StringGetCharacter(":",0);
candles_times = TimeToString(iTime(Symbol(),_Period,0), TIME_MINUTES);
time_to_string = StringSplit(candles_times, a, result);
//Implement this later
/*
if(InpUseTradingSession)
{
if(InpTradingSession == LONDON_SESSION && londonSession[0] <= result[0] && londonSession[1] >= result[0])
{
londonSession
}
return;
}*/
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CExpertBase::IsTradingTime(void)
{
bool result = false;
if(mUseTradingSession)
result = true;
return result;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CExpertBase::LotSize(double SL=0)
{
//Lot Size Calculator
//If the position size is dynamic
if(mRiskDefaultSize==RISK_DEFAULT_AUTO)
{
//If the stop loss is not zero then calculate the lot size
Print("Stop loss ", SL);
if(SL!=0)
{
double RiskBaseAmount=0;
//TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty
double TickValue=SymbolInfoDouble(mSymbol,SYMBOL_TRADE_TICK_VALUE);
Print("Tick value ", TickValue);
//Define the base for the risk calculation depending on the parameter chosen
if(mRiskBase==RISK_BASE_BALANCE)
RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE);
if(mRiskBase==RISK_BASE_EQUITY)
RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY);
if(mRiskBase==RISK_BASE_FREEMARGIN)
RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN);
//Calculate the Position Size
mVolume=((RiskBaseAmount*mMaxRiskPerTrade/100)/(SL*TickValue));
Print("Volume ", mVolume);
}
//If the stop loss is zero then the lot size is the default one
if(SL==0)
{
mVolume=mDefaultLotSize;
}
}
//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size
mVolume=MathFloor(mVolume/SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_STEP);
//Limit the lot size in case it is greater than the maximum allowed by the user
if(mVolume>mMaxLotSize)
mVolume=mMaxLotSize;
//Limit the lot size in case it is greater than the maximum allowed by the broker
if(mVolume>SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX))
mVolume=SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX);
Print("Lot ", mVolume, " Max lot ", SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MAX));
//If the lot size is too small then set it to 0 and don't trade
if(mVolume<mMinLotSize || mVolume < SymbolInfoDouble(mSymbol,SYMBOL_VOLUME_MIN))
{
mVolume=0;
Print("Lot size too small : ", mVolume);
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CExpertBase::TradeWatcher(void)
{
// Check the account balance equity for profit
int pCountBuy = 0, pCountSell = 0, oCountBuy = 0, oCountSell = 0, totalBuy = 0, totalSell = 0, realTotalBuy = 0, realTotalSell = 0;
int realOCountBuy, realOCountSell;
ulong ticket;
signalDirection = NAV_SIGNAL_NONE;
//If there're many positions and account balance is negative
Print("There is ", PositionsTotal(), " opened positions");
if(PositionsTotal() > 0)
{
//Count the opened positions by type
int cntP = PositionsTotal();
for(int i = cntP-1; i>=0; i--)
{
ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY
&& PositionGetInteger(POSITION_MAGIC)==mMagicNumber)
{
openedBuyPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
pCountBuy += 1;
}
Print("POSITION_SYMBOL ", PositionGetString(POSITION_SYMBOL), " = ", mSymbol, " POSITION_TYPE ",PositionGetInteger(POSITION_TYPE), " = ", POSITION_TYPE_SELL, " Magic ", PositionGetInteger(POSITION_MAGIC), " = ",mMagicNumber);
if(PositionGetString(POSITION_SYMBOL)==mSymbol && PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL
&& PositionGetInteger(POSITION_MAGIC)==mMagicNumber)
{
openedSellPositionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
pCountSell += 1;
}
}
else
{
Print(GetLastError());
}
}
}
//Count the orders by type
int cntO = OrdersTotal();
Print("Total pending orders ", cntO);
for(int i = cntO-1; i>=0; i--)
{
ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP
&& OrderGetInteger(ORDER_MAGIC)==mMagicNumber)
{
oCountBuy += 1;
lastBuyOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN);
}
Print("ORDER_SYMBOL ", OrderGetString(ORDER_SYMBOL), " Real symbol ", mSymbol, " ORDER_TYPE ", OrderGetInteger(ORDER_TYPE), " Real type ", ORDER_TYPE_SELL_STOP, " Magic ", OrderGetInteger(ORDER_MAGIC), " Real magic ", mMagicNumber);
if(OrderGetString(ORDER_SYMBOL)==mSymbol && OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP
&& OrderGetInteger(ORDER_MAGIC)==mMagicNumber)
{
oCountSell += 1;
lastSellOrderPrice = OrderGetDouble(ORDER_PRICE_OPEN);
}
}
else
{
Print(GetLastError());
}
}
Print("openedBuyPositionPrice ", openedBuyPositionPrice, " openedSellPositionPrice ", openedSellPositionPrice);
Print("lastBuyOrderPrice ", lastBuyOrderPrice, " lastSellOrderPrice ", lastSellOrderPrice);
double floatingProfitPercent = ((AccountInfoDouble(ACCOUNT_EQUITY) - AccountInfoDouble(ACCOUNT_BALANCE))*100)/AccountInfoDouble(ACCOUNT_BALANCE);
// Check if profit is at least the mMaxRiskPerTrade
Print(" MaxRiskPerTrade ",mMaxRiskPerTrade, " Floating profit percent ", floatingProfitPercent, " Account equity ", AccountInfoDouble(ACCOUNT_EQUITY), " Account balance ", AccountInfoDouble(ACCOUNT_BALANCE));
//The number of buy pending order should be twice the opened sell positions; and vice versa
realOCountBuy = pCountSell+1;
realOCountSell = pCountBuy*2;
totalBuy = pCountBuy+oCountBuy;
totalSell = pCountSell+oCountSell;
realTotalBuy = pCountSell+1;
realTotalSell = pCountBuy+1;
Print("Sell order (", oCountSell, ") Real (", realOCountSell, ")");
Print("Buy order (", oCountBuy, ") Real (", realOCountBuy, ")", " Opened sell ", pCountSell);
Print("oCountSell ", oCountSell, " < ", " realOCountSell ", realOCountSell, " && ", " pCountBuy ", pCountBuy," > 0");
if(OrdersTotal() == 0 && PositionsTotal() == 0)
{
signalDirection = NAV_SIGNAL_BOTH;
}
else
{
//If there's only one pending order left, close it.
if(OrdersTotal() >= 1 && PositionsTotal() == 0)
{
signalDirection = NAV_SIGNAL_ALL;
Print("Exit if no opened position");
}
else
{
//When there are multiple positions, check is the account is making enough profit
if(floatingProfitPercent > mMaxRiskPerTrade)
{
signalDirection = NAV_SIGNAL_ALL;
Print("Exit on profit target");
}
else
{
Print("realTotalSell ", realTotalSell, " <= ", " totalSell ", totalSell ," && ", " pCountBuy ",pCountBuy ," > 0");
if(realTotalSell > totalSell && pCountBuy > 0)
{
signalType = NAV_ENTRY_SIGNAL;
signalDirection = NAV_SIGNAL_SELL;
Print("Sell order (", oCountSell, ") is less than it should be (", realOCountSell, ")");
}
else
{
if(realTotalBuy > totalBuy && pCountSell > 0)
{
signalType = NAV_ENTRY_SIGNAL;
signalDirection = NAV_SIGNAL_BUY;
//mEntrySignals[0].SetSignal(OFX_ENTRY_SIGNAL, OFX_SIGNAL_BUY);
Print("Buy order (", oCountBuy, ") is less than it should be (", realOCountBuy, ")");
}
}
}
}
}
}
//+------------------------------------------------------------------+
@@ -0,0 +1,35 @@
/*
Framework_2.03.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
// History
// 1.00 - First version, not well version controlled
// 2.00 - Changed framework structure, functionally same as 1.00
// 2.01 - Added TP and SL
// 2.02 - Move compound signals into expertbase
// Templates now use common files between mq4 and mq5
// MakeMQH batch script also recreates framework.mqh
// 2.03 - Added macros to CommonBase to standardise init checking
// Moved base classes up one level and removed unnecessary folders
#ifndef _FRAMEWORK_VERSION_
#define _FRAMEWORK_VERSION_ "2.03"
#include "CommonBase.mqh"
#include "Trade/Trade.mqh"
#include "SignalBase.mqh"
#include "TPSLBase.mqh"
#include "ExpertBase.mqh"
#include "../Extensions/AllGridExtensions.mqh"
#endif
@@ -0,0 +1,59 @@
/*
IndicatorBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
class CIndicatorBase : public CCommonBase {
private:
protected: // member variables
// Only used for MQL5
int mIndicatorHandle;
public: // constructors
CIndicatorBase() : CCommonBase()
{ Init(); }
CIndicatorBase(string symbol, ENUM_TIMEFRAMES timeframe)
: CCommonBase(symbol, timeframe)
{ Init(); }
~CIndicatorBase();
int Init();
public:
virtual double GetData(const int index) { return(GetData(0,index)); }
virtual double GetData(const int bufferNum, const int index){ return (0); }
};
CIndicatorBase::~CIndicatorBase() {
#ifdef __MQL5__
if (mIndicatorHandle!=INVALID_HANDLE) IndicatorRelease(mIndicatorHandle);
#endif
}
int CIndicatorBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
mIndicatorHandle = INVALID_HANDLE;
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,95 @@
/*
SignalBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "CommonBase.mqh"
//#include "IndicatorBase.mqh"
//// New
//// This is to maintain compatibility and allow sub classes to still
//// use mEntrySignal= or mExitSignal=
//// mEntrySignal and mExitSignal are effectively deprecated now
#define mEntrySignal mSignalValues[OFX_ENTRY_SIGNAL] // Deprecated
#define mExitSignal mSignalValues[OFX_EXIT_SIGNAL] // Deprecated
//// New
enum ENUM_OFX_SIGNAL_TYPE
{
OFX_ENTRY_SIGNAL,
OFX_EXIT_SIGNAL
};
enum ENUM_OFX_SIGNAL_DIRECTION
{
OFX_SIGNAL_NONE = 0,
OFX_SIGNAL_BUY = 1,
OFX_SIGNAL_SELL = 2,
OFX_SIGNAL_BOTH = 3,
OFX_SIGNAL_ALL = 4
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CSignalBase : public CCommonBase
{
private:
protected: // member variables
//// Replaced
ENUM_OFX_SIGNAL_DIRECTION mSignalValues[2];
double mMaxRiskPerTrade;
////ENUM_OFX_SIGNAL_DIRECTION mEntrySignal;
////ENUM_OFX_SIGNAL_DIRECTION mExitSignal;
public: // constructors
CSignalBase() : CCommonBase()
{ Init(); }
CSignalBase(string symbol, ENUM_TIMEFRAMES timeframe) : CCommonBase(symbol, timeframe)
{ Init(); }
~CSignalBase() { }
int Init();
public:
virtual void UpdateSignal() { return; }
//// Changed - maintain backward compatibility
virtual ENUM_OFX_SIGNAL_DIRECTION EntrySignal() { return(mSignalValues[OFX_ENTRY_SIGNAL]); }
virtual ENUM_OFX_SIGNAL_DIRECTION ExitSignal() { return(mSignalValues[OFX_EXIT_SIGNAL]); }
//// New, and shows my lack of planning
virtual void SetSignal(ENUM_OFX_SIGNAL_TYPE type,
ENUM_OFX_SIGNAL_DIRECTION value)
{ mSignalValues[type] = value; }
virtual void SetMaxRiskPerTrade(double maxRiskPerTrade) { mMaxRiskPerTrade = maxRiskPerTrade;}
virtual ENUM_OFX_SIGNAL_DIRECTION GetSignal(ENUM_OFX_SIGNAL_TYPE type)
{ return(mSignalValues[type]); }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CSignalBase::Init()
{
if(InitResult()!=INIT_SUCCEEDED)
return(InitResult());
//// Replaced
ArrayInitialize(mSignalValues, OFX_SIGNAL_NONE);
////mEntrySignal = OFX_SIGNAL_NONE;
////mExitSignal = OFX_SIGNAL_NONE;
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,39 @@
/*
TPSLBase.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "Signalbase.mqh"
class CTPSLBase : public CSignalBase {
private:
public: // constructors
CTPSLBase() : CSignalBase() { Init(); }
CTPSLBase(string symbol, ENUM_TIMEFRAMES timeframe) : CSignalBase(symbol, timeframe) { Init(); }
~CTPSLBase() { }
int Init();
public:
virtual double GetTakeProfit() { return(0.0); }
virtual double GetStopLoss() { return(0.0); }
};
int CTPSLBase::Init() {
if (InitResult()!=INIT_SUCCEEDED) return(InitResult());
return(INIT_SUCCEEDED);
}
@@ -0,0 +1,16 @@
/*
Trade.mqh
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#ifdef __MQL4__
#include "Trade_mql4.mqh"
#endif
#ifdef __MQL5__
#include "Trade_mql5.mqh"
#endif
@@ -0,0 +1,123 @@
/*
Trade.mqh
(For MQL4)
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include "..\CommonBase.mqh"
struct MqlTradeRequest {
int action; // Trade operation type (as int here)
ulong magic; // Expert Advisor ID (magic number)
ulong order; // Order ticket
string symbol; // Trade symbol
double volume; // Requested volume for a deal in lots
double price; // Price
double stoplimit; // StopLimit level of the order
double sl; // Stop Loss level of the order
double tp; // Take Profit level of the order
ulong deviation; // Maximal possible deviation from the requested price
ENUM_ORDER_TYPE type; // Order type
int type_filling; // Order execution type (int here)
int type_time; // Order expiration type (int here)
datetime expiration; // Order expiration time (for the orders of ORDER_TIME_SPECIFIED type)
string comment; // Order comment
ulong position; // Position ticket
ulong position_by; // The ticket of an opposite position
};
enum ENUM_POSITION_TYPE {
POSITION_TYPE_BUY = ORDER_TYPE_BUY,
POSITION_TYPE_SELL = ORDER_TYPE_SELL
};
class CTradeCustom : public CCommonBase {
private:
protected: // member variables
int mMagic; // expert magic number
public: // constructors
CTradeCustom();
~CTradeCustom();
public:
ulong RequestMagic() { return(mMagic); }
void SetExpertMagicNumber(const int magic) { mMagic=magic; }
double BuyPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_ASK)); }
double SellPrice(string symbol) { return(SymbolInfoDouble(symbol, SYMBOL_BID)); }
bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
bool Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="");
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const int deviation=ULONG_MAX);
////New
void PositionCountByType(const string symbol, int &count[]);
};
CTradeCustom::CTradeCustom() {
mMagic = 0;
}
CTradeCustom::~CTradeCustom() {
}
bool CTradeCustom::Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") {
if (price==0.0) price = BuyPrice(symbol);
int ticket = OrderSend(symbol, ORDER_TYPE_BUY, volume, price, 0, sl, tp, comment, mMagic);
return(ticket>0);
}
bool CTradeCustom::Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="") {
if (price==0.0) price = SellPrice(symbol);
int ticket = OrderSend(symbol, ORDER_TYPE_SELL, volume, price, 0, sl, tp, comment, mMagic);
return(ticket>0);
}
bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const int deviation=ULONG_MAX) {
int slippage = (deviation==ULONG_MAX) ? 0 : deviation;
bool result = true;
int cnt = OrdersTotal();
for (int i = cnt-1; i>=0; i--) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic && OrderType()==positionType) {
result &= OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage);
}
}
}
return(result);
}
////New
void CTradeCustom::PositionCountByType(const string symbol, int &count[]) {
ArrayResize(count, 6);
ArrayInitialize(count, 0);
int cnt = OrdersTotal();
for (int i = cnt-1; i>=0; i--) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if (OrderSymbol()==symbol && OrderMagicNumber()==mMagic) {
count[(int)OrderType()]++;
}
}
}
return;
}
@@ -0,0 +1,152 @@
/*
Trade.mqh
(For MQL5)
Copyright 2013-2020, Orchard Forex
https://www.orchardforex.com
*/
#include <Trade/Trade.mqh>
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CTradeCustom : public CTrade
{
private:
protected: // member variables
public: // constructors
public:
bool PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType,const ulong deviation=ULONG_MAX);
bool PositionCloseByTicket(const ulong ticket,const ulong deviation=ULONG_MAX);
bool PositionCloseAll(const ulong deviation=ULONG_MAX);
bool OrderCloseAll();
////New
void PositionCountByType(const string symbol, int &count[]);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CTradeCustom::PositionCloseByType(const string symbol, ENUM_POSITION_TYPE positionType, const ulong deviation=ULONG_MAX)
{
bool result = true;
int cnt = PositionsTotal();
for(int i = cnt-1; i>=0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_TYPE)==positionType && PositionGetInteger(POSITION_MAGIC)==m_magic)
{
result &= PositionClose(ticket, deviation);
}
}
else
{
m_result.retcode=TRADE_RETCODE_REJECT;
result = false;
}
}
return(result);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CTradeCustom::PositionCloseByTicket(const ulong ticket,const ulong deviation=-1)
{
bool result = true;
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_MAGIC)==m_magic)
{
result &= PositionClose(ticket, deviation);
}
}
else
{
m_result.retcode=TRADE_RETCODE_REJECT;
result = false;
}
return(result);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CTradeCustom::PositionCloseAll(const ulong deviation=-1)
{
bool result = true;
int cnt = PositionsTotal();
for(int i = cnt-1; i>=0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
result &= PositionClose(ticket, deviation);
}
else
{
m_result.retcode=TRADE_RETCODE_REJECT;
result = false;
}
}
return(result);
}
bool CTradeCustom::OrderCloseAll(){
bool result = true;
int cnt = OrdersTotal();
for(int i = cnt-1; i>=0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
result &= OrderDelete(ticket);
}
else
{
m_result.retcode=TRADE_RETCODE_REJECT;
result = false;
}
}
return(result);
}
////New
void CTradeCustom::PositionCountByType(const string symbol, int &count[])
{
ArrayResize(count, 6);
ArrayInitialize(count, 0);
int cnt = PositionsTotal();
for(int i = cnt-1; i>=0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_MAGIC)==m_magic)
{
count[(int)PositionGetInteger(POSITION_TYPE)]++;
}
}
}
return;
}
//+------------------------------------------------------------------+
@@ -0,0 +1,7 @@
Version 2.03
Added macros to CommonBase to standardise init checking
Moved base classes up one level and removed unnecessary folders
Updated framework number
@@ -0,0 +1,20 @@
//+------------------------------------------------------------------+
//| GridFramework.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//
// The only purpose of this mqh file is to provide a single
// point to change the current framework version
//
// If you place an include to this file in your code you
// will get the version framework defined in this file
// unless your code has already included another
// framework file
#ifndef _FRAMEWORK_VERSION_
#include "GridEA/Framework.mqh"
#endif
@@ -0,0 +1,114 @@
@echo off
:
: Get the current date and time in a format to show in the files
:
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
set ldt=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2% %ldt:~8,2%:%ldt:~10,2%:%ldt:~12,2%
:
: Make sure there is an Extensions folder here
:
if not exist Extensions\ goto :quit
:
: Move into the extensions folder to start
:
cd Extensions
:
: Remove any existing mqh files
:
del *.mqh
:
: Step through the directories here and build up mqh files for each
:
for /D %%f in (*) do (
call :makemqh %%f
)
:
: Build the AllExtensions file
:
call :makemqh .
:
: Move back up to the frameworks folder
:
cd ..
:
: Step through the framework files and build up the new framework.mqh
:
set framework_version=
for /f "tokens=*" %%f in ('dir /b /a:d /o:n "Framework_*"') do (
set framework_version=%%f
)
call :makeframework1 %framework_version%
goto :quit
:makeframework1
set file=Framework.mqh
echo /* > %file%
echo Framework.mqh >> %file%
echo. >> %file%
echo Copyright 2013-2020, Orchard Forex >> %file%
echo https://www.orchardforex.com >> %file%
echo. >> %file%
echo. >> %file%
echo */ >> %file%
echo. >> %file%
echo // >> %file%
echo // The only purpose of this mqh file is to provide a single >> %file%
echo // point to change the current framework version >> %file%
echo // >> %file%
echo // If you place an include to this file in your code you >> %file%
echo // will get the version framework defined in this file >> %file%
echo // unless your code has already included another >> %file%
echo // framework file >> %file%
echo. >> %file%
echo #ifndef _FRAMEWORK_VERSION_ >> %file%
echo #include "%1/Framework.mqh" >> %file%
echo #endif >> %file%
goto :eof
:makemqh
set mcurrent=%cd%
set mpath1=%~f1
for %%f in ("%mpath1%") do set mpath=%%~nxf
set msub=%mpath%/
if "%mcurrent%"=="%mpath1%" set msub=
set mfile=All%mpath%.mqh
echo /* > %mfile%
echo All%mn2%.mqh >> %mfile%
echo. >> %mfile%
echo Copyright 2013-2020, Orchard Forex >> %mfile%
echo https://www.orchardforex.com >> %mfile%
echo. >> %mfile%
echo Auto Generated at %ldt% >> %mfile%
echo. >> %mfile%
echo */ >> %mfile%
echo. >> %mfile%
echo // >> %mfile%
echo // Extension %mn2% go here >> %mfile%
echo // >> %mfile%
for %%f in (%1\*.mqh) do (
if not "%%~nxf"=="%mfile%" echo #include "%msub%%%~nxf" >> %mfile%
)
echo Built include file %mfile%
goto :eof
:quit
echo Finished
pause
goto :eof