diff --git a/Experts/Nkanven/Framework EA/Gervis.mq5 b/Experts/Nkanven/Framework EA/Gervis.mq5 new file mode 100644 index 0000000..36f92a1 --- /dev/null +++ b/Experts/Nkanven/Framework EA/Gervis.mq5 @@ -0,0 +1,197 @@ +/* + + MA Crossover.mq5 + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + + Description: + +*/ + +#property copyright "Copyright 2013-2020, Orchard Forex" +#property link "https://www.orchardforex.com" +#property version "1.00" +#property strict + +// +// This is where we pull in the framework +// +#include + +// +// Input Section +// +// Fast moving average +input int InpFastPeriods = 10; // Fast periods +input ENUM_MA_METHOD InpFastMethod = MODE_SMA; // Fast method +input ENUM_APPLIED_PRICE InpFastAppliedPrice = PRICE_CLOSE; // Fast price + +// Slow moving average +input int InpSlowPeriods = 20; // Slow periods +input ENUM_MA_METHOD InpSlowMethod = MODE_SMA; // Slow method +input ENUM_APPLIED_PRICE InpSlowAppliedPrice = PRICE_CLOSE; // Slow price + +// Bar numbers for comparison +//input int InpBar2 = 2; // Base bar number +//input int InpBar1 = 1; // Crossover bar number + +// +// 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 = 20200701; // Magic Number + +// +// Declare the expert, use the child class name +// +#define CExpert CExpertBase +CExpert *Expert; + +// +// Signals, use the child class names if applicable +// +CSignalBase *EntrySignal; +CSignalBase *ExitSignal; + +// +// Indicators - use the child class name here +// +CIndicatorMA *FastIndicator; +CIndicatorMA *SlowIndicator; + +int OnInit() { + + // + // Instantiate the expert + // + Expert = new CExpert(); + + // + // Assign the default values to the expert + // + Expert.SetVolume(InpVolume); + Expert.SetTradeComment(InpComment); + Expert.SetMagic(InpMagicNumber); + + // + // Create the indicators + // + FastIndicator = new CIndicatorMA(InpFastPeriods, 0, InpFastMethod, InpFastAppliedPrice); + SlowIndicator = new CIndicatorMA(InpSlowPeriods, 0, InpSlowMethod, InpSlowAppliedPrice); + + // + // Set up the signals + // + EntrySignal = new CSignalCrossover(); + EntrySignal.AddIndicator(FastIndicator, 0); + EntrySignal.AddIndicator(SlowIndicator, 0); + + //ExitSignal = Not needed, using the same signal as entry + + // + // Add the signals to the expert + // + Expert.AddEntrySignal(EntrySignal); + Expert.AddExitSignal(EntrySignal); // Same signal + + // + // Finish expert initialisation and check result + // + int result = Expert.OnInit(); + + return(result); + +} + +void OnDeinit(const int reason) { + + EventKillTimer(); + + delete Expert; + //delete ExitSignal; + delete EntrySignal; + delete FastIndicator; + delete SlowIndicator; + + return; + +} + +void OnTick() { + + Expert.OnTick(); + return; + +} + +void OnTimer() { + + Expert.OnTimer(); + return; + +} + +void OnTrade() { + + Expert.OnTrade(); + return; + +} + +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) { + + Expert.OnTradeTransaction(trans, request, result); + return; + +} + +double OnTester() { + + return(Expert.OnTester()); + +} + +void OnTesterInit() { + + Expert.OnTesterInit(); + return; + +} + +void OnTesterPass() { + + Expert.OnTesterPass(); + return; + +} + +void OnTesterDeinit() { + + Expert.OnTesterDeinit(); + return; + +} + +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { + + Expert.OnChartEvent(id, lparam, dparam, sparam); + return; + +} + +void OnBookEvent(const string &symbol) { + + Expert.OnBookEvent(); + return; + +} + + diff --git a/Experts/Nkanven/Gervis.ex5 b/Experts/Nkanven/Gervis.ex5 new file mode 100644 index 0000000..3dc95b3 Binary files /dev/null and b/Experts/Nkanven/Gervis.ex5 differ diff --git a/Experts/Nkanven/Gervis.mq5 b/Experts/Nkanven/Gervis.mq5 new file mode 100644 index 0000000..c948b51 --- /dev/null +++ b/Experts/Nkanven/Gervis.mq5 @@ -0,0 +1,129 @@ +//+------------------------------------------------------------------+ +//| Gervis.mq5 | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" +#property version "1.00" + + +#include +#include + +CiMA* sma; +CiMA* ssma; + +#include // Description of variables +#include // Error library +#include // Prechecks +#include // +#include +#include // Scan for opened positions +#include //Check transaction history +#include //Manage trade dynamic open and close conditions +#include // Check buy and sell entries signals and execute them +#include // Lot size calculate +#include // Close opened positions +#include +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + //sma = new CiMA(); + //ssma = new CiMA(); + + //sma.Create(gSymbol, PERIOD_CURRENT, InpMAPeriods, InpMAAppliedPrice, InpMAMethod, PRICE_CLOSE); + //ssma.Create(gSymbol, PERIOD_CURRENT, 200, InpMAAppliedPrice, InpMAMethod, PRICE_CLOSE); + InitializeVariables(); +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + SymbolInfoTick(_Symbol,last_tick); + + //sma.Refresh(-1); + //ssma.Refresh(-1); + TimeCurrent(dt); + + //gSma = sma.Main(1); + //gSsma = ssma.Main(1); + CheckOperationHours(); + + gCandleHigh = iHigh(gSymbol, PERIOD_CURRENT, 1); + gCandleLow = iLow(gSymbol, PERIOD_CURRENT, 1); + gCandleOpen = iOpen(gSymbol, PERIOD_CURRENT, 1); + gCandleClose = iClose(gSymbol, PERIOD_CURRENT, 1); + + gMinStopLoss =MathAbs(SymbolInfoInteger(gSymbol, SYMBOL_TRADE_STOPS_LEVEL))+20; + +//isQualifiedCandle(0); + OrderClose(); + ScanPositions(); + if(gTotalOpenPositions==0) + gSignalEntry = SIGNAL_ENTRY_BUY; + + CheckSpread(); + entryConditions(); + EvaluateEntry(); + drawLine(); + ExecuteEntry(); + + Comment( + "Expert Advisor by Anselme Nkondog (c) 2021\n "+ + " Hour " + dt.hour + " Min "+ dt.min+"\n" + " Last Highest Price " + gLastHighestPrice + " Price %change "+ gPriceChange); + + } +//+------------------------------------------------------------------+ + +//Initialize variables +void InitializeVariables() + { + gIsNewCandle=false; + gIsTradedThisBar=false; + gIsOperatingHours=false; + gIsSpreadOK=false; + + gLotSize=InpDefaultLotSize; + gTickValue=0; + + gTotalOpenBuy=0; + gTotalOpenSell=0; + + gSignalEntry=SIGNAL_ENTRY_NEUTRAL; + gSignalExit=SIGNAL_EXIT_NEUTRAL; + Print("Variables intialized"); + } + +//Check and return if the spread is not too high +void CheckSpread() + { +//Get the current spread in points, the (int) transforms the double coming from MarketInfo into an integer to avoid a warning when compiling + long SpreadCurr=SymbolInfoInteger(gSymbol, SYMBOL_SPREAD); + Print("Spread ", SpreadCurr); + if(SpreadCurr<=InpMaxSpread) + { + gIsSpreadOK=true; + } + else + { + gIsSpreadOK=false; + } + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Frameworks/Gervis/CommonBase.mqh b/Include/Nkanven/Frameworks/Gervis/CommonBase.mqh new file mode 100644 index 0000000..46edb6a --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/CommonBase.mqh @@ -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); + +} + diff --git a/Include/Nkanven/Frameworks/Gervis/ExpertBase.mqh b/Include/Nkanven/Frameworks/Gervis/ExpertBase.mqh new file mode 100644 index 0000000..e5afc1d --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/ExpertBase.mqh @@ -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; i0); +} + +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; + +} diff --git a/Include/Nkanven/Frameworks/Gervis/Trade/Trade_mql5.mqh b/Include/Nkanven/Frameworks/Gervis/Trade/Trade_mql5.mqh new file mode 100644 index 0000000..3bae1c9 --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/Trade/Trade_mql5.mqh @@ -0,0 +1,66 @@ +/* + Trade.mqh + (For MQL5) + + Copyright 2013-2020, Orchard Forex + https://www.orchardforex.com + +*/ + +#include + +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; + +} diff --git a/Include/Nkanven/Frameworks/Gervis/Updates.txt b/Include/Nkanven/Frameworks/Gervis/Updates.txt new file mode 100644 index 0000000..281bf10 --- /dev/null +++ b/Include/Nkanven/Frameworks/Gervis/Updates.txt @@ -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 \ No newline at end of file diff --git a/Include/Nkanven/Frameworks/GervisFrame.mqh b/Include/Nkanven/Frameworks/GervisFrame.mqh new file mode 100644 index 0000000..faa324f --- /dev/null +++ b/Include/Nkanven/Frameworks/GervisFrame.mqh @@ -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 \ No newline at end of file diff --git a/Include/Nkanven/GDea/ScanPositions.mqh b/Include/Nkanven/GDea/ScanPositions.mqh index 7adfdb0..9125ec1 100644 --- a/Include/Nkanven/GDea/ScanPositions.mqh +++ b/Include/Nkanven/GDea/ScanPositions.mqh @@ -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) diff --git a/Include/Nkanven/GDea/TradingHour.mqh b/Include/Nkanven/GDea/TradingHour.mqh index 7933ad8..249ec7b 100644 --- a/Include/Nkanven/GDea/TradingHour.mqh +++ b/Include/Nkanven/GDea/TradingHour.mqh @@ -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; } + } //+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/CheckHistory.mqh b/Include/Nkanven/Gervis/CheckHistory.mqh new file mode 100644 index 0000000..8c5f1b0 --- /dev/null +++ b/Include/Nkanven/Gervis/CheckHistory.mqh @@ -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 +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/ClosePositions.mqh b/Include/Nkanven/Gervis/ClosePositions.mqh new file mode 100644 index 0000000..219a413 --- /dev/null +++ b/Include/Nkanven/Gervis/ClosePositions.mqh @@ -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); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/EntriesManager.mqh b/Include/Nkanven/Gervis/EntriesManager.mqh new file mode 100644 index 0000000..9e58a69 Binary files /dev/null and b/Include/Nkanven/Gervis/EntriesManager.mqh differ diff --git a/Include/Nkanven/Gervis/EntriesManagerDCA.mqh b/Include/Nkanven/Gervis/EntriesManagerDCA.mqh new file mode 100644 index 0000000..ae18a89 Binary files /dev/null and b/Include/Nkanven/Gervis/EntriesManagerDCA.mqh differ diff --git a/Include/Nkanven/Gervis/HighestPriceLevel.mqh b/Include/Nkanven/Gervis/HighestPriceLevel.mqh new file mode 100644 index 0000000..bb464e6 --- /dev/null +++ b/Include/Nkanven/Gervis/HighestPriceLevel.mqh @@ -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"); + } +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/LotSizeCal.mqh b/Include/Nkanven/Gervis/LotSizeCal.mqh new file mode 100644 index 0000000..2fafb5b --- /dev/null +++ b/Include/Nkanven/Gervis/LotSizeCal.mqh @@ -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(LotSizeInpMaxStopLoss) + { + 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(InpDefaultTakeProfitInpMaxTakeProfit) + { + 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(InpDefaultLotSizeInpMaxLotSize) + { + 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; + } + } diff --git a/Include/Nkanven/Gervis/ScanPositions.mqh b/Include/Nkanven/Gervis/ScanPositions.mqh new file mode 100644 index 0000000..7adfdb0 --- /dev/null +++ b/Include/Nkanven/Gervis/ScanPositions.mqh @@ -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; igLastBarTraded || gLastBarTraded==NULL) + gLastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", gTotalOpenOrders, " - Total buys ", gTotalOpenBuy, " - Total sells ", gTotalOpenSell); + return true; + } \ No newline at end of file diff --git a/Include/Nkanven/Gervis/TradeManager.mqh b/Include/Nkanven/Gervis/TradeManager.mqh new file mode 100644 index 0000000..3bf43bd --- /dev/null +++ b/Include/Nkanven/Gervis/TradeManager.mqh @@ -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 +//+------------------------------------------------------------------+ diff --git a/Include/Nkanven/Gervis/TradingHour.mqh b/Include/Nkanven/Gervis/TradingHour.mqh new file mode 100644 index 0000000..945f776 --- /dev/null +++ b/Include/Nkanven/Gervis/TradingHour.mqh @@ -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= InpTradingStartMin); + + if(InpTradingHourStart==InpTradingHourEnd && dt.hour==InpTradingHourStart) + { + gIsOperatingHours=true; + return; + } + + if(InpTradingHourStart= 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; + } + } +//+------------------------------------------------------------------+