Gervis DCA

This commit is contained in:
Nkondog Anselme
2022-01-01 15:32:05 +01:00
parent 0717013a21
commit 2bb0816712
27 changed files with 1777 additions and 2 deletions
@@ -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_ "1.0"
#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,12 @@
//+------------------------------------------------------------------+
//| GervisFrame.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
#ifndef _FRAMEWORK_VERSION_
#include "Gervis/Framework.mqh"
#endif
+3 -1
View File
@@ -38,7 +38,9 @@ bool ScanPositions()
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
gTotalOpenSell++;
//Increment the total orders count
gTotalOpenOrders++;
gTotalOpenPositions++;
gPositionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
//Find what is the open time of the most recent trade and assign it to LastBarTraded
//this is necessary to check if we already traded in the current candle
if((datetime)PositionGetInteger(POSITION_TIME)>gLastBarTraded || gLastBarTraded==NULL)
+4 -1
View File
@@ -31,15 +31,18 @@ void CheckOperationHours()
gIsOperatingHours=true;
return;
}
if(dt.hour > InpTradingHourStart)
if(dt.hour > InpTradingHourStart && dt.hour < InpTradingHourEnd)
{
gIsOperatingHours=true;
}
}
if(InpTradingHourStart>InpTradingHourEnd && ((dt.hour>=InpTradingHourStart && dt.hour<=23) || (dt.hour<=InpTradingHourEnd && dt.hour>=0)))
{
gIsOperatingHours=true;
}
}
//+------------------------------------------------------------------+
+27
View File
@@ -0,0 +1,27 @@
//+------------------------------------------------------------------+
//| CheckHistory.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
// #define MacrosHello "Hello, world!"
// #define MacrosYear 2010
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
// #import "user32.dll"
// int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
// int ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
// string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+
+38
View File
@@ -0,0 +1,38 @@
//+------------------------------------------------------------------+
//| ClosePositions.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
CTrade trade;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool OrderClose()
{
bool result = true;
int cnt = OrdersTotal();
if(cnt == 1)
{
for(int i = cnt-1; i>=0; i--)
{
ulong ticket = OrderGetTicket(i);
if(OrderSelect(ticket))
{
result &= trade.OrderDelete(ticket);
}
else
{
result = false;
}
}
}
return(result);
}
//+------------------------------------------------------------------+
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,33 @@
//+------------------------------------------------------------------+
//| HighestPriceLevel.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void drawLine()
{
string obj_name = "Recent high";
if(highestPrice != gLastHighestPrice)
{
ObjectDelete(current_chart_id, obj_name);
}
ObjectCreate(current_chart_id, obj_name, OBJ_HLINE, 0, iTime(gSymbol,_Period,0), gLastHighestPrice);
//--- set color to Red
ObjectSetInteger(current_chart_id, obj_name, OBJPROP_COLOR, clrRed);
//--- set object width
ObjectSetInteger(current_chart_id, obj_name, OBJPROP_WIDTH, 1);
//--- Move the line
ObjectMove(current_chart_id, obj_name, 0, iTime(gSymbol,_Period,0), gLastHighestPrice);
highestPrice = gLastHighestPrice;
Print("Drawing line");
}
//+------------------------------------------------------------------+
+59
View File
@@ -0,0 +1,59 @@
//+------------------------------------------------------------------+
//| LotSizeCal.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//Lot Size Calculator
void LotSizeCalculate(double SL=0)
{
//If the position size is dynamic
if(InpRiskDefaultSize==RISK_DEFAULT_AUTO)
{
//If the stop loss is not zero then calculate the lot size
if(SL!=0)
{
double RiskBaseAmount=0;
double RiskBase=0;
//TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty
double TickValue=SymbolInfoDouble(gSymbol,SYMBOL_TRADE_TICK_VALUE);
//Define the base for the risk calculation depending on the parameter chosen
if(RiskBase==RISK_BASE_BALANCE)
RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE);
if(RiskBase==RISK_BASE_EQUITY)
RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY);
if(RiskBase==RISK_BASE_FREEMARGIN)
RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN);
//Calculate the Position Size
LotSize=((RiskBaseAmount*InpMaxRiskPerTrade/100)/(SL*TickValue));
}
//If the stop loss is zero then the lot size is the default one
if(SL==0)
{
LotSize=InpDefaultLotSize;
}
}
//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size
LotSize=MathFloor(LotSize/SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_STEP);
printf("Lot size ", LotSize);
//Limit the lot size in case it is greater than the maximum allowed by the user
if(LotSize>InpMaxLotSize)
LotSize=InpMaxLotSize;
//Limit the lot size in case it is greater than the maximum allowed by the broker
if(LotSize>SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX))
LotSize=SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX);
Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MAX));
//If the lot size is too small then set it to 0 and don't trade
if(LotSize<InpMinLotSize || LotSize < SymbolInfoDouble(gSymbol,SYMBOL_VOLUME_MIN))
{
LotSize=0;
Print("Lot size too small : ", LotSize);
}
}
+172
View File
@@ -0,0 +1,172 @@
//+------------------------------------------------------------------+
//| Parameters.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//Enumerative for the entry signal value
enum ENUM_SIGNAL_ENTRY
{
SIGNAL_ENTRY_NEUTRAL=0, //SIGNAL ENTRY NEUTRAL
SIGNAL_ENTRY_BUY=1, //SIGNAL ENTRY BUY
SIGNAL_ENTRY_SELL=2, //SIGNAL ENTRY BUY
};
//Enumerative for the exit signal value
enum ENUM_SIGNAL_EXIT
{
SIGNAL_EXIT_NEUTRAL=0, //SIGNAL EXIT NEUTRAL
SIGNAL_EXIT_BUY=1, //SIGNAL EXIT BUY
SIGNAL_EXIT_SELL=-1, //SIGNAL EXIT SELL
SIGNAL_EXIT_ALL=2, //SIGNAL EXIT ALL
};
//Enumerative for the allowed trading direction
enum ENUM_TRADING_ALLOW_DIRECTION
{
TRADING_ALLOW_BOTH=0, //ALLOW BOTH BUY AND SELL
TRADING_ALLOW_BUY=1, //ALLOW BUY ONLY
TRADING_ALLOW_SELL=-1, //ALLOW SELL ONLY
};
//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
};
//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 Stop Loss mode
enum ENUM_MODE_SL
{
SL_FIXED=0, //FIXED STOP LOSS
SL_AUTO=1, //AUTOMATIC STOP LOSS
};
//Enumerative for the Take Profit Mode
enum ENUM_MODE_TP
{
TP_FIXED=0, //FIXED TAKE PROFIT
TP_AUTO=1, //AUTOMATIC TAKE PROFIT
};
//Enumerative for the stop loss calculation
enum ENUM_MODE_SL_BY
{
SL_BY_POINTS=0, //STOP LOSS PASSED IN POINTS
SL_BY_PRICE=1, //STOP LOSS PASSED BY PRICE
};
//Enumerative for candle type
enum ENUM_CANDLE_TYPE
{
NEUTRAL_CANDLE=0,
BEARISH_CANDLE=1,
BULLISH_CANDLE=2,
};
//Enumerative for price momentum
enum ENUM_PRICE_MOMENTUM
{
UP=2,
DOWN=1,
NEUTRAL=0,
};
struct LastTransaction
{
string time;
int type;
double profit;
} lt;
//
// Input Section
//
// Moving average
input int InpMAPeriods = 10; // MA Periods
input ENUM_MA_METHOD InpMAMethod = MODE_SMA; // MA Method
input ENUM_APPLIED_PRICE InpMAAppliedPrice = PRICE_CLOSE; // MA price
input string Comment_0="=========="; //Risk Management Settings
input ENUM_RISK_DEFAULT_SIZE InpRiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode
input double InpDefaultLotSize=1; //Position Size (if fixed or if no stop loss defined)
input ENUM_RISK_BASE InpRiskBase=RISK_BASE_BALANCE; //Risk Base
input double InpMaxRiskPerTrade=0.5; //Percentage To Risk Each Trade
input double InpMinLotSize=0.01; //Minimum Position Size Allowed
input double InpMaxLotSize=100; //Maximum Position Size Allowed
input int InpMaxSpread=20; //Maximum Spread Allowed
input int InpSlippage=5; //Maximum Slippage Allowed in points
input ENUM_MODE_SL InpStopLossMode=SL_AUTO; //Stop Loss Mode
input int InpDefaultStopLoss=0; //Default Stop Loss In Points (0=No Stop Loss)
input int InpMinStopLoss=0; //Minimum Allowed Stop Loss In Points
input int InpMaxStopLoss=5000; //Maximum Allowed Stop Loss In Points
input bool InpAtrStopLoss=false; //Set Stop loss based on ATR
input int InpAtrStopLossFactor=3; //Multiplicator for ATR stop loss
input ENUM_MODE_TP InpTakeProfitMode=TP_AUTO; //Take Profit Mode
input int InpDefaultTakeProfit=0; //Default Take Profit In Points (0=No Take Profit)
input int InpMinTakeProfit=0; //Minimum Allowed Take Profit In Points
input int InpMaxTakeProfit=5000; //Maximum Allowed Take Profit In Points
input double InpTakeProfitPercent=1.0; //Take Profit percent on risk base
//
// Some standard inputs,
// remember to change the default magic for each EA
//
input double InpVolume = 0.01; // Default order size
input string InpComment = __FILE__; // Default trade comment
input int InpMagicNumber = 198901; // Magic Number
input string Comment_1="=========="; //Trading Hours Settings
input bool InpUseTradingHours=false; //Limit Trading Hours
input int InpTradingHourStart=1; //Trading Start Hour (Broker Server Hour)
input int InpTradingHourEnd=23; //Trading End Hour (Broker Server Hour)
input int InpTradingStartMin=30; //Trading Start minute (Broker Server Hour)
input int InpTradingEndMin=0; //Trading End minute
bool gIsNewCandle=false;
bool gIsTradedThisBar=false;
bool gIsOperatingHours=false;
bool gIsPreChecksOk=false; //Indicates if the pre checks are satisfied
bool gIsSpreadOK=false; //Indicates if the spread is low enough to trade
double gLotSize=InpDefaultLotSize;
int gTickValue=0;
int gTotalOpenBuy=0;
int gTotalOpenSell=0;
int gTotalOpenOrders=0;
int gTotalOpenPositions=0;
int gOrderOpRetry=5;
double gBuyStopLossPrice, gMinStopLoss;
double gSellStopLossPrice;
double gBuyEntryPrice;
double gSellEntryPrice;
double gPositionOpenPrice, gLastHighestPrice, highestPrice, gPriceChange;
string gSymbol = Symbol();
datetime gLastBarTraded=NULL;
double gSma, gSsma, gHighSma, gLowSma, gPrevSma;
double gCandleHigh, gCandleLow, gCandleOpen, gCandleClose;
double LotSize=0;
long current_chart_id = ChartID();
MqlTick last_tick;
MqlDateTime dt;
ENUM_SIGNAL_ENTRY gSignalEntry=SIGNAL_ENTRY_NEUTRAL; //Entry signal variable
ENUM_SIGNAL_EXIT gSignalExit=SIGNAL_EXIT_NEUTRAL;
+62
View File
@@ -0,0 +1,62 @@
//+------------------------------------------------------------------+
//| Prechecks.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//Perform integrity checks when the EA is loaded
void CheckPreChecks()
{
gIsPreChecksOk=true;
//Check if Live Trading is enabled in MT4
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
{
gIsPreChecksOk=false;
Print("Live Trading is not enabled, please enable it in MT4 and chart settings");
return;
}
//Check if the default stop loss you are setting in above the minimum and below the maximum
if(InpDefaultStopLoss<InpMinStopLoss || InpDefaultStopLoss>InpMaxStopLoss)
{
gIsPreChecksOk=false;
Print("Default Stop Loss must be between Minimum and Maximum Stop Loss Allowed");
return;
}
//Check if the default take profit you are setting in above the minimum and below the maximum
if(InpDefaultTakeProfit<InpMinTakeProfit || InpDefaultTakeProfit>InpMaxTakeProfit)
{
gIsPreChecksOk=false;
Print("Default Take Profit must be between Minimum and Maximum Take Profit Allowed");
return;
}
//Check if the Lot Size is between the minimum and maximum
if(InpDefaultLotSize<InpMinLotSize || InpDefaultLotSize>InpMaxLotSize)
{
gIsPreChecksOk=false;
Print("Default Lot Size must be between Minimum and Maximum Lot Size Allowed");
return;
}
//Slippage must be >= 0
if(InpSlippage<0)
{
gIsPreChecksOk=false;
Print("Slippage must be a positive value");
return;
}
//MaxSpread must be >= 0
if(InpMaxSpread<0)
{
gIsPreChecksOk=false;
Print("Maximum Spread must be a positive value");
return;
}
//MaxRiskPerTrade is a % between 0 and 100
if(InpMaxRiskPerTrade<0 || InpMaxRiskPerTrade>100)
{
gIsPreChecksOk=false;
Print("Maximum Risk Per Trade must be a percentage between 0 and 100");
return;
}
}
+49
View File
@@ -0,0 +1,49 @@
//+------------------------------------------------------------------+
//| ScanPositions.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//Scan all positions to find the ones submitted by the EA
//NOTE This function is defined as bool because we want to return true if it is successful and false if it fails
bool ScanPositions()
{
//Scan all the orders, retrieving some of the details
gTotalOpenOrders = 0;
gTotalOpenBuy = 0;
gTotalOpenSell = 0;
for(int i=0; i<PositionsTotal(); i++)
{
//If there is a problem reading the order print the error, exit the function and return false
if(PositionGetTicket(i) == 0)
{
int Error=GetLastError();
string ErrorText=GetLastErrorText(Error);
Print("ERROR - Unable to select the order - ",Error," - ",ErrorText);
return false;
}
//If the order is not for the instrument on chart we can ignore it
if(PositionGetSymbol(i)!=gSymbol)
continue;
//If the order has Magic Number different from the Magic Number of the EA then we can ignore it
if(PositionGetInteger(POSITION_MAGIC)!=InpMagicNumber)
continue;
//If it is a buy order then increment the total count of buy orders
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
gTotalOpenBuy++;
//If it is a sell order then increment the total count of sell orders
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
gTotalOpenSell++;
//Increment the total orders count
gTotalOpenOrders++;
//Find what is the open time of the most recent trade and assign it to LastBarTraded
//this is necessary to check if we already traded in the current candle
if((datetime)PositionGetInteger(POSITION_TIME)>gLastBarTraded || gLastBarTraded==NULL)
gLastBarTraded=(datetime)PositionGetInteger(POSITION_TIME);
}
Print("Total positions ", gTotalOpenOrders, " - Total buys ", gTotalOpenBuy, " - Total sells ", gTotalOpenSell);
return true;
}
+27
View File
@@ -0,0 +1,27 @@
//+------------------------------------------------------------------+
//| TradeManager.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
// #define MacrosHello "Hello, world!"
// #define MacrosYear 2010
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
// #import "user32.dll"
// int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
// int ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
// string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+
+49
View File
@@ -0,0 +1,49 @@
//+------------------------------------------------------------------+
//| TradingHour.mqh |
//| Copyright 2021, Nkondog Anselme Venceslas |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Nkondog Anselme Venceslas"
#property link "https://www.mql5.com"
//Check and return if it is operation hours or not
void CheckOperationHours()
{
//If we are not using operating hours then IsOperatingHours is true and I skip the other checks
if(!InpUseTradingHours)
{
gIsOperatingHours=true;
return;
}
//Check if the current hour is between the allowed hours of operations, if so IsOperatingHours is set true
Print("1 this is ", (InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart));
Print("2 this is ", (InpTradingHourStart<InpTradingHourEnd));
Print("3 this is ", InpTradingHourStart == dt.hour && dt.min >= InpTradingStartMin);
if(InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart)
{
gIsOperatingHours=true;
return;
}
if(InpTradingHourStart<InpTradingHourEnd)
{
if(InpTradingHourStart == dt.hour && dt.min >= InpTradingStartMin)
{
gIsOperatingHours=true;
return;
}
if(dt.hour > InpTradingHourStart)
{
gIsOperatingHours=true;
return;
}
}
if(InpTradingHourStart>InpTradingHourEnd && ((dt.hour>=InpTradingHourStart && dt.hour<=23) || (dt.hour<=InpTradingHourEnd && dt.hour>=0)))
{
gIsOperatingHours=true;
return;
}
}
//+------------------------------------------------------------------+