diff --git a/.gitignore b/.gitignore index 29bd3c9..9119e28 100644 --- a/.gitignore +++ b/.gitignore @@ -69,8 +69,8 @@ Experts/Advisors/ Experts/Examples/ Include/Arrays/ Include/C* -Include/E* -Include/F* +Include/Expert/ +Include/Files/ Include/G* Include/I Include/M* diff --git a/Include/E_CheckHistory.mqh b/Include/E_CheckHistory.mqh new file mode 100644 index 0000000..aa967ff Binary files /dev/null and b/Include/E_CheckHistory.mqh differ diff --git a/Include/E_ClosePositions.mqh b/Include/E_ClosePositions.mqh new file mode 100644 index 0000000..7b061e4 --- /dev/null +++ b/Include/E_ClosePositions.mqh @@ -0,0 +1,81 @@ +//+------------------------------------------------------------------+ +//| E_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; + +// We declare a function CloseOpenPositions of type int and we want to return +// the number of positions that are closed. +void CloseOpenPositions() + { + + int TotalClose=0; // We want to count how many orders have been closed. + int c_slippage = Slippage; +Print("Close position status ", ClosePosition); +// Normalization of the slippage. + if(_Digits==3 || _Digits==5) + { + c_slippage=c_slippage*10; + } + +// We scan all the orders backwards. +// This is required as if we start from the first order, we will have problems with the counters and the loop. + for(int i=PositionsTotal()-1; i>=0; i--) + { + + ulong ticket = PositionGetTicket(i); + + Print("Position profit is ", PositionGetDouble(POSITION_PROFIT)); + PositionProfit = PositionGetDouble(POSITION_PROFIT); + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspana) + { + // We select the order of index i, selecting by position and from the pool of market/pending trades. + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspana) + { + // We select the order of index i, selecting by position and from the pool of market/pending trades. + //If the selection is successful we try to close the order. + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + + if(ClosePosition) + { + if(trade.PositionClose(ticket, c_slippage)) + { + TotalClose++; + ClosePosition = false; + } + else + { + // If the order fails to be closed, we print the error. + Print("Order failed to close with error - ",GetLastError()); + } + } + // We can use a delay if the execution is too fast. + // Sleep() will wait X milliseconds before proceeding with the code. + // Sleep(300); + } + } +//+------------------------------------------------------------------+ diff --git a/Include/E_EntriesManagement.mqh b/Include/E_EntriesManagement.mqh new file mode 100644 index 0000000..d69973d Binary files /dev/null and b/Include/E_EntriesManagement.mqh differ diff --git a/Include/E_Parameters.mqh b/Include/E_Parameters.mqh new file mode 100644 index 0000000..4eb0be0 Binary files /dev/null and b/Include/E_Parameters.mqh differ diff --git a/Include/E_ScanPositions.mqh b/Include/E_ScanPositions.mqh new file mode 100644 index 0000000..53f5789 --- /dev/null +++ b/Include/E_ScanPositions.mqh @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| E_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 + TotalOpenOrders = 0; + TotalOpenBuy = 0; + TotalOpenSell = 0; + for(int i=0; iLastBarTraded || LastBarTraded==0) + LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); + } + Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell); + return true; + } \ No newline at end of file diff --git a/Include/E_TradeManagement.mqh b/Include/E_TradeManagement.mqh new file mode 100644 index 0000000..9b95978 --- /dev/null +++ b/Include/E_TradeManagement.mqh @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| E_TradeManagement.mqh | +//| Copyright 2021, Nkondog Anselme Venceslas | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2021, Nkondog Anselme Venceslas" +#property link "https://www.mql5.com" + +//Done for the day after a profitable trade +//If closed trade was opened the day before, look for trade opportunities +double minProfitAllow = AccountInfoDouble(ACCOUNT_BALANCE)*(Breakevent/100); +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void TradeManager() + { + CanSell = true; + CanBuy = true; + + if(lt.time == TimeToString(TimeCurrent(), TIME_DATE)) + { + if(lt.type == DEAL_TYPE_BUY && lt.profit < 0) + { + CanBuy = false; + } + if(lt.type = DEAL_TYPE_SELL && lt.profit < 0) + { + CanSell = false; + } + } + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ProfitRunner() + { + Print("Min acceptablbe profit ", minProfitAllow); + ClosePosition = false; + if(PositionProfit > minProfitAllow) + FollowProfit=true; + + if(FollowProfit) + { + if(Kijunsen > iClose(Symb, _Period, 1) && TotalOpenBuy > 0) + { + ClosePosition = true; + } + if(Kijunsen < iClose(Symb, _Period, 1) && TotalOpenSell > 0) + { + ClosePosition = true; + } + } + Print("Looking to close this position ", ClosePosition, " Follow profit ", FollowProfit); + } +//+------------------------------------------------------------------+ diff --git a/Include/ExpertBase.mqh b/Include/ExpertBase.mqh new file mode 100644 index 0000000..e5afc1d --- /dev/null +++ b/Include/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; i