From fe5c50066a91c9737964c719db334b833d8ed1e3 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 25 Jan 2025 03:57:57 +0330 Subject: [PATCH] Backup Workspace ... --- .../Classes/x-saherelm.base.class.mq5 | 101 + .../Classes/x-saherelm.x-account.class.mq5 | 398 + .../Classes/x-saherelm.x-alert.class.mq5 | 1577 +++ .../Classes/x-saherelm.x-app-dialog.class.mq5 | 275 + .../x-saherelm.x-bar.analyser.class.mq5 | 5633 ++++++++ .../Classes/x-saherelm.x-cobject.class.mq5 | 3279 +++++ .../Classes/x-saherelm.x-expert.class.mq5 | 997 ++ .../Classes/x-saherelm.x-helper.class.mq5 | 148 + .../Classes/x-saherelm.x-http.class.mq5 | 373 + .../Classes/x-saherelm.x-md5.class.mq5 | 445 + .../Classes/x-saherelm.x-poi.class.mq5 | 4234 ++++++ .../Classes/x-saherelm.x-poi.drawer.class.mq5 | 4801 +++++++ .../Classes/x-saherelm.x-trade.class.mq5 | 3941 ++++++ BKPS/14031106/Documents/BKP/1/1.mq5 | 580 + BKPS/14031106/Documents/BKP/1/2.mq5 | 195 + BKPS/14031106/Documents/BKP/1/3.mq5 | 319 + BKPS/14031106/Documents/BKP/1/4.mq5 | 530 + BKPS/14031106/Documents/BKP/1/tmp.codes.mq5 | 729 + ...-121.smc.market.cycle.helper.class.old.mq5 | 4143 ++++++ .../BKP/1/x-121.smc.twpv.conditions2.mq5 | 137 + .../BKP/1/x-121.smc.x.signal.lib copy.mq5 | 1983 +++ .../BKP/1/x-121.smc.x.signal.lib.mq5 | 1943 +++ .../BKP/1/x-121.smc.xobgpv.signal.lib.mq5 | 1020 ++ .../BKP/1/x-121.smc.xobspv.signal.lib.mq5 | 1138 ++ .../1/x-121.smc.xtwpv.old.1.signal.lib.mq5 | 1420 ++ .../1/x-121.smc.xtwpv.old.12signal.lib.mq5 | 1367 ++ .../BKP/1/x-121.smc.xtwpv.old.3signal.lib.mq5 | 957 ++ .../1/x-121.smc.xtwpv.old.4.signal.lib.mq5 | 1083 ++ .../BKP/1/x-121.smc.xtwpv.old.signal.lib.mq5 | 2060 +++ .../BKP/1/x-saherelm.x121.helper.mq5 | 4636 +++++++ .../Documents/BKP/1/x-saherelm.x121.mq5 | 2407 ++++ .../BKP/1/x-saherelm.x121.old.helper.mq5 | 5171 +++++++ .../Documents/BKP/1/x-saherelm.x121.old.mq5 | 2321 ++++ .../BKP/1/x-saherelm.x121.xempty.mq5 | 325 + .../Documents/BKP/2/tmp.signalling.mq5 | 1302 ++ .../BKP/2/x-121.smc.xpvt.signal.lib.mq5 | 2484 ++++ .../BKP/2/x-121.smc.xpz.signal.lib.mq5 | 1700 +++ .../BKP/2/x-121.smc.xrspvi.signal.lib.mq5 | 2483 ++++ .../BKP/2/x-121.smc.xstrpv.signal.lib.mq5 | 2097 +++ .../Diagrams/Position Protection.drawio | 279 + .../Documents/JsModules/x-color.tools.js | 506 + .../Documents/JsModules/x-file.tools.js | 887 ++ .../Documents/JsModules/x-shell.tools.js | 219 + .../JsModules/x-type-detector.tools.js | 268 + .../Documents/JsModules/x-value.tools.js | 1528 ++ .../Temlates/x-saherelm.x-ea.template.ea.mq5 | 542 + .../Temlates/x-saherelm.x-panel.ea.mq5 | 575 + .../Experts/x-saherelm.x-121.smc.ea.ex5 | Bin 0 -> 393866 bytes .../Experts/x-saherelm.x-121.smc.ea.mq5 | 461 + .../Helpers/x-saherelm.x121.helper.mq5 | 2932 ++++ .../Helpers/x-saherelm.x121.xatr.helper.mq5 | 1215 ++ .../Helpers/x-saherelm.x121.xche.helper.mq5 | 1314 ++ .../Helpers/x-saherelm.x121.xdon.helper.mq5 | 1337 ++ .../Helpers/x-saherelm.x121.xpv.helper.mq5 | 2274 +++ .../Helpers/x-saherelm.x121.xstr.helper.mq5 | 1054 ++ .../Helpers/x-saherelm.x121.xvwap.helper.mq5 | 1435 ++ .../Helpers/x-saherelm.xcc.helper.mq5 | 249 + .../Helpers/x-saherelm.xct.helper.mq5 | 231 + .../Indicators/x-saherelm.x121.xatr.ex5 | Bin 0 -> 20850 bytes .../Indicators/x-saherelm.x121.xatr.mq5 | 648 + .../Indicators/x-saherelm.x121.xche.ex5 | Bin 0 -> 19730 bytes .../Indicators/x-saherelm.x121.xche.mq5 | 624 + .../Indicators/x-saherelm.x121.xdon.ex5 | Bin 0 -> 15582 bytes .../Indicators/x-saherelm.x121.xdon.mq5 | 692 + .../Indicators/x-saherelm.x121.xpv.ex5 | Bin 0 -> 40166 bytes .../Indicators/x-saherelm.x121.xpv.mq5 | 1002 ++ .../Indicators/x-saherelm.x121.xstr.ex5 | Bin 0 -> 16008 bytes .../Indicators/x-saherelm.x121.xstr.mq5 | 636 + .../Indicators/x-saherelm.x121.xvwap.ex5 | Bin 0 -> 16238 bytes .../Indicators/x-saherelm.x121.xvwap.mq5 | 711 + BKPS/14031106/Indicators/x-saherelm.xcc.ex5 | Bin 0 -> 12988 bytes BKPS/14031106/Indicators/x-saherelm.xcc.mq5 | 437 + BKPS/14031106/Indicators/x-saherelm.xct.ex5 | Bin 0 -> 17034 bytes BKPS/14031106/Indicators/x-saherelm.xct.mq5 | 262 + .../Libraries/x-saherelm.common.lib.mq5 | 10115 ++++++++++++++ .../Libraries/x-saherelm.draw.lib.mq5 | 2620 ++++ .../Libraries/x-saherelm.x-poi.lib.mq5 | 11521 ++++++++++++++++ .../Libraries/x-saherelm.x-trade.lib.mq5 | 6032 ++++++++ .../Classes/x-121.smc.base.strategy.class.mq5 | 1075 ++ .../Classes/x-121.smc.cobjects.class.mq5 | 35 + .../Classes/x-121.smc.ea.panel.class.mq5 | 63 + .../x-121.smc.market.cycle.helper.class.mq5 | 779 ++ .../x-121.smc.x-tradehandler.class.mq5 | 4336 ++++++ .../Experts/x-121.smc.expert.class.mq5 | 2501 ++++ .../Libraries/x-121.smc.guard.lib.mq5 | 1608 +++ .../X121SMCEA/Libraries/x-121.smc.lib.mq5 | 749 + .../Signals/x-121.smc.x.signal.lib.mq5 | 1724 +++ .../Signals/x-121.smc.xobpv.signal.lib.mq5 | 1724 +++ .../Strategy/x-121.smc.strategy.class.mq5 | 1366 ++ 89 files changed, 139298 insertions(+) create mode 100644 BKPS/14031106/Classes/x-saherelm.base.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-account.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-alert.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-app-dialog.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-bar.analyser.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-cobject.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-expert.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-helper.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-http.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-md5.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-poi.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-poi.drawer.class.mq5 create mode 100644 BKPS/14031106/Classes/x-saherelm.x-trade.class.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/1.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/2.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/3.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/4.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/tmp.codes.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.market.cycle.helper.class.old.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.twpv.conditions2.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib copy.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xobgpv.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xobspv.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.1.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.12signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.3signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.4.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-saherelm.x121.helper.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-saherelm.x121.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.helper.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.mq5 create mode 100644 BKPS/14031106/Documents/BKP/1/x-saherelm.x121.xempty.mq5 create mode 100644 BKPS/14031106/Documents/BKP/2/tmp.signalling.mq5 create mode 100644 BKPS/14031106/Documents/BKP/2/x-121.smc.xpvt.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/2/x-121.smc.xpz.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/2/x-121.smc.xrspvi.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/BKP/2/x-121.smc.xstrpv.signal.lib.mq5 create mode 100644 BKPS/14031106/Documents/Diagrams/Position Protection.drawio create mode 100644 BKPS/14031106/Documents/JsModules/x-color.tools.js create mode 100644 BKPS/14031106/Documents/JsModules/x-file.tools.js create mode 100644 BKPS/14031106/Documents/JsModules/x-shell.tools.js create mode 100644 BKPS/14031106/Documents/JsModules/x-type-detector.tools.js create mode 100644 BKPS/14031106/Documents/JsModules/x-value.tools.js create mode 100644 BKPS/14031106/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 create mode 100644 BKPS/14031106/Documents/Temlates/x-saherelm.x-panel.ea.mq5 create mode 100644 BKPS/14031106/Experts/x-saherelm.x-121.smc.ea.ex5 create mode 100644 BKPS/14031106/Experts/x-saherelm.x-121.smc.ea.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.xatr.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.xche.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.xdon.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.xpv.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.xstr.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.x121.xvwap.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.xcc.helper.mq5 create mode 100644 BKPS/14031106/Helpers/x-saherelm.xct.helper.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xatr.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xatr.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xche.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xche.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xdon.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xdon.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xpv.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xpv.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xstr.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xstr.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xvwap.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.x121.xvwap.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.xcc.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.xcc.mq5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.xct.ex5 create mode 100644 BKPS/14031106/Indicators/x-saherelm.xct.mq5 create mode 100644 BKPS/14031106/Libraries/x-saherelm.common.lib.mq5 create mode 100644 BKPS/14031106/Libraries/x-saherelm.draw.lib.mq5 create mode 100644 BKPS/14031106/Libraries/x-saherelm.x-poi.lib.mq5 create mode 100644 BKPS/14031106/Libraries/x-saherelm.x-trade.lib.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Experts/x-121.smc.expert.class.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Libraries/x-121.smc.guard.lib.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Libraries/x-121.smc.lib.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Signals/x-121.smc.x.signal.lib.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Signals/x-121.smc.xobpv.signal.lib.mq5 create mode 100644 BKPS/14031106/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 diff --git a/BKPS/14031106/Classes/x-saherelm.base.class.mq5 b/BKPS/14031106/Classes/x-saherelm.base.class.mq5 new file mode 100644 index 0000000..0e7557f --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.base.class.mq5 @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XBaseClass +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// XBase Class ... +class XCBase +{ + // + // Public ... + public: + // + // Protected ... + + // + // Represent Basic Unique Tag ... + virtual string GetTag() { + return NULL; + } + + // + // Retrieve Class Token ... + virtual string GetToken() { + return NULL; + } + + // + // Protected + protected: + // + // Private ... + private: +}; + +// +template +string GenerateSpecifiedCommonSummary( + T &mItem, + string separator = "\n", + bool includeScores = true, + bool setLabel = false // +) +{ + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + mItem.GenerateScore( + bullishScore, + bearishScore // + ); + + // + result = + // + (!setLabel + ? "" + : "Commons:" + separator) + + "---------------" + separator + + "Symbol: " + mItem.symbol + separator + + "Period: " + ToString(mItem.period) + separator + + "Time: " + ToString(mItem.time) + separator + + (includeScores + ? "---------------" + separator + + "Scores:" + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "---------------" + separator + : "") + + "" + // + ; + + // + return result; +} + +// diff --git a/BKPS/14031106/Classes/x-saherelm.x-account.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-account.class.mq5 new file mode 100644 index 0000000..c451091 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-account.class.mq5 @@ -0,0 +1,398 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAccount +// Description: provides all Account requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XCAccount : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + void XCAccount() + { + // + mAccountInfo = new CAccountInfo(); + } + + // + // Deconstructor ... + void ~XCAccount() + { + } + + // + // START Provided Functions ... + // + + // + // User Account ... + long GetUserAccount() + { + return mAccountInfo.Login(); + } + + // + // Account Leverage ... + long GetLeverage() + { + return mAccountInfo.Leverage(); + } + + // + // Get Trade Expert State ... + bool CanExpertTrade() + { + return mAccountInfo.TradeExpert(); + } + + // + // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... + // -------------------------- + // ACCOUNT_TRADE_MODE_DEMO + // ACCOUNT_TRADE_MODE_CONTEST + // ACCOUNT_TRADE_MODE_REAL + ENUM_ACCOUNT_TRADE_MODE GetTradeMode() + { + return mAccountInfo.TradeMode(); + } + + // + // Get Account Balance ... + double GetBalance() + { + return mAccountInfo.Balance(); + } + + // + // Get the amount of give Credit ... + double GetCredit() + { + return mAccountInfo.Credit(); + } + + // + // Get the amount of current Profit on account ... + double GetProfit() + { + return mAccountInfo.Profit(); + } + + // + // Get the amount of current Equity on account ... + double GetEquity() + { + return mAccountInfo.Equity(); + } + + // + // Get the amount of reserved Margin ... + double GetMargin() + { + return mAccountInfo.Margin(); + } + + // + // Get the amount of free Margin ... + double GetFreeMargin() + { + return mAccountInfo.FreeMargin(); + } + + // + // Get the Level of Margin ... + double GetMarginLevel() + { + return mAccountInfo.MarginLevel(); + } + + // + // Get the Level Of Margin for a Deposit ... + double GetMarginCall() + { + return mAccountInfo.MarginCall(); + } + + // + // Get the Level of Margin for Stop out ... + double GetMarginStopOut() + { + return mAccountInfo.MarginStopOut(); + } + + // + // Get the Client Name ... + string GetName() + { + return mAccountInfo.Name(); + } + + // + // Get the Trade Server Name ... + string GetServerName() + { + return mAccountInfo.Server(); + } + + // + // Get deposit Currency Name ... + string GetCurrency() + { + return mAccountInfo.Currency(); + } + + // + // Get the Company Name that serves an Account ... + string GetCompany() + { + return mAccountInfo.Company(); + } + + // + // Calculate Profits for the current account based on passed parameters ... + double CalculateTradeProfit( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry, // open price + double exit // close price + ) + { + // + double result = mAccountInfo.OrderProfitCheck( + symbol, + type, + volume, + entry, + exit); + + // + return result; + } + + // + // Calculate amount of margin which required for trade operation ... + double CalculateMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.MarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate amount of free margin left after trade operation ... + double CalculateFreeMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.FreeMarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate the Maximum possible volume of trade operation ... + double CalculateMaxVolume( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double entry, // open price + double percent = 100 // percent of available margin + ) + { + // + double result = mAccountInfo.MaxLotCheck( + symbol, + type, + entry, + percent); + + // + return result; + } + + // + // Calculate Point Value for Given Symbol based on Account ... + double GetPointValue( + string symbol // trading symbol + ) + { + // + double result = 0; + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + double ticksPerPoint = tickSize / point; + + // + result = tickValue / ticksPerPoint; + + // + return result; + } + + // + // Calculate Risk Amount based on account Currency by Providing: + // Points and Volume ... + double CalculateRiskAmount( + string symbol, // trading symbol + double points, // amount of Risk Points + double volume // position Volume + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = pointValue * volume * points; + + // + return result; + } + + // + // Calculate Risk Points based on account Currency by Providing: + // Volume and Amount ... + double CalculateRiskPoints( + string symbol, // trading symbol + double volume, // position Volume + double amount // amount of Risk based on Account Currency + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * volume); + + // + return result; + } + + // + // Calculate Volume based on account Currency by Providing: + // Amount and Risk Points ... + double CalculateVolume( + string symbol, // trading symbol + double amount, // amount of Risk based on Account Currency + double points // amount of Risk Points + ) + { + // + double result = 0; + + // + points = + points <= 0 + ? 10 + : points; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * points); + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Account Info ... + CAccountInfo mAccountInfo; +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/BKPS/14031106/Classes/x-saherelm.x-alert.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-alert.class.mq5 new file mode 100644 index 0000000..2c7ef5e --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-alert.class.mq5 @@ -0,0 +1,1577 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAlert +// Description: provides all Alerts requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Class Definition ... + +class XCAlert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCAlert( + string prefix = "X-Alert", // Alerts Prefixe + bool enableAlerts = true, // Enable Alerts + bool logAlerts = true, // Log Alerts + bool terminalAlerts = false, // Terminal Alerts + bool mailAlerts = false, // Mail Alerts + bool pushAlerts = false // Push Alerts + ) + { + // + mPrefix = prefix; + mLogAlerts = logAlerts; + mMailAlerts = mailAlerts; + mPushAlerts = pushAlerts; + mEnableAlerts = enableAlerts; + mTerminalAlerts = terminalAlerts; + + // + // Normalize Prefix if Not Provided ... + if (!IsValid(mPrefix)) + { + mPrefix = GetTag(); + } + } + + // + // Deconstructor ... + ~XCAlert() + { + } + + // + // Override ... + string GetTag() override + { + return GetSpecificToken(this); + } + + // + // Properties Getter(s) / Setter(s) ... + + // + string GetPrefix() + { + return mPrefix; + } + + // + void SetPrefix(string value) + { + mPrefix = value; + } + + // + bool GetLogAlerts() + { + return mLogAlerts; + } + + // + void SetLogAlerts(bool value) + { + mLogAlerts = value; + } + + // + bool GetEnableAlerts() + { + return mEnableAlerts; + } + + // + void SetEnableAlerts(bool value) + { + mEnableAlerts = value; + } + + // + bool GetPushAlerts() + { + return mPushAlerts; + } + + // + void SetPushAlerts(bool value) + { + mPushAlerts = value; + } + + // + bool GetMailAlerts() + { + return mMailAlerts; + } + + // + void SetMailAlerts(bool value) + { + mMailAlerts = value; + } + + // + bool GetTerminalAlerts() + { + return mTerminalAlerts; + } + + // + void SetTerminalAlerts(bool value) + { + mTerminalAlerts = value; + } + + // + // Tools Funtions ... + + // + // Alerts ... + + // + // Logging an Alert ... + void LogAlert(string message) + { + // + // Validate Args ... + if (!CanLogAlert()) + { + return; + } + + // + Log(message); + } + + // + // Terminal Alert ... + void TerminalAlert(string message) + { + // + // Validate Args ... + if (!CanTerminalAlert()) + { + return; + } + + // + // Prepare Message ... + message = PrepareMessage(message); + + // Send Terminal Alert ... + Alert(message); + } + + // + // Mail Alert ... + void MailAlert(string message) + { + // + // Validate Args ... + if (!CanMailAlert()) + { + return; + } + + // + // Send Mail Alert ... + SendMail(GetPrefix(), message); + } + + // + // Send Push Notification ... + void PushAlert(string message) + { + // + // Validate Args ... + if (!CanPushAlert()) + { + return; + } + + // + // Prepare Message ... + message = PrepareMessage(message); + + // + // Send Push Notification Alert ... + SendNotification(message); + } + + // + // Send an Alert by Handling all Different Specified + // type's of Alert's if they are Enabled ... + void Alert(string message) + { + // + // Handle Log, if Enabled ... + LogAlert(message); + + // + // Handle Mail if Enabled ... + MailAlert(message); + + // + // Handle Push if Enabled ... + PushAlert(message); + + // + // Handle Terminal if Enabled ... + TerminalAlert(message); + } + + // + // Logs ... + + // + // Log a Message ... + void Log(string message) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), " > ", message); + } + void Log(string tag, string message) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), "_", tag, " > ", message); + } + void LogEmpty() + { + // + if (!CanLog()) + { + return; + } + + // + Print(" "); + } + + // + // Log Specific Array ... + template + void LogArray( + T &array[], // Array to Log + string label = NULL // Array Label + ) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), ">", (IsValid(label) ? label : "")); + ArrayPrint(array); + } + + // + // Error ... + + // + // Log an Error ... + void LogError( + int error = -1 // Specific Error, if it's equal to -1, use Last Error ... + ) + { + // + if (!CanLog()) + { + return; + } + + // + if (error <= -1) + { + error = GetLastError(); + } + + // + string errorMsg = GetErrorDescription(error); + + // + Log("Error: " + errorMsg); + } + + // + // Retrieve Specified Error Code Description ... + string GetErrorDescription(int err_code) + { + // + string result = ""; + + // + switch (err_code) + { + // + //--- Constant Description + + // + case ERR_SUCCESS: + result = "The operation completed successfully"; + break; + + // + case ERR_INTERNAL_ERROR: + result = "Unexpected internal error"; + break; + + // + case ERR_WRONG_INTERNAL_PARAMETER: + result = "Wrong parameter in the inner call of the client terminal function"; + break; + + // + case ERR_INVALID_PARAMETER: + result = "Wrong parameter when calling the system function"; + break; + + // + case ERR_NOT_ENOUGH_MEMORY: + result = "Not enough memory to perform the system function"; + break; + + // + case ERR_STRUCT_WITHOBJECTS_ORCLASS: + result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; + break; + + // + case ERR_INVALID_ARRAY: + result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; + break; + + // + case ERR_ARRAY_RESIZE_ERROR: + result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; + break; + + // + case ERR_STRING_RESIZE_ERROR: + result = "Not enough memory for the relocation of string"; + break; + + // + case ERR_NOTINITIALIZED_STRING: + result = "Not initialized string"; + break; + + // + case ERR_INVALID_DATETIME: + result = "Invalid date and/or time"; + break; + + // + case ERR_ARRAY_BAD_SIZE: + result = "Requested array size exceeds 2 GB"; + break; + + // + case ERR_INVALID_POINTER: + result = "Wrong pointer"; + break; + + // + case ERR_INVALID_POINTER_TYPE: + result = "Wrong type of pointer"; + break; + + // + case ERR_FUNCTION_NOT_ALLOWED: + result = "System function is not allowed to call"; + break; + + // + //--- Charts + + // + case ERR_CHART_WRONG_ID: + result = "Wrong chart ID"; + break; + + // + case ERR_CHART_NO_REPLY: + result = "Chart does not respond"; + break; + + // + case ERR_CHART_NOT_FOUND: + result = "Chart not found"; + break; + + // + case ERR_CHART_NO_EXPERT: + result = "No Expert Advisor in the chart that could handle the event"; + break; + + // + case ERR_CHART_CANNOT_OPEN: + result = "Chart opening error"; + break; + + // + case ERR_CHART_CANNOT_CHANGE: + result = "Failed to change chart symbol and period"; + break; + + // + case ERR_CHART_CANNOT_CREATE_TIMER: + result = "Failed to create timer"; + break; + + // + case ERR_CHART_WRONG_PROPERTY: + result = "Wrong chart property ID"; + break; + + // + case ERR_CHART_SCREENSHOT_FAILED: + result = "Error creating screenshots"; + break; + + // + case ERR_CHART_NAVIGATE_FAILED: + result = "Error navigating through chart"; + break; + + // + case ERR_CHART_TEMPLATE_FAILED: + result = "Error applying template"; + break; + + // + case ERR_CHART_WINDOW_NOT_FOUND: + result = "Subwindow containing the indicator was not found"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_ADD: + result = "Error adding an indicator to chart"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_DEL: + result = "Error deleting an indicator from the chart"; + break; + + // + case ERR_CHART_INDICATOR_NOT_FOUND: + result = "Indicator not found on the specified chart"; + break; + + // + //--- Graphical Objects + case ERR_OBJECT_ERROR: + result = "Error working with a graphical object"; + break; + + // + case ERR_OBJECT_NOT_FOUND: + result = "Graphical object was not found"; + break; + + // + case ERR_OBJECT_WRONG_PROPERTY: + result = "Wrong ID of a graphical object property"; + break; + + // + case ERR_OBJECT_GETDATE_FAILED: + result = "Unable to get date corresponding to the value"; + break; + + // + case ERR_OBJECT_GETVALUE_FAILED: + result = "Unable to get value corresponding to the date"; + break; + + // + //--- MarketInfo + + // + case ERR_MARKET_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_MARKET_NOT_SELECTED: + result = "Symbol is not selected in MarketWatch"; + break; + + // + case ERR_MARKET_WRONG_PROPERTY: + result = "Wrong identifier of a symbol property"; + break; + + // + case ERR_MARKET_LASTTIME_UNKNOWN: + result = "Time of the last tick is not known (no ticks)"; + break; + + // + case ERR_MARKET_SELECT_ERROR: + result = "Error adding or deleting a symbol in MarketWatch"; + break; + + // + //--- History Access + + // + case ERR_HISTORY_NOT_FOUND: + result = "Requested history not found"; + break; + + // + case ERR_HISTORY_WRONG_PROPERTY: + result = "Wrong ID of the history property"; + break; + + // + //--- Global_Variables + + // + case ERR_GLOBALVARIABLE_NOT_FOUND: + result = "Global variable of the client terminal is not found"; + break; + + // + case ERR_GLOBALVARIABLE_EXISTS: + result = "Global variable of the client terminal with the same name already exists"; + break; + + // + case ERR_MAIL_SEND_FAILED: + result = "Email sending failed"; + break; + + // + case ERR_PLAY_SOUND_FAILED: + result = "Sound playing failed"; + break; + + // + case ERR_MQL5_WRONG_PROPERTY: + result = "Wrong identifier of the program property"; + break; + + // + case ERR_TERMINAL_WRONG_PROPERTY: + result = "Wrong identifier of the terminal property"; + break; + + // + case ERR_FTP_SEND_FAILED: + result = "File sending via ftp failed"; + break; + + // + case ERR_NOTIFICATION_SEND_FAILED: + result = "Error in sending notification"; + break; + + // + //--- Custom Indicator Buffers + + // + case ERR_BUFFERS_NO_MEMORY: + result = "Not enough memory for the distribution of indicator buffers"; + break; + + // + case ERR_BUFFERS_WRONG_INDEX: + result = "Wrong indicator buffer index"; + break; + + // + //--- Custom Indicator Properties + + // + case ERR_CUSTOM_WRONG_PROPERTY: + result = "Wrong ID of the custom indicator property"; + break; + + // + //--- Account + + // + case ERR_ACCOUNT_WRONG_PROPERTY: + result = "Wrong account property ID"; + break; + + // + case ERR_TRADE_WRONG_PROPERTY: + result = "Wrong trade property ID"; + break; + + // + case ERR_TRADE_DISABLED: + result = "Trading by Expert Advisors prohibited"; + break; + + // + case ERR_TRADE_POSITION_NOT_FOUND: + result = "Position not found"; + break; + + // + case ERR_TRADE_ORDER_NOT_FOUND: + result = "Order not found"; + break; + + // + case ERR_TRADE_DEAL_NOT_FOUND: + result = "Deal not found"; + break; + + // + case ERR_TRADE_SEND_FAILED: + result = "Trade request sending failed"; + break; + + // + //--- Indicators + + // + case ERR_INDICATOR_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_INDICATOR_CANNOT_CREATE: + result = "Indicator cannot be created"; + break; + + // + case ERR_INDICATOR_NO_MEMORY: + result = "Not enough memory to add the indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_APPLY: + result = "The indicator cannot be applied to another indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_ADD: + result = "Error applying an indicator to chart"; + break; + + // + case ERR_INDICATOR_DATA_NOT_FOUND: + result = "Requested data not found"; + break; + + // + case ERR_INDICATOR_WRONG_HANDLE: + result = "Wrong indicator handle"; + break; + + // + case ERR_INDICATOR_WRONG_PARAMETERS: + result = "Wrong number of parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_PARAMETERS_MISSING: + result = "No parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_CUSTOM_NAME: + result = "The first parameter in the array must be the name of the custom indicator"; + break; + + // + case ERR_INDICATOR_PARAMETER_TYPE: + result = "Invalid parameter type in the array when creating an indicator"; + break; + + // + case ERR_INDICATOR_WRONG_INDEX: + result = "Wrong index of the requested indicator buffer"; + break; + + // + //--- Depth of Market + + // + case ERR_BOOKS_CANNOT_ADD: + result = "Depth Of Market can not be added"; + break; + + // + case ERR_BOOKS_CANNOT_DELETE: + result = "Depth Of Market can not be removed"; + break; + + // + case ERR_BOOKS_CANNOT_GET: + result = "The data from Depth Of Market can not be obtained"; + break; + + // + case ERR_BOOKS_CANNOT_SUBSCRIBE: + result = "Error in subscribing to receive new data from Depth Of Market"; + break; + + // + //--- File Operations + + // + case ERR_TOO_MANY_FILES: + result = "More than 64 files cannot be opened at the same time"; + break; + + // + case ERR_WRONG_FILENAME: + result = "Invalid file name"; + break; + + // + case ERR_TOO_LONG_FILENAME: + result = "Too long file name"; + break; + + // + case ERR_CANNOT_OPEN_FILE: + result = "File opening error"; + break; + + // + case ERR_FILE_CACHEBUFFER_ERROR: + result = "Not enough memory for cache to read"; + break; + + // + case ERR_CANNOT_DELETE_FILE: + result = "File deleting error"; + break; + + // + case ERR_INVALID_FILEHANDLE: + result = "A file with this handle was closed, or was not opening at all"; + break; + + // + case ERR_WRONG_FILEHANDLE: + result = "Wrong file handle"; + break; + + // + case ERR_FILE_NOTTOWRITE: + result = "The file must be opened for writing"; + break; + + // + case ERR_FILE_NOTTOREAD: + result = "The file must be opened for reading"; + break; + + // + case ERR_FILE_NOTBIN: + result = "The file must be opened as a binary one"; + break; + + // + case ERR_FILE_NOTTXT: + result = "The file must be opened as a text"; + break; + + // + case ERR_FILE_NOTTXTORCSV: + result = "The file must be opened as a text or CSV"; + break; + + // + case ERR_FILE_NOTCSV: + result = "The file must be opened as CSV"; + break; + + // + case ERR_FILE_READERROR: + result = "File reading error"; + break; + + // + case ERR_FILE_BINSTRINGSIZE: + result = "String size must be specified, because the file is opened as binary"; + break; + + // + case ERR_INCOMPATIBLE_FILE: + result = "A text file must be for string arrays, for other arrays - binary"; + break; + + // + case ERR_FILE_IS_DIRECTORY: + result = "This is not a file, this is a directory"; + break; + + // + case ERR_FILE_NOT_EXIST: + result = "File does not exist"; + break; + + // + case ERR_FILE_CANNOT_REWRITE: + result = "File can not be rewritten"; + break; + + // + case ERR_WRONG_DIRECTORYNAME: + result = "Wrong directory name"; + break; + + // + case ERR_DIRECTORY_NOT_EXIST: + result = "Directory does not exist"; + break; + + // + case ERR_FILE_ISNOT_DIRECTORY: + result = "This is a file, not a directory"; + break; + + // + case ERR_CANNOT_DELETE_DIRECTORY: + result = "The directory cannot be removed"; + break; + + // + case ERR_CANNOT_CLEAN_DIRECTORY: + result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; + break; + + // + case ERR_FILE_WRITEERROR: + result = "Failed to write a resource to a file"; + break; + + // + //--- String Casting + + // + case ERR_NO_STRING_DATE: + result = "No date in the string"; + break; + + // + case ERR_WRONG_STRING_DATE: + result = "Wrong date in the string"; + break; + + // + case ERR_WRONG_STRING_TIME: + result = "Wrong time in the string"; + break; + + // + case ERR_STRING_TIME_ERROR: + result = "Error converting string to date"; + break; + + // + case ERR_STRING_OUT_OF_MEMORY: + result = "Not enough memory for the string"; + break; + + // + case ERR_STRING_SMALL_LEN: + result = "The string length is less than expected"; + break; + + // + case ERR_STRING_TOO_BIGNUMBER: + result = "Too large number, more than ULONG_MAX"; + break; + + // + case ERR_WRONG_FORMATSTRING: + result = "Invalid format string"; + break; + + // + case ERR_TOO_MANY_FORMATTERS: + result = "Amount of format specifiers more than the parameters"; + break; + + // + case ERR_TOO_MANY_PARAMETERS: + result = "Amount of parameters more than the format specifiers"; + break; + + // + case ERR_WRONG_STRING_PARAMETER: + result = "Damaged parameter of string type"; + break; + + // + case ERR_STRINGPOS_OUTOFRANGE: + result = "Position outside the string"; + break; + + // + case ERR_STRING_ZEROADDED: + result = "0 added to the string end, a useless operation"; + break; + + // + case ERR_STRING_UNKNOWNTYPE: + result = "Unknown data type when converting to a string"; + break; + + // + case ERR_WRONG_STRING_OBJECT: + result = "Damaged string object"; + break; + + // + //--- Operations with Arrays + + // + case ERR_INCOMPATIBLE_ARRAYS: + result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; + break; + + // + case ERR_SMALL_ASSERIES_ARRAY: + result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; + break; + + // + case ERR_SMALL_ARRAY: + result = "Too small array, the starting position is outside the array"; + break; + + // + case ERR_ZEROSIZE_ARRAY: + result = "An array of zero length"; + break; + + // + case ERR_NUMBER_ARRAYS_ONLY: + result = "Must be a numeric array"; + break; + + // + case ERR_ONEDIM_ARRAYS_ONLY: + result = "Must be a one-dimensional array"; + break; + + // + case ERR_SERIES_ARRAY: + result = "Timeseries cannot be used"; + break; + + // + case ERR_DOUBLE_ARRAY_ONLY: + result = "Must be an array of type double"; + break; + + // + case ERR_FLOAT_ARRAY_ONLY: + result = "Must be an array of type float"; + break; + + // + case ERR_LONG_ARRAY_ONLY: + result = "Must be an array of type long"; + break; + + // + case ERR_INT_ARRAY_ONLY: + result = "Must be an array of type int"; + break; + + // + case ERR_SHORT_ARRAY_ONLY: + result = "Must be an array of type short"; + break; + + // + case ERR_CHAR_ARRAY_ONLY: + result = "Must be an array of type char"; + break; + + // + //--- Operations with OpenCL + + // + case ERR_OPENCL_NOT_SUPPORTED: + result = "OpenCL functions are not supported on this computer"; + break; + + // + case ERR_OPENCL_INTERNAL: + result = "Internal error occurred when running OpenCL"; + break; + + // + case ERR_OPENCL_INVALID_HANDLE: + result = "Invalid OpenCL handle"; + break; + + // + case ERR_OPENCL_CONTEXT_CREATE: + result = "Error creating the OpenCL context"; + break; + + // + case ERR_OPENCL_QUEUE_CREATE: + result = "Failed to create a run queue in OpenCL"; + break; + + // + case ERR_OPENCL_PROGRAM_CREATE: + result = "Error occurred when compiling an OpenCL program"; + break; + + // + case ERR_OPENCL_TOO_LONG_KERNEL_NAME: + result = "Too long kernel name (OpenCL kernel)"; + break; + + // + case ERR_OPENCL_KERNEL_CREATE: + result = "Error creating an OpenCL kernel"; + break; + + // + case ERR_OPENCL_SET_KERNEL_PARAMETER: + result = "Error occurred when setting parameters for the OpenCL kernel"; + break; + + // + case ERR_OPENCL_EXECUTE: + result = "OpenCL program runtime error"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_SIZE: + result = "Invalid size of the OpenCL buffer"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_OFFSET: + result = "Invalid offset in the OpenCL buffer"; + break; + + // + case ERR_OPENCL_BUFFER_CREATE: + result = "Failed to create and OpenCL buffer"; + break; + + // + //--- User-Defined Errors + default: + result = "UNKNOWN Erro ..."; + break; + } + + // + return result; + } + + // + // Retrieve Specified Error Code Description ... + string GetTradeServerReturnCodeDescription(int return_code) + { + // + string result = ""; + + // + switch (return_code) + { + // + case TRADE_RETCODE_REQUOTE: + result = "Requote"; + break; + + // + case TRADE_RETCODE_REJECT: + result = "Request rejected"; + break; + + // + case TRADE_RETCODE_CANCEL: + result = "Request canceled by trader"; + break; + + // + case TRADE_RETCODE_PLACED: + result = "Order placed"; + break; + + // + case TRADE_RETCODE_DONE: + result = "Request completed"; + break; + + // + case TRADE_RETCODE_DONE_PARTIAL: + result = "Only part of the request was completed"; + break; + + // + case TRADE_RETCODE_ERROR: + result = "Request processing error"; + break; + + // + case TRADE_RETCODE_TIMEOUT: + result = "Request canceled by timeout"; + break; + + // + case TRADE_RETCODE_INVALID: + result = "Invalid request"; + break; + + // + case TRADE_RETCODE_INVALID_VOLUME: + result = "Invalid volume in the request"; + break; + + // + case TRADE_RETCODE_INVALID_PRICE: + result = "Invalid price in the request"; + break; + + // + case TRADE_RETCODE_INVALID_STOPS: + result = "Invalid stops in the request"; + break; + + // + case TRADE_RETCODE_TRADE_DISABLED: + result = "Trade is disabled"; + break; + + // + case TRADE_RETCODE_MARKET_CLOSED: + result = "Market is closed"; + break; + + // + case TRADE_RETCODE_NO_MONEY: + result = "There is not enough money to complete the request"; + break; + + // + case TRADE_RETCODE_PRICE_CHANGED: + result = "Prices changed"; + break; + + // + case TRADE_RETCODE_PRICE_OFF: + result = "There are no quotes to process the request"; + break; + + // + case TRADE_RETCODE_INVALID_EXPIRATION: + result = "Invalid order expiration date in the request"; + break; + + // + case TRADE_RETCODE_ORDER_CHANGED: + result = "Order state changed"; + break; + + // + case TRADE_RETCODE_TOO_MANY_REQUESTS: + result = "Too frequent requests"; + break; + + // + case TRADE_RETCODE_NO_CHANGES: + result = "No changes in request"; + break; + + // + case TRADE_RETCODE_SERVER_DISABLES_AT: + result = "Autotrading disabled by server"; + break; + + // + case TRADE_RETCODE_CLIENT_DISABLES_AT: + result = "Autotrading disabled by client terminal"; + break; + + // + case TRADE_RETCODE_LOCKED: + result = "Request locked for processing"; + break; + + // + case TRADE_RETCODE_FROZEN: + result = "Order or position frozen"; + break; + + // + case TRADE_RETCODE_INVALID_FILL: + result = "Invalid order filling type"; + break; + + // + case TRADE_RETCODE_CONNECTION: + result = "No connection with the trade server"; + break; + + // + case TRADE_RETCODE_ONLY_REAL: + result = "Operation is allowed only for live accounts"; + break; + + // + case TRADE_RETCODE_LIMIT_ORDERS: + result = "The number of pending orders has reached the limit"; + break; + + // + case TRADE_RETCODE_LIMIT_VOLUME: + result = "The volume of orders and positions for the symbol has reached the limit"; + break; + + // + default: + result = "Invalid return code of the trade server"; + break; + } + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + + // + bool CanLog() + { + return mLogAlerts; + } + + // + bool CanLogAlert() + { + // + bool result = GetEnableAlerts() && GetLogAlerts(); + + // + return result; + } + + // + bool CanTerminalAlert() + { + // + bool result = GetEnableAlerts() && GetTerminalAlerts(); + + // + return result; + } + + // + bool CanMailAlert() + { + // + bool result = GetEnableAlerts() && GetMailAlerts(); + + // + return result; + } + + // + bool CanPushAlert() + { + // + bool result = GetEnableAlerts() && GetPushAlerts(); + + // + return result; + } + + private: + // + // Props ... + string mPrefix; // Alerts Prefixe + bool mEnableAlerts; // Enable Alerts + bool mLogAlerts; // Log Alerts + bool mTerminalAlerts; // Terminal Alerts + bool mMailAlerts; // Mail Alerts + bool mPushAlerts; // Push Alerts + + // + // Tools ... + + // + // Clear Escape String and + // Attach Alert Prefix to Message ... + string PrepareMessage(string message) + { + // + StringReplace(message, "\n", " | "); + + // + StringConcatenate(message, GetPrefix(), " > ", message); + + // + return message; + } +}; + +// +// a Base Class by Support Alert ... +class XCBaseAlert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor(s) ... + void XCBaseAlert() + { + // + // Instance Alert ... + mAlert = new XCAlert(); + } + + // + // Deconstructors ... + void ~XCBaseAlert() + { + // + delete mAlert; + } + + // + // Alert Handler Functions ... + + // + // Alert Functions Getter(s) / Setters(s) ... + + // + string GetAlertPrefix() + { + return mAlert.GetPrefix(); + } + + // + void SetAlertPrefix(string value) + { + mAlert.SetPrefix(value); + } + + // + bool GetAlertLogAlerts() + { + return mAlert.GetLogAlerts(); + } + + // + void SetAlertLogAlerts(bool value) + { + mAlert.SetLogAlerts(value); + } + + // + bool GetAlertEnableAlerts() + { + return mAlert.GetEnableAlerts(); + } + + // + void SetAlertEnableAlerts(bool value) + { + mAlert.SetEnableAlerts(value); + } + + // + bool GetAlertPushAlerts() + { + return mAlert.GetPushAlerts(); + } + + // + void SetAlertPushAlerts(bool value) + { + mAlert.SetPushAlerts(value); + } + + // + bool GetAlertMailAlerts() + { + return mAlert.GetMailAlerts(); + } + + // + void SetAlertMailAlerts(bool value) + { + mAlert.SetMailAlerts(value); + } + + // + bool GetAlertTerminalAlerts() + { + return mAlert.GetTerminalAlerts(); + } + + // + void SetAlertTerminalAlerts(bool value) + { + mAlert.SetTerminalAlerts(value); + } + + // + // Alert Actions ... + + // + // Logging an Alert ... + void LogAlert(string message) + { + mAlert.LogAlert(message); + } + + // + // Terminal Alert ... + void TerminalAlert(string message) + { + mAlert.TerminalAlert(message); + } + + // + // Mail Alert ... + void MailAlert(string message) + { + mAlert.MailAlert(message); + } + + // + // Send Push Notification ... + void PushAlert(string message) + { + mAlert.PushAlert(message); + } + + // + // Send an Alert by Handling all Different Specified + // type's of Alert's if they are Enabled ... + void Alert(string message) + { + mAlert.Alert(message); + } + + // + // Logs ... + + // + // Log a Message ... + void Log(string message) + { + mAlert.Log(message); + } + void Log(string tag, string message) + { + mAlert.Log(tag, message); + } + void LogEmpty() + { + mAlert.LogEmpty(); + } + + // + // Log Specific Array ... + template + void LogArray( + T &array[], // Array to Log + string label = NULL // Array Label + ) + { + mAlert.LogArray(array, label); + } + + // + // Error ... + + // + // Log an Error ... + void LogError( + int error = -1 // Specific Error, if it's equal to -1, use Last Error ... + ) + { + mAlert.LogError(error); + } + + // + // Retrieve Specified Error Code Description ... + string GetErrorDescription(int err_code) + { + return mAlert.GetErrorDescription(err_code); + } + + // + // Retrieve Specified Error Code Description ... + string GetTradeServerReturnCodeDescription(int return_code) + { + return mAlert.GetTradeServerReturnCodeDescription(return_code); + } + + // + // Protected ... + protected: + // + // Alert ... + XCAlert *mAlert; + + // + // Private ... + private: +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-app-dialog.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-app-dialog.class.mq5 new file mode 100644 index 0000000..6bfa4d9 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-app-dialog.class.mq5 @@ -0,0 +1,275 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCPanel +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include + +// +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Extentions ... + +/** + * Check a Qery Contains in a Content or not ... + * + * @param mQuery: String ... + * @param mContent: String ... + * @param ignoreCase: Boolean ... + * + * @return ( bool ) + */ +bool XContains( + string mQuery, // Search String + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + return Contains( + mQuery, + mContent, + ignoreCase // + ); +} + +// +// Implementation ... + +// +// a Base App Dialog Class ... +class XCAppDialog : public CAppDialog +{ + public: + // + // Action ... + + // + // Virual ... + + /** + * Override Close Button Click Action ... + */ + void OnClickButtonClose() + { + // + bool isClosed = ConfirmDialog("Close EA ?"); + + // + if (isClosed) + { + Destroy(); + } + } + + // + // Configuration Actions ... + + /** + * Show or Hide Minimize Button ... + * + * @param show: boolean + */ + void MinimizeButton(bool show) + { + // + int controlIDX = ControlFind("MinMax"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + if (show) + { + Control(controlIDX).Show(); + } + else + { + Control(controlIDX).Hide(); + } + } + + /** + * Show or Hide Close Button ... + * + * @param show: boolean + */ + void CloseButton(bool show) + { + // + int controlIDX = ControlFind("Close"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + if (show) + { + Control(controlIDX).Show(); + } + else + { + Control(controlIDX).Hide(); + } + } + + /** + * Minimize Functionality Implementation ... + */ + void Minimize() + { + // + m_minimized = true; + Rebound(m_min_rect); + ClientAreaVisible(false); + } + + /** + * Set Background Color ... + * + * @param clr: Color ... + */ + void BackgroundColor(color clr) + { + // + int controlIDX = ControlFind("Client"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + CWnd *obj = Control(controlIDX); + CWndClient *wndclient = (CWndClient *)obj; + + // + wndclient.ColorBackground(clr); + } + + // + protected: + // + + /** + * Find Specific Control in Dialog ... + * + * @param name: String to Search + * + * @return ( int ) + */ + int ControlFind(string name) + { + // + int result = -1; + + // + if (!IsValid(name)) + { + return result; + } + + // + int count = ControlsTotal(); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + string iName = Control(i).Name(); + + // + bool isContains = XContains( + name, + iName, + true // Ignore Case ... + ); + if (isContains) + { + // + result = i; + break; + } + } + + // + return result; + } + + /** + * Create and Run Confirm Dialog ... + * + * @param message: message for Message Box ... + * + * @return ( bool ) + */ + bool ConfirmDialog(string message = NULL) + { + // + bool result = false; + + // + if (!IsValid(message)) + { + message = "Confirm ?"; + } + + // + int dialogResult = MessageBox(message, NULL, MB_YESNO); + + // + // use 'switch' or 'if' as needed + switch (dialogResult) + { + // + // Yes ... + case IDYES: + result = true; + break; + // + // No ... + case IDNO: + result = false; + break; + // + // Cancel ... + case IDCANCEL: + result = false; + break; + } + + // + return result; + } + + // + private: + // + + // +}; \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-bar.analyser.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-bar.analyser.class.mq5 new file mode 100644 index 0000000..577fea6 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-bar.analyser.class.mq5 @@ -0,0 +1,5633 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOI +// Description: Bar Analysing ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +// Definitions ... + +// +// Implementations ... +class XCBarAnalyser : public XCBase +{ + // + public: + // + + // + // Constructor(s) ... + void XCBarAnalyser() + { + } + + // + // Deconstructor ... + void ~XCBarAnalyser() + { + } + + // + // Getter(s) / Setter(s) ... + + // + // Providers ... + + // + // Actions ... + + /** + * Calculate Loopback Data for Specific Bar ... + * + * @param index: Integer, Bar Current Index ... + * @param start: Integer, Start of Loopback ... + * @param end: Integer, End of Loopback ... + * @param count: Integer, Number of Calculating Bars ... + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * @return ( bool ) + */ + bool CalculateLoopBackData( + int &index, + int &start, + int &end, + int &count, + XOHCL &bar, + int loopback = 1 // + ) + { + // + bool result = false; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + index = -1; + start = -1; + end = -1; + count = -1; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + index = bar.Index(); + start = index + 1; + end = start + loopback; + count = end - start; + result = count >= 1; + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Retrieve Loopback HH & LL Data ... + * + * @param hhIDX: Integer, HH Index ... + * @param hh: Double, HH Value ... + * @param llIDX: Integer, LL Index ... + * @param ll: Double, LL Value ... + * @param bar: XOHCL instance ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool CalculateLoopbackHLData( + int &hhIDX, + double &hh, + int &llIDX, + double &ll, + XOHCL &bar, + int loopback // + ) + { + // + bool result = false; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + int index = -1; + int start = -1; + int end = -1; + int count = -1; + result = CalculateLoopBackData( + index, + start, + end, + count, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + hhIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + count, + start // + ); + result = IsValidIndex(hhIDX); + if (!result) + { + return result; + } + + // + llIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + count, + start // + ); + result = IsValidIndex(llIDX); + if (!result) + { + return result; + } + + // + hh = iHigh( + bar.symbol, + bar.period, + hhIDX // + ); + ll = iLow( + bar.symbol, + bar.period, + llIDX // + ); + + // + return result; + } + + /** + * Calculate Bar Range ... + * + * @param bar: XOHCL instance ... + * + * @return ( double ) + */ + double GetBarRangePercent(XOHCL &bar) + { + // + double result = 0; + + // + result = bar.GetRange() / 100; + + // + return result; + } + + /** + * Detect Same Bars ... + * + * @param bar: XOHCL instance, Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Holds Result Direction ... + * @param index: Integer, Holds Result Index ... + * @param sameBars: Iteger, Required Same Bar ... + * + * @return ( bool ) + */ + bool HasSameBars( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int &index, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + index = bar.Index(); + bool canContinue = true; + int sameBullishBarsFounded = 0; + int sameBearishBarsFounded = 0; + bool canContinueForBullish = true; + bool canContinueForBearish = true; + while (canContinue) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + index // + ); + if (!result) + { + break; + } + + // + bool isBullish = iBar.IsBullish(); + bool isBearish = iBar.IsBearish(); + result = isBullish || + isBearish; + if (!result) + { + break; + } + + // + if (isBullish) + { + // + sameBullishBarsFounded++; + canContinueForBearish = false; + } + else + { + // + sameBearishBarsFounded++; + canContinueForBullish = false; + } + + // + result = canContinueForBullish || + canContinueForBearish; + if (!result) + { + break; + } + + // + canContinueForBullish = + canContinueForBullish && + sameBullishBarsFounded > 0; + + // + canContinueForBearish = + canContinueForBearish && + sameBearishBarsFounded > 0; + + // + canContinue = + canContinueForBullish || + canContinueForBearish; + if (canContinue) + { + index++; + } + } + + // + bool hasBullishSameBars = + sameBullishBarsFounded >= sameBars; + + // + bool hasBearishSameBars = + sameBearishBarsFounded >= sameBars; + + // + result = hasBullishSameBars || + hasBearishSameBars; + if (!result) + { + return result; + } + + // + dir = + hasBullishSameBars + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Detect Price Consolidation ... + * + * @param bar: XOHCL instance Reference, Start Bar ... + * @param loopback: Integer, Consolidation Range Finder ... + * @param upper: Double Reference ... + * @param lower: Double Reference ... + * @param upperAppliedTo: ENUM_APPLIED_PRICE member, Upper Price ... + * @param lowerAppliedTo: ENUM_APPLIED_PRICE member, Lower Price ... + * + * @return ( bool ) + */ + bool IsConsolidate( + XOHCL &bar, + double &upper, + double &lower, + int loopback = 30, + ENUM_APPLIED_PRICE upperAppliedTo = PRICE_HIGH, + ENUM_APPLIED_PRICE lowerAppliedTo = PRICE_LOW // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + if (loopback < 7) + { + loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int consolidationRange = 30; + double points = GetPoints(bar.symbol); + int index = bar.Index(); + + // + double upperPrice[]; + int upperPriceCount = FillPrice( + upperPrice, + upperAppliedTo, + bar.symbol, + bar.period, + index, + loopback // + ); + + // + double lowerPrice[]; + int lowerPriceCount = FillPrice( + lowerPrice, + lowerAppliedTo, + bar.symbol, + bar.period, + index, + loopback // + ); + + // + result = upperPriceCount == lowerPriceCount && + lowerPriceCount == loopback; + if (!result) + { + return result; + } + + // + upper = upperPrice[ArrayMaximum(upperPrice)]; + lower = lowerPrice[ArrayMinimum(lowerPrice)]; + + // + double range = upper - lower; + result = range <= consolidationRange * points; + + // + return result; + } + + /** + * Check Bar Has Bullish Trend or not ... + * + * @param bar: XOHCL instance ... + * @param forceAll: Boolean ... + * + * @return ( bool ) + */ + bool HasBullishTrend( + XOHCL &bar, + bool forceAll = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL tmpHSW[]; + XOHCL tmpLSW[]; + + // + bool trend1 = HasBullishTrend( + bar, + tmpHSW, + tmpLSW, + true // + ); + + // + bool trend2 = HasBullishTrend( + bar, + tmpHSW, + tmpLSW, + false // + ); + + // + if (!forceAll) + { + // + result = trend1; + if (!result) + { + return result; + } + } + + // + result = + trend1 || + trend2; + + // + return result; + } + + /** + * Check Bar Has Bearish Trend or not ... + * + * @param bar: XOHCL instance ... + * @param forceAll: Boolean ... + * + * @return ( bool ) + */ + bool HasBearishTrend( + XOHCL &bar, + bool forceAll = false // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL tmpHSW[]; + XOHCL tmpLSW[]; + + // + bool trend1 = HasBearishTrend( + bar, + tmpHSW, + tmpLSW, + true // + ); + + // + bool trend2 = HasBearishTrend( + bar, + tmpHSW, + tmpLSW, + false // + ); + + // + if (!forceAll) + { + // + result = trend1; + if (!result) + { + return result; + } + } + + // + result = + trend1 || + trend2; + + // + return result; + } + + /** + * Check Specified Bar Has Bullish Pattern or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length for Patterns ... + * @param verifications: Integer, Number of Given Verifications ... + * @param checkHammer: Boolean, Specified Check Hammer Pattern ... + * @param checkMorningStar: Boolean, Specified Check Morning Star Pattern ... + * @param checkBullishMarubozu: Boolean, Specified Check Marubozu Pattern ... + * @param checkBullishEngulfing: Boolean, Specified Check Engulfing Pattern ... + * + * @return ( bool ) + */ + bool HasBullishPattern( + XOHCL &bar, + int loopback = 0, + int verifications = 1, + bool checkHammer = true, + bool checkMorningStar = true, + bool checkBullishMarubozu = true, + bool checkBullishEngulfing = true // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (verifications <= 0) + { + verifications = 1; + } + + // + int founded = 0; + + // + int idx = bar.Index(); + for (int i = idx; i <= idx + loopback; i++) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + bool isHammer = + !checkHammer + ? false + : IsHammer(iBar); + if (isHammer) + { + founded++; + } + + // + bool isMorningStar = + !checkMorningStar + ? false + : IsMorningStar(iBar); + if (isMorningStar) + { + founded++; + } + + // + bool isBullishMarubozu = + !checkBullishMarubozu + ? false + : IsBullishMarubozu(iBar); + if (isBullishMarubozu) + { + founded++; + } + + // + bool isBullishEngulfing = + !checkBullishEngulfing + ? false + : IsBullishEngulfing(iBar); + if (isBullishEngulfing) + { + founded++; + } + + // + } + + // + result = + result && + founded >= verifications; + + // + return result; + } + + /** + * Check Specified Bar Has Bearish Pattern or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length for Patterns ... + * @param verifications: Integer, Number of Given Verifications ... + * @param checkShootingStar: Boolean, Specified Check Shooting Star Pattern ... + * @param checkEveningStar: Boolean, Specified Check Evening Star Pattern ... + * @param checkBearishMarubozu: Boolean, Specified Check Marubozu Pattern ... + * @param checkBearishEngulfing: Boolean, Specified Check Engulfing Pattern ... + * + * @return ( bool ) + */ + bool HasBearishPattern( + XOHCL &bar, + int loopback = 0, + int verifications = 1, + bool checkShootingStar = true, + bool checkEveningStar = true, + bool checkBearishMarubozu = true, + bool checkBearishEngulfing = true // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (verifications <= 0) + { + verifications = 1; + } + + // + int founded = 0; + + // + int idx = bar.Index(); + for (int i = idx - 1; i <= idx + loopback; i++) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + bool isShootingStar = + !checkShootingStar + ? false + : IsShootingStar(iBar); + if (isShootingStar) + { + founded++; + } + + // + bool isEveningStar = + !checkEveningStar + ? false + : IsEveningStar(iBar); + if (isEveningStar) + { + founded++; + } + + // + bool isBearishMarubozu = + !checkBearishMarubozu + ? false + : IsBearishMarubozu(iBar); + if (isBearishMarubozu) + { + founded++; + } + + // + bool isBearishEngulfing = + !checkBearishEngulfing + ? false + : IsBearishEngulfing(iBar); + if (isBearishEngulfing) + { + founded++; + } + + // + } + + // + result = + result && + founded >= verifications; + + // + return result; + } + + // + // Commons ... + + /** + * Check Specified Bar's Range is Extended or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool HasExtendedRange( + XOHCL &bar, + int loopback = 3 // + ) + { + // + bool result = false; + + // + if (loopback < 3) + { + loopback = 3; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + int start = index + 1; + int end = start + loopback; + int count = end - start; + result = count >= 1; + if (!result) + { + return result; + } + + // + double sum = 0; + XOHCL iBar = bar; + for (int i = start; i < end; i++) + { + // + bool isRetrieved = iBar.GetPreviousBar(iBar); + if (!isRetrieved) + { + continue; + } + + // + sum += iBar.GetRange(); + } + + // + result = sum > 0; + if (!result) + { + return result; + } + + // + double avg = sum / count; + + // + result = bar.GetRange() >= avg; + + // + return result; + } + + /** + * Check Specified Bar's Body is Extended or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool HasExtendedBody( + XOHCL &bar, + int loopback = 3 // + ) + { + // + bool result = false; + + // + if (loopback < 3) + { + loopback = 3; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + int start = index + 1; + int end = start + loopback; + int count = end - start; + result = count >= 1; + if (!result) + { + return result; + } + + // + double sum = 0; + XOHCL iBar = bar; + for (int i = start; i < end; i++) + { + // + bool isRetrieved = iBar.GetPreviousBar(iBar); + if (!isRetrieved) + { + continue; + } + + // + sum += iBar.GetBody(); + } + + // + result = sum > 0; + if (!result) + { + return result; + } + + // + double avg = sum / count; + + // + result = bar.GetBody() >= avg; + + // + return result; + } + + /** + * Check Specified Bar's Body and Range is Extended or not ... + * + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool IsExtended( + XOHCL &bar, + int loopback = 3 // + ) + { + // + bool result = false; + + // + bool hasExtendedBody = HasExtendedBody(bar, loopback); + bool hasExtendedRange = HasExtendedRange(bar, loopback); + result = hasExtendedBody && + hasExtendedRange; + + // + return result; + } + + /** + * Check Specified Bar is Swing High or not ... + * + * @param bar: XOHCL instnce ... + * @param range: Integer, Specified Range ... + * + * @return ( bool ) + */ + bool IsSwingHigh( + XOHCL &bar, + int range = 2 // + ) + { + // + bool result = false; + + // + if (range < 1) + { + range = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + index + i // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + index - i // + ); + if (!result) + { + break; + } + + // + result = bar.high >= iPrevBar.high && + bar.high >= iNextBar.high; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check Specified Bar is Swing Low or not ... + * + * @param bar: XOHCL instnce ... + * @param range: Integer, Specified Range ... + * + * @return ( bool ) + */ + bool IsSwingLow( + XOHCL &bar, + int range = 2 // + ) + { + // + bool result = false; + + // + if (range < 1) + { + range = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + index + i // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + index - i // + ); + if (!result) + { + break; + } + + // + result = bar.low <= iPrevBar.low && + bar.low <= iNextBar.low; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check a Bar is Momentum Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param bodyPercent: Double ... + * + * @return ( bool ) + */ + bool IsMomentumBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double bodyPercent = 70 // + ) + { + // + bool result = false; + + // + if (extend < 0) + { + extend = 0; + } + + // + if (bodyPercent < 50) + { + bodyPercent = 50; + } + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (extend > 0) + { + // + result = IsExtended( + bar, + extend // + ); + + // + if (!result) + { + return result; + } + } + + // + double body = bar.GetBody(); + double rp = GetBarRangePercent(bar); + + // + result = body >= rp * bodyPercent; + + // + if (result) + { + // + dir = + bar.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + /** + * Check a Bar is Rejection Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param shadowPercent: Double ... + * + * @return ( bool ) + */ + bool IsRejectionBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double shadowPercent = 60 // + ) + { + // + bool result = false; + + // + if (extend < 0) + { + extend = 0; + } + + // + if (shadowPercent < 50) + { + shadowPercent = 50; + } + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (extend > 0) + { + // + result = IsExtended( + bar, + extend // + ); + + // + if (!result) + { + return result; + } + } + + // + double body = bar.GetBody(); + double range = bar.GetRange(); + double shadows = bar.GetShadows(); + double lowShadow = bar.GetLowShadow(); + double highShadow = bar.GetHighShadow(); + double rp = GetBarRangePercent(bar); + + // + result = shadows >= rp * shadowPercent; + + // + if (result) + { + // + dir = + lowShadow > highShadow + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + /** + * Check Specified Bar is Engulfing Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param bodyPercent: Double ... + * + * @return ( bool ) + */ + bool IsEngulfBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double bodyPercent = 60 // + ) + { + // + bool result = false; + + // + if (extend < 0) + { + extend = 0; + } + + // + if (bodyPercent < 50) + { + bodyPercent = 50; + } + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + if (extend > 0) + { + // + result = IsExtended( + pBar, + extend // + ); + + // + if (!result) + { + return result; + } + } + + // + // Check Engulfig ... + result = + bar.GetUp() > pBar.GetUp() && + bar.GetDown() < pBar.GetDown(); + if (!result) + { + return result; + } + + // + // Check Engulfing Direction ... + bool isBullishEngulfed = + pBar.IsBearish() && + bar.IsBullish(); + bool isBearishEngulfed = + pBar.IsBullish() && + bar.IsBearish(); + + // + result = isBullishEngulfed || + isBearishEngulfed; + if (!result) + { + return result; + } + + // + dir = isBullishEngulfed + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Check Specified Bar is Pin Bar or not ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param shadowPercent: Double ... + * @param bodyPercent: Double ... + * + * @return ( bool ) + */ + bool IsPinBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double shadowPercent = 65, + double bodyPercent = 25 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0 && + bodyPercent > 0 && + shadowPercent > 0 && + bodyPercent < shadowPercent; + if (!result) + { + return result; + } + + // + // Chack Range Extends ... + if (extend > 0) + { + // + result = HasExtendedRange( + bar, + extend // + ); + if (!result) + { + return result; + } + } + + // + // Check Body ... + double rangePercent = GetBarRangePercent(bar); + + // + double body = bar.GetBody(); + double highShadow = bar.GetHighShadow(); + double lowShadow = bar.GetLowShadow(); + + // + // Check Body ... + result = body / rangePercent >= bodyPercent; + if (!result) + { + return result; + } + + // + bool isPassedHighShadow = + highShadow / rangePercent >= shadowPercent; + bool isPassedLowShadow = + lowShadow / rangePercent >= shadowPercent; + result = + isPassedLowShadow || + isPassedHighShadow; + if (!result) + { + return result; + } + + // + dir = isPassedLowShadow + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Decision Bar (Pin, Momentum or Rejection) ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * @param extend: Integer ... + * @param shadowForPinAndRejectionBarPercent: Double ... + * @param bodyForPinBarPercent: Double ... + * @param bodyForEngulfBarPercent: Double ... + * @param bodyForMomentumBarPercent: Double ... + * + * @return ( bool ) + */ + bool IsDecisionBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int extend = 1, + double shadowForPinAndRejectionBarPercent = 65, + double bodyForPinBarPercent = 25, + double bodyForEngulfBarPercent = 65, + double bodyForMomentumBarPercent = 70 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Pin Bar ... + ENUM_X_DIRECTION pinDir; + bool isPiBar = IsPinBar( + bar, + pinDir, + extend, + shadowForPinAndRejectionBarPercent, + bodyForPinBarPercent // + ); + + // + // Engulfing Bar ... + ENUM_X_DIRECTION engulfDir; + bool isEngulfBar = IsEngulfBar( + bar, + engulfDir, + extend, + bodyForEngulfBarPercent // + ); + + // + // Momentum Bar ... + ENUM_X_DIRECTION momentumDir; + bool isMomentumBar = IsMomentumBar( + bar, + momentumDir, + extend, + bodyForMomentumBarPercent // + ); + + // + // Rejection Bar ... + ENUM_X_DIRECTION rejectionDir; + bool isRejectionBar = IsRejectionBar( + bar, + rejectionDir, + extend, + shadowForPinAndRejectionBarPercent // + ); + + // + result = isPiBar || + isEngulfBar || + isMomentumBar || + isRejectionBar; + if (result) + { + // + if (isPiBar) + { + dir = pinDir; + } + else if (isEngulfBar) + { + dir = engulfDir; + } + else if (isMomentumBar) + { + dir = momentumDir; + } + else + { + dir = rejectionDir; + } + } + + // + result = IsBullish(dir) || + IsBearish(dir); + + // + return result; + } + + /** + * Check Fibonacci Level 382 Pressure ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool HasFiboPressure( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bearishFib382 = GetFibonacciLevel( + bar.high, + bar.low, + 0.382, + 1 // + ); + double bullishFib382 = GetFibonacciLevel( + bar.high, + bar.low, + 0.382, + -1 // + ); + + // + bool isBullish = bar.GetDown() > bearishFib382; + bool isBearish = bar.GetUp() < bullishFib382; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Support and Resistance Zones ... + + /** + * Check a Bar is Support Bar or not ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Specified Verifiation Range ... + * + * @return ( bool ) + */ + bool IsSupport( + XOHCL &bar, + int range = 21 // + ) + { + // + bool result = false; + + // + if (range < 2) + { + range = 2; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + int prevIDX = index + i; + int nextIDX = index - 1; + + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + prevIDX // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + nextIDX // + ); + if (!result) + { + break; + } + + // + result = bar.low <= iPrevBar.low && + bar.low <= iNextBar.low; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check a Bar is Resistance Bar or not ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Specified Verifiation Range ... + * + * @return ( bool ) + */ + bool IsResistance( + XOHCL &bar, + int range = 21 // + ) + { + // + bool result = false; + + // + if (range < 2) + { + range = 2; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = bar.Index(); + result = range > 0 && + index >= range; + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + for (int i = 1; i <= range; i++) + { + // + int prevIDX = index + i; + int nextIDX = index - 1; + + // + // Prev Bar ... + XOHCL iPrevBar; + result = iPrevBar.Init( + symbol, + period, + prevIDX // + ); + if (!result) + { + break; + } + + // + // Next Bar ... + XOHCL iNextBar; + result = iNextBar.Init( + symbol, + period, + nextIDX // + ); + if (!result) + { + break; + } + + // + result = bar.high >= iPrevBar.high && + bar.high >= iNextBar.high; + if (!result) + { + break; + } + } + + // + return result; + } + + // + // Order Blocks ... + + /** + * Detect an Order Block Based on Given Bar ... + * + * @param bar: XOHCL instance, Specified Start Bar ... + * @param ob: XOHCL instance, Fill it if Order Block Found ... + * @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ... + * @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ... + * + * @return ( bool ) + */ + bool HasOrderBlock( + XOHCL &bar, + XOHCL &ob, + ENUM_X_DIRECTION &dir, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + ob.Clean(); + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = 0; + result = HasSameBars( + bar, + dir, + index, + sameBars // + ); + if (!result) + { + return result; + } + + // + int obIndex = index; + result = ob.Init( + bar.symbol, + bar.period, + obIndex // + ); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Fair Value Gaps ... + + /** + * Detect a Fair Value Gap Based on Given Bar ... + * + * @param bar: XOHCL instance, Specified Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ... + * @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ... + * + * @return ( bool ) + */ + bool HasFairValueGap( + XOHCL &bar, + XOHCL &prevBar, + XOHCL &nextBar, + ENUM_X_DIRECTION &dir, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + prevBar.Clean(); + nextBar.Clean(); + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int index = 0; + result = HasSameBars( + bar, + dir, + index, + sameBars // + ); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(dir); + + // + int to = bar.Index() + 1; + int from = index + 1; + for (int i = from; i > to; i--) + { + // + result = prevBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + result = nextBar.Init( + bar.symbol, + bar.period, + i - 2 // + ); + if (!result) + { + break; + } + + // + result = isBullish + ? prevBar.high < nextBar.low + : prevBar.low > nextBar.high; + if (result) + { + break; + } + } + + // + if (!result) + { + // + prevBar.Clean(); + nextBar.Clean(); + dir = X_DIRECTION_NONE; + } + + // + return result; + } + + // + // Bar CHOCH ... + + /** + * Check Specified Bar Has PullBack or not ... + * + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param bar: XOHCL instance, Speciied Bar ... + * @param loopback: Integer, loopback Length ... + * @param forceBody: Boolean, Specified Choch Happens only by Bar's Body ... + * + * @return ( bool ) + */ + bool HasPullBack( + ENUM_X_DIRECTION &dir, + XOHCL &bar, + int loopback = 3, + bool forceBody = false // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + // Calculate Loopback Data ... + int index = -1; + int start = -1; + int end = -1; + int count = -1; + result = CalculateLoopBackData( + index, + start, + end, + count, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + // Calculate Loopback HH and LL Data ... + int hhIDX = -1; + double hh = -1; + int llIDX = -1; + double ll = -1; + result = CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + bool isBullishDirection = + bar.high > hh && + bar.low > ll; + bool isBearishDirection = + bar.high < hh && + bar.low < ll; + result = isBullishDirection || + isBearishDirection; + if (!result) + { + return result; + } + + // + if (forceBody) + { + // + isBullishDirection = + bar.GetUp() > hh && + bar.GetDown() > ll; + isBearishDirection = + bar.GetUp() < hh && + bar.GetDown() < ll; + result = isBullishDirection || + isBearishDirection; + if (!result) + { + return result; + } + } + + // + // Check Bar's Direction in related to CHOCH Direction ... + result = + isBullishDirection + ? bar.IsBullish() + : bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Set Direction ... + dir = + isBullishDirection + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Check Loopback End Bar ... + XOHCL endBar; + result = endBar.Init( + symbol, + period, + end - 1 // + ); + if (!result) + { + return result; + } + + // + // End Bar Must be InDirect by Specified Bar ... + result = + isBullishDirection + ? endBar.IsBearish() + : endBar.IsBullish(); + + // + // Check Loopback for Directional Bars ... + + // + return result; + } + + // + // Tools ... + + // + bool IsStrong( + XOHCL &bar, + double percent = 50 // Percent of Body + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = + (bar.GetRange() * percent) / 100 <= bar.GetBody(); + + // + return result; + } + + // + bool HasStrongLowShadow( + XOHCL &bar, + double percent = 50, // Percent of Body + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = + (bar.GetRange() * percent) / 100 <= bar.GetLowShadow(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + result = bar.Index() > __loopback; + if (!result) + { + return result; + } + + // + // Get Highest High and Lowest Low in loopback Range ... + int startIndex = bar.Index() - __loopback; + int endIndex = bar.Index() + __loopback; + int requiredBars = MathAbs(endIndex - startIndex); + + // + // Highs ... + double highs[]; + int copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + + // + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + int highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + double highestHigh = highs[highestHighIDX]; + + // + // Lows ... + double lows[]; + int copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + + // + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + int lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + double lowestLow = lows[lowestLowIDX]; + + // + result = bar.low == lowestLow && + highestHigh > bar.high; + if (!result) + { + return result; + } + + // + // Try to Validate Sharp Ratio ... + + // + Clean(highs); + Clean(lows); + + // + // Left Side ... + startIndex = bar.Index() + 1; + endIndex = startIndex + (__loopback / 2) - 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double leftDiff = highestHigh - lowestLow; + + // + Clean(highs); + Clean(lows); + + // + // Right Side ... + startIndex = bar.Index() - 1; + endIndex = startIndex - (__loopback / 2) + 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double rightDiff = highestHigh - lowestLow; + double diff = MathMax(leftDiff, rightDiff); + result = bar.GetLowShadow() >= (diff / 100) * _sharpRatio; + + // + return result; + } + + // + bool HasStrongHighShadow( + XOHCL &bar, + double percent = 50, // Percent of Body + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = + (bar.GetRange() * percent) / 100 <= bar.GetHighShadow(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + result = bar.Index() > __loopback; + if (!result) + { + return result; + } + + // + // Get Highest High and Lowest Low in loopback Range ... + int startIndex = bar.Index() - __loopback; + int endIndex = bar.Index() + __loopback; + int requiredBars = MathAbs(endIndex - startIndex); + + // + // Highs ... + double highs[]; + int copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + + // + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + int highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + double highestHigh = highs[highestHighIDX]; + + // + // Lows ... + double lows[]; + int copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + + // + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + int lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + double lowestLow = lows[lowestLowIDX]; + + // + result = bar.high == highestHigh && + lowestLow < bar.low; + if (!result) + { + return result; + } + + // + // Try to Validate Sharp Ratio ... + + // + Clean(highs); + Clean(lows); + + // + // Left Side ... + startIndex = bar.Index() + 1; + endIndex = startIndex + (__loopback / 2) - 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double leftDiff = highestHigh - lowestLow; + + // + Clean(highs); + Clean(lows); + + // + // Right Side ... + startIndex = bar.Index() - 1; + endIndex = startIndex - (__loopback / 2) + 1; + requiredBars = MathAbs(endIndex - startIndex); + + // + copiedHighs = CopyHigh( + bar.symbol, + bar.period, + startIndex, + requiredBars, + highs // + ); + result = copiedHighs == requiredBars; + if (!result) + { + return result; + } + + // + highestHighIDX = ArrayMaximum(highs); + result = IsValidIndex(highestHighIDX); + if (!result) + { + return result; + } + + // + highestHigh = highs[highestHighIDX]; + + // + copiedLows = CopyLow( + bar.symbol, + bar.period, + startIndex, + requiredBars, + lows // + ); + result = copiedLows == requiredBars; + if (!result) + { + return result; + } + + // + lowestLowIDX = ArrayMinimum(lows); + result = IsValidIndex(lowestLowIDX); + if (!result) + { + return result; + } + + // + lowestLow = lows[lowestLowIDX]; + + // + double rightDiff = highestHigh - lowestLow; + double diff = MathMax(leftDiff, rightDiff); + result = bar.GetHighShadow() >= (diff / 100) * _sharpRatio; + + // + return result; + } + + // + bool IsStrongBullish( + XOHCL &bar, + double percent = 50 // Percent of Body + ) + { + // + bool result = false; + + // + result = + bar.IsValid() && + bar.IsBullish() && + IsStrong(bar, percent); + + // + return result; + } + + // + bool IsStrongBearish( + XOHCL &bar, + double percent = 50 // Percent of Body + ) + { + // + bool result = false; + + // + result = + bar.IsValid() && + bar.IsBearish() && + IsStrong(bar, percent); + + // + return result; + } + + // + bool IsSharpBullish( + XOHCL &bar, + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + int hIDX = bar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + int lIDX = bar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + result = + // + hIDX >= 0 && + lIDX >= 0 && + MathAbs(hIDX - bar.Index()) < 2 + // + ; + + // + if (!result) + { + return result; + } + + // + XOHCL hBar; + result = hBar.Init( + bar.symbol, + bar.period, + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL lBar; + result = lBar.Init( + bar.symbol, + bar.period, + lIDX // + ); + if (!result) + { + return result; + } + + // + double lhDif = hBar.high - lBar.low; + + // + int hhIDX = hBar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + + // + int llIDX = lBar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + XOHCL hhBar; + result = hhBar.Init( + bar.symbol, + bar.period, + hhIDX + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL llBar; + result = llBar.Init( + bar.symbol, + bar.period, + llIDX + lIDX // + ); + if (!result) + { + return result; + } + + // + double llhhDif = hhBar.high - llBar.low; + + // + result = + // + lBar.low > llBar.low && + hBar.high > hhBar.high && + lhDif >= llhhDif * _sharpRatio + // + ; + + // + return result; + } + + // + bool IsSharpBearish( + XOHCL &bar, + int __loopback = 2, + double _sharpRatio = 2.5 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (__loopback < 0) + { + __loopback = 2; + } + + // + if (_sharpRatio < 0) + { + _sharpRatio = 2.5; + } + + // + int hIDX = bar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + int lIDX = bar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + result = + // + hIDX >= 0 && + lIDX >= 0 && + MathAbs(hIDX - bar.Index()) < 2 + // + ; + + // + if (!result) + { + return result; + } + + // + XOHCL hBar; + result = hBar.Init( + bar.symbol, + bar.period, + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL lBar; + result = lBar.Init( + bar.symbol, + bar.period, + lIDX // + ); + if (!result) + { + return result; + } + + // + double lhDif = hBar.high - lBar.low; + + // + int hhIDX = hBar.FindHighestIndex( + __loopback, + MODE_HIGH // + ); + + // + int llIDX = lBar.FindLowestIndex( + __loopback, + MODE_LOW // + ); + + // + XOHCL hhBar; + result = hhBar.Init( + bar.symbol, + bar.period, + hhIDX + hIDX // + ); + if (!result) + { + return result; + } + + // + XOHCL llBar; + result = llBar.Init( + bar.symbol, + bar.period, + llIDX + lIDX // + ); + if (!result) + { + return result; + } + + // + double llhhDif = hhBar.high - llBar.low; + + // + result = + // + lBar.low < llBar.low && + hBar.high < hhBar.high && + lhDif >= llhhDif * _sharpRatio + // + ; + + // + return result; + } + + // + // + // + + // + // Retrieve Bullish Pressure ... + double GetBullishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + result += bars[i].GetLowShadow(); + } + + // + return result; + } + + // + // Retrieve Bearish Pressure ... + double GetBearishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + result += bars[i].GetHighShadow(); + } + + // + return result; + } + + // + bool HasBullishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPressure(bar, __loopback); + double bearishPressure = GetBearishPressure(bar, __loopback); + + // + result = + // + bullishPressure > 0 && + bearishPressure >= 0 && + bullishPressure > bearishPressure + // + ; + + // + return result; + } + + // + bool HasBearishPressure( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPressure(bar, __loopback); + double bearishPressure = GetBearishPressure(bar, __loopback); + + // + result = + // + bearishPressure > 0 && + bullishPressure >= 0 && + bearishPressure > bullishPressure + // + ; + + // + return result; + } + + // + // Retrieve Bullish Power ... + double GetBullishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + // + if (bars[i].IsBullish()) + { + result += bars[i].GetBody(); + } + } + + // + return result; + } + + // + // Retrieve Bearish Pressure ... + double GetBearishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + double result = 0; + + // + if (!bar.IsValid()) + { + return result; + } + + // + XOHCL bars[]; + int barsCount = GetBars( + bars, + bar.symbol, + bar.period, + bar.Index(), + __loopback // + ); + if (!IsValidSize(barsCount)) + { + return result; + } + + // + for (int i = 0; i < barsCount; i++) + { + // + if (bars[i].IsBearish()) + { + result += bars[i].GetBody(); + } + } + + // + return result; + } + + // + bool HasBullishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPower(bar, __loopback); + double bearishPressure = GetBearishPower(bar, __loopback); + + // + result = + // + bullishPressure > 0 && + bearishPressure >= 0 && + bullishPressure > bearishPressure + // + ; + + // + return result; + } + + // + bool HasBearishPower( + XOHCL &bar, + int __loopback = 7 // + ) + { + // + bool result = false; + + // + if (__loopback < 0) + { + __loopback = 7; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double bullishPressure = GetBullishPower(bar, __loopback); + double bearishPressure = GetBearishPower(bar, __loopback); + + // + result = + // + bearishPressure > 0 && + bullishPressure >= 0 && + bearishPressure > bullishPressure + // + ; + + // + return result; + } + + // + // Decisions ... + + // + bool IsBullishDecision( + XOHCL &bar, + double percent = 70 // Percent of Body + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() && + bar.Index() > 0 && + bar.IsBullish() && + (bar.GetRange() * percent) / 100 <= bar.GetBody() + // + ; + + // + return result; + } + + // + bool IsBearishDecision( + XOHCL &bar, + double percent = 70 // Percent of Body + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() && + bar.Index() > 0 && + bar.IsBearish() && + (bar.GetRange() * percent) / 100 <= bar.GetBody() + // + ; + + // + return result; + } + + // + // Candlestic Patterns ... + + // + // Check Doji ... + bool IsDoji( + XOHCL &bar // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = bar.open == bar.close; + + // + return result; + } + + // + // Check Hammer ... + bool IsHammer( + XOHCL &bar, + double _upShadowFactor = 0.1, + double _downShadowFactor = 0.6, + bool applyFib382Check = true, + bool applyPrevShadowCheck = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_upShadowFactor < 0) + { + _upShadowFactor = 0.1; + } + + // + if (_downShadowFactor < 0) + { + _upShadowFactor = 0.6; + } + + // + double range = bar.GetRange(); + + // + // Check Upper Shadow Must be 0 or Under 10% ... + double upShadow = bar.GetHighShadow(); + result = upShadow < range * _upShadowFactor; + if (!result) + { + return result; + } + + // + // Check Down Shadow Must at least 60% ... + double downShadow = bar.GetLowShadow(); + result = downShadow > range * _downShadowFactor; + if (!result) + { + return result; + } + + // + // Check Fib 382 ... + if (result && applyFib382Check) + { + // + double fib382 = GetFibonacciLevel( + bar.high, + bar.low, + 0.382, + -1 // + ); + result = bar.GetDown() > fib382; + } + + // + // Check Shadow Based on Prev Bar ... + if (result && applyPrevShadowCheck) + { + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + result = bar.low < pBar.low; + } + + // + return result; + } + + // + // Check Sgooting Star ... + // Reversal Hammer ... + bool IsShootingStar( + XOHCL &bar, + double _upShadowFactor = 0.6, + double _downShadowFactor = 0.1, + bool applyFib382Check = true, + bool applyPrevShadowCheck = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_upShadowFactor < 0) + { + _upShadowFactor = 0.6; + } + + // + if (_downShadowFactor < 0) + { + _upShadowFactor = 0.1; + } + + // + double range = bar.GetRange(); + + // + // Check Upper Shadow Must be 0 or Under 10% ... + double upShadow = bar.GetHighShadow(); + result = upShadow > range * _upShadowFactor; + if (!result) + { + return result; + } + + // + // Check Down Shadow Must at least 60% ... + double downShadow = bar.GetLowShadow(); + result = downShadow < range * _downShadowFactor; + if (!result) + { + return result; + } + + // + // Check Fib 382 ... + if (result && applyFib382Check) + { + // + double fib382 = GetFibonacciLevel( + bar.high, + bar.low, + 0.382, + 1 // + ); + result = bar.GetUp() < fib382; + } + + // + // Check Shadow Based on Prev Bar ... + if (result && applyPrevShadowCheck) + { + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + result = bar.high > pBar.high; + } + + // + return result; + } + + // + // Check Bullish Engulfing ... + bool IsBullishEngulfing( + XOHCL &bar, + double _engulfBarBodyFactor = 0.7 // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_engulfBarBodyFactor < 0) + { + _engulfBarBodyFactor = 0.7; + } + + // + // Check Bar Is Bullish ... + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double body = bar.GetBody(); + + // + // Check Prev Bar Must Bearish ... + result = pBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Check Shadows Engulf Prev Bar ... + result = + // + bar.high > pBar.high && + bar.low <= pBar.low + // + ; + if (!result) + { + return result; + } + + // + // Check Engulfed Bar Must Inside Engulfer Body ... + result = + // + bar.GetUp() > pBar.GetUp() && + bar.GetDown() < pBar.GetDown() + // + ; + if (!result) + { + return result; + } + + // + // Check Body of Engulfing Bar ... + if (result && _engulfBarBodyFactor > 0) + { + result = body >= range * _engulfBarBodyFactor; + } + + // + return result; + } + + // + // Check Bearish Engulfing ... + bool IsBearishEngulfing( + XOHCL &bar, + double _engulfBarBodyFactor = 0.7 // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_engulfBarBodyFactor < 0) + { + _engulfBarBodyFactor = 0.7; + } + + // + // Check Bar Is Bearish ... + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double body = bar.GetBody(); + + // + // Check Prev Bar Must Bullish ... + result = pBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Check Shadows Engulf Prev Bar ... + result = bar.high >= pBar.high && + bar.low < pBar.low; + if (!result) + { + return result; + } + + // + // Check Engulfed Bar Must Inside Engulfer Body ... + result = + // + bar.GetUp() > pBar.GetUp() && + bar.GetDown() < pBar.GetDown() + // + ; + if (!result) + { + return result; + } + + // + // Check Body of Engulfing Bar ... + if (result && _engulfBarBodyFactor > 0) + { + result = body >= range * _engulfBarBodyFactor; + } + + // + return result; + } + + // + // Check Morning Star Pattern ... + bool IsMorningStar( + XOHCL &bar, + double _middleRangeFactor = 0.3, + double _startBodyFactor = 0.6, + bool forceCheckMiddleBarDirection = true, + bool forceCheckStartBody = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_middleRangeFactor < 0) + { + _middleRangeFactor = 0.3; + } + + // + if (_startBodyFactor < 0) + { + _startBodyFactor = 0.6; + } + + // + // Current Bar Must be Bullish ... + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar must be Bearish ... + if (result && forceCheckMiddleBarDirection) + { + // + result = pBar.IsBearish(); + if (!result) + { + return result; + } + } + + // + // Retrieve Previous Bar of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev Of Prev Bar Must be Bearish ... + result = ppBar.IsBearish(); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double pRange = pBar.GetRange(); + double ppRange = ppBar.GetRange(); + + // + // Middle Bar must be Smaller than Ratio of other ... + result = + // + pRange < range * _middleRangeFactor && + pRange < ppRange * _middleRangeFactor + // + ; + if (!result) + { + return result; + } + + // + if (result && forceCheckStartBody) + { + // + result = ppBar.GetBody() > ppRange * _startBodyFactor; + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Check Evening Star Pattern ... + bool IsEveningStar( + XOHCL &bar, + double _middleRangeFactor = 0.3, + double _startBodyFactor = 0.6, + bool forceCheckMiddleBarDirection = true, + bool forceCheckStartBody = true // + ) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + if (_middleRangeFactor < 0) + { + _middleRangeFactor = 0.3; + } + + // + if (_startBodyFactor < 0) + { + _startBodyFactor = 0.6; + } + + // + // Current Bar Must be Bearish ... + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar must be Bullish ... + if (result && forceCheckMiddleBarDirection) + { + // + result = pBar.IsBullish(); + if (!result) + { + return result; + } + } + + // + // Retrieve Previous Bar of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev Of Prev Bar Must be Bullish ... + result = ppBar.IsBullish(); + if (!result) + { + return result; + } + + // + double range = bar.GetRange(); + double pRange = pBar.GetRange(); + double ppRange = ppBar.GetRange(); + + // + // Middle Bar must be Smaller than Ratio of other ... + result = + // + pRange < range * _middleRangeFactor && + pRange < ppRange * _middleRangeFactor + // + ; + if (!result) + { + return result; + } + + // + if (result && forceCheckStartBody) + { + // + result = ppBar.GetBody() > ppRange * _startBodyFactor; + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Bullish Marubozu ... + bool IsBullishMarubozu(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + result = + // + bar.GetUp() == bar.high && + bar.GetDown() == bar.low + // + ; + + // + return result; + } + + // + // Bearish Marubozu ... + bool IsBearishMarubozu(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + result = + // + bar.GetUp() == bar.high && + bar.GetDown() == bar.low + // + ; + + // + return result; + } + + // + // Contextual Patterns ... + + // + // Check Swing High ... + bool IsBarSwingHigh(XOHCL &bar) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bearish ... + result = bar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bullish ... + result = pBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bullish ... + result = ppBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Check All Highs ... + result = + // + bar.high < pBar.high && + pBar.high > ppBar.high + // + ; + + // + return result; + } + + // + // Find Simple 3 Candle Based Swing High ... + bool IsSimpleSwingHigh( + XOHCL &bar, + double thresholdInPoint = 1 // + ) + { + // + bool result = false; + + // + int index = bar.Index(); + result = index > 0; + if (!result) + { + return result; + } + + // + XOHCL nextBar; + result = bar.GetNextBar(nextBar); + if (!result) + { + return result; + } + + // + XOHCL prevBar; + result = bar.GetPreviousBar(prevBar); + if (!result) + { + return result; + } + + // + double point = GetPoints(bar.symbol); + double requiredOffset = point * thresholdInPoint; + + // + result = + bar.high > nextBar.high && + bar.high > prevBar.high && + (thresholdInPoint <= 0 + ? true + : MathAbs( + MathMax( + nextBar.high, + prevBar.high) - + bar.high) >= requiredOffset); + + // + return result; + } + + // + // Find Last Swing High ... + bool FindLastSwingHigh( + XOHCL &bar, + XOHCL &swing // + ) + { + // + bool result = false; + + // + swing.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = iBars( + bar.symbol, + bar.period // + ); + int maxAllowed = MathMin(100, (totalBars / 100)); + + // + int idx = bar.Index(); + for (int i = idx; i <= idx + maxAllowed; i++) + { + // + swing.Clean(); + result = swing.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + // + swing.Clean(); + break; + } + + // + result = IsBarSwingHigh(swing); + if (result) + { + break; + } + } + + // + return result; + } + + // + // Check Swing Low ... + bool IsBarSwingLow(XOHCL &bar) + { + // + bool result = false; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bullish ... + result = bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bearish ... + result = pBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bearish ... + result = ppBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Check All Lows ... + result = + // + bar.low > pBar.low && + pBar.low < ppBar.low + // + ; + + // + return result; + } + + // + // Find Simple 3 Candle Based Swing Low ... + bool IsSimpleSwingLow( + XOHCL &bar, + double thresholdInPoint = 1 // + ) + { + // + bool result = false; + + // + int index = bar.Index(); + result = index > 0; + if (!result) + { + return result; + } + + // + XOHCL nextBar; + result = bar.GetNextBar(nextBar); + if (!result) + { + return result; + } + + // + XOHCL prevBar; + result = bar.GetPreviousBar(prevBar); + if (!result) + { + return result; + } + + // + double point = GetPoints(bar.symbol); + double requiredOffset = point * thresholdInPoint; + + // + result = + bar.low < nextBar.low && + bar.low < prevBar.low && + (thresholdInPoint <= 0 + ? true + : MathAbs( + MathMax( + nextBar.low, + prevBar.low) - + bar.low) >= requiredOffset); + + // + return result; + } + + // + // Find Last Swing Low ... + bool FindLastSwingLow( + XOHCL &bar, + XOHCL &swing // + ) + { + // + bool result = false; + + // + swing.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = iBars( + bar.symbol, + bar.period // + ); + int maxAllowed = MathMin(100, (totalBars / 100)); + + // + int idx = bar.Index(); + for (int i = idx; i <= idx + maxAllowed; i++) + { + // + swing.Clean(); + result = swing.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + // + swing.Clean(); + break; + } + + // + result = IsBarSwingLow(swing); + if (result) + { + break; + } + } + + // + return result; + } + + // + // Check Bullish FVG ... + bool HasBullishFVG( + XOHCL &bar, + double &upper, + double &lower, + datetime &start, + datetime &end, + bool forceMiddleBarCheck = true, + bool forceCheckLastBarDirection = false // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + end = NULL; + start = NULL; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bullish ... + result = + !forceCheckLastBarDirection + ? true + : bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bullish ... + result = pBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bullish ... + result = ppBar.IsBullish(); + if (!result) + { + return result; + } + + // + // Other Conditions ... + result = + // + bar.low > ppBar.high + // + ; + + // + // Check Middle Bar Range ... + if (result && forceMiddleBarCheck) + { + // + result = + // + pBar.high > bar.low && + pBar.low < ppBar.high + // + ; + + // + if (!result) + { + return result; + } + } + + // + if (result) + { + // + end = bar.time; + upper = bar.low; + lower = ppBar.high; + start = ppBar.time; + } + + // + return result; + } + + // + // Check Bearish FVG ... + bool HasBearishFVG( + XOHCL &bar, + double &upper, + double &lower, + datetime &start, + datetime &end, + bool forceMiddleBarCheck = true, + bool forceCheckLastBarDirection = false // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + end = NULL; + start = NULL; + + // + // Validate Content and Ignore 0 Bar + // since it is not Completed ... + result = bar.IsValid() && bar.Index() > 0; + if (!result) + { + return result; + } + + // + // Current Bar Must be Bearish ... + result = + !forceCheckLastBarDirection + ? true + : bar.IsBullish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Prev Bar Must be Bearish ... + result = pBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Retrieve Prev of Prev Bar ... + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + return result; + } + + // + // Prev of Prev Bar Must be Bearish ... + result = ppBar.IsBearish(); + if (!result) + { + return result; + } + + // + // Other Conditions ... + result = + // + bar.high < ppBar.low + // + ; + + // + // Check Middle Bar Range ... + if (result && forceMiddleBarCheck) + { + // + result = + // + pBar.high > bar.low && + pBar.low < ppBar.high + // + ; + + // + if (!result) + { + return result; + } + } + + // + if (result) + { + // + end = bar.time; + lower = bar.high; + upper = ppBar.low; + start = ppBar.time; + } + + // + return result; + } + + // + // Find Support ... + bool HasSupport( + XOHCL &bar, + XOHCL &dest, + ENUM_X_PRICE type = X_PRICE_CLOSE, + int _loopback = 21, + int tries = 100 // + ) + { + // + bool result = false; + + // + dest.Clean(); + + // + if (_loopback < 0) + { + _loopback = 21; + } + + // + if (tries < 0) + { + tries = 100; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + for (int i = 1; i < tries; i++) + { + // + int _length = _loopback * i; + + // + int lowestIDX = bar.FindLowestIndex( + _length, + MODE_LOW // + ); + result = IsValidIndex(lowestIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + lowestIDX // + ); + if (!result) + { + break; + } + + // + result = + // + price > iLBar.high + // + ; + if (result) + { + // + dest = iLBar; + break; + } + } + + // + result = dest.IsValid(); + + // + return result; + } + + // + // Find Resistance ... + bool HasResistance( + XOHCL &bar, + XOHCL &dest, + ENUM_X_PRICE type = X_PRICE_CLOSE, + int _loopback = 21, + int tries = 100 // + ) + { + // + bool result = false; + + // + dest.Clean(); + + // + if (_loopback < 0) + { + _loopback = 21; + } + + // + if (tries < 0) + { + tries = 100; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + for (int i = 1; i < tries; i++) + { + // + int _length = _loopback * i; + + // + int highestIDX = bar.FindHighestIndex( + _length, + MODE_LOW // + ); + result = IsValidIndex(highestIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + highestIDX // + ); + if (!result) + { + break; + } + + // + result = + // + price < iHBar.high + // + ; + if (result) + { + // + dest = iHBar; + break; + } + } + + // + result = dest.IsValid(); + + // + return result; + } + + // + // Trend Detection ... + + // + // Find Bullish Trend ... + bool HasBullishTrend( + XOHCL &bar, + XOHCL &highSwingBars[], + XOHCL &lowSwingBars[], + bool forceMethod2 = false, + int _loopback = 3, + int tries = 3, + ENUM_X_PRICE type = X_PRICE_CLOSE // + ) + { + // + bool result = false; + + // + Clean(lowSwingBars); + Clean(highSwingBars); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + int lastIDX = bar.Index(); + double lastH = 0; + double lastL = 0; + for (int i = 1; i < tries + 1; i++) + { + // + // Use Regular Method ... + if (!forceMethod2) + { + // + int iHIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_HIGH, + _loopback, + lastIDX // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH < lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_LOW, + _loopback, + lastIDX // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL < lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + // + // Use Other MEthod ... + else + { + // + int _length = i * _loopback; + int start = + // + i == 1 + ? 1 + : _length - _loopback + // + ; + + // + int iHIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + _loopback, + start // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH < lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + _loopback, + start // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL < lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + } + + // + if (result) + { + // + result = + // + ArraySize(lowSwingBars) == tries && + ArraySize(highSwingBars) == tries + // + ; + } + + // + if (!result) + { + // + Clean(lowSwingBars); + Clean(highSwingBars); + } + + // + return result; + } + + // + // Find Bearish Trend ... + bool HasBearishTrend( + XOHCL &bar, + XOHCL &highSwingBars[], + XOHCL &lowSwingBars[], + bool forceMethod2 = false, + int _loopback = 3, + int tries = 3, + ENUM_X_PRICE type = X_PRICE_CLOSE // + ) + { + // + bool result = false; + + // + Clean(lowSwingBars); + Clean(highSwingBars); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double price = bar.GetPrice(type); + + // + int lastIDX = bar.Index(); + double lastH = 0; + double lastL = 0; + for (int i = 1; i < tries + 1; i++) + { + // + // Use Regular Method ... + if (!forceMethod2) + { + // + int iHIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_HIGH, + _loopback, + lastIDX // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH > lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = FindSwing( + bar.symbol, + bar.period, + X_SWING_LOW, + _loopback, + lastIDX // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL > lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + // + // Use Other MEthod ... + else + { + // + int _length = i * _loopback; + int start = + // + i == 1 + ? 1 + : _length - _loopback + // + ; + + // + int iHIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + _loopback, + start // + ); + result = IsValidIndex(iHIDX); + if (!result) + { + break; + } + + // + XOHCL iHBar; + result = iHBar.Init( + bar.symbol, + bar.period, + iHIDX // + ); + if (!result) + { + break; + } + + // + double iH = iHBar.high; + bool isIHAccepted = + // + iH > 0 && + ( + // + lastH == 0 + ? true + : iH > lastH + // + ) + // + ; + if (isIHAccepted) + { + // + AddRef( + iHBar, + highSwingBars // + ); + + // + lastH = iH; + lastIDX = iHIDX; + } + + // + int iLIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + _loopback, + start // + ); + result = IsValidIndex(iLIDX); + if (!result) + { + break; + } + + // + XOHCL iLBar; + result = iLBar.Init( + bar.symbol, + bar.period, + iLIDX // + ); + if (!result) + { + break; + } + + // + double iL = iLBar.low; + bool isILAccepted = + // + iL > 0 && + ( + // + lastL == 0 + ? true + : iL > lastL + // + ) + // + ; + if (isILAccepted) + { + // + AddRef( + iLBar, + lowSwingBars // + ); + + // + lastL = iL; + lastIDX = iLIDX; + } + } + } + + // + if (result) + { + // + result = + // + ArraySize(lowSwingBars) == tries && + ArraySize(highSwingBars) == tries + // + ; + } + + // + if (!result) + { + // + Clean(lowSwingBars); + Clean(highSwingBars); + } + + // + return result; + } + + // + // Order Blocks ... + + // + // Find Bullish Order Block ... + bool HasBullishOrderBlock( + XOHCL &bar, + XOHCL &orderBlock, + int _minimumSameBars = 4 // + ) + { + // + bool result = false; + + // + orderBlock.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (_minimumSameBars < 0) + { + _minimumSameBars = 4; + } + + // + XOHCL cBar; + int founded = 0; + int cIDX = bar.Index(); + bool isEnough = false; + while (!isEnough) + { + // + result = cBar.Init( + bar.symbol, + bar.period, + cIDX // + ); + if (!result) + { + break; + } + + // + result = cBar.IsBullish(); + if (!result && cBar.IsBearish()) + { + break; + } + + // + cIDX++; + founded++; + } + + // + // Here we have to check founded and if it's fill + // our requirements ... + // cIDX is Order Block Index ... + result = + // + cBar.IsValid() && + bar.high > cBar.high && + founded >= _minimumSameBars + // + ; + if (!result) + { + return result; + } + + // + result = orderBlock.Init( + bar.symbol, + bar.period, + cIDX // + ); + if (!result) + { + // + orderBlock.Clean(); + return result; + } + + // + return result; + } + + // + // Find Bearish Order Block ... + bool HasBearishOrderBlock( + XOHCL &bar, + XOHCL &orderBlock, + int _minimumSameBars = 4 // + ) + { + // + bool result = false; + + // + orderBlock.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + if (_minimumSameBars < 0) + { + _minimumSameBars = 4; + } + + // + XOHCL cBar; + int founded = 0; + int cIDX = bar.Index(); + bool isEnough = false; + while (!isEnough) + { + // + bool isInited = cBar.Init( + bar.symbol, + bar.period, + cIDX // + ); + + // + result = cBar.IsBearish(); + if (!result && cBar.IsBullish()) + { + break; + } + + // + cIDX++; + founded++; + } + + // + // Here we have to check founded and if it's fill + // our requirements ... + // cIDX is Order Block Index ... + result = + // + cBar.IsValid() && + bar.high < cBar.low && + founded >= _minimumSameBars + // + ; + if (!result) + { + return result; + } + + // + result = orderBlock.Init( + bar.symbol, + bar.period, + cIDX // + ); + if (!result) + { + // + orderBlock.Clean(); + return result; + } + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + // Props ... + + // + // Actions ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-cobject.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-cobject.class.mq5 new file mode 100644 index 0000000..2f3c488 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-cobject.class.mq5 @@ -0,0 +1,3279 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XChartObjects +// Description: provides all require Chart Objects ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +#include +#include +#include +#include +#include + +// +// Definitions ... + +enum ENUM_XCHARTOBJECTS +{ + // + // Global ... + X_ZONE_OBJ = 7860, + X_BOX_OBJ = 7861, + X_BAR_ARROW_OBJ = 7862, + // + X_SIGNAL_OBJ = 8860, + X_TREND_OBJ = 8861, + X_XPVPIVOT_OBJ = 8862, + X_OHCL_OBJ = 8863, + // + // Structured ... + X_TRADE_DAY_OBJ = 9860, + X_MARKET_SESSION_OBJ = 9861, + X_SWING_HIGH_OBJ = 9862, + X_SWING_LOW_OBJ = 9863, + X_BULLISH_MOMENTUM_BAR_OBJ = 9864, + X_BEARISH_MOMENTUM_BAR_OBJ = 9865, + X_BULLISH_REJECTION_BAR_OBJ = 9866, + X_BEARISH_REJECTION_BAR_OBJ = 9867, + X_SUPPORT_ZONE_OBJ = 9868, + X_RESISTANCE_ZONE_OBJ = 9869, + X_SUPPLY_ZONE_OBJ = 9870, + X_DEMAND_ZONE_OBJ = 9871, + X_BULLISH_ORDERBLOCK_OBJ = 9872, + X_BEARISH_ORDERBLOCK_OBJ = 9873, + X_BULLISH_FVG_OBJ = 9874, + X_BEARISH_FVG_OBJ = 9875, + X_TICK_ZONE_OBJ = 9876, + X_TICKS_ZONE_OBJ = 9877, + X_CONSOLIDATION_ZONE_OBJ = 9878, +}; + +enum ENUM_X_CHART_IDS +{ + X_TO, + X_FROM, + X_UPPER, + X_LOWER, + X_ENTRY, + X_TARGET, + X_SL, + X_TP, + X_BAR_H_SHW, + X_BAR_BDY, + X_BAR_L_SHW, +}; + +string ToString(ENUM_X_CHART_IDS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_TO: + result = "TO"; + break; + + // + case X_FROM: + result = "FROM"; + break; + + // + case X_UPPER: + result = "UPPER"; + break; + + // + case X_LOWER: + result = "LOWER"; + break; + + // + case X_ENTRY: + result = "ENTRY"; + break; + + // + case X_TARGET: + result = "TARGET"; + break; + + // + case X_SL: + result = "SL"; + break; + + // + case X_TP: + result = "TP"; + break; + + // + case X_BAR_H_SHW: + result = "HSHW"; + break; + + // + case X_BAR_BDY: + result = "BODY"; + break; + + // + case X_BAR_L_SHW: + result = "LSHW"; + break; + + // + } + + // + return result; +} + +// +// Implementation ... + +// +// Global Chart Objects ... + +// +// Bas Chart Object ... +class XCBaseObject : public CChartObject +{ + // + public: + // + + // + // Getter(s) / Setter(s) ... + + /** + * Get Object Specified Name ... + * + * @return ( string ) + */ + string ObjName() + { + return mObjName; + } + + /** + * Set Object Specified Name ... + * + * @param value: String ... + */ + void ObjName(string value) + { + mObjName = value; + } + + // + private: + // + + // + // Props ... + string mObjName; // Object Specified Name ... + + // +}; + +class XCBarArrowObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param name: String, Specified Object ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param swing: XCSwing instance ... + * + * @return ( bool ) + */ + bool CreateByBar( + long chart_id, + string name, + int window, + int arrow, + XOHCL &bar, + ENUM_X_PRICE priceType // + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() + // + ; + if (!result) + { + return result; + } + + // + datetime time = bar.time; + double price = bar.GetPrice(priceType); + + // + result = mArrow.Create( + chart_id, + name, + window, + time, + price, + (char)arrow // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + // + // Setter(s) ... + + /** + * Set Arrow Anchor ... + * + * @param value: ENUM_ARROW_ANCHOR member ... + */ + void ArrowAnchor(ENUM_ARROW_ANCHOR value) + { + mArrow.Anchor(value); + } + + /** + * Set Arrow Color ... + * + * @param value: Color ... + */ + void ArrowColor(color value) + { + mArrow.Color(value); + } + + /** + * Set Arrow Width ... + * + * @param value: Integer ... + */ + void ArrowWidth(int value) + { + mArrow.Width(value); + } + + // + private: + // + CChartObjectArrow mArrow; + + // +}; + +// +// Swing ... +class XCSwingObject : public XCBarArrowObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param swing: XCSwing instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateBySwing( + long chart_id, + int window, + int arrow, + XCSwing &swing, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + // + swing.IsValid() + // + ; + if (!result) + { + return result; + } + + // + string name = swing.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + XOHCL bar; + result = swing.FillBar(bar); + if (!result) + { + return result; + } + + // + ENUM_X_PRICE price = swing.IsSwingHigh() + ? X_PRICE_HIGH + : X_PRICE_LOW; + + // + result = CreateByBar( + chart_id, + name, + window, + arrow, + bar, + price // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } +}; + +// +// Swing High ... +class XCSwingHighObject : public XCSwingObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param swing: XCSwing instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCSwing &swing, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = swing.IsValid() && + swing.IsSwingHigh(); + if (!result) + { + return result; + } + + // + result = CreateBySwing( + chart_id, + window, + arrow, + swing, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SWING_HIGH_OBJ; + } + + // +}; + +// +// Swing Low ... +class XCSwingLowObject : public XCSwingObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param swing: XCSwing instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCSwing &swing, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = swing.IsValid() && + swing.IsSwingLow(); + if (!result) + { + return result; + } + + // + result = CreateBySwing( + chart_id, + window, + arrow, + swing, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SWING_LOW_OBJ; + } + + // +}; + +// +// Momentum ... +class XCMomentumBarObject : public XCBarArrowObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param momentumBar: XCMomentumBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateByMomentum( + long chart_id, + int window, + int arrow, + XCMomentumBar &momentumBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + // + momentumBar.IsValid() + // + ; + if (!result) + { + return result; + } + + // + string name = momentumBar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + XOHCL bar; + result = momentumBar.FillBar(bar); + if (!result) + { + return result; + } + + // + ENUM_X_PRICE price = momentumBar.IsBullish() + ? X_PRICE_LOW + : X_PRICE_HIGH; + + // + result = CreateByBar( + chart_id, + name, + window, + arrow, + bar, + price // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } +}; + +// +// Bullish Momentum Bar ... +class XCBullishMomentumBarObject : public XCMomentumBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param momentumBar: XCMomentumBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCMomentumBar &momentumBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = momentumBar.IsValid() && + momentumBar.IsBullish(); + if (!result) + { + return result; + } + + // + result = CreateByMomentum( + chart_id, + window, + arrow, + momentumBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_MOMENTUM_BAR_OBJ; + } + + // +}; + +// +// Bearish Momentum Bar ... +class XCBearishMomentumBarObject : public XCMomentumBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param momentumBar: XCMomentumBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCMomentumBar &momentumBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = momentumBar.IsValid() && + momentumBar.IsBearish(); + if (!result) + { + return result; + } + + // + result = CreateByMomentum( + chart_id, + window, + arrow, + momentumBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BEARISH_MOMENTUM_BAR_OBJ; + } + + // +}; + +// +// Rejection ... +class XCRejectionBarObject : public XCBarArrowObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param rejectionBar: XCRejectionBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateByRejection( + long chart_id, + int window, + int arrow, + XCRejectionBar &rejectionBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + // + rejectionBar.IsValid() + // + ; + if (!result) + { + return result; + } + + // + string name = rejectionBar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + XOHCL bar; + result = rejectionBar.FillBar(bar); + if (!result) + { + return result; + } + + // + ENUM_X_PRICE price = rejectionBar.IsBullish() + ? X_PRICE_LOW + : X_PRICE_HIGH; + + // + result = CreateByBar( + chart_id, + name, + window, + arrow, + bar, + price // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } +}; + +// +// Bullish Rejection Bar ... +class XCBullishRejectionBarObject : public XCRejectionBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param rejectionBar: XCRejectionBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCRejectionBar &rejectionBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = rejectionBar.IsValid() && + rejectionBar.IsBullish(); + if (!result) + { + return result; + } + + // + result = CreateByRejection( + chart_id, + window, + arrow, + rejectionBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_REJECTION_BAR_OBJ; + } + + // +}; + +// +// Bearish Rejection Bar ... +class XCBearishRejectionBarObject : public XCRejectionBarObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param arrow: Integer, Specified Arrow Code ... + * @param rejectionBar: XCRejectionBar instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + int arrow, + XCRejectionBar &rejectionBar, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = rejectionBar.IsValid() && + rejectionBar.IsBearish(); + if (!result) + { + return result; + } + + // + result = CreateByRejection( + chart_id, + window, + arrow, + rejectionBar, + prefix // + ); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BEARISH_REJECTION_BAR_OBJ; + } + + // +}; + +// +// XCZoneObject ... +class XCZoneObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param name: String, Specified Object Identifier on Chart ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool CreateByZone( + long chart_id, + string name, + int window, + XCZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + bool isValidFrom = zone.IsValidFrom(); + bool isValidBoundary = zone.IsValidBoundary(); + + // + result = + // + IsValid(name) && + isValidFrom && + isValidBoundary + // + ; + if (!result) + { + return result; + } + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + datetime from = zone.From(); + datetime to = NormalizeTime(zone.To()); + + // + double upper = zone.Upper(); + double lower = zone.Lower(); + + // + result = mRect.Create( + chart_id, + name, + window, + from, + upper, + to, + lower // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_ZONE_OBJ; + } + + // + // Setter(s) ... + + /** + * Set Zone Width ... + * + * @param value: Integer ... + */ + void ZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Zone Color ... + * + * @param value: Color ... + */ + void ZoneColor(color value) + { + mRect.Color(value); + } + + /** + * Set Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ZoneStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Zone Fill ... + * + * @param value: Boolean ... + */ + void ZoneFill(bool value) + { + mRect.Fill(value); + } + + // + private: + // + CChartObjectRectangle mRect; + + // +}; + +// +// Support Zone ... +class XCSupportZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCSupportZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCSupportZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SUPPORT_ZONE_OBJ; + } +}; + +// +// Resistance Zone ... +class XCResistanceZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCResistanceZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCResistanceZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_RESISTANCE_ZONE_OBJ; + } +}; + +// +// Supply Zone ... +class XCSupplyZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCSupplyZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCSupplyZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SUPPLY_ZONE_OBJ; + } +}; + +// +// Demand Zone ... +class XCDemandZoneObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCDemandZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCDemandZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_DEMAND_ZONE_OBJ; + } +}; + +// +// Bullish Order Block ... +class XCBullishOrderBlockObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCOrderBlock &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_ORDERBLOCK_OBJ; + } +}; + +// +// Bearish Order Block ... +class XCBearishOrderBlockObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCOrderBlock &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_ORDERBLOCK_OBJ; + } +}; + +// +// Bullish Fair Value Gaps ... +class XCBullishFairValueGapObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCFVG &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BULLISH_FVG_OBJ; + } +}; + +class XCConsolidationZoneObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XConsolidationZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XConsolidationZone &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + result = mRect.Create( + chart_id, + name, + window, + zone.From(), + zone.upper, + TimeCurrent(), + zone.lower // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_CONSOLIDATION_ZONE_OBJ; + } + + // + // Setter(s) ... + + /** + * Set Zone Width ... + * + * @param value: Integer ... + */ + void ZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Zone Color ... + * + * @param value: Color ... + */ + void ZoneColor(color value) + { + mRect.Color(value); + } + + /** + * Set Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ZoneStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Zone Fill ... + * + * @param value: Boolean ... + */ + void ZoneFill(bool value) + { + mRect.Fill(value); + } + + // + private: + // + CChartObjectRectangle mRect; + + // +}; + +// +// Bearish Fair Value Gaps ... +class XCBearishFairValueGapObject : public XCZoneObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCOrderBlock instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCFVG &zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + + // + result = CreateByZone( + chart_id, + name, + window, + zone, + prefix // + ); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BEARISH_FVG_OBJ; + } +}; + +// +// Signal ... +class XCSignalObject : public XCBaseObject +{ + // + public: + // + + // + // Constructor ... + void XCSignalObject() + { + } + + // + // Deconstructor ... + void ~XCSignalObject() + { + } + + /** + * Create a Signal Object on Chart ... + * + * @param chart_id: Long ... + * @param name: String ... + * @param window: Integer ... + * @param signal: XSignal instance ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + const int window, + XSignal &signal, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + string name = signal.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + int delay = (PeriodSeconds(signal.period) * 2); + datetime time1 = (datetime)((int)signal.time - delay); + datetime time2 = (datetime)((int)signal.time + delay); + + // + // TP ... + string tpName = ToString(X_TP) + "_" + nameMD5; + result = mTPTrend.Create( + chart_id, + tpName, + window, + time1, + signal.tp, + time2, + signal.tp // + ); + if (!result) + { + return result; + } + + // + // SL ... + string slName = ToString(X_SL) + "_" + nameMD5; + result = mSLTrend.Create( + chart_id, + slName, + window, + time1, + signal.sl, + time2, + signal.sl // + ); + if (!result) + { + // + mTPTrend.Delete(); + return result; + } + + // + // TARGET ... + if (signal.target > 0) + { + // + string targetName = ToString(X_TARGET) + "_" + nameMD5; + result = mTargetTrend.Create( + chart_id, + targetName, + window, + time1, + signal.target, + time2, + signal.target // + ); + if (!result) + { + // + mTPTrend.Delete(); + mSLTrend.Delete(); + return result; + } + } + + // + // ENTRY ... + string entrName = ToString(X_ENTRY) + "_" + nameMD5; + result = mEntryTrend.Create( + chart_id, + entrName, + window, + time1, + signal.entry, + time2, + signal.entry // + ); + if (!result) + { + // + mTPTrend.Delete(); + mSLTrend.Delete(); + mTargetTrend.Delete(); + return result; + } + + // + // Set Object Name ... + ObjName(name); + + // + return result; + } + + // + // Setter(s) ... + + // + // TP ... + + /** + * Set TP Width ... + * + * @param value: Integer ... + */ + void TPWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mTPTrend.Width(value); + } + + /** + * Set TP Color ... + * + * @param value: Color ... + */ + void TPColor(color value) + { + mTPTrend.Color(value); + } + + /** + * Set TP Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void TPStyle(ENUM_LINE_STYLE value) + { + mTPTrend.Style(value); + } + + // + // SL ... + + /** + * Set SL Width ... + * + * @param value: Integer ... + */ + void SLWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSLTrend.Width(value); + } + + /** + * Set SL Color ... + * + * @param value: Color ... + */ + void SLColor(color value) + { + mSLTrend.Color(value); + } + + /** + * Set SL Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void SLStyle(ENUM_LINE_STYLE value) + { + mSLTrend.Style(value); + } + + // + // TARGET ... + + /** + * Set Target Width ... + * + * @param value: Integer ... + */ + void TargetWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mTargetTrend.Width(value); + } + + /** + * Set Target Color ... + * + * @param value: Color ... + */ + void TargetColor(color value) + { + mTargetTrend.Color(value); + } + + /** + * Set Target Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void TargetStyle(ENUM_LINE_STYLE value) + { + mTargetTrend.Style(value); + } + + // + // ENTRY ... + + /** + * Set Entry Width ... + * + * @param value: Integer ... + */ + void EntryWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mEntryTrend.Width(value); + } + + /** + * Set Entry Color ... + * + * @param value: Color ... + */ + void EntryColor(color value) + { + mEntryTrend.Color(value); + } + + /** + * Set Entry Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void EntryStyle(ENUM_LINE_STYLE value) + { + mEntryTrend.Style(value); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_SIGNAL_OBJ; + } + + // + private: + // + + // + CChartObjectTrend mTPTrend; + CChartObjectTrend mSLTrend; + CChartObjectTrend mEntryTrend; + CChartObjectTrend mTargetTrend; +}; + +// +// XPVPivot Object ... +class XCXPVPivotObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XPVPivot &pivot, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = pivot.IsValid(); + if (!result) + { + return result; + } + + // + string name = pivot.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + result = mRect.Create( + chart_id, + name, + window, + pivot.from, + pivot.upper, + pivot.to, + pivot.lower // + ); + + // + if (result) + { + ObjName(name); + } + + // + string mTrendName = "MID_" + name; + double mid = pivot.CalculateMid(); + result = mTrend.Create( + chart_id, + mTrendName, + window, + pivot.from, + mid, + pivot.to, + mid // + ); + if (!result) + { + // + mRect.Delete(); + mRect.Detach(); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Pivot Width ... + * + * @param value: Integer ... + */ + void PivotWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + mTrend.Width(value); + } + + /** + * Set Pivot Color ... + * + * @param value: Color ... + */ + void PivotColor(color value) + { + // + mRect.Color(value); + mTrend.Color(value); + } + + /** + * Set Pivot Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void PivotStyle(ENUM_LINE_STYLE value) + { + // + mRect.Style(value); + mTrend.Style(value); + } + + /** + * Set Pivot Fill ... + * + * @param value: Boolean ... + */ + void PivotFill(bool value) + { + mRect.Fill(value); + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_XPVPIVOT_OBJ; + } + + // + private: + // + + // + // Props ... + CChartObjectRectangle mRect; + CChartObjectTrend mTrend; +}; + +class XCOHCLObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XOHCL &bar, + datetime to, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + IsValid(to); + if (!result) + { + return result; + } + + // + string name = bar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + // High Shadow ... + string hShadowName = ToString(X_BAR_H_SHW) + "_" + nameMD5; + + // + result = mHighShadowRect.Create( + chart_id, + hShadowName, + window, + bar.time, + bar.high, + to, + bar.GetUp() // + ); + if (!result) + { + return result; + } + + // + // Body ... + string bodyName = ToString(X_BAR_BDY) + "_" + nameMD5; + + // + result = mBodyRect.Create( + chart_id, + bodyName, + window, + bar.time, + bar.GetUp(), + to, + bar.GetDown() // + ); + if (!result) + { + // + mHighShadowRect.Delete(); + mHighShadowRect.Detach(); + return result; + } + + // + // Low Shadow ... + string lShadowName = ToString(X_BAR_L_SHW) + "_" + nameMD5; + + // + result = mLowShadowRect.Create( + chart_id, + lShadowName, + window, + bar.time, + bar.GetDown(), + to, + bar.low // + ); + if (!result) + { + // + mBodyRect.Delete(); + mBodyRect.Detach(); + mHighShadowRect.Delete(); + mHighShadowRect.Detach(); + return result; + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set High Shadow Width ... + * + * @param value: Integer ... + */ + void HighShadowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mHighShadowRect.Width(value); + } + + /** + * Set High Shadow Color ... + * + * @param value: Color ... + */ + void HighShadowColor(color value) + { + mHighShadowRect.Color(value); + } + + /** + * Set High Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void HighShadowStyle(ENUM_LINE_STYLE value) + { + mHighShadowRect.Style(value); + } + + /** + * Set High Shadow Fill ... + * + * @param value: Boolean ... + */ + void HighShadowFill(bool value) + { + mHighShadowRect.Fill(value); + } + + /** + * Set Body Width ... + * + * @param value: Integer ... + */ + void BodyWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBodyRect.Width(value); + } + + /** + * Set Body Color ... + * + * @param value: Color ... + */ + void BodyColor(color value) + { + mBodyRect.Color(value); + } + + /** + * Set Body Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BodyStyle(ENUM_LINE_STYLE value) + { + mBodyRect.Style(value); + } + + /** + * Set Body Fill ... + * + * @param value: Boolean ... + */ + void BodyFill(bool value) + { + mBodyRect.Fill(value); + } + + /** + * Set Low Shadow Width ... + * + * @param value: Integer ... + */ + void LowShadowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mLowShadowRect.Width(value); + } + + /** + * Set Low Shadow Color ... + * + * @param value: Color ... + */ + void LowShadowColor(color value) + { + mLowShadowRect.Color(value); + } + + /** + * Set Low Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void LowShadowStyle(ENUM_LINE_STYLE value) + { + mLowShadowRect.Style(value); + } + + /** + * Set Low Shadow Fill ... + * + * @param value: Boolean ... + */ + void LowShadowFill(bool value) + { + mLowShadowRect.Fill(value); + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_OHCL_OBJ; + } + + // + private: + // + + // + // Props ... + CChartObjectRectangle mHighShadowRect; + CChartObjectRectangle mBodyRect; + CChartObjectRectangle mLowShadowRect; +}; + +class XCBoxObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + string name, + double upper, + double lower, + datetime from, + datetime to, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + upper > 0 && + lower > 0 && + to > from && + IsValid(to) && + IsValid(name) && + IsValid(from) && + upper > lower; + if (!result) + { + return result; + } + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + result = mRect.Create( + chart_id, + name, + window, + from, + upper, + to, + lower // + ); + if (!result) + { + return result; + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Width ... + * + * @param value: Integer ... + */ + void BoxWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Color ... + * + * @param value: Color ... + */ + void BoxColor(color value) + { + mRect.Color(value); + } + + /** + * Set Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BoxStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Fill ... + * + * @param value: Boolean ... + */ + void BoxFill(bool value) + { + mRect.Fill(value); + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_BOX_OBJ; + } + + // + private: + // + + // + // Props ... + CChartObjectRectangle mRect; +}; + +// +// Zone Ticks ... + +// +// Specify How to Draws Specified Levels ... +struct XTickZoneLevelSpecs +{ + // + double percent; // Max Allowed Percent of Tick Zone ... + + // + // Label Info ... + color labelColor; + string labelFont; + int labelFontSize; + double labelAngel; + + // + // Zone Info ... + bool zoneFill; + int zoneWidth; + color zoneColor; + ENUM_LINE_STYLE zoneStyle; + + // + // Constructor ... + XTickZoneLevelSpecs() + { + Default(); + } + + // + // Tools ... + + /** + * Initialize Drawing Specs ... + * + * @param _percent: Double, Max Allowed Percent ... + * @param _labelColor: Color, Specified Label Color ... + * @param _zoneColoe: Color, Specified Zone Color ... + * @param _zoneFill: Boolean, Specified Fill Zone or not ... + * @param _zoneStyle: ENUM_LINE_STYLE member, Specified Zone Style ... + * @param _labelFontSize: Integer, Specified Label Font Size ... + * @param _labelFont: String, Specified Label Font Name ... + * @param _labelAngel: Double, Specified Label Angel ... + * + * @return ( bool ) + */ + bool Init( + double _percent, + color _labelColor = clrWhite, + color _zoneColor = clrWhite, + bool _zoneFill = false, + ENUM_LINE_STYLE _zoneStyle = STYLE_DOT, + int _zoneWidth = 1, + int _labelFontSize = 12, + string _labelFont = "Arial", + double _labelAngel = 0 // + ) + { + // + bool result = false; + + // + Default(); + + // + result = _percent > 0; + if (!result) + { + return result; + } + + // + percent = _percent; + labelColor = _labelColor; + zoneColor = _zoneColor; + zoneFill = _zoneFill; + zoneStyle = _zoneStyle; + + // + if (_zoneWidth > 0) + { + zoneWidth = _zoneWidth; + } + + // + if (_labelFontSize > 0) + { + labelFontSize = _labelFontSize; + } + + // + if (IsSpecifiedValid(_labelFont)) + { + labelFont = _labelFont; + } + + // + if (_labelAngel >= 0) + { + labelAngel = _labelAngel; + } + + // + result = IsValid(); + + // + return result; + } + + /** + * Set Default Properties ... + */ + void Default() + { + // + percent = 0; + + // + // Label ... + labelAngel = 0; + labelFontSize = 13; + labelFont = "Arial"; + labelColor = clrWhite; + + // + // Zone ... + zoneWidth = 1; + zoneFill = false; + zoneColor = clrWhite; + zoneStyle = STYLE_DOT; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + percent > 0 && + // + // Zone ... + zoneWidth > 0 && + // + // Label ... + labelFontSize > 0 && + IsSpecifiedValid(labelFont) + // + ; + + // + return result; + } + + // +}; + +class XCTickZoneObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param name: String, Specify Chart Object Identifier ... + * @param from: Datetime ... + * @param to: Datetime ... + * @param zone: XCTickZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + string name, + datetime from, + datetime to, + XCTickZone *zone, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + IsValid(name) && + zone.IsValid() && + IsValid(to) && + IsValid(from); + if (!result) + { + return result; + } + + // + double points = GetPoints(zone.symbol); + if (points <= 0) + { + points = 1; + } + double distance = 1 * points; + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + + // + string rectName = "TKZ_" + name; + result = mRect.Create( + chart_id, + rectName, + window, + from, + zone.high, + to, + zone.low // + ); + if (!result) + { + return result; + } + + // + int fromToDiff = ((int)to - (int)from); + datetime labelsDate = (datetime)((int)to - (fromToDiff / 5)); + + // + string lblName = "LBLT_" + name; + result = mTLabel.Create( + chart_id, + lblName, + window, + labelsDate, + zone.high - distance // + ); + if (!result) + { + return result; + } + + // + mTLabel.Description("T: " + ToString(zone.percent) + "%"); + + // + string lblVName = "LBLV_" + name; + result = mVLabel.Create( + chart_id, + lblVName, + window, + labelsDate, + zone.low + (2.5 * distance) // + ); + if (!result) + { + return result; + } + + // + mVLabel.Description("V: " + ToString(zone.volumePercent) + "%"); + + // + ObjName(name); + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_TICK_ZONE_OBJ; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Zone Width ... + * + * @param value: Integer ... + */ + void ZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRect.Width(value); + } + + /** + * Set Zone Color ... + * + * @param value: Color ... + */ + void ZoneColor(color value) + { + mRect.Color(value); + } + + /** + * Set Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ZoneStyle(ENUM_LINE_STYLE value) + { + mRect.Style(value); + } + + /** + * Set Zone Fill ... + * + * @param value: Boolean ... + */ + void ZoneFill(bool value) + { + mRect.Fill(value); + } + + /** + * Set Label Color ... + * + * @param value: Color ... + */ + void LabelColor(color value) + { + // + mTLabel.Color(value); + mVLabel.Color(value); + } + + /** + * Set Label Size ... + * + * @param value: Integer ... + */ + void LabelSize(int value) + { + // + mTLabel.FontSize(value); + mVLabel.FontSize(value); + } + + /** + * Set Label Font ... + * + * @param value: String ... + */ + void LabelFont(string value) + { + // + mTLabel.Font(value); + mVLabel.Font(value); + } + + /** + * Set Label Angle ... + * + * @param value: double ... + */ + void LabelAngle(double value) + { + // + mTLabel.Angle(value); + mVLabel.Angle(value); + } + + // + private: + // + // Props ... + CChartObjectRectangle mRect; + CChartObjectLabel mTLabel; + CChartObjectLabel mVLabel; + + // +}; +class XCTicksZoneObject : public XCBaseObject +{ + // + public: + // + + // + void ~XCTicksZoneObject() + { + mZones.Clear(); + } + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param zone: XCTicksZone instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XCTicksZone &zone, + XTickZoneLevelSpecs &specs[], + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string name = zone.GetTag(); + int levels = zone.Levels(); + result = levels > 0; + if (!result) + { + return result; + } + + // + for (int i = 0; i < levels; i++) + { + // + XCTickZone *iZone = zone.GetZone(i); + XCTickZoneObject *iObj; + iObj = new XCTickZoneObject(); + bool isCreated = iObj.Create( + chart_id, + window, + ToString(i) + "_" + name, + zone.From(), + zone.To(), + iZone, + prefix // + ); + if (!isCreated) + { + break; + } + + // + XTickZoneLevelSpecs iSpec; + bool hasSpecs = FindSpecs( + iZone, + iSpec, + specs // + ); + if (hasSpecs) + { + // + // Label ... + iObj.LabelFont(iSpec.labelFont); + iObj.LabelAngle(iSpec.labelAngel); + iObj.LabelColor(iSpec.labelColor); + iObj.LabelSize(iSpec.labelFontSize); + + // + // Zone ... + iObj.ZoneFill(iSpec.zoneFill); + iObj.ZoneColor(iSpec.zoneColor); + iObj.ZoneWidth(iSpec.zoneWidth); + iObj.ZoneStyle(iSpec.zoneStyle); + } + + // + mZones.Add(iObj); + } + + // + if (result) + { + ObjName(name); + } + else + { + mZones.Clear(); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_TICKS_ZONE_OBJ; + } + + // + // Getter(s) / Setter(s) ... + + // + // Actions ... + + /** + * Destroy Object ... + */ + void Destroy() + { + mZones.Clear(); + } + + /** + * Find Specified TickZone Drawing Specs ... + * + * @param zone: XCTickZone instance, reference to Search For it ... + * @param spec: XTickZoneLevelSpecs instance, reference to Result ... + * @param specs: XTickZoneLevelSpecs instance Collection for Search ... + * + * @return ( bool ) + */ + bool FindSpecs( + XCTickZone *zone, + XTickZoneLevelSpecs &spec, + XTickZoneLevelSpecs &specs[] // + ) + { + // + bool result = false; + + // + int count = ArraySize(specs); + result = + zone.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XTickZoneLevelSpecs iSpecs = specs[i]; + + // + bool isSpecValidForZone = + !spec.IsValid() + ? zone.percent <= iSpecs.percent + : zone.percent <= iSpecs.percent && + spec.percent > iSpecs.percent; + if (isSpecValidForZone) + { + spec = iSpecs; + } + } + + // + result = spec.IsValid(); + + // + return result; + } + + // + private: + // + // Props ... + CArrayObj mZones; + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-expert.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-expert.class.mq5 new file mode 100644 index 0000000..7c05c61 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-expert.class.mq5 @@ -0,0 +1,997 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCBaseExpert +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Helpers/x-saherelm.xcc.helper.mq5" +#include "../Helpers/x-saherelm.xct.helper.mq5" + +// +// Definitions ... +string XCBaseExpertToken = "XCBaseEA"; + +// +// Inputs ... + +// +// Implementations ... +class XCBaseExpert : public XCBaseAlert +{ + // + public: + // + + // + XCTrade *mTrader; // Trader of Expert Adviser ... + + // + // Constructur(s) ... + void XCBaseExpert() + { + } + + // + // Deconstructor ... + void ~XCBaseExpert() + { + // + delete mTrader; + } + + // + // Getter(s) / Setter(s) ... + + // + // Common ... + + /** + * Get Magic Number ... + * + * @return ( long ) + */ + long MagicNumber() + { + return mMagicNumber; + } + + /** + * Set Magic Number ... + * + * @param value: Long ... + */ + void MagicNumber(long value) + { + // + mMagicNumber = value; + ReConfigure(); + } + + /** + * Get Slippage ... + * + * @return ( int ) + */ + int Slippage() + { + return mSlippage; + } + + /** + * Set Slippage ... + * + * @param value: Integer ... + */ + void Slippage(int value) + { + // + mSlippage = value; + ReConfigure(); + } + + /** + * Get Tag Prefix ... + * + * @return ( string ) + */ + string TagPrefix() + { + return mTagPrefix; + } + + /** + * Set Tag Prefix ... + * + * @param value: String ... + */ + void TagPrefix(string value) + { + // + mTagPrefix = value; + ReConfigure(); + } + + // + // Symbol ... + + /** + * Get Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Set Period ... + * + * @param value: ENUM_TIMEFRAMES member ... + */ + void SetPeriod(ENUM_TIMEFRAMES value) + { + // + mPeriod = value; + ReConfigure(); + } + + /** + * Get Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Set Symbol ... + * + * @param value: String ... + */ + void SetSymbol(string value) + { + // + mSymbol = value; + ReConfigure(); + } + + /** + * Get Multi Symbol is Enable or Not ... + * + * @return ( bool ) + */ + bool MultiSymbol() + { + return mMultiSymbol; + } + + /** + * Set Multi Symbol is Enable or Not ... + * + * @param value: Boolean ... + */ + void MultiSymbol(bool value) + { + // + mMultiSymbol = value; + ReConfigure(); + } + + /** + * Get Multi Provided Symbols ... + * + * @return ( string ) + */ + string Symbols() + { + return mSymbols; + } + + /** + * Set Multi Provided Symbols ... + * + * @param value: String ... + */ + void Symbols(string value) + { + // + mSymbols = value; + ReConfigure(); + } + + // + // Signalling ... + + /** + * Get Force Disable Signalling ... + * + * @return ( bool ) + */ + bool Disabled() + { + return mDisabled; + } + + /** + * Set Force Disable Signalling ... + * + * @param value: Boolean ... + */ + void Disabled(bool value) + { + // + mDisabled = value; + ReConfigure(); + } + + /** + * Get Allow Long Signals ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Allow Long Signals ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + // + mAllowLong = value; + ReConfigure(); + } + + /** + * Get Allow Short Signalling ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Allow Short Signalling ... + * + * @param value: Boolean ... + */ + void AllowShort(bool value) + { + // + mAllowShort = value; + ReConfigure(); + } + + // + // Reports ... + + /** + * Get Report New Month State ... + * + * @return ( bool ) + */ + bool ReportNewMonths() + { + return mReportNewMonths; + } + + /** + * Set Report New Month State ... + * + * @param value: Boolean ... + */ + void ReportNewMonths(bool value) + { + // + mReportNewMonths = value; + ReConfigure(); + } + + /** + * Get Report New Weeks State ... + * + * @return ( bool ) + */ + bool ReportNewWeeks() + { + return mReportNewWeeks; + } + + /** + * Set Report New Weeks State ... + * + * @param value: Boolean ... + */ + void ReportNewWeeks(bool value) + { + // + mReportNewWeeks = value; + ReConfigure(); + } + + /** + * Get Report New Days State ... + * + * @return ( bool ) + */ + bool ReportNewDays() + { + return mReportNewDays; + } + + /** + * Set Report New Days State ... + * + * @param value: Boolean ... + */ + void ReportNewDays(bool value) + { + // + mReportNewDays = value; + ReConfigure(); + } + + /** + * Get Report New Hours State ... + * + * @return ( bool ) + */ + bool ReportNewHours() + { + return mReportNewHours; + } + + /** + * Set Report New Hours State ... + * + * @param value: Boolean ... + */ + void ReportNewHours(bool value) + { + // + mReportNewHours = value; + ReConfigure(); + } + + // + // Actions ... + + /** + * Handle Expert OnInit Event ... + * + * @return ( bool ) + */ + bool HandleOnInit() + { + // + bool result = false; + + // + string message = ""; + + // + // Validate Input ... + result = ValidateInputs(); + if (!result) + { + // + message = "Invalid Inputs ...."; + + // + Alert(message); + } + + // + // Initial All Requirements ... + result = InitEA(); + if (!result) + { + return result; + } + + // + // Initial All GUI Requirements ... + result = InitGUI(); + if (!result) + { + return result; + } + + // + message = "Initialized Successfully ..."; + Alert(message); + + // + return result; + } + + /** + * Handle Expert OnDeInit Event ... + */ + void HandleOnDeInit() + { + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + Alert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); + } + + /** + * Handle Expert OnTick Event ... + */ + void HandleOnTick() + { + // + UpdateGUI(); + HandleReportTime(); + HandleStrategiesOnTick(); + HandleStrategiesGuard(); + } + + /** + * Handle Expert OnTrade Event ... + */ + void HandleOnTrade() + { + mTrader.HandleOnTrade(); + } + + /** + * Handle Expert OnTimer Event ... + */ + void HandleOnTimer() + { + } + + /** + * Handle Expert OnChart Event ... + */ + void HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Virtual Actions ... + + /** + * Apply Default Configurations ... + */ + virtual void DefaultConfigure() + { + // + // Commons ... + Slippage(10); + TagPrefix(""); + MagicNumber(1694056); + + // + // Symbol ... + SetSymbol(_Symbol); + SetPeriod(_Period); + MultiSymbol(false); + Symbols("EURUSDb,GBPUSDb,USDJPYb,USDCHFb,DowJones30,XAUUSDb"); + + // + // Signalling ... + Disabled(false); + AllowLong(true); + AllowShort(true); + + // + string tag = GetTag(); + + // + // Alert ... + SetAlertPrefix(tag); + SetAlertLogAlerts(true); + SetAlertPushAlerts(true); + SetAlertMailAlerts(false); + SetAlertEnableAlerts(true); + SetAlertTerminalAlerts(false); + + // + // Reports ... + ReportNewDays(true); + ReportNewWeeks(false); + ReportNewHours(false); + ReportNewMonths(false); + } + + /** + * Vaslidate Inputs ... + * + * @return ( virtual bool ) + */ + virtual bool ValidateInputs() + { + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + mSlippage > 0 && + mMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + errMessage = " Errors: \n" + errMessage; + Alert(errMessage); + } + + // + return result; + } + + // + // Initializers and DeInitializers ... + + /** + * Initial EA Requirements ... + * + * @return ( virtual bool ) + */ + virtual bool InitEA() + { + // + bool result = false; + + // + // Initialize Indicator Helpers ... + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); // Default Configurations ... + mCTHelper = new XCXCTHelper(); + result = mCTHelper.Init( + _Symbol, + _Period, + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); // Default Configurations ... + mCCHelper = new XCXCCHelper(); + result = mCCHelper.Init( + _Symbol, + _Period, + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Create Trader Instance and Configure it ... + mTrader = new XCTrade( + mSlippage, + mMagicNumber // + ); + + // + return result; + } + + /** + * Destroy Initialized Requirements ... + */ + virtual void DestroyEA() + { + // + delete mTrader; + delete mCTHelper; + delete mCCHelper; + } + + /** + * GUI Initialize if required ... + * + * @return ( virtual bool ) + */ + virtual bool InitGUI() + { + // + bool result = false; + + // + result = true; + + // + return result; + } + + /** + * Update All GUI Contents ... + */ + virtual void UpdateGUI() + { + } + + /** + * Destroy all Initialized GUi Elements ... + */ + virtual void DestroyGUI() + { + } + + // + // Event Handlers ... + + /** + * Calls When a Position's SL Triggered ... + * + * @param deal: XDeal instance ... + */ + virtual void HandleOnStopLossTriggered(const XDeal &deal) + { + HandleReportBalance(); + } + + /** + * Calls When a Position's TP Triggered ... + * + * @param deal: XDeal instance ... + */ + virtual void HandleOnTakeProfitTriggered(const XDeal &deal) + { + HandleReportBalance(); + } + + /** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ + virtual void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + HandleReportBalance(); + } + + /** + * Handle Position Modified ... + * + * @param ticket: ULONG ... + * @param profit: Double ... + * @param comment: String ... + */ + virtual void HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Position Partially Closed ... + * + * @param ticket: ULONG ... + * @param profit: Double ... + * @param comment: String ... + */ + virtual void HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Deals Changed ... + * + * @param count: Integer, Number of Changes ... + */ + virtual void HandleOnDealsChanged(int count) + { + } + + /** + * Handle Orders Changed ... + * + * @param count: Integer, Number of Changes ... + */ + virtual void HandleOnOrdersChanged(int count) + { + } + + /** + * Handle Positions Changed ... + * + * @param count: Integer, Number of Changes ... + */ + virtual void HandleOnPositionsChanged(int count) + { + } + + /** + * Do All Signalling Processing Here ... + */ + virtual void HandleStrategiesOnTick() + { + } + + /** + * Check Strategies for Guards and then Apply Them ... + */ + virtual void HandleStrategiesGuard() + { + } + + // + // Time Handlers ... + + virtual void HandleOnNewMonth() + { + } + + virtual void HandleOnNewWeek() + { + } + + virtual void HandleOnNewDay() + { + } + + virtual void HandleOnNewHour() + { + } + + virtual void ReConfigure() + { + } + + /** + * Generate Identifier Tag ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + // + string result = NULL; + + // + string tagPrefix = TagPrefix(); + if (IsValid(tagPrefix)) + { + result = tagPrefix; + } + else + { + result = ""; + } + + // + result = + XCBaseExpertToken + result; + + // + return result; + } + + // + protected: + // + + // + // Props ... + + // + XTimeTracker mTimeTracker; // Time Tracker for Providing Reports ... + XCXCTHelper *mCTHelper; // Bar Timer Indicator Helper class ... + XCXCCHelper *mCCHelper; // Chart Styler Indicator Helper Class ... + + // + // Actions ... + + /** + * Report Account Balance ... + */ + void HandleReportBalance() + { + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(mTrader.mAccount.GetBalance()); + Log(msg); + } + + /** + * Time Reporting based on Inputs ... + */ + void HandleReportTime() + { + // + // Monthly Report .... + if (mTimeTracker.IsNewMonth()) + { + // + HandleOnNewMonth(); + + // + if (mReportNewMonths) + { + // + string msg = "New Month ..."; + + // + Alert(msg); + } + } + + // + // Weekly Report .... + if (mTimeTracker.IsNewWeek()) + { + // + HandleOnNewWeek(); + + // + if (mReportNewWeeks) + { + // + string msg = "New Week ..."; + + // + Alert(msg); + } + } + + // + // Daily Report .... + if (mTimeTracker.IsNewDay()) + { + // + HandleOnNewDay(); + + // + if (mReportNewDays) + { + // + string msg = "New Day ..."; + + // + Alert(msg); + } + } + + // + // Hourly Report .... + if (mTimeTracker.IsNewHour()) + { + // + HandleOnNewHour(); + + // + if (mReportNewHours) + { + // + string msg = "New Hour ..."; + + // + Alert(msg); + } + } + } + + // + private: + // + + // + // Props ... + + // + // Common ... + long mMagicNumber; // Magic Number ... + int mSlippage; // Slippage ... + string mTagPrefix; // Tag Prefix ... + + // + // Symbol ... + ENUM_TIMEFRAMES mPeriod; // Period ... + string mSymbol; // Symbol ... + bool mMultiSymbol; // Multi Symbol is Enable or Not ... + string mSymbols; // Multi Provided Symbols ... + + // + // Signalling ... + bool mDisabled; // Force Disable Signalling ... + bool mAllowLong; // Allow Long Signals ... + bool mAllowShort; // Allow Short Signals ... + + // + // Reports ... + bool mReportNewMonths; // Report New Month ... + bool mReportNewWeeks; // Report New Weeks ... + bool mReportNewDays; // Report New Days ... + bool mReportNewHours; // Report New Hours ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-helper.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-helper.class.mq5 new file mode 100644 index 0000000..8aa63e8 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-helper.class.mq5 @@ -0,0 +1,148 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseHelper +// Description: provides all Base Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Definitions ... + +// +// a Class for Handle base requirements ... +// for indicators ... +class XCBaseHelper : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + void XCBaseHelper( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period // Trading Time Frame + ) + { + // + mSymbol = symbol; + mPeriod = period; + } + + // + // Deconstructor ... + void ~XCBaseHelper() + { + // + IndicatorRelease(mHandler); + } + + // + // Setter(s) / Getter(s) ... + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Retrieve Bars ... + int CountBars() + { + // + int result = + Bars( + mSymbol, + mPeriod + // + ); + + // + return result; + } + + // + // Retrieve Indicator Calculated Bars ... + int CountCalculatedBars() + { + return BarsCalculated(mHandler); + } + + // + // Generate Tag ... + virtual string GetTag() + { + // + string result = NULL; + + // + result = + // + GetToken() + + "[" + + GetSymbol() + "|" + + ToString(GetPeriod()) + + "]" + // + ; + + // + return result; + } + + // + // Functions ... + + // + // Protected ... + protected: + // + // Props ... + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // Indicator Handler ... + int mHandler; + + // + // Private ... + private: + // +}; + +// +// Tools .... \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-http.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-http.class.mq5 new file mode 100644 index 0000000..631532f --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-http.class.mq5 @@ -0,0 +1,373 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCHttp +// Description: provides all HTTP requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Definitions ... + +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; + +// +// Imports ... + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// a Class for Manage Account ... +class XCHttp : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + void XCHttp() + { + XCHttp("", 10000); + } + void XCHttp( + string path, // Base Folder to Store Data + int timeout // base timeout for Requests + ) + { + // + Path(path); + Timeout(timeout); + } + + // + // Deconstructor ... + void ~XCHttp() + { + } + + // + // Properties Getter(s) / Setter(s) ... + + // + // Path ... + void Path(string value) + { + // + mPath = value; + + // + if (!IsValid(mPath)) + { + mPath = GetTag(); + } + } + + string Path() + { + return mPath; + } + + // + // Timeout ... + void Timeout(int value) + { + mTimeout = value; + } + + // + int Timeout() + { + return mTimeout; + } + + // + // Error ... + int Error() + { + return mError; + } + + // + // Response ... + string Response() + { + return mResponse; + } + + // + // Overrides ... + string GetTag() override + { + return GetSpecificToken(this); + } + + // + // Tools ... + + // + // Send Global Request ... + int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) + { + return result; + } + + // + // Reset State ... + ResetState(); + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders); + + // + if (result < 0) + { + mError = GetLastError(); + } + else + { + mResponse = CharArrayToString(response); + } + + // + return result; + } + + // + // Get Request ... + int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Post Request ... + int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Handle Download Specific URL Content to Specific Path and File Name ... + bool Download( + string url, // the URL address which going to download + string fileName // Specify Destination file name to Store Response + ) + { + // + bool result = false; + + // + string filePath = GetFilePath(fileName); + string cookie = NULL; + string referer = NULL; + int timeout = Timeout(); + + // + char payload[]; + string headers; + char response[]; + string responseHeaders; + + // + // Send Request ... + int requestResult = GetRequest( + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + // Define File Handler ... + int mFileHandler = FileOpen( + filePath, + FILE_WRITE | FILE_BIN); + if (mFileHandler == INVALID_HANDLE) + { + // + mError = GetLastError(); + return result; + } + + // + // Write Response to File ... + uint writed = FileWriteArray( + mFileHandler, + response, + 0, + ArraySize(response)); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + result = writed > 0; + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... + protected: + // + // Destintion Folder Path ... + string mPath; + + // + // WEB Request Timeout Value ... + int mTimeout; + + // + // WEB Request's Response ... + string mResponse; + + // + // Error Value ... + int mError; + + // + // Private ... + private: + // + // Reset Errors State ... + void ResetState() + { + // + // Reset Errors ... + mError = -1; + mResponse = ""; + ResetLastError(); + } + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } +}; + +// +// Tools ... + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-md5.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-md5.class.mq5 new file mode 100644 index 0000000..e5cc201 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-md5.class.mq5 @@ -0,0 +1,445 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCMD5 +// Description: Provides MD5 Hashing Requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Definitions ... +// + +// +static uchar _md5_PADDING[64] = + { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// +#define _md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define _md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define _md5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _md5_I(x, y, z) ((y) ^ ((x) | (~z))) +#define _md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +// +#define _md5_FF(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_F((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_GG(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_G((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_HH(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_H((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_II(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_I((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_INIT_STATE_0 0x67452301 +#define _md5_INIT_STATE_1 0xefcdab89 +#define _md5_INIT_STATE_2 0x98badcfe +#define _md5_INIT_STATE_3 0x10325476 + +// +#define _md5_S11 7 +#define _md5_S12 12 +#define _md5_S13 17 +#define _md5_S14 22 + +// +#define _md5_S21 5 +#define _md5_S22 9 +#define _md5_S23 14 +#define _md5_S24 20 + +// +#define _md5_S31 4 +#define _md5_S32 11 +#define _md5_S33 16 +#define _md5_S34 23 + +// +#define _md5_S41 6 +#define _md5_S42 10 +#define _md5_S43 15 +#define _md5_S44 21 + +// +// END Definitions ... +// + +// +// XCMD5 a library for Hashing ... +class XCMD5 +{ + // + // Public Provides ... + public: + // + // Protected Provides ... + + // + // Constructor ... + XCMD5(void) + { + } + + // + // Deconstructor ... + ~XCMD5(void) + { + } + + // + // Hash Specified Char Array ... + string Hash( + uchar &mSource[], // Specify Char Array to Hash + int mLength = 0 // Specify Length of Char Array which required to hash + ) + { + // + string result = ""; + + // + int sourceCount = ArraySize(mSource); + + // + // Validate Args ... + if ( + sourceCount <= 0 || + (sourceCount > 0 && mLength > sourceCount)) + { + return result; + } + + // + // Normalize Args ... + if (mLength == 0) + { + mLength = sourceCount; + } + + // + // Init MD5 ... + MD5Init(); + + // + // Update Buffer ... + MD5Update(mSource, mLength); + + // + // Calculate Result ... + result = MD5Final(); + + // + return result; + } + + // + // Hash Specified String ... + string Hash( + string mSource // Specified String + ) + { + // + string result = ""; + + // + // Converts String to Char Array ... + uchar bytes[]; + StringToCharArray( + mSource, + bytes, + 0, + StringLen(mSource)); + + // + result = Hash( + bytes, + ArraySize(bytes)); + + // + return result; + } + + protected: + // + // Private Provides ... + private: + // + uint m_lMD5[4]; + uint m_nCount[2]; + uchar m_lpszBuffer[64]; + + // + // Convert Byte to DWord ... + void ByteToDWord(int &out[], uint &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + out[i] = (int)in[j] | (int)in[j + 1] << 8 | (int)in[j + 2] << 16 | (int)in[j + 3] << 24; + } + } + + // + // Convert DWord to Byte ... + void DWordToByte(uchar &out[], int &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + // + out[j] = (uchar)(in[i] & 0xff); + out[j + 1] = (uchar)((in[i] >> 8) & 0xff); + out[j + 2] = (uchar)((in[i] >> 16) & 0xff); + out[j + 3] = (uchar)((in[i] >> 24) & 0xff); + } + } + + // + // Init MD5 Array ... + void MD5Init() + { + // + ArrayInitialize(m_lpszBuffer, 64); + + // + m_nCount[0] = m_nCount[1] = 0; + m_lMD5[0] = _md5_INIT_STATE_0; + m_lMD5[1] = _md5_INIT_STATE_1; + m_lMD5[2] = _md5_INIT_STATE_2; + m_lMD5[3] = _md5_INIT_STATE_3; + } + + // + // Update MD5 ... + void MD5Update(uchar &inBuf[], uint inLen) + { + // + int i, ii; + int mdi; + + // + uint in[16]; + int i0 = 0; + + // + mdi = (int)((m_nCount[0] >> 3) & 0x3F); + + // + if ((m_nCount[0] + ((uint)inLen << 3)) < m_nCount[0]) + { + m_nCount[1]++; + } + + // + m_nCount[0] += ((uint)inLen << 3); + m_nCount[1] += ((uint)inLen >> 29); + + // + while ((inLen--) > 0) + { + // + m_lpszBuffer[mdi++] = inBuf[i0++]; + if (mdi == 0x40) + { + // + for (i = 0, ii = 0; i < 16; i++, ii += 4) + { + in[i] = (((uint)m_lpszBuffer[ii + 3]) << 24) | (((uint)m_lpszBuffer[ii + 2]) << 16) | (((uint)m_lpszBuffer[ii + 1]) << 8) | ((uint)m_lpszBuffer[ii]); + } + + // + Transform(m_lMD5, in); + + // + mdi = 0; + } + } + } + + // + // Finalize an MD5 Expression ... + string MD5Final() + { + // + uchar bits[8]; + int nIndex; + uint nPadLen; + const int nMD5Size = 16; + uchar lpszMD5[16]; + string temp; + string out = ""; + int i; + + // + DWordToByte(bits, m_nCount, 8); + nIndex = (int)((m_nCount[0] >> 3) & 0x3f); + nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); + MD5Update(_md5_PADDING, nPadLen); + MD5Update(bits, 8); + DWordToByte(lpszMD5, m_lMD5, nMD5Size); + + // + for (i = 0; i < nMD5Size; i++) + { + // + if (lpszMD5[i] == 0) + { + temp = "00"; + } + else if (lpszMD5[i] <= 15) + { + temp = StringFormat("0%x", lpszMD5[i]); + } + else + { + temp = StringFormat("%x", lpszMD5[i]); + } + + // + out += temp; + } + + // + lpszMD5[0] = '\0'; + + // + return (out); + } + + // + // Transform Buffers ... + void Transform(uint &buf[], uint &in[]) + { + // + uint a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // + _md5_FF(a, b, c, d, in[0], _md5_S11, 0xD76AA478); + _md5_FF(d, a, b, c, in[1], _md5_S12, 0xE8C7B756); + _md5_FF(c, d, a, b, in[2], _md5_S13, 0x242070DB); + _md5_FF(b, c, d, a, in[3], _md5_S14, 0xC1BDCEEE); + _md5_FF(a, b, c, d, in[4], _md5_S11, 0xF57C0FAF); + _md5_FF(d, a, b, c, in[5], _md5_S12, 0x4787C62A); + _md5_FF(c, d, a, b, in[6], _md5_S13, 0xA8304613); + _md5_FF(b, c, d, a, in[7], _md5_S14, 0xFD469501); + _md5_FF(a, b, c, d, in[8], _md5_S11, 0x698098D8); + _md5_FF(d, a, b, c, in[9], _md5_S12, 0x8B44F7AF); + _md5_FF(c, d, a, b, in[10], _md5_S13, 0xFFFF5BB1); + _md5_FF(b, c, d, a, in[11], _md5_S14, 0x895CD7BE); + _md5_FF(a, b, c, d, in[12], _md5_S11, 0x6B901122); + _md5_FF(d, a, b, c, in[13], _md5_S12, 0xFD987193); + _md5_FF(c, d, a, b, in[14], _md5_S13, 0xA679438E); + _md5_FF(b, c, d, a, in[15], _md5_S14, 0x49B40821); + + // + _md5_GG(a, b, c, d, in[1], _md5_S21, 0xF61E2562); + _md5_GG(d, a, b, c, in[6], _md5_S22, 0xC040B340); + _md5_GG(c, d, a, b, in[11], _md5_S23, 0x265E5A51); + _md5_GG(b, c, d, a, in[0], _md5_S24, 0xE9B6C7AA); + _md5_GG(a, b, c, d, in[5], _md5_S21, 0xD62F105D); + _md5_GG(d, a, b, c, in[10], _md5_S22, 0x02441453); + _md5_GG(c, d, a, b, in[15], _md5_S23, 0xD8A1E681); + _md5_GG(b, c, d, a, in[4], _md5_S24, 0xE7D3FBC8); + _md5_GG(a, b, c, d, in[9], _md5_S21, 0x21E1CDE6); + _md5_GG(d, a, b, c, in[14], _md5_S22, 0xC33707D6); + _md5_GG(c, d, a, b, in[3], _md5_S23, 0xF4D50D87); + _md5_GG(b, c, d, a, in[8], _md5_S24, 0x455A14ED); + _md5_GG(a, b, c, d, in[13], _md5_S21, 0xA9E3E905); + _md5_GG(d, a, b, c, in[2], _md5_S22, 0xFCEFA3F8); + _md5_GG(c, d, a, b, in[7], _md5_S23, 0x676F02D9); + _md5_GG(b, c, d, a, in[12], _md5_S24, 0x8D2A4C8A); + + // + _md5_HH(a, b, c, d, in[5], _md5_S31, 0xFFFA3942); + _md5_HH(d, a, b, c, in[8], _md5_S32, 0x8771F681); + _md5_HH(c, d, a, b, in[11], _md5_S33, 0x6D9D6122); + _md5_HH(b, c, d, a, in[14], _md5_S34, 0xFDE5380C); + _md5_HH(a, b, c, d, in[1], _md5_S31, 0xA4BEEA44); + _md5_HH(d, a, b, c, in[4], _md5_S32, 0x4BDECFA9); + _md5_HH(c, d, a, b, in[7], _md5_S33, 0xF6BB4B60); + _md5_HH(b, c, d, a, in[10], _md5_S34, 0xBEBFBC70); + _md5_HH(a, b, c, d, in[13], _md5_S31, 0x289B7EC6); + _md5_HH(d, a, b, c, in[0], _md5_S32, 0xEAA127FA); + _md5_HH(c, d, a, b, in[3], _md5_S33, 0xD4EF3085); + _md5_HH(b, c, d, a, in[6], _md5_S34, 0x04881D05); + _md5_HH(a, b, c, d, in[9], _md5_S31, 0xD9D4D039); + _md5_HH(d, a, b, c, in[12], _md5_S32, 0xE6DB99E5); + _md5_HH(c, d, a, b, in[15], _md5_S33, 0x1FA27CF8); + _md5_HH(b, c, d, a, in[2], _md5_S34, 0xC4AC5665); + + // + _md5_II(a, b, c, d, in[0], _md5_S41, 0xF4292244); + _md5_II(d, a, b, c, in[7], _md5_S42, 0x432AFF97); + _md5_II(c, d, a, b, in[14], _md5_S43, 0xAB9423A7); + _md5_II(b, c, d, a, in[5], _md5_S44, 0xFC93A039); + _md5_II(a, b, c, d, in[12], _md5_S41, 0x655B59C3); + _md5_II(d, a, b, c, in[3], _md5_S42, 0x8F0CCC92); + _md5_II(c, d, a, b, in[10], _md5_S43, 0xFFEFF47D); + _md5_II(b, c, d, a, in[1], _md5_S44, 0x85845DD1); + _md5_II(a, b, c, d, in[8], _md5_S41, 0x6FA87E4F); + _md5_II(d, a, b, c, in[15], _md5_S42, 0xFE2CE6E0); + _md5_II(c, d, a, b, in[6], _md5_S43, 0xA3014314); + _md5_II(b, c, d, a, in[13], _md5_S44, 0x4E0811A1); + _md5_II(a, b, c, d, in[4], _md5_S41, 0xF7537E82); + _md5_II(d, a, b, c, in[11], _md5_S42, 0xBD3AF235); + _md5_II(c, d, a, b, in[2], _md5_S43, 0x2AD7D2BB); + _md5_II(b, c, d, a, in[9], _md5_S44, 0xEB86D391); + + // + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; + } +}; diff --git a/BKPS/14031106/Classes/x-saherelm.x-poi.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-poi.class.mq5 new file mode 100644 index 0000000..4e89e82 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-poi.class.mq5 @@ -0,0 +1,4234 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOI +// Description: Provides Point of Interests ... +// - Swing Highs; +// - Swing Lows; +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +#include + +// +// Implementation ... + +// +// POI Detector Class ... +class XCPOIDetector : public XCBaseAlert +{ + // + public: + // + XCPOIDrawer *mDrawer; + + // + // Constructors ... + /** + * Create an Instance ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + */ + void XCPOIDetector( + string symbol, + ENUM_TIMEFRAMES period // + ) + { + // + // Attach Required Properties ... + mSymbol = symbol; + mPeriod = period; + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + mSymbol, + mPeriod // + ); + + // + // Create Default Drawer Instance ... + mDrawer = new XCPOIDrawer(); + + // + // Apply Default Configurations ... + Default(); + } + + // + // Deconstructor ... + void ~XCPOIDetector() + { + Destroy(); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Retrieve Detector Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve Detector Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Get Max Number of POIs which holds ... + * + * @return ( int ) + */ + int MaxNumberOfPOIs() + { + return mMaxNumberOfPOIs; + } + + /** + * Set Max Number of POIs which holds ... + * 0 => Infinity ... + * + * @param value: Integer ... + */ + void MaxNumberOfPOIs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxNumberOfPOIs = value; + } + + /** + * Get Number of POI(s) which must Find at Initializations ... + * + * @return ( int ) + */ + int MaxNumberOfRequiredPOIs() + { + return mMaxNumberOfRequiredPOIs; + } + + /** + * Set Number of POI(s) which must Find at Initializations ... + * 2 is Default ... + * + * @param value: Integer ... + */ + void MaxNumberOfRequiredPOIs(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mMaxNumberOfRequiredPOIs = value; + } + + /** + * Check Is Locked or not ... + * + * @return ( bool ) + */ + bool IsLocked() + { + return mLock; + } + + // + // POI(s) Configs ... + + // + // Swings ... + + /** + * Get Swing Verification Range Length ... + * + * @return ( int ) + */ + int SwingRange() + { + return mSwingRange; + } + + /** + * Set Swing Verification Range Length ... + * + * @param value: Integer ... + */ + void SwingRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSwingRange = value; + } + + // + // Momentum Bars ... + + /** + * Get Momentum Bars must Extends Range ... + * + * @return ( int ) + */ + int MomentumBarExtendRange() + { + return mMomentumBarExtendRange; + } + + /** + * Set Momentum Bars must Extends Range ... + * + * @param value: Integer ... + */ + void MomentumBarExtendRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMomentumBarExtendRange = value; + } + + /** + * Get Momentum Bars Body Percent ... + * + * @return ( double ) + */ + double MomentumBarBodyPercent() + { + return mMomentumBarBodyPercent; + } + + /** + * Set Momentum Bars Body Percent ... + * + * @param value: Double ... + */ + void MomentumBarBodyPercent(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + mMomentumBarBodyPercent = value; + } + + // + // Rejection Bars ... + + /** + * Get Rejection Bars must Extends Range ... + * + * @return ( int ) + */ + int RejectionBarExtendRange() + { + return mRejectionBarExtendRange; + } + + /** + * Set Rejection Bars must Extends Range ... + * + * @param value: Integer ... + */ + void RejectionBarExtendRange(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRejectionBarExtendRange = value; + } + + /** + * Get Rejection Bars Shadow Percent ... + * + * @return ( double ) + */ + double RejectionBarShadowPercent() + { + return mRejectionBarShadowPercent; + } + + /** + * Set Rejection Bars Shadow Percent ... + * + * @param value: Double ... + */ + void RejectionBarShadowPercent(double value) + { + // + if (value < 50) + { + value = 50; + } + + // + mRejectionBarShadowPercent = value; + } + + // + // Support and Resistance Zone(s) ... + + /** + * Get Support and Resistance Range for Verification ... + * + * @return ( int ) + */ + int SupportAndResistanceRange() + { + return mSupportAndResistanceRange; + } + + /** + * Set Support and Resistance Range for Verification ... + * + * @param value: Integer ... + */ + void SupportAndResistanceRange(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mSupportAndResistanceRange = value; + } + + // + // Supply and Demand Zone(s) ... + + /** + * Get Supply and Demand Range Verifications ... + * + * @return ( int ) + */ + int SupplyAndDemandRange() + { + return mSupplyAndDemandRange; + } + + /** + * Set Supply and Demand Range Verifications ... + * + * @param value: Integer ... + */ + void SupplyAndDemandRange(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mSupplyAndDemandRange = value; + } + + // + // Order Blocks ... + + /** + * Get Order Blocks Detection Bars ... + * + * @return ( int ) + */ + int OrderBlocksSameBars() + { + return mOrderBlocksSameBars; + } + + /** + * Set Order Blocks Detection Bars ... + * + * @param value: Argument 1 + */ + void OrderBlocksSameBars(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mOrderBlocksSameBars = value; + } + + // + // Fair Value Gaps ... + + /** + * Get Fair Value Gaps Detection Same Bars ... + * + * @return ( int ) + */ + int FairValueGapsSameBars() + { + return mFairValueGapsSameBars; + } + + /** + * Set Fair Value Gaps Detection Same Bars ... + * + * @param value: Integer ... + */ + void FairValueGapsSameBars(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mFairValueGapsSameBars = value; + } + + // + // Ticks Zone ... + + /** + * Get Ticks Range Levels ... + * + * @return ( int ) + */ + int TicksRangeZoneLevel() + { + return mTicksRangeZoneLevel; + } + + /** + * Set Ticks Range Levels ... + * + * @param value: Integer ... + */ + void TicksRangeZoneLevel(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mTicksRangeZoneLevel = value; + } + + /** + * Get Ticks Range Zone Loopback Period ... + * + * @return ( int ) + */ + int TicksRangeZoneRange() + { + return mTicksRangeZoneRange; + } + + /** + * Set Ticks Range Zone Loopback Period ... + * + * @param value: Integer ... + */ + void TicksRangeZoneRange(int value) + { + // + if (value < 7) + { + value = 7; + } + + // + mTicksRangeZoneRange = value; + } + + // + // Actions ... + + /** + * Initialize POI Detector ... + */ + void Init() + { + DetectRequiredPOIs(); + } + + /** + * Update POI(s) ... + * + * @param state: an Array Refrence of ENUM_XPOI_EVENTS members ... + */ + int Update( + ENUM_XPOI_EVENTS &state[] // + ) + { + // + int result = 0; + + // + Clean(state); + + // + // Check Bar Tracker if Waits ... + if (!mBarTracker.IsNewBar()) + { + return result; + } + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + datetime cTime = TimeCurrent(); + + // + XOHCL zBar; + bool isInited = zBar.Init( + symbol, + period, + zIndex // + ); + if (!isInited) + { + return result; + } + + // + XOHCL cBar; + isInited = cBar.Init( + symbol, + period, + cIndex // + ); + if (!isInited) + { + return result; + } + + // + // POI Detecting ... + bool isDetected = false; + + // + // Swings ... + int swingRange = SwingRange(); + if (swingRange > 0) + { + // + XOHCL swingBar; + isInited = swingBar.Init( + symbol, + period, + zIndex + swingRange // + ); + if (isInited) + { + // + // Swing High ... + isDetected = DetectSwingHigh(swingBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SWING_HIGH_DETECTED; + XCSwing *param; + bool hasItem = GetLastItem( + param, + mSwingHighs // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Swing Low ... + isDetected = DetectSwingLow(swingBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SWING_LOW_DETECTED; + XCSwing *param; + bool hasItem = GetLastItem( + param, + mSwingLows // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + } + + // + // Bullish Momentum Bars ... + isDetected = DetectBullishMomentumBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_MOMENTUM_BAR_DETECTED; + XCMomentumBar *param; + bool hasItem = GetLastItem( + param, + mBullishMomentumBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Momentum Bars ... + isDetected = DetectBearishMomentumBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_MOMENTUM_BAR_DETECTED; + XCMomentumBar *param; + bool hasItem = GetLastItem( + param, + mBearishMomentumBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bullish Rejection Bars ... + isDetected = DetectBullishRejectionBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_REJECTION_BAR_DETECTED; + XCRejectionBar *param; + bool hasItem = GetLastItem( + param, + mBullishRejectionBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Rejection Bars ... + isDetected = DetectBearishRejectionBar(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_REJECTION_BAR_DETECTED; + XCRejectionBar *param; + bool hasItem = GetLastItem( + param, + mBearishRejectionBars // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Support and Resistance Zones ... + int supResRange = SupportAndResistanceRange(); + if (supResRange > 0) + { + // + XOHCL supResBar; + isInited = supResBar.Init( + symbol, + period, + zIndex + supResRange // + ); + if (isInited) + { + // + // Support Zones ... + isDetected = DetectSupportZone(supResBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SUPPORT_ZONE_DETECTED; + XCSupportZone *param; + bool hasItem = GetLastItem( + param, + mSupportZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Resistance Zones ... + isDetected = DetectResistanceZone(supResBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_RESISTANCE_ZONE_DETECTED; + XCResistanceZone *param; + bool hasItem = GetLastItem( + param, + mResistanceZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + } + + // + // Supply And Demand Zones ... + int supDemRange = SupplyAndDemandRange(); + if (supDemRange > 0) + { + // + // Supply Zone ... + isDetected = DetectSupplyZone(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_SUPPLY_ZONE_DETECTED; + XCSupplyZone *param; + bool hasItem = GetLastItem( + param, + mSupplyZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Demand Zone ... + isDetected = DetectDemandZone(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_DEMAND_ZONE_DETECTED; + XCDemandZone *param; + bool hasItem = GetLastItem( + param, + mDemandZones // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + + // + // Order Blocks ... + int obSameBars = OrderBlocksSameBars(); + if (obSameBars > 0) + { + // + // Bullish Order Block ... + isDetected = DetectBullishOrderBlock(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_ORDERBLOCK_DETECTED; + XCOrderBlock *param; + bool hasItem = GetLastItem( + param, + mBullishOrderBlocks // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Order Block ... + isDetected = DetectBearishOrderBlock(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_ORDERBLOCK_DETECTED; + XCOrderBlock *param; + bool hasItem = GetLastItem( + param, + mBearishOrderBlocks // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + + // + // Fair Value Gaps ... + int fvgSameBars = FairValueGapsSameBars(); + if (fvgSameBars > 0) + { + // + // Bullish Fair Value Gap ... + isDetected = DetectBullishFairValueGap(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BULLISH_FVG_DETECTED; + XCFVG *param; + bool hasItem = GetLastItem( + param, + mBullishFairValueGaps // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + + // + // Bearish Fair Value Gap ... + isDetected = DetectBearishFairValueGap(cBar); + if (isDetected) + { + // + ENUM_XPOI_EVENTS event = X_BEARISH_FVG_DETECTED; + XCFVG *param; + bool hasItem = GetLastItem( + param, + mBearishFairValueGaps // + ); + if (hasItem) + { + // + NotifyEventListeners( + event, + param // + ); + } + + // + Add( + event, + state // + ); + } + } + + // + // Ticks Range Zone ... + int ticksLevels = TicksRangeZoneLevel(); + int ticksRange = TicksRangeZoneRange(); + if (ticksLevels > 0 && + ticksRange > 0) + { + // + isDetected = DetectTicksZoneRange(cBar); + if (isDetected) + { + } + } + + // + ValidatePOIs(cBar); + + // + CleanupUnusedPOIs(); + + // + mBarTracker.Waits(); + + // + result = ArraySize(state); + + // + return result; + } + + /** + * Destroy Class ... + */ + void Destroy() + { + // + DestroyPOIs(); + DestroySessions(); + DestroyEventListeners(); + + // + delete mDrawer; + delete mTicksZone; + } + + // + // Retrievers ... + + /** + * Get Current State of POIs ... + * + * @param state: XPOIState instance ... + */ + void GetState( + XPOIState &state // + ) + { + // + state.Clean(); + + // + state.symbol = mSymbol; + state.period = mPeriod; + state.time = TimeCurrent(); + + // + Copy( + mSwingHighs, + state.swingHighs // + ); + + // + Copy( + mSwingLows, + state.swingLows // + ); + + // + Copy( + mBullishMomentumBars, + state.bullishMomentumBars // + ); + + // + Copy( + mBearishMomentumBars, + state.bearishMomentumBars // + ); + + // + Copy( + mBullishRejectionBars, + state.bullishRejectionBars // + ); + + // + Copy( + mBearishRejectionBars, + state.bearishRejectionBars // + ); + + // + Copy( + mSupportZones, + state.supportZones // + ); + + // + Copy( + mResistanceZones, + state.resistanceZones // + ); + + // + Copy( + mSupplyZones, + state.supplyZones // + ); + + // + Copy( + mDemandZones, + state.demandZones // + ); + + // + Copy( + mBullishOrderBlocks, + state.bullishOrderBlocks // + ); + + // + Copy( + mBearishOrderBlocks, + state.bearishOrderBlocks // + ); + + // + Copy( + mBullishFairValueGaps, + state.bullishFairValueGaps // + ); + + // + Copy( + mBearishFairValueGaps, + state.bearishFairValueGaps // + ); + + // + state.ticksZone = mTicksZone; + + // + } + + // + // Event Listeners ... + + /** + * Add Event Listener ... + * + * @param listener: TOnPOIEvent instance ... + */ + void AddEventListener(TOnPOIEvent listener) + { + // + Add( + listener, + mEventListeners // + ); + } + + // + // Destroy ... + + /** + * Destroy Detected POI(s) ... + */ + void DestroyPOIs() + { + // + Clean(mSwingHighs); + Clean(mSwingLows); + + // + Clean(mBullishMomentumBars); + Clean(mBearishMomentumBars); + + // + Clean(mBullishRejectionBars); + Clean(mBearishRejectionBars); + + // + Clean(mSupportZones); + Clean(mResistanceZones); + + // + Clean(mSupplyZones); + Clean(mDemandZones); + + // + Clean(mBullishOrderBlocks); + Clean(mBearishOrderBlocks); + + // + Clean(mBullishFairValueGaps); + Clean(mBearishFairValueGaps); + + // + ArrayFree(mSwingHighs); + ArrayFree(mSwingLows); + ArrayFree(mBullishMomentumBars); + ArrayFree(mBearishMomentumBars); + ArrayFree(mBullishRejectionBars); + ArrayFree(mBearishRejectionBars); + ArrayFree(mSupportZones); + ArrayFree(mResistanceZones); + ArrayFree(mSupplyZones); + ArrayFree(mDemandZones); + ArrayFree(mBullishOrderBlocks); + ArrayFree(mBearishOrderBlocks); + ArrayFree(mBullishFairValueGaps); + ArrayFree(mBearishFairValueGaps); + } + + /** + * Destroy Added Sessions ... + */ + void DestroySessions() + { + } + + /** + * Destroy Rejistered Event Handlers ... + */ + void DestroyEventListeners() + { + // + Clean(mEventListeners); + + // + ArrayFree(mEventListeners); + } + + // + // Virtual Actions ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Common ... + + // + MaxNumberOfPOIs(10); + MaxNumberOfRequiredPOIs(2); + + // + SwingRange(2); + + // + MomentumBarExtendRange(2); + MomentumBarBodyPercent(70); + + // + RejectionBarExtendRange(0); + RejectionBarShadowPercent(55); + + // + SupportAndResistanceRange(7); + + // + SupplyAndDemandRange(144); + + // + OrderBlocksSameBars(3); + + // + FairValueGapsSameBars(3); + + // + TicksRangeZoneLevel(10); + TicksRangeZoneRange(144); + } + + // + // Detector Functions ... + + /** + * Detect Swing High ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSwingHigh(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SwingRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsSwingHigh( + bar, + range // + ); + if (result) + { + // + XCSwing *swing; + swing = new XCSwing(); + result = swing.Init( + bar, + X_POI_SWING_HIGH // + ); + + // + if (result) + { + // + Add( + swing, + mSwingHighs // + ); + } + } + + // + return result; + } + + /** + * Detect Swing Low ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSwingLow(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SwingRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsSwingLow( + bar, + range // + ); + if (result) + { + // + XCSwing *swing; + swing = new XCSwing(); + result = swing.Init( + bar, + X_POI_SWING_LOW // + ); + + // + if (result) + { + // + Add( + swing, + mSwingLows // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Momentum Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishMomentumBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = MomentumBarExtendRange(); + double bodyPercent = MomentumBarBodyPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsMomentumBar( + bar, + dir, + extendRange, + bodyPercent // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (result) + { + // + XCMomentumBar *momentumBar; + momentumBar = new XCMomentumBar(); + result = momentumBar.Init(bar); + + // + if (result) + { + // + Add( + momentumBar, + mBullishMomentumBars // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Momentum Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishMomentumBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = MomentumBarExtendRange(); + double bodyPercent = MomentumBarBodyPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsMomentumBar( + bar, + dir, + extendRange, + bodyPercent // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (result) + { + // + XCMomentumBar *momentumBar; + momentumBar = new XCMomentumBar(); + result = momentumBar.Init(bar); + + // + if (result) + { + // + Add( + momentumBar, + mBearishMomentumBars // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Rejection Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishRejectionBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = RejectionBarExtendRange(); + double shadowPercent = RejectionBarShadowPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsRejectionBar( + bar, + dir, + extendRange, + shadowPercent // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (result) + { + // + XCRejectionBar *rejectionBar; + rejectionBar = new XCRejectionBar(); + result = rejectionBar.Init(bar); + + // + if (result) + { + // + Add( + rejectionBar, + mBullishRejectionBars // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Rejection Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishRejectionBar(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid() && + bar.Index() > 0; + if (!result) + { + return result; + } + + // + int extendRange = RejectionBarExtendRange(); + double shadowPercent = RejectionBarShadowPercent(); + ENUM_X_DIRECTION dir; + result = mBarAnalyser.IsRejectionBar( + bar, + dir, + extendRange, + shadowPercent // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (result) + { + // + XCRejectionBar *rejectionBar; + rejectionBar = new XCRejectionBar(); + result = rejectionBar.Init(bar); + + // + if (result) + { + // + Add( + rejectionBar, + mBearishRejectionBars // + ); + } + } + + // + return result; + } + + /** + * Detect Support Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSupportZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupportAndResistanceRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsSupport( + bar, + range // + ); + if (result) + { + // + XCSupportZone *support; + support = new XCSupportZone(); + result = support.Init( + bar, + range // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + support.To(cTime); + + // + Add( + support, + mSupportZones // + ); + } + } + + // + return result; + } + + /** + * Detect Resistance Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectResistanceZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupportAndResistanceRange(); + int barIndex = bar.Index(); + result = range > 0 && + barIndex >= range; + if (!result) + { + return result; + } + + // + result = mBarAnalyser.IsResistance( + bar, + range // + ); + if (result) + { + // + XCResistanceZone *resistance; + resistance = new XCResistanceZone(); + result = resistance.Init( + bar, + range // + ); + + // + if (result) + { + // + Add( + resistance, + mResistanceZones // + ); + } + } + + // + return result; + } + + /** + * Detect Supply Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectSupplyZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupplyAndDemandRange(); + result = range > 0; + if (!result) + { + return result; + } + + // + int hhIDX = -1; + double hh = -1; + + // + int llIDX = -1; + double ll = -1; + + // + result = mBarAnalyser + .CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + range // + ); + if (!result) + { + return result; + } + + // + XOHCL supplyBar; + result = supplyBar.Init( + bar.symbol, + bar.period, + hhIDX // + ); + if (result) + { + // + XCSupplyZone *supply; + supply = new XCSupplyZone(); + result = supply.Init( + supplyBar, + range // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + supply.To(cTime); + + // + Add( + supply, + mSupplyZones // + ); + } + } + + // + return result; + } + + /** + * Detect Demand Zone ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectDemandZone(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int range = SupplyAndDemandRange(); + result = range > 0; + if (!result) + { + return result; + } + + // + int hhIDX = -1; + double hh = -1; + + // + int llIDX = -1; + double ll = -1; + + // + result = mBarAnalyser + .CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + range // + ); + if (!result) + { + return result; + } + + // + XOHCL demandBar; + result = demandBar.Init( + bar.symbol, + bar.period, + llIDX // + ); + if (result) + { + // + XCDemandZone *demand; + demand = new XCDemandZone(); + result = demand.Init( + demandBar, + range // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + demand.To(cTime); + + // + Add( + demand, + mDemandZones // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishOrderBlock(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + + // + Add( + ob, + mBullishOrderBlocks // + ); + } + } + + // + return result; + } + + /** + * Detect Bullish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishOrderBlock( + XOHCL &bar, + XCOrderBlock *&ob // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + } + } + + // + return result; + } + + /** + * Detect Bearish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishOrderBlock(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCOrderBlock *ob; + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + + // + Add( + ob, + mBearishOrderBlocks // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Order Block ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishOrderBlock( + XOHCL &bar, + XCOrderBlock *&ob // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL obBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasOrderBlock( + bar, + obBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + ob = new XCOrderBlock(); + result = ob.Init( + obBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + ob.To(cTime); + } + } + + // + return result; + } + + /** + * Detect Bullish Fair Value Gap ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBullishFairValueGap(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL prevBar; + XOHCL nextBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasFairValueGap( + bar, + prevBar, + nextBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCFVG *fvg; + fvg = new XCFVG(); + result = fvg.Init( + prevBar, + nextBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + fvg.To(cTime); + + // + Add( + fvg, + mBullishFairValueGaps // + ); + } + } + + // + return result; + } + + /** + * Detect Bearish Fair Value Gap ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectBearishFairValueGap(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + result = sameBars > 0; + if (!result) + { + return result; + } + + // + XOHCL prevBar; + XOHCL nextBar; + ENUM_X_DIRECTION dir; + result = mBarAnalyser + .HasFairValueGap( + bar, + prevBar, + nextBar, + dir, + sameBars // + ); + result = + result && + dir == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + if (result) + { + // + XCFVG *fvg; + fvg = new XCFVG(); + result = fvg.Init( + prevBar, + nextBar, + dir // + ); + + // + if (result) + { + // + datetime cTime = TimeCurrent(); + fvg.To(cTime); + + // + Add( + fvg, + mBearishFairValueGaps // + ); + } + } + + // + return result; + } + + // + protected: + // + + // + // Actions ... + + /** + * Lock ... + */ + void Lock() + { + mLock = true; + } + + /** + * Unlock ... + */ + void Unlock() + { + mLock = false; + } + + /** + * Detect Required POI(s) ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + */ + void DetectRequiredPOIs(int barIndex = 0) + { + // + // Validate Reuired POI(s) ... + int requiredPOIs = MaxNumberOfRequiredPOIs(); + if (requiredPOIs <= 0) + { + return; + } + + // + // Locking Detector ... + Lock(); + + // + // Normalize Bar Index ... + if (barIndex < 0) + { + barIndex = 0; + } + + // + int swingLowsCount = 0; + int swingHighsCount = 0; + + // + int bullishMomentumBarsCount = 0; + int bearishMomentumBarsCount = 0; + + // + int bullishRejectionBarsCount = 0; + int bearishRejectionBarsCount = 0; + + // + int supportZonesCount = 0; + int resistanceZonesCount = 0; + + // + int supplyZonesCount = 0; + int demandZonesCount = 0; + + // + int bullishOrderBlocksCount = 0; + int bearishOrderBlocksCount = 0; + + // + int bullishFairValueGapsCount = 0; + int bearishFairValueGapsCount = 0; + + // + bool canContinue = true; + + // + while (canContinue) + { + // + // Swings ... + int swingRange = SwingRange(); + if (swingRange > 0) + { + // + // Swing Highs ... + swingHighsCount = DetectRequiredSwingHighs(barIndex); + if (swingHighsCount == requiredPOIs) + { + ArrayReverse(mSwingHighs); + } + + // + // Swing Lows ... + swingLowsCount = DetectRequiredSwingLows(barIndex); + if (swingLowsCount == requiredPOIs) + { + ArrayReverse(mSwingLows); + } + } + + // + bool canLookupMomentumBars = + MomentumBarExtendRange() >= 0 && + MomentumBarBodyPercent() > 0; + if (canLookupMomentumBars) + { + // + // + // Bullish Momentum Bars ... + bullishMomentumBarsCount = DetectRequiredBullishMomentumBars(barIndex); + if (bullishMomentumBarsCount == requiredPOIs) + { + ArrayReverse(mBullishMomentumBars); + } + + // + // Bearish Momentum Bars ... + bearishMomentumBarsCount = DetectRequiredBearishMomentumBars(barIndex); + if (bearishMomentumBarsCount == requiredPOIs) + { + ArrayReverse(mBearishMomentumBars); + } + } + + // + bool canLookupRejectionBars = + RejectionBarExtendRange() >= 0 && + RejectionBarShadowPercent() > 0; + if (canLookupRejectionBars) + { + // + // + // Bullish Rejection Bars ... + bullishRejectionBarsCount = DetectRequiredBullishRejectionBars(barIndex); + if (bullishRejectionBarsCount == requiredPOIs) + { + ArrayReverse(mBullishRejectionBars); + } + + // + // Bearish Rejection Bars ... + bearishRejectionBarsCount = DetectRequiredBearishRejectionBars(barIndex); + if (bearishRejectionBarsCount == requiredPOIs) + { + ArrayReverse(mBearishRejectionBars); + } + } + + // + // Support and Resistance Zones ... + int supResRange = SupportAndResistanceRange(); + if (supResRange > 0) + { + // + // Support Zone(s) ... + supportZonesCount = DetectRequiredSupportZones(barIndex); + if (supportZonesCount == requiredPOIs) + { + ArrayReverse(mSupportZones); + } + + // + // Resistance Zone(s) ... + resistanceZonesCount = DetectRequiredResistanceZones(barIndex); + if (resistanceZonesCount == requiredPOIs) + { + ArrayReverse(mResistanceZones); + } + } + + // + // Supply and Demand Zones ... + int supDemRange = SupplyAndDemandRange(); + if (supDemRange > 0) + { + // + supplyZonesCount = DetectRequiredSupplyZones(barIndex); + if (supplyZonesCount == requiredPOIs) + { + ArrayReverse(mSupplyZones); + } + + // + demandZonesCount = DetectRequiredDemandZones(barIndex); + if (demandZonesCount == requiredPOIs) + { + ArrayReverse(mDemandZones); + } + } + + // + // Oder Blocks ... + int obSameBars = OrderBlocksSameBars(); + if (obSameBars > 0) + { + // + // Bullish Order Blocks ... + bullishOrderBlocksCount = DetectRequiredBullishOrderBlocks(barIndex); + if (bullishOrderBlocksCount == requiredPOIs) + { + ArrayReverse(mBullishOrderBlocks); + } + + // + // Bearish Order Blocks ... + bearishOrderBlocksCount = DetectRequiredBearishOrderBlocks(barIndex); + if (bearishOrderBlocksCount == requiredPOIs) + { + ArrayReverse(mBearishOrderBlocks); + } + } + + // + // Fair Value Gaps ... + int fvgSameBars = FairValueGapsSameBars(); + if (fvgSameBars > 0) + { + // + // Bullish Fair Value Gaps ... + bullishFairValueGapsCount = DetectRequiredBullishFairValueGaps(barIndex); + if (bullishFairValueGapsCount == requiredPOIs) + { + ArrayReverse(mBullishFairValueGaps); + } + + // + // Bearish Fair Value Gaps ... + bearishFairValueGapsCount = DetectRequiredBearishFairValueGaps(barIndex); + if (bearishFairValueGapsCount == requiredPOIs) + { + ArrayReverse(mBearishFairValueGaps); + } + } + + // + // Swings ... + bool canContinueSwingHighs = + swingRange > 0 + ? swingHighsCount < requiredPOIs + : false; + bool canContinueSwingLows = + swingRange > 0 + ? swingLowsCount < requiredPOIs + : false; + + // + // Support and Resistance Zones ... + bool canContinueSupportZones = + supResRange > 0 + ? supportZonesCount < requiredPOIs + : false; + bool canContinueResistanceZones = + supResRange > 0 + ? resistanceZonesCount < requiredPOIs + : false; + + // + // Supply and Demand Zones ... + bool canContinueSupplyZones = + supDemRange > 0 + ? supplyZonesCount < requiredPOIs + : false; + bool canContinueDemandZones = + supDemRange > 0 + ? demandZonesCount < requiredPOIs + : false; + + // + // Order Blocks ... + bool canContinueBullishOrderBlocks = + obSameBars > 0 + ? bullishOrderBlocksCount < requiredPOIs + : false; + bool canContinueBearishOrderBlocks = + obSameBars > 0 + ? bearishOrderBlocksCount < requiredPOIs + : false; + + // + // Fair Value Gaps ... + bool canContinueBullishFairValueGaps = + fvgSameBars > 0 + ? bullishFairValueGapsCount < requiredPOIs + : false; + bool canContinueBearishFairValueGaps = + fvgSameBars > 0 + ? bearishFairValueGapsCount < requiredPOIs + : false; + + // + // Rejection Bars ... + bool canContinueBullishRejectionBars = + canLookupRejectionBars + ? bullishRejectionBarsCount < requiredPOIs + : false; + bool canContinueBearishRejectionBars = + canLookupRejectionBars + ? bearishRejectionBarsCount < requiredPOIs + : false; + + // + // Momentum Bars ... + bool canContinueBullishMomentumBars = + canLookupMomentumBars + ? bullishMomentumBarsCount < requiredPOIs + : false; + bool canContinueBearishMomentumBars = + canLookupMomentumBars + ? bearishMomentumBarsCount < requiredPOIs + : false; + + // + canContinue = + // + // Swings ... + canContinueSwingHighs || + canContinueSwingLows || + // + // Support and Resistance Zones ... + canContinueSupportZones || + canContinueResistanceZones || + // + // Supply and Demand Zones ... + canContinueSupplyZones || + canContinueDemandZones || + // + // Order Blocks ... + canContinueBullishOrderBlocks || + canContinueBearishOrderBlocks || + // + // Fair Value Gaps ... + canContinueBullishFairValueGaps || + canContinueBearishFairValueGaps || + // + // Rejection Bars ... + canContinueBullishRejectionBars || + canContinueBearishRejectionBars || + // + // Momentum Bars ... + canContinueBullishMomentumBars || + canContinueBearishMomentumBars + // + ; + if (canContinue) + { + barIndex++; + } + } + + // + // Unlocking Detector ... + Unlock(); + } + + /** + * Validate Founded POI(s) ... + * + * @param bar: XOHCL instance ... + */ + void ValidatePOIs(XOHCL &bar) + { + } + + /** + * Cleanup Unused Objects ... + */ + void CleanupUnusedPOIs() + { + // + int maxAllowed = MaxNumberOfPOIs(); + if (!IsValidSize(maxAllowed)) + { + return; + } + + // + int swingHighsCount = ArraySize(mSwingHighs); + int swingLowsCount = ArraySize(mSwingLows); + // int tradingDaysCount = ArraySize(mTradingDays); + // int marketSessionsCount = ArraySize(mMarketSessions); + // int momentumBarsCount = ArraySize(mMomentumBars); + // int rejectionBarsCount = ArraySize(mRejectionBars); + // int supportZonesCount = ArraySize(mSupportZones); + // int resistanceZonesCount = ArraySize(mResistanceZones); + // int supplyZonesCount = ArraySize(mSupplyZones); + // int demandZonesCount = ArraySize(mDemandZones); + // int bullishOBsCount = ArraySize(mBullishOrderBlocks); + // int bearishOBsCount = ArraySize(mBearishOrderBlocks); + // int bullishFVGsCount = ArraySize(mBullishFVGs); + // int bearishFVGsCount = ArraySize(mBearishFVGs); + + // + int from = 0; + int requiredPOIs = MaxNumberOfRequiredPOIs(); + int count = maxAllowed - requiredPOIs; + int to = count - 1; + + // + // Swings ... + + // // + // // Swing Highs ... + // if (swingHighsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSwingHighs, + // from, + // count // + // ); + // } + + // // + // // Swing Lows ... + // if (swingLowsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSwingLows, + // from, + // count // + // ); + // } + + // // + // // Trading Days ... + // if (tradingDaysCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mTradingDays, + // from, + // count // + // ); + + // // + // mTradingDayObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Market Sessions ... + // if (marketSessionsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mMarketSessions, + // from, + // count // + // ); + + // // + // mMarketSessionObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Momentum Bars ... + // if (momentumBarsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mMomentumBars, + // from, + // count // + // ); + + // // + // mMomentumBarObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Rejection Bars ... + // if (rejectionBarsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mRejectionBars, + // from, + // count // + // ); + + // // + // mRejectionBarObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Support and Resistance Zones ... + + // // + // // Support Zones ... + // if (supportZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSupportZones, + // from, + // count // + // ); + + // // + // mSupportZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Resistance Zones ... + // if (resistanceZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mResistanceZones, + // from, + // count // + // ); + + // // + // mResistanceZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Supply and Demand Zones ... + + // // + // // Supply Zones ... + // if (supplyZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mSupplyZones, + // from, + // count // + // ); + + // // + // mSupplyZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Demand Zones ... + // if (demandZonesCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mDemandZones, + // from, + // count // + // ); + + // // + // mDemandZoneObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Order Blocks ... + + // // + // // Bullish Order Blocks ... + // if (bullishOBsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBullishOrderBlocks, + // from, + // count // + // ); + + // // + // mBullishOrderBlockObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Bearish Order Blocks ... + // if (bearishOBsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBearishOrderBlocks, + // from, + // count // + // ); + + // // + // mBearishOrderBlockObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Fair Vakue Gaps ... + + // // + // // Bullish FVGs ... + // if (bullishFVGsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBullishFVGs, + // from, + // count // + // ); + + // // + // mBullishFVGObjects.DeleteRange( + // from, + // to // + // ); + // } + + // // + // // Bearish FVGs ... + // if (bearishFVGsCount >= maxAllowed) + // { + // // + // ArrayRemove( + // mBearishFVGs, + // from, + // count // + // ); + + // // + // mBearishFVGObjects.DeleteRange( + // from, + // to // + // ); + // } + + // + } + + /** + * Notify Event Listeners ... + * + * @param event: ENUM_XPOI_EVENTS member, Specified Occured Event ... + * @param param: XCBasePOI implementation, Specified Event Object ... + */ + void NotifyEventListeners( + ENUM_XPOI_EVENTS event, + XCBasePOI *param // + ) + { + // + int count = ArraySize(mEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mEventListeners[i]( + event, + param // + ); + } + } + + void AddObjectIfNotExists(XCBaseObject *object) + { + // + string name = object.ObjName(); + + // + bool canAdd = true; + int count = mDrawnObjects.Total(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + string iName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName(); + + // + if (name == iName) + { + // + canAdd = false; + break; + } + } + } + + // + if (canAdd) + { + mDrawnObjects.Add(object); + } + } + + // + private: + // + + // + // Props ... + + // + bool mLock; // Lock State ... + string mSymbol; // Market Symbol ... + ENUM_TIMEFRAMES mPeriod; // Market Period ... + int mMaxNumberOfPOIs; // Max Allowed Number of POI(s) which Can Holds ... + int mMaxNumberOfRequiredPOIs; // Max Allowed Number of POI(s) which Must Find at Initializion Time ... + + // + CArrayObj mDrawnObjects; // Drawn Objects ... + XBarTracker mBarTracker; // Market Bar Tracker ... + XCBarAnalyser mBarAnalyser; // Bar Analyser ... + + // + TOnPOIEvent mEventListeners[]; // Event Listeners ... + + // + // POI Props ... + + // + // XDay ... + + // + // XSession ... + + // + // XSwing ... + int mSwingRange; // Swing Verification Range Length ... + + // + // Swing High ... + + // + XCSwing *mSwingHighs[]; // Holds Founded Swing Highs ... + + /** + * Detect Required Swing Highs ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSwingHighs(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSwingHighs); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SwingRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSwingHigh(bar); + + // + result = ArraySize(mSwingHighs); + + // + return result; + } + + // + // Swing Low ... + + // + XCSwing *mSwingLows[]; // Holds Founded Swing Lows ... + + /** + * Detect Required Swing Lows ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSwingLows(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSwingLows); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SwingRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSwingLow(bar); + + // + result = ArraySize(mSwingLows); + + // + return result; + } + + // + // Momentum Bars ... + int mMomentumBarExtendRange; // Momentum Bars must Extends Range ... + double mMomentumBarBodyPercent; // Momentum Bars Body Percent ... + + // + // Bullish ... + XCMomentumBar *mBullishMomentumBars[]; // Holds Founded Bullish Momentum Bars ... + + /** + * Detect Required Bullish Momentum Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishMomentumBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishMomentumBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishMomentumBar(bar); + + // + result = ArraySize(mBullishMomentumBars); + + // + return result; + } + + // + // Bearish ... + XCMomentumBar *mBearishMomentumBars[]; // Holds Founded Bearish Momentum Bars ... + + /** + * Detect Required Bearish Momentum Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishMomentumBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishMomentumBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishMomentumBar(bar); + + // + result = ArraySize(mBearishMomentumBars); + + // + return result; + } + + // + // Rejection Bars ... + int mRejectionBarExtendRange; // Rejection Bars must Extends Range ... + double mRejectionBarShadowPercent; // Rejection Bars Shadow Percent ... + + // + // Bullish ... + XCRejectionBar *mBullishRejectionBars[]; // Holds Founded Bullish Rejection Bars ... + + /** + * Detect Required Bullish Rejection Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishRejectionBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishRejectionBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishRejectionBar(bar); + + // + result = ArraySize(mBullishRejectionBars); + + // + return result; + } + + // + // Bearish ... + XCRejectionBar *mBearishRejectionBars[]; // Holds Founded Bearish Rejection Bars ... + + /** + * Detect Required Bearish Rejection Bars ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishRejectionBars(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishRejectionBars); + if (count >= required) + { + // + result = count; + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishRejectionBar(bar); + + // + result = ArraySize(mBearishRejectionBars); + + // + return result; + } + + // + // Support and Resistance Zone ... + int mSupportAndResistanceRange; // Support and Resistance Range for Verification ... + + // + // Support Zone(s) ... + XCSupportZone *mSupportZones[]; // Holds Founded Support Zones ... + + /** + * Detect Required Support Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSupportZones(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSupportZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupportAndResistanceRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSupportZone(bar); + + // + result = ArraySize(mSupportZones); + + // + return result; + } + + // + // Resistance Zone(s) ... + XCResistanceZone *mResistanceZones[]; // Holds Founded Resistance Zones ... + + /** + * Detect Required Resistance Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredResistanceZones(int barIndex = 0) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mResistanceZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupportAndResistanceRange(); + if (range < 0 || barIndex < range) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectResistanceZone(bar); + + // + result = ArraySize(mResistanceZones); + + // + return result; + } + + // + // Supply and Demand Zones ... + int mSupplyAndDemandRange; // Supply and Demand Range Verifications ... + + // + // Supply Zone(s) ... + XCSupplyZone *mSupplyZones[]; // Holds Founded Supply Zones ... + + /** + * Detect Required Supply Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredSupplyZones(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mSupplyZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupplyAndDemandRange(); + if (range < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectSupplyZone(bar); + + // + result = ArraySize(mSupplyZones); + + // + return result; + } + + // + // Demand Zone(s) ... + XCDemandZone *mDemandZones[]; // Holds Founded Demand Zones ... + + /** + * Detect Required Demand Zones ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredDemandZones(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mDemandZones); + if (count >= required) + { + // + result = count; + return result; + } + + // + int range = SupplyAndDemandRange(); + if (range < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectDemandZone(bar); + + // + result = ArraySize(mDemandZones); + + // + return result; + } + + // + // Order Blocks ... + int mOrderBlocksSameBars; // Order Blocks Detection Bars ... + + // + // Bullish OB ... + XCOrderBlock *mBullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ... + + /** + * Detect Required Bullish Order Blocks ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishOrderBlocks(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishOrderBlocks); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishOrderBlock(bar); + + // + result = ArraySize(mBullishOrderBlocks); + + // + return result; + } + + // + // Bearish OB ... + XCOrderBlock *mBearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ... + + /** + * Detect Required Bearish Order Blocks ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishOrderBlocks(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishOrderBlocks); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = OrderBlocksSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishOrderBlock(bar); + + // + result = ArraySize(mBearishOrderBlocks); + + // + return result; + } + + // + // Fair Value Gaps ... + int mFairValueGapsSameBars; // Fair Value Gaps Detection Same Bars ... + + // + // Bullish FVG ... + XCFVG *mBullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ... + + /** + * Detect Required Bullish Fair Value Gaps ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBullishFairValueGaps(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBullishFairValueGaps); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBullishFairValueGap(bar); + + // + result = ArraySize(mBullishFairValueGaps); + + // + return result; + } + + // + // Bearish FVG ... + XCFVG *mBearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ... + + /** + * Detect Required Bearish Fair Value Gaps ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + * + * @return ( int ) + */ + int DetectRequiredBearishFairValueGaps(int barIndex) + { + // + int result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int required = MaxNumberOfRequiredPOIs(); + if (required <= 0) + { + return result; + } + + // + int count = ArraySize(mBearishFairValueGaps); + if (count >= required) + { + // + result = count; + return result; + } + + // + int sameBars = FairValueGapsSameBars(); + if (sameBars < 0) + { + return result; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL bar; + bool isInited = bar.Init( + symbol, + period, + barIndex // + ); + if (!isInited) + { + return result; + } + + // + DetectBearishFairValueGap(bar); + + // + result = ArraySize(mBearishFairValueGaps); + + // + return result; + } + + // + // Ticks Range Zones ... + int mTicksRangeZoneLevel; // Ticks Range Levels ... + int mTicksRangeZoneRange; // Ticks Range Zone Loopback Period ... + + // + XCTicksZone *mTicksZone; // Ticks Zone ... + // XCTicksZoneObject *mTicksZoneObject; // Ticks Zone Object ... + + /** + * Detect Ticks Zone Range ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool DetectTicksZoneRange(XOHCL &bar) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int ticksLevels = TicksRangeZoneLevel(); + int ticksRange = TicksRangeZoneRange(); + result = ticksLevels > 0 && + ticksRange > 0; + if (!result) + { + return result; + } + + // + int startBarIndex = bar.Index() + ticksRange; + XOHCL startBar; + result = startBar.Init( + bar.symbol, + bar.period, + startBarIndex // + ); + if (!result) + { + return result; + } + + // + mTicksZone = new XCTicksZone(); + result = mTicksZone.Init( + startBar, + bar // + ); + if (!result) + { + // + mTicksZone = NULL; + return result; + } + + // + return result; + } + + // + // Liquidity Zones ... + + // + // Sell Side ... + + // + // Buy Side ... + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-poi.drawer.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-poi.drawer.class.mq5 new file mode 100644 index 0000000..eb7b9c0 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-poi.drawer.class.mq5 @@ -0,0 +1,4801 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOIDrawer +// Description: Provides Point of Interests +// Drawing Tools ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-cobject.class.mq5" + +// +// Definitions ... +class XCPOIDrawer : public XCBase +{ + // + public: + // + + // + // Constructor ... + void XCPOIDrawer() + { + // + Default(); + } + + // + // Deconstructor ... + void ~XCPOIDrawer() + { + // + ArrayFree(mTicksZoneSpecs); + } + + // + // Setter Getter (s) ... + + /** + * Get Prefix ... + * + * @return ( string ) + */ + string Prefix() + { + return mPrefix; + } + + /** + * Set Prifx ... + * + * @param value: String ... + */ + void Prefix(string value) + { + mPrefix = value; + } + + /** + * Get Chart ID ... + * + * @return ( long ) + */ + long ChartIdentification() + { + return mChartIdentification; + } + + /** + * Set Chart ID ... + * + * @param value: Long ... + */ + void ChartIdentification(long value) + { + // + if (value < 0) + { + value = 0; + } + + // + mChartIdentification = value; + } + + /** + * Get SubWindow Id ... + * + * @return ( int ) + */ + int SubWindowIdentification() + { + return mSubWindowIdentification; + } + + /** + * Set SubWindow Id ... + * + * @param value: Integer ... + */ + void SubWindowIdentification(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSubWindowIdentification = value; + } + + // + // XOHCL ... + + /** + * Get Bar Width ... + * + * @return ( int ) + */ + int BarWidth() + { + return mBarWidth; + } + + /** + * Set Bar Width ... + * + * @param value: Integer ... + */ + void BarWidth(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mBarWidth = value; + } + + /** + * Get Bar Bullish Color ... + * + * @return ( color ) + */ + color BarBullishColor() + { + return mBarBullishColor; + } + + /** + * Set Bar Bullish Color ... + * + * @param value: Color ... + */ + void BarBullishColor(color value) + { + mBarBullishColor = value; + } + + /** + * Get Bar Bearish Color ... + * + * @return ( color ) + */ + color BarBearishColor() + { + return mBarBearishColor; + } + + /** + * Set Bar Bearish Color ... + * + * @param value: Color ... + */ + void BarBearishColor(color value) + { + mBarBearishColor = value; + } + + /** + * Get Fill Bar High Shadow State ... + * + * @return ( bool ) + */ + bool BarFillHighShadow() + { + return mBarFillHighShadow; + } + + /** + * Set Fill Bar High Shadow State ... + * + * @param value: Boolean ... + */ + void BarFillHighShadow(bool value) + { + mBarFillHighShadow = value; + } + + /** + * Get Bar High Shadow Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BarHighShadowStyle() + { + return mBarHighShadowStyle; + } + + /** + * Set Bar High Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BarHighShadowStyle(ENUM_LINE_STYLE value) + { + mBarHighShadowStyle = value; + } + + /** + * Get Fill Bar Body State ... + * + * @return ( bool ) + */ + bool BarFillBody() + { + return mBarFillBody; + } + + /** + * Set Fill Bar Body State ... + * + * @param value: Boolean ... + */ + void BarFillBody(bool value) + { + mBarFillBody = value; + } + + /** + * Get Bar Body Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BarBodyStyle() + { + return mBarBodyStyle; + } + + /** + * Set Bar Body Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BarBodyStyle(ENUM_LINE_STYLE value) + { + mBarBodyStyle = value; + } + + /** + * Get Fill Bar Low Show State ... + * + * @return ( bool ) + */ + bool BarFillLowShadow() + { + return mBarFillLowShadow; + } + + /** + * Set Fill Bar Low Show State ... + * + * @param value: Boolean ... + */ + void BarFillLowShadow(bool value) + { + mBarFillLowShadow = value; + } + + /** + * Get Bar Low Shadow Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BarLowShadowStyle() + { + return mBarLowShadowStyle; + } + + /** + * Set Bar Low Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BarLowShadowStyle(ENUM_LINE_STYLE value) + { + mBarLowShadowStyle = value; + } + + // + // Swing Low ... + + /** + * Get Swing Low Width ... + * + * @return ( int ) + */ + int SwingLowWidth() + { + return mSwingLowWidth; + } + + /** + * Set Swing Low Width ... + * + * @param value: Integer ... + */ + void SwingLowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingLowWidth = value; + } + + /** + * Get Swing Low Arrow Code ... + * + * @return ( int ) + */ + int SwingLowArrow() + { + return mSwingLowArrow; + } + + /** + * Set Swing Low Arrow Code ... + * + * @param value: Integer ... + */ + void SwingLowArrow(int value) + { + // + mSwingLowArrow = value; + } + + /** + * Get Swing Low Color ... + * + * @return ( color ) + */ + color SwingLowColor() + { + return mSwingLowColor; + } + + /** + * Set Swing Low Color ... + * + * @param value: Color ... + */ + void SwingLowColor(color value) + { + mSwingLowColor = value; + } + + // + // Swing High ... + + /** + * Get Swing High Width ... + * + * @return ( int ) + */ + int SwingHighWidth() + { + return mSwingHighWidth; + } + + /** + * Set Swing High Width ... + * + * @param value: Integer ... + */ + void SwingHighWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingHighWidth = value; + } + + /** + * Get Swing High Arrow Code ... + * + * @return ( int ) + */ + int SwingHighArrow() + { + return mSwingHighArrow; + } + + /** + * Set Swing High Arrow Code ... + * + * @param value: Integer ... + */ + void SwingHighArrow(int value) + { + // + mSwingHighArrow = value; + } + + /** + * Get Swing High Color ... + * + * @return ( color ) + */ + color SwingHighColor() + { + return mSwingHighColor; + } + + /** + * Set Swing High Color ... + * + * @param value: Color ... + */ + void SwingHighColor(color value) + { + mSwingHighColor = value; + } + + // + // Bullish Momentum Bar ... + + /** + * Get Bullish Momentum Bar Width ... + * + * @return ( int ) + */ + int BullishMomentumBarWidth() + { + return mBullishMomentumBarWidth; + } + + /** + * Set Bullish Momentum Bar Width ... + * + * @param value: Integer ... + */ + void BullishMomentumBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishMomentumBarWidth = value; + } + + /** + * Get Bullish Momentum Bar Arrow Code ... + * + * @return ( int ) + */ + int BullishMomentumBarArrow() + { + return mBullishMomentumBarArrow; + } + + /** + * Set Bullish Momentum Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BullishMomentumBarArrow(int value) + { + // + mBullishMomentumBarArrow = value; + } + + /** + * Get Bullish Momentum Bar Color ... + * + * @return ( color ) + */ + color BullishMomentumBarColor() + { + return mBullishMomentumBarColor; + } + + /** + * Set Bullish Momentum Bar Color ... + * + * @param value: Color ... + */ + void BullishMomentumBarColor(color value) + { + mBullishMomentumBarColor = value; + } + + // + // Bearish Momentum Bar ... + + /** + * Get Bearish Momentum Bar Width ... + * + * @return ( int ) + */ + int BearishMomentumBarWidth() + { + return mBearishMomentumBarWidth; + } + + /** + * Set Bearish Momentum Bar Width ... + * + * @param value: Integer ... + */ + void BearishMomentumBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishMomentumBarWidth = value; + } + + /** + * Get Bearish Momentum Bar Arrow Code ... + * + * @return ( int ) + */ + int BearishMomentumBarArrow() + { + return mBearishMomentumBarArrow; + } + + /** + * Set Bearish Momentum Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BearishMomentumBarArrow(int value) + { + // + mBearishMomentumBarArrow = value; + } + + /** + * Get Bearish Momentum Bar Color ... + * + * @return ( color ) + */ + color BearishMomentumBarColor() + { + return mBearishMomentumBarColor; + } + + /** + * Set Bearish Momentum Bar Color ... + * + * @param value: Color ... + */ + void BearishMomentumBarColor(color value) + { + mBearishMomentumBarColor = value; + } + + // + // Bullish Rejection Bar ... + + /** + * Get Bullish Rejection Bar Width ... + * + * @return ( int ) + */ + int BullishRejectionBarWidth() + { + return mBullishRejectionBarWidth; + } + + /** + * Set Bullish Rejection Bar Width ... + * + * @param value: Integer ... + */ + void BullishRejectionBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishRejectionBarWidth = value; + } + + /** + * Get Bullish Rejection Bar Arrow Code ... + * + * @return ( int ) + */ + int BullishRejectionBarArrow() + { + return mBullishRejectionBarArrow; + } + + /** + * Set Bullish Rejection Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BullishRejectionBarArrow(int value) + { + // + mBullishRejectionBarArrow = value; + } + + /** + * Get Bullish Rejection Bar Color ... + * + * @return ( color ) + */ + color BullishRejectionBarColor() + { + return mBullishRejectionBarColor; + } + + /** + * Set Bullish Rejection Bar Color ... + * + * @param value: Color ... + */ + void BullishRejectionBarColor(color value) + { + mBullishRejectionBarColor = value; + } + + // + // Bearish Rejection Bar ... + + /** + * Get Bearish Rejection Bar Width ... + * + * @return ( int ) + */ + int BearishRejectionBarWidth() + { + return mBearishRejectionBarWidth; + } + + /** + * Set Bearish Rejection Bar Width ... + * + * @param value: Integer ... + */ + void BearishRejectionBarWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishRejectionBarWidth = value; + } + + /** + * Get Bearish Rejection Bar Arrow Code ... + * + * @return ( int ) + */ + int BearishRejectionBarArrow() + { + return mBearishRejectionBarArrow; + } + + /** + * Set Bearish Rejection Bar Arrow Code ... + * + * @param value: Integer ... + */ + void BearishRejectionBarArrow(int value) + { + // + mBearishRejectionBarArrow = value; + } + + /** + * Get Bearish Rejection Bar Color ... + * + * @return ( color ) + */ + color BearishRejectionBarColor() + { + return mBearishRejectionBarColor; + } + + /** + * Set Bearish Rejection Bar Color ... + * + * @param value: Color ... + */ + void BearishRejectionBarColor(color value) + { + mBearishRejectionBarColor = value; + } + + // + // Supply Zone ... + + /** + * Get Fill Supply Zone ... + * + * @return ( bool ) + */ + bool SupplyZoneFill() + { + return mSupplyZoneFill; + } + + /** + * Set Fill Supply Zone ... + * + * @param value: Boolean ... + */ + void SupplyZoneFill(bool value) + { + mSupplyZoneFill = value; + } + + /** + * Get Supply Zone Width ... + * + * @return ( int ) + */ + int SupplyZoneWidth() + { + return mSupplyZoneWidth; + } + + /** + * Set Supply Zone Width ... + * + * @param value: Integer ... + */ + void SupplyZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSupplyZoneWidth = value; + } + + /** + * Get Supply Zone Color ... + * + * @return ( color ) + */ + color SupplyZoneColor() + { + return mSupplyZoneColor; + } + + /** + * Set Supply Zone Color ... + * + * @param value: Color ... + */ + void SupplyZoneColor(color value) + { + mSupplyZoneColor = value; + } + + /** + * Get Supply Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE SupplyZoneStyle() + { + return mSupplyZoneStyle; + } + + /** + * Set Supply Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void SupplyZoneStyle(ENUM_LINE_STYLE value) + { + mSupplyZoneStyle = value; + } + + // + // Demand Zone ... + + /** + * Get Fill Demand Zone ... + * + * @return ( bool ) + */ + bool DemandZoneFill() + { + return mDemandZoneFill; + } + + /** + * Set Fill Demand Zone ... + * + * @param value: Boolean ... + */ + void DemandZoneFill(bool value) + { + mDemandZoneFill = value; + } + + /** + * Get Demand Zone Width ... + * + * @return ( int ) + */ + int DemandZoneWidth() + { + return mDemandZoneWidth; + } + + /** + * Set Demand Zone Width ... + * + * @param value: Integer ... + */ + void DemandZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mDemandZoneWidth = value; + } + + /** + * Get Demand Zone Color ... + * + * @return ( color ) + */ + color DemandZoneColor() + { + return mDemandZoneColor; + } + + /** + * Set Demand Zone Color ... + * + * @param value: Color ... + */ + void DemandZoneColor(color value) + { + mDemandZoneColor = value; + } + + /** + * Get Demand Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE DemandZoneStyle() + { + return mDemandZoneStyle; + } + + /** + * Set Demand Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void DemandZoneStyle(ENUM_LINE_STYLE value) + { + mDemandZoneStyle = value; + } + + // + // Resistance Zone ... + + /** + * Get Fill Resistance Zone ... + * + * @return ( bool ) + */ + bool ResistanceZoneFill() + { + return mResistanceZoneFill; + } + + /** + * Set Fill Resistance Zone ... + * + * @param value: Boolean ... + */ + void ResistanceZoneFill(bool value) + { + mResistanceZoneFill = value; + } + + /** + * Get Resistance Zone Width ... + * + * @return ( int ) + */ + int ResistanceZoneWidth() + { + return mResistanceZoneWidth; + } + + /** + * Set Resistance Zone Width ... + * + * @param value: Integer ... + */ + void ResistanceZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mResistanceZoneWidth = value; + } + + /** + * Get Resistance Zone Color ... + * + * @return ( color ) + */ + color ResistanceZoneColor() + { + return mResistanceZoneColor; + } + + /** + * Set Resistance Zone Color ... + * + * @param value: Color ... + */ + void ResistanceZoneColor(color value) + { + mResistanceZoneColor = value; + } + + /** + * Get Resistance Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE ResistanceZoneStyle() + { + return mResistanceZoneStyle; + } + + /** + * Set Resistance Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void ResistanceZoneStyle(ENUM_LINE_STYLE value) + { + mResistanceZoneStyle = value; + } + + // + // Support Zone ... + + /** + * Get Fill Support Zone ... + * + * @return ( bool ) + */ + bool SupportZoneFill() + { + return mSupportZoneFill; + } + + /** + * Set Fill Support Zone ... + * + * @param value: Boolean ... + */ + void SupportZoneFill(bool value) + { + mSupportZoneFill = value; + } + + /** + * Get Support Zone Width ... + * + * @return ( int ) + */ + int SupportZoneWidth() + { + return mSupportZoneWidth; + } + + /** + * Set Support Zone Width ... + * + * @param value: Integer ... + */ + void SupportZoneWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSupportZoneWidth = value; + } + + /** + * Get Support Zone Color ... + * + * @return ( color ) + */ + color SupportZoneColor() + { + return mSupportZoneColor; + } + + /** + * Set Support Zone Color ... + * + * @param value: Color ... + */ + void SupportZoneColor(color value) + { + mSupportZoneColor = value; + } + + /** + * Get Support Zone Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE SupportZoneStyle() + { + return mSupportZoneStyle; + } + + /** + * Set Support Zone Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void SupportZoneStyle(ENUM_LINE_STYLE value) + { + mSupportZoneStyle = value; + } + + // + // Bullish Order Block ... + + /** + * Get Fill Bullish Order Block ... + * + * @return ( bool ) + */ + bool BullishOrderBlockFill() + { + return mBullishOrderBlockFill; + } + + /** + * Set Fill Bullish Order Block ... + * + * @param value: Boolean ... + */ + void BullishOrderBlockFill(bool value) + { + mBullishOrderBlockFill = value; + } + + /** + * Get Bullish Order Block Width ... + * + * @return ( int ) + */ + int BullishOrderBlockWidth() + { + return mBullishOrderBlockWidth; + } + + /** + * Set Bullish Order Block Width ... + * + * @param value: Integer ... + */ + void BullishOrderBlockWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishOrderBlockWidth = value; + } + + /** + * Get Bullish Order Block Color ... + * + * @return ( color ) + */ + color BullishOrderBlockColor() + { + return mBullishOrderBlockColor; + } + + /** + * Set Bullish Order Block Color ... + * + * @param value: Color ... + */ + void BullishOrderBlockColor(color value) + { + mBullishOrderBlockColor = value; + } + + /** + * Get Bullish Order Block Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BullishOrderBlockStyle() + { + return mBullishOrderBlockStyle; + } + + /** + * Set Bullish Order Block Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BullishOrderBlockStyle(ENUM_LINE_STYLE value) + { + mBullishOrderBlockStyle = value; + } + + // + // Bearish Order Block ... + + /** + * Get Fill Bearish Order Block ... + * + * @return ( bool ) + */ + bool BearishOrderBlockFill() + { + return mBearishOrderBlockFill; + } + + /** + * Set Fill Bearish Order Block ... + * + * @param value: Boolean ... + */ + void BearishOrderBlockFill(bool value) + { + mBearishOrderBlockFill = value; + } + + /** + * Get Bearish Order Block Width ... + * + * @return ( int ) + */ + int BearishOrderBlockWidth() + { + return mBearishOrderBlockWidth; + } + + /** + * Set Bearish Order Block Width ... + * + * @param value: Integer ... + */ + void BearishOrderBlockWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishOrderBlockWidth = value; + } + + /** + * Get Bearish Order Block Color ... + * + * @return ( color ) + */ + color BearishOrderBlockColor() + { + return mBearishOrderBlockColor; + } + + /** + * Set Bearish Order Block Color ... + * + * @param value: Color ... + */ + void BearishOrderBlockColor(color value) + { + mBearishOrderBlockColor = value; + } + + /** + * Get Bearish Order Block Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BearishOrderBlockStyle() + { + return mBearishOrderBlockStyle; + } + + /** + * Set Bearish Order Block Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BearishOrderBlockStyle(ENUM_LINE_STYLE value) + { + mBearishOrderBlockStyle = value; + } + + // + // Bullish FVG ... + + /** + * Get Fill Bullish FVG ... + * + * @return ( bool ) + */ + bool BullishFVGFill() + { + return mBullishFVGFill; + } + + /** + * Set Fill Bullish FVG ... + * + * @param value: Boolean ... + */ + void BullishFVGFill(bool value) + { + mBullishFVGFill = value; + } + + /** + * Get Bullish FVG Width ... + * + * @return ( int ) + */ + int BullishFVGWidth() + { + return mBullishFVGWidth; + } + + /** + * Set Bullish FVG Width ... + * + * @param value: Integer ... + */ + void BullishFVGWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBullishFVGWidth = value; + } + + /** + * Get Bullish FVG Color ... + * + * @return ( color ) + */ + color BullishFVGColor() + { + return mBullishFVGColor; + } + + /** + * Set Bullish FVG Color ... + * + * @param value: Color ... + */ + void BullishFVGColor(color value) + { + mBullishFVGColor = value; + } + + /** + * Get Bullish FVG Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BullishFVGStyle() + { + return mBullishFVGStyle; + } + + /** + * Set Bullish FVG Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BullishFVGStyle(ENUM_LINE_STYLE value) + { + mBullishFVGStyle = value; + } + + // + // Bearish FVG ... + + /** + * Get Fill Bearish FVG ... + * + * @return ( bool ) + */ + bool BearishFVGFill() + { + return mBearishFVGFill; + } + + /** + * Set Fill Bearish FVG ... + * + * @param value: Boolean ... + */ + void BearishFVGFill(bool value) + { + mBearishFVGFill = value; + } + + /** + * Get Bearish FVG Width ... + * + * @return ( int ) + */ + int BearishFVGWidth() + { + return mBearishFVGWidth; + } + + /** + * Set Bearish FVG Width ... + * + * @param value: Integer ... + */ + void BearishFVGWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBearishFVGWidth = value; + } + + /** + * Get Bearish FVG Color ... + * + * @return ( color ) + */ + color BearishFVGColor() + { + return mBearishFVGColor; + } + + /** + * Set Bearish FVG Color ... + * + * @param value: Color ... + */ + void BearishFVGColor(color value) + { + mBearishFVGColor = value; + } + + /** + * Get Bearish FVG Style ... + * + * @return ( ENUM_LINE_STYLE ) + */ + ENUM_LINE_STYLE BearishFVGStyle() + { + return mBearishFVGStyle; + } + + /** + * Set Bearish FVG Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BearishFVGStyle(ENUM_LINE_STYLE value) + { + mBearishFVGStyle = value; + } + + // + // Virtuals ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Apply Default Props ... + + // + Prefix(NULL); + ChartIdentification(0); + SubWindowIdentification(0); + + // + BarWidth(1); + BarBearishColor(clrRed); + BarBullishColor(clrLime); + BarFillBody(false); + BarFillHighShadow(false); + BarFillLowShadow(false); + BarBodyStyle(STYLE_DOT); + BarLowShadowStyle(STYLE_DOT); + BarHighShadowStyle(STYLE_DOT); + + // + int arrowWidth = 1; + + // + SwingLowArrow(108); + SwingLowColor(clrAqua); + SwingLowWidth(arrowWidth); + + // + SwingHighArrow(108); + SwingHighWidth(arrowWidth); + SwingHighColor(clrMagenta); + + // + arrowWidth++; + + // + BullishMomentumBarArrow(225); + BullishMomentumBarWidth(arrowWidth); + BullishMomentumBarColor(clrAqua); + + // + BearishMomentumBarArrow(226); + BearishMomentumBarWidth(arrowWidth); + BearishMomentumBarColor(clrMagenta); + + // + arrowWidth++; + + // + BullishRejectionBarArrow(217); + BullishRejectionBarWidth(arrowWidth); + BullishRejectionBarColor(clrAqua); + + // + BearishRejectionBarArrow(218); + BearishRejectionBarWidth(arrowWidth); + BearishRejectionBarColor(clrMagenta); + + // + SupportZoneFill(false); + SupportZoneWidth(1); + SupportZoneStyle(STYLE_DOT); + SupportZoneColor(clrLime); + + // + ResistanceZoneFill(false); + ResistanceZoneWidth(1); + ResistanceZoneStyle(STYLE_DOT); + ResistanceZoneColor(clrRed); + + // + SupplyZoneFill(false); + SupplyZoneWidth(1); + SupplyZoneStyle(STYLE_DOT); + SupplyZoneColor(clrRed); + + // + DemandZoneFill(false); + DemandZoneWidth(1); + DemandZoneStyle(STYLE_DOT); + DemandZoneColor(clrGreen); + + // + BullishOrderBlockFill(false); + BullishOrderBlockWidth(1); + BullishOrderBlockStyle(STYLE_DASHDOT); + BullishOrderBlockColor(clrLime); + + // + BearishOrderBlockFill(false); + BearishOrderBlockWidth(1); + BearishOrderBlockStyle(STYLE_DASHDOT); + BearishOrderBlockColor(clrRed); + + // + BullishFVGFill(false); + BullishFVGWidth(1); + BullishFVGStyle(STYLE_DOT); + BullishFVGColor(clrLime); + + // + BearishFVGFill(false); + BearishFVGWidth(1); + BearishFVGStyle(STYLE_DOT); + BearishFVGColor(clrRed); + + // + // Add Default TickZone Specs ... + bool isSpecsInited = false; + bool fillTickZone = false; + XTickZoneLevelSpecs specs10; + isSpecsInited = specs10.Init( + 10, + clrWhite, + clrWhite, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs10); + } + + // + XTickZoneLevelSpecs specs20; + isSpecsInited = specs20.Init( + 20, + clrOrange, + clrOrange, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs20); + } + + // + XTickZoneLevelSpecs specs30; + isSpecsInited = specs30.Init( + 30, + clrOrange, + clrOrange, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs30); + } + + // + XTickZoneLevelSpecs specs40; + isSpecsInited = specs40.Init( + 40, + clrOrange, + clrOrange, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs40); + } + + // + XTickZoneLevelSpecs specs50; + isSpecsInited = specs50.Init( + 50, + clrYellow, + clrYellow, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs50); + } + + // + XTickZoneLevelSpecs specs60; + isSpecsInited = specs60.Init( + 60, + clrYellow, + clrYellow, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs60); + } + + // + XTickZoneLevelSpecs specs70; + isSpecsInited = specs70.Init( + 70, + clrYellow, + clrYellow, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs70); + } + + // + XTickZoneLevelSpecs specs80; + isSpecsInited = specs80.Init( + 80, + clrRed, + clrRed, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs80); + } + + // + XTickZoneLevelSpecs specs90; + isSpecsInited = specs90.Init( + 90, + clrRed, + clrRed, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs90); + } + + // + XTickZoneLevelSpecs specs100; + isSpecsInited = specs100.Init( + 100, + clrRed, + clrRed, + fillTickZone // + ); + if (isSpecsInited) + { + AddTickZoneLevelSpecs(specs100); + } + + // + } + + // + // Object Creators ... + + // + // Swings ... + + /** + * Create Swing High Object ... + * + * @param swing: XCSwing instance ... + * @param object: XCSwingHighObject pointer ... + * + * @return ( bool ) + */ + bool CreateSwingHigh( + XCSwing &swing, + XCSwingHighObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + swing.IsValid() && + swing.IsSwingHigh(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = SwingHighArrow(); + int width = SwingHighWidth(); + color crl = SwingHighColor(); + + // + object = new XCSwingHighObject(); + result = object.Create( + chartID, + window, + arrow, + swing, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_BOTTOM); + + // + return result; + } + + /** + * Create Swing Low Object ... + * + * @param swing: XCSwing instance ... + * @param object: XCSwingLowObject pointer ... + * + * @return ( bool ) + */ + bool CreateSwingLow( + XCSwing &swing, + XCSwingLowObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + swing.IsValid() && + swing.IsSwingLow(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = SwingLowArrow(); + int width = SwingLowWidth(); + color crl = SwingLowColor(); + + // + object = new XCSwingLowObject(); + result = object.Create( + chartID, + window, + arrow, + swing, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_TOP); + + // + return result; + } + + // + // Momentum Bars ... + + /** + * Create Bullish Momentum Bar Object ... + * + * @param momentumBar: XCMomentumBar instance ... + * @param object: XCBullishMomentumObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishMomentumBar( + XCMomentumBar &momentumBar, + XCBullishMomentumBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + momentumBar.IsValid() && + momentumBar.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BullishMomentumBarArrow(); + int width = BullishMomentumBarWidth(); + color crl = BullishMomentumBarColor(); + + // + object = new XCBullishMomentumBarObject(); + result = object.Create( + chartID, + window, + arrow, + momentumBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_TOP); + + // + return result; + } + + /** + * Create Bearish Momentum Bar Object ... + * + * @param momentumBar: XCMomentumBar instance ... + * @param object: XCBearishMomentumObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishMomentumBar( + XCMomentumBar &momentumBar, + XCBearishMomentumBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + momentumBar.IsValid() && + momentumBar.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BearishMomentumBarArrow(); + int width = BearishMomentumBarWidth(); + color crl = BearishMomentumBarColor(); + + // + object = new XCBearishMomentumBarObject(); + result = object.Create( + chartID, + window, + arrow, + momentumBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_BOTTOM); + + // + return result; + } + + // + // Rejection Bars ... + + /** + * Create Bullish Rejection Bar Object ... + * + * @param momentumBar: XCRejectionBar instance ... + * @param object: XCBullishRejectionObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishRejectionBar( + XCRejectionBar &rejectionBar, + XCBullishRejectionBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + rejectionBar.IsValid() && + rejectionBar.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BullishRejectionBarArrow(); + int width = BullishRejectionBarWidth(); + color crl = BullishRejectionBarColor(); + + // + object = new XCBullishRejectionBarObject(); + result = object.Create( + chartID, + window, + arrow, + rejectionBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_TOP); + + // + return result; + } + + /** + * Create Bearish Rejection Bar Object ... + * + * @param rejectionBar: XCRejectionBar instance ... + * @param object: XCBearishRejectionObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishRejectionBar( + XCRejectionBar &rejectionBar, + XCBearishRejectionBarObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + rejectionBar.IsValid() && + rejectionBar.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int arrow = BearishRejectionBarArrow(); + int width = BearishRejectionBarWidth(); + color crl = BearishRejectionBarColor(); + + // + object = new XCBearishRejectionBarObject(); + result = object.Create( + chartID, + window, + arrow, + rejectionBar, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ArrowColor(crl); + object.ArrowWidth(width); + object.ArrowAnchor(ANCHOR_BOTTOM); + + // + return result; + } + + // + // Support and Resistance ... + + /** + * Create Support Object ... + * + * @param zone: XCSupportZone instance ... + * @param object: XCSupportZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateSupportZone( + XCSupportZone &zone, + XCSupportZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = SupportZoneFill(); + int width = SupportZoneWidth(); + color crl = SupportZoneColor(); + ENUM_LINE_STYLE style = SupportZoneStyle(); + + // + object = new XCSupportZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Resistance Object ... + * + * @param zone: XCResistanceZone instance ... + * @param object: XCResistanceZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateResistanceZone( + XCResistanceZone &zone, + XCResistanceZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = ResistanceZoneFill(); + int width = ResistanceZoneWidth(); + color crl = ResistanceZoneColor(); + ENUM_LINE_STYLE style = ResistanceZoneStyle(); + + // + object = new XCResistanceZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + // + // Supply and Demand Zones ... + + /** + * Create Supply Object ... + * + * @param zone: XCSupplyZone instance ... + * @param object: XCSupplyZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateSupplyZone( + XCSupplyZone &zone, + XCSupplyZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = SupplyZoneFill(); + int width = SupplyZoneWidth(); + color crl = SupplyZoneColor(); + ENUM_LINE_STYLE style = SupplyZoneStyle(); + + // + object = new XCSupplyZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Demand Object ... + * + * @param zone: XCDemandZone instance ... + * @param object: XCDemandZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateDemandZone( + XCDemandZone &zone, + XCDemandZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = DemandZoneFill(); + int width = DemandZoneWidth(); + color crl = DemandZoneColor(); + ENUM_LINE_STYLE style = DemandZoneStyle(); + + // + object = new XCDemandZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + // + // Order Blocks ... + + /** + * Create Bullish Order Block Object ... + * + * @param zone: XCOrderBlock instance ... + * @param object: XCBullishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishOrderBlock( + XCOrderBlock &zone, + XCBullishOrderBlockObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BullishOrderBlockFill(); + int width = BullishOrderBlockWidth(); + color crl = BullishOrderBlockColor(); + ENUM_LINE_STYLE style = BullishOrderBlockStyle(); + + // + object = new XCBullishOrderBlockObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Bearish Order Block Object ... + * + * @param zone: XCOrderBlock instance ... + * @param object: XCBearishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishOrderBlock( + XCOrderBlock &zone, + XCBearishOrderBlockObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = + zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BearishOrderBlockFill(); + int width = BearishOrderBlockWidth(); + color crl = BearishOrderBlockColor(); + ENUM_LINE_STYLE style = BearishOrderBlockStyle(); + + // + object = new XCBearishOrderBlockObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + // + // Fair Value Gaps ... + + /** + * Create Bullish Fair Value Gap Object ... + * + * @param zone: XCFVG instance ... + * @param object: XCBullishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBullishFairValueGap( + XCFVG &zone, + XCBullishFairValueGapObject *&object // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBullish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BullishFVGFill(); + int width = BullishFVGWidth(); + color crl = BullishFVGColor(); + ENUM_LINE_STYLE style = BullishFVGStyle(); + + // + object = new XCBullishFairValueGapObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + /** + * Create Bearish Fair Value Gap Object ... + * + * @param zone: XCFVG instance ... + * @param object: XCBearishOrderBlockObject pointer ... + * + * @return ( bool ) + */ + bool CreateBearishFairValueGap( + XCFVG &zone, + XCBearishFairValueGapObject *&object // + ) + { + // + bool result = false; + + // + result = zone.IsValid() && + zone.IsBearish(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + bool fill = BearishFVGFill(); + int width = BearishFVGWidth(); + color crl = BearishFVGColor(); + ENUM_LINE_STYLE style = BearishFVGStyle(); + + // + object = new XCBearishFairValueGapObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.ZoneFill(fill); + object.ZoneColor(crl); + object.ZoneWidth(width); + object.ZoneStyle(style); + + // + return result; + } + + // + // Ticks Zone ... + + /** + * Add Tick Zone Draw Specifications ... + * + * @param specs: XTickZoneLevelSpecs instance ... + */ + void AddTickZoneLevelSpecs( + XTickZoneLevelSpecs &specs // + ) + { + // + if (!specs.IsValid()) + { + return; + } + + // + bool isExists = false; + int count = ArraySize(mTicksZoneSpecs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XTickZoneLevelSpecs iSpec = mTicksZoneSpecs[i]; + + // + isExists = specs.percent == iSpec.percent; + if (isExists) + { + break; + } + } + } + if (isExists) + { + return; + } + + // + AddRef( + specs, + mTicksZoneSpecs // + ); + } + + /** + * Draw Specified Ticker Zone ... + * + * @param zone: XCTicksZone instance Specified Ticker Zone ... + * @param object: XCTicksZoneObject pointer ... + * + * @return ( bool ) + */ + bool CreateTicksZone( + XCTicksZone &zone, + XCTicksZoneObject *&object // + ) + { + // + bool result = false; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCTicksZoneObject(); + result = object.Create( + chartID, + window, + zone, + mTicksZoneSpecs, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Create Consolidation Zone Object ... + * + * @param zone: XConsolidationZone instance Reference ... + * + * @return ( bool ) + */ + bool CreateConsolidationZone( + XConsolidationZone &zone, + XCConsolidationZoneObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCConsolidationZoneObject(); + result = object.Create( + chartID, + window, + zone, + prefix // + ); + + // + return result; + } + + /** + * Create Bar Object ... + * + * @param bar: XOHCL instance Reference .. + * @param object: XCOHCLObject pointer Reference .. + * @param to: Datetime ... + * + * @return ( bool ) + */ + bool CreateBar( + XOHCL &bar, + XCOHCLObject *&object, + datetime to = NULL // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + to = NormalizeTime(to); + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + int width = BarWidth(); + + // + color bullishColor = BarBullishColor(); + color bearishColor = BarBearishColor(); + + // + bool fillBody = BarFillBody(); + bool fillHighShadow = BarFillHighShadow(); + bool fillLowShadow = BarFillLowShadow(); + + // + ENUM_LINE_STYLE bodyStyle = BarBodyStyle(); + ENUM_LINE_STYLE highShadowStyle = BarHighShadowStyle(); + ENUM_LINE_STYLE lowShadowStyle = BarLowShadowStyle(); + + // + object = new XCOHCLObject(); + result = object.Create( + chartID, + window, + bar, + to, + prefix // + ); + if (result) + { + // + // Apply Styling ... + + // + object.BodyWidth(width); + object.LowShadowWidth(width); + object.HighShadowWidth(width); + + // + object.BodyStyle(bodyStyle); + object.LowShadowStyle(lowShadowStyle); + object.HighShadowStyle(highShadowStyle); + + // + bool isBullish = bar.IsBullish(); + if (isBullish) + { + // + object.BodyColor(bullishColor); + object.LowShadowColor(bullishColor); + object.HighShadowColor(bullishColor); + } + else + { + // + object.BodyColor(bearishColor); + object.LowShadowColor(bearishColor); + object.HighShadowColor(bearishColor); + } + + // + object.BodyFill(fillBody); + object.HighShadowFill(fillHighShadow); + object.LowShadowFill(fillLowShadow); + } + + // + return result; + } + + /** + * Create Specific Box on Chart ... + * + * @param upper: Double ... + * @param lower: Double ... + * @param from: Datetime ... + * @param to: Datetime ... + * @param clr: Color ... + * @param width: Integer ... + * @param fill: Boolean ... + * @param style: ENUM_LINE_STYLE member ... + * + * @return ( bool ) + */ + bool CreateBox( + XCBoxObject *&object, + double upper, + double lower, + datetime from, + datetime to, + color clr = clrYellowGreen, + int width = 1, + bool fill = false, + ENUM_LINE_STYLE style = STYLE_SOLID // + ) + { + // + bool result = false; + + // + object = NULL; + + // + to = NormalizeTime(to); + + // + string dateStr = ToFormatString(from) + "|" + ToFormatString(to); + string dateMD5 = ToMD5(dateStr); + string name = "XBox_" + + ToString(upper) + "_" + + ToString(lower) + "_" + + dateMD5; + + // + result = + upper > 0 && + lower > 0 && + to > from && + IsValid(to) && + IsValid(name) && + IsValid(from) && + upper > lower; + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCBoxObject(); + result = object.Create( + chartID, + window, + name, + upper, + lower, + from, + to, + prefix // + ); + + // + if (!result) + { + return result; + } + + // + object.BoxColor(clr); + object.BoxFill(fill); + object.BoxWidth(width); + object.BoxStyle(style); + + // + return result; + } + + /** + * Draw Specified Signal ... + * + * @param signal: XSignal instance ... + */ + bool DrawSignal( + XSignal &signal, + XCSignalObject *&object // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCSignalObject(); + result = object.Create( + chartID, + window, + signal, + prefix // + ); + if (!result) + { + return result; + } + + // + object.TPWidth(1); + object.TPColor(clrGreen); + object.TPWidth(STYLE_DOT); + + // + object.SLWidth(1); + object.SLColor(clrRed); + object.SLWidth(STYLE_DOT); + + // + object.TargetWidth(1); + object.TargetColor(clrLightBlue); + object.TargetWidth(STYLE_DOT); + + // + object.EntryWidth(1); + object.EntryColor(clrYellow); + object.EntryWidth(STYLE_DOT); + + // + return result; + } + + /** + * Draw Price Zone ... + * + * @param zone: XPriceZones instance Reference ... + * @param forDir: ENUM_X_DIRECTION member ... + * + * @return ( int ) + */ + int DrawPriceZone( + XPriceZones &zone, + XCBaseObject *&drawnObjects[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE, + bool onlyBoundary = false // + ) + { + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (!zone.IsValid()) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + bool isBearish = IsBearish(forDir); + bool isAll = forDir == X_DIRECTION_ALL || + forDir == X_DIRECTION_NONE; + + // + if (isAll || isBullish) + { + // + if (onlyBoundary) + { + // + double upper = 0; + double lower = 0; + datetime to = NULL; + datetime from = NULL; + + // + bool isRetrieved = zone.GetBoxData( + X_DIRECTION_NONE, + upper, + lower, + from, + to // + ); + if (isRetrieved) + { + // + color clr = + isBullish + ? BarBullishColor() + : isBearish + ? BarBearishColor() + : clrGray; + XCBoxObject *iObj; + result = CreateBox( + iObj, + upper, + lower, + from, + to, + clr, + 1, + false, + STYLE_DOT // + ); + if (result) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + else + { + // + // Support Zone ... + if (zone.HasSupportZone()) + { + // + XCSupportZoneObject *iObj; + bool isCreated = CreateSupportZone( + zone.supportZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // Demand Zone ... + if (zone.HasDemandZone()) + { + // + XCDemandZoneObject *iObj; + bool isCreated = CreateDemandZone( + zone.demandZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // OrderBlock ... + if (zone.HasOrderBlock() && + zone.orderBlock.IsBullish()) + { + // + XCBullishOrderBlockObject *iObj; + bool isCreated = CreateBullishOrderBlock( + zone.orderBlock, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // FairValueGap ... + if (zone.HasFairValueGap() && + zone.fairValueGap.IsBullish()) + { + // + XCBullishFairValueGapObject *iObj; + bool isCreated = CreateBullishFairValueGap( + zone.fairValueGap, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + if (isAll || isBearish) + { + // + if (onlyBoundary) + { + // + double upper = 0; + double lower = 0; + datetime to = NULL; + datetime from = NULL; + + // + bool isRetrieved = zone.GetBoxData( + X_DIRECTION_NONE, + upper, + lower, + from, + to // + ); + if (isRetrieved) + { + // + color clr = + isBullish + ? BarBullishColor() + : isBearish + ? BarBearishColor() + : clrGray; + XCBoxObject *iObj; + result = CreateBox( + iObj, + upper, + lower, + from, + to, + clr, + 1, + false, + STYLE_DOT // + ); + if (result) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + else + { + // + // Resistance Zone ... + if (zone.HasResistanceZone()) + { + // + XCResistanceZoneObject *iObj; + bool isCreated = CreateResistanceZone( + zone.resistanceZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // Supply Zone ... + if (zone.HasSupplyZone()) + { + // + XCSupplyZoneObject *iObj; + bool isCreated = CreateSupplyZone( + zone.supplyZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // OrderBlock ... + if (zone.HasOrderBlock() && + zone.orderBlock.IsBearish()) + { + // + XCBearishOrderBlockObject *iObj; + bool isCreated = CreateBearishOrderBlock( + zone.orderBlock, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // FairValueGap ... + if (zone.HasFairValueGap() && + zone.fairValueGap.IsBearish()) + { + // + XCBearishFairValueGapObject *iObj; + bool isCreated = CreateBearishFairValueGap( + zone.fairValueGap, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + /** + * Draw Specified State Zone ... + * + * @param source: XStateZones instance Reference ... + * + * @return ( int ) + */ + int DrawStateZones( + XStateZones &source, + XCBaseObject *&drawnObjects[] // + ) + { + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (!source.IsValid()) + { + return result; + } + + // + // SupportZones ... + int count = source.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = source.supportZones[i]; + XCSupportZoneObject *iObj; + + // + bool isCreated = CreateSupportZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // ResistanceZones ... + count = source.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = source.resistanceZones[i]; + XCResistanceZoneObject *iObj; + + // + bool isCreated = CreateResistanceZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // SupplyZones ... + count = source.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = source.supplyZones[i]; + XCSupplyZoneObject *iObj; + + // + bool isCreated = CreateSupplyZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // DemandZones ... + count = source.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = source.demandZones[i]; + XCDemandZoneObject *iObj; + + // + bool isCreated = CreateDemandZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // BullishOrderBlocks ... + count = source.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = source.bullishOrderBlocks[i]; + XCBullishOrderBlockObject *iObj; + + // + bool isCreated = CreateBullishOrderBlock( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // BearishOrderBlocks ... + count = source.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = source.bearishOrderBlocks[i]; + XCBearishOrderBlockObject *iObj; + + // + bool isCreated = CreateBearishOrderBlock( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // BullishFairValueGaps ... + count = source.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = source.bullishFairValueGaps[i]; + XCBullishFairValueGapObject *iObj; + + // + bool isCreated = CreateBullishFairValueGap( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // BearishFairValueGaps ... + count = source.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = source.bearishFairValueGaps[i]; + XCBearishFairValueGapObject *iObj; + + // + bool isCreated = CreateBearishFairValueGap( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + /** + * Draw Specified Market Structure ... + * + * @param model: XMarketStructure instance Reference ... + * + * @return ( int ) + */ + int DrawMarketStructure( + XMarketStructure &model, + XCBaseObject *&drawnObjects[] // + ) + { + // + int result = 0; + + // + Clean(drawnObjects); + + // + datetime cTime = TimeCurrent(); + + // + bool isValid = + model.IsValid(); + if (!isValid) + { + return result; + } + + // + if (model.lowestValeBar.IsValid()) + { + // + XCOHCLObject *iObj; + bool isCreated = CreateBar( + model.lowestValeBar, + iObj, + cTime // + ); + + // + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + if (model.lowestValePeakBreakeUpBar.IsValid()) + { + // + XCOHCLObject *iObj; + bool isCreated = CreateBar( + model.lowestValePeakBreakeUpBar, + iObj, + cTime // + ); + + // + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + if (model.valeAboveLowestValePeakBar.IsValid()) + { + // + XCOHCLObject *iObj; + bool isCreated = CreateBar( + model.valeAboveLowestValePeakBar, + iObj, + cTime // + ); + + // + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + if (model.highestPeakBar.IsValid()) + { + // + XCOHCLObject *iObj; + bool isCreated = CreateBar( + model.highestPeakBar, + iObj, + cTime // + ); + + // + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + if (model.peakBelowHighestPeakValeBar.IsValid()) + { + // + XCOHCLObject *iObj; + bool isCreated = CreateBar( + model.peakBelowHighestPeakValeBar, + iObj, + cTime // + ); + + // + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + if (model.highestPeakValeBreakeDownBar.IsValid()) + { + // + XCOHCLObject *iObj; + bool isCreated = CreateBar( + model.highestPeakValeBreakeDownBar, + iObj, + cTime // + ); + + // + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + if (HasChild(model.valePriceZones)) + { + // + int count = ArraySize(model.valePriceZones); + for (int i = 0; i < count; i++) + { + // + XPriceZones ipZone = model.valePriceZones[i]; + + // + XCBaseObject *ipObjects[]; + int ipDrawnObjects = DrawPriceZone( + ipZone, + ipObjects, + model.bias // + ); + if (IsValidSize(ipObjects)) + { + // + Copy( + ipObjects, + drawnObjects, + false // + ); + } + } + } + + // + if (HasChild(model.peakPriceZones)) + { + // + int count = ArraySize(model.peakPriceZones); + for (int i = 0; i < count; i++) + { + // + XPriceZones ipZone = model.peakPriceZones[i]; + + // + XCBaseObject *ipObjects[]; + int ipDrawnObjects = DrawPriceZone( + ipZone, + ipObjects, + model.bias // + ); + if (IsValidSize(ipObjects)) + { + // + Copy( + ipObjects, + drawnObjects, + false // + ); + } + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + /** + * Draw Specified POI State ... + * + * @param state: XPOIState instance Reference ... + * @param drawnObjects: CArrayObj instance for Holding Drawn Objects ... + * @param drawTicksZone: Boolean ... + * @param ignoreSwingHighs: Boolean ... + * @param ignoreSwingLows: Boolean ... + * @param ignoreSupportZones: Boolean ... + * @param ignoreResistanceZones: Boolean ... + * @param ignoreSupplyZones: Boolean ... + * @param ignoreDemandZones: Boolean ... + * @param ignoreBullishOrderBlocks: Boolean ... + * @param ignoreBearishOrderBlocks: Boolean ... + * @param ignoreBullishFairValueGaps: Boolean ... + * @param ignoreBearishFairValueGaps: Boolean ... + * @param ignoreBullishRejectionBars: Boolean ... + * @param ignoreBearishRejectionBars: Boolean ... + * @param ignoreBullishMomentumBars: Boolean ... + * @param ignoreBearishMomentumBars: Boolean ... + */ + int DrawState( + XPOIState &state, + XCBaseObject *&drawnObjects[], + bool drawTicksZone = false, + bool ignoreSwingHighs = false, + bool ignoreSwingLows = false, + bool ignoreSupportZones = false, + bool ignoreResistanceZones = false, + bool ignoreSupplyZones = false, + bool ignoreDemandZones = false, + bool ignoreBullishOrderBlocks = false, + bool ignoreBearishOrderBlocks = false, + bool ignoreBullishFairValueGaps = false, + bool ignoreBearishFairValueGaps = false, + bool ignoreBullishRejectionBars = false, + bool ignoreBearishRejectionBars = false, + bool ignoreBullishMomentumBars = false, + bool ignoreBearishMomentumBars = false // + ) + { + // + int result = 0; + + // + if (!state.IsValid() || + !state.HasChild()) + { + return result; + } + + // + Clean(drawnObjects); + + // + // SwingHighs ... + if (!ignoreSwingHighs) + { + // + int count = state.CountSwingHighs(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = state.swingHighs[i]; + XCSwingHighObject *iObj; + + // + bool isCreated = CreateSwingHigh( + iSwing, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // SwingLows ... + if (!ignoreSwingLows) + { + // + int count = state.CountSwingLows(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = state.swingLows[i]; + XCSwingLowObject *iObj; + + // + bool isCreated = CreateSwingLow( + iSwing, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // SupportZones ... + if (!ignoreSupportZones) + { + // + int count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = state.supportZones[i]; + XCSupportZoneObject *iObj; + + // + bool isCreated = CreateSupportZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // ResistanceZones ... + if (!ignoreResistanceZones) + { + // + int count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = state.resistanceZones[i]; + XCResistanceZoneObject *iObj; + + // + bool isCreated = CreateResistanceZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // SupplyZones ... + if (!ignoreSupplyZones) + { + // + int count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = state.supplyZones[i]; + XCSupplyZoneObject *iObj; + + // + bool isCreated = CreateSupplyZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // DemandZones ... + if (!ignoreDemandZones) + { + // + int count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = state.demandZones[i]; + XCDemandZoneObject *iObj; + + // + bool isCreated = CreateDemandZone( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishOrderBlocks ... + if (!ignoreBullishOrderBlocks) + { + // + int count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = state.bullishOrderBlocks[i]; + XCBullishOrderBlockObject *iObj; + + // + bool isCreated = CreateBullishOrderBlock( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishOrderBlocks ... + if (!ignoreBearishOrderBlocks) + { + // + int count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = state.bearishOrderBlocks[i]; + XCBearishOrderBlockObject *iObj; + + // + bool isCreated = CreateBearishOrderBlock( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishFairValueGaps ... + if (!ignoreBullishFairValueGaps) + { + // + int count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = state.bullishFairValueGaps[i]; + XCBullishFairValueGapObject *iObj; + + // + bool isCreated = CreateBullishFairValueGap( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishFairValueGaps ... + if (!ignoreBearishFairValueGaps) + { + // + int count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = state.bearishFairValueGaps[i]; + XCBearishFairValueGapObject *iObj; + + // + bool isCreated = CreateBearishFairValueGap( + iZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishRejectionBars ... + if (!ignoreBullishRejectionBars) + { + // + int count = state.CountBullishRejectionBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iBar = state.bullishRejectionBars[i]; + XCBullishRejectionBarObject *iObj; + + // + bool isCreated = CreateBullishRejectionBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishRejectionBars ... + if (!ignoreBearishRejectionBars) + { + // + int count = state.CountBearishRejectionBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iBar = state.bearishRejectionBars[i]; + XCBearishRejectionBarObject *iObj; + + // + bool isCreated = CreateBearishRejectionBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BullishMomentumBars ... + if (!ignoreBullishMomentumBars) + { + // + int count = state.CountBullishMomentumBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCMomentumBar *iBar = state.bullishMomentumBars[i]; + XCBullishMomentumBarObject *iObj; + + // + bool isCreated = CreateBullishMomentumBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + // BearishMomentumBars ... + if (!ignoreBearishMomentumBars) + { + // + int count = state.CountBearishMomentumBars(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCMomentumBar *iBar = state.bearishMomentumBars[i]; + XCBearishMomentumBarObject *iObj; + + // + bool isCreated = CreateBearishMomentumBar( + iBar, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + } + + // + if (drawTicksZone && state.ticksZone != NULL) + { + // + XCTicksZoneObject *iObj; + bool isCreated = CreateTicksZone( + state.ticksZone, + iObj // + ); + if (isCreated) + { + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + /** + * Draw Specific Pivot ... + * + * @param pivot: XPVPivot instance Reference ... + * @param drawState: Boolean ... + * @param drawTicksZone: Boolean ... + * @param ignoreSwingHighs: Boolean ... + * @param ignoreSwingLows: Boolean ... + * @param ignoreSupportZones: Boolean ... + * @param ignoreResistanceZones: Boolean ... + * @param ignoreSupplyZones: Boolean ... + * @param ignoreDemandZones: Boolean ... + * @param ignoreBullishOrderBlocks: Boolean ... + * @param ignoreBearishOrderBlocks: Boolean ... + * @param ignoreBullishFairValueGaps: Boolean ... + * @param ignoreBearishFairValueGaps: Boolean ... + * @param ignoreBullishRejectionBars: Boolean ... + * @param ignoreBearishRejectionBars: Boolean ... + * @param ignoreBullishMomentumBars: Boolean ... + * @param ignoreBearishMomentumBars: Boolean ... + */ + int DrawPivot( + XPVPivot &pivot, + XCBaseObject *&drawnObjects[], + bool drawState = false, + bool drawStateAsBox = false, + bool drawTicksZone = false, + bool ignoreSwingHighs = false, + bool ignoreSwingLows = false, + bool ignoreSupportZones = false, + bool ignoreResistanceZones = false, + bool ignoreSupplyZones = false, + bool ignoreDemandZones = false, + bool ignoreBullishOrderBlocks = false, + bool ignoreBearishOrderBlocks = false, + bool ignoreBullishFairValueGaps = false, + bool ignoreBearishFairValueGaps = false, + bool ignoreBullishRejectionBars = false, + bool ignoreBearishRejectionBars = false, + bool ignoreBullishMomentumBars = false, + bool ignoreBearishMomentumBars = false // + ) + { + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (!pivot.IsValid()) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + // Draw Pivot it self ... + XCXPVPivotObject *iPivotObj; + iPivotObj = new XCXPVPivotObject(); + bool isCreated = iPivotObj.Create( + chartID, + window, + pivot, + prefix // + ); + if (!isCreated) + { + return result; + } + + // + color clrPivotColor = pivot.IsPeak() + ? clrAqua + : clrMagenta; + iPivotObj.PivotColor(clrPivotColor); + iPivotObj.PivotWidth(2); + + // + Add( + (XCBaseObject *)iPivotObj, + drawnObjects // + ); + + // + result = ArraySize(drawnObjects); + + // + if (!drawState) + { + return result; + } + + // + if (!pivot.state.IsValid()) + { + return result; + } + + // + XCBaseObject *stateObjects[]; + int stateCount = 0; + + // + if (!drawStateAsBox) + { + // + stateCount = DrawState( + pivot.state, + stateObjects, + drawTicksZone, + ignoreSwingHighs, + ignoreSwingLows, + ignoreSupportZones, + ignoreResistanceZones, + ignoreSupplyZones, + ignoreDemandZones, + ignoreBullishOrderBlocks, + ignoreBearishOrderBlocks, + ignoreBullishFairValueGaps, + ignoreBearishFairValueGaps, + ignoreBullishRejectionBars, + ignoreBearishRejectionBars, + ignoreBullishMomentumBars, + ignoreBearishMomentumBars // + ); + } + else + { + // + double peakUpper = 0; + double peakLower = 0; + double valeUpper = 0; + double valeLower = 0; + + // + datetime peakTo = NULL; + datetime valeTo = NULL; + datetime peakFrom = NULL; + datetime valeFrom = NULL; + + // + bool hasBoxData = DetectPivotStateBoxData( + pivot, + peakUpper, + peakLower, + peakFrom, + peakTo, + valeUpper, + valeLower, + valeFrom, + valeTo // + ); + + // + if (hasBoxData) + { + // + XCBoxObject *peakBox; + bool isCreated = CreateBox( + peakBox, + peakUpper, + peakLower, + peakFrom, + peakTo, + clrMagenta, + 1, + false, + STYLE_DASHDOT // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)peakBox, + stateObjects // + ); + } + + // + XCBoxObject *valeBox; + isCreated = CreateBox( + valeBox, + valeUpper, + valeLower, + valeFrom, + valeTo, + clrAqua, + 1, + false, + STYLE_DASHDOT // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)valeBox, + stateObjects // + ); + } + } + } + + // + if (IsValidSize(stateCount)) + { + // + Copy( + stateObjects, + drawnObjects, + false // Doesn't Clean ... + ); + + // + ArrayFree(stateObjects); + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + /** + * Draw Specified XFVGOrderBlock Object ... + * + * @param models: XFVGOrderBlock instance Reference ... + * + * @return ( int ) + */ + int DrawFVGOrderBlock( + XFVGOrderBlock &model, + XCBaseObject *&drawnObjects[] // + ) + { + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (!model.IsValid()) + { + return result; + } + + // + ENUM_X_DIRECTION iDir; + result = model.GetDirection(iDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(iDir); + if (isBullish) + { + // + // Order Block ... + XCBullishOrderBlockObject *iOBObj; + bool isCreated = CreateBullishOrderBlock( + model.orderBlock, + iOBObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iOBObj, + drawnObjects // + ); + } + + // + // FVG ... + XCBullishFairValueGapObject *iFVGObj; + isCreated = CreateBullishFairValueGap( + model.fairValueGap, + iFVGObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iOBObj, + drawnObjects // + ); + } + } + else + { + // + // Order Block ... + XCBearishOrderBlockObject *iOBObj; + bool isCreated = CreateBearishOrderBlock( + model.orderBlock, + iOBObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iOBObj, + drawnObjects // + ); + } + + // + // FVG ... + XCBearishFairValueGapObject *iFVGObj; + isCreated = CreateBearishFairValueGap( + model.fairValueGap, + iFVGObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iFVGObj, + drawnObjects // + ); + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + // Props ... + + // + string mPrefix; // Prefix of Created Objects ... + long mChartIdentification; // Chart Id ... + int mSubWindowIdentification; // Sub Window ... + + // + // XOHCL ... + int mBarWidth; // Bar Width ... + color mBarBullishColor; // Bar Bullish Color ... + color mBarBearishColor; // Bar Bearish Color ... + bool mBarFillHighShadow; // Fill Bar High Shadow ... + ENUM_LINE_STYLE mBarHighShadowStyle; // Bar High Shadow Style ... + bool mBarFillBody; // Fill Bar Body ... + ENUM_LINE_STYLE mBarBodyStyle; // Bar Body Style ... + bool mBarFillLowShadow; // Fill Bar Low Show ... + ENUM_LINE_STYLE mBarLowShadowStyle; // Bar Low Shadow Style ... + + // + // Swing Low ... + int mSwingLowWidth; // Swing Low Width ... + int mSwingLowArrow; // Swing Low Arrow Code ... + color mSwingLowColor; // Swing Low Color ... + + // + // Swing High ... + int mSwingHighWidth; // Swing High Width ... + int mSwingHighArrow; // Swing High Arrow Code ... + color mSwingHighColor; // Swing High Color ... + + // + // Bullish Momentum Bar ... + int mBullishMomentumBarWidth; // Bullish Momentum Bar Width ... + int mBullishMomentumBarArrow; // Bullish Momentum Bar Arrow Code ... + color mBullishMomentumBarColor; // Bullish Momentum Bar Color ... + + // + // Bearish Momentum Bar ... + int mBearishMomentumBarWidth; // Bearish Momentum Bar Width ... + int mBearishMomentumBarArrow; // Bearish Momentum Bar Arrow Code ... + color mBearishMomentumBarColor; // Bearish Momentum Bar Color ... + + // + // Bullish Rejection Bar ... + int mBullishRejectionBarWidth; // Bullish Rejection Bar High Width ... + int mBullishRejectionBarArrow; // Bullish Rejection Bar High Arrow Code ... + color mBullishRejectionBarColor; // Bullish Rejection Bar High Color ... + + // + // Bearish Rejection Bar ... + int mBearishRejectionBarWidth; // Bearish Rejection Bar Width ... + int mBearishRejectionBarArrow; // Bearish Rejection Bar Arrow Code ... + color mBearishRejectionBarColor; // Bearish Rejection Bar Color ... + + // + // Supply Zone ... + bool mSupplyZoneFill; // Fill Supply Zone ... + int mSupplyZoneWidth; // Supply Zone Width ... + color mSupplyZoneColor; // Supply Zone Color ... + ENUM_LINE_STYLE mSupplyZoneStyle; // Supply Zone Style ... + + // + // Demand Zone ... + bool mDemandZoneFill; // Fill Demand Zone ... + int mDemandZoneWidth; // Demand Zone Width ... + color mDemandZoneColor; // Demand Zone Color ... + ENUM_LINE_STYLE mDemandZoneStyle; // Demand Zone Style ... + + // + // Resistance Zone ... + bool mResistanceZoneFill; // Fill Resistance Zone ... + int mResistanceZoneWidth; // Resistance Zone Width ... + color mResistanceZoneColor; // Resistance Zone Color ... + ENUM_LINE_STYLE mResistanceZoneStyle; // Resistance Zone Style ... + + // + // Support Zone ... + bool mSupportZoneFill; // Fill Support Zone ... + int mSupportZoneWidth; // Support Zone Width ... + color mSupportZoneColor; // Support Zone Color ... + ENUM_LINE_STYLE mSupportZoneStyle; // Support Zone Style ... + + // + // Bullish Order Block ... + bool mBullishOrderBlockFill; // Fill Bullish Order Block ... + int mBullishOrderBlockWidth; // Bullish Order Block Width ... + color mBullishOrderBlockColor; // Bullish Order Block Color ... + ENUM_LINE_STYLE mBullishOrderBlockStyle; // Bullish Order Block Style ... + + // + // Bearish Order Block ... + bool mBearishOrderBlockFill; // Fill Bearish Order Block ... + int mBearishOrderBlockWidth; // Bearish Order Block Width ... + color mBearishOrderBlockColor; // Bearish Order Block Color ... + ENUM_LINE_STYLE mBearishOrderBlockStyle; // Bearish Order Block Style ... + + // + // Bullish FVG ... + bool mBullishFVGFill; // Fill Bullish FVG ... + int mBullishFVGWidth; // Bullish FVG Width ... + color mBullishFVGColor; // Bullish FVG Color ... + ENUM_LINE_STYLE mBullishFVGStyle; // Bullish FVG Style ... + + // + // Bearish FVG ... + bool mBearishFVGFill; // Fill Bearish FVG ... + int mBearishFVGWidth; // Bearish FVG Width ... + color mBearishFVGColor; // Bearish FVG Color ... + ENUM_LINE_STYLE mBearishFVGStyle; // Bearish FVG Style ... + + // + // Ticks Zone ... + XTickZoneLevelSpecs mTicksZoneSpecs[]; // Zone Draw Specifications ... + + // +}; \ No newline at end of file diff --git a/BKPS/14031106/Classes/x-saherelm.x-trade.class.mq5 b/BKPS/14031106/Classes/x-saherelm.x-trade.class.mq5 new file mode 100644 index 0000000..64599b8 --- /dev/null +++ b/BKPS/14031106/Classes/x-saherelm.x-trade.class.mq5 @@ -0,0 +1,3941 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-account.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... + +// +// Overrides ... + +// +// XCTrade Base Class ... +class XCTradeBase : public CTrade +{ + public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// Implementation ... + +// +// a Class For Manage Trades and Handle Trading Actions ... +class XCTrade : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCAccount *mAccount; // Account Info Provider + + // + // Constructors ... + void XCTrade( + int slippage, // Specify Slippage + ulong magicNumber, // Specify Magic Number + double maxAllowedSpread = 0, // Max Allowed Spred for Opening Trades + int maxAllowedPositions = 0, // Max Allowed Positions + double maxAllowedDrawdownFactor = 0 // Max Allowed Drawdown Factor + ) + { + // + // Setting Props ... + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + mMaxAllowedSpread = maxAllowedSpread; + mMaxAllowedPositions = maxAllowedPositions; + mMaxAllowedDrawdownFactor = maxAllowedDrawdownFactor; + + // + mAccount = new XCAccount(); + + // + // Instance Base Trader Class ... + mTrader = new XCTradeBase(); + + // + // Configuring Base Trader Class ... + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // OnTrade Context ... + + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + ~XCTrade() + { + // + // Remove Pointer ... + delete mTrader; + delete mAccount; + + // + Clean(mOnModifyEventHandlers); + Clean(mStopLossEventHandlers); + Clean(mTakeProfitEventHandlers); + Clean(mOnForceCloseEventHandlers); + Clean(mDealsChangedEventHandlers); + Clean(mOrdersChangedEventHandlers); + Clean(mOnPartialCloseEventHandlers); + Clean(mPositionsChangedEventHandlers); + Clean(mTradeStateChangedEventHandlers); + + // + ArrayFree(mOnModifyEventHandlers); + ArrayFree(mStopLossEventHandlers); + ArrayFree(mTakeProfitEventHandlers); + ArrayFree(mDealsChangedEventHandlers); + ArrayFree(mOnForceCloseEventHandlers); + ArrayFree(mOrdersChangedEventHandlers); + ArrayFree(mOnPartialCloseEventHandlers); + ArrayFree(mPositionsChangedEventHandlers); + ArrayFree(mTradeStateChangedEventHandlers); + } + + // + // Props ... + + // + // Retrieve Slippage ... + int GetSlippage() + { + return mSlippage; + } + + // + // Retrieve Magic Number ... + ulong GetMagicNumber() + { + return mMagicNumber; + } + + // + double GetMaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + // + int GetMaxAllowedPositions() + { + return mMaxAllowedPositions; + } + + // + void SetMaxAllowedPositions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedPositions = value; + } + + // + double GetMaxAllowedDrawdownFactor() + { + return mMaxAllowedDrawdownFactor; + } + + // + // Add Event Listeners ... + + // + void AddOnModifyPositionEventHandler(TOnModify handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnModifyEventHandlers + // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers + // + ); + } + + // + void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnPartialCloseEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + // Functions ... + + // + // Handlers ... + + // + // Process On Trade Requirement ... + // this Only Used when we Have to Proccess OnTrade Event in EA(s) ... + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + result.Clean(); + + // + if (mScanStarted) + { + // + ProcessOnTradeContext(result); + } + else + { + // + // Init Trade Context ... + InitOnTradeContext(); + + // + return; + } + + // + // Here we Can Check the Start ... + bool isValid = + // + result.IsValid() && + // + !result.hasNewDeal && + !result.hasNewOrder && + !result.hasNewPosition && + !result.hasNewHistoryOrder + // + ; + if (!isValid) + { + return; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(result); + + // + // Deals ... + if (result.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(result.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + int dealsCount = GetDeals(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // Orders ... + if (result.hasNewOrder || result.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders); + } + + // + // Positions ... + if (result.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(result.newPositions); + } + } + + // + // This Must be Called Every time OnTrade Event Happening ... + // this Used for Implementing Custom Senarios ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Trade Actions ... + + // + // Main ... + + // + // Policies ... + + // + // Check Acocunt Balance is Allow new Trades or not ... + bool CheckEquityForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedDrawdownFactor <= 0) + { + // + result = true; + return result; + } + + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance); + + // + double maxAllowedBalanceDrawDown = GetMaxAllowedEquity(); + + // + result = equity > balance || + (equity <= balance && + selectedBalance <= maxAllowedBalanceDrawDown); + + // + return result; + } + + // + // Check Max Allowed Positions Policy for Trade ... + bool CheckPositionsForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedPositions <= 0) + { + // + result = true; + return result; + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + if (positionsCount <= 0) + { + // + result = true; + return result; + } + + // + result = positionsCount < mMaxAllowedPositions; + + // + return result; + } + + // + // Check Spread is Ok for Executing Specific Signal ... + bool CheckSpreadForSignalExecution(XSignal &mSignal) + { + // + bool result = false; + + // + bool isSpreadCheckEnable = mMaxAllowedSpread > 0; + if (!isSpreadCheckEnable) + { + result = true; + } + else + { + // + // Retrieve Signal Spread ... + double spread = GetSpread(mSignal.symbol); + result = spread <= mMaxAllowedSpread; + } + + // + return result; + } + + // + // Check Account Policy ... + bool CheckAccountPolicy( + XSignal &mSignal, // For Executing Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state // State Holder + ) + { + // + bool result = false; + + // + // Check Positions For Trade ... + result = CheckPositionsForTrade(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + + // + // Check Equity For Trade ... + result = CheckEquityForTrade(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; + return result; + } + + // + // Check Spread for Trade ... + result = CheckSpreadForSignalExecution(mSignal); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_SPREAD; + return result; + } + + // + return result; + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &mSignal, // Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + bool result = false; + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + double currentEntry = GetEntry( + mSignal.symbol, + mSignal.type + // + ); + bool isLong = IsLong(mSignal.type); + + // + if (!mSignal.IsValid()) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + // Prepare Signal Comment ... + string mSComment = mSignal.GenerateComment(); + if (!Contains(mSComment, mSignal.comment)) + { + mSignal.comment += mSComment; + } + + // + // Handle Market Execution ... + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + // + // Do Apply Policies here ... + bool hasPolicy = !checkPolicies + ? true + : CheckAccountPolicy(mSignal, state); + if (!hasPolicy) + { + result = false; + } + else + { + // + if (isLong) + { + // + result = Buy( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + mSignal.comment + // + ); + } + else + { + // + result = Sell( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + mSignal.comment + // + ); + } + } + } + // + // Handle Stop Execution ... + else if (mSignal.mode == X_ORDER_MODE_STOP) + { + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? mSignal.entry > currentEntry + : mSignal.entry < currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyStop( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + else + { + // + result = SellStop( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + } + // + // Handle Limit Execution ... + else if (mSignal.mode == X_ORDER_MODE_LIMIT) + { + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? mSignal.entry < currentEntry + : mSignal.entry > currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyLimit( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + else + { + // + result = SellLimit( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + } + + // + // Handle Ticket ... + if (result) + { + // + state = X_SIGNAL_EXECUTION_SUCCEED; + + // + ulong ticket; + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + ticket = GetLastOpenPositionTicket(); + } + else + { + ticket = GetLastPlacedOrderTicket(); + } + + // + mSignal.positionId = ticket; + + // + // Handle Store XPositionInfo ... + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + // + // TODO: Implement this ... + } + + // + // Handle Executing Support Signals ... + int supportsCount = ArraySize(mSignal.supports); + if (supportsCount > 0) + { + // + int executed = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XSignal iSupport = mSignal.supports[i]; + + // + int supIndex = i + 1; + string iComment = GenerateSupportTag(ticket); + iSupport.comment = iComment; + + // + bool isExecuted = ExecuteSignal( + iSupport, + state, + lifetime, + expiration + // + ); + if (isExecuted) + { + executed++; + } + } + + // + result = executed == supportsCount; + } + } + + // + return result; + } + + // + // Execute a Collection Of Signals ... + int ExecuteSignals( + XSignal &signals[], // Collection of Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + int result = 0; + + // + Clean(states); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration, + checkPolicies + // + ); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + int ExecuteSpecifiedSignals( + XSignal &signals[], // Collection of Signal for Execution + XSignal ¬Executeds[], // Not Executed Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + int result = 0; + + // + Clean(states); + Clean(notExecuteds); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration + // + ); + + // + if (isExecuted) + { + result++; + } + else + { + // + AddRef( + signals[i], + notExecuteds // + ); + } + } + + // + return result; + } + + // + // Regular Trade Actions ... + + // + // Buy ... + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Sell ... + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Check a Position is Exists Open or not ... + bool IsOpen( + ulong ticket // Specified Position Ticket + ) + { + // + bool result = false; + + // + result = mPositionInfo + .SelectByTicket(ticket); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = NULL // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + XPosition position; + result = + GetPosition( + ticket, + position // + ) && + (tp >= 0 || sl >= 0); + if (!result) + { + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (!IsValid(comment) == 0) + { + // + // if there isn't provided Comment + // Use Position Comment for default ... + comment = "Modify " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment + // + ); + if (result) + { + // + NotifyModifyEvent( + ticket, + position.profit, + comment // + ); + } + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Check Position Open ... + XPosition position; + result = GetPosition( + ticket, + position // + ); + if (!result) + { + return result; + } + + // + // Use Default Position Comment if it's Not Provided ... + if (!IsValid(comment)) + { + comment = "Close " + GetPositionComment(ticket); + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment + // + ); + if (result) + { + // + NotifyForceCloseEvent( + ticket, + position, + comment // + ); + } + + // + return result; + } + + // + // Close Specified Positions ... + int Close( + string comment = NULL, // Close Position By Specific Comment + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + int result = 0; + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close a Collection of Positions ... + int Close( + XPosition &positions[], // Collection of Positions + string comment // Close Comment + ) + { + // + int result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + XPosition position; + result = GetPosition( + ticket, + position // + ); + if (!result) + { + return result; + } + + // + // Use Default Partial Close Comment ... + if (!IsValid(comment)) + { + // + comment += "PClose " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment + // + ); + if (result) + { + // + NotifyPartialCloseEvent( + ticket, + position.profit, + comment // + ); + } + + // + return result; + } + + // + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) + { + return mTrader + .OrderDelete(ticket); + } + + // + // Cancel Specific Orders ... + int CancelOrders( + XOrder &orders[] // Specified Orders ... + ) + { + // + int result = 0; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader + .OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result++; + } + } + + // + return result; + } + + // + // Extractors ... + + // + // Positions ... + + // + // Calculate Positions Profit ... + double Profit( + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + double result = 0; + + // + // Retrieve Positions ... + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic + // + ); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + result += positions[i].profit; + } + + // + return result; + } + + // + // Retrieve Specific Position by Index ... + bool GetPosition( + int index, // Specified Index + XPosition &result // Hold's Result + ) + { + // + bool isInited = result + .ByIndex(index); + + // + return isInited; + } + + // + // Retrieve Specific Position by Ticket ... + bool GetPosition( + ulong ticket, // Specified Ticket + XPosition &result // Hold's Result + ) + { + // + bool isInited = result + .ByTicket(ticket); + + // + return isInited; + } + + // + double GetPositionCommission( + ulong ticket // Specified Ticket + ) + { + // + double result = 0; + + // + XPosition position; + bool hasPosition = GetPosition( + ticket, + position // + ); + if (!hasPosition) + { + return result; + } + + // + XDeal deals[]; + int dealsCount = GetDeals( + deals, + position.symbol, + position.provider, + position.period, + NULL, + DEAL_ENTRY_IN // + ); + if (IsValidSize(dealsCount)) + { + // + for (int i = 0; i < dealsCount; i++) + { + // + XDeal iDeal = deals[i]; + if (iDeal.positionId == ticket) + { + // + result = iDeal.commission; + break; + } + } + } + + // + return result; + } + + // + // Retrieve Positions ... + int GetPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = PositionsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XPosition iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + void GetPositions( + XPosition &longs[], // Hold's Longs Result + XPosition &shorts[], // Hold's Shorts Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + // Retrieve Long Positions ... + GetPositions( + longs, + symbol, + provider, + period, + X_POSITION_TYPE_LONG, + filterByMagic, + forceClean // + ); + + // + // Retrieve Short Positions ... + GetPositions( + shorts, + symbol, + provider, + period, + X_POSITION_TYPE_SHORT, + filterByMagic, + forceClean // + ); + } + + // + // Select In Profit Positions ... + int GetInProfitPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit <= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Drawdown Positions ... + int GetInDrawdownPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit >= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Orders ... + + // + // Retrieve Specific Order by Index ... + bool GetOrder( + int index, // Specified Index + XOrder &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Positions Orders ... + int GetOrders( + ulong ticket, // Positions Ticket + XOrder &result[], // Hold's Result + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + // Select History by Specified Ticket ... + bool isHistorySelected = HistorySelectByPosition(ticket); + if (!isHistorySelected) + { + return mResult; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder; + bool isLoaded = iOrder.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + bool isTicketFilterPassed = + // + iOrder.ticket = ticket + // + ; + if (!isTicketFilterPassed) + { + continue; + } + + // + AddRef( + iOrder, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve All Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve Historical Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Deals ... + + // + // Retrieve Specific Deal by Index ... + bool GetDeal( + int index, // Specified Index + XDeal &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + bool GetLastDeal( + XDeal &result // Hold's Result + ) + { + // + bool mResult = false; + + // + mResult = HistorySelect(0, TimeCurrent()); + if (!mResult) + { + return mResult; + } + + // + int lastDealIndex = HistoryDealsTotal() - 1; + + // + mResult = GetDeal( + lastDealIndex, + result // + ); + + // + return mResult; + } + + // + // Retrieve Specified Deal's History ... + int GetDealsHistory( + XDeal &deal, // Specified Deal + XOrder &history[], // Deals History + bool forceClean = true // Clean Result Array + ) + { + // + int result = 0; + + // + if (!deal.IsValid()) + { + return result; + } + + // + result = GetOrders( + deal.positionId, + history, + forceClean); + + // + return result; + } + + // + // Retrieve All Deals ... + int GetDeals( + XDeal &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_DEAL_TYPE type = NULL, // Deal Type + ENUM_DEAL_ENTRY entry = NULL, // Deal Entry + ENUM_DEAL_REASON reason = NULL, // Deal Reason + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = HistoryDealsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XDeal iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + entry, + reason, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Support Functions ... + + // + // Check a Position has Support or not ... + bool HasSupport( + ulong ticket, + bool forceOpen = true // + ) + { + // + bool result = false; + + // + result = ticket > 0; + if (!result) + { + return result; + } + + // + if (forceOpen) + { + // + result = IsOpen(ticket); + if (!result) + { + return result; + } + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + result = IsValidSize(positionsCount); + if (!result) + { + return result; + } + + // + // Extract Support Positions ... + XPosition supports[]; + int supportsCount = ExtractSupports( + positions, + supports // + ); + result = IsValidSize(supportsCount); + if (!result) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + result = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (result) + { + break; + } + } + + // + return result; + } + + // + // Retrieve Specific Position's Supports ... + int GetSupports( + ulong ticket, + XPosition &dest[], // Result ... + bool forceOpen = true // + ) + { + // + int result = 0; + + // + Clean(dest); + + // + bool hasSupport = HasSupport( + ticket, + forceOpen // + ); + if (!hasSupport) + { + return result; + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + // Extract Support Positions ... + XPosition supports[]; + int supportsCount = ExtractSupports( + positions, + supports // + ); + if (!IsValidSize(supportsCount)) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + bool isOwn = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (isOwn) + { + // + AddRef( + iSupport, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Retrieve Specific Position's Supports ... + int GetSupports( + ulong ticket, + XOrder &dest[], // Result ... + bool forceOpen = true // + ) + { + // + int result = 0; + + // + Clean(dest); + + // + bool hasSupport = HasSupport( + ticket, + forceOpen // + ); + if (!hasSupport) + { + return result; + } + + // + XOrder orders[]; + int ordersCount = GetOrders( + orders, + NULL, // All Symbols ... + NULL, // All Providers ... + NULL, // All Periods ... + X_POSITION_TYPE_ALL, // All Types ... + ORDER_STATE_PLACED, // Untriggere Orders ... + true // + ); + if (!IsValidSize(ordersCount)) + { + return result; + } + + // + // Extract Support Positions ... + XOrder supports[]; + int supportsCount = ExtractSupports( + orders, + supports // + ); + if (!IsValidSize(supportsCount)) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XOrder iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + bool isOwn = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (isOwn) + { + // + AddRef( + iSupport, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Tools ... + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // Prepare Dynamic Volume ... + double GetDynamicVolume( + string _symbol, + double _balanceFactor, + double _volumeStep // + ) + { + // + double result = 0; + + // + // Validate Inputs ... + if (!IsValid(_symbol) || + _volumeStep <= 0 || + _balanceFactor <= 0) + { + return result; + } + + // + // Retrieve Account Balance ... + double balance = mAccount.GetBalance(); + + // + double bStep = balance / _balanceFactor; + bStep = MathFloor(bStep); + if (bStep == 0) + { + bStep = 1; + } + + // + result = bStep * _volumeStep; + + // + result = NormalizeVolume( + result, + _symbol // + ); + + // + return result; + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Event Listener Notifiers ... + + // + // State ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // Deals ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Orders ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Positions ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // StopLoss ... + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + // Take Profit ... + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + + // + void NotifyModifyEvent( + ulong ticket, + double profit, + string comment // + ) + { + // + int count = ArraySize(mOnModifyEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnModify iHandler = mOnModifyEventHandlers[i]; + iHandler( + ticket, + profit, + comment // + ); + } + } + + // + void NotifyForceCloseEvent( + ulong ticket, + XPosition &position, + string comment // + ) + { + // + int count = ArraySize(mOnForceCloseEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnForceClose iHandler = mOnForceCloseEventHandlers[i]; + iHandler( + ticket, + position, + comment // + ); + } + } + + // + void NotifyPartialCloseEvent( + ulong ticket, + double profit, + string comment // + ) + { + // + int count = ArraySize(mOnPartialCloseEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnModify iHandler = mOnPartialCloseEventHandlers[i]; + iHandler( + ticket, + profit, + comment // + ); + } + } + + // + // Tools ... + + // + // Retrieve Specified Position Comment ... + string GetPositionComment(ulong ticket) + { + // + string result = NULL; + + // + if (!IsOpen(ticket)) + { + return result; + } + + // + XPosition position; + bool isLoaded = position.ByTicket(ticket); + if (!isLoaded) + { + return result; + } + + // + result = position.comment; + + // + return result; + } + + // + ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder orders[]; + int ordersCount = GetDealsHistory( + deal, + orders); + if (!ordersCount) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + if (IsValid(iOrder.comment)) + { + // + ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment); + if (IsValid(iPeriod)) + { + result = iPeriod; + break; + } + } + } + + // + return result; + } + + // + double GetMaxAllowedEquity() + { + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double balanceForFactor = MathAbs(equity - balance); + if (balanceForFactor <= 0) + { + balanceForFactor = balance; + } + else + { + balanceForFactor = equity; + } + + // + double result = balanceForFactor * mMaxAllowedDrawdownFactor; + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + int mSlippage; // Slippage ... + ulong mMagicNumber; // Magic Number (Unique Identifier) ... + + // + double mMaxAllowedSpread; // Max Allowed Spred for Opening Trades + int mMaxAllowedPositions; // Max Allowed Same Positions + double mMaxAllowedDrawdownFactor; // Max Allowed Drawdown Factor + + // + XCTradeBase *mTrader; // Base CTrade Manipulated Instance ... + + // + CDealInfo mDealInfo; // Deals Info ... + COrderInfo mOrderInfo; // Order Info ... + CPositionInfo mPositionInfo; // Positions Info + CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ... + + // + // Position Info Collector ... + + // + // Tools ... + + // + // OnTrade Event Handlers Section ... + + // + // Props ... + + // + int mDaysForRead; // Reading Dates for Trade History Checker ... + datetime mEndDate; // End Date for Trade history Checking ... + datetime mStartDate; // Start Date for Trade history Checking ... ... + int mOrdersCount; // Number of Active orders ... + int mPositionsCount; // Number of Open positions ... + int mDealsCount; // Number of Deals in the Trade History Checking ... + int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ... + bool mScanStarted; // a Flag of counter relevance ... + + // + // Event Listeners ... + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + TOnModify mOnModifyEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + + // + // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/1/1.mq5 b/BKPS/14031106/Documents/BKP/1/1.mq5 new file mode 100644 index 0000000..90e6eeb --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/1.mq5 @@ -0,0 +1,580 @@ +////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: XSTR +// Description: Super Trend Indicator ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121_XAMA Indicator" +#property strict + +// +// START Constants ... +// + +#define ShortName "XSTR" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// Market ... +input group "ATR"; +input int atrLength = 14; // Length +input double atrMultiplier = 3.0; // Multiplier +input ENUM_APPLIED_PRICE atrAppliedTo = PRICE_MEDIAN; // Applied To + +// +// Presentation ... +input group "Presentation"; +input bool showTrends = true; // Show Trends +input bool fillTrends = true; // Fill Trends + +// +// END Inputs ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 9 +#property indicator_plots 2 + +// +#define fillUpBufferIndex 0 +double fillUpBuffer[]; + +#define fillDownBufferIndex 1 +double fillDownBuffer[]; + +// +#define fillingPlotBufferIndex 0 + +// +#property indicator_label1 "XSTR Filling" +#property indicator_type1 DRAW_FILLING +#property indicator_color1 clrBisque, clrPaleGreen + +// +#define mainBufferIndex 2 +#define mainPlotBufferIndex 1 +double mainBuffer[]; + +// +#define mainColorBufferIndex 3 +double mainColorBuffer[]; + +// +#property indicator_label2 "XSTR" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 CLR_NONE, clrGreen, clrDarkRed +#property indicator_style2 STYLE_DOT + +// +// DATA Buffers ... + +// +#define atrBufferIndex 4 +double atrBuffer[]; + +// +#define trendBufferIndex 5 +double trendBuffer[]; + +// +#define upBufferIndex 6 +double upBuffer[]; + +// +#define downBufferIndex 7 +double downBuffer[]; + +// +#define priceBufferIndex 8 +double priceBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int atrHandler = INVALID_HANDLE; + +// +int changeOfTrend; +int startBearishTrend; +int startBullishTrend; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + atrHandler = iATR( + _Symbol, + _Period, + atrLength); + if (atrHandler == INVALID_HANDLE) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(atrHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[]) +{ + // + int numOfRequiredAtrs; + if (prev_calculated > rates_total || prev_calculated < 0) + { + numOfRequiredAtrs = rates_total; + } + else + { + // + numOfRequiredAtrs = rates_total - prev_calculated; + if (prev_calculated > 0) + { + numOfRequiredAtrs++; + } + } + + // + // Checking for stop ... + if (IsStopped()) + { + return 0; + } + + // + // Check Number of items Copy or not ... + int copiedATRs = CopyBuffer(atrHandler, 0, 0, numOfRequiredAtrs, atrBuffer); + if (copiedATRs <= 0) + { + return 0; + } + + // + int limit; + + // + // checking for the limit start of calculation of an indicator ... + if (prev_calculated > rates_total || prev_calculated <= 0) + { + // + // starting index for calculation of all bars ... + limit = maxLength; + } + else + { + // + // starting number for calculation of new bars + limit = prev_calculated - 1; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + // Calculated Price ... + double price = getPrice( + atrAppliedTo, + open, + high, + low, + close, + i); + // price = (high[i] + low[i]) / 2; + priceBuffer[i] = price; + + // + double atr = atrBuffer[i]; + + // + // Up ... + upBuffer[i] = price + (atrMultiplier * atr); + + // + // Down ... + downBuffer[i] = price - (atrMultiplier * atr); + + // + if (close[i] > upBuffer[i - 1]) + { + // + trendBuffer[i] = 1; + if (trendBuffer[i - 1] == -1) + { + changeOfTrend = 1; + } + } + else if (close[i] < downBuffer[i - 1]) + { + // + trendBuffer[i] = -1; + if (trendBuffer[i - 1] == 1) + { + changeOfTrend = 1; + } + } + else if (trendBuffer[i - 1] == 1) + { + // + trendBuffer[i] = 1; + changeOfTrend = 0; + } + else if (trendBuffer[i - 1] == -1) + { + // + trendBuffer[i] = -1; + changeOfTrend = 0; + } + + // + // Down Trend Starting ... + if (trendBuffer[i] < 0 && trendBuffer[i - 1] > 0) + { + startBearishTrend = 1; + } + else + { + startBearishTrend = 0; + } + + // + // Up Trend Starting ... + if (trendBuffer[i] > 0 && trendBuffer[i - 1] < 0) + { + startBullishTrend = 1; + } + else + { + startBullishTrend = 0; + } + + // + if (trendBuffer[i] > 0 && downBuffer[i] < downBuffer[i - 1]) + { + downBuffer[i] = downBuffer[i - 1]; + } + + // + if (trendBuffer[i] < 0 && upBuffer[i] > upBuffer[i - 1]) + { + upBuffer[i] = upBuffer[i - 1]; + } + + // + if (startBearishTrend == 1) + { + upBuffer[i] = priceBuffer[i] + (atrMultiplier * atr); + } + + // + if (startBullishTrend == 1) + { + downBuffer[i] = priceBuffer[i] - (atrMultiplier * atr); + } + + // + // Draw the indicator ... + + // + double colorIDX = 0; + mainColorBuffer[i] = colorIDX; + + // + if (trendBuffer[i] == 1) + { + // + mainBuffer[i] = downBuffer[i]; + if (changeOfTrend == 1) + { + mainBuffer[i - 1] = mainBuffer[i - 2]; + changeOfTrend = 0; + } + + // + colorIDX = 1; + } + else if (trendBuffer[i] == -1) + { + // + mainBuffer[i] = upBuffer[i]; + if (changeOfTrend == 1) + { + // + mainBuffer[i - 1] = mainBuffer[i - 2]; + changeOfTrend = 0; + } + + // + colorIDX = 2; + } + + // + if (showTrends) + { + mainColorBuffer[i] = colorIDX; + } + + // + // Filling ... + if (fillTrends) + { + // + fillUpBuffer[i] = mainBuffer[i]; + fillDownBuffer[i] = close[i]; + } + else + { + // + fillUpBuffer[i] = EMPTY_VALUE; + fillDownBuffer[i] = EMPTY_VALUE; + } + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + // Validate Args ... + result = + // + atrLength >= 2 + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = atrLength; + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // PLOT Buffers ... + + // + // FILLINGS ... + SetIndexBuffer(fillUpBufferIndex, fillUpBuffer, INDICATOR_DATA); + SetIndexBuffer(fillDownBufferIndex, fillDownBuffer, INDICATOR_DATA); + PlotIndexSetInteger(fillingPlotBufferIndex, PLOT_SHOW_DATA, false); + + // + // MAIN ... + SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); + PlotIndexSetInteger(mainPlotBufferIndex, PLOT_SHOW_DATA, showTrends); + SetIndexBuffer(mainColorBufferIndex, mainColorBuffer, INDICATOR_COLOR_INDEX); + + // + // DATA Buffers ... + + // + // ATR ... + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + // TREND ... + SetIndexBuffer(trendBufferIndex, trendBuffer, INDICATOR_CALCULATIONS); + + // + // UP ... + SetIndexBuffer(upBufferIndex, upBuffer, INDICATOR_CALCULATIONS); + + // + // DOWN ... + SetIndexBuffer(downBufferIndex, downBuffer, INDICATOR_CALCULATIONS); + + // + // PRICE ... + SetIndexBuffer(priceBufferIndex, priceBuffer, INDICATOR_CALCULATIONS); +} + +// +// END Functions ... +// + +// +// TEMPLATE Function ... + +template +double getPrice(ENUM_APPLIED_PRICE tprice, T &open[], T &high[], T &low[], T &close[], int i) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} diff --git a/BKPS/14031106/Documents/BKP/1/2.mq5 b/BKPS/14031106/Documents/BKP/1/2.mq5 new file mode 100644 index 0000000..3081db2 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/2.mq5 @@ -0,0 +1,195 @@ + +//+------------------------------------------------------------------+ +//| SuperTrend.mq5 | +//| Copyright 2011, FxGeek | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2011, FxGeek" +#property link " http://www.mql5.com" +#property version "1.00" +#property indicator_chart_window +#property indicator_buffers 9 +#property indicator_plots 2 + +#property indicator_label1 "Filling" +#property indicator_type1 DRAW_FILLING +#property indicator_color1 clrBisque, clrPaleGreen + +#property indicator_label2 "SuperTrend" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 clrGreen, clrRed + +input int Periode=10; +input double Multiplier=3; +input bool Show_Filling=true; // Show as DRAW_FILLING + +double Filled_a[]; +double Filled_b[]; +double SuperTrend[]; +double ColorBuffer[]; +double Atr[]; +double Up[]; +double Down[]; +double Middle[]; +double trend[]; + +int atrHandle; +int changeOfTrend; +int flag; +int flagh; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,Filled_a,INDICATOR_DATA); + SetIndexBuffer(1,Filled_b,INDICATOR_DATA); + SetIndexBuffer(2,SuperTrend,INDICATOR_DATA); + SetIndexBuffer(3,ColorBuffer,INDICATOR_COLOR_INDEX); + SetIndexBuffer(4,Atr,INDICATOR_CALCULATIONS); + SetIndexBuffer(5,Up,INDICATOR_CALCULATIONS); + SetIndexBuffer(6,Down,INDICATOR_CALCULATIONS); + SetIndexBuffer(7,Middle,INDICATOR_CALCULATIONS); + SetIndexBuffer(8,trend,INDICATOR_CALCULATIONS); + + atrHandle=iATR(_Symbol,_Period,Periode); +//--- + return(0); + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- + int to_copy; + if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } + + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(atrHandle,0,0,to_copy,Atr)<=0) + { + Print("Getting Atr is failed! Error",GetLastError()); + return(0); + } + + int first; + if(prev_calculated>rates_total || prev_calculated<=0) // checking for the first start of calculation of an indicator + { + first=Periode; // starting index for calculation of all bars + } + else + { + first=prev_calculated-1; // starting number for calculation of new bars + } + for(int i=first; iUp[i-1]) + { + trend[i]=1; + if(trend[i-1]==-1) changeOfTrend=1; + + } + else if(close[i]0) + { + flag=1; + } + else + { + flag=0; + } + + if(trend[i]>0 && trend[i-1]<0) + { + flagh=1; + } + else + { + flagh=0; + } + + if(trend[i]>0 && Down[i]Up[i-1]) + Up[i]=Up[i-1]; + + if(flag==1) + Up[i]=Middle[i]+(Multiplier*Atr[i]); + + if(flagh==1) + Down[i]=Middle[i]-(Multiplier*Atr[i]); + + //-- Draw the indicator + if(trend[i]==1) + { + SuperTrend[i]=Down[i]; + if(changeOfTrend==1) + { + SuperTrend[i-1]=SuperTrend[i-2]; + changeOfTrend=0; + } + ColorBuffer[i]=0.0; + } + else if(trend[i]==-1) + { + SuperTrend[i]=Up[i]; + if(changeOfTrend==1) + { + SuperTrend[i-1]= SuperTrend[i-2]; + changeOfTrend = 0; + } + ColorBuffer[i]=1.0; + } + + if(Show_Filling) + { + Filled_a[i]= SuperTrend[i]; + Filled_b[i]= close[i]; + }else{ + Filled_a[i]= EMPTY_VALUE; + Filled_b[i]= EMPTY_VALUE; + } + + } + +//--- return value of prev_calculated for next call + return(rates_total); + } +//+------------------------------------------------------------------+ + + \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/1/3.mq5 b/BKPS/14031106/Documents/BKP/1/3.mq5 new file mode 100644 index 0000000..136b238 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/3.mq5 @@ -0,0 +1,319 @@ + + // + // Reading Previous Conditions ... + ENUM_XPOI_EVENTS consolidationPoiEventsPrev[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEventsPrev[]; + X121SMCCycleConditions consolidationConditionsPrev; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEventsPrev, + consolidationPoiEventsPrev, + consolidationConditionsPrev, + cIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + X121SMCCycleConditions conditionState = consolidationConditions; + X121SMCCycleConditions conditionStatePrev = consolidationConditionsPrev; + + // + XOHCL cCBar; + result = cCBar.Init( + conditionState.symbol, + conditionState.period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cPBar; + result = cCBar.GetPreviousBar(cPBar); + if (!result) + { + return result; + } + + // + // Engulf ... + ENUM_X_DIRECTION cCBarEngulfDir; + bool isCCBarEngulfed = consolidationCycleHelper + .mBarAnalyser + .IsEngulfBar( + cCBar, + cCBarEngulfDir, + 0 // Extended ... + ); + bool isCCBarBullishEngulfed = + isCCBarEngulfed && + IsBullish(cCBarEngulfDir); + bool isCCBarBearishEngulfed = + isCCBarEngulfed && + IsBearish(cCBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cCBarMomentumDir; + bool isCCBarMomentum = consolidationCycleHelper + .mBarAnalyser + .IsMomentumBar( + cCBar, + cCBarMomentumDir, + 1 // Extended ... + ); + bool isCCBarBullishMomentum = + isCCBarMomentum && + IsBullish(cCBarMomentumDir); + bool isCCBarBearishMomentum = + isCCBarMomentum && + IsBearish(cCBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cCBarRejectDir; + bool isCCBarRejected = consolidationCycleHelper + .mBarAnalyser + .IsRejectionBar( + cCBar, + cCBarRejectDir, + 1 // Extended ... + ); + bool isCCBarBullishRejected = + isCCBarRejected && + IsBullish(cCBarRejectDir); + bool isCCBarBearishRejected = + isCCBarRejected && + IsBearish(cCBarRejectDir); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCCBarPassedBullish = + // + isCCBarBullishEngulfed || + isCCBarBullishMomentum || + isCCBarBullishRejected + // + ; + + // + // Bearish ... + bool isCCBarPassedBearish = + // + isCCBarBearishEngulfed || + isCCBarBearishMomentum || + isCCBarBearishRejected + // + ; + + // + double cPeakPrev = conditionStatePrev.x121Conditions.peaksBuffer[0]; + double cValePrev = conditionStatePrev.x121Conditions.valesBuffer[0]; + + // + double cPeak = conditionState.x121Conditions.peaksBuffer[1]; + double cVale = conditionState.x121Conditions.valesBuffer[1]; + + // + bool isCPeakSame = cPeak == cPeakPrev; + bool isCValeSame = cVale == cValePrev; + + // + bool isCNewPeakPrev = conditionStatePrev.x121Conditions.isNewPeak; + bool isCNewPeakOverLastPrev = conditionStatePrev.x121Conditions.isNewPeakOverLast; + bool isCNewPeakUnderLastPrev = conditionStatePrev.x121Conditions.isNewPeakUnderLast; + + // + bool isCNewValePrev = conditionStatePrev.x121Conditions.isNewVale; + bool isCNewValeOverLastPrev = conditionStatePrev.x121Conditions.isNewValeOverLast; + bool isCNewValeUnderLastPrev = conditionStatePrev.x121Conditions.isNewValeUnderLast; + + // + bool isCRSIOverSold = conditionState.x121Conditions.isRSIOverSold; + bool isCRSICrossedOverOverSold = conditionState.x121Conditions.isRSICrossedOverOverSold; + bool isCRSICrossedUnderOverSold = conditionState.x121Conditions.isRSICrossedUnderOverSold; + + // + bool isCRSIOverBought = conditionState.x121Conditions.isRSIOverBought; + bool isCRSICrossedOverOverBought = conditionState.x121Conditions.isRSICrossedOverOverBought; + bool isCRSICrossedUnderOverBought = conditionState.x121Conditions.isRSICrossedUnderOverBought; + + // + bool isCRSIOverSoldPrev = conditionStatePrev.x121Conditions.isRSIOverSold; + bool isCRSICrossedOverOverSoldPrev = conditionStatePrev.x121Conditions.isRSICrossedOverOverSold; + bool isCRSICrossedUnderOverSoldPrev = conditionStatePrev.x121Conditions.isRSICrossedUnderOverSold; + + // + bool isCRSIOverBoughtPrev = conditionStatePrev.x121Conditions.isRSIOverBought; + bool isCRSICrossedOverOverBoughtPrev = conditionStatePrev.x121Conditions.isRSICrossedOverOverBought; + bool isCRSICrossedUnderOverBoughtPrev = conditionStatePrev.x121Conditions.isRSICrossedUnderOverBought; + + // + isBullish = + // + isCNewValePrev && + isCCBarPassedBullish + // + ; + + // + isBearish = + // + isCNewPeakPrev && + isCCBarPassedBearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.pivot = + isBullish + ? conditionState.x121Conditions.valesBuffer[1] + : conditionState.x121Conditions.peaksBuffer[1]; + + // + double peak = analyseConditions.x121Conditions.peaksBuffer[1]; + double vale = analyseConditions.x121Conditions.valesBuffer[1]; + + // + double strUpper = analyseConditions.x121Conditions.strUpBuffer[1]; + double strLower = analyseConditions.x121Conditions.strDownBuffer[1]; + + // + bool isStrSwitchedToBullish = analyseConditions.x121Conditions.isStrSwitchedToBullish; + bool isStrSwitchedToBearish = analyseConditions.x121Conditions.isStrSwitchedToBearish; + + // + isBullish = isStrSwitchedToBullish; + isBearish = isStrSwitchedToBearish; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.pivot = + isBullish + ? peak + : vale; + + + + // + // Looking For Sar Change ... + + // + double sar = analyseConditions.x121Conditions.sarBuffer[1]; + + // + double peak = analyseConditions.x121Conditions.peaksBuffer[1]; + double vale = analyseConditions.x121Conditions.valesBuffer[1]; + + // + bool isSarEqualsToPeak = analyseConditions.x121Conditions.isSarEqualsToPeak; + bool isSarEqualsToVale = analyseConditions.x121Conditions.isSarEqualsToVale; + + // + bool isSarSwitchedToBullish = analyseConditions.x121Conditions.isSarSwitchedToBullish; + bool isSarSwitchedToBearish = analyseConditions.x121Conditions.isSarSwitchedToBearish; + + // + isBullish = + isBullish && + isSarEqualsToPeak && + isSarSwitchedToBullish; + + // + isBearish = + isBearish && + isSarEqualsToVale && + isSarSwitchedToBearish; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + Print("Sar Switched ..."); + + + + // + // Detect a Zone Arround Price Zone ... + int supplyZonesCount = consolidationState.CountSupplyZones(); + if (IsValidSize(supplyZonesCount)) { + // + for (int i = 0; i < supplyZonesCount; i++) { + // + XCSupplyZone *iZone = consolidationState.supplyZones[i]; + + // + bool isOver = iZone.Lower() > pzUpper; + bool isUnder = iZone.Upper() < pzLower; + + // + bool isValid = + isOver || + isUnder; + if (isValid) { + + } + } + } + + // + // Method 1 ... + // VWap Switch Start ... + + // + bool bullishMethod1 = + // + isSarBullish && + isStrBullish && + isSlopesBullish && + hasBullishTrend && + cBar.IsBullish() && + isAtrBullishSlope && + isPVBullishFormed && + isRsiBullishFormed && + isVWapBullishFormed + // + ; + + // + bool bearishMethod1 = + // + isSarBearish && + isStrBearish && + isSlopesBearish && + hasBearishTrend && + cBar.IsBearish() && + isAtrBearishSlope && + isPVBearishFormed && + isRsiBearishFormed && + isVWapBearishFormed + // + ; diff --git a/BKPS/14031106/Documents/BKP/1/4.mq5 b/BKPS/14031106/Documents/BKP/1/4.mq5 new file mode 100644 index 0000000..15975f6 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/4.mq5 @@ -0,0 +1,530 @@ +////////////////////////////////////////////////////////////////////////////////// +////// Detect Price Zones : +///////////////////////////////////////////////////////////////////////////////// + + // + XPriceZones priceZone; + bool isPriceZoneValidForPeak; + bool isPriceZoneValidForVale; + + // + priceZone.Clean(); + isPriceZoneValidForPeak = false; + isPriceZoneValidForVale = false; + + // + // Detect Price Zone ... + + // + double pzPeak = decisionXConditions.peaksBuffer[1]; + double pzVale = decisionXConditions.valesBuffer[1]; + + // + // Detecting Decision Price ones ... + XPriceZones decisionPriceZone; + bool hasDecisionPriceZone = CalculatePriceInsideZones( + decisionPriceZone, + decisionState, + cBar // + ); + double decisionPriceZoneUpper = 0; + double decisionPriceZoneLower = 0; + bool isDecisionPriceZoneValidForPeak = false; + bool isDecisionPriceZoneValidForVale = false; + if (hasDecisionPriceZone) + { + // + bool hasBoundary = decisionPriceZone.GetBoundary( + X_DIRECTION_ALL, + decisionPriceZoneUpper, + decisionPriceZoneLower // + ); + + // + isDecisionPriceZoneValidForPeak = + hasBoundary && + pzPeak <= decisionPriceZoneUpper && + pzPeak >= decisionPriceZoneLower; + + // + isDecisionPriceZoneValidForVale = + hasBoundary && + pzVale <= decisionPriceZoneUpper && + pzVale >= decisionPriceZoneLower; + } + + // + // Detecting Analyse Price ones ... + XPriceZones analysePriceZone; + bool hasAnalysePriceZone = CalculatePriceInsideZones( + analysePriceZone, + analyseState, + cBar // + ); + double analysePriceZoneUpper = 0; + double analysePriceZoneLower = 0; + bool isAnalysePriceZoneValidForPeak = false; + bool isAnalysePriceZoneValidForVale = false; + if (hasAnalysePriceZone) + { + // + bool hasBoundary = analysePriceZone.GetBoundary( + X_DIRECTION_ALL, + analysePriceZoneUpper, + analysePriceZoneLower // + ); + + // + isAnalysePriceZoneValidForPeak = + hasBoundary && + pzPeak <= analysePriceZoneUpper && + pzPeak >= analysePriceZoneLower; + + // + isAnalysePriceZoneValidForVale = + hasBoundary && + pzVale <= analysePriceZoneUpper && + pzVale >= analysePriceZoneLower; + } + + // + // Detecting Verification Price ones ... + XPriceZones verificationPriceZone; + bool hasVerificationPriceZone = CalculatePriceInsideZones( + verificationPriceZone, + verificationState, + cBar // + ); + double verificationPriceZoneUpper = 0; + double verificationPriceZoneLower = 0; + bool isVerificationPriceZoneValidForPeak = false; + bool isVerificationPriceZoneValidForVale = false; + if (hasVerificationPriceZone) + { + // + bool hasBoundary = verificationPriceZone.GetBoundary( + X_DIRECTION_ALL, + verificationPriceZoneUpper, + verificationPriceZoneLower // + ); + + // + isVerificationPriceZoneValidForPeak = + hasBoundary && + pzPeak <= verificationPriceZoneUpper && + pzPeak >= verificationPriceZoneLower; + + // + isVerificationPriceZoneValidForVale = + hasBoundary && + pzVale <= verificationPriceZoneUpper && + pzVale >= verificationPriceZoneLower; + } + + +////////////////////////////////////////////////////////////////////////////////// +////// Detect Pivot Zones : +///////////////////////////////////////////////////////////////////////////////// + + // + double X121SMCXPivotPeak; + double X121SMCXPivotVale; + datetime X121SMCXPivotEnd; + datetime X121SMCXPivotStart; + ENUM_XPV_PIVOTS X121SMCXPivotType = XPV_NONE; + + // + // Detect PV Pivot ... + + // + bool isPivotPeakZoneRejected = false; + bool isPivotPeakZoneBreakedUp = false; + bool isPivotPeakZoneBreakedDown = false; + bool isPivotValeZoneRejected = false; + bool isPivotValeZoneBreakedUp = false; + bool isPivotValeZoneBreakedDown = false; + bool hasPivot = conditions.pivotZone.IsValid(); + if (!hasPivot) + { + // + hasPivot = IsValid(X121SMCXPivotStart); + if (!hasPivot) + { + // + bool isNewVale = decisionXConditions.isNewVale; + bool isNewValeOverLast = decisionXConditions.isNewValeOverLast; + bool isNewValeUnderLast = decisionXConditions.isNewValeUnderLast; + bool isSameVales = decisionXConditions.valesBuffer[1] == + decisionXConditions.valesBuffer[2] && + decisionXConditions.valesBuffer[2] == + decisionXConditions.valesBuffer[3]; + bool isSameCycleVales = decisionXConditions.valesBuffer[1] == + analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == + verificationXConditions.valesBuffer[1]; + + // + bool isNewPeak = decisionXConditions.isNewPeak; + bool isNewPeakOverLast = decisionXConditions.isNewPeakOverLast; + bool isNewPeakUnderLast = decisionXConditions.isNewPeakUnderLast; + bool isSamePeaks = decisionXConditions.peaksBuffer[1] == + decisionXConditions.peaksBuffer[2] && + decisionXConditions.peaksBuffer[2] == + decisionXConditions.peaksBuffer[3]; + bool isSameCyclePeaks = decisionXConditions.peaksBuffer[1] == + analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == + verificationXConditions.peaksBuffer[1]; + + // + bool isValeStart = + isSameVales && + isSameCycleVales; + bool isPeakStart = + isSamePeaks && + isSameCyclePeaks; + + // + bool isStart = isPeakStart || + isValeStart; + if (isStart) + { + // + X121SMCXPivotStart = cTime; + X121SMCXPivotType = + isPeakStart + ? XPV_PEAK + : XPV_VALE; + + // + X121SMCXPivotPeak = decisionXConditions.peaksBuffer[1]; + X121SMCXPivotVale = decisionXConditions.valesBuffer[1]; + } + + // + hasPivot = IsValid(X121SMCXPivotStart); + + // + // Create XPVPivot instance ... + if (hasPivot) + { + // + conditions.pivotZone.symbol = symbol; + conditions.pivotZone.period = period; + + // + conditions.pivotZone.to = cTime; + conditions.pivotZone.repetition = 3; + + // + conditions.pivotZone.upper = X121SMCXPivotPeak; + conditions.pivotZone.lower = X121SMCXPivotVale; + + // + conditions.pivotZone.type = X121SMCXPivotType; + conditions.pivotZone.from = X121SMCXPivotStart; + } + } + } + + // + if (hasPivot) + { + // + bool isBreaked = X121SMCXPivotType == XPV_PEAK + ? decisionXConditions.isBreakedUpPrevPeak + : decisionXConditions.isBreakedDownPrevVale; + + // + if (!isBreaked) + { + // + X121SMCXPivotPeak = decisionXConditions.peaksBuffer[1]; + X121SMCXPivotVale = decisionXConditions.valesBuffer[1]; + + // + conditions.pivotZone.to = cTime; + conditions.pivotZone.repetition++; + conditions.pivotZone.upper = X121SMCXPivotPeak; + conditions.pivotZone.lower = X121SMCXPivotVale; + } + else + { + // + X121SMCXPivotEnd = cTime; + conditions.pivotZone.to = cTime; + } + + // + // Fill Pivot State ... + + // + XPOIState analysePivotState; + DetectPivotPOIs( + conditions.pivotZone, + analyseState, + analysePivotState // + ); + + // + XPOIState decisionPivotState; + DetectPivotPOIs( + conditions.pivotZone, + decisionState, + decisionPivotState // + ); + + // + // Combine two State ... + XPOIState combinedPivotState; + XPOIState iStates[]; + AddRef( + analysePivotState, + iStates // + ); + AddRef( + decisionPivotState, + iStates // + ); + CombineStates( + combinedPivotState, + iStates // + ); + combinedPivotState = decisionPivotState; + + // + ArrayFree(iStates); + + // + combinedPivotState.time = decisionPivotState.time; + combinedPivotState.symbol = decisionPivotState.symbol; + combinedPivotState.period = decisionPivotState.period; + + // + // Hold Only Areas Which on Upper or Lower bondary of Pivot Zone ... + FilterPivotState( + conditions.pivotZone, + combinedPivotState // + ); + + // + conditions.pivotZone.state = combinedPivotState; + + // + double peakUpper = 0; + double peakLower = 0; + double valeUpper = 0; + double valeLower = 0; + + // + datetime peakTo = NULL; + datetime valeTo = NULL; + datetime peakFrom = NULL; + datetime valeFrom = NULL; + + // + bool hasBoxData = DetectPivotStateBoxData( + conditions.pivotZone, + peakUpper, + peakLower, + peakFrom, + peakTo, + valeUpper, + valeLower, + valeFrom, + valeTo // + ); + + // + // Calculate Pivot Tick Zones ... + + // + int ticksLevels = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneLevel(); + int ticksRange = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneRange(); + + // + CalculatePivotTickZone( + conditions.pivotZone, + ticksLevels, + ticksRange // + ); + + // + isPivotPeakZoneRejected = + hasBoxData && + ( + // + IsBarReject( + peakLower, + X_DIRECTION_BEARISH, + cBar // + ) + // + || + // + IsBarReject( + peakUpper, + X_DIRECTION_BEARISH, + cBar // + ) + // + ); + isPivotPeakZoneBreakedUp = + hasBoxData && + IsBarBreak( + peakUpper, + X_DIRECTION_BULLISH, + cBar // + ); + isPivotPeakZoneBreakedDown = + hasBoxData && + IsBarBreak( + peakLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isPivotValeZoneRejected = + hasBoxData && + ( + // + IsBarReject( + valeLower, + X_DIRECTION_BULLISH, + cBar // + ) + // + || + // + IsBarReject( + valeUpper, + X_DIRECTION_BULLISH, + cBar // + ) + // + ); + isPivotValeZoneBreakedUp = + hasBoxData && + IsBarBreak( + valeUpper, + X_DIRECTION_BULLISH, + cBar // + ); + isPivotValeZoneBreakedDown = + hasBoxData && + IsBarBreak( + valeLower, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + bool isPivotEnded = IsValid(X121SMCXPivotEnd); + if (isPivotEnded) + { + // + X121SMCXPivotPeak = 0; + X121SMCXPivotVale = 0; + X121SMCXPivotEnd = NULL; + X121SMCXPivotStart = NULL; + X121SMCXPivotType = XPV_NONE; + + // + conditions.pivotZone.Clean(); + } + + +////////////////////////////////////////////////////////////////////////////////// +////// Detect Pivot Zones : +///////////////////////////////////////////////////////////////////////////////// + + // + bool isCondition1Bullish = + // + hasPivot && + // + isCBarBullishFormed && + isCBarBullishPullbacked && + // + hasAnalyseBullishTrend && + hasDecisionBullishTrend && + hasVerificationBullishTrend && + // + decisionXConditions.isSarBullish && + analyseXConditions.isSarBullish && + verificationXConditions.isSarBullish && + // + false + // + ; + + // + bool isCondition1Bearish = + // + hasPivot && + // + isCBarBearishFormed && + isCBarBearishPullbacked && + // + hasAnalyseBearishTrend && + hasDecisionBearishTrend && + hasVerificationBearishTrend && + // + decisionXConditions.isSarBearish && + analyseXConditions.isSarBearish && + verificationXConditions.isSarBearish && + // + false + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + conditions.priceZone = analysePriceZone; + conditions.isPriceZoneValidForPeak = isAnalysePriceZoneValidForPeak; + conditions.isPriceZoneValidForVale = isAnalysePriceZoneValidForVale; + + // + pzPeak = analysePriceZoneUpper; + pzVale = analysePriceZoneLower; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + // point = + // isCondition1Bullish ? pzPeak + // : pzVale; + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCondition1Bullish + ? pzVale + : pzPeak; + } diff --git a/BKPS/14031106/Documents/BKP/1/tmp.codes.mq5 b/BKPS/14031106/Documents/BKP/1/tmp.codes.mq5 new file mode 100644 index 0000000..07fd1fb --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/tmp.codes.mq5 @@ -0,0 +1,729 @@ + // + double cPZoneUpper = 0; + double cPZoneLower = 0; + datetime cPZoneFrom = NULL; + datetime cPZoneTo = NULL; + result = consolidationPriceZone.GetBoxData( + X_DIRECTION_ALL, + cPZoneUpper, + cPZoneLower, + cPZoneFrom, + cPZoneTo // + ); + if (!result) + { + return result; + } + + // + double aPZoneUpper = 0; + double aPZoneLower = 0; + datetime aPZoneFrom = NULL; + datetime aPZoneTo = NULL; + result = analysePriceZone.GetBoxData( + X_DIRECTION_ALL, + aPZoneUpper, + aPZoneLower, + aPZoneFrom, + aPZoneTo // + ); + if (!result) + { + return result; + } + + + // + // RSI ... + double rsi = decisionConditions.x121Conditions.rsiBuffer[1]; + + // + bool isRSIOverBought = decisionConditions.x121Conditions.isRSIOverBought; + bool isRSICrossedOverOverBought = decisionConditions.x121Conditions.isRSICrossedOverOverBought; + bool isRSICrossedUnderOverBought = decisionConditions.x121Conditions.isRSICrossedUnderOverBought; + + // + bool isRSIOverSold = decisionConditions.x121Conditions.isRSIOverSold; + bool isRSICrossedOverOverSold = decisionConditions.x121Conditions.isRSICrossedOverOverSold; + bool isRSICrossedUnderOverSold = decisionConditions.x121Conditions.isRSICrossedUnderOverSold; + + // + // PV ... + double peak = decisionConditions.x121Conditions.peaksBuffer[1]; + double vale = decisionConditions.x121Conditions.valesBuffer[1]; + + // + bool isNewPeak = decisionConditions.x121Conditions.isNewPeak; + bool isNewPeakOverLast = decisionConditions.x121Conditions.isNewPeakOverLast; + bool isNewPeakUnderLast = decisionConditions.x121Conditions.isNewPeakUnderLast; + + // + bool isNewVale = decisionConditions.x121Conditions.isNewVale; + bool isNewValeOverLast = decisionConditions.x121Conditions.isNewValeOverLast; + bool isNewValeUnderLast = decisionConditions.x121Conditions.isNewValeUnderLast; + + // + // STR ... + double str = decisionConditions.x121Conditions.strBuffer[1]; + + // + bool isStrBullish = decisionConditions.x121Conditions.isStrBullish; + bool isStrBearish = decisionConditions.x121Conditions.isStrBearish; + + // + bool isStrSwitchedToBullish = decisionConditions.x121Conditions.isStrSwitchedToBullish; + bool isStrSwitchedToBearish = decisionConditions.x121Conditions.isStrSwitchedToBearish; + + // + // ATR ... + double atr = decisionConditions.x121Conditions.atrBuffer[1]; + double atrUpper = decisionConditions.x121Conditions.atrUpperBuffer[1]; + double atrLower = decisionConditions.x121Conditions.atrLowerBuffer[1]; + + // + bool isCloseOverATRUpper = decisionConditions.x121Conditions.isCloseOverATRUpper; + bool isCloseOverATRLower = decisionConditions.x121Conditions.isCloseOverATRLower; + + // + bool isCloseUnderATRUpper = decisionConditions.x121Conditions.isCloseUnderATRUpper; + bool isCloseUnderATRLower = decisionConditions.x121Conditions.isCloseUnderATRLower; + + // + bool isRejectUpATRUpper = decisionConditions.x121Conditions.isRejectUpATRUpper; + bool isRejectDownATRUpper = decisionConditions.x121Conditions.isRejectDownATRUpper; + + // + bool isRejectUpATRLower = decisionConditions.x121Conditions.isRejectUpATRLower; + bool isRejectDownATRLower = decisionConditions.x121Conditions.isRejectDownATRLower; + + // + bool isBreakUpATRUpper = decisionConditions.x121Conditions.isBreakUpATRUpper; + bool isBreakDownATRUpper = decisionConditions.x121Conditions.isBreakDownATRUpper; + + // + bool isBreakUpATRLower = decisionConditions.x121Conditions.isBreakUpATRLower; + bool isBreakDownATRLower = decisionConditions.x121Conditions.isBreakDownATRLower; + + // + // SAR ... + double sar = decisionConditions.x121Conditions.sarBuffer[1]; + + // + bool isSarBullish = decisionConditions.x121Conditions.isSarBullish; + bool isSarBearish = decisionConditions.x121Conditions.isSarBearish; + + // + bool isSarSwitchedToBullish = decisionConditions.x121Conditions.isSarSwitchedToBullish; + bool isSarSwitchedToBearish = decisionConditions.x121Conditions.isSarSwitchedToBearish; + + // + // DON ... + + // + double donOpenUpper = decisionConditions.x121Conditions.donOpenUpperBuffer[1]; + double donOpenLower = decisionConditions.x121Conditions.donOpenLowerBuffer[1]; + double donHighUpper = decisionConditions.x121Conditions.donHighUpperBuffer[1]; + double donHighLower = decisionConditions.x121Conditions.donHighLowerBuffer[1]; + double donLowUpper = decisionConditions.x121Conditions.donLowUpperBuffer[1]; + double donLowLower = decisionConditions.x121Conditions.donLowLowerBuffer[1]; + double donCloseUpper = decisionConditions.x121Conditions.donCloseUpperBuffer[1]; + double donCloseLower = decisionConditions.x121Conditions.donCloseLowerBuffer[1]; + + // + bool isRejectDonOpenUpper = decisionConditions.x121Conditions.isRejectDonOpenUpper; + bool isRejectDonHighUpper = decisionConditions.x121Conditions.isRejectDonHighUpper; + bool isRejectDonLowUpper = decisionConditions.x121Conditions.isRejectDonLowUpper; + bool isRejectDonCloseUpper = decisionConditions.x121Conditions.isRejectDonCloseUpper; + + // + bool isRejectDonOpenLower = decisionConditions.x121Conditions.isRejectDonOpenLower; + bool isRejectDonHighLower = decisionConditions.x121Conditions.isRejectDonHighLower; + bool isRejectDonLowLower = decisionConditions.x121Conditions.isRejectDonLowLower; + bool isRejectDonCloseLower = decisionConditions.x121Conditions.isRejectDonCloseLower; + + // + bool isBreakDonOpenUpper = decisionConditions.x121Conditions.isBreakDonOpenUpper; + bool isBreakDonHighUpper = decisionConditions.x121Conditions.isBreakDonHighUpper; + bool isBreakDonLowUpper = decisionConditions.x121Conditions.isBreakDonLowUpper; + bool isBreakDonCloseUpper = decisionConditions.x121Conditions.isBreakDonCloseUpper; + + // + bool isBreakDonOpenLower = decisionConditions.x121Conditions.isBreakDonOpenLower; + bool isBreakDonHighLower = decisionConditions.x121Conditions.isBreakDonHighLower; + bool isBreakDonLowLower = decisionConditions.x121Conditions.isBreakDonLowLower; + bool isBreakDonCloseLower = decisionConditions.x121Conditions.isBreakDonCloseLower; + + // + // VWAP ... + + // + // COMPLEX ... + // Complex Conditions ... + + // + bool isNewPeakOverATRUpper = + isNewPeak && + peak > atrUpper; + + // + bool isNewValeUnderATRLower = + isNewVale && + vale < atrLower; + + // + bool isDonHighUpperEqualsToPeak = + donHighUpper == peak; + + // + bool isDonLowLowerEqualsToVale = + donLowLower == vale; + + // + bool isBullishSign = ( + // + triggerConditions.x121Conditions.isBreakUpATRLower || + triggerConditions.x121Conditions.isRejectUpATRLower || + triggerConditions.x121Conditions.isBreakDonHighLower || + triggerConditions.x121Conditions.isRejectDonHighLower || + triggerConditions.x121Conditions.isBreakDonCloseLower || + triggerConditions.x121Conditions.isRejectDonCloseLower + // + ); + bool isBearishSign = ( + // + triggerConditions.x121Conditions.isBreakDownATRUpper || + triggerConditions.x121Conditions.isRejectDownATRUpper || + triggerConditions.x121Conditions.isBreakDonLowUpper || + triggerConditions.x121Conditions.isRejectDonLowUpper || + triggerConditions.x121Conditions.isBreakDonCloseUpper || + triggerConditions.x121Conditions.isRejectDonCloseUpper + // + ); + + + + // + // Check RSI in Over Bought or Over Sold ... + + // + bool isRSICrossedOverOverSold = consolidationConditions.x121Conditions.isRSICrossedOverOverSold; + bool isRSICrossedUnderOverBought = consolidationConditions.x121Conditions.isRSICrossedUnderOverBought; + + // + result = isRSICrossedOverOverSold || + isRSICrossedUnderOverBought; + if (!result) + { + return result; + } + + +/////////////////////////////////////////////// + + + +/** + * Draw X121 SMC Conditions ... + * + * @param conditions: X121SMCStrategyConditions instance Reference ... + * @param drawMarketStructure: Boolean ... + * @param drawPriceZones: Boolean ... + * @param drawDecisionZones: Boolean ... + * + * @return ( int ) + */ +int DrawX121SMCStrategyConditions( + X121SMCStrategyConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer, + bool drawMarketStructure = true, + bool drawPriceZones = true, + bool drawDecisionZones = true, + bool drawOnlyPriceZonesBoundary = true // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL || + !conditions.IsValid() || + !HasDirection(conditions.signalDir)) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.signalDir); + + // // + // bool hasPriceZones = conditions.priceZones.IsValid(); + // if (hasPriceZones && + // drawPriceZones) + // { + // // + // XCBaseObject *objects[]; + // int objectsCount = drawer.DrawPriceZone( + // conditions.priceZones, + // objects, + // conditions.signalDir, + // drawOnlyPriceZonesBoundary // + // ); + // if (IsValidSize(objectsCount)) + // { + // // + // Copy( + // objects, + // drawnObjects, + // false // + // ); + // } + // } + + // // + // bool hasDecisionZones = conditions.decisionZones.IsValid(); + // if (hasDecisionZones && + // drawDecisionZones) + // { + // // + // XCBaseObject *objects[]; + // int objectsCount = drawer.DrawPriceZone( + // conditions.decisionZones, + // objects, + // conditions.signalDir, + // drawOnlyPriceZonesBoundary // + // ); + // if (IsValidSize(objectsCount)) + // { + // // + // Copy( + // objects, + // drawnObjects, + // false // + // ); + // } + // } + + // // + // bool hasMarketStructure = conditions.marketStructure.IsValid(); + // if (hasMarketStructure && + // drawMarketStructure) + // { + // // + // XCBaseObject *objects[]; + // int objectsCount = drawer.DrawMarketStructure( + // conditions.marketStructure, + // objects // + // ); + // if (IsValidSize(objectsCount)) + // { + // // + // Copy( + // objects, + // drawnObjects, + // false // + // ); + // } + // } + + // + result = ArraySize(drawnObjects); + + // + return result; +} + + +//////////////////////////////////////////////// + + // // + // isCBarBearishFormed && + // (isPivotToDownRejected || + // isPivotToDownBreaked) && + // conditions.pivotZone.IsVale() && + // // + // // SAR ... + // isSarBearishFormed && + // // // + // // // STR ... + // // !(decisionXConditions.isStrBullish) && + // // // + // // // VWAP ... + // // !(decisionXConditions.isVWapBullishState || + // // decisionXConditions.isVWapBullishOrdered) && + // // + + + // // + // isCBarBullishFormed && + // (isPivotToUpRejected || + // isPivotToUpBreaked) && + // conditions.pivotZone.IsPeak() && + // // + // // SAR ... + // isSarBullishFormed && + // // // + // // // STR ... + // // !(decisionXConditions.isStrBearish) && + // // // + // // // VWAP ... + // // !(decisionXConditions.isVWapBearishState || + // // decisionXConditions.isVWapBearishOrdered) && + // // + +///////////////////////////////////////////////////////////////////// + + visionXConditions.isBreakedUpPrevCheMax && + visionXConditions.isCheSwitchedToBullish + + visionXConditions.isCheSwitchedToBearish && + visionXConditions.isBreakedDownPrevCheMin + +////////////////////////////////////////////////////////////////////// + + // + bool hasOrderBlock = hasBullishOrderBlocks || + hasBearishOrderBlocks; + if (hasOrderBlock) + { + // + Print("Detect Order Block ..."); + + // + XCBaseObject *drawnObjects[]; + + // + if (hasBullishOrderBlocks) + { + // + for (int i = 0; i < bullishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = bullishOBs[i]; + + // + XCBullishOrderBlockObject *iObObj; + bool isCreated = triggerCycleHelper + .mPOIDetector + .mDrawer + .CreateBullishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + if (hasBearishOrderBlocks) + { + // + for (int i = 0; i < bearishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = bearishOBs[i]; + + // + XCBearishOrderBlockObject *iObObj; + bool isCreated = triggerCycleHelper + .mPOIDetector + .mDrawer + .CreateBearishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + int drawnCount = ArraySize(drawnObjects); + if (IsValidSize(drawnCount)) + { + Print(""); + } + } + +////////////////////////////////////////////////////////////////////// + + + // + // Summarize Conditions ... + + // + bool isCondition1Bullish = + // + // Vision ... + ( + // + false + // + ) + // + && + // + // Consolidation ... + ( + // + true + // + ) + // + && + // + // Verification ... + ( + // + true + // + ) + // + && + // + // Analyse ... + ( + // + true + // + ) + // + && + // + // Decision ... + ( + // + true + // + ) + // + ; + + // + bool isCondition1Bearish = + // + // Vision ... + ( + // + false + // + ) + // + && + // + // Consolidation ... + ( + // + true + // + ) + // + && + // + // Verification ... + ( + // + true + // + ) + // + && + // + // Analyse ... + ( + // + true + // + ) + // + && + // + // Decision ... + ( + // + true + // + ) + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + // conditions.pivot = + // isCondition1Bullish + // ? conditions.pivotZone.upper + // : conditions.pivotZone.lower; + } + + +///////////////////////////////////////////////////////////////////////// + + // + // DRAW ... + // + + // + XCBaseObject *drawnObjects[]; + + // + if (hasBullishOrderBlocks) + { + // + for (int i = 0; i < bullishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bullishOBs[i]; + + // + XCBullishOrderBlockObject *iObObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateBullishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + if (hasBearishOrderBlocks) + { + // + for (int i = 0; i < bearishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bearishOBs[i]; + + // + XCBearishOrderBlockObject *iObObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateBearishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + // if (hasOldestBullishOB) + // { + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBullishOrderBlock( + // oldestBullishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasYoungestBullishOB) + // { + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBullishOrderBlock( + // youngestBullishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasOldestBearishOB) + // { + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBearishOrderBlock( + // oldestBearishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasYoungestBearishOB) + // { + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBearishOrderBlock( + // youngestBearishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + +///////////////////////////////////////////////////////////////////////// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.market.cycle.helper.class.old.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.market.cycle.helper.class.old.mq5 new file mode 100644 index 0000000..492a1aa --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.market.cycle.helper.class.old.mq5 @@ -0,0 +1,4143 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121SMCCycleHelper +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +// +// Implementations ... + +enum ENUM_X_CYCLES +{ + X_CYCLE_NONE, + X_CYCLE_TRIGGER, + X_CYCLE_DECISION, + X_CYCLE_ANALYSE, + X_CYCLE_VERIFICATION, + X_CYCLE_CONSOLIDATION, + X_CYCLE_VISION, +}; + +string ToString(ENUM_X_CYCLES value) +{ + // + string result = EnumToString(value); + + // + StringReplace(result, "X_CYCLE_", ""); + + // + return result; +} + +enum ENUM_X_CYCLE_EVENTS +{ + SAR_CHANGE_DETECTED, + NEW_PEAK_DETECTED, + NEW_VALE_DETECTED, + PIVOT_POINT_DETECTED, + VWAP_ORDER_CHANGE_ETECTED, + VWAP_STATE_CHANGE_DETCTED, + CONSOLIDATION_BREAKED_DETECTED, + PEAK_PIVOT_STARTED, + PEAK_PIVOT_ENDED, + VALE_PIVOT_STARTED, + VALE_PIVOT_ENDED, +}; + +class XC121SMCCycleHelper : public XCBase +{ + // + public: + // + // Props ... + + // + // X121 ... + XCX121Helper *mX121Helper; + + // + // POI Detector ... + XCPOIDetector *mPOIDetector; + + // + // Bar Analyser + XCBarAnalyser *mBarAnalyser; + + // + // Constructor(s) ... + XC121SMCCycleHelper() + { + Default(); + } + + // + // Deconstructor ... + ~XC121SMCCycleHelper() + { + DeInit(); + } + + // + // Getter/Setter(s) ... + + /** + * Get Max llowed Changes to Save ... + * + * @return ( int ) + */ + int MaxAllowedSavedChanges() + { + return mMaxAllowedSavedChanges; + } + + /** + * Set Max llowed Changes to Save ... + * + * @param value: Integer ... + */ + void MaxAllowedSavedChanges(int value) + { + // + if (value < 10) + { + value = 10; + } + + // + mMaxAllowedSavedChanges = value; + } + + /** + * Get Consolidation Loopback Length ... + * + * @return ( int ) + */ + int ConsolidationLoopback() + { + return mConsolidationLoopback; + } + + /** + * Set Consolidation Loopback Length ... + * + * @param value: Integer ... + */ + void ConsolidationLoopback(int value) + { + // + if (value < 7) + { + value = 7; + } + + // + mConsolidationLoopback = value; + } + + /** + * Get Valid Pivot Points Repetition Length ... + * min => 7 + * + * @return ( int ) + */ + int ValidPivotRepetition() + { + return mValidPivotRepetition; + } + + /** + * Set Valid Pivot Points Repetition Length ... + * + * @param value: Integer ... + * min => 7 + */ + void ValidPivotRepetition(int value) + { + // + if (value < 7) + { + value = 7; + } + + // + mValidPivotRepetition = value; + } + + // + // Actions ... + + /** + * Initialize ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + * @param x121Inputs: X121Inputs instance ... + * + * @return ( bool ) + */ + bool Init( + string symbol, + ENUM_TIMEFRAMES period, + X121Inputs &x121Inputs // + ) + { + // + bool result = false; + + // + result = IsValid(symbol) && + IsValid(period); + if (!result) + { + return result; + } + + // + // X121 ... + mX121Helper = new XCX121Helper(); + result = mX121Helper.Init( + symbol, + period, + x121Inputs // + ); + if (!result) + { + return result; + } + + // + mPOIDetector = new XCPOIDetector( + symbol, + period // + ); + mPOIDetector.MaxNumberOfRequiredPOIs(10); + mPOIDetector.Init(); + + // + // Initialize Bar Analyser Class Instance ... + mBarAnalyser = new XCBarAnalyser(); + + // + // Set Chart Style ... + ApplyChartStyle(); + + // + return result; + } + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + // + string result = NULL; + + // + result = mX121Helper.GetSymbol(); + + // + return result; + } + + /** + * Retrieve TimeFrame (Period) ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + result = mX121Helper.GetPeriod(); + + // + return result; + } + + /** + * Get Specified Bar ... + * + * @param source: XOHCL instance, Source Bar ... + * @param bar: XOHCL instance, Dest Bar ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &source, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = + IsValid(symbol) && + IsValid(period) && + source.IsValid(); + if (!result) + { + return result; + } + + // + int index = iBarShift( + symbol, + period, + source.time // + ); + result = bar.Init( + symbol, + period, + index // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + return result; + } + + /** + * Retrieve Specified Bar ... + * + * @param bar: XOHCL instance ... + * @param index: Integer ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &bar, + int index = 0 // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (index < 0) + { + index = 0; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + /** + * Retrieve Specified Bar ... + * + * @param bar: XOHCL instance ... + * @param time: Datetime ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &bar, + datetime time = NULL // + ) + { + // + bool result = false; + + // + int index = GetBarIndex(time); + result = GetBar(bar, + index // + ); + + // + return result; + } + + /** + * Retrieve Specified Time Bar Index ... + * + * @param time: DateTime ... + * + * @return ( int ) + */ + int GetBarIndex(datetime time = NULL) + { + // + int result = -1; + + // + time = NormalizeTime(time); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = iBarShift( + symbol, + period, + time // + ); + + // + return result; + } + + /** + * Retrieve Cycle Conditions ... + * + * @param events: ENUM_X_CYCLE_EVENTS member, Array ... + * @param conditions: X121SMCCycleConditions instance ... + * @param barIndex: Integer ... + * @param loopback: Integer ... + * + * @return ( bool ) + */ + bool GetConditions( + ENUM_X_CYCLE_EVENTS &events[], + ENUM_XPOI_EVENTS &poiEvents[], + X121SMCCycleConditions &conditions, + int barIndex = 0, + int loopback = 7 // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 5) + { + loopback = 5; + } + + // + Clean(events); + Clean(poiEvents); + conditions.Clean(); + + // + result = mX121Helper.GetConditions( + conditions.x121Conditions, + barIndex, + loopback // + ); + if (!result) + { + // + conditions.Clean(); + return result; + } + + // + mPOIDetector.Update(poiEvents); + mPOIDetector.GetState(conditions.state); + + // + conditions.symbol = conditions.x121Conditions.symbol; + conditions.period = conditions.x121Conditions.period; + conditions.time = TimeCurrent(); + + // + result = conditions.IsValid(); + + // + if (result) + { + // + if (!IsValidSize(ArraySize(mPivots))) + { + Detect(barIndex); + } + + // + Calculate( + barIndex, + events, + conditions // + ); + } + + // + return result; + } + + /** + * Detect Market Structure ... + * + * @param model: XMarketStructure instance Reference ... + * + * @return ( bool ) + */ + bool DetectMarketStructure( + XMarketStructure &model // + ) + { + // + bool result = false; + + // + model.Clean(); + + // + int barIndex = 0; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + model.symbol = symbol; + model.period = period; + + // + int highestPeakIndex = -1; + double highestPeakVale = 0; + double highestPeak = mX121Helper + .GetHighestPeak( + barIndex, + highestPeakIndex, + highestPeakVale // + ); + + // + int lowestValeIndex = -1; + double lowestValePeak = 0; + double lowestVale = mX121Helper + .GetLowestVale( + barIndex, + lowestValeIndex, + lowestValePeak // + ); + + // + result = IsValidIndex(highestPeakIndex) && + IsValidIndex(lowestValeIndex); + if (!result) + { + return result; + } + + // + model.bias = + highestPeakIndex < lowestValeIndex + ? X_DIRECTION_BEARISH + : highestPeakIndex > lowestValeIndex + ? X_DIRECTION_BULLISH + : X_DIRECTION_NONE; + + // + result = HasDirection(model.bias); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(model.bias); + + // + // Looking for Change Of Character Proved ... + + // + // Bullish Bias: + // - Price Must Break Up Lowst Vale's Peak; + // - Create a Vale Above Lowest Vale's Peak; + + // + // Bearish Bias: + // - Price Must Breake Down HighestPeak's Vale; + // - Create a Peak Under Highest Peak's Vale; + + // + // Checking Peak Breake Up ... + int lowestValePeakBreakeUpIndex = -1; + for (int i = lowestValeIndex; i >= barIndex; i--) + { + // + XOHCL iBar; + result = GetBar(iBar, i); + if (!result) + { + continue; + } + + // + bool isBreake = iBar.IsBreakeUp(lowestValePeak); + if (isBreake) + { + // + lowestValePeakBreakeUpIndex = i; + break; + } + } + bool isValidBreakeUpLowestValePeak = IsValidIndex(lowestValePeakBreakeUpIndex) && + lowestValePeakBreakeUpIndex <= lowestValeIndex; + + // + // Checking Vale Breake Down ... + int highestPeakValeBreakeDownIndex = -1; + for (int i = highestPeakIndex; i >= barIndex; i--) + { + // + XOHCL iBar; + result = GetBar(iBar, i); + if (!result) + { + continue; + } + + // + bool isBreake = iBar.IsBreakeDown(highestPeakVale); + if (isBreake) + { + // + highestPeakValeBreakeDownIndex = i; + break; + } + } + bool isValidBreakeDownHighestPeakVale = IsValidIndex(highestPeakValeBreakeDownIndex) && + highestPeakValeBreakeDownIndex <= highestPeakIndex; + // + result = isBullish + ? isValidBreakeUpLowestValePeak + : isValidBreakeDownHighestPeakVale; + if (!result) + { + return result; + } + + // + // Checking Create a Vale above Peak ... + int valeAboveLowestValePeakIndex = -1; + double valeAboveLowestValePeakPeak = 0; + for (int i = lowestValePeakBreakeUpIndex; i >= barIndex; i--) + { + // + double iVale = mX121Helper.GetVale(i); + + // + bool isValid = + iVale > 0 && + iVale > lowestValePeak; + if (isValid) + { + // + valeAboveLowestValePeakIndex = i; + valeAboveLowestValePeakPeak = mX121Helper.GetPeak(i); + break; + } + } + bool isValidValeAboveLowestValePeak = IsValidIndex(valeAboveLowestValePeakIndex) && + valeAboveLowestValePeakIndex < lowestValePeakBreakeUpIndex; + + // + // Checking Create a Peak below Vale ... + int peakBelowHighestPeakValeIndex = -1; + double peakBelowHighestPeakValeVale = 0; + for (int i = highestPeakValeBreakeDownIndex; i >= barIndex; i--) + { + // + double iPeak = mX121Helper.GetPeak(i); + + // + bool isValid = + iPeak > 0 && + iPeak < highestPeakVale; + if (isValid) + { + // + peakBelowHighestPeakValeIndex = i; + peakBelowHighestPeakValeVale = mX121Helper.GetVale(i); + break; + } + } + bool isValidPeakBelowHighestPeakVale = IsValidIndex(peakBelowHighestPeakValeIndex) && + peakBelowHighestPeakValeIndex < highestPeakValeBreakeDownIndex; + + // + result = isBullish ? isValidValeAboveLowestValePeak + : isValidPeakBelowHighestPeakVale; + if (!result) + { + return result; + } + + // + // Now we Have to Detect Valid Peaks and Valid Vales Here ... + // based on Detected Range ... + + // + XPVPivotPoint iPeakPoint; + XPVPivotPoint iValePoint; + XPriceZones peakPriceZone; + XPriceZones valePriceZone; + + // + XPOIState state; + mPOIDetector.GetState( + state // + ); + + // + int minRepetition = 5; + + // + int from = + isBullish + ? valeAboveLowestValePeakIndex + : peakBelowHighestPeakValeIndex; + for (int i = from; i >= barIndex; i--) + { + // + XOHCL iBar; + bool isInited = GetBar(iBar, i); + + // + double iPeak = mX121Helper.GetPeak(i); + double iVale = mX121Helper.GetVale(i); + + // + bool hasPeakPriceInsideZone = CalculatePriceInsideZones( + peakPriceZone, + state, + iPeak // + ); + bool hasValePriceInsideZone = CalculatePriceInsideZones( + valePriceZone, + state, + iVale // + ); + + // + if (hasPeakPriceInsideZone) + { + // + // Peak ... + if (!iPeakPoint.IsValid()) + { + // + // Initialization ... + iPeakPoint.value = iPeak; + iPeakPoint.repetition = 1; + iPeakPoint.type = XPV_PEAK; + iPeakPoint.time = iBar.time; + } + else + { + // + if (iPeakPoint.value == iPeak) + { + iPeakPoint.repetition++; + } + else + { + // + if (iPeakPoint.repetition > minRepetition) + { + // + AddRef( + iPeakPoint, + model.peaks // + ); + + // + AddRef( + peakPriceZone, + model.peakPriceZones // + ); + } + + // + iPeakPoint.Clean(); + peakPriceZone.Clean(); + iPeakPoint.value = iPeak; + iPeakPoint.repetition = 1; + iPeakPoint.type = XPV_PEAK; + iPeakPoint.time = iBar.time; + } + } + } + + // + if (hasValePriceInsideZone) + { + // + // Vale ... + if (!iValePoint.IsValid()) + { + // + // Initialization ... + iValePoint.value = iVale; + iValePoint.repetition = 1; + iValePoint.type = XPV_VALE; + iValePoint.time = iBar.time; + } + else + { + // + if (iValePoint.value == iVale) + { + iValePoint.repetition++; + } + else + { + // + if (iValePoint.repetition > minRepetition) + { + // + AddRef( + iValePoint, + model.vales // + ); + + // + AddRef( + valePriceZone, + model.valePriceZones // + ); + } + + // + iValePoint.Clean(); + valePriceZone.Clean(); + iValePoint.value = iVale; + iValePoint.repetition = 1; + iValePoint.type = XPV_VALE; + iValePoint.time = iBar.time; + } + } + } + } + + // + // in Bullish Bias we Looking for Vales Oder ... + // in Bearish Bias we Looking for Peaks Oder ... + + // + // Bullish Bias Drawn ... + if (isBullish) + { + // + result = GetBar( + model.lowestValeBar, + lowestValeIndex // + ); + if (!result) + { + return result; + } + + // + if (isValidBreakeUpLowestValePeak) + { + // + result = GetBar( + model.lowestValePeakBreakeUpBar, + lowestValePeakBreakeUpIndex // + ); + if (!result) + { + return result; + } + } + + // + if (isValidValeAboveLowestValePeak) + { + // + result = GetBar( + model.valeAboveLowestValePeakBar, + valeAboveLowestValePeakIndex // + ); + if (!result) + { + return result; + } + } + } + + // + // Bearish Bias Drawn ... + if (!isBullish) + { + // + result = GetBar( + model.highestPeakBar, + highestPeakIndex // + ); + if (!result) + { + return result; + } + + // + if (isValidBreakeDownHighestPeakVale) + { + // + result = GetBar( + model.highestPeakValeBreakeDownBar, + highestPeakValeBreakeDownIndex // + ); + if (!result) + { + return result; + } + } + + // + if (isValidPeakBelowHighestPeakVale) + { + // + result = GetBar( + model.peakBelowHighestPeakValeBar, + peakBelowHighestPeakValeIndex // + ); + if (!result) + { + return result; + } + } + } + + // + result = model.IsValid(); + + // + return result; + } + + // + // Tools ... + + /** + * Get POI State of Specified Pivot ... + * + * @param pivot: XPVPivot instance Reference ... + * @param lookupSwingHighs: Boolean ... + * @param lookupSwingLows: Boolean ... + * @param lookupSupportZones: Boolean ... + * @param lookupResistanceZones: Boolean ... + * @param lookupSupplyZones: Boolean ... + * @param lookupDemandZones: Boolean ... + * @param lookupBullishOrderBlocks: Boolean ... + * @param lookupBearishOrderBlocks: Boolean ... + * @param lookupBullishFairValueGaps: Boolean ... + * @param lookupBearishFairValueGaps: Boolean ... + * @param lookupBullishRejectionBars: Boolean ... + * @param lookupBearishRejectionBars: Boolean ... + * @param lookupBullishMomentumBars: Boolean ... + * @param lookupBearishMomentumBars: Boolean ... + * + * @return ( bool ) + */ + bool FillPivotState( + XPVPivot &pivot, + bool lookupSwingHighs = true, + bool lookupSwingLows = true, + bool lookupSupportZones = true, + bool lookupResistanceZones = true, + bool lookupSupplyZones = true, + bool lookupDemandZones = true, + bool lookupBullishOrderBlocks = true, + bool lookupBearishOrderBlocks = true, + bool lookupBullishFairValueGaps = true, + bool lookupBearishFairValueGaps = true, + bool lookupBullishRejectionBars = true, + bool lookupBearishRejectionBars = true, + bool lookupBullishMomentumBars = true, + bool lookupBearishMomentumBars = true // + ) + { + // + bool result = false; + + // + XPOIState state; + state.Clean(); + + // + result = pivot.IsValid(); + if (!result) + { + return result; + } + + // + XPOIState _state; + mPOIDetector.GetState(_state); + result = _state.IsValid() && + _state.HasChild(); + if (!result) + { + return result; + } + + // + DetectPivotPOIs( + pivot, + _state, + state, + lookupSwingHighs, + lookupSwingLows, + lookupSupportZones, + lookupResistanceZones, + lookupSupplyZones, + lookupDemandZones, + lookupBullishOrderBlocks, + lookupBearishOrderBlocks, + lookupBullishFairValueGaps, + lookupBearishFairValueGaps, + lookupBullishRejectionBars, + lookupBearishRejectionBars, + lookupBullishMomentumBars, + lookupBearishMomentumBars // + ); + + // + result = state.IsValid() && + state.HasChild(); + if (result) + { + // + pivot.state = state; + + // + CalculatePivotTickZone(pivot); + } + + // + return result; + } + + /** + * Validate Specified Pivot's State ... + * + * @param pivot: XPVPivot instance Reference ... + * @param barIndex: Integer ... + */ + void ValidatePivotState( + XPVPivot &pivot, + int barIndex = 0 // + ) + { + // + if (!pivot.IsValid() || + !pivot.state.IsValid() || + !pivot.state.HasChild()) + { + return; + } + + // + double upperr = pivot.upper; + double lower = pivot.lower; + + // + XOHCL cBar; + bool isInited = cBar.Init( + pivot.symbol, + pivot.period, + barIndex // + ); + if (!isInited) + { + return; + } + + // + int count = 0; + + // + double ask = GetAsk(pivot.symbol); + double bid = GetBid(pivot.symbol); + + // + double pivotMid = pivot.CalculateMid(); + + // + // Try to Validate States ... + + // + bool isPriceInPremium = + // + ask > pivotMid && + bid > pivotMid && + cBar.low > pivotMid + // + ; + + // + bool isPriceInDiscount = + // + ask < pivotMid && + bid < pivotMid && + cBar.high < pivotMid + // + ; + + // + // Swings ... + XCSwing *tmpSwings[]; + + // + // Swing Highs ... + Clean(tmpSwings); + count = pivot.state.CountSwingHighs(); + if (IsValidSize(count)) + { + // + if (isPriceInPremium) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = pivot.state.swingHighs[i]; + + // + bool isValid = + // + iSwing.GetTime() >= pivot.from && + iSwing.GetTime() <= pivot.to && + iSwing.GetValue() > pivotMid + // + ; + if (isValid) + { + // + Add( + iSwing, + tmpSwings // + ); + } + } + + // + Copy( + tmpSwings, + pivot.state.swingHighs // + ); + } + } + + // + // Swing Lows ... + Clean(tmpSwings); + count = pivot.state.CountSwingLows(); + if (IsValidSize(count)) + { + // + if (isPriceInDiscount) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = pivot.state.swingLows[i]; + + // + bool isValid = + // + iSwing.GetTime() >= pivot.from && + iSwing.GetTime() <= pivot.to && + iSwing.GetValue() < pivotMid + // + ; + if (isValid) + { + // + Add( + iSwing, + tmpSwings // + ); + } + } + + // + Copy( + tmpSwings, + pivot.state.swingLows // + ); + } + } + + // + Clean(tmpSwings); + + // + // Rejection Bars ... + XCRejectionBar *tmpRejections[]; + + // + // Bullish ... + Clean(tmpRejections); + count = pivot.state.CountBullishRejectionBars(); + if (IsValidSize(count)) + { + // + if (isPriceInDiscount) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iRejection = pivot.state.bullishRejectionBars[i]; + + // + XOHCL iBar; + bool isFilled = iRejection.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValid = + // + iRejection.BarTime() >= pivot.from && + iBar.high < pivotMid + // + ; + if (isValid) + { + // + Add( + iRejection, + tmpRejections // + ); + } + } + + // + Copy( + tmpRejections, + pivot.state.bullishRejectionBars // + ); + } + } + + // + // Bearish ... + Clean(tmpRejections); + count = pivot.state.CountBearishRejectionBars(); + if (IsValidSize(count)) + { + // + if (isPriceInPremium) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iRejection = pivot.state.bearishRejectionBars[i]; + + // + XOHCL iBar; + bool isFilled = iRejection.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValid = + // + iRejection.BarTime() >= pivot.from && + iBar.low > pivotMid + // + ; + if (isValid) + { + // + Add( + iRejection, + tmpRejections // + ); + } + } + + // + Copy( + tmpRejections, + pivot.state.bearishRejectionBars // + ); + } + } + + // + Clean(tmpRejections); + + // + // Support Zone ... + XCSupportZone *tmpSupports[]; + count = pivot.state.CountSupportZones(); + if (IsValidSize(count)) + { + // + if (isPriceInDiscount) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = pivot.state.supportZones[i]; + + // + bool isValid = + // + iZone.Upper() < pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpSupports // + ); + } + } + + // + Copy( + tmpSupports, + pivot.state.supportZones // + ); + } + } + + // + Clean(tmpSupports); + + // + // Resistance Zone ... + XCResistanceZone *tmpResistances[]; + count = pivot.state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + if (isPriceInPremium) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = pivot.state.resistanceZones[i]; + + // + bool isValid = + // + iZone.Lower() > pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpResistances // + ); + } + } + + // + Copy( + tmpResistances, + pivot.state.resistanceZones // + ); + } + } + + // + Clean(tmpResistances); + + // + // Supply Zones ... + XCSupplyZone *tmpSupplies[]; + count = pivot.state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + if (isPriceInPremium) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = pivot.state.supplyZones[i]; + + // + bool isValid = + // + iZone.Lower() > pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpSupplies // + ); + } + } + + // + Copy( + tmpSupplies, + pivot.state.supplyZones // + ); + } + } + + // + Clean(tmpSupplies); + + // + // Demand Zones ... + XCDemandZone *tmpDemands[]; + count = pivot.state.CountDemandZones(); + if (IsValidSize(count)) + { + // + if (isPriceInDiscount) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = pivot.state.demandZones[i]; + + // + bool isValid = + // + iZone.Upper() < pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpDemands // + ); + } + } + + // + Copy( + tmpDemands, + pivot.state.demandZones // + ); + } + } + + // + Clean(tmpDemands); + + // + // Order Blocks ... + XCOrderBlock *tmpOrderBlocks[]; + + // + // Bullish ... + Clean(tmpOrderBlocks); + count = pivot.state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + if (isPriceInDiscount) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = pivot.state.bullishOrderBlocks[i]; + + // + bool isValid = + // + iZone.Upper() < pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpOrderBlocks // + ); + } + } + + // + Copy( + tmpOrderBlocks, + pivot.state.bullishOrderBlocks // + ); + } + } + + // + // Bearish ... + Clean(tmpOrderBlocks); + count = pivot.state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + if (isPriceInPremium) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = pivot.state.bearishOrderBlocks[i]; + + // + bool isValid = + // + iZone.Lower() > pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpOrderBlocks // + ); + } + } + + // + Copy( + tmpOrderBlocks, + pivot.state.bearishOrderBlocks // + ); + } + } + + // + Clean(tmpOrderBlocks); + + // + // Fair Value Gaps ... + XCFVG *tmpFVGs[]; + + // + // Bullish ... + Clean(tmpFVGs); + count = pivot.state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + if (isPriceInDiscount) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = pivot.state.bullishFairValueGaps[i]; + + // + bool isValid = + // + iZone.Upper() < pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpFVGs // + ); + } + } + + // + Copy( + tmpFVGs, + pivot.state.bullishFairValueGaps // + ); + } + } + + // + // Bearish ... + Clean(tmpFVGs); + count = pivot.state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + if (isPriceInPremium) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = pivot.state.bearishFairValueGaps[i]; + + // + bool isValid = + // + iZone.Lower() > pivotMid + // + ; + if (isValid) + { + // + Add( + iZone, + tmpFVGs // + ); + } + } + + // + Copy( + tmpFVGs, + pivot.state.bearishFairValueGaps // + ); + } + } + + // + Clean(tmpFVGs); + + // + } + + /** + * Detect Cycle Trend Based On Pivots ... + * + * @param dir: ENUM_X_DIRECTION member Reference ... + * @param numberOfPivots: Integer ... + * @param maxAllowedLoopback: Integer ... + * @param minRequiredPivotVerification: Integer ... + * + * @return ( bool ) + */ + bool DetectTrend( + ENUM_X_DIRECTION &dir, + int numberOfPivots = 3, + int maxAllowedLoopback = 576, + int minRequiredPivotVerification = 5 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + if (numberOfPivots < 3) + { + numberOfPivots = 3; + } + + // + int index = 0; + double peaks[]; + double vales[]; + double peak = 0; + double vale = 0; + int peaksVerified = 0; + int valesVerified = 0; + bool canContinue = true; + while (canContinue) + { + // + // Peak ... + bool lookupPeak = ArraySize(peaks) < numberOfPivots; + if (lookupPeak) + { + // + double iPeak = mX121Helper.GetPeak(index); + if (iPeak == peak) + { + peaksVerified++; + } + else + { + // + if (peaksVerified >= minRequiredPivotVerification) + { + // + Add( + iPeak, + peaks // + ); + + // + peaksVerified = 0; + lookupPeak = ArraySize(peaks) < numberOfPivots; + } + else + { + peak = iPeak; + } + } + } + + // + // Vale ... + bool lookupVale = ArraySize(vales) < numberOfPivots; + if (lookupVale) + { + // + double iVale = mX121Helper.GetVale(index); + if (iVale == vale) + { + valesVerified++; + } + else + { + // + if (valesVerified >= minRequiredPivotVerification) + { + // + Add( + iVale, + vales // + ); + + // + valesVerified = 0; + lookupVale = ArraySize(vales) < numberOfPivots; + } + else + { + vale = iVale; + } + } + } + + // + canContinue = index < maxAllowedLoopback && + (lookupPeak || + lookupVale); + if (canContinue) + { + index++; + } + } + + // + int verifications = 0; + + // + // Peaks ... + int peaksCount = ArraySize(peaks); + if (!result && + peaksCount == numberOfPivots) + { + // + verifications = 0; + for (int i = 0; i < peaksCount - 1; i++) + { + // + double iValue = peaks[i]; + double nValue = peaks[i + 1]; + if (iValue < nValue) + { + verifications++; + } + } + + // + result = verifications == numberOfPivots - 1; + if (result) + { + dir = X_DIRECTION_BEARISH; + } + } + + // + // Vales ... + int valesCount = ArraySize(vales); + if (!result && + valesCount == numberOfPivots) + { + // + verifications = 0; + for (int i = 0; i < valesCount - 1; i++) + { + // + double iValue = vales[i]; + double nValue = vales[i + 1]; + if (iValue > nValue) + { + verifications++; + } + } + + // + result = verifications == numberOfPivots - 1; + if (result) + { + dir = X_DIRECTION_BULLISH; + } + } + + // + return result; + } + + /** + * Detect Market Structure based on Peaks and Vales ... + * + * @param dir: ENUM_X_DIRECTION member Reference ... + * @param minVerification: Integer ... + * + * @return ( bool ) + */ + bool HasPVDirection( + ENUM_X_DIRECTION &dir, + int minVerification = 12 // + ) + { + // + bool result = false; + + // + if (minVerification < 7) + { + minVerification = 7; + } + + // + dir = X_DIRECTION_NONE; + + // + int bullishSum = mBullishPeaks + mBullishVales; + int bearishSum = mBearishPeaks + mBearishVales; + + // + int diff = MathAbs(bullishSum - bearishSum); + bool isDiffPassed = diff >= minVerification; + result = isDiffPassed; + if (!result) + { + return result; + } + + // + dir = bullishSum > bearishSum + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Change Values Actions ... + + /** + * Count Saved Parabolic Sar Changes ... + * + * @return ( int ) + */ + int CountSarChanges() + { + return ArraySize(mSarChanges); + } + + /** + * Fill Saved Sar Changes ... + * + * @param changes: XValueChange instance Array Reference ... + * + * @return ( int ) + */ + int FillSarChanges( + XValueChange &changes[] // + ) + { + // + Clean(changes); + + // + Copy( + mSarChanges, + changes // + ); + + // + int result = ArraySize(changes); + + // + return result; + } + + /** + * Retrieve Last Sar Changes ... + * + * @param change: XValueChange instance ... + * + * @return ( bool ) + */ + bool GetLastSarChange(XValueChange &change) + { + // + bool result = false; + + // + result = GetLastItem( + change, + mSarChanges // + ); + + // + return result; + } + + /** + * Count Saved Peaks Changes ... + * + * @return ( int ) + */ + int CountPeaksChanges() + { + return ArraySize(mPeaksChanges); + } + + /** + * Fill Saved Peaks Changes ... + * + * @param changes: XValueChange instance Array Reference ... + * + * @return ( int ) + */ + int FillPeaksChanges( + XValueChange &changes[] // + ) + { + // + Clean(changes); + + // + Copy( + mPeaksChanges, + changes // + ); + + // + int result = ArraySize(changes); + + // + return result; + } + + /** + * Retrieve Last Peak Changes ... + * + * @param change: XValueChange instance ... + * + * @return ( bool ) + */ + bool GetLastPeakChange(XValueChange &change) + { + // + bool result = false; + + // + result = GetLastItem( + change, + mPeaksChanges // + ); + + // + return result; + } + + /** + * Count Saved Vales Changes ... + * + * @return ( int ) + */ + int CountValesChanges() + { + return ArraySize(mValesChanges); + } + + /** + * Fill Saved Vales Changes ... + * + * @param changes: XValueChange instance Array Reference ... + * + * @return ( int ) + */ + int FillValesChanges( + XValueChange &changes[] // + ) + { + // + Clean(changes); + + // + Copy( + mValesChanges, + changes // + ); + + // + int result = ArraySize(changes); + + // + return result; + } + + /** + * Retrieve Last Vale Changes ... + * + * @param change: XValueChange instance ... + * + * @return ( bool ) + */ + bool GetLastValeChange(XValueChange &change) + { + // + bool result = false; + + // + result = GetLastItem( + change, + mValesChanges // + ); + + // + return result; + } + + /** + * Count Saved VWap Order Changes ... + * + * @return ( int ) + */ + int CountVWapOrderChanges() + { + return ArraySize(mVWapOrderChanges); + } + + /** + * Fill Saved VWap Order Changes ... + * + * @param changes: XValueChange instance Array Reference ... + * + * @return ( int ) + */ + int FillVWapOrderChanges( + XValueChange &changes[] // + ) + { + // + Clean(changes); + + // + Copy( + mVWapOrderChanges, + changes // + ); + + // + int result = ArraySize(changes); + + // + return result; + } + + /** + * Retrieve Last VWap Order Changes ... + * + * @param change: XValueChange instance ... + * + * @return ( bool ) + */ + bool GetLastVWapOrderChange(XValueChange &change) + { + // + bool result = false; + + // + result = GetLastItem( + change, + mVWapOrderChanges // + ); + + // + return result; + } + + /** + * Count Saved VWap State Changes ... + * + * @return ( int ) + */ + int CountVWapStateChanges() + { + return ArraySize(mVWapStateChanges); + } + + /** + * Fill Saved VWap State Changes ... + * + * @param changes: XValueChange instance Array Reference ... + * + * @return ( int ) + */ + int FillVWapStateChanges( + XValueChange &changes[] // + ) + { + // + Clean(changes); + + // + Copy( + mVWapStateChanges, + changes // + ); + + // + int result = ArraySize(changes); + + // + return result; + } + + /** + * Retrieve Last VWap State Changes ... + * + * @param change: XValueChange instance ... + * + * @return ( bool ) + */ + bool GetLastVWapStateChange(XValueChange &change) + { + // + bool result = false; + + // + result = GetLastItem( + change, + mVWapStateChanges // + ); + + // + return result; + } + + /** + * Count Founded Consolidation Zones ... + * + * @return ( int ) + */ + int CountConsolidationZones() + { + return ArraySize(mConsolidationZones); + } + + /** + * Fill Broken Consolidations ... + * + * @param consolidations: XConsolidationZone instance Array Reference ... + * + * @return ( int ) + */ + int FillConsolidationZones( + XConsolidationZone &consolidations[] // + ) + { + // + Clean(consolidations); + + // + Copy( + mConsolidationZones, + consolidations // + ); + + // + int result = ArraySize(consolidations); + + // + return result; + } + + /** + * Retrieve Last Consolidation Breaks ... + * + * @param change: XValueChange instance ... + * + * @return ( bool ) + */ + bool GetLastConsolidationZone(XConsolidationZone &zone) + { + // + bool result = false; + + // + result = GetLastItem( + zone, + mConsolidationZones // + ); + + // + return result; + } + + /** + * Count Pivot Points Change ... + * + * @return ( int ) + */ + int CountPivotPoints() + { + return ArraySize(mPivotPoints); + } + + /** + * Retrieve All Pivot Point Changes as a Collection ... + * + * @param pivots: XPVPivotPoint instance Reference ... + * + * @return ( int ) + */ + int FillPivotPoints(XPVPivotPoint &pivots[]) + { + // + int result = 0; + + // + Clean(pivots); + + // + int count = CountPivotPoints(); + if (!IsValidSize(pivots)) + { + return result; + } + + // + Copy( + mPivotPoints, + pivots // + ); + + // + result = ArraySize(pivots); + + // + return result; + } + + /** + * Retrieve All Peak Pivot Point Changes as a Collection ... + * + * @param pivots: XPVPivotPoint instance Reference ... + * + * @return ( int ) + */ + int FillPeakPivotPoints(XPVPivotPoint &pivots[]) + { + // + int result = 0; + + // + Clean(pivots); + + // + int count = CountPivotPoints(); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XPVPivotPoint iPivot = mPivotPoints[i]; + + // + bool isValid = iPivot.IsPeak(); + if (isValid) + { + // + AddRef( + iPivot, + pivots // + ); + } + } + + // + result = ArraySize(pivots); + + // + return result; + } + + /** + * Get Last Peaks Pivot Point ... + * + * @param pivot: XPVPivotPoint instance Reference ... + * + * @return ( bool ) + */ + bool GetLastPeakPivotPoint(XPVPivotPoint &pivot) + { + // + bool result = false; + + // + pivot.Clean(); + + // + XPVPivotPoint pivots[]; + int count = FillPeakPivotPoints(pivots); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + pivot = pivots[count - 1]; + + // + return result; + } + + /** + * Retrieve All Vale Pivot Point Changes as a Collection ... + * + * @param pivots: XPVPivotPoint instance Reference ... + * + * @return ( int ) + */ + int FillValePivotPoints(XPVPivotPoint &pivots[]) + { + // + int result = 0; + + // + Clean(pivots); + + // + int count = CountPivotPoints(); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XPVPivotPoint iPivot = mPivotPoints[i]; + + // + bool isValid = iPivot.IsVale(); + if (isValid) + { + // + AddRef( + iPivot, + pivots // + ); + } + } + + // + result = ArraySize(pivots); + + // + return result; + } + + /** + * Get Last Vale Pivot Point ... + * + * @param pivot: XPVPivotPoint instance Reference ... + * + * @return ( bool ) + */ + bool GetLastValePivotPoint(XPVPivotPoint &pivot) + { + // + bool result = false; + + // + pivot.Clean(); + + // + XPVPivotPoint pivots[]; + int count = FillValePivotPoints(pivots); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + pivot = pivots[count - 1]; + + // + return result; + } + + /** + * Count Calculated Pivots ... + * + * @return ( int ) + */ + int CountPivots() + { + return ArraySize(mPivots); + } + + /** + * Fill Pivots ... + * + * @param pivots: XPVPivot instance Reference Array ... + * + * @return ( int ) + */ + int FillPivots(XPVPivot &pivots[]) + { + // + int result = 0; + + // + Clean(pivots); + + // + Copy( + mPivots, + pivots // + ); + + // + result = ArraySize(pivots); + + // + return result; + } + + /** + * Retrieve Last Pivot ... + * + * @param pivot: XPVPivot instance Reference ... + * + * @return ( bool ) + */ + bool GetLastPivot(XPVPivot &pivot) + { + // + bool result = false; + + // + pivot.Clean(); + + // + XPVPivot pivots[]; + int count = FillPivots(pivots); + if (IsValidSize(count)) + { + pivot = pivots[count - 1]; + } + + // + result = pivot.IsValid(); + + // + return result; + } + + /** + * Retrieve Active Peak Pivot ... + * + * @param pivot: XPVPivot instance Reference ... + * + * @return ( bool ) + */ + bool GetActivePeakPivot(XPVPivot &pivot) + { + // + bool result = false; + + // + pivot.Clean(); + + // + pivot = mActivePeakPivot; + + // + result = pivot.IsValid(); + + // + return result; + } + + /** + * Retrieve Active Vale Pivot ... + * + * @param pivot: XPVPivot instance Reference ... + * + * @return ( bool ) + */ + bool GetActiveValePivot(XPVPivot &pivot) + { + // + bool result = false; + + // + pivot.Clean(); + + // + pivot = mActiveValePivot; + + // + result = pivot.IsValid(); + + // + return result; + } + + // + // Virtuals ... + + /** + * Set Default Properties Values ... + */ + virtual void Default() + { + // + ValidPivotRepetition(21); + ConsolidationLoopback(10); + MaxAllowedSavedChanges(50); + } + + // + protected: + // + + /** + * Calculate Requirements ... + * + * @param barIndex: Integer, Bar Index ... + * @param events: ENUM_X_CYCLE_EVENTS member, Array ... + * @param conditions: X121SMCCycleConditions instance ... + */ + void Calculate( + int barIndex, + ENUM_X_CYCLE_EVENTS &events[], + X121SMCCycleConditions &conditions // + ) + { + // + Clean(events); + + // + string symbol = GetSymbol(); + datetime cTime = TimeCurrent(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL changeBar; + int index = + barIndex <= 0 + ? 1 + : barIndex; + bool isInited = GetBar( + changeBar, + index // + ); + if (!isInited) + { + return; + } + + // + // Detect Sar Change ... + bool isSarSwitchedToBullish = conditions.x121Conditions.isSarSwitchedToBullish; + bool isSarSwitchedToBearish = conditions.x121Conditions.isSarSwitchedToBearish; + bool isSarChanged = isSarSwitchedToBullish || + isSarSwitchedToBearish; + + // + if (isSarChanged) + { + // + XValueChange sarChanged; + + // + datetime time = changeBar.time; + double after = conditions.x121Conditions.sarBuffer[1]; + double before = conditions.x121Conditions.sarBuffer[2]; + ENUM_X_DIRECTION dir = + isSarSwitchedToBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Initialize Model ... + isInited = sarChanged.Init( + before, + after, + dir, + time // + ); + if (isInited) + { + // + isInited = AddSarChange(sarChanged); + + // + if (isInited) + { + // + Add( + SAR_CHANGE_DETECTED, + events // + ); + } + } + } + + // + // Detect Peaks Changes ... + + // + bool isNewPeak = conditions.x121Conditions.isNewPeak; + double peak = conditions.x121Conditions.peaksBuffer[1]; + double peakPrev = conditions.x121Conditions.peaksBuffer[2]; + bool isPeakSameAsPrev = peak == peakPrev; + bool isNewPeakOverLast = conditions.x121Conditions.isNewPeakOverLast; + bool isNewPeakUnderLast = conditions.x121Conditions.isNewPeakUnderLast; + + // + if (isNewPeak) + { + // + XValueChange peaksChanged; + + // + datetime time = changeBar.time; + double after = conditions.x121Conditions.peaksBuffer[1]; + double before = conditions.x121Conditions.peaksBuffer[2]; + ENUM_X_DIRECTION dir = + isNewPeakOverLast + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Initialize Model ... + isInited = peaksChanged.Init( + before, + after, + dir, + time // + ); + if (isInited) + { + // + isInited = AddPeaksChange(peaksChanged); + + // + if (isInited) + { + // + Add( + NEW_PEAK_DETECTED, + events // + ); + } + } + } + + // + // Detect Vales Changes ... + + // + bool isNewVale = conditions.x121Conditions.isNewVale; + double vale = conditions.x121Conditions.valesBuffer[1]; + double valePrev = conditions.x121Conditions.valesBuffer[2]; + bool isValeSameAsPrev = vale == valePrev; + bool isNewValeOverLast = conditions.x121Conditions.isNewValeOverLast; + bool isNewValeUnderLast = conditions.x121Conditions.isNewValeUnderLast; + + // + if (isNewVale) + { + // + XValueChange valesChanged; + + // + datetime time = changeBar.time; + double after = conditions.x121Conditions.valesBuffer[1]; + double before = conditions.x121Conditions.valesBuffer[2]; + ENUM_X_DIRECTION dir = + isNewValeUnderLast + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Initialize Model ... + isInited = valesChanged.Init( + before, + after, + dir, + time // + ); + if (isInited) + { + // + isInited = AddValesChange(valesChanged); + + // + if (isInited) + { + // + Add( + NEW_VALE_DETECTED, + events // + ); + } + } + } + + // + // Count Bullish / Bearish Peaks and Vales ... + + // + // Peaks ... + + // + if (isNewPeakOverLast) + { + // + mBullishPeaks++; + mIsLastPeakBullish = true; + } + + // + if (isNewPeakUnderLast) + { + // + mBearishPeaks++; + mIsLastPeakBullish = false; + } + + // + if (isPeakSameAsPrev) + { + // + if (mIsLastPeakBullish) + { + // + mBullishPeaks++; + mBearishPeaks--; + if (mBearishPeaks < 0) + { + mBearishPeaks = 0; + } + } + else + { + // + mBullishPeaks--; + mBearishPeaks++; + if (mBullishPeaks < 0) + { + mBullishPeaks = 0; + } + } + } + + // + // Vales ... + + // + if (isNewValeOverLast) + { + // + mBullishVales++; + mIsLastValeBullish = true; + } + + // + if (isNewValeUnderLast) + { + // + mBearishVales++; + mIsLastValeBullish = false; + } + + // + if (isValeSameAsPrev) + { + // + if (mIsLastValeBullish) + { + // + mBullishVales++; + mBearishVales--; + if (mBearishVales < 0) + { + mBearishVales = 0; + } + } + else + { + // + mBullishVales--; + mBearishVales++; + if (mBullishVales < 0) + { + mBullishVales = 0; + } + } + } + + // + // VWap Direction Change ... + + // + // Ordered Change ... + bool isVWapSwitchedToBullishOrdered = + conditions.x121Conditions.isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered = + conditions.x121Conditions.isVWapSwitchedToBearishOrdered; + bool isVWAPOrderedChanged = isVWapSwitchedToBullishOrdered || + isVWapSwitchedToBearishOrdered; + // + if (isVWAPOrderedChanged) + { + // + XValueChange vwapOrderChanged; + + // + datetime time = changeBar.time; + ENUM_X_DIRECTION dir = + isVWapSwitchedToBullishOrdered + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double after = 0; + double before = 0; + if (isVWapSwitchedToBullishOrdered) + { + // + // After Max ... + after = MathMax( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + after = MathMax( + after, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + + // + // Before Min ... + before = MathMin( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + before = MathMin( + before, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + } + else + { + // + // After Min ... + after = MathMin( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + after = MathMin( + after, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + + // + // Before Max ... + before = MathMax( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + before = MathMax( + before, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + } + + // + // Initialize Model ... + isInited = vwapOrderChanged.Init( + before, + after, + dir, + time // + ); + if (isInited) + { + // + isInited = AddVWapOrderChange(vwapOrderChanged); + + // + if (isInited) + { + // + Add( + VWAP_ORDER_CHANGE_ETECTED, + events // + ); + } + } + } + + // + // States Changed ... + bool isVWapSwitchedToBullishState = + conditions.x121Conditions.isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState = + conditions.x121Conditions.isVWapSwitchedToBearishState; + bool isVWapStatesChanged = isVWapSwitchedToBullishState || + isVWapSwitchedToBearishState; + + // + if (isVWapStatesChanged) + { + // + XValueChange vwapStateChanged; + + // + datetime time = changeBar.time; + ENUM_X_DIRECTION dir = + isVWapSwitchedToBullishState + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double after = 0; + double before = 0; + if (isVWapSwitchedToBullishState) + { + // + // After Max ... + after = MathMax( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + after = MathMax( + after, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + + // + // Before Min ... + before = MathMin( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + before = MathMin( + before, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + } + else + { + // + // After Min ... + after = MathMin( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + after = MathMin( + after, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + + // + // Before Max ... + before = MathMax( + conditions.x121Conditions.vwapFastBuffer[1], + conditions.x121Conditions.vwapMidBuffer[1] // + ); + before = MathMax( + before, + conditions.x121Conditions.vwapSlowBuffer[1] // + ); + } + + // + // Initialize Model ... + isInited = vwapStateChanged.Init( + before, + after, + dir, + time // + ); + if (isInited) + { + // + isInited = AddVWapStateChange(vwapStateChanged); + + // + if (isInited) + { + // + Add( + VWAP_STATE_CHANGE_DETCTED, + events // + ); + } + } + } + + // + // Detect Consolidations ... + + // + int consolidationLoopback = ConsolidationLoopback(); + if (IsValidSize(consolidationLoopback)) + { + // + double upper = 0; + double lower = 0; + bool hasConsolidation = + mBarAnalyser.IsConsolidate( + changeBar, + upper, + lower, + consolidationLoopback // + ); + + // + if (hasConsolidation && + !mActiveConsolidationZone.IsValid()) + { + // + // Initialize Consolidation Zone ... + bool isInited = mActiveConsolidationZone.Init( + changeBar.symbol, + changeBar.period, + upper, + lower, + consolidationLoopback // + ); + } + + // + if (!hasConsolidation && + mActiveConsolidationZone.IsValid()) + { + // + mActiveConsolidationZone.Update(); + bool isBreaked = mActiveConsolidationZone.IsBreaked(); + + // + if (isBreaked) + { + // + // Add Active to List ... + bool isInited = AddConsolidationZone(mActiveConsolidationZone); + if (isInited) + { + // + // Clean Active Zone ... + mActiveConsolidationZone.Clean(); + + // + Add( + CONSOLIDATION_BREAKED_DETECTED, + events // + ); + } + } + } + + // + // Draw ... + // if (mActiveConsolidationZone.IsValid()) + // { + // // + // if (mActiveConsolidationZoneObj != NULL) + // { + // mActiveConsolidationZoneObj.Delete(); + // } + + // // + // bool isCreated = mPOIDetector.mDrawer.CreateConsolidationZone( + // mActiveConsolidationZone, + // mActiveConsolidationZoneObj // + // ); + // } + } + + // + // Check Valid Peaks and Vales ... + if (isNewPeak || isNewVale) + { + // + int count = 0; + double value = 0; + int repetition = 0; + ENUM_TIMEFRAMES period = GetPeriod(); + int periodSeconds = PeriodSeconds(period); + int minRepetition = ValidPivotRepetition(); + ENUM_XPV_PIVOTS type = isNewPeak + ? XPV_PEAK + : XPV_VALE; + + // + XValueChange lastChange; + XValueChange prevChange; + + // + count = CountPeaksChanges(); + if (isNewPeak && count >= 2) + { + // + lastChange = mPeaksChanges[count - 1]; + prevChange = mPeaksChanges[count - 2]; + } + + // + count = CountValesChanges(); + if (isNewVale && count >= 2) + { + // + lastChange = mValesChanges[count - 1]; + prevChange = mValesChanges[count - 2]; + } + + // + if (lastChange.IsValid() && + prevChange.IsValid()) + { + // + value = prevChange.after; + int delayTime = ((int)lastChange.time - (int)prevChange.time); + repetition = delayTime / periodSeconds; + + // + bool isValidPivot = repetition >= minRepetition; + if (isValidPivot) + { + // + XPVPivotPoint pivotPoint; + pivotPoint.type = type; + pivotPoint.value = value; + pivotPoint.time = prevChange.time; + pivotPoint.repetition = repetition; + + // + bool isInited = AddPivotPoint(pivotPoint); + if (isInited) + { + // + Add( + PIVOT_POINT_DETECTED, + events // + ); + } + } + } + } + + // + // Calculate XPVPivot ... + int pvValidation = ValidPivotRepetition(); + if (IsValidSize(pvValidation)) + { + // + // Peak ... + mActivePeakPivot.symbol = symbol; + mActivePeakPivot.period = period; + mActivePeakPivot.type = XPV_PEAK; + + // + if (mActivePeakPivot.upper == 0 && peak > 0) + { + // + mActivePeakPivot.upper = peak; + mActivePeakPivot.lower = vale; + mActivePeakPivot.from = changeBar.time; + + // + Add( + PEAK_PIVOT_STARTED, + events // + ); + } + else if (mActivePeakPivot.upper > 0 && mActivePeakPivot.upper == peak) + { + // + mActivePeakPivot.repetition++; + mActivePeakPivot.to = changeBar.time; + + // + if (mActivePeakPivot.IsValid()) + { + // + FillPivotState(mActivePeakPivot); + ValidatePivotState(mActivePeakPivot, barIndex); + } + } + else if (mActivePeakPivot.upper > 0 && mActivePeakPivot.upper != peak) + { + // + if (mActivePeakPivot.repetition >= pvValidation) + { + // + bool isInited = AddPivot(mActivePeakPivot); + if (isInited) + { + // + Add( + PEAK_PIVOT_ENDED, + events // + ); + + // + mActivePeakPivot.Clean(); + } + } + else + { + // + mActivePeakPivot.upper = peak; + mActivePeakPivot.lower = vale; + mActivePeakPivot.repetition = 0; + mActivePeakPivot.from = changeBar.time; + + // + Add( + PEAK_PIVOT_STARTED, + events // + ); + } + } + + // + // Vale ... + mActiveValePivot.symbol = symbol; + mActiveValePivot.period = period; + mActiveValePivot.type = XPV_VALE; + + // + // Peak ... + if (mActiveValePivot.lower == 0 && vale > 0) + { + // + mActiveValePivot.lower = vale; + mActiveValePivot.upper = peak; + mActiveValePivot.from = changeBar.time; + + // + Add( + VALE_PIVOT_STARTED, + events // + ); + } + else if (mActiveValePivot.lower > 0 && mActiveValePivot.lower == vale) + { + // + mActiveValePivot.repetition++; + mActiveValePivot.to = changeBar.time; + + // + if (mActiveValePivot.IsValid()) + { + // + FillPivotState(mActiveValePivot); + ValidatePivotState(mActiveValePivot, barIndex); + } + } + else if (mActiveValePivot.lower > 0 && mActiveValePivot.lower != vale) + { + // + if (mActiveValePivot.repetition >= pvValidation) + { + // + bool isInited = AddPivot(mActiveValePivot); + if (isInited) + { + // + Add( + VALE_PIVOT_ENDED, + events // + ); + + // + mActiveValePivot.Clean(); + } + } + else + { + // + mActiveValePivot.lower = vale; + mActiveValePivot.upper = peak; + mActiveValePivot.repetition = 0; + mActiveValePivot.from = changeBar.time; + + // + Add( + VALE_PIVOT_STARTED, + events // + ); + } + } + } + } + + /** + * Detect Requirements ... + */ + void Detect(int barIndex) + { + // + if (isDetecting) + { + return; + } + + // + int start = barIndex; + int max = 576; + int validPivotRepetition = ValidPivotRepetition(); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + // Try To Detect Valid Peaks or Vales ... + double peak = 0; + double vale = 0; + int peakRepetition = 0; + int valeRepetition = 0; + + // + int from = start; + int index = from; + int count = start + max; + + // + bool canContinue = true; + + // + // Loop Throug Peaks and Vales ... + while (canContinue) + { + // + datetime toTime = iTime( + symbol, + period, + index // + ); + + // + double iPeak = mX121Helper.GetPeak(index); + double iVale = mX121Helper.GetVale(index); + + // + // Peak ... + if (peak == 0 && iPeak > 0) + { + // + peak = iPeak; + peakRepetition = 0; + } + else if (peak > 0 && iPeak > 0 && peak == iPeak) + { + peakRepetition++; + } + else if (peak > 0 && iPeak > 0 && peak != iPeak) + { + // + if (peakRepetition >= validPivotRepetition) + { + // + datetime fromTime = iTime( + symbol, + period, + index - peakRepetition // + ); + + // + // Create XPVPivotPoint ... + XPVPivotPoint pivotPoint; + pivotPoint.value = iPeak; + pivotPoint.time = toTime; + pivotPoint.type = XPV_PEAK; + pivotPoint.repetition = peakRepetition; + if (pivotPoint.IsValid()) + { + // + AddRef( + pivotPoint, + mPivotPoints // + ); + } + + // + // Create XPVPivot ... + XPVPivot pivot; + pivot.symbol = symbol; + pivot.period = period; + pivot.from = fromTime; + pivot.to = toTime; + pivot.repetition = peakRepetition; + pivot.type = XPV_PEAK; + pivot.upper = peak; + pivot.lower = iVale; + FillPivotState(pivot); + + // + if (pivot.IsValid()) + { + // + AddRef( + pivot, + mPivots // + ); + } + } + + // + peak = iPeak; + peakRepetition = 0; + } + + // + // Vale ... + if (vale == 0 && iVale > 0) + { + // + vale = iVale; + valeRepetition = 0; + } + else if (vale > 0 && iVale > 0 && vale == iVale) + { + valeRepetition++; + } + else if (vale > 0 && iVale > 0 && vale != iVale) + { + // + if (valeRepetition >= validPivotRepetition) + { + // + datetime fromTime = iTime( + symbol, + period, + index - valeRepetition // + ); + + // + // Create XPVPivotPoint ... + XPVPivotPoint pivotPoint; + pivotPoint.value = iVale; + pivotPoint.time = toTime; + pivotPoint.type = XPV_VALE; + pivotPoint.repetition = valeRepetition; + if (pivotPoint.IsValid()) + { + // + AddRef( + pivotPoint, + mPivotPoints // + ); + } + + // + // Create XPVPivot ... + XPVPivot pivot; + pivot.symbol = symbol; + pivot.period = period; + pivot.from = fromTime; + pivot.to = toTime; + pivot.repetition = valeRepetition; + pivot.type = XPV_VALE; + pivot.upper = iPeak; + pivot.lower = vale; + FillPivotState(pivot); + + // + if (pivot.IsValid()) + { + // + AddRef( + pivot, + mPivots // + ); + } + } + + // + vale = iVale; + valeRepetition = 0; + } + + // + index++; + canContinue = index < count; + } + + // + int pivotsCount = ArraySize(mPivots); + if (IsValidSize(mPivots)) + { + ArrayReverse(mPivots); + } + + // + isDetecting = false; + } + + // + private: + // + // Props ... + + // + bool mIsLastPeakBullish; + int mBullishPeaks; // Count Bullish Peaks ... + int mBearishPeaks; // Count Bearish Peaks ... + + // + bool mIsLastValeBullish; + int mBullishVales; // Count Bullish Vales ... + int mBearishVales; // Count Bearish Vales ... + + // + // Change Holders ... + int mMaxAllowedSavedChanges; // Max llowed Changes to Save ... + XValueChange mSarChanges[]; // Holds Parabolic Sar Direction Changes ... + XValueChange mPeaksChanges[]; // Holds Peaks Changes ... + XValueChange mValesChanges[]; // Holds Vales Changes ... + XValueChange mVWapOrderChanges[]; // Holds Vales Changes ... + XValueChange mVWapStateChanges[]; // Holds Vales Changes ... + + // + int mConsolidationLoopback; // Consolidation Loopback Length ... + XConsolidationZone mConsolidationZones[]; // Holds Consolidation Zones ... + XConsolidationZone mActiveConsolidationZone; // Holds Actiove Consolidation Zone ... + // XCConsolidationZoneObject *mActiveConsolidationZoneObj; + + // + int mValidPivotRepetition; // Valid Pivot Point's Repetition ... + XPVPivotPoint mPivotPoints[]; // Holds Pivots ... + + // + bool isDetecting; + XPVPivot mActivePeakPivot; // Active Pivots ... + XPVPivot mActiveValePivot; // Active Pivots ... + XPVPivot mPivots[]; // Holds Active Pivot ... + + // + // Actions ... + + /** + * Release All Resources ... + */ + void DeInit() + { + // + delete mX121Helper; + + // + delete mBarAnalyser; + } + + /** + * Apply Chart Style ... + */ + void ApplyChartStyle() + { + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + + // + ENUM_CHART_MODE mMode = CHART_CANDLES; // chart's mMode + bool mShowBidLine = true; // show bid line + bool mShowAskLine = true; // show ask line + bool mShowGrid = false; // show grids on chart + bool mShowVolumes = false; // show volumes + bool mShowTradeLevels = true; // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true; // chart autoscroll + bool mQuickNavigation = true; // chart quick navigation state + color mForeGroundColor = clrWhite; // chart's foreground color + color mBackGroundColor = clrBlack; // chart's background color + color mUpColor = clrGreen; // Up Color + color mDownColor = clrRed; // Down Color + color mBullishColor = clrGreen; // Bullish color + color mBearishColor = clrRed; // Bearish color + color mGridColor = clrGray; // grid color + color mBidLineColor = clrGray; // bid line color + color mAskLineColor = clrRed; // ask line color + color mLineColor = clrLime; // line mMode and doji candlestick color + color mStopColor = clrGold; // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen; // volumes color + + // + ChartSetInteger(chartId, CHART_MODE, mMode); + ChartSetInteger(chartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(chartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(chartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(chartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(chartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(chartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(chartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(chartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(chartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(chartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(chartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(chartId, CHART_COLOR_VOLUME, mVolumesColor); + } + + /** + * Fill Pivot Tick Zone ... + * + * @param pivot: XPVPivot instance Reference ... + */ + void CalculatePivotTickZone( + XPVPivot &pivot // + ) + { + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + bool isInited = false; + + // + datetime from = pivot.from; + XOHCL iFromBar; + int iFromBarIndex = iBarShift( + symbol, + period, + from // + ); + isInited = iFromBar.Init( + symbol, + period, + iFromBarIndex // + ); + if (!isInited) + { + return; + } + + // + datetime to = pivot.to; + XOHCL iToBar; + int iToBarIndex = iBarShift( + symbol, + period, + to // + ); + isInited = iToBar.Init( + symbol, + period, + iToBarIndex // + ); + if (!isInited) + { + return; + } + + // + if (iFromBarIndex <= iToBarIndex) + { + return; + } + + // + XCTicksZone *iZone; + iZone = new XCTicksZone(); + + // + int ticksLevels = mPOIDetector.TicksRangeZoneLevel(); + int ticksRange = mPOIDetector.TicksRangeZoneRange(); + isInited = ticksLevels > 0 && + ticksRange > 0; + if (!isInited) + { + return; + } + + // + isInited = iZone.Init( + iFromBar, + iToBar // + ); + if (!isInited) + { + return; + } + + // + pivot.state.ticksZone = iZone; + } + + // + // Change Values Actions ... + + /** + * Add Specified Parabolic Sar Changed Item ... + * + * @param value: XValueChange instance Reference ... + * + * @return ( bool ) + */ + bool AddSarChange(XValueChange &value) + { + // + bool result = false; + + // + result = value.IsValid(); + if (!result) + { + return result; + } + + // + int beforeCount = CountSarChanges(); + + // + AddIfNotExists( + value, + mSarChanges // + ); + + // + int afterCount = CountSarChanges(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mSarChanges, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified Peaks Changed Item ... + * + * @param value: XValueChange instance Reference ... + * + * @return ( bool ) + */ + bool AddPeaksChange(XValueChange &value) + { + // + bool result = false; + + // + result = value.IsValid(); + if (!result) + { + return result; + } + + // + int beforeCount = CountSarChanges(); + + // + AddIfNotExists( + value, + mPeaksChanges // + ); + + // + int afterCount = CountSarChanges(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mPeaksChanges, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified Vales Changed Item ... + * + * @param value: XValueChange instance Reference ... + * + * @return ( bool ) + */ + bool AddValesChange(XValueChange &value) + { + // + bool result = false; + + // + result = value.IsValid(); + if (!result) + { + return result; + } + + // + int beforeCount = CountSarChanges(); + + // + AddIfNotExists( + value, + mValesChanges // + ); + + // + int afterCount = CountSarChanges(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mValesChanges, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified VWap Order Changed Item ... + * + * @param value: XValueChange instance Reference ... + * + * @return ( bool ) + */ + bool AddVWapOrderChange(XValueChange &value) + { + // + bool result = false; + + // + result = value.IsValid(); + if (!result) + { + return result; + } + + // + int beforeCount = CountSarChanges(); + + // + AddIfNotExists( + value, + mVWapOrderChanges // + ); + + // + int afterCount = CountSarChanges(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mVWapOrderChanges, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified VWap State Changed Item ... + * + * @param value: XValueChange instance Reference ... + * + * @return ( bool ) + */ + bool AddVWapStateChange(XValueChange &value) + { + // + bool result = false; + + // + result = value.IsValid(); + if (!result) + { + return result; + } + + // + int beforeCount = CountSarChanges(); + + // + AddIfNotExists( + value, + mVWapStateChanges // + ); + + // + int afterCount = CountSarChanges(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mVWapStateChanges, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified Consolidation Zone to List ... + * + * @param zone: XConsolidationZone instance Reference ... + * + * @return ( bool ) + */ + bool AddConsolidationZone(XConsolidationZone &zone) + { + // + bool result = false; + + // + result = zone.IsValid(); + + // + int beforeCount = CountConsolidationZones(); + + // + AddRef( + zone, + mConsolidationZones // + ); + + // + int afterCount = CountConsolidationZones(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mConsolidationZones, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified Pivot Point to List ... + * + * @param pivotPoint: XPVPivotPoint instance Reference ... + * + * @return ( bool ) + */ + bool AddPivotPoint(XPVPivotPoint &pivotPoint) + { + // + bool result = false; + + // + if (!pivotPoint.IsValid()) + { + return result; + } + + // + int beforeCount = CountPivotPoints(); + + // + AddRef( + pivotPoint, + mPivotPoints // + ); + + // + int afterCount = CountPivotPoints(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mPivotPoints, + maxAllowed // + ); + } + + // + return result; + } + + /** + * Add Specified Pivot to List ... + * + * @param pivot: XPVPivot instance Reference ... + * + * @return ( bool ) + */ + bool AddPivot(XPVPivot &pivot) + { + // + bool result = false; + + // + if (!pivot.IsValid()) + { + return result; + } + + // + int beforeCount = CountPivots(); + + // + AddRef( + pivot, + mPivots // + ); + + // + int afterCount = CountPivots(); + + // + result = afterCount == beforeCount + 1; + if (result) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSavedChanges(); + CleanupArray( + mPivots, + maxAllowed // + ); + } + + // + return result; + } + + // +}; diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.twpv.conditions2.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.twpv.conditions2.mq5 new file mode 100644 index 0000000..ff6c2b3 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.twpv.conditions2.mq5 @@ -0,0 +1,137 @@ + + // + // OPEN ... + double triggerDonOpenUpper = triggerConditions.x121Conditions.donOpenUpperBuffer[1]; + double triggerDonOpenLower = triggerConditions.x121Conditions.donOpenLowerBuffer[1]; + double triggerDonOpenUpperPrev = triggerConditions.x121Conditions.donOpenUpperBuffer[2]; + double triggerDonOpenLowerPrev = triggerConditions.x121Conditions.donOpenLowerBuffer[2]; + + // + // HIGH ... + double triggerDonHighUpper = triggerConditions.x121Conditions.donHighUpperBuffer[1]; + double triggerDonHighLower = triggerConditions.x121Conditions.donHighLowerBuffer[1]; + double triggerDonHighUpperPrev = triggerConditions.x121Conditions.donHighUpperBuffer[2]; + double triggerDonHighLowerPrev = triggerConditions.x121Conditions.donHighLowerBuffer[2]; + + // + // CLOSE ... + double triggerDonCloseUpper = triggerConditions.x121Conditions.donCloseUpperBuffer[1]; + double triggerDonCloseLower = triggerConditions.x121Conditions.donCloseLowerBuffer[1]; + double triggerDonCloseUpperPrev = triggerConditions.x121Conditions.donCloseUpperBuffer[2]; + double triggerDonCloseLowerPrev = triggerConditions.x121Conditions.donCloseLowerBuffer[2]; + + // + // LOW ... + double triggerDonLowUpper = triggerConditions.x121Conditions.donLowUpperBuffer[1]; + double triggerDonLowLower = triggerConditions.x121Conditions.donLowLowerBuffer[1]; + double triggerDonLowUpperPrev = triggerConditions.x121Conditions.donLowUpperBuffer[2]; + double triggerDonLowLowerPrev = triggerConditions.x121Conditions.donLowLowerBuffer[2]; + + // + // Calculate PBar Rejected Don Upper and Lower ... + + // + bool isPBarRejectDonLowUpper = pBar.high > triggerDonLowUpperPrev; + bool isPBarRejectDonOpenUpper = pBar.high > triggerDonOpenUpperPrev; + bool isPBarRejectDonCloseUpper = pBar.high > triggerDonCloseUpperPrev; + bool isPBarRejectedDonUpper = isPBarRejectDonLowUpper || + isPBarRejectDonOpenUpper || + isPBarRejectDonCloseUpper; + + // + bool isPBarRejectDonHighLower = pBar.low < triggerDonHighLowerPrev; + bool isPBarRejectDonOpenLower = pBar.low < triggerDonOpenLowerPrev; + bool isPBarRejectDonCloseLower = pBar.low < triggerDonCloseLowerPrev; + bool isPBarRejectedDonLower = isPBarRejectDonHighLower || + isPBarRejectDonOpenLower || + isPBarRejectDonCloseLower; + + // + // Calculate PBar Breaked Don Upper and Lower ... + + // + bool isPBarBreakdDonLowUpper = pBar.GetUp() > triggerDonLowUpperPrev && + pBar.GetDown() < triggerDonLowUpperPrev; + bool isPBarBreakdDonOpenUpper = pBar.GetUp() > triggerDonOpenUpperPrev && + pBar.GetDown() < triggerDonOpenUpperPrev; + bool isPBarBreakdDonCloseUpper = pBar.GetUp() > triggerDonCloseUpperPrev && + pBar.GetDown() < triggerDonCloseUpperPrev; + bool isPBarBreakedDonUpper = isPBarBreakdDonLowUpper || + isPBarBreakdDonOpenUpper || + isPBarBreakdDonCloseUpper; + + // + bool isPBarBreakdDonHighLower = pBar.GetUp() > triggerDonHighLowerPrev && + pBar.GetDown() < triggerDonHighLowerPrev; + bool isPBarBreakdDonOpenLower = pBar.GetUp() > triggerDonOpenLowerPrev && + pBar.GetDown() < triggerDonOpenLowerPrev; + bool isPBarBreakdDonCloseLower = pBar.GetUp() > triggerDonCloseLowerPrev && + pBar.GetDown() < triggerDonCloseLowerPrev; + bool isPBarBreakedDonLower = isPBarBreakdDonHighLower || + isPBarBreakdDonOpenLower || + isPBarBreakdDonCloseLower; + + // + bool isRejectTriggerDonUpper = + // + // PBar ... + isPBarBearishRejected && + isPBarRejectedDonUpper && + // + // CBar ... + isCBarBearishMomentumBar && + cBar.close < triggerDonLowUpper && + // + triggerPeak == triggerDonHighUpper + // + ; + + // + bool isRejectTriggerDonLower = + // + // PBar ... + isPBarBullishRejected && + isPBarRejectedDonLower && + // + // CBar ... + isCBarBullishMomentumBar && + cBar.close > triggerDonHighLower && + // + triggerVale == triggerDonLowLower + // + ; + + // + if (isRejectTriggerDonUpper || + isRejectTriggerDonLower) + { + Print("Don Rejected ..."); + } + + // + bool isBreakedDonUpper = + // + false + // + ; + + // + bool isBreakedDonLower = + // + false + // + ; + + // + bool isEngulfedDonUpper = + // + false + // + ; + + // + bool isEngulfedDonLower = + // + false + // + ; diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib copy.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib copy.mq5 new file mode 100644 index 0000000..64d1fc7 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib copy.mq5 @@ -0,0 +1,1983 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: X +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + double higherPeak; + datetime higherPeakTime; + + // + double lowerVale; + datetime lowerValeTime; + + // + XPVPivot pivotZone; + + // + // Constructor ... + X121SMCStrategyXSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + pivotZone.Clean(); + + // + higherPeak = 0; + higherPeakTime = NULL; + + // + lowerVale = 0; + lowerValeTime = NULL; + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXSignalConditions mXConditions; +X121SMCStrategyXSignalConditions mXConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + // zBar.Init( + // symbol, + // period, + // zIndex // + // ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + // cBar.Init( + // symbol, + // period, + // cIndex // + // ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + // pBar.Init( + // symbol, + // period, + // pIndex // + // ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // PinBar ... + ENUM_X_DIRECTION cBarPinDir; + bool isCBarPin = decisionCycleHelper + .mBarAnalyser + .IsPinBar( + cBar, + cBarPinDir, + 1 // + ); + bool isCBarBullishPin = + isCBarPin && + IsBullish(cBarPinDir); + bool isCBarBearishPin = + isCBarPin && + IsBearish(cBarPinDir); + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // Pull Back ... + ENUM_X_DIRECTION cBarPullbackDir; + bool isCBarPullbacked = + decisionCycleHelper + .mBarAnalyser + .HasPullBack( + cBarPullbackDir, + cBar // + ); + bool isCBarBullishPullbacked = + isCBarPullbacked && + IsBullish(cBarPullbackDir); + bool isCBarBearishPullbacked = + isCBarPullbacked && + IsBearish(cBarPullbackDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bars Pattern and Power and Pressures ... + + // + bool hasCBarBullishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBullishPattern( + cBar, + 2 // + ); + + // + bool hasCBarBearishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBearishPattern( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPower = + decisionCycleHelper + .mBarAnalyser + .HasBullishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPower = + decisionCycleHelper + .mBarAnalyser + .HasBearishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBullishPressure( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBearishPressure( + cBar, + 2 // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + ( + // + hasCBarBullishPattern && + isCBarHasBullishPower && + isCBarHasBullishPressure + // + ) + // + || + // + ( + // + isCBarBullishPin || + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ) + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + ( + // + hasCBarBearishPattern && + isCBarHasBearishPower && + isCBarHasBearishPressure + // + ) + // + || + // + ( + // + isCBarBearishPin || + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ) + // + ; + + // + // Set Higher Peak and Lowe Vale ... + + // + XOHCL higherPeakBar; + bool hasHigherPeak = + conditions.higherPeak > 0 && + IsValid(conditions.higherPeakTime); + bool isHigherPeakBreaked = false; + bool isHigherPeakRejected = false; + + // + if (!hasHigherPeak) + { + // + int higherPeakIDX = -1; + double higherPeak = + decisionCycleHelper + .mX121Helper + .xpvHelper + .GetHigherPeak( + higherPeakIDX, + decisionXConditions.peaksBuffer[1], + cIndex // + ); + + // + if (higherPeak > 0 && + IsValidIndex(higherPeakIDX)) + { + // + bool hasHigherPeak = higherPeakBar.Init( + symbol, + period, + higherPeakIDX // + ); + + // + if (hasHigherPeak) + { + // + conditions.higherPeakTime = cTime; + conditions.higherPeak = higherPeak; + } + } + } + + // + if (hasHigherPeak) + { + // + isHigherPeakBreaked = IsBarBreak( + conditions.higherPeak, + X_DIRECTION_BULLISH, + cBar // + ); + + // + isHigherPeakRejected = IsBarReject( + conditions.higherPeak, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + XOHCL lowerValeBar; + bool hasLowerVale = + conditions.lowerVale > 0 && + IsValid(conditions.lowerValeTime); + bool isLowerValeBreaked = false; + bool isLowerValeRejected = false; + + // + if (!hasLowerVale) + { + // + int lowerValeIDX = -1; + double lowerVale = + decisionCycleHelper + .mX121Helper + .xpvHelper + .GetLowerVale( + lowerValeIDX, + decisionXConditions.valesBuffer[1], + cIndex // + ); + + // + if (lowerVale > 0 && + IsValidIndex(lowerValeIDX)) + { + // + hasLowerVale = lowerValeBar.Init( + symbol, + period, + lowerValeIDX // + ); + + // + if (hasLowerVale) + { + // + conditions.lowerVale = lowerVale; + conditions.lowerValeTime = cTime; + } + } + } + + // + if (hasLowerVale) + { + // + isLowerValeBreaked = IsBarBreak( + conditions.lowerVale, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isLowerValeRejected = IsBarReject( + conditions.lowerVale, + X_DIRECTION_BULLISH, + cBar // + ); + } + + // + double pivotMid = 0; + bool isPivotToUpRejected = false; + bool isPivotToDownRejected = false; + bool isPivotToUpBreaked = false; + bool isPivotToDownBreaked = false; + bool hasPivot = conditions.pivotZone.IsValid(); + + // + if (!hasPivot) + { + // + bool isSamePeaks = decisionXConditions.peaksBuffer[1] == + decisionXConditions.peaksBuffer[2] && + decisionXConditions.peaksBuffer[2] == + decisionXConditions.peaksBuffer[3]; + bool isSameCyclePeaks = decisionXConditions.peaksBuffer[1] == + analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == + verificationXConditions.peaksBuffer[1]; + bool hasPeakPivot = + // isSamePeaks && + hasHigherPeak && + isSameCyclePeaks && + (isHigherPeakBreaked || + isHigherPeakRejected); + + // + bool isSameVales = decisionXConditions.valesBuffer[1] == + decisionXConditions.valesBuffer[2] && + decisionXConditions.valesBuffer[2] == + decisionXConditions.valesBuffer[3]; + bool isSameCycleVales = decisionXConditions.valesBuffer[1] == + analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == + verificationXConditions.valesBuffer[1]; + bool hasValePivot = + // isSameVales && + hasLowerVale && + isSameCycleVales && + (isLowerValeBreaked || + isLowerValeRejected); + + // + bool hasPivot = hasPeakPivot || + hasValePivot; + if (hasPivot) + { + // + XPVPivot pivot; + + // + pivot.symbol = symbol; + pivot.period = period; + + // + pivot.upper = decisionXConditions.peaksBuffer[1]; + pivot.lower = decisionXConditions.valesBuffer[1]; + + // + pivot.to = cTime; + pivot.from = cTime; + pivot.repetition = 3; + + // + pivot.type = + hasPeakPivot + ? XPV_PEAK + : XPV_VALE; + + // + hasPivot = pivot.IsValid(); + if (hasPivot) + { + conditions.pivotZone = pivot; + } + } + } + + // + if (hasPivot) + { + // + pivotMid = conditions + .pivotZone + .CalculateMid(); + + // + isPivotToUpRejected = IsBarReject( + pivotMid, + X_DIRECTION_BULLISH, + cBar // + ); + + // + isPivotToDownRejected = IsBarReject( + pivotMid, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isPivotToUpBreaked = IsBarBreak( + pivotMid, + X_DIRECTION_BULLISH, + cBar // + ); + + // + isPivotToDownBreaked = IsBarBreak( + pivotMid, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + // Sar Conditions ... + + // + bool isSarBullishFormed = + ( + // + ( + // + decisionXConditions.isBreakedUpPrevSar && + (decisionXConditions.isSarBullish || + decisionXConditions.isSarSwitchedToBullish) + // + ) + // + ); + + // + bool isSarBearishFormed = + ( + // + ( + // + decisionXConditions.isBreakedDownPrevSar && + (decisionXConditions.isSarBearish || + decisionXConditions.isSarSwitchedToBearish) + // + ) + // + ); + + // + // + // + + // + // Summarize Conditions ... + + // + bool isCondition1Bullish = + // + hasPivot && + // + isCBarBullishFormed && + (isPivotToUpRejected || + isPivotToUpBreaked) && + conditions.pivotZone.IsPeak() && + // + // SAR ... + isSarBullishFormed && + // // + // // STR ... + // !(decisionXConditions.isStrBearish) && + // // + // // VWAP ... + // !(decisionXConditions.isVWapBearishState || + // decisionXConditions.isVWapBearishOrdered) && + // + true + // + ; + + // + bool isCondition1Bearish = + // + hasPivot && + // + isCBarBearishFormed && + (isPivotToDownRejected || + isPivotToDownBreaked) && + conditions.pivotZone.IsVale() && + // + // SAR ... + isSarBearishFormed && + // // + // // STR ... + // !(decisionXConditions.isStrBullish) && + // // + // // VWAP ... + // !(decisionXConditions.isVWapBullishState || + // decisionXConditions.isVWapBullishOrdered) && + // + true + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = pivotMid; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCondition1Bullish + ? conditions.pivotZone.upper + : conditions.pivotZone.lower; + + // + } + + // + // + // + + // + isBullish = + // + // false + isCondition1Bullish + // + ; + + // + isBearish = + // + // false + isCondition1Bearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXSiganlTrigger( + // + X121SMCStrategyXSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // SAR ... + double sar = decisionXConditions.sarBuffer[1]; + + // + // STR ... + double str = decisionXConditions.strBuffer[1]; + + // + // CHE ... + double le1 = decisionXConditions.le1Buffer[1]; + double le2 = decisionXConditions.le2Buffer[1]; + double se1 = decisionXConditions.se1Buffer[1]; + double se2 = decisionXConditions.se2Buffer[1]; + + // + // ATR ... + double atrUpper = decisionXConditions.atrUpperBuffer[1]; + double atrLower = decisionXConditions.atrLowerBuffer[1]; + + // + // PV ... + double peak = decisionXConditions.peaksBuffer[1]; + double vale = decisionXConditions.valesBuffer[1]; + + // + int higherPeakIDX = -1; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper.GetHigherPeak( + higherPeakIDX, + peak // + ); + + // + int lowerValeIDX = -1; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper.GetLowerVale( + lowerValeIDX, + vale // + ); + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = + isBullish + ? ask > point && bid > point + : ask < point && bid < point; + // bool isPointBreaked = IsBarBreak( + // point, + // setupDir, + // cBar // + // ); + + // + // Summary ... + + // + isBullish = + // + isBullish && + // isPointBreaked && + // isSlopesBullish && + cBar.IsBullish() + // + ; + + // + isBearish = + // + isBearish && + // isPointBreaked && + // isSlopesBearish && + cBar.IsBearish() + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + decisionState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + + // + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + } + target = 0; + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double momentumBarPointsDif = 30 * points; + + // + // Bullish Momentum Bar Selection ... + XOHCL bullishMomentumBar; + int bullishMomentumBarsCount = decisionState.CountBullishMomentumBars(); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.low) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bullishMomentumBar.IsValid() || + (bullishMomentumBar.IsValid() && + bullishMomentumBar.low < entry && + bullishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bullishMomentumBar = iBar; + } + } + } + + // + // Bearish Momentum Bar Selection ... + XOHCL bearishMomentumBar; + int bearishMomentumBarsCount = decisionState.CountBearishMomentumBars(); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.high) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bearishMomentumBar.IsValid() || + (bearishMomentumBar.IsValid() && + bearishMomentumBar.high > entry && + bearishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bearishMomentumBar = iBar; + } + } + } + + // + double sls[]; + Add( + sar, + sls // + ); + Add( + str, + sls // + ); + + // + if (isBullish) + { + // + Add( + atrLower, + sls // + ); + + // // + // Add( + // vale, + // sls // + // ); + + // + if (bullishMomentumBar.IsValid()) + { + // + Add( + bullishMomentumBar.low, + sls // + ); + } + + // // + // if (IsValidIndex(lowerValeIDX)) + // { + // // + // Add( + // lowerVale, + // sls // + // ); + // } + + // + if (le1 != EMPTY_VALUE) + { + // + Add( + le1, + sls // + ); + } + + // + if (le2 != EMPTY_VALUE) + { + // + Add( + le2, + sls // + ); + } + } + else + { + // + Add( + atrUpper, + sls // + ); + + // // + // Add( + // peak, + // sls // + // ); + + // + if (bearishMomentumBar.IsValid()) + { + // + Add( + bearishMomentumBar.high, + sls // + ); + } + + // + // if (IsValidIndex(higherPeakIDX)) + // { + // // + // Add( + // higherPeak, + // sls // + // ); + // } + + // + if (se1 != EMPTY_VALUE) + { + // + Add( + se1, + sls // + ); + } + + // + if (se2 != EMPTY_VALUE) + { + // + Add( + se2, + sls // + ); + } + } + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + iAtr *= 2.5; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double riskInPoints = risk / points; + if (riskInPoints >= 150) + { + // + target = + isBullish + ? entry + (points * 200) + : entry - (points * 200); + + // + target = 0; + } + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_X); + + // + // result = DetectX121SMCGuards( + // provider, + // guards, + // positions, + // triggerCycleHelper, + // decisionCycleHelper, + // analyseCycleHelper, + // verificationCycleHelper, + // consolidationCycleHelper, + // visionCycleHelper // + // ); + + // + return result; +} + +// +int AddX121SMCXConditionsIfNotExists( + X121SMCStrategyXSignalConditions &item, + X121SMCStrategyXSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXConditions( + X121SMCStrategyXSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib.mq5 new file mode 100644 index 0000000..0e58dc6 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.x.signal.lib.mq5 @@ -0,0 +1,1943 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: X +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + double higherPeak; + datetime higherPeakTime; + + // + double lowerVale; + datetime lowerValeTime; + + // + XPVPivot pivotZone; + + // + // Constructor ... + X121SMCStrategyXSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + pivotZone.Clean(); + + // + higherPeak = 0; + higherPeakTime = NULL; + + // + lowerVale = 0; + lowerValeTime = NULL; + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXSignalConditions mXConditions; +X121SMCStrategyXSignalConditions mXConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + // zBar.Init( + // symbol, + // period, + // zIndex // + // ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + // cBar.Init( + // symbol, + // period, + // cIndex // + // ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + // pBar.Init( + // symbol, + // period, + // pIndex // + // ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + bool hasConsolidationBullishTrend = consolidationXConditions.isTrendBullish; + bool hasConsolidationBearishTrend = consolidationXConditions.isTrendBearish; + + // + // Verification ... + bool hasVerificationBullishTrend = verificationXConditions.isTrendBullish; + bool hasVerificationBearishTrend = verificationXConditions.isTrendBearish; + + // + // Analyse ... + bool hasAnalyseBullishTrend = analyseXConditions.isTrendBullish; + bool hasAnalyseBearishTrend = analyseXConditions.isTrendBearish; + + // + // Decision ... + bool hasDecisionBullishTrend = decisionXConditions.isTrendBullish; + bool hasDecisionBearishTrend = decisionXConditions.isTrendBearish; + + // + // Detect Bar State ... + + // + // PinBar ... + ENUM_X_DIRECTION cBarPinDir; + bool isCBarPin = decisionCycleHelper + .mBarAnalyser + .IsPinBar( + cBar, + cBarPinDir, + 1 // + ); + bool isCBarBullishPin = + isCBarPin && + IsBullish(cBarPinDir); + bool isCBarBearishPin = + isCBarPin && + IsBearish(cBarPinDir); + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // Pull Back ... + ENUM_X_DIRECTION cBarPullbackDir; + bool isCBarPullbacked = + decisionCycleHelper + .mBarAnalyser + .HasPullBack( + cBarPullbackDir, + cBar // + ); + bool isCBarBullishPullbacked = + isCBarPullbacked && + IsBullish(cBarPullbackDir); + bool isCBarBearishPullbacked = + isCBarPullbacked && + IsBearish(cBarPullbackDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bars Pattern and Power and Pressures ... + + // + bool hasCBarBullishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBullishPattern( + cBar, + 2 // + ); + + // + bool hasCBarBearishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBearishPattern( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPower = + decisionCycleHelper + .mBarAnalyser + .HasBullishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPower = + decisionCycleHelper + .mBarAnalyser + .HasBearishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBullishPressure( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBearishPressure( + cBar, + 2 // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + ( + // + hasCBarBullishPattern && + isCBarHasBullishPower && + isCBarHasBullishPressure + // + ) + // + || + // + ( + // + isCBarBullishPin || + // isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ) + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + ( + // + hasCBarBearishPattern && + isCBarHasBearishPower && + isCBarHasBearishPressure + // + ) + // + || + // + ( + // + isCBarBearishPin || + // isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ) + // + ; + + // + // Set Higher Peak and Lowe Vale ... + + // + XOHCL higherPeakBar; + bool hasHigherPeak = + conditions.higherPeak > 0 && + IsValid(conditions.higherPeakTime); + bool isHigherPeakBreaked = false; + bool isHigherPeakRejected = false; + + // + if (!hasHigherPeak) + { + // + int higherPeakIDX = -1; + double higherPeak = + decisionCycleHelper + .mX121Helper + .xpvHelper + .GetHigherPeak( + higherPeakIDX, + decisionXConditions.peaksBuffer[1], + cIndex // + ); + + // + if (higherPeak > 0 && + IsValidIndex(higherPeakIDX)) + { + // + bool hasHigherPeak = higherPeakBar.Init( + symbol, + period, + higherPeakIDX // + ); + + // + if (hasHigherPeak) + { + // + conditions.higherPeakTime = cTime; + conditions.higherPeak = higherPeak; + } + } + } + + // + if (hasHigherPeak) + { + // + isHigherPeakBreaked = IsBarBreak( + conditions.higherPeak, + X_DIRECTION_BULLISH, + cBar // + ); + + // + isHigherPeakRejected = IsBarReject( + conditions.higherPeak, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + XOHCL lowerValeBar; + bool hasLowerVale = + conditions.lowerVale > 0 && + IsValid(conditions.lowerValeTime); + bool isLowerValeBreaked = false; + bool isLowerValeRejected = false; + + // + if (!hasLowerVale) + { + // + int lowerValeIDX = -1; + double lowerVale = + decisionCycleHelper + .mX121Helper + .xpvHelper + .GetLowerVale( + lowerValeIDX, + decisionXConditions.valesBuffer[1], + cIndex // + ); + + // + if (lowerVale > 0 && + IsValidIndex(lowerValeIDX)) + { + // + hasLowerVale = lowerValeBar.Init( + symbol, + period, + lowerValeIDX // + ); + + // + if (hasLowerVale) + { + // + conditions.lowerVale = lowerVale; + conditions.lowerValeTime = cTime; + } + } + } + + // + if (hasLowerVale) + { + // + isLowerValeBreaked = IsBarBreak( + conditions.lowerVale, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isLowerValeRejected = IsBarReject( + conditions.lowerVale, + X_DIRECTION_BULLISH, + cBar // + ); + } + + // + double pivotMid = 0; + bool isPivotToUpRejected = false; + bool isPivotToDownRejected = false; + bool isPivotToUpBreaked = false; + bool isPivotToDownBreaked = false; + bool hasPivot = conditions.pivotZone.IsValid(); + + // + if (!hasPivot) + { + // + bool isSamePeaks = decisionXConditions.peaksBuffer[1] == + decisionXConditions.peaksBuffer[2] && + decisionXConditions.peaksBuffer[2] == + decisionXConditions.peaksBuffer[3]; + bool isSameCyclePeaks = decisionXConditions.peaksBuffer[1] == + analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == + verificationXConditions.peaksBuffer[1]; + bool hasPeakPivot = + // isSamePeaks && + hasHigherPeak && + isSameCyclePeaks && + (isHigherPeakBreaked || + isHigherPeakRejected); + + // + bool isSameVales = decisionXConditions.valesBuffer[1] == + decisionXConditions.valesBuffer[2] && + decisionXConditions.valesBuffer[2] == + decisionXConditions.valesBuffer[3]; + bool isSameCycleVales = decisionXConditions.valesBuffer[1] == + analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == + verificationXConditions.valesBuffer[1]; + bool hasValePivot = + // isSameVales && + hasLowerVale && + isSameCycleVales && + (isLowerValeBreaked || + isLowerValeRejected); + + // + bool hasPivot = hasPeakPivot || + hasValePivot; + if (hasPivot) + { + // + XPVPivot pivot; + + // + pivot.symbol = symbol; + pivot.period = period; + + // + pivot.upper = decisionXConditions.peaksBuffer[1]; + pivot.lower = decisionXConditions.valesBuffer[1]; + + // + pivot.to = cTime; + pivot.from = cTime; + pivot.repetition = 3; + + // + pivot.type = + hasPeakPivot + ? XPV_PEAK + : XPV_VALE; + + // + hasPivot = pivot.IsValid(); + if (hasPivot) + { + conditions.pivotZone = pivot; + } + } + } + + // + if (hasPivot) + { + // + pivotMid = conditions + .pivotZone + .CalculateMid(); + + // + isPivotToUpRejected = IsBarReject( + pivotMid, + X_DIRECTION_BULLISH, + cBar // + ); + + // + isPivotToDownRejected = IsBarReject( + pivotMid, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isPivotToUpBreaked = IsBarBreak( + pivotMid, + X_DIRECTION_BULLISH, + cBar // + ); + + // + isPivotToDownBreaked = IsBarBreak( + pivotMid, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + // Sar Conditions ... + + // + bool isSarBullishFormed = + ( + // + ( + // + decisionXConditions.isBreakedUpPrevSar && + (decisionXConditions.isSarBullish || + decisionXConditions.isSarSwitchedToBullish) + // + ) + // + ); + + // + bool isSarBearishFormed = + ( + // + ( + // + decisionXConditions.isBreakedDownPrevSar && + (decisionXConditions.isSarBearish || + decisionXConditions.isSarSwitchedToBearish) + // + ) + // + ); + + // + // + // + + // + // Summarize Conditions ... + + // + bool isCondition1Bullish = + // + hasPivot && + // + isCBarBullishFormed && + (isPivotToUpRejected || + isPivotToUpBreaked) && + conditions.pivotZone.IsPeak() && + // + // SAR ... + isSarBullishFormed && + // // + // // STR ... + // !(decisionXConditions.isStrBearish) && + // // + // // VWAP ... + // !(decisionXConditions.isVWapBearishState || + // decisionXConditions.isVWapBearishOrdered) && + // + true + // + ; + + // + bool isCondition1Bearish = + // + hasPivot && + // + isCBarBearishFormed && + (isPivotToDownRejected || + isPivotToDownBreaked) && + conditions.pivotZone.IsVale() && + // + // SAR ... + isSarBearishFormed && + // // + // // STR ... + // !(decisionXConditions.isStrBullish) && + // // + // // VWAP ... + // !(decisionXConditions.isVWapBullishState || + // decisionXConditions.isVWapBullishOrdered) && + // + true + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = pivotMid; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCondition1Bullish + ? conditions.pivotZone.upper + : conditions.pivotZone.lower; + + // + } + + // + // + // + + // + isBullish = + // + // false + isCondition1Bullish + // + ; + + // + isBearish = + // + // false + isCondition1Bearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXSiganlTrigger( + // + X121SMCStrategyXSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // SAR ... + double sar = decisionXConditions.sarBuffer[1]; + + // + // STR ... + double str = decisionXConditions.strBuffer[1]; + + // + // CHE ... + double le1 = decisionXConditions.le1Buffer[1]; + double le2 = decisionXConditions.le2Buffer[1]; + double se1 = decisionXConditions.se1Buffer[1]; + double se2 = decisionXConditions.se2Buffer[1]; + + // + // ATR ... + double atrUpper = decisionXConditions.atrUpperBuffer[1]; + double atrLower = decisionXConditions.atrLowerBuffer[1]; + + // + // PV ... + double peak = decisionXConditions.peaksBuffer[1]; + double vale = decisionXConditions.valesBuffer[1]; + + // + int higherPeakIDX = -1; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper.GetHigherPeak( + higherPeakIDX, + peak // + ); + + // + int lowerValeIDX = -1; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper.GetLowerVale( + lowerValeIDX, + vale // + ); + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = + isBullish + ? ask > point && bid > point + : ask < point && bid < point; + // bool isPointBreaked = IsBarBreak( + // point, + // setupDir, + // cBar // + // ); + + // + // Summary ... + + // + isBullish = + // + isBullish && + // isPointBreaked && + // isSlopesBullish && + cBar.IsBullish() + // + ; + + // + isBearish = + // + isBearish && + // isPointBreaked && + // isSlopesBearish && + cBar.IsBearish() + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + decisionState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + + // + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + } + target = 0; + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double momentumBarPointsDif = 30 * points; + + // + // Bullish Momentum Bar Selection ... + XOHCL bullishMomentumBar; + int bullishMomentumBarsCount = decisionState.CountBullishMomentumBars(); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.low) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bullishMomentumBar.IsValid() || + (bullishMomentumBar.IsValid() && + bullishMomentumBar.low < entry && + bullishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bullishMomentumBar = iBar; + } + } + } + + // + // Bearish Momentum Bar Selection ... + XOHCL bearishMomentumBar; + int bearishMomentumBarsCount = decisionState.CountBearishMomentumBars(); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.high) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bearishMomentumBar.IsValid() || + (bearishMomentumBar.IsValid() && + bearishMomentumBar.high > entry && + bearishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bearishMomentumBar = iBar; + } + } + } + + // + double sls[]; + Add( + sar, + sls // + ); + Add( + str, + sls // + ); + + // + if (isBullish) + { + // + Add( + atrLower, + sls // + ); + + // // + // Add( + // vale, + // sls // + // ); + + // + if (bullishMomentumBar.IsValid()) + { + // + Add( + bullishMomentumBar.low, + sls // + ); + } + + // // + // if (IsValidIndex(lowerValeIDX)) + // { + // // + // Add( + // lowerVale, + // sls // + // ); + // } + + // + if (le1 != EMPTY_VALUE) + { + // + Add( + le1, + sls // + ); + } + + // + if (le2 != EMPTY_VALUE) + { + // + Add( + le2, + sls // + ); + } + } + else + { + // + Add( + atrUpper, + sls // + ); + + // // + // Add( + // peak, + // sls // + // ); + + // + if (bearishMomentumBar.IsValid()) + { + // + Add( + bearishMomentumBar.high, + sls // + ); + } + + // + // if (IsValidIndex(higherPeakIDX)) + // { + // // + // Add( + // higherPeak, + // sls // + // ); + // } + + // + if (se1 != EMPTY_VALUE) + { + // + Add( + se1, + sls // + ); + } + + // + if (se2 != EMPTY_VALUE) + { + // + Add( + se2, + sls // + ); + } + } + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + iAtr *= 2.5; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double riskInPoints = risk / points; + if (riskInPoints >= 150) + { + // + target = + isBullish + ? entry + (points * 200) + : entry - (points * 200); + + // + target = 0; + } + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_X); + + // + // result = DetectX121SMCGuards( + // provider, + // guards, + // positions, + // triggerCycleHelper, + // decisionCycleHelper, + // analyseCycleHelper, + // verificationCycleHelper, + // consolidationCycleHelper, + // visionCycleHelper // + // ); + + // + return result; +} + +// +int AddX121SMCXConditionsIfNotExists( + X121SMCStrategyXSignalConditions &item, + X121SMCStrategyXSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXConditions( + X121SMCStrategyXSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xobgpv.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xobgpv.signal.lib.mq5 new file mode 100644 index 0000000..bc3329e --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xobgpv.signal.lib.mq5 @@ -0,0 +1,1020 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XOBGPV +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXOBGPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + XFVGOrderBlock fvgOB; + + // + // Constructor ... + X121SMCStrategyXOBGPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + fvgOB.Clean(); + } + + /** + * Update Order Blocks Date ... + */ + void UpdateOrderBlocks() + { + // + datetime cTime = TimeCurrent(); + + // + fvgOB.orderBlock.To(cTime); + fvgOB.fairValueGap.To(cTime); + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXOBGPVSignalConditions mXOBGPVConditions; +X121SMCStrategyXOBGPVSignalConditions mXOBGPVConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXOBGPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXOBGPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + ENUM_X_DIRECTION forDir; + XFVGOrderBlock bullishOrderBlocks[]; + XFVGOrderBlock bearishOrderBlocks[]; + bool isTested = DetectFVGOB( + forDir, + bullishOrderBlocks, + bearishOrderBlocks, + consolidationState, + analyseState // + ); + + // + isBullish = + isTested && + IsBullish(forDir); + // + isBearish = + isTested && + IsBearish(forDir); + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.dir = forDir; + if (isBullish) + { + conditions.fvgOB = bullishOrderBlocks[0]; + } + else + { + conditions.fvgOB = bearishOrderBlocks[0]; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXOBGPVSiganlTrigger( + // + X121SMCStrategyXOBGPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 576 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + double decisionPeak = decisionConditions.x121Conditions.peaksBuffer[1]; + double isNewDecisionPeak = decisionConditions.x121Conditions.isNewPeak; + + // + double decisionVale = decisionConditions.x121Conditions.valesBuffer[1]; + double isNewDecisionVale = decisionConditions.x121Conditions.isNewVale; + + // + bool isTriggerRSICrossedOverOverSold = triggerConditions.x121Conditions.isRsiCrossedOverOverSold; + bool isTriggerRSICrossedUnderOverBought = triggerConditions.x121Conditions.isRsiCrossedUnderOverBought; + + // + bool isDecisionRSICrossedOverOverSold = decisionConditions.x121Conditions.isRsiCrossedOverOverSold; + bool isDecisionRSICrossedUnderOverBought = decisionConditions.x121Conditions.isRsiCrossedUnderOverBought; + + // + // Waits For Price to Go Inside FVG ... + bool isPriceInsideOB = IsPriceInsideZone( + cBar, + conditions.fvgOB.orderBlock // + ); + + // + bool isPriceInsideFVG = IsPriceInsideZone( + cBar, + conditions.fvgOB.fairValueGap // + ); + + // + result = isPriceInsideOB && + isPriceInsideFVG && + conditions.fvgOB.IsValid(); + if (!result) + { + return result; + } + + // + double fvgOBUpper = 0; + double fvgOBLower = 0; + bool hasBoundary = conditions.fvgOB.GetBoundary( + fvgOBUpper, + fvgOBLower // + ); + result = hasBoundary; + if (!result) + { + return result; + } + + // + // Detect Bullish Conditions ... + isBullish = + isBullish && + cBar.IsBullish() && + decisionVale < fvgOBUpper && + decisionVale > fvgOBLower + // && + // isTriggerRSICrossedOverOverSold + ; + + // + // Detect Bearish Conditions ... + isBearish = + isBearish && + cBar.IsBearish() && + decisionPeak < fvgOBUpper && + decisionPeak > fvgOBLower + // && + // isTriggerRSICrossedUnderOverBought + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + + // + double sls[]; + + // + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + if (conditions.fvgOB.IsValid()) + { + // + Add( + fvgOBUpper, + sls // + ); + + // + Add( + fvgOBLower, + sls // + ); + } + + // + if (isBullish) + { + // + int idx = -1; + double lowerVale = triggerCycleHelper.mX121Helper.xpvHelper.GetLowerVale( + idx, + vale // + ); + if (lowerVale > 0) + { + // + Add( + lowerVale, + sls // + ); + } + + // + Add( + vale, + sls // + ); + } + else if (isBearish) + { + // + int idx = -1; + double higherPeak = triggerCycleHelper.mX121Helper.xpvHelper.GetHigherPeak( + idx, + peak // + ); + if (higherPeak > 0) + { + // + Add( + higherPeak, + sls // + ); + } + + // + Add( + peak, + sls // + ); + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - atr + : slsMax + atr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + target = 0; + + // + } + + // + // Ignore Target ... + target = 0; + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +// +int AddX121SMCXOBGPVConditionsIfNotExists( + X121SMCStrategyXOBGPVSignalConditions &item, + X121SMCStrategyXOBGPVSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + bool canAdd = !IsValidSize(count); + if (!canAdd) + { + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + bool hasSame = false; + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXOBGPVSignalConditions iItem = items[i]; + + // + hasSame = iItem.fvgOB.IsSameAs(item.fvgOB); + if (hasSame) + { + break; + } + } + + // + canAdd = !hasSame; + } + + // + if (canAdd) + { + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + } + + // + return result; +} + +// +// Draw Signal ... +int DrawX121SMCXOBGPVSiganl( + X121SMCStrategyXOBGPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.dir); + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xobspv.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xobspv.signal.lib.mq5 new file mode 100644 index 0000000..18316cd --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xobspv.signal.lib.mq5 @@ -0,0 +1,1138 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XOBSPV +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXOBSPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + XPriceZones priceZone; + + // + // Constructor ... + X121SMCStrategyXOBSPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + + // + priceZone.Clean(); + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXOBSPVSignalConditions mXOBSPVConditions; +X121SMCStrategyXOBSPVSignalConditions mXOBSPVConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXOBSPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXOBSPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + // Waits for new Peak or Vale ... + + // + // Reading Previous Conditions ... + ENUM_XPOI_EVENTS consolidationPoiEventsPrev[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEventsPrev[]; + X121SMCCycleConditions consolidationConditionsPrev; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEventsPrev, + consolidationPoiEventsPrev, + consolidationConditionsPrev, + cIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + double decisionPeak = decisionConditions.x121Conditions.peaksBuffer[1]; + double decisionVale = decisionConditions.x121Conditions.valesBuffer[1]; + + // + // Find Price Inside Zone ... + XPriceZones priceZone = conditions.priceZone; + bool hasPriceZones = conditions.priceZone.IsValid(); + if (!hasPriceZones) + { + // + hasPriceZones = CalculatePriceInsideZones( + priceZone, + analyseState, + cBar // + ); + + // + if (hasPriceZones) + { + // + // Validate Price Zone ... + double upper = 0; + double lower = 0; + hasPriceZones = priceZone.GetBoundary( + X_DIRECTION_ALL, + upper, + lower // + ); + result = hasPriceZones; + if (!result) + { + return result; + } + + // + bool isValid = decisionPeak <= upper || + decisionVale >= lower; + hasPriceZones = isValid; + result = hasPriceZones; + if (!result) + { + return result; + } + + // + conditions.priceZone = priceZone; + } + } + + // + // Detect Str Change Direction ... + + // + bool isDecisionSarBullish = decisionConditions.x121Conditions.isSarBullish; + bool isDecisionSarBearish = decisionConditions.x121Conditions.isSarBearish; + + // + bool isDecisionStrBullish = decisionConditions.x121Conditions.isStrBullish; + bool isDecisionStrBearish = decisionConditions.x121Conditions.isStrBearish; + + // + bool isDecisionSarCrossedOverVale = decisionConditions.x121Conditions.isSarCrossedOverVale; + bool isDecisionSarCrossedUnderPeak = decisionConditions.x121Conditions.isSarCrossedUnderPeak; + + // + bool isDecisionStrCrossedOverVale = decisionConditions.x121Conditions.isStrCrossedOverVale; + bool isDecisionStrCrossedUnderPeak = decisionConditions.x121Conditions.isStrCrossedUnderPeak; + + // + bool isDecisionPeakOverAtrUpper = decisionConditions.x121Conditions.isPeakOverAtrUpper; + bool isDecisionValeUnderAtrLower = decisionConditions.x121Conditions.isValeUnderAtrLower; + + // + bool isDecisionVWapBullishState = decisionConditions.x121Conditions.isVWapBullishState; + bool isDecisionVWapSwitchedToBullishState = decisionConditions.x121Conditions.isVWapSwitchedToBullishState; + + // + bool isDecisionVWapBullishOrdered = decisionConditions.x121Conditions.isVWapBullishOrdered; + bool isDecisionVWapSwitchedToBullishOrdered = decisionConditions.x121Conditions.isVWapSwitchedToBullishOrdered; + + // + bool isDecisionVWapBearishState = decisionConditions.x121Conditions.isVWapBearishState; + bool isDecisionVWapSwitchedToBearishState = decisionConditions.x121Conditions.isVWapSwitchedToBearishState; + + // + bool isDecisionVWapBearishOrdered = decisionConditions.x121Conditions.isVWapBearishOrdered; + bool isDecisionVWapSwitchedToBearishOrdered = decisionConditions.x121Conditions.isVWapSwitchedToBearishOrdered; + + // + bool isDecisionStrUpperOverPeak = decisionConditions.x121Conditions.isStrUpperOverPeak; + bool isDecisionStrLowerOverVale = decisionConditions.x121Conditions.isStrLowerOverVale; + + // + bool isDecisionStrUpperUnderPeak = decisionConditions.x121Conditions.isStrUpperUnderPeak; + bool isDecisionStrLowerUnderVale = decisionConditions.x121Conditions.isStrLowerUnderVale; + + // + bool isDecisionDonLowUpperLesserThanDonCloseUpper = + decisionConditions.x121Conditions.donLowUpperBuffer[1] < + decisionConditions.x121Conditions.donCloseUpperBuffer[1]; + + // + bool isDecisionDonHighLowerGreaterThanDonCloseLower = + decisionConditions.x121Conditions.donHighLowerBuffer[1] < + decisionConditions.x121Conditions.donCloseLowerBuffer[1]; + + // + // Summarize Conditions ... + + // + isBullish = + // + isDecisionValeUnderAtrLower + // + && + // + isDecisionDonHighLowerGreaterThanDonCloseLower + // + && + // + ( + // + isDecisionVWapBullishState || + isDecisionVWapBullishOrdered + // + ) + // + && + // + ( + // + isDecisionStrUpperOverPeak || + isDecisionStrLowerOverVale + // + ) + // + && + // + ( + // + ( + // + isDecisionStrBullish && + isDecisionSarCrossedOverVale + // + ) + // + || + // + ( + // + isDecisionSarBullish && + isDecisionStrCrossedOverVale + // + ) + // + ) + // + ; + + // + isBearish = + // + isDecisionPeakOverAtrUpper + // + && + // + isDecisionDonLowUpperLesserThanDonCloseUpper + // + && + // + ( + // + isDecisionVWapBearishState || + isDecisionVWapBearishOrdered + // + ) + // + && + // + ( + // + isDecisionStrUpperUnderPeak || + isDecisionStrLowerUnderVale + // + ) + // + && + // + ( + // + ( + // + isDecisionStrBearish && + isDecisionSarCrossedUnderPeak + // + ) + // + || + // + ( + // + isDecisionSarBearish && + isDecisionStrCrossedUnderPeak // + ) + // + ) + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXOBSPVSiganlTrigger( + // + X121SMCStrategyXOBSPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + double decisionLastBullishStr = decisionCycleHelper.mX121Helper.xstrHelper.GetLastSTR(X_DIRECTION_BULLISH); + double decisionLastBearishStr = decisionCycleHelper.mX121Helper.xstrHelper.GetLastSTR(X_DIRECTION_BEARISH); + + // + bool isDecisionLastBearishStrBreakedUp = IsBarBreak( + decisionLastBearishStr, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isDecisionLastBullishStrBreakedDown = IsBarBreak( + decisionLastBullishStr, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Detect Bullish Conditions ... + isBullish = + // + isBullish && + cBar.IsBullish() && + isDecisionLastBearishStrBreakedUp + // + ; + + // + // Detect Bearish Conditions ... + isBearish = + // + isBearish && + cBar.IsBearish() && + isDecisionLastBullishStrBreakedDown + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + + // + double sls[]; + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + double iPeak = decisionConditions.x121Conditions.peaksBuffer[1]; + double iVale = decisionConditions.x121Conditions.valesBuffer[1]; + + // + if (isBullish) + { + // + int lowerValeIDX = -1; + double lowerVale = triggerCycleHelper.mX121Helper.xpvHelper.GetLowerVale( + lowerValeIDX, + iVale // + ); + if (lowerVale > 0) + { + // + Add( + lowerVale, + sls // + ); + } + + // + Add( + iVale, + sls // + ); + } + else if (isBearish) + { + // + int higherPeakIDX = -1; + double higherPeak = triggerCycleHelper.mX121Helper.xpvHelper.GetHigherPeak( + higherPeakIDX, + iPeak // + ); + if (higherPeak > 0) + { + // + Add( + higherPeak, + sls // + ); + } + + // + Add( + iPeak, + sls // + ); + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + target = 0; + + // + } + + // + // Ignore Target ... + target = 0; + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +// +int AddX121SMCXOBSPVConditionsIfNotExists( + X121SMCStrategyXOBSPVSignalConditions &item, + X121SMCStrategyXOBSPVSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXOBSPVSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXOBSPVSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.1.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.1.signal.lib.mq5 new file mode 100644 index 0000000..55fb83e --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.1.signal.lib.mq5 @@ -0,0 +1,1420 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// // +// const string X121SMCXTWPV_Method_1_Token = "X121SMCXTWPV_1"; +// const string X121SMCXTWPV_Method_2_Token = "X121SMCXTWPV_2"; +// const string X121SMCXTWPV_Method_3_Token = "X121SMCXTWPV_3"; + +// // +// enum ENUM_X_X121SMC_XTWPV_METHODS +// { +// X_X121SMC_XTWPV_METHOD_UNKNOWN, +// X_X121SMC_XTWPV_METHOD_1, +// X_X121SMC_XTWPV_METHOD_2, +// X_X121SMC_XTWPV_METHOD_3, +// }; + +// // +// string ToString(ENUM_X_X121SMC_XTWPV_METHODS value) +// { +// // +// string result = NULL; + +// // +// if (value == X_X121SMC_XTWPV_METHOD_UNKNOWN) +// { +// return result; +// } + +// // +// switch (value) +// { +// // +// case X_X121SMC_XTWPV_METHOD_1: +// result = "Method_1"; +// break; + +// // +// case X_X121SMC_XTWPV_METHOD_2: +// result = "Method_2"; +// break; +// } + +// // +// return result; +// } + +// // +// ENUM_X_X121SMC_XTWPV_METHODS ParseMethod(string value) +// { +// // +// ENUM_X_X121SMC_XTWPV_METHODS result = X_X121SMC_XTWPV_METHOD_UNKNOWN; + +// // +// if (!IsValid(value)) +// { +// return result; +// } + +// // +// if (Contains(X121SMCXTWPV_Method_1_Token, value)) +// { +// result = X_X121SMC_XTWPV_METHOD_1; +// } +// else if (Contains(X121SMCXTWPV_Method_2_Token, value)) +// { +// result = X_X121SMC_XTWPV_METHOD_2; +// } + +// // +// return result; +// } + +// +// Definitions ... +struct X121SMCStrategyXTWPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + XMarketStructure consolidationMarketStructure; + XMarketStructure analyseMarketStructure; + + // + datetime newPeakAboveAtrUpperAt; + datetime newValeBelowAtrLowerAt; + datetime sarSiwtchedToBullishAt; + datetime sarSiwtchedToBearishAt; + datetime rsiCrossedOverOverSoldAt; + datetime rsiCrossedUnderOverBoughtAt; + + // + XPriceZones decisionZone; + XPriceZones peakPriceZone; + XPriceZones valePriceZone; + + // + // Constructor ... + X121SMCStrategyXTWPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + decisionZone.Clean(); + peakPriceZone.Clean(); + valePriceZone.Clean(); + + // + analyseMarketStructure.Clean(); + consolidationMarketStructure.Clean(); + + // + newPeakAboveAtrUpperAt = NULL; + newValeBelowAtrLowerAt = NULL; + sarSiwtchedToBullishAt = NULL; + sarSiwtchedToBearishAt = NULL; + rsiCrossedOverOverSoldAt = NULL; + rsiCrossedUnderOverBoughtAt = NULL; + } + + /** + * Check Required Market Strucutre Exists or not ... + * + * @return ( bool ) + */ + bool HasMarketStrucutre() + { + // + bool result = false; + + // + result = + // + analyseMarketStructure.IsValid() && + consolidationMarketStructure.IsValid() + // + && + // + analyseMarketStructure.HasTrend() && + consolidationMarketStructure.HasTrend() + // + && + // + analyseMarketStructure.bias == consolidationMarketStructure.bias + // + ; + + // + return result; + } + + /** + * Check if Conditions Filled ... + * + * @return ( bool ) + */ + bool IsFilled() + { + // + bool result = false; + + // + result = HasMarketStrucutre(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(analyseMarketStructure.bias); + + // + result = + isBullish + ? IsValid(newValeBelowAtrLowerAt) && + IsValid(sarSiwtchedToBullishAt) && + IsValid(rsiCrossedOverOverSoldAt) + : IsValid(newPeakAboveAtrUpperAt) && + IsValid(sarSiwtchedToBearishAt) && + IsValid(rsiCrossedUnderOverBoughtAt); + + // + return result; + } + + /** + * Check if Has Price Zones ... + * + * @return ( bool ) + */ + bool HasPriceZone() + { + // + bool result = false; + + // + result = HasMarketStrucutre(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(analyseMarketStructure.bias); + + // + result = + isBullish + ? valePriceZone.IsValid() + : peakPriceZone.IsValid(); + + // + return result; + } + + /** + * Check if Has Decision Zones ... + * + * @return ( bool ) + */ + bool HasDecisionZone() + { + return HasPriceZone() && + decisionZone.IsValid(); + } + + // +}; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXTWPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + bool hasMarketStructure = conditions.HasMarketStrucutre(); + if (!hasMarketStructure) + { + // + bool hasConsolidationMarketStructure = + consolidationCycleHelper + .DetectMarketStructure(conditions.consolidationMarketStructure); + + // + bool hasAnalyseMarketStructure = + analyseCycleHelper + .DetectMarketStructure(conditions.analyseMarketStructure); + + // + hasMarketStructure = conditions.HasMarketStrucutre(); + result = hasMarketStructure; + if (!result) + { + return result; + } + } + + // + // We Are Sure we Have Direct Structure Bias ... + isBullish = IsBullish(conditions.analyseMarketStructure.bias); + isBearish = IsBearish(conditions.analyseMarketStructure.bias); + + // + // RSI ... + double rsi = triggerConditions.x121Conditions.rsiBuffer[1]; + + // + bool isRSICrossedOverOverBought = triggerConditions.x121Conditions.isRSICrossedOverOverBought; + bool isRSICrossedUnderOverBought = triggerConditions.x121Conditions.isRSICrossedUnderOverBought; + + // + bool isRSICrossedOverOverSold = triggerConditions.x121Conditions.isRSICrossedOverOverSold; + bool isRSICrossedUnderOverSold = triggerConditions.x121Conditions.isRSICrossedUnderOverSold; + + // + // PV ... + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + bool isNewPeak = triggerConditions.x121Conditions.isNewPeak; + bool isNewVale = triggerConditions.x121Conditions.isNewVale; + + // + // ATR ... + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double atrUpper = triggerConditions.x121Conditions.atrUpperBuffer[1]; + double atrLower = triggerConditions.x121Conditions.atrLowerBuffer[1]; + + // + // SAR ... + double sar = triggerConditions.x121Conditions.sarBuffer[1]; + + // + bool isSarSwitchedToBullish = triggerConditions.x121Conditions.isSarSwitchedToBullish; + bool isSarSwitchedToBearish = triggerConditions.x121Conditions.isSarSwitchedToBearish; + + // + // Complex Conditions ... + + // + bool isNewPeakAboveAtrUpper = + isNewPeak && + peak > atrUpper; + + // + bool isNewValeBelowAtrLower = + isNewVale && + vale < atrLower; + + // + // Fill Conditions ... + bool isConditionsFilled = conditions.IsFilled(); + if (!isConditionsFilled) + { + // + // Cleanup ... + + // + // Sar ... + + // + // Bullish ... + if (isBullish && + isSarSwitchedToBearish && + IsValid(conditions.sarSiwtchedToBullishAt)) + { + conditions.sarSiwtchedToBullishAt = NULL; + } + + // + // Bearish ... + if (isBearish && + isSarSwitchedToBullish && + IsValid(conditions.sarSiwtchedToBearishAt)) + { + conditions.sarSiwtchedToBearishAt = NULL; + } + + // + // Rsi ... + + // + // Bullish ... + if (isBullish && + isRSICrossedUnderOverSold && + IsValid(conditions.rsiCrossedOverOverSoldAt)) + { + conditions.rsiCrossedOverOverSoldAt = NULL; + } + + // + // Bearish ... + if (isBearish && + isRSICrossedOverOverBought && + IsValid(conditions.rsiCrossedUnderOverBoughtAt)) + { + conditions.rsiCrossedUnderOverBoughtAt = NULL; + } + + // + // Atr Change ... + + // + // Bullish ... + if (isBullish && + isNewPeak && + IsValid(conditions.newValeBelowAtrLowerAt)) + { + conditions.newValeBelowAtrLowerAt = NULL; + } + + // + // Bearish ... + if (isBearish && + isNewVale && + IsValid(conditions.newPeakAboveAtrUpperAt)) + { + conditions.newPeakAboveAtrUpperAt = NULL; + } + + // + // Filling Up ... + + // + // Sar Change ... + + // + // Bullish ... + if (isBullish && + isSarSwitchedToBullish && + !IsValid(conditions.sarSiwtchedToBullishAt)) + { + conditions.sarSiwtchedToBullishAt = cTime; + } + + // + // Bearish ... + if (isBearish && + isSarSwitchedToBearish && + !IsValid(conditions.sarSiwtchedToBearishAt)) + { + conditions.sarSiwtchedToBearishAt = cTime; + } + + // + // Rsi Change ... + + // + // Bullish ... + if (isBullish && + isRSICrossedOverOverSold && + !IsValid(conditions.rsiCrossedOverOverSoldAt)) + { + conditions.rsiCrossedOverOverSoldAt = cTime; + } + + // + // Bearish ... + if (isBearish && + isRSICrossedUnderOverBought && + !IsValid(conditions.rsiCrossedUnderOverBoughtAt)) + { + conditions.rsiCrossedUnderOverBoughtAt = cTime; + } + + // + // Atr Change ... + // New Peaks and Vale ... + + // + // Bullish ... + if (isBullish && + isNewValeBelowAtrLower && + !IsValid(conditions.newValeBelowAtrLowerAt)) + { + conditions.newValeBelowAtrLowerAt = cTime; + } + + // + // Bearish ... + if (isBearish && + isNewPeakAboveAtrUpper && + !IsValid(conditions.newPeakAboveAtrUpperAt)) + { + conditions.newPeakAboveAtrUpperAt = cTime; + } + + // + isConditionsFilled = conditions.IsFilled(); + result = isConditionsFilled; + if (!result) + { + return result; + } + } + + // + // Fill Price Zones ... + bool hasPriceZone = conditions.HasPriceZone(); + if (!hasPriceZone) + { + // + if (isBullish) + { + // + XPriceZones vPZone; + bool hasValeInsideZone = CalculatePriceInsideZones( + vPZone, + analyseState, + vale // + ); + + // + XPriceZones cbPZone; + bool hasPriceInsideZone = CalculatePriceInsideZones( + cbPZone, + analyseState, + cBar // + ); + + // + if (hasValeInsideZone && + hasPriceInsideZone && + vPZone.IsBullish() && + cbPZone.IsBullish()) + { + conditions.valePriceZone = cbPZone; + } + } + else if (isBearish) + { + // + XPriceZones pPZone; + bool hasPeakInsideZone = CalculatePriceInsideZones( + pPZone, + analyseState, + peak // + ); + + // + XPriceZones cbPZone; + bool hasPriceInsideZone = CalculatePriceInsideZones( + cbPZone, + analyseState, + cBar // + ); + + // + if ( + hasPeakInsideZone && + hasPriceInsideZone && + pPZone.IsBearish() && + cbPZone.IsBearish()) + { + conditions.peakPriceZone = cbPZone; + } + } + + // + hasPriceZone = conditions.HasPriceZone(); + result = hasPriceZone; + if (!result) + { + return result; + } + } + + // + // Check for Decision ... + bool hasDecision = conditions.HasDecisionZone(); + if (!hasDecision) + { + // + if (isBullish) + { + // + XPriceZones pZone; + bool hasPZone = CalculatePriceInsideZones( + pZone, + decisionState, + vale // + ); + + // + if (hasPZone && + pZone.IsBullish()) + { + conditions.decisionZone = pZone; + } + } + else if (isBearish) + { + // + XPriceZones pZone; + bool hasPZone = CalculatePriceInsideZones( + pZone, + decisionState, + peak // + ); + + // + if (hasPZone && + pZone.IsBearish()) + { + conditions.decisionZone = pZone; + } + } + + // + hasDecision = conditions.HasDecisionZone(); + result = hasDecision; + if (!result) + { + return result; + } + } + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXTWPVSiganlTrigger( + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + + // + double sls[]; + + // + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + if (isBullish) + { + // + double lowerVale = triggerCycleHelper.mX121Helper.GetLowerVale(vale); + if (lowerVale > 0) + { + // + Add( + lowerVale, + sls // + ); + } + } + else if (isBearish) + { + // + double higherPeak = triggerCycleHelper.mX121Helper.GetHigherPeak(peak); + if (higherPeak > 0) + { + // + Add( + higherPeak, + sls // + ); + } + } + + // + if (ArraySize(sls) == 0) + { + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - atr + : slsMax + atr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + target = 0; + + // + } + + // + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +// +// Draw Signal ... +int DrawX121SMCXTWPVSiganl( + X121SMCStrategyXTWPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.dir); + + // + XCBaseObject *priceZoneObjs[]; + XCBaseObject *decisionZoneObjs[]; + XCBaseObject *marketStructureObjs[]; + + // + bool hasMarketStructure = conditions.HasMarketStrucutre(); + if (hasMarketStructure) + { + // // + // drawer.DrawMarketStructure( + // conditions.analyseMarketStructure, + // marketStructureObjs // + // ); + } + + // + bool hasPriceZone = conditions.HasPriceZone(); + if (hasPriceZone) + { + // + XPriceZones pZone; + if (isBullish) + { + pZone = conditions.valePriceZone; + } + else + { + pZone = conditions.peakPriceZone; + } + + // + drawer.DrawPriceZone( + pZone, + priceZoneObjs, + conditions.dir // + ); + } + + // + bool hasDecisionZone = conditions.HasDecisionZone(); + if (hasDecisionZone) + { + // + drawer.DrawPriceZone( + conditions.decisionZone, + decisionZoneObjs + // , + // conditions.dir // + ); + } + + // + Copy( + priceZoneObjs, + drawnObjects, + false // + ); + + // + Copy( + decisionZoneObjs, + drawnObjects, + false // + ); + + // + Copy( + marketStructureObjs, + drawnObjects, + false // + ); + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.12signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.12signal.lib.mq5 new file mode 100644 index 0000000..a87e49f --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.12signal.lib.mq5 @@ -0,0 +1,1367 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXTWPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + XMarketStructure consolidationMarketStructure; + XMarketStructure analyseMarketStructure; + + // + datetime newPeakAboveAtrUpperAt; + datetime newValeBelowAtrLowerAt; + datetime sarSiwtchedToBullishAt; + datetime sarSiwtchedToBearishAt; + datetime rsiCrossedOverOverSoldAt; + datetime rsiCrossedUnderOverBoughtAt; + + // + XPriceZones decisionZone; + XPriceZones peakPriceZone; + XPriceZones valePriceZone; + + // + // Constructor ... + X121SMCStrategyXTWPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + decisionZone.Clean(); + peakPriceZone.Clean(); + valePriceZone.Clean(); + + // + analyseMarketStructure.Clean(); + consolidationMarketStructure.Clean(); + + // + newPeakAboveAtrUpperAt = NULL; + newValeBelowAtrLowerAt = NULL; + sarSiwtchedToBullishAt = NULL; + sarSiwtchedToBearishAt = NULL; + rsiCrossedOverOverSoldAt = NULL; + rsiCrossedUnderOverBoughtAt = NULL; + } + + /** + * Check Required Market Strucutre Exists or not ... + * + * @return ( bool ) + */ + bool HasMarketStrucutre() + { + // + bool result = false; + + // + result = + // + analyseMarketStructure.IsValid() && + consolidationMarketStructure.IsValid() + // + && + // + analyseMarketStructure.HasTrend() && + consolidationMarketStructure.HasTrend() + // + && + // + analyseMarketStructure.bias == consolidationMarketStructure.bias + // + ; + + // + return result; + } + + /** + * Check if Conditions Filled ... + * + * @return ( bool ) + */ + bool IsFilled() + { + // + bool result = false; + + // + result = HasMarketStrucutre(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(analyseMarketStructure.bias); + + // + result = + isBullish + ? IsValid(newValeBelowAtrLowerAt) && + IsValid(sarSiwtchedToBullishAt) && + IsValid(rsiCrossedOverOverSoldAt) + : IsValid(newPeakAboveAtrUpperAt) && + IsValid(sarSiwtchedToBearishAt) && + IsValid(rsiCrossedUnderOverBoughtAt); + + // + return result; + } + + /** + * Check if Has Price Zones ... + * + * @return ( bool ) + */ + bool HasPriceZone() + { + // + bool result = false; + + // + result = HasMarketStrucutre(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(analyseMarketStructure.bias); + + // + result = + isBullish + ? valePriceZone.IsValid() + : peakPriceZone.IsValid(); + + // + return result; + } + + /** + * Check if Has Decision Zones ... + * + * @return ( bool ) + */ + bool HasDecisionZone() + { + return HasPriceZone() && + decisionZone.IsValid(); + } + + // +}; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXTWPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + bool hasMarketStructure = conditions.HasMarketStrucutre(); + if (!hasMarketStructure) + { + // + bool hasConsolidationMarketStructure = + consolidationCycleHelper + .DetectMarketStructure(conditions.consolidationMarketStructure); + + // + bool hasAnalyseMarketStructure = + analyseCycleHelper + .DetectMarketStructure(conditions.analyseMarketStructure); + + // + hasMarketStructure = conditions.HasMarketStrucutre(); + result = hasMarketStructure; + if (!result) + { + return result; + } + } + + // + // We Are Sure we Have Direct Structure Bias ... + isBullish = IsBullish(conditions.analyseMarketStructure.bias); + isBearish = IsBearish(conditions.analyseMarketStructure.bias); + + // + // RSI ... + double rsi = triggerConditions.x121Conditions.rsiBuffer[1]; + + // + bool isRSICrossedOverOverBought = triggerConditions.x121Conditions.isRSICrossedOverOverBought; + bool isRSICrossedUnderOverBought = triggerConditions.x121Conditions.isRSICrossedUnderOverBought; + + // + bool isRSICrossedOverOverSold = triggerConditions.x121Conditions.isRSICrossedOverOverSold; + bool isRSICrossedUnderOverSold = triggerConditions.x121Conditions.isRSICrossedUnderOverSold; + + // + // PV ... + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + bool isNewPeak = triggerConditions.x121Conditions.isNewPeak; + bool isNewVale = triggerConditions.x121Conditions.isNewVale; + + // + // ATR ... + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double atrUpper = triggerConditions.x121Conditions.atrUpperBuffer[1]; + double atrLower = triggerConditions.x121Conditions.atrLowerBuffer[1]; + + // + // SAR ... + double sar = triggerConditions.x121Conditions.sarBuffer[1]; + + // + bool isSarSwitchedToBullish = triggerConditions.x121Conditions.isSarSwitchedToBullish; + bool isSarSwitchedToBearish = triggerConditions.x121Conditions.isSarSwitchedToBearish; + + // + // Complex Conditions ... + + // + bool isNewPeakAboveAtrUpper = + isNewPeak && + peak > atrUpper; + + // + bool isNewValeBelowAtrLower = + isNewVale && + vale < atrLower; + + // + // Fill Conditions ... + bool isConditionsFilled = conditions.IsFilled(); + if (!isConditionsFilled) + { + // + // Cleanup ... + + // + // Sar ... + + // + // Bullish ... + if (isBullish && + isSarSwitchedToBearish && + IsValid(conditions.sarSiwtchedToBullishAt)) + { + conditions.sarSiwtchedToBullishAt = NULL; + } + + // + // Bearish ... + if (isBearish && + isSarSwitchedToBullish && + IsValid(conditions.sarSiwtchedToBearishAt)) + { + conditions.sarSiwtchedToBearishAt = NULL; + } + + // + // Rsi ... + + // + // Bullish ... + if (isBullish && + isRSICrossedUnderOverSold && + IsValid(conditions.rsiCrossedOverOverSoldAt)) + { + conditions.rsiCrossedOverOverSoldAt = NULL; + } + + // + // Bearish ... + if (isBearish && + isRSICrossedOverOverBought && + IsValid(conditions.rsiCrossedUnderOverBoughtAt)) + { + conditions.rsiCrossedUnderOverBoughtAt = NULL; + } + + // + // Atr Change ... + + // + // Bullish ... + if (isBullish && + isNewPeak && + IsValid(conditions.newValeBelowAtrLowerAt)) + { + conditions.newValeBelowAtrLowerAt = NULL; + } + + // + // Bearish ... + if (isBearish && + isNewVale && + IsValid(conditions.newPeakAboveAtrUpperAt)) + { + conditions.newPeakAboveAtrUpperAt = NULL; + } + + // + // Filling Up ... + + // + // Sar Change ... + + // + // Bullish ... + if (isBullish && + isSarSwitchedToBullish && + !IsValid(conditions.sarSiwtchedToBullishAt)) + { + conditions.sarSiwtchedToBullishAt = cTime; + } + + // + // Bearish ... + if (isBearish && + isSarSwitchedToBearish && + !IsValid(conditions.sarSiwtchedToBearishAt)) + { + conditions.sarSiwtchedToBearishAt = cTime; + } + + // + // Rsi Change ... + + // + // Bullish ... + if (isBullish && + isRSICrossedOverOverSold && + !IsValid(conditions.rsiCrossedOverOverSoldAt)) + { + conditions.rsiCrossedOverOverSoldAt = cTime; + } + + // + // Bearish ... + if (isBearish && + isRSICrossedUnderOverBought && + !IsValid(conditions.rsiCrossedUnderOverBoughtAt)) + { + conditions.rsiCrossedUnderOverBoughtAt = cTime; + } + + // + // Atr Change ... + // New Peaks and Vale ... + + // + // Bullish ... + if (isBullish && + isNewValeBelowAtrLower && + !IsValid(conditions.newValeBelowAtrLowerAt)) + { + conditions.newValeBelowAtrLowerAt = cTime; + } + + // + // Bearish ... + if (isBearish && + isNewPeakAboveAtrUpper && + !IsValid(conditions.newPeakAboveAtrUpperAt)) + { + conditions.newPeakAboveAtrUpperAt = cTime; + } + + // + isConditionsFilled = conditions.IsFilled(); + result = isConditionsFilled; + if (!result) + { + return result; + } + } + + // + // Fill Price Zones ... + bool hasPriceZone = conditions.HasPriceZone(); + if (!hasPriceZone) + { + // + if (isBullish) + { + // + XPriceZones vPZone; + bool hasValeInsideZone = CalculatePriceInsideZones( + vPZone, + analyseState, + vale // + ); + + // + XPriceZones cbPZone; + bool hasPriceInsideZone = CalculatePriceInsideZones( + cbPZone, + analyseState, + cBar // + ); + + // + if (hasValeInsideZone && + hasPriceInsideZone && + vPZone.IsBullish() && + cbPZone.IsBullish()) + { + conditions.valePriceZone = cbPZone; + } + } + else if (isBearish) + { + // + XPriceZones pPZone; + bool hasPeakInsideZone = CalculatePriceInsideZones( + pPZone, + analyseState, + peak // + ); + + // + XPriceZones cbPZone; + bool hasPriceInsideZone = CalculatePriceInsideZones( + cbPZone, + analyseState, + cBar // + ); + + // + if ( + hasPeakInsideZone && + hasPriceInsideZone && + pPZone.IsBearish() && + cbPZone.IsBearish()) + { + conditions.peakPriceZone = cbPZone; + } + } + + // + hasPriceZone = conditions.HasPriceZone(); + result = hasPriceZone; + if (!result) + { + return result; + } + } + + // + // Check for Decision ... + bool hasDecision = conditions.HasDecisionZone(); + if (!hasDecision) + { + // + if (isBullish) + { + // + XPriceZones pZone; + bool hasPZone = CalculatePriceInsideZones( + pZone, + decisionState, + vale // + ); + + // + if (hasPZone && + pZone.IsBullish()) + { + conditions.decisionZone = pZone; + } + } + else if (isBearish) + { + // + XPriceZones pZone; + bool hasPZone = CalculatePriceInsideZones( + pZone, + decisionState, + peak // + ); + + // + if (hasPZone && + pZone.IsBearish()) + { + conditions.decisionZone = pZone; + } + } + + // + hasDecision = conditions.HasDecisionZone(); + result = hasDecision; + if (!result) + { + return result; + } + } + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXTWPVSiganlTrigger( + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + // Detect Bullish Conditions ... + isBullish = + isBullish && + cBar.IsBullish(); + + // + // Detect Bearish Conditions ... + isBearish = + isBearish && + cBar.IsBearish(); + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + + // + double sls[]; + + // + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + if (isBullish) + { + // + double lowerVale = triggerCycleHelper.mX121Helper.xpvHelper.GetLowerVale(vale); + if (lowerVale > 0) + { + // + Add( + lowerVale, + sls // + ); + } + } + else if (isBearish) + { + // + double higherPeak = triggerCycleHelper.mX121Helper.xpvHelper.GetHigherPeak(peak); + if (higherPeak > 0) + { + // + Add( + higherPeak, + sls // + ); + } + } + + // + if (ArraySize(sls) == 0) + { + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - atr + : slsMax + atr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + target = 0; + + // + } + + // + // Ignore Target ... + target = 0; + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +// +// Draw Signal ... +int DrawX121SMCXTWPVSiganl( + X121SMCStrategyXTWPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.dir); + + // + XCBaseObject *priceZoneObjs[]; + XCBaseObject *decisionZoneObjs[]; + XCBaseObject *marketStructureObjs[]; + + // + bool hasMarketStructure = conditions.HasMarketStrucutre(); + if (hasMarketStructure) + { + // // + // drawer.DrawMarketStructure( + // conditions.analyseMarketStructure, + // marketStructureObjs // + // ); + } + + // + bool hasPriceZone = conditions.HasPriceZone(); + if (hasPriceZone) + { + // + XPriceZones pZone; + if (isBullish) + { + pZone = conditions.valePriceZone; + } + else + { + pZone = conditions.peakPriceZone; + } + + // + drawer.DrawPriceZone( + pZone, + priceZoneObjs, + conditions.dir // + ); + } + + // + bool hasDecisionZone = conditions.HasDecisionZone(); + if (hasDecisionZone) + { + // + drawer.DrawPriceZone( + conditions.decisionZone, + decisionZoneObjs + // , + // conditions.dir // + ); + } + + // + Copy( + priceZoneObjs, + drawnObjects, + false // + ); + + // + Copy( + decisionZoneObjs, + drawnObjects, + false // + ); + + // + Copy( + marketStructureObjs, + drawnObjects, + false // + ); + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.3signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.3signal.lib.mq5 new file mode 100644 index 0000000..154cf57 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.3signal.lib.mq5 @@ -0,0 +1,957 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXTWPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + datetime newPeakOverATRUpperAt; + datetime newValeUnderATRLowerAt; + + // + datetime donHighUpperEqualsToPeakAt; + datetime donLowLowerEqualsToValeAt; + + // + datetime closeOverATRUpperAt; + datetime closeUnderATRLowerAt; + + // + datetime rsiOverSoldAt; + datetime rsiOverBoughtAt; + + // + datetime newPeakOverLastAt; + datetime newValeUnderLastAt; + + // + datetime bullishBarSignAt; + datetime bearishBarSignAt; + + // + XPriceZones priceZone; + + // + // Constructor ... + X121SMCStrategyXTWPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + priceZone.Clean(); + + // + newPeakOverATRUpperAt = NULL; + newValeUnderATRLowerAt = NULL; + + // + donHighUpperEqualsToPeakAt = NULL; + donLowLowerEqualsToValeAt = NULL; + + // + closeOverATRUpperAt = NULL; + closeUnderATRLowerAt = NULL; + + // + rsiOverSoldAt = NULL; + rsiOverBoughtAt = NULL; + + // + newPeakOverLastAt = NULL; + newValeUnderLastAt = NULL; + + // + bullishBarSignAt = NULL; + bearishBarSignAt = NULL; + } + + /** + * Check if Conditions Filled ... + * + * @return ( bool ) + */ + bool IsFilled(ENUM_X_DIRECTION &fillDir) + { + // + bool result = false; + + // + fillDir = X_DIRECTION_NONE; + + // + bool hasNewPeakOverATRUpper = IsValid(newPeakOverATRUpperAt); + bool hasNewValeUnderATRLower = IsValid(newValeUnderATRLowerAt); + + // + bool hasDonHighUpperEqualsToPeak = IsValid(donHighUpperEqualsToPeakAt); + bool hasDonLowLowerEqualsToVale = IsValid(donLowLowerEqualsToValeAt); + + // + bool hasCloseOverATRUpper = IsValid(closeOverATRUpperAt); + bool hasCloseUnderATRLower = IsValid(closeUnderATRLowerAt); + + // + bool hasRsiOverSold = IsValid(rsiOverSoldAt); + bool hasRsiOverBought = IsValid(rsiOverBoughtAt); + + // + bool hasNewPeakOverLast = IsValid(newPeakOverLastAt); + bool hasNewValeUnderLast = IsValid(newValeUnderLastAt); + + // + bool hasBullishBarSign = IsValid(bullishBarSignAt); + bool hasBearishBarSign = IsValid(bearishBarSignAt); + + // + bool isBullish = + ( + // + hasRsiOverSold && + hasBullishBarSign && + hasNewValeUnderLast && + hasCloseUnderATRLower && + hasNewValeUnderATRLower && + hasDonLowLowerEqualsToVale + // + ); + + // + bool isBearish = + ( + // + hasRsiOverBought && + hasBearishBarSign && + hasNewPeakOverLast && + hasCloseOverATRUpper && + hasNewPeakOverATRUpper && + hasDonHighUpperEqualsToPeak + // + ); + + // + result = + (isBullish || isBearish) && + !(isBullish && isBearish); + if (result) + { + // + fillDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + bool HasPriceZone() + { + return priceZone.IsValid(); + } + + // +}; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXTWPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + result = analyseConditions.x121Conditions.isStrSwitchedToBullish || + analyseConditions.x121Conditions.isStrSwitchedToBearish; + if (!result) + { + return result; + } + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXTWPVSiganlTrigger( + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + // Detect Bullish Conditions ... + isBullish = + isBullish && + cBar.IsBullish(); + + // + // Detect Bearish Conditions ... + isBearish = + isBearish && + cBar.IsBearish(); + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + + // + double sls[]; + + // + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + if (isBullish) + { + // + double lowerVale = triggerCycleHelper.mX121Helper.xpvHelper.GetLowerVale(vale); + if (lowerVale > 0) + { + // + Add( + lowerVale, + sls // + ); + } + } + else if (isBearish) + { + // + double higherPeak = triggerCycleHelper.mX121Helper.xpvHelper.GetHigherPeak(peak); + if (higherPeak > 0) + { + // + Add( + higherPeak, + sls // + ); + } + } + + // + if (ArraySize(sls) == 0) + { + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - atr + : slsMax + atr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + target = 0; + + // + } + + // + // Ignore Target ... + target = 0; + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +// +// Draw Signal ... +int DrawX121SMCXTWPVSiganl( + X121SMCStrategyXTWPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.dir); + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.4.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.4.signal.lib.mq5 new file mode 100644 index 0000000..66a317c --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.4.signal.lib.mq5 @@ -0,0 +1,1083 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXTWPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + XFVGOrderBlock bullishOrderBlocks[]; + XFVGOrderBlock bearishOrderBlocks[]; + + // + // Constructor ... + X121SMCStrategyXTWPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + Clean(bullishOrderBlocks); + Clean(bearishOrderBlocks); + } + + /** + * Update Order Blocks Date ... + */ + void UpdateOrderBlocks() + { + // + int count = 0; + datetime cTime = TimeCurrent(); + + // + count = ArraySize(bullishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + bullishOrderBlocks[i].orderBlock.To(cTime); + bullishOrderBlocks[i].fairValueGap.To(cTime); + } + } + + // + count = ArraySize(bearishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + bearishOrderBlocks[i].orderBlock.To(cTime); + bearishOrderBlocks[i].fairValueGap.To(cTime); + } + } + } + + // +}; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXTWPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + ENUM_X_DIRECTION forDir; + XFVGOrderBlock bullishOrderBlocks[]; + XFVGOrderBlock bearishOrderBlocks[]; + bool isTested = TestPOIState( + forDir, + bullishOrderBlocks, + bearishOrderBlocks, + consolidationState, + analyseState, + decisionState // + ); + + // + isBullish = + isTested && + IsBullish(forDir); + // + isBearish = + isTested && + IsBearish(forDir); + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.dir = forDir; + Copy( + bullishOrderBlocks, + conditions.bullishOrderBlocks // + ); + Copy( + bearishOrderBlocks, + conditions.bearishOrderBlocks // + ); + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXTWPVSiganlTrigger( + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 576 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + double decisionPeak = decisionConditions.x121Conditions.peaksBuffer[1]; + double isNewDecisionPeak = decisionConditions.x121Conditions.isNewPeak; + + // + double decisionVale = decisionConditions.x121Conditions.valesBuffer[1]; + double isNewDecisionVale = decisionConditions.x121Conditions.isNewVale; + + // + // Waits For Price to Go Inside FVG ... + XFVGOrderBlock fvgOrderBlock; + bool isPriceInsideOB = false; + bool isPriceInsideFVG = false; + if (isBullish) + { + // + int count = ArraySize(conditions.bullishOrderBlocks); + for (int i = 0; i < count; i++) + { + // + XFVGOrderBlock iModel = conditions.bullishOrderBlocks[i]; + + // + isPriceInsideOB = IsPriceInsideZone( + cBar, + iModel.orderBlock // + ); + + // + isPriceInsideFVG = IsPriceInsideZone( + cBar, + iModel.fairValueGap // + ); + + // + if (isPriceInsideOB && + isPriceInsideFVG) + { + // + fvgOrderBlock = iModel; + break; + } + + // + isPriceInsideOB = false; + isPriceInsideFVG = false; + } + } + else + { + // + int count = ArraySize(conditions.bearishOrderBlocks); + for (int i = 0; i < count; i++) + { + // + XFVGOrderBlock iModel = conditions.bearishOrderBlocks[i]; + + // + isPriceInsideOB = IsPriceInsideZone( + cBar, + iModel.orderBlock // + ); + + // + isPriceInsideFVG = IsPriceInsideZone( + cBar, + iModel.fairValueGap // + ); + + // + if (isPriceInsideOB && + isPriceInsideFVG) + { + // + fvgOrderBlock = iModel; + break; + } + + // + isPriceInsideOB = false; + isPriceInsideFVG = false; + } + } + + // + result = isPriceInsideOB && + isPriceInsideFVG && + fvgOrderBlock.IsValid(); + if (!result) + { + return result; + } + + // + double fvgOBUpper = 0; + double fvgOBLower = 0; + bool hasBoundary = fvgOrderBlock.GetBoundary( + fvgOBUpper, + fvgOBLower // + ); + result = hasBoundary; + if (!result) + { + return result; + } + + // + // Detect Bullish Conditions ... + isBullish = + isBullish && + cBar.IsBullish() && + isNewDecisionVale; + + // + // Detect Bearish Conditions ... + isBearish = + isBearish && + cBar.IsBearish() && + isNewDecisionPeak; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + + // + double sls[]; + + // + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + double peak = triggerConditions.x121Conditions.peaksBuffer[1]; + double vale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + if (fvgOrderBlock.IsValid()) + { + // + Add( + fvgOBUpper, + sls // + ); + + // + Add( + fvgOBLower, + sls // + ); + } + + // + if (isBullish) + { + // + double lowerVale = triggerCycleHelper.mX121Helper.xpvHelper.GetLowerVale(vale); + if (lowerVale > 0) + { + // + Add( + lowerVale, + sls // + ); + } + + // + Add( + vale, + sls // + ); + } + else if (isBearish) + { + // + double higherPeak = triggerCycleHelper.mX121Helper.xpvHelper.GetHigherPeak(peak); + if (higherPeak > 0) + { + // + Add( + higherPeak, + sls // + ); + } + + // + Add( + peak, + sls // + ); + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - atr + : slsMax + atr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + target = 0; + + // + } + + // + // Ignore Target ... + target = 0; + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +// +int AddX121SMCXTWPVConditionsIfNotExists( + X121SMCStrategyXTWPVSignalConditions &item, + X121SMCStrategyXTWPVSignalConditions &items[] // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + bool canAdd = !IsValidSize(count); + if (!canAdd) + { + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) { + // + X121SMCStrategyXTWPVSignalConditions iItem = items[i]; + + // + if (iItem.dir != item.dir) { + continue; + } + + // + bool isIBullish = IsBullish(iItem); + if (isIBullish) { + // + int iCount = ArraySize(iItem.bullishOrderBlocks); + for (int j = 0; j < iCount; j++) { + // + XFVGOrderBlock jFO = iItem.bullishOrderBlocks[j]; + + } + } else { + + } + } + } + + // + if (canAdd) + { + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + } + + // + result = ArraySize(items); + + // + return result; +} + +// +// Draw Signal ... +int DrawX121SMCXTWPVSiganl( + X121SMCStrategyXTWPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.dir); + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.signal.lib.mq5 new file mode 100644 index 0000000..ba1637d --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-121.smc.xtwpv.old.signal.lib.mq5 @@ -0,0 +1,2060 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +const string X121SMCXTWPV_Method_1_Token = "X121SMCXTWPV_1"; +const string X121SMCXTWPV_Method_2_Token = "X121SMCXTWPV_2"; +const string X121SMCXTWPV_Method_3_Token = "X121SMCXTWPV_3"; + +// +enum ENUM_X_X121SMC_XTWPV_METHODS +{ + X_X121SMC_XTWPV_METHOD_UNKNOWN, + X_X121SMC_XTWPV_METHOD_1, + X_X121SMC_XTWPV_METHOD_2, + X_X121SMC_XTWPV_METHOD_3, +}; + +// +string ToString(ENUM_X_X121SMC_XTWPV_METHODS value) +{ + // + string result = NULL; + + // + if (value == X_X121SMC_XTWPV_METHOD_UNKNOWN) + { + return result; + } + + // + switch (value) + { + // + case X_X121SMC_XTWPV_METHOD_1: + result = "Method_1"; + break; + + // + case X_X121SMC_XTWPV_METHOD_2: + result = "Method_2"; + break; + } + + // + return result; +} + +// +ENUM_X_X121SMC_XTWPV_METHODS ParseMethod(string value) +{ + // + ENUM_X_X121SMC_XTWPV_METHODS result = X_X121SMC_XTWPV_METHOD_UNKNOWN; + + // + if (!IsValid(value)) + { + return result; + } + + // + if (Contains(X121SMCXTWPV_Method_1_Token, value)) + { + result = X_X121SMC_XTWPV_METHOD_1; + } + else if (Contains(X121SMCXTWPV_Method_2_Token, value)) + { + result = X_X121SMC_XTWPV_METHOD_2; + } + + // + return result; +} + +// +// Definitions ... +struct X121SMCStrategyXTWPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double point; + XPVPivot pivot; + + // + XConsolidationZone consolidationZone; + + // + string method; + + // + bool hasSupportZone; + bool hasResistanceZone; + bool hasSupplyZone; + bool hasDemandZone; + bool hasOrderBlock; + bool hasFairValueGap; + XCSupportZone *supportZone; + XCResistanceZone *resistanceZone; + XCSupplyZone *supplyZone; + XCDemandZone *demandZone; + XCOrderBlock *orderBlock; + XCFVG *fairValueGap; + + // + // Constructor ... + X121SMCStrategyXTWPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + point = 0; + pivot.Clean(); + consolidationZone.Clean(); + + // + method = NULL; + + // + CleanPriceInsideZones(); + } + + /** + * Clean Price Insie Zones ... + */ + void CleanPriceInsideZones() + { + // + hasSupportZone = false; + hasResistanceZone = false; + hasSupplyZone = false; + hasDemandZone = false; + hasOrderBlock = false; + hasFairValueGap = false; + + // + supportZone = NULL; + resistanceZone = NULL; + supplyZone = NULL; + demandZone = NULL; + orderBlock = NULL; + fairValueGap = NULL; + } + + /** + * Count Price Inside Zones ... + * + * @return ( int ) + */ + int CountPriceInsideZones() + { + // + int result = 0; + + // + if (hasSupportZone) + { + result++; + } + + // + if (hasResistanceZone) + { + result++; + } + + // + if (hasSupplyZone) + { + result++; + } + + // + if (hasDemandZone) + { + result++; + } + + // + if (hasOrderBlock) + { + result++; + } + + // + if (hasFairValueGap) + { + result++; + } + + // + return result; + } + + /** + * Check Conditions Has Price Inside Zones ... + * + * @return ( bool ) + */ + bool HasPriceInsideZones() + { + // + bool result = false; + + // + result = IsValidSize(CountPriceInsideZones()); + + // + return result; + } + + /** + * Check Conditions Has Bullish Price Inside Zone ... + * + * @return ( bool ) + */ + bool HasBullishPriceInsideZone() + { + // + bool result = false; + + // + result = + // + HasPriceInsideZones() && + // + (hasDemandZone || + hasSupportZone || + (hasOrderBlock && + orderBlock.IsBullish()) || + (hasFairValueGap && + fairValueGap.IsBullish())) + // + ; + + // + return result; + } + + /** + * Check Conditions Has Bearish Price Inside Zone ... + * + * @return ( bool ) + */ + bool HasBearishPriceInsideZone() + { + // + bool result = false; + + // + result = + // + HasPriceInsideZones() && + // + (hasSupplyZone || + hasResistanceZone || + (hasOrderBlock && + orderBlock.IsBearish()) || + (hasFairValueGap && + fairValueGap.IsBearish())) + // + ; + + // + return result; + } + + /** + * Check has Vald Pivot or not ... + * + * @return ( bool ) + */ + bool HasPivot() + { + return pivot.IsValid(); + } + + /** + * Check Model Has Consolidation Zone or not ... + * + * @return ( bool ) + */ + bool HasConsolidationZone() + { + return consolidationZone.IsValid(); + } + + // +}; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXTWPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Setup Conditions ... + + // + XMarketStructure consolidationMarketStructure; + bool hasConsolidationMarketStructure = + consolidationCycleHelper + .DetectMarketStructure(consolidationMarketStructure); + + // + XMarketStructure analyseMarketStructure; + bool hasAnalyseMarketStructure = + analyseCycleHelper + .DetectMarketStructure(analyseMarketStructure); + + // + // Check Same Bias ... + result = + hasAnalyseMarketStructure && + hasConsolidationMarketStructure && + analyseMarketStructure.HasTrend() && + consolidationMarketStructure.HasTrend() && + analyseMarketStructure.bias == consolidationMarketStructure.bias; + if (!result) + { + return result; + } + + // + XOHCL analyseCBar; + result = analyseCycleHelper.GetBar( + cBar, + analyseCBar // + ); + if (!result) + { + return result; + } + + // + XOHCL analysePBar; + result = analyseCBar.GetPreviousBar(analysePBar); + if (!result) + { + return result; + } + + // + double bullishFib = GetFibonacciLevel( + analyseCBar.high, + analyseCBar.low, + GetFiboLevelValue(X_FIBO_LEVEL_382), + -1 // + ); + + // + double bearishFib = GetFibonacciLevel( + analyseCBar.high, + analyseCBar.low, + GetFiboLevelValue(X_FIBO_LEVEL_382), + 1 // + ); + + // + // Detect Market Trend ... + // ENUM_X_DIRECTION trend; + // bool hasTrend = verificationCycleHelper + // .DetectTrend(trend); + // bool hasBullishTrend = hasTrend && + // IsBullish(trend); + // bool hasBearishTrend = hasTrend && + // IsBearish(trend); + // result = hasBullishTrend || + // hasBearishTrend; + // if (!result) + // { + // return result; + // } + + // + // Detect Trend Based On Peaks and Vales ... + ENUM_X_DIRECTION trend; + bool hasTrend = triggerCycleHelper + .HasPVDirection(trend); + bool hasBullishTrend = hasTrend && + IsBullish(trend); + bool hasBearishTrend = hasTrend && + IsBearish(trend); + + // + // Retrieve Active Pivots ... + + // + XPVPivot peakPivot; + bool hasPeakPivot = analyseCycleHelper + .GetActivePeakPivot(peakPivot); + + // + XPVPivot valePivot; + bool hasValePivot = analyseCycleHelper + .GetActiveValePivot(valePivot); + + // + // Check Pivot ... + bool hasPivot = conditions.HasPivot(); + if (!hasPivot) + { + // + if (hasPeakPivot && !hasValePivot) + { + conditions.pivot = peakPivot; + } + else if (hasValePivot && !hasPeakPivot) + { + conditions.pivot = valePivot; + } + else if (hasPeakPivot && hasValePivot) + { + // + if (peakPivot.from > valePivot.from) + { + conditions.pivot = peakPivot; + } + else if (valePivot.from > peakPivot.from) + { + conditions.pivot = valePivot; + } + } + + // + hasPivot = conditions.HasPivot(); + result = hasPivot; + if (!result) + { + return result; + } + } + + // + // Update Pivot States ... + if (hasPivot) + { + // + conditions.pivot.to = cTime; + analyseCycleHelper.FillPivotState(conditions.pivot); + + // + // Check Pivot Renewation ... + bool hasNewPivot = + // + (hasPeakPivot && + peakPivot.from > conditions.pivot.from) || + (hasValePivot && + valePivot.from > conditions.pivot.from) + // + ; + result = !hasNewPivot; + if (!result) + { + // + conditions.pivot.Clean(); + return result; + } + } + + // + // XOHCL Conditions ... + + // + // Fibo Pressure ... + ENUM_X_DIRECTION pBarFiboPressureDir; + bool pBarHasFiboPressure = triggerCycleHelper + .mBarAnalyser + .HasFiboPressure( + pBar, + pBarFiboPressureDir // + ); + bool isPBarHasBullishFiboPressure = + pBarHasFiboPressure && + IsBullish(pBarFiboPressureDir); + bool isPBarHasBearishFiboPressure = + pBarHasFiboPressure && + IsBearish(pBarFiboPressureDir); + + // + // Rejection ... + ENUM_X_DIRECTION pBarRejectionDir; + bool isPBarRejected = triggerCycleHelper + .mBarAnalyser + .IsRejectionBar( + pBar, + pBarRejectionDir, + 0 // + ); + bool isPBarBullishRejected = + isPBarRejected && + IsBullish(pBarRejectionDir); + bool isPBarBearishRejected = + isPBarRejected && + IsBearish(pBarRejectionDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentumBar = triggerCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // + ); + bool isCBarBullishMomentumBar = + isCBarMomentumBar && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentumBar = + isCBarMomentumBar && + IsBearish(cBarMomentumDir); + + // + // Engulfing ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = triggerCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Helper cBar Conditions ... + bool isBearishFiboPassed = bullishFib <= conditions.pivot.lower; + bool isBullishFiboPassed = bearishFib >= conditions.pivot.upper; + + // + // Detect a Zone Which Price Inside it ... + // Helper (Optional) ... + conditions.CleanPriceInsideZones(); + bool hasPriceInsideZones = conditions.HasPriceInsideZones(); + int priceInsideZonesCount = conditions.CountPriceInsideZones(); + if (!hasPriceInsideZones) + { + // + hasPriceInsideZones = DetectPriceInsideZones( + verificationState, + cBar, + priceInsideZonesCount, + conditions.hasSupportZone, + conditions.supportZone, + conditions.hasResistanceZone, + conditions.resistanceZone, + conditions.hasSupplyZone, + conditions.supplyZone, + conditions.hasDemandZone, + conditions.demandZone, + conditions.hasOrderBlock, + conditions.orderBlock, + conditions.hasFairValueGap, + conditions.fairValueGap // + ); + + // + priceInsideZonesCount = conditions.CountPriceInsideZones(); + } + + // + // Check Price Inside Consolidation Zone ... + XConsolidationZone cZone; + bool hasConsolidationZone = conditions + .HasConsolidationZone(); + if (!hasConsolidationZone) + { + // + hasConsolidationZone = triggerCycleHelper + .GetLastConsolidationZone(cZone); + // + if (!hasConsolidationZone) + { + // + XConsolidationZone cZones[]; + int count = triggerCycleHelper + .FillConsolidationZones(cZones); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XConsolidationZone iZone = cZones[i]; + + // + XCZone *iCZone; + bool isInited = ToZone(iZone, iCZone); + if (!isInited) + { + continue; + } + + // + bool isValid = IsPriceInsideZone( + cBar, + iCZone // + ); + if (isValid) + { + cZone = iZone; + } + } + } + + // + conditions.consolidationZone = cZone; + hasConsolidationZone = conditions + .HasConsolidationZone(); + } + } + if (hasConsolidationZone) + { + conditions.consolidationZone = cZone; + } + + // + // PV Conditions ... + + // + double analysePeak = analyseConditions.x121Conditions.peaksBuffer[1]; + double analysePeakPrev = analyseConditions.x121Conditions.peaksBuffer[2]; + double analysePeakDiff = MathAbs(analysePeakPrev - analysePeak); + + // + bool isNewAnalysePeak = analyseConditions.x121Conditions.isNewPeak; + bool isNewAnalysePeakOverLast = analyseConditions.x121Conditions.isNewPeakOverLast; + bool isNewAnalysePeakUnderLast = analyseConditions.x121Conditions.isNewPeakUnderLast; + + // + double analyseVale = analyseConditions.x121Conditions.valesBuffer[1]; + double analyseValePrev = analyseConditions.x121Conditions.valesBuffer[2]; + double analyseValeDiff = MathAbs(analyseValePrev - analyseVale); + + // + bool isNewAnalyseVale = analyseConditions.x121Conditions.isNewVale; + bool isNewAnalyseValeOverLast = analyseConditions.x121Conditions.isNewValeOverLast; + bool isNewAnalyseValeUnderLast = analyseConditions.x121Conditions.isNewValeUnderLast; + + // + double triggerPeak = triggerConditions.x121Conditions.peaksBuffer[1]; + double triggerVale = triggerConditions.x121Conditions.valesBuffer[1]; + + // + bool isNewTriggerPeak = triggerConditions.x121Conditions.isNewPeak; + bool isNewTriggerPeakOverLast = triggerConditions.x121Conditions.isNewPeakOverLast; + bool isNewTriggerPeakUnderLast = triggerConditions.x121Conditions.isNewPeakUnderLast; + + // + bool isNewTriggerVale = triggerConditions.x121Conditions.isNewVale; + bool isNewTriggerValeOverLast = triggerConditions.x121Conditions.isNewValeOverLast; + bool isNewTriggerValeUnderLast = triggerConditions.x121Conditions.isNewValeUnderLast; + + // + int condition2MinPVDiffPoint = 30; + bool isAnalysePeakDiffPointPassed = analysePeakDiff >= (condition2MinPVDiffPoint * points); + bool isAnalyseValeDiffPointPassed = analyseValeDiff >= (condition2MinPVDiffPoint * points); + + // + // DONCHAIN Conditions ... + + // + double analyseDonOpenUpper = analyseConditions.x121Conditions.donOpenUpperBuffer[1]; + double analyseDonOpenLower = analyseConditions.x121Conditions.donOpenLowerBuffer[1]; + + // + double analyseDonHighUpper = analyseConditions.x121Conditions.donHighUpperBuffer[1]; + double analyseDonHighLower = analyseConditions.x121Conditions.donHighLowerBuffer[1]; + + // + double analyseDonCloseUpper = analyseConditions.x121Conditions.donCloseUpperBuffer[1]; + double analyseDonCloseLower = analyseConditions.x121Conditions.donCloseLowerBuffer[1]; + + // + double analyseDonLowUpper = analyseConditions.x121Conditions.donLowUpperBuffer[1]; + double analyseDonLowLower = analyseConditions.x121Conditions.donLowLowerBuffer[1]; + + // + // OPEN ... + double triggerDonOpenUpper = triggerConditions.x121Conditions.donOpenUpperBuffer[1]; + double triggerDonOpenLower = triggerConditions.x121Conditions.donOpenLowerBuffer[1]; + double triggerDonOpenUpperPrev = triggerConditions.x121Conditions.donOpenUpperBuffer[2]; + double triggerDonOpenLowerPrev = triggerConditions.x121Conditions.donOpenLowerBuffer[2]; + + // + // HIGH ... + double triggerDonHighUpper = triggerConditions.x121Conditions.donHighUpperBuffer[1]; + double triggerDonHighLower = triggerConditions.x121Conditions.donHighLowerBuffer[1]; + double triggerDonHighUpperPrev = triggerConditions.x121Conditions.donHighUpperBuffer[2]; + double triggerDonHighLowerPrev = triggerConditions.x121Conditions.donHighLowerBuffer[2]; + + // + // CLOSE ... + double triggerDonCloseUpper = triggerConditions.x121Conditions.donCloseUpperBuffer[1]; + double triggerDonCloseLower = triggerConditions.x121Conditions.donCloseLowerBuffer[1]; + double triggerDonCloseUpperPrev = triggerConditions.x121Conditions.donCloseUpperBuffer[2]; + double triggerDonCloseLowerPrev = triggerConditions.x121Conditions.donCloseLowerBuffer[2]; + + // + // LOW ... + double triggerDonLowUpper = triggerConditions.x121Conditions.donLowUpperBuffer[1]; + double triggerDonLowLower = triggerConditions.x121Conditions.donLowLowerBuffer[1]; + double triggerDonLowUpperPrev = triggerConditions.x121Conditions.donLowUpperBuffer[2]; + double triggerDonLowLowerPrev = triggerConditions.x121Conditions.donLowLowerBuffer[2]; + + // + double triggerAtr = triggerConditions.x121Conditions.atrBuffer[1]; + double triggerUpperAtr = triggerConditions.x121Conditions.atrUpperBuffer[1]; + double triggerLowerAtr = triggerConditions.x121Conditions.atrLowerBuffer[1]; + + // + bool isNewTriggerPeakOverAtrUpper = + // + isNewTriggerPeak && + triggerPeak > triggerUpperAtr + // + ; + + // + bool isNewTriggerValeUnderAtrLower = + // + isNewTriggerVale && + triggerVale < triggerLowerAtr + // + ; + + // + if (isNewTriggerPeakOverAtrUpper || + isNewTriggerValeUnderAtrLower) + { + Print("ATR Break ..."); + } + + // + // Method 1 ... + + // + // Bullish Conditions 1 ... + bool bullishConditions1 = + // + false && + hasBullishTrend && + isBullishFiboPassed && + hasConsolidationZone && + analyseCBar.IsBullish() && + isNewAnalysePeakOverLast && + conditions.pivot.upper < analysePeak && + conditions.pivot.upper < analyseCBar.GetUp() && + conditions.pivot.upper > analyseCBar.GetDown() + // + ; + if (bullishConditions1) + { + // + conditions.point = conditions.pivot.upper; + conditions.method = ToString(X_X121SMC_XTWPV_METHOD_1); + } + + // + // Bearish Conditions 1 ... + bool bearishConditions1 = + // + false && + hasBearishTrend && + isBearishFiboPassed && + hasConsolidationZone && + analyseCBar.IsBearish() && + isNewAnalyseValeUnderLast && + conditions.pivot.lower > analyseVale && + conditions.pivot.lower < analyseCBar.GetUp() && + conditions.pivot.lower > analyseCBar.GetDown() + // + ; + if (bearishConditions1) + { + // + conditions.point = conditions.pivot.lower; + conditions.method = ToString(X_X121SMC_XTWPV_METHOD_1); + } + + // + // Method 2 ... + + // + // Bullish Conditions 2 ... + bool bullishConditions2 = + // + false && + hasBullishTrend && + isNewAnalyseValeOverLast && + isAnalyseValeDiffPointPassed && + analyseDonCloseLower > analyseVale + // + ; + if (bullishConditions2) + { + // + conditions.point = analyseVale; + conditions.method = ToString(X_X121SMC_XTWPV_METHOD_2); + } + + // + // Bearish Conditions 2 ... + bool bearishConditions2 = + // + false && + hasBearishTrend && + isNewAnalysePeakUnderLast && + isAnalysePeakDiffPointPassed && + analyseDonCloseUpper > analysePeak + // + ; + if (bearishConditions2) + { + // + conditions.point = analysePeak; + conditions.method = ToString(X_X121SMC_XTWPV_METHOD_2); + } + + // + // Method 3 ... + + // + // Bullish Conditions 3 ... + bool bullishConditions3 = + // + false + // + ; + if (bullishConditions3) + { + // + conditions.point = analyseVale; + conditions.method = ToString(X_X121SMC_XTWPV_METHOD_3); + } + + // + // Bearish Conditions 3 ... + bool bearishConditions3 = + // + false + // + ; + if (bearishConditions3) + { + // + conditions.point = analysePeak; + conditions.method = ToString(X_X121SMC_XTWPV_METHOD_3); + } + + // + // Summary Conditions ... + + // + isBullish = + // + bullishConditions1 || + bullishConditions2 || + bullishConditions3 + // + ; + + // + isBearish = + // + bearishConditions1 || + bearishConditions2 || + bearishConditions3 + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXTWPVSiganlTrigger( + // + X121SMCStrategyXTWPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Trigger Conditions ... + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + XPVPivotPoint pivotPoints[]; + XPVPivotPoint nearestPivotPoint; + bool hasNearestPivotPoint = false; + int pivotPointsCount = triggerCycleHelper + .FillPivotPoints(pivotPoints); + if (IsValidSize(pivotPointsCount)) + { + // + for (int i = 0; i < pivotPointsCount; i++) + { + // + XPVPivotPoint iPoint = pivotPoints[i]; + + // + bool canSet = + (isBullish + ? iPoint.value < conditions.point + : iPoint.value > conditions.point) + // + && + // + (!nearestPivotPoint.IsValid() + ? true + : isBullish + ? nearestPivotPoint.value > iPoint.value + : nearestPivotPoint.value < iPoint.value); + if (canSet) + { + nearestPivotPoint = iPoint; + } + } + + // + hasNearestPivotPoint = nearestPivotPoint.IsValid(); + } + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + + // + double oppositTarget = CalculateTarget( + cBar, + analyseState, + Opposit(setupDir) // + ); + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double atr = triggerConditions.x121Conditions.atrBuffer[1]; + + // + double sls[]; + + // + bool hasConsolidationZone = conditions.HasConsolidationZone(); + if (hasConsolidationZone) + { + // + if (isBullish) + { + Add( + conditions.consolidationZone.lower, + sls // + ); + } + else + { + Add( + conditions.consolidationZone.upper, + sls // + ); + } + } + if (hasNearestPivotPoint) + { + Add( + nearestPivotPoint.value, + sls // + ); + } + if (ArraySize(sls) == 0) + { + // + double pointsDiff = (10 * points); + double pointsPlus = conditions.point + pointsDiff; + double pointsMinus = conditions.point - pointsDiff; + + // + // Force SL ... + Add( + conditions.point, + sls // + ); + + // + Add( + pointsPlus, + sls // + ); + + // + Add( + pointsMinus, + sls // + ); + + // + Add( + oppositTarget, + sls // + ); + } + + // + bool hasPriceInsideZones = conditions.HasPriceInsideZones(); + bool hasBullishPriceInsideZone = conditions.HasBullishPriceInsideZone(); + bool hasBearishPriceInsideZone = conditions.HasBearishPriceInsideZone(); + + // + if ( + isBullish && + hasPriceInsideZones && + hasBullishPriceInsideZone // + ) + { + // + // Demand ... + if (conditions.hasDemandZone) + { + // + Add( + conditions.demandZone.Lower(), + sls // + ); + } + + // + // Support ... + if (conditions.hasSupportZone) + { + // + Add( + conditions.supportZone.Lower(), + sls // + ); + } + + // + // Order Block ... + if (conditions.hasOrderBlock) + { + // + Add( + conditions.orderBlock.Lower(), + sls // + ); + } + + // + // Fair Value Gap ... + if (conditions.hasFairValueGap) + { + // + Add( + conditions.fairValueGap.Lower(), + sls // + ); + } + } + + // + if ( + isBearish && + hasPriceInsideZones && + hasBearishPriceInsideZone // + ) + { + // + // Supply ... + if (conditions.hasSupplyZone) + { + // + Add( + conditions.supplyZone.Upper(), + sls // + ); + } + + // + // Resistance ... + if (conditions.hasResistanceZone) + { + // + Add( + conditions.resistanceZone.Upper(), + sls // + ); + } + + // + // Order Block ... + if (conditions.hasOrderBlock) + { + // + Add( + conditions.orderBlock.Upper(), + sls // + ); + } + + // + // Fair Value Gap ... + if (conditions.hasFairValueGap) + { + // + Add( + conditions.fairValueGap.Upper(), + sls // + ); + } + } + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - atr + : slsMax + atr; + double risk = MathAbs(entry - sl); + double targetDelta = 2 * (risk / 3); + if (target == 0) + { + // + int minTargetPint = 50; + double minTargetPointValue = minTargetPint * points; + if (targetDelta < minTargetPointValue) + { + targetDelta = minTargetPointValue; + } + + // + // Force Target On Half Risk ... + target = + isBullish + ? entry + targetDelta + : entry - targetDelta; + + // + } + + // + conditions.sl = sl; + conditions.target = 0; // target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; +} + +/** + * Draw Conditions Pivot Zone ... + * + * @param conditions: X121SMCStrategyXTWPVSignalConditions instance Reference ... + * @param drawer: XCPOIDrawer pointer ... + * @param drawnObjects: XCBaseObject instance Reference Collection ... + * @param drawState: Boolean ... + * @param drawTicksZone: Boolean ... + * @param ignoreSwingHighs: Boolean ... + * @param ignoreSwingLows: Boolean ... + * @param ignoreSupportZones: Boolean ... + * @param ignoreResistanceZones: Boolean ... + * @param ignoreSupplyZones: Boolean ... + * @param ignoreDemandZones: Boolean ... + * @param ignoreBullishOrderBlocks: Boolean ... + * @param ignoreBearishOrderBlocks: Boolean ... + * @param ignoreBullishFairValueGaps: Boolean ... + * @param ignoreBearishFairValueGaps: Boolean ... + * @param ignoreBullishRejectionBars: Boolean ... + * @param ignoreBearishRejectionBars: Boolean ... + * @param ignoreBullishMomentumBars: Boolean ... + * @param ignoreBearishMomentumBars: Boolean ... + * + * @return ( int ) + */ +int DrawXTWPVPivotZone( + X121SMCStrategyXTWPVSignalConditions &conditions, + XCPOIDrawer *drawer, + XCBaseObject *&drawnObjects[], + bool drawState = false, + bool drawTicksZone = false, + bool ignoreSwingHighs = false, + bool ignoreSwingLows = false, + bool ignoreSupportZones = false, + bool ignoreResistanceZones = false, + bool ignoreSupplyZones = false, + bool ignoreDemandZones = false, + bool ignoreBullishOrderBlocks = false, + bool ignoreBearishOrderBlocks = false, + bool ignoreBullishFairValueGaps = false, + bool ignoreBearishFairValueGaps = false, + bool ignoreBullishRejectionBars = false, + bool ignoreBearishRejectionBars = false, + bool ignoreBullishMomentumBars = false, + bool ignoreBearishMomentumBars = false // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL || + !conditions.HasPivot()) + { + return result; + } + + // + drawer.DrawPivot( + // + conditions.pivot, + drawnObjects, + // + drawState, + drawTicksZone, + ignoreSwingHighs, + ignoreSwingLows, + ignoreSupportZones, + ignoreResistanceZones, + ignoreSupplyZones, + ignoreDemandZones, + ignoreBullishOrderBlocks, + ignoreBearishOrderBlocks, + ignoreBullishFairValueGaps, + ignoreBearishFairValueGaps, + ignoreBullishRejectionBars, + ignoreBearishRejectionBars, + ignoreBullishMomentumBars, + ignoreBearishMomentumBars // + ); + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +/** + * Drw Conditions Price Inside Zones ... + * + * @param conditions: X121SMCStrategyXTWPVSignalConditions instance Reference ... + * @param drawer: XCPOIDrawer pointer ... + * @param drawnObjects: XCBaseObject instance Reference Collection ... + * + * @return ( int ) + */ +int DrawTWPVPriceInsideZones( + X121SMCStrategyXTWPVSignalConditions &conditions, + XCPOIDrawer *drawer, + XCBaseObject *&drawnObjects[] // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if ( + drawer == NULL || + !conditions.HasPriceInsideZones()) + { + return result; + } + + // + // Support ... + if (conditions.hasSupportZone) + { + // + XCSupportZoneObject *iObj; + bool isCreated = drawer.CreateSupportZone( + conditions.supportZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // Resistance ... + if (conditions.hasResistanceZone) + { + // + XCResistanceZoneObject *iObj; + bool isCreated = drawer.CreateResistanceZone( + conditions.resistanceZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // Supply ... + if (conditions.hasSupplyZone) + { + // + XCSupplyZoneObject *iObj; + bool isCreated = drawer.CreateSupplyZone( + conditions.supplyZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // Demand ... + if (conditions.hasDemandZone) + { + // + XCDemandZoneObject *iObj; + bool isCreated = drawer.CreateDemandZone( + conditions.demandZone, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + + // + // Order Block ... + if (conditions.hasOrderBlock) + { + // + bool isBullish = conditions.orderBlock.IsBullish(); + if (isBullish) + { + // + XCBullishOrderBlockObject *iObj; + bool isCreated = drawer.CreateBullishOrderBlock( + conditions.orderBlock, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + else + { + // + XCBearishOrderBlockObject *iObj; + bool isCreated = drawer.CreateBearishOrderBlock( + conditions.orderBlock, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + // FairValueGap ... + if (conditions.hasFairValueGap) + { + // + bool isBullish = conditions.fairValueGap.IsBullish(); + if (isBullish) + { + // + XCBullishFairValueGapObject *iObj; + bool isCreated = drawer.CreateBullishFairValueGap( + conditions.fairValueGap, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + else + { + // + XCBearishFairValueGapObject *iObj; + bool isCreated = drawer.CreateBearishFairValueGap( + conditions.fairValueGap, + iObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObj, + drawnObjects // + ); + } + } + } + + // + result = ArraySize(drawnObjects); + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.helper.mq5 b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.helper.mq5 new file mode 100644 index 0000000..e2bb055 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.helper.mq5 @@ -0,0 +1,4636 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121Helper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... +enum ENUM_X121_BUFFERS +{ + // + // Main Buffers ... + X121_PEAKS_LINE = 0, + X121_VALES_LINE = 1, + X121_SAR_LINE = 2, + X121_ATR_UPPER_LINE = 3, + X121_ATR_LOWER_LINE = 4, + X121_STR_LOWER_LINE = 5, + X121_VWAP_FAST_LINE = 7, + X121_VWAP_MID_LINE = 9, + X121_VWAP_SLOW_LINE = 11, + X121_DON_OPEN_UPPER_LINE = 13, + X121_DON_OPEN_LOWER_LINE = 14, + X121_DON_HIGH_UPPER_LINE = 15, + X121_DON_HIGH_LOWER_LINE = 16, + X121_DON_LOW_UPPER_LINE = 17, + X121_DON_LOW_LOWER_LINE = 18, + X121_DON_CLOSE_UPPER_LINE = 19, + X121_DON_CLOSE_LOWER_LINE = 20, + // + // Data Buffers ... + // + // XPV Data ... + X121_CURRENT_HH_LINE = 21, + X121_CURRENT_LL_LINE = 22, + X121_SHORT_HH_LINE = 23, + X121_SHORT_LL_LINE = 24, + X121_MEDIUM_HH_LINE = 25, + X121_MEDIUM_LL_LINE = 26, + X121_LONG_HH_LINE = 27, + X121_LONG_LL_LINE = 28, + X121_HIND_HH_LINE = 29, + X121_HIND_LL_LINE = 30, + // + // VWAP Data ... + X121_VWAP_VOLUME_LINE = 31, + X121_VWAP_PRICE_LINE = 32, + X121_VWAP_FAST_STATE_LINE = 33, + X121_VWAP_MID_STATE_LINE = 34, + X121_VWAP_SLOW_STATE_LINE = 35, + // + // ATR ... + X121_ATR_LINE = 36, + X121_ATR_UPPER_RAW_LINE = 37, + X121_ATR_LOWER_RAW_LINE = 38, + // + // RSI ... + X121_RSI_LINE = 39, + // + // STR ... + X121_STR_PRICE_LINE = 40, + X121_STR_UP_LINE = 41, + X121_STR_DOWN_LINE = 42, + X121_STR_STATE_LINE = 43, +}; + +// +enum ENUM_XVWAP_STATES +{ + // + XVWAP_STATE_BULLISH = 1, + XVWAP_STATE_BEARISH = 2, + XVWAP_STATE_NEUTURAL = 3, +}; + +// +// Inputs ... +struct X121Inputs +{ + // + // Props ... + + // + // Cycles ... + + // + // Short ... + ENUM_X_PERIOD_METHOD scMethod; // How to Find Period + ENUM_TIMEFRAMES scPeriod; // Time Period + + // + // Medium ... + ENUM_X_PERIOD_METHOD mcMethod; // How to Find Period + ENUM_TIMEFRAMES mcPeriod; // Time Period + + // + // Long ... + ENUM_X_PERIOD_METHOD lcMethod; // How to Find Period + ENUM_TIMEFRAMES lcPeriod; // Time Period + + // + // Hind ... + ENUM_X_PERIOD_METHOD hcMethod; // How to Find Period + ENUM_TIMEFRAMES hcPeriod; // Time Period + + // + // Boundary Detection ... + ENUM_SERIESMODE hhMode; // Highest High Calculation Method + ENUM_SERIESMODE llMode; // Lowest Low Calculation Method + + // + // Parabolic Sar Detection ... + double sarStep; // Step + double sarMax; // Maximum + + // + // RSI ... + int rsiLength; // Length + double rsiOverSoldLevel; // Over Sold Level + double rsiOverBoughtLevel; // Over Bought Level + ENUM_APPLIED_PRICE rsiAppliedTo; // Applied To + + // + // Atr Detection ... + int atrLength; // Length + double atrMultiplier; // Multiplier + ENUM_APPLIED_PRICE atrUpperAppliedTo; // Upper Zone Applied To + ENUM_APPLIED_PRICE atrLowerAppliedTo; // Lower Zone Applied To + ENUM_X_MA_METHOD atrSmoothingMode; // Smoothing Method + + // + // Str Detection ... + ENUM_APPLIED_PRICE strAppliedTo; // Applied To + + // + // VWap Detection ... + int vwapFastLength; // Fast Length + int vwapMidLength; // Mid Length + int vwapSlowLength; // Slow Length + ENUM_APPLIED_PRICE vwapAppliedTo; // Applied To + + // + // Donchain Detection ... + int donchainLength; // Donchain Length + + // + // Presentation ... + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + int sarArrowCode; // Parabolic Sar Arrow Code + int peaksArrowCode; // Peaks Arrow Code + int valesArrowCode; // Vales Arrow Code + + // + // Global ... + bool showSar; // Show Parabolic Sar + bool showAtr; // Show Atr + bool showStr; // Show Str + bool showPeaks; // Show Peaks + bool showVales; // Show Vales + bool showVWap; // Show VWap + bool showDonchain; // Show Donchain + + // + // Atr Presentation ... + bool showAtrUpper; // Show Upper Zone + bool showAtrLower; // Show Lower Zone + + // + // VWap Presentation ... + bool showVWapFast; // Show VWap Fast + bool showVWapMedium; // Show VWap Medium + bool showVWapSlow; // Show VWap Slow + + // + // Donchain Presentation ... + + // + bool showUpper; // Show Upper Band + bool showLower; // Show Lower Band + + // + bool showOpen; // Show Open + bool showHigh; // Show High + bool showClose; // Show Close + bool showLow; // Show Low + + // + // Constructor ... + X121Inputs() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Cycles ... + + // + // Short ... + scMethod = X_PERIOD_NOTHING; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_NOTHING; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_NOTHING; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_NOTHING; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + + // + // RSI ... + rsiLength = 0; + rsiOverSoldLevel = 0; + rsiOverBoughtLevel = 0; + rsiAppliedTo = PRICE_CLOSE; + + // + // Paraboli Sar Detection ... + sarStep = 0; + sarMax = 0; + + // + // Atr Detection ... + atrLength = 0; // Length + atrMultiplier = 0; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_NONE; // Smoothing Method + + // + // Str Detection ... + strAppliedTo = PRICE_MEDIAN; + + // + // VWap Detection ... + vwapFastLength = 0; + vwapMidLength = 0; + vwapSlowLength = 0; + vwapAppliedTo = PRICE_CLOSE; + + // + // Donchain Detection ... + donchainLength = 0; + + // + // Presentation ... + + // + startCalculationForLastBars = 0; + + // + sarArrowCode = 0; + peaksArrowCode = 0; + valesArrowCode = 0; + + // + // Globals ... + showSar = false; + showAtr = false; + showStr = false; + showPeaks = false; + showVales = false; + showVWap = false; + showDonchain = false; + + // + // Atr Presentation ... + showAtrUpper = false; // Show Upper Zone + showAtrLower = false; // Show Lower Zone + + // + // VWap Presentation ... + showVWapFast = false; + showVWapMedium = false; + showVWapSlow = false; + + // + // Donchain Presentation ... + + // + showUpper = false; + showLower = false; + + // + showOpen = false; + showHigh = false; + showClose = false; + showLow = false; + } + + /** + * Set Default Values ... + */ + void Default() + { + // + // Cycles ... + + // + // Short ... + scMethod = X_PERIOD_AUTO; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_AUTO; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_AUTO; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_AUTO; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + + // + // RSI ... + rsiLength = 14; + rsiOverSoldLevel = 30; + rsiOverBoughtLevel = 70; + rsiAppliedTo = PRICE_CLOSE; + + // + // Paraboli Sar Detection ... + sarStep = 0.02; + sarMax = 0.2; + + // + // Atr Detection ... + atrLength = 14; // Length + atrMultiplier = 1; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + + // + // Str Detection ... + strAppliedTo = PRICE_MEDIAN; + + // + // VWap Detection ... + vwapFastLength = 20; + vwapMidLength = 40; + vwapSlowLength = 60; + vwapAppliedTo = PRICE_CLOSE; + + // + // Donchain Detection ... + donchainLength = 40; + + // + // Presentation ... + + // + startCalculationForLastBars = 1500; + + // + sarArrowCode = 159; + peaksArrowCode = 159; + valesArrowCode = 159; + + // + // Globals ... + showSar = true; + showAtr = true; + showStr = true; + showPeaks = true; + showVales = true; + showVWap = false; + showDonchain = false; + + // + // Atr Presentation ... + showAtrUpper = true; // Show Upper Zone + showAtrLower = true; // Show Lower Zone + + // + // VWap Presentation ... + showVWapFast = true; + showVWapMedium = true; + showVWapSlow = true; + + // + // Donchain Presentation ... + + // + showUpper = true; + showLower = true; + + // + showOpen = true; + showHigh = false; + showClose = true; + showLow = false; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + // RSI ... + rsiLength > 0 && + rsiOverSoldLevel > 0 && + rsiOverBoughtLevel > 0 && + rsiOverSoldLevel < rsiOverBoughtLevel && + // PSAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 && + // + // XDON ... + donchainLength > 0 && + // + // VWAP ... + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; + } + + /** + * Extract Max Input Length ... + * + * @return ( int ) + */ + int Max() + { + // + int result = 0; + + // + // VWAP ... + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapMidLength); + + // + // ATR ... + result = MathMax(result, atrLength); + result = MathMax(result, rsiLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121Conditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double sarBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + double atrBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + double rsiBuffer[]; + double strBuffer[]; + double strStateBuffer[]; + + // + // Conditions ... + + // + // STR ... + + // + bool isStrBullish; + bool isStrSwitchedToBullish; + + // + bool isStrBearish; + bool isStrSwitchedToBearish; + + // + // XRSI ... + + // + bool isRSIOverBought; + bool isRSICrossedOverOverBought; + bool isRSICrossedUnderOverBought; + + // + bool isRSIOverSold; + bool isRSICrossedUnderOverSold; + bool isRSICrossedOverOverSold; + + // + // XSAR ... + + // + bool isSarBullish; + bool isSarBearish; + + // + bool isSarSwitchedToBullish; + bool isSarSwitchedToBearish; + + // + // XPV ... + + // + bool isNewPeak; + bool isNewPeakOverLast; + bool isNewPeakUnderLast; + + // + bool isNewVale; + bool isNewValeOverLast; + bool isNewValeUnderLast; + + // + // XVWAP ... + + // + bool isVWapFastBullish; + bool isVWapFastBearish; + bool isVWapFastNeutural; + + // + bool isVWapMidBullish; + bool isVWapMidBearish; + bool isVWapMidNeutural; + + // + bool isVWapSlowBullish; + bool isVWapSlowBearish; + bool isVWapSlowNeutural; + + // + bool isVWapFastOverMid; + bool isVWapMidOverSlow; + + // + bool isVWapFastUnderMid; + bool isVWapMidUnderSlow; + + // + bool isVWapBullishState; + bool isVWapBearishState; + bool isVWapNeuturalState; + + // + bool isVWapBullishOrdered; + bool isVWapBearishOrdered; + + // + bool isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered; + + // + bool isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState; + bool isVWapSwitchedToNeuturalState; + + // + // XDON ... + + // + // bool isCloseLower + + // + // Constructor ... + X121Conditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(sarBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(vwapFastBuffer); + Clean(vwapMidBuffer); + Clean(vwapSlowBuffer); + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + Clean(atrBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + Clean(vwapVolumeBuffer); + Clean(vwapPriceBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapMidStateBuffer); + Clean(vwapSlowStateBuffer); + Clean(rsiBuffer); + Clean(strBuffer); + Clean(strStateBuffer); + + // + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + + // + // Conditions ... + + // + // STR ... + + // + isStrBullish = false; + isStrSwitchedToBullish = false; + + // + isStrBearish = false; + isStrSwitchedToBearish = false; + + // + // XRSI ... + + // + isRSIOverBought = false; + isRSICrossedUnderOverBought = false; + isRSICrossedOverOverBought = false; + + // + isRSIOverSold = false; + isRSICrossedOverOverSold = false; + isRSICrossedUnderOverSold = false; + + // + // XSAR ... + + // + isSarBullish = false; + isSarBearish = false; + + // + isSarSwitchedToBullish = false; + isSarSwitchedToBearish = false; + + // + // XPV ... + + // + isNewPeak = false; + isNewPeakOverLast = false; + isNewPeakUnderLast = false; + + // + isNewVale = false; + isNewValeOverLast = false; + isNewValeUnderLast = false; + + // + // XVWAP ... + + // + isVWapFastBullish = false; + isVWapFastBearish = false; + isVWapFastNeutural = false; + + // + isVWapMidBullish = false; + isVWapMidBearish = false; + isVWapMidNeutural = false; + + // + isVWapSlowBullish = false; + isVWapSlowBearish = false; + isVWapSlowNeutural = false; + + // + isVWapFastOverMid = false; + isVWapMidOverSlow = false; + + // + isVWapFastUnderMid = false; + isVWapMidUnderSlow = false; + + // + isVWapBullishState = false; + isVWapBearishState = false; + isVWapNeuturalState = false; + + // + isVWapBullishOrdered = false; + isVWapBearishOrdered = false; + + // + isVWapSwitchedToBullishOrdered = false; + isVWapSwitchedToBearishOrdered = false; + + // + isVWapSwitchedToBullishState = false; + isVWapSwitchedToBearishState = false; + isVWapSwitchedToNeuturalState = false; + + // + // XDON ... + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + // TODO: Implement this if required ... + string conditionsStr = + // + // STR ... + ToString("isStrBullish", isStrBullish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBullish", isStrSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isStrBearish", isStrBearish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBearish", isStrSwitchedToBearish, ignoreFalseConditions, separator) + + // + // XSAR ... + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + + ToString("isSarBearish", isSarBearish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBullish", isSarSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBearish", isSarSwitchedToBearish, ignoreFalseConditions, separator) + + // + // XPV ... + ToString("isNewPeak", isNewPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverLast", isNewPeakOverLast, ignoreFalseConditions, separator) + + ToString("isNewPeakUnderLast", isNewPeakUnderLast, ignoreFalseConditions, separator) + + ToString("isNewVale", isNewVale, ignoreFalseConditions, separator) + + ToString("isNewValeOverLast", isNewValeOverLast, ignoreFalseConditions, separator) + + ToString("isNewValeUnderLast", isNewValeUnderLast, ignoreFalseConditions, separator) + + // + // RSI ... + ToString("isRSIOverBought", isRSIOverBought, ignoreFalseConditions, separator) + + ToString("isRSICrossedOverOverBought", isRSICrossedOverOverBought, ignoreFalseConditions, separator) + + ToString("isRSICrossedUnderOverBought", isRSICrossedUnderOverBought, ignoreFalseConditions, separator) + + ToString("isRSIOverSold", isRSIOverSold, ignoreFalseConditions, separator) + + ToString("isRSICrossedUnderOverSold", isRSICrossedUnderOverSold, ignoreFalseConditions, separator) + + ToString("isRSICrossedOverOverSold", isRSICrossedOverOverSold, ignoreFalseConditions, separator) + + // + // XVWAP ... + ToString("isVWapFastBullish", isVWapFastBullish, ignoreFalseConditions, separator) + + ToString("isVWapFastBearish", isVWapFastBearish, ignoreFalseConditions, separator) + + ToString("isVWapFastNeutural", isVWapFastNeutural, ignoreFalseConditions, separator) + + ToString("isVWapMidBullish", isVWapMidBullish, ignoreFalseConditions, separator) + + ToString("isVWapMidBearish", isVWapMidBearish, ignoreFalseConditions, separator) + + ToString("isVWapMidNeutural", isVWapMidNeutural, ignoreFalseConditions, separator) + + ToString("isVWapSlowBullish", isVWapSlowBullish, ignoreFalseConditions, separator) + + ToString("isVWapSlowBearish", isVWapSlowBearish, ignoreFalseConditions, separator) + + ToString("isVWapSlowNeutural", isVWapSlowNeutural, ignoreFalseConditions, separator) + + ToString("isVWapFastOverMid", isVWapFastOverMid, ignoreFalseConditions, separator) + + ToString("isVWapMidOverSlow", isVWapMidOverSlow, ignoreFalseConditions, separator) + + ToString("isVWapFastUnderMid", isVWapFastUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapMidUnderSlow", isVWapMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isVWapBullishState", isVWapBullishState, ignoreFalseConditions, separator) + + ToString("isVWapBearishState", isVWapBearishState, ignoreFalseConditions, separator) + + ToString("isVWapNeuturalState", isVWapNeuturalState, ignoreFalseConditions, separator) + + ToString("isVWapBullishOrdered", isVWapBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapBearishOrdered", isVWapBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishOrdered", isVWapSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishOrdered", isVWapSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishState", isVWapSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishState", isVWapSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToNeuturalState", isVWapSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Implementation ... + +class XCX121Helper : public XCBaseHelper +{ + // + public: + // + + // + // Constructors ... + XCX121Helper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121Helper() + { + } + + // + // Tools ... + + /** + * Initialize Indicator Helper ... + * + * @param symbol: String, Symbol ... + * @param period: ENUM_TIMEFRAMES member, Period ... + * @param inputs: X121Inputs instance, Indicator Inputs ... + * + * @return ( bool ) + */ + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121Inputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + // Validate Inputs ... + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + // Setting Arrays As Series ... + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121", + // + // Inputs ... + // + // Cycles ... + "", + // + // Short ... + "", + mInputs.scMethod, + mInputs.scPeriod, + // + // Medium ... + "", + mInputs.mcMethod, + mInputs.mcPeriod, + // + // Long ... + "", + mInputs.lcMethod, + mInputs.lcPeriod, + // + // Hind ... + "", + mInputs.hcMethod, + mInputs.hcPeriod, + // + // Boundary Detection ... + "", + mInputs.hhMode, + mInputs.llMode, + // + // Rsi Detection ... + "", + mInputs.rsiLength, + mInputs.rsiAppliedTo, + // + // Parabolic Sar Detection ... + "", + mInputs.sarStep, + mInputs.sarMax, + // + // Atr Detection ... + "", + mInputs.atrLength, + mInputs.atrMultiplier, + mInputs.atrUpperAppliedTo, + mInputs.atrLowerAppliedTo, + mInputs.atrSmoothingMode, + // + // VWap Detection ... + "", + mInputs.vwapFastLength, + mInputs.vwapMidLength, + mInputs.vwapSlowLength, + mInputs.vwapAppliedTo, + // + // Donchain Detection ... + "", + mInputs.donchainLength, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + mInputs.sarArrowCode, + mInputs.peaksArrowCode, + mInputs.valesArrowCode, + // + // Commons ... + mInputs.showSar, + mInputs.showAtr, + mInputs.showPeaks, + mInputs.showVales, + mInputs.showVWap, + mInputs.showDonchain, + // + // Atr Presentation ... + "", + mInputs.showAtrUpper, + mInputs.showAtrLower, + // + // VWap Presentation ... + "", + mInputs.showVWapFast, + mInputs.showVWapMedium, + mInputs.showVWapSlow, + // + // Donchain Presentation ... + "", + mInputs.showUpper, + mInputs.showLower, + mInputs.showOpen, + mInputs.showHigh, + mInputs.showClose, + mInputs.showLow + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Retrieve Current Indicator Configs ... + * + * @return ( Inputs ) + */ + X121Inputs GetInputs() + { + return mInputs; + } + + /** + * Set New Indicator Inputs ... + * + * @param inputs: X121Inputs instance, Indicator Inputs ... + * + * @return ( bool ) + */ + bool SetInputs( + X121Inputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Implement Value Getters ... + + // + // XRSI ... + + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(rsiBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return rsiBuffer[barIndex]; + } + + // + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rsiBuffer, + buffer, + forceClean + // + ); + } + + // + // SAR ... + + // + double GetSar( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sarBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sarBuffer[barIndex]; + } + + // + int CopySar( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sarBuffer, + buffer, + forceClean + // + ); + } + + // + // ATR ... + + // + // Common ... + + // + double GetAtr( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrBuffer[barIndex]; + } + + // + int CopyAtr( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperBuffer[barIndex]; + } + + // + int CopyAtrUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrUpperRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperRawBuffer[barIndex]; + } + + // + int CopyAtrUpperRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperRawBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerBuffer[barIndex]; + } + + // + int CopyAtrLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrLowerRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerRawBuffer[barIndex]; + } + + // + int CopyAtrLowerRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerRawBuffer, + buffer, + forceClean + // + ); + } + + // + // PV ... + + // + // PEAKS ... + + // + double GetPeak( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(peaksBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return peaksBuffer[barIndex]; + } + + // + int CopyPeak( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + peaksBuffer, + buffer, + forceClean + // + ); + } + + // + // VALES ... + + // + double GetVale( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(valesBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return valesBuffer[barIndex]; + } + + // + int CopyVale( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + valesBuffer, + buffer, + forceClean + // + ); + } + + // + // + // + + // + double GetHigherPeak( + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(index); + if (iValue > peak) + { + // + result = iValue; + break; + } + + // + canContinue = index < barIndex + loopback; + index++; + } + + // + return result; + } + + // + double GetLowerPeak( + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(index); + if (iValue < peak) + { + // + result = iValue; + break; + } + + // + canContinue = index < barIndex + loopback; + index++; + } + + // + return result; + } + + // + double GetHigherVale( + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(index); + if (iValue > vale) + { + // + result = iValue; + break; + } + + // + canContinue = index < barIndex + loopback; + index++; + } + + // + return result; + } + + // + double GetLowerVale( + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(index); + if (iValue < vale) + { + // + result = iValue; + break; + } + + // + canContinue = index < barIndex + loopback; + index++; + } + + // + return result; + } + + // + // + // + + // + double GetLowestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetHighestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetLowestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + double GetHighestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + // CURRENT ... + + // + // HH ... + + // + double GetCHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cHHBuffer[barIndex]; + } + + // + int CopyCHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetCLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cLLBuffer[barIndex]; + } + + // + int CopyCLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cLLBuffer, + buffer, + forceClean + // + ); + } + + // + // SHORT ... + + // + // HH ... + + // + double GetSHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sHHBuffer[barIndex]; + } + + // + int CopySHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetSLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sLLBuffer[barIndex]; + } + + // + int CopySLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sLLBuffer, + buffer, + forceClean + // + ); + } + + // + // MEDIUM ... + + // + // HH ... + + // + double GetMHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mHHBuffer[barIndex]; + } + + // + int CopyMHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetMLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mLLBuffer[barIndex]; + } + + // + int CopyMLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mLLBuffer, + buffer, + forceClean + // + ); + } + + // + // LONG ... + + // + // HH ... + + // + double GetLHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lHHBuffer[barIndex]; + } + + // + int CopyLHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetLLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lLLBuffer[barIndex]; + } + + // + int CopyLLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lLLBuffer, + buffer, + forceClean + // + ); + } + + // + // HIND ... + + // + // HH ... + + // + double GetHHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hHHBuffer[barIndex]; + } + + // + int CopyHHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetHLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hLLBuffer[barIndex]; + } + + // + int CopyHLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hLLBuffer, + buffer, + forceClean + // + ); + } + + // + // VWAP ... + + // + // FAST ... + + // + double GetVWapFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastBuffer[barIndex]; + } + + // + int CopyVWapFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE FAST ... + + // + double GetVWapFastState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastStateBuffer[barIndex]; + } + + // + int CopyVWapFastState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastStateBuffer, + buffer, + forceClean + // + ); + } + + // + // MID ... + + // + double GetVWapMid( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidBuffer[barIndex]; + } + + // + int CopyVWapMid( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE MID ... + + // + double GetVWapMidState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidStateBuffer[barIndex]; + } + + // + int CopyVWapMidState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidStateBuffer, + buffer, + forceClean + // + ); + } + + // + // SLOW ... + + // + double GetVWapSlowBuffer( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowBuffer[barIndex]; + } + + // + int CopyVWapSlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE SLOW ... + + // + double GetVWapSlowState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowStateBuffer[barIndex]; + } + + // + int CopyVWapSlowState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowStateBuffer, + buffer, + forceClean + // + ); + } + + // + // VOLUME ... + + // + double GetVWapVolume( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapVolumeBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapVolumeBuffer[barIndex]; + } + + // + int CopyVWapVolume( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapVolumeBuffer, + buffer, + forceClean + // + ); + } + + // + // PRICE ... + + // + double GetVWapPrice( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapPriceBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapPriceBuffer[barIndex]; + } + + // + int CopyVWapPrice( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapPriceBuffer, + buffer, + forceClean + // + ); + } + + // + // Converts to State ... + ENUM_XVWAP_STATES ToVWAPState(double value) + { + // + ENUM_XVWAP_STATES result = + value == 1 + ? XVWAP_STATE_BULLISH + : value == 2 + ? XVWAP_STATE_BEARISH + : XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + bool IsVWAPBullish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BULLISH; + + // + return result; + } + + // + bool IsVWAPBearish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BEARISH; + + // + return result; + } + + // + bool IsVWAPNeutural(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + // XDON ... + + // + // OPEN ... + + // + // UPPER ... + + // + double GetDonOpenUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenUpperBuffer[barIndex]; + } + + // + int CopyDonOpenUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonOpenLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenLowerBuffer[barIndex]; + } + + // + int CopyDonOpenLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // CLOSE ... + + // + // UPPER ... + + // + double GetDonCloseUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseUpperBuffer[barIndex]; + } + + // + int CopyDonCloseUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonCloseLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseLowerBuffer[barIndex]; + } + + // + int CopyDonCloseLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // HIGH ... + + // + // UPPER ... + + // + double GetDonHighUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighUpperBuffer[barIndex]; + } + + // + int CopyDonHighUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonHighLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighLowerBuffer[barIndex]; + } + + // + int CopyDonHighLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // LOW ... + + // + // UPPER ... + + // + double GetDonLowUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowUpperBuffer[barIndex]; + } + + // + int CopyDonLowUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonLoweLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowLowerBuffer[barIndex]; + } + + // + int CopyDonLoweLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // Conditions Generation ... + + bool GetConditions( + X121Conditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyRSI( + zIndex, + loopback, + conditions.rsiBuffer // + ); + + // + CopySar( + zIndex, + loopback, + conditions.sarBuffer // + ); + + // + CopyAtr( + zIndex, + loopback, + conditions.atrBuffer // + ); + + // + CopyAtrUpper( + zIndex, + loopback, + conditions.atrUpperBuffer // + ); + + // + CopyAtrUpperRaw( + zIndex, + loopback, + conditions.atrUpperRawBuffer // + ); + + // + CopyAtrLower( + zIndex, + loopback, + conditions.atrLowerBuffer // + ); + + // + CopyAtrLowerRaw( + zIndex, + loopback, + conditions.atrLowerRawBuffer // + ); + + // + CopyPeak( + zIndex, + loopback, + conditions.peaksBuffer // + ); + + // + CopyVale( + zIndex, + loopback, + conditions.valesBuffer // + ); + + // + CopyCHH( + zIndex, + loopback, + conditions.cHHBuffer // + ); + + // + CopyCLL( + zIndex, + loopback, + conditions.cLLBuffer // + ); + + // + CopySHH( + zIndex, + loopback, + conditions.sHHBuffer // + ); + + // + CopySLL( + zIndex, + loopback, + conditions.sLLBuffer // + ); + + // + CopyMHH( + zIndex, + loopback, + conditions.mHHBuffer // + ); + + // + CopyMLL( + zIndex, + loopback, + conditions.mLLBuffer // + ); + + // + CopyLHH( + zIndex, + loopback, + conditions.lHHBuffer // + ); + + // + CopyLLL( + zIndex, + loopback, + conditions.lLLBuffer // + ); + + // + CopyHHH( + zIndex, + loopback, + conditions.hHHBuffer // + ); + + // + CopyHLL( + zIndex, + loopback, + conditions.hLLBuffer // + ); + + // + CopyVWapFast( + zIndex, + loopback, + conditions.vwapFastBuffer // + ); + + // + CopyVWapFastState( + zIndex, + loopback, + conditions.vwapFastStateBuffer // + ); + + // + CopyVWapMid( + zIndex, + loopback, + conditions.vwapMidBuffer // + ); + + // + CopyVWapMidState( + zIndex, + loopback, + conditions.vwapMidStateBuffer // + ); + + // + CopyVWapSlow( + zIndex, + loopback, + conditions.vwapSlowBuffer // + ); + + // + CopyVWapSlowState( + zIndex, + loopback, + conditions.vwapSlowStateBuffer // + ); + + // + CopyVWapVolume( + zIndex, + loopback, + conditions.vwapVolumeBuffer // + ); + + // + CopyVWapPrice( + zIndex, + loopback, + conditions.vwapPriceBuffer // + ); + + // + CopyDonOpenUpper( + zIndex, + loopback, + conditions.donOpenUpperBuffer // + ); + + // + CopyDonOpenLower( + zIndex, + loopback, + conditions.donOpenLowerBuffer // + ); + + // + CopyDonCloseUpper( + zIndex, + loopback, + conditions.donCloseUpperBuffer // + ); + + // + CopyDonCloseLower( + zIndex, + loopback, + conditions.donCloseLowerBuffer // + ); + + // + CopyDonHighUpper( + zIndex, + loopback, + conditions.donHighUpperBuffer // + ); + + // + CopyDonHighLower( + zIndex, + loopback, + conditions.donHighLowerBuffer // + ); + + // + CopyDonLowUpper( + zIndex, + loopback, + conditions.donLowUpperBuffer // + ); + + // + CopyDonLoweLower( + zIndex, + loopback, + conditions.donLowLowerBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // XRSI ... + + // + bool isRSIOverBought = conditions.rsiBuffer[cIDX] > mInputs.rsiOverBoughtLevel; + bool isRSIOverBoughtPrev = conditions.rsiBuffer[pIDX] > mInputs.rsiOverBoughtLevel; + + // + bool isRSICrossedOverOverBought = isRSIOverBought && + !isRSIOverBoughtPrev; + bool isRSICrossedUnderOverBought = !isRSIOverBought && + isRSIOverBoughtPrev; + + // + bool isRSIOverSold = conditions.rsiBuffer[cIDX] < mInputs.rsiOverSoldLevel; + bool isRSIOverSoldPrev = conditions.rsiBuffer[pIDX] < mInputs.rsiOverSoldLevel; + + // + bool isRSICrossedUnderOverSold = isRSIOverSold && + !isRSIOverSoldPrev; + bool isRSICrossedOverOverSold = !isRSIOverSold && + isRSIOverSoldPrev; + + // + // XSAR ... + + // + bool isSarBullish = conditions.sarBuffer[cIDX] < cBar.low; + bool isSarBullishPrev = conditions.sarBuffer[pIDX] < pBar.low; + + // + bool isSarBearish = conditions.sarBuffer[cIDX] > cBar.high; + bool isSarBearishPrev = conditions.sarBuffer[pIDX] > pBar.high; + + // + bool isSarSwitchedToBullish = isSarBullish && + !isSarBullishPrev; + bool isSarSwitchedToBearish = isSarBearish && + !isSarBearishPrev; + + // + // XPV ... + + // + bool isNewPeak = conditions.peaksBuffer[cIDX] != conditions.peaksBuffer[pIDX]; + bool isNewPeakOverLast = isNewPeak && + conditions.peaksBuffer[cIDX] > conditions.peaksBuffer[pIDX]; + bool isNewPeakUnderLast = isNewPeak && + conditions.peaksBuffer[cIDX] < conditions.peaksBuffer[pIDX]; + + // + bool isNewVale = conditions.valesBuffer[cIDX] != conditions.valesBuffer[pIDX]; + bool isNewValeOverLast = isNewVale && + conditions.valesBuffer[cIDX] > conditions.valesBuffer[pIDX]; + bool isNewValeUnderLast = isNewVale && + conditions.valesBuffer[cIDX] < conditions.valesBuffer[pIDX]; + + // + // XVWAP ... + + // + bool isVWapFastBullish = IsVWAPBullish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBullishPrev = IsVWAPBullish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastBearish = IsVWAPBearish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBearishPrev = IsVWAPBearish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastNeutural = IsVWAPNeutural(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastNeuturalPrev = IsVWAPNeutural(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapMidBullish = IsVWAPBullish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBullishPrev = IsVWAPBullish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidBearish = IsVWAPBearish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBearishPrev = IsVWAPBearish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidNeutural = IsVWAPNeutural(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidNeuturalPrev = IsVWAPNeutural(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapSlowBullish = IsVWAPBullish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBullishPrev = IsVWAPBullish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowBearish = IsVWAPBearish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBearishPrev = IsVWAPBearish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowNeutural = IsVWAPNeutural(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowNeuturalPrev = IsVWAPNeutural(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapFastOverMid = conditions.vwapFastBuffer[cIDX] > conditions.vwapMidBuffer[cIDX]; + bool isVWapFastOverMidPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidOverSlow = conditions.vwapMidBuffer[cIDX] > conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidOverSlowPrev = conditions.vwapMidBuffer[pIDX] > conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFastUnderMid = conditions.vwapFastBuffer[cIDX] < conditions.vwapMidBuffer[cIDX]; + bool isVWapFastUnderMidPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidUnderSlow = conditions.vwapMidBuffer[cIDX] < conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidUnderSlowPrev = conditions.vwapMidBuffer[pIDX] < conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapBullishState = isVWapFastBullish && + isVWapMidBullish && + isVWapSlowBullish; + bool isVWapBullishStatePrev = isVWapFastBullishPrev && + isVWapMidBullishPrev && + isVWapSlowBullishPrev; + + // + bool isVWapBearishState = isVWapFastBearish && + isVWapMidBearish && + isVWapSlowBearish; + bool isVWapBearishStatePrev = isVWapFastBearishPrev && + isVWapMidBearishPrev && + isVWapSlowBearishPrev; + + // + bool isVWapNeuturalState = isVWapFastNeutural && + isVWapMidNeutural && + isVWapSlowNeutural; + bool isVWapNeuturalStatePrev = isVWapFastNeuturalPrev && + isVWapMidNeuturalPrev && + isVWapSlowNeuturalPrev; + + // + bool isVWapBullishOrdered = isVWapFastOverMid && + isVWapMidOverSlow; + bool isVWapBullishOrderedPrev = isVWapFastOverMidPrev && + isVWapMidOverSlowPrev; + + // + bool isVWapBearishOrdered = isVWapFastUnderMid && + isVWapMidUnderSlow; + bool isVWapBearishOrderedPrev = isVWapFastUnderMidPrev && + isVWapMidUnderSlowPrev; + + // + bool isVWapSwitchedToBullishOrdered = isVWapBullishOrdered && + !isVWapBullishOrderedPrev; + bool isVWapSwitchedToBearishOrdered = isVWapBearishOrdered && + !isVWapBearishOrderedPrev; + + // + bool isVWapSwitchedToBullishState = isVWapBullishState && + !isVWapBullishStatePrev; + bool isVWapSwitchedToBearishState = isVWapBearishState && + !isVWapBearishStatePrev; + bool isVWapSwitchedToNeuturalState = isVWapNeuturalState && + !isVWapNeuturalStatePrev; + + // + // XDON ... + + // + // Set ... + conditions.isRSIOverBought = isRSIOverBought; + conditions.isRSICrossedOverOverBought = isRSICrossedOverOverBought; + conditions.isRSICrossedUnderOverBought = isRSICrossedUnderOverBought; + conditions.isRSIOverSold = isRSIOverSold; + conditions.isRSICrossedUnderOverSold = isRSICrossedUnderOverSold; + conditions.isRSICrossedOverOverSold = isRSICrossedOverOverSold; + conditions.isSarBullish = isSarBullish; + conditions.isSarBearish = isSarBearish; + conditions.isSarSwitchedToBullish = isSarSwitchedToBullish; + conditions.isSarSwitchedToBearish = isSarSwitchedToBearish; + conditions.isNewPeak = isNewPeak; + conditions.isNewPeakOverLast = isNewPeakOverLast; + conditions.isNewPeakUnderLast = isNewPeakUnderLast; + conditions.isNewVale = isNewVale; + conditions.isNewValeOverLast = isNewValeOverLast; + conditions.isNewValeUnderLast = isNewValeUnderLast; + conditions.isVWapFastBullish = isVWapFastBullish; + conditions.isVWapFastBearish = isVWapFastBearish; + conditions.isVWapFastNeutural = isVWapFastNeutural; + conditions.isVWapMidBullish = isVWapMidBullish; + conditions.isVWapMidBearish = isVWapMidBearish; + conditions.isVWapMidNeutural = isVWapMidNeutural; + conditions.isVWapSlowBullish = isVWapSlowBullish; + conditions.isVWapSlowBearish = isVWapSlowBearish; + conditions.isVWapSlowNeutural = isVWapSlowNeutural; + conditions.isVWapFastOverMid = isVWapFastOverMid; + conditions.isVWapMidOverSlow = isVWapMidOverSlow; + conditions.isVWapFastUnderMid = isVWapFastUnderMid; + conditions.isVWapMidUnderSlow = isVWapMidUnderSlow; + conditions.isVWapBullishState = isVWapBullishState; + conditions.isVWapBearishState = isVWapBearishState; + conditions.isVWapNeuturalState = isVWapNeuturalState; + conditions.isVWapBullishOrdered = isVWapBullishOrdered; + conditions.isVWapBearishOrdered = isVWapBearishOrdered; + conditions.isVWapSwitchedToBullishOrdered = isVWapSwitchedToBullishOrdered; + conditions.isVWapSwitchedToBearishOrdered = isVWapSwitchedToBearishOrdered; + conditions.isVWapSwitchedToBullishState = isVWapSwitchedToBullishState; + conditions.isVWapSwitchedToBearishState = isVWapSwitchedToBearishState; + conditions.isVWapSwitchedToNeuturalState = isVWapSwitchedToNeuturalState; + + // + return result; + } + + // + protected: + // + + // + private: + // + // Props ... + X121Inputs mInputs; // Inputs ... + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double sarBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + double atrBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + double rsiBuffer[]; + + // + // Tools ... + + /** + * Calculate Buffers ... + */ + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // RSI ... + CopyBuffer( + mHandler, + X121_RSI_LINE, + 0, + totalBars, + rsiBuffer + // + ); + + // + // XSAR ... + CopyBuffer( + mHandler, + X121_SAR_LINE, + 0, + totalBars, + sarBuffer + // + ); + + // + // ATR ... + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_LINE, + 0, + totalBars, + atrUpperBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_LINE, + 0, + totalBars, + atrLowerBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LINE, + 0, + totalBars, + atrBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_RAW_LINE, + 0, + totalBars, + atrUpperRawBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_RAW_LINE, + 0, + totalBars, + atrLowerRawBuffer + // + ); + + // + // XPV ... + + // + // PEAKS ... + CopyBuffer( + mHandler, + X121_PEAKS_LINE, + 0, + totalBars, + peaksBuffer + // + ); + + // + // VALES ... + CopyBuffer( + mHandler, + X121_VALES_LINE, + 0, + totalBars, + valesBuffer + // + ); + + // + // CURRENT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_CURRENT_HH_LINE, + 0, + totalBars, + cHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_CURRENT_LL_LINE, + 0, + totalBars, + cLLBuffer + // + ); + + // + // SHORT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_SHORT_HH_LINE, + 0, + totalBars, + sHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_SHORT_LL_LINE, + 0, + totalBars, + sLLBuffer + // + ); + + // + // MEDIUM ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_MEDIUM_HH_LINE, + 0, + totalBars, + mHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_MEDIUM_LL_LINE, + 0, + totalBars, + mLLBuffer + // + ); + + // + // LONG ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_LONG_HH_LINE, + 0, + totalBars, + lHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_LONG_LL_LINE, + 0, + totalBars, + lLLBuffer + // + ); + + // + // HIND ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_HIND_HH_LINE, + 0, + totalBars, + hHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_HIND_LL_LINE, + 0, + totalBars, + hLLBuffer + // + ); + + // + // XVWAP ... + + // + // FAST ... + CopyBuffer( + mHandler, + X121_VWAP_FAST_LINE, + 0, + totalBars, + vwapFastBuffer + // + ); + + // + // FAST STATE ... + CopyBuffer( + mHandler, + X121_VWAP_FAST_STATE_LINE, + 0, + totalBars, + vwapFastStateBuffer + // + ); + + // + // MID ... + CopyBuffer( + mHandler, + X121_VWAP_MID_LINE, + 0, + totalBars, + vwapMidBuffer + // + ); + + // + // MID STATE ... + CopyBuffer( + mHandler, + X121_VWAP_MID_STATE_LINE, + 0, + totalBars, + vwapMidStateBuffer + // + ); + + // + // SLOW ... + CopyBuffer( + mHandler, + X121_VWAP_SLOW_LINE, + 0, + totalBars, + vwapSlowBuffer + // + ); + + // + // SLOW STATE ... + CopyBuffer( + mHandler, + X121_VWAP_SLOW_STATE_LINE, + 0, + totalBars, + vwapSlowStateBuffer + // + ); + + // + // VOLUME ... + CopyBuffer( + mHandler, + X121_VWAP_VOLUME_LINE, + 0, + totalBars, + vwapVolumeBuffer + // + ); + + // + // PRICE ... + CopyBuffer( + mHandler, + X121_VWAP_PRICE_LINE, + 0, + totalBars, + vwapPriceBuffer + // + ); + + // + // XDON ... + + // + // OPEN ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_OPEN_UPPER_LINE, + 0, + totalBars, + donOpenUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_OPEN_LOWER_LINE, + 0, + totalBars, + donOpenLowerBuffer + // + ); + + // + // CLOSE ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_CLOSE_UPPER_LINE, + 0, + totalBars, + donCloseUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_CLOSE_LOWER_LINE, + 0, + totalBars, + donCloseLowerBuffer + // + ); + + // + // HIGH ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_HIGH_UPPER_LINE, + 0, + totalBars, + donHighUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_HIGH_LOWER_LINE, + 0, + totalBars, + donHighLowerBuffer + // + ); + + // + // LOW ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_LOW_UPPER_LINE, + 0, + totalBars, + donLowUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_LOW_LOWER_LINE, + 0, + totalBars, + donLowLowerBuffer + // + ); + } +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.mq5 b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.mq5 new file mode 100644 index 0000000..4a24037 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.mq5 @@ -0,0 +1,2407 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 +// Description: Peaks and Vales ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121" + +// +// Includes Common Library ... +#include "../Classes/x-saherelm.x-poi.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +input group "Makret Cycles"; + +// +input group "Short"; +input ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES scPeriod = NULL; // Time Period + +// +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES mcPeriod = NULL; // Time Period + +// +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES lcPeriod = NULL; // Time Period + +// +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES hcPeriod = NULL; // Time Period + +// +input group "Boundary Detection"; +input ENUM_SERIESMODE hhMode = MODE_HIGH; // Highest High Calculation Method +input ENUM_SERIESMODE llMode = MODE_LOW; // Lowest Low Calculation Method + +// +input group "Rsi Detection"; +input int rsiLength = 14; // Length +input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Parabolic Sar Detection"; +input double sarStep = 0.02; // Step +input double sarMax = 0.2; // Maximum + +// +input group "Atr Detection"; +input int atrLength = 14; // Length +input double atrMultiplier = 1; // Multiplier +input ENUM_APPLIED_PRICE atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To +input ENUM_APPLIED_PRICE atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To +input ENUM_X_MA_METHOD atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + +// +input group "Str Detecttion"; +input ENUM_APPLIED_PRICE strAppliedTo = PRICE_MEDIAN; // Applied To + +// +input group "VWap Detection"; +input int vwapFastLength = 20; // Fast Length +input int vwapMidLength = 40; // Mid Length +input int vwapSlowLength = 60; // Slow Length +input ENUM_APPLIED_PRICE vwapAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Donchain Detection"; +input int donchainLength = 40; // Donchain Length + +// +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars + +// +input int sarArrowCode = 159; // Parabolic Sar Arrow Code +input int peaksArrowCode = 159; // Peaks Arrow Code +input int valesArrowCode = 159; // Vales Arrow Code + +// +input bool showSar = true; // Show Parabolic Sar +input bool showAtr = true; // Show Atr +input bool showStr = true; // Show Str +input bool showPeaks = true; // Show Peaks +input bool showVales = true; // Show Vales +input bool showVWap = true; // Show VWap +input bool showDonchain = true; // Show Donchain + +// +input group "Atr Presentation"; +input bool showAtrUpper = true; // Show Upper Zone +input bool showAtrLower = true; // Show Lower Zone + +// +input group "VWap Presentation"; +input bool showVWapFast = true; // Show VWap Fast +input bool showVWapMedium = true; // Show VWap Medium +input bool showVWapSlow = true; // Show VWap Slow + +// +input group "Donchain Presentation"; +input bool showUpper = true; // Show Upper Band +input bool showLower = true; // Show Lower Band +input bool showOpen = true; // Show Open +input bool showHigh = false; // Show High +input bool showClose = true; // Show Close +input bool showLow = false; // Show Low + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 44 +#property indicator_plots 17 + +// +// PEAKS ... + +// +#define peaksBufferIndex 0 +double peaksBuffer[]; + +// +#property indicator_label1 "X121 PEAKS" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrAqua +#property indicator_width1 1 + +// +// VALES ... + +// +#define valesBufferIndex 1 +double valesBuffer[]; + +// +#property indicator_label2 "X121 VALES" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrMagenta +#property indicator_width2 1 + +// +// SAR ... + +// +#define sarBufferIndex 2 +double sarBuffer[]; + +// +#property indicator_label3 "X121 SAR" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrYellow +#property indicator_width3 1 + +// +// ATR ... + +// +// Upper ... + +// +#define atrUpperBufferIndex 3 +double atrUpperBuffer[]; + +#property indicator_label4 "X121 ATRU" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrYellow +#property indicator_style4 STYLE_DOT +#property indicator_width4 2 + +// +// Lower ... + +// +#define atrLowerBufferIndex 4 +double atrLowerBuffer[]; + +#property indicator_label5 "X121 ATRL" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrYellow +#property indicator_style5 STYLE_DOT +#property indicator_width5 2 + +// +// STR ... +#define strBufferIndex 5 +double strBuffer[]; + +#define strColorBufferIndex 6 +double strColorBuffer[]; + +// +#define strPlotBufferIndex 5 +#property indicator_label6 "X121 STR" +#property indicator_type6 DRAW_COLOR_LINE +#property indicator_color6 CLR_NONE, clrLime, clrRed, clrGray +#property indicator_style6 STYLE_SOLID +#property indicator_width6 2 + +// +// VWAP ... + +// +// FAST ... +#define vwapFastBufferIndex 7 +double vwapFastBuffer[]; + +#define vwapFastColorBufferIndex 8 +double vwapFastColorBuffer[]; + +// +#define vwapFastPlotBufferIndex 6 +#property indicator_label7 "X121 VWF" +#property indicator_type7 DRAW_COLOR_LINE +#property indicator_color7 CLR_NONE, clrAqua, clrMagenta, clrGray +#property indicator_style7 STYLE_SOLID +#property indicator_width7 2 + +// +// MID ... +#define vwapMidBufferIndex 9 +double vwapMidBuffer[]; + +#define vwapMidColorBufferIndex 10 +double vwapMidColorBuffer[]; + +// +#define vwapMidPlotBufferIndex 7 +#property indicator_label8 "X121 VWM" +#property indicator_type8 DRAW_COLOR_LINE +#property indicator_color8 CLR_NONE, clrGreen, clrRed, clrGray +#property indicator_style8 STYLE_SOLID +#property indicator_width8 2 + +// +// SLOW ... +#define vwapSlowBufferIndex 11 +double vwapSlowBuffer[]; + +#define vwapSlowColorBufferIndex 12 +double vwapSlowColorBuffer[]; + +// +#define vwapSlowPlotBufferIndex 8 +#property indicator_label9 "X121 VWS" +#property indicator_type9 DRAW_COLOR_LINE +#property indicator_color9 CLR_NONE, clrSteelBlue, clrDarkRed, clrGray +#property indicator_style9 STYLE_SOLID +#property indicator_width9 2 + +// +// XDON ... + +// +// Open ... + +// +#define donOpenUpperBufferIndex 13 +double donOpenUpperBuffer[]; + +// +#define donOpenUpperPlotBufferIndex 9 +#property indicator_label10 "X121 O U" +#property indicator_type10 DRAW_LINE +#property indicator_color10 clrCornflowerBlue +#property indicator_width10 1 + +// +#define donOpenLowerBufferIndex 14 +double donOpenLowerBuffer[]; + +// +#define donOpenLowerPlotBufferIndex 10 +#property indicator_label11 "X121 O L" +#property indicator_type11 DRAW_LINE +#property indicator_color11 clrCornflowerBlue +#property indicator_width11 1 + +// +// High ... + +// +#define donHighUpperBufferIndex 15 +double donHighUpperBuffer[]; + +// +#define donHighUpperPlotBufferIndex 11 +#property indicator_label12 "X121 H U" +#property indicator_type12 DRAW_LINE +#property indicator_color12 clrAquamarine +#property indicator_width12 1 + +// +#define donHighLowerBufferIndex 16 +double donHighLowerBuffer[]; + +// +#define donHighLowerPlotBufferIndex 12 +#property indicator_label13 "X121 H L" +#property indicator_type13 DRAW_LINE +#property indicator_color13 clrAquamarine +#property indicator_width13 1 + +// +// Low ... + +// +#define donLowUpperBufferIndex 17 +double donLowUpperBuffer[]; + +// +#define donLowUpperPlotBufferIndex 13 +#property indicator_label14 "X121 L U" +#property indicator_type14 DRAW_LINE +#property indicator_color14 clrDarkOrchid +#property indicator_width14 1 + +// +#define donLowLowerBufferIndex 18 +double donLowLowerBuffer[]; + +// +#define donLowLowerPlotBufferIndex 14 +#property indicator_label15 "X121 L L" +#property indicator_type15 DRAW_LINE +#property indicator_color15 clrDarkOrchid +#property indicator_width15 1 + +// +// Close ... + +// +#define donCloseUpperBufferIndex 19 +double donCloseUpperBuffer[]; + +// +#define donCloseUpperPlotBufferIndex 15 +#property indicator_label16 "X121 C U" +#property indicator_type16 DRAW_LINE +#property indicator_color16 clrCoral +#property indicator_width16 1 + +// +#define donCloseLowerBufferIndex 20 +double donCloseLowerBuffer[]; + +// +#define donCloseLowerPlotBufferIndex 16 +#property indicator_label17 "X121 C L" +#property indicator_type17 DRAW_LINE +#property indicator_color17 clrCoral +#property indicator_width17 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 20; + +// +// CURRENT ... + +// +#define cHHBufferIndex mLastBufferIndex + 1 +double cHHBuffer[]; + +// +#define cLLBufferIndex mLastBufferIndex + 2 +double cLLBuffer[]; + +// +// SHORT ... + +// +#define sHHBufferIndex mLastBufferIndex + 3 +double sHHBuffer[]; + +// +#define sLLBufferIndex mLastBufferIndex + 4 +double sLLBuffer[]; + +// +// MEDIUM ... + +// +#define mHHBufferIndex mLastBufferIndex + 5 +double mHHBuffer[]; + +// +#define mLLBufferIndex mLastBufferIndex + 6 +double mLLBuffer[]; + +// +// LONG ... + +// +#define lHHBufferIndex mLastBufferIndex + 7 +double lHHBuffer[]; + +// +#define lLLBufferIndex mLastBufferIndex + 8 +double lLLBuffer[]; + +// +// HIND ... + +// +#define hHHBufferIndex mLastBufferIndex + 9 +double hHHBuffer[]; + +// +#define hLLBufferIndex mLastBufferIndex + 10 +double hLLBuffer[]; + +// +// VWAP ... +#define vwapVolumeBufferIndex mLastBufferIndex + 11 +double vwapVolumeBuffer[]; + +// +// Price ... +#define vwapPriceBufferIndex mLastBufferIndex + 12 +double vwapPriceBuffer[]; + +// +// Fast State ... +#define vwapFastStateBufferIndex mLastBufferIndex + 13 +double vwapFastStateBuffer[]; + +// +// Mid State ... +#define vwapMidStateBufferIndex mLastBufferIndex + 14 +double vwapMidStateBuffer[]; + +// +// Slow State ... +#define vwapSlowStateBufferIndex mLastBufferIndex + 15 +double vwapSlowStateBuffer[]; + +// +// ATR ... + +#define atrBufferIndex mLastBufferIndex + 16 +double atrBuffer[]; + +#define atrUpperRawBufferIndex mLastBufferIndex + 17 +double atrUpperRawBuffer[]; + +#define atrLowerRawBufferIndex mLastBufferIndex + 18 +double atrLowerRawBuffer[]; + +// +// RSI ... +#define rsiBufferIndex mLastBufferIndex + 19 +double rsiBuffer[]; + +// +// STR ... + +// +// Price ... +#define strPriceBufferIndex mLastBufferIndex + 20 +double strPriceBuffer[]; + +// +// Up ... +#define strUpBufferIndex mLastBufferIndex + 21 +double strUpBuffer[]; + +// +// Down ... +#define strDownBufferIndex mLastBufferIndex + 22 +double strDownBuffer[]; + +// +// Trend ... +#define strStateBufferIndex mLastBufferIndex + 23 +double strStateBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; +int rlimit; + +// +int maxLength; + +// +// RSI Handler ... +int rsiHandler = INVALID_HANDLE; + +// +// SAR Handler ... +int sarHandler = INVALID_HANDLE; + +// +// ATR Handler ... +int atrHandler = INVALID_HANDLE; + +// +bool isStrTrendChanged; +bool isStrStartBearishTrend; +bool isStrStartBullishTrend; + +// +// XMarketCycle sc; +int mSCLength = 0; +ENUM_TIMEFRAMES mSCPeriod = NULL; + +// +// XMarketCycle mc; +int mMCLength = 0; +ENUM_TIMEFRAMES mMCPeriod = NULL; + +// +// XMarketCycle lc; +int mLCLength = 0; +ENUM_TIMEFRAMES mLCPeriod = NULL; + +// +// XMarketCycle hc; +int mHCLength = 0; +ENUM_TIMEFRAMES mHCPeriod = NULL; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // RSI ... + rsiHandler = iRSI( + _Symbol, + _Period, + rsiLength, + rsiAppliedTo // + ); + bool isInited = rsiHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // SAR ... + sarHandler = iSAR( + _Symbol, + _Period, + sarStep, + sarMax // + ); + isInited = sarHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength // + ); + isInited = atrHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + if (!InitMarketCycles()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(rsiHandler); + IndicatorRelease(sarHandler); + IndicatorRelease(atrHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Fill All Buffers by Zero ... + if (prev_calculated == 0) + { + // + ArrayInitialize(peaksBuffer, 0); + ArrayInitialize(valesBuffer, 0); + ArrayInitialize(sarBuffer, 0); + } + + // + // Validate Calculated Bars ... + + // + // RSI ... + int rsiCalculatedBars = BarsCalculated(rsiHandler); + + // + // SAR ... + int sarCalculatedBars = BarsCalculated(sarHandler); + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // RSI ... + rsiCalculatedBars >= maxLength && + // + // SAR ... + sarCalculatedBars >= maxLength && + // + // ATR ... + sarCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + rlimit = (prev_calculated > rates_total || prev_calculated <= 0) + ? maxLength + : prev_calculated - 1; + + // + // Buffers Copy ... + + // + // RSI ... + int copiedRsis = CopyBuffer(rsiHandler, 0, 0, limit, rsiBuffer); + + // + // SAR ... + int copiedSars = CopyBuffer(sarHandler, 0, 0, limit, sarBuffer); + + // + // ATR ... + int copiedAtrs = CopyBuffer(atrHandler, 0, 0, limit, atrBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // + // RSI ... + copiedRsis > 0 && + // + // SAR ... + copiedSars > 0 && + // + // ATR ... + copiedAtrs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + // RSI ... + rsiLength > 0 && + // + // PSAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 && + // + // XDON ... + donchainLength > 0 && + // + // VWAP ... + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // XPV ... + result = MathMax(mSCLength, mMCLength); + result = MathMax(result, mLCLength); + result = MathMax(result, mHCLength); + + // + // XVWAP ... + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapMidLength); + result = MathMax(result, vwapSlowLength); + + // + // ATR ... + result = MathMax(result, atrLength); + + // + // RSI ... + result = MathMax(result, rsiLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // PEAKS ... + + // + ENUM_DRAW_TYPE peaksDrawType = showPeaks ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(peaksBuffer, true); + SetIndexBuffer(peaksBufferIndex, peaksBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peaksBufferIndex, PLOT_SHOW_DATA, showPeaks); + PlotIndexSetInteger(peaksBufferIndex, PLOT_DRAW_TYPE, peaksDrawType); + + // + PlotIndexSetDouble(peaksBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(peaksBufferIndex, PLOT_ARROW, peaksArrowCode); + + // + // VALES ... + + // + ENUM_DRAW_TYPE valesDrawType = showVales ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(valesBuffer, true); + SetIndexBuffer(valesBufferIndex, valesBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valesBufferIndex, PLOT_SHOW_DATA, showVales); + PlotIndexSetInteger(valesBufferIndex, PLOT_DRAW_TYPE, valesDrawType); + + // + PlotIndexSetDouble(valesBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(valesBufferIndex, PLOT_ARROW, valesArrowCode); + + // + // SAR ... + + // + ENUM_DRAW_TYPE sarDrawType = showSar ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(sarBufferIndex, PLOT_SHOW_DATA, showSar); + PlotIndexSetInteger(sarBufferIndex, PLOT_DRAW_TYPE, sarDrawType); + + // + PlotIndexSetDouble(sarBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(sarBufferIndex, PLOT_ARROW, sarArrowCode); + + // + // ATR ... + + // + // UPPER ... + bool canShowAtrUpper = showAtr && showAtrUpper; + ENUM_DRAW_TYPE atrUpperDrawType = canShowAtrUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrUpperBuffer, true); + SetIndexBuffer(atrUpperBufferIndex, atrUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrUpperBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_SHOW_DATA, canShowAtrUpper); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_DRAW_TYPE, atrUpperDrawType); + + // + // LOWER ... + bool canShowAtrLower = showAtr && showAtrLower; + ENUM_DRAW_TYPE atrLowerDrawType = canShowAtrLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrLowerBuffer, true); + SetIndexBuffer(atrLowerBufferIndex, atrLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrLowerBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_SHOW_DATA, canShowAtrLower); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_DRAW_TYPE, atrLowerDrawType); + + // + // STR ... + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(strColorBuffer, true); + SetIndexBuffer(strBufferIndex, strBuffer, INDICATOR_DATA); + SetIndexBuffer(strColorBufferIndex, strColorBuffer, INDICATOR_COLOR_INDEX); + + // + // XVWAP ... + + // + // Fast ... + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapFastColorBuffer, true); + SetIndexBuffer(vwapFastBufferIndex, vwapFastBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapFastColorBufferIndex, vwapFastColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Mid ... + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapMidColorBuffer, true); + SetIndexBuffer(vwapMidBufferIndex, vwapMidBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapMidColorBufferIndex, vwapMidColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Slow ... + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapSlowColorBuffer, true); + SetIndexBuffer(vwapSlowBufferIndex, vwapSlowBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapSlowColorBufferIndex, vwapSlowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // XDON ... + + // + // Open ... + + // + // UPPER ... + bool canShowCOpenUpper = showDonchain && showUpper && showOpen; + ENUM_DRAW_TYPE donOpenUpperDrawType = canShowCOpenUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenUpperBuffer, true); + SetIndexBuffer(donOpenUpperBufferIndex, donOpenUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenUpper); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_DRAW_TYPE, donOpenUpperDrawType); + + // + // LOWER ... + bool canShowCOpenLower = showDonchain && showLower && showOpen; + ENUM_DRAW_TYPE donOpenLowerDrawType = canShowCOpenLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenLowerBuffer, true); + SetIndexBuffer(donOpenLowerBufferIndex, donOpenLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenLower); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_DRAW_TYPE, donOpenLowerDrawType); + + // + // Close ... + + // + // UPPER ... + bool canShowCCloseUpper = showDonchain && showUpper && showClose; + ENUM_DRAW_TYPE donCloseUpperDrawType = canShowCCloseUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseUpperBuffer, true); + SetIndexBuffer(donCloseUpperBufferIndex, donCloseUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseUpper); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_DRAW_TYPE, donCloseUpperDrawType); + + // + // LOWER ... + bool canShowCCloseLower = showDonchain && showLower && showClose; + ENUM_DRAW_TYPE donCloseLowerDrawType = canShowCCloseLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseLowerBuffer, true); + SetIndexBuffer(donCloseLowerBufferIndex, donCloseLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseLower); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_DRAW_TYPE, donCloseLowerDrawType); + + // + // High ... + + // + // UPPER ... + bool canShowCHighUpper = showDonchain && showUpper && showHigh; + ENUM_DRAW_TYPE donHighUpperDrawType = canShowCHighUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighUpperBuffer, true); + SetIndexBuffer(donHighUpperBufferIndex, donHighUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighUpper); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_DRAW_TYPE, donHighUpperDrawType); + + // + // LOWER ... + bool canShowCHighLower = showDonchain && showLower && showHigh; + ENUM_DRAW_TYPE donHighLowerDrawType = canShowCHighLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighLowerBuffer, true); + SetIndexBuffer(donHighLowerBufferIndex, donHighLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighLower); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_DRAW_TYPE, donHighLowerDrawType); + + // + // Low ... + + // + // UPPER ... + bool canShowCLowUpper = showDonchain && showUpper && showLow; + ENUM_DRAW_TYPE donLowUpperDrawType = canShowCLowUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowUpperBuffer, true); + SetIndexBuffer(donLowUpperBufferIndex, donLowUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowUpper); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_DRAW_TYPE, donLowUpperDrawType); + + // + // LOWER ... + bool canShowCLowLower = showDonchain && showLower && showLow; + ENUM_DRAW_TYPE donLowLowerDrawType = canShowCLowLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowLowerBuffer, true); + SetIndexBuffer(donLowLowerBufferIndex, donLowLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowLower); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_DRAW_TYPE, donLowLowerDrawType); + + // + // Data Buffers ... + + // + // CURRENT ... + + // + ArraySetAsSeries(cHHBuffer, true); + SetIndexBuffer(cHHBufferIndex, cHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(cLLBuffer, true); + SetIndexBuffer(cLLBufferIndex, cLLBuffer, INDICATOR_CALCULATIONS); + + // + // SHORT ... + + // + ArraySetAsSeries(sHHBuffer, true); + SetIndexBuffer(sHHBufferIndex, sHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(sLLBuffer, true); + SetIndexBuffer(sLLBufferIndex, sLLBuffer, INDICATOR_CALCULATIONS); + + // + // MEDIUM ... + + // + ArraySetAsSeries(mHHBuffer, true); + SetIndexBuffer(mHHBufferIndex, mHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(mLLBuffer, true); + SetIndexBuffer(mLLBufferIndex, mLLBuffer, INDICATOR_CALCULATIONS); + + // + // LONG ... + + // + ArraySetAsSeries(lHHBuffer, true); + SetIndexBuffer(lHHBufferIndex, lHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(lLLBuffer, true); + SetIndexBuffer(lLLBufferIndex, lLLBuffer, INDICATOR_CALCULATIONS); + + // + // HIND ... + + // + ArraySetAsSeries(hHHBuffer, true); + SetIndexBuffer(hHHBufferIndex, hHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(hLLBuffer, true); + SetIndexBuffer(hLLBufferIndex, hLLBuffer, INDICATOR_CALCULATIONS); + + // + // XVWAP ... + + // + // Volumes ... + ArraySetAsSeries(vwapVolumeBuffer, true); + SetIndexBuffer(vwapVolumeBufferIndex, vwapVolumeBuffer, INDICATOR_CALCULATIONS); + + // + // Price ... + ArraySetAsSeries(vwapPriceBuffer, true); + SetIndexBuffer(vwapPriceBufferIndex, vwapPriceBuffer, INDICATOR_CALCULATIONS); + + // + // Fast State ... + ArraySetAsSeries(vwapFastStateBuffer, true); + SetIndexBuffer(vwapFastStateBufferIndex, vwapFastStateBuffer, INDICATOR_CALCULATIONS); + + // + // Mid State ... + ArraySetAsSeries(vwapMidStateBuffer, true); + SetIndexBuffer(vwapMidStateBufferIndex, vwapMidStateBuffer, INDICATOR_CALCULATIONS); + + // + // Slow State ... + ArraySetAsSeries(vwapSlowStateBuffer, true); + SetIndexBuffer(vwapSlowStateBufferIndex, vwapSlowStateBuffer, INDICATOR_CALCULATIONS); + + // + // ATR ... + + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrUpperRawBuffer, true); + SetIndexBuffer(atrUpperRawBufferIndex, atrUpperRawBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrLowerRawBuffer, true); + SetIndexBuffer(atrLowerRawBufferIndex, atrLowerRawBuffer, INDICATOR_CALCULATIONS); + + // + // RSI ... + + // + ArraySetAsSeries(rsiBuffer, true); + SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); + + // + // STR ... + + // + ArraySetAsSeries(strPriceBuffer, true); + SetIndexBuffer(strPriceBufferIndex, strPriceBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(strUpBuffer, true); + SetIndexBuffer(strUpBufferIndex, strUpBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(strDownBuffer, true); + SetIndexBuffer(strDownBufferIndex, strDownBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(strStateBuffer, true); + SetIndexBuffer(strStateBufferIndex, strStateBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + // Calculate Cycles ... + CalculateCycles(bar_index); + + // + // Calculate Peaks and Vales ... + CalculatePeaksAndVales(bar_index); + + // + CalculateDonchains( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateAtrZones( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); + + // + CalculateStr( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); + + // + // Calculate Required VWAP Data Buffers ... + if (ratesTotal - bar_index <= maxLength) + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // Prevent Moving Forward ... + } + else + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateVWAPS( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Initial Market Cycles ... + * + * @return ( bool ) + */ +bool InitMarketCycles() +{ + // + bool result = false; + + // + int cPeriodSeconds = PeriodSeconds(_Period); + + // + // Find Cycle Period ... + if (scMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mSCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_SHORT, + _Period // + ); + } + else + { + mSCPeriod = scPeriod; + } + + // + if (IsValid(mSCPeriod)) + { + mSCLength = PeriodSeconds(mSCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (mcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mMCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_MEDIUM, + _Period // + ); + } + else + { + mMCPeriod = mcPeriod; + } + + // + if (IsValid(mMCPeriod)) + { + mMCLength = PeriodSeconds(mMCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (lcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mLCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_LONG, + _Period // + ); + } + else + { + mLCPeriod = lcPeriod; + } + + // + if (IsValid(mLCPeriod)) + { + mLCLength = PeriodSeconds(mLCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (hcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mHCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_HIND, + _Period // + ); + } + else + { + mHCPeriod = hcPeriod; + } + + // + if (IsValid(mHCPeriod)) + { + mHCLength = PeriodSeconds(mHCPeriod) / cPeriodSeconds; + } + + // + result = mSCLength > 0 && + mMCLength > mSCLength && + mLCLength > mMCLength && + mHCLength > mLCLength; + + // + return result; +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // CURRENT ... + cHHBuffer[barIndex] = 0; + cLLBuffer[barIndex] = 0; + + // + // SHORT ... + sHHBuffer[barIndex] = 0; + sLLBuffer[barIndex] = 0; + + // + // MEDIUM ... + mHHBuffer[barIndex] = 0; + mLLBuffer[barIndex] = 0; + + // + // LONG ... + lHHBuffer[barIndex] = 0; + lLLBuffer[barIndex] = 0; + + // + // HIND ... + hHHBuffer[barIndex] = 0; + hLLBuffer[barIndex] = 0; + + // + // PEAKS ... + peaksBuffer[barIndex] = 0; + + // + // VALES ... + valesBuffer[barIndex] = 0; + + // + // SARS ... + sarBuffer[barIndex] = 0; + + // + // RSIS ... + rsiBuffer[barIndex] = 0; + + // + // ATRS ... + atrBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrUpperRawBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrLowerRawBuffer[barIndex] = 0; + + // + // STR ... + strBuffer[barIndex] = 0; + strUpBuffer[barIndex] = 0; + strDownBuffer[barIndex] = 0; + strPriceBuffer[barIndex] = 0; + strColorBuffer[barIndex] = hideColorIDX; + strStateBuffer[barIndex] = hideColorIDX; + + // + // VWAP ... + + // + vwapFastBuffer[barIndex] = 0; + vwapMidBuffer[barIndex] = 0; + vwapSlowBuffer[barIndex] = 0; + vwapVolumeBuffer[barIndex] = 0; + vwapPriceBuffer[barIndex] = 0; + + // + vwapFastColorBuffer[barIndex] = hideColorIDX; + vwapMidColorBuffer[barIndex] = hideColorIDX; + vwapSlowColorBuffer[barIndex] = hideColorIDX; + vwapFastStateBuffer[barIndex] = hideColorIDX; + vwapMidStateBuffer[barIndex] = hideColorIDX; + vwapSlowStateBuffer[barIndex] = hideColorIDX; + + // + donOpenUpperBuffer[barIndex] = 0; + donOpenLowerBuffer[barIndex] = 0; + donCloseUpperBuffer[barIndex] = 0; + donCloseLowerBuffer[barIndex] = 0; + donHighUpperBuffer[barIndex] = 0; + donHighLowerBuffer[barIndex] = 0; + donLowUpperBuffer[barIndex] = 0; + donLowLowerBuffer[barIndex] = 0; +} + +/** + * Calculate Specified Market Cycle Info ... + * + * @param barIndex: Integer, Bar Index ... + * @param cycle: ENUM_X_MARKET_CYCLES member, Specified Cycle ... + * @param hhBuffer: Highest High Buffer Reference ... + * @param llBuffer: Lowest Low Buffer Reference ... + */ +void CalculateCycle( + int barIndex, + ENUM_X_MARKET_CYCLES cycle, + double &hhBuffer[], + double &llBuffer[] // +) +{ + // + XOHCL bar; + bool isBarInited = bar.Init( + _Symbol, + _Period, + barIndex + // + ); + if (!isBarInited) + { + return; + } + + // + int mLength = 0; + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + mLength = mSCLength; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + mLength = mMCLength; + break; + + // + case X_MARKET_CYCLE_LONG: + mLength = mLCLength; + break; + + // + case X_MARKET_CYCLE_HIND: + mLength = mHCLength; + break; + } + + // + if (mLength == 0) + { + return; + } + + // + // Find Highest High ... + double hhValue = bar.FindHighest( + mLength, + hhMode + // + ); + hhBuffer[barIndex] = hhValue; + + // + // Find Lowest Low ... + double llValue = bar.FindLowest( + mLength, + llMode + // + ); + llBuffer[barIndex] = llValue; +} + +/** + * Claculate Cycles ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculateCycles(int barIndex) +{ + // + // SHORT ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_SHORT, + sHHBuffer, + sLLBuffer // + ); + + // + // MEDIUM ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_MEDIUM, + mHHBuffer, + mLLBuffer // + ); + + // + // LONG ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_LONG, + lHHBuffer, + lLLBuffer // + ); + + // + // HIND ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_HIND, + hHHBuffer, + hLLBuffer // + ); +} + +/** + * Calculate Peaks and Vales ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculatePeaksAndVales(int barIndex) +{ + // + int lastIndex = barIndex + 1; + int barsCount = iBars(_Symbol, _Period); + + // + // PEAKS ... + double lastPeak = + lastIndex < barsCount + ? peaksBuffer[lastIndex] + : 0; + + // + double isHH = sHHBuffer[barIndex]; + double imHH = mHHBuffer[barIndex]; + double ilHH = lHHBuffer[barIndex]; + double ihHH = hHHBuffer[barIndex]; + + // + double iHHs[4] = { + isHH, + imHH, + ilHH, + ihHH // + }; + double rValue = GetAverage(iHHs); + bool isPeak = rValue == isHH && + isHH == imHH && + imHH == ilHH && + ilHH == ihHH; + double iPeak = + isPeak + ? rValue + : lastPeak; + peaksBuffer[barIndex] = iPeak; + + // + // VALES ... + double lastVale = + lastIndex < barsCount + ? valesBuffer[lastIndex] + : 0; + + // + double isLL = sLLBuffer[barIndex]; + double imLL = mLLBuffer[barIndex]; + double ilLL = lLLBuffer[barIndex]; + double ihLL = hLLBuffer[barIndex]; + + // + double iLLs[4] = { + isLL, + imLL, + ilLL, + ihLL // + }; + double sValue = GetAverage(iLLs); + bool isVale = sValue == isLL && + isLL == imLL && + imLL == ilLL && + ilLL == ihLL; + double iVale = + isVale + ? sValue + : lastVale; + valesBuffer[barIndex] = iVale; +} + +/** + * Calculate VWAP Value for Specified Bar ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Specified VWAP Length ... + * @param _show: Boolean, Specified Show Buffer or not ... + * @param _buffer: Double Array Reference, Points to Buffer ... + * @param _colorBuffer: Double Array Reference, Points to Color Buffer ... + * @param _stateBuffer: Double Array Reference, Points to State Buffer ... + */ +void CalculateVWAP( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, // Calculation Length + bool _show, + double &_buffer[], + double &_colorBuffer[], + double &_stateBuffer[] // +) +{ + // + double vSum = 0; + double pSum = 0; + double mSum = 0; + for (int x = 0; x < _length; x++) + { + // + pSum += vwapPriceBuffer[x + bar_index]; + vSum += vwapVolumeBuffer[x + bar_index]; + mSum += vwapPriceBuffer[x + bar_index] * vwapVolumeBuffer[x + bar_index]; + } + + // + double iValue = mSum / vSum; + iValue = NormalizeDouble(iValue, _Digits); + + // + _buffer[bar_index] = iValue; + + // + bool isBullish = low[bar_index] > iValue; + bool isBearish = high[bar_index] < iValue; + + // + double iColor = + isBullish + ? bullishColorIDX + : isBearish + ? bearishColorIDX + : neuturalColorIDX; + + // + _colorBuffer[bar_index] = hideColorIDX; + _stateBuffer[bar_index] = iColor; + if (showVWap && _show) + { + _colorBuffer[bar_index] = iColor; + } +} + +/** + * Calculate Donchain ... + * + * @param bar_index: Integer, Bar Index ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Donchain Length ... + * @param _ouBuffer: Double Array Reference ... + * @param _olBuffer: Double Array Reference ... + * @param _huBuffer: Double Array Reference ... + * @param _hlBuffer: Double Array Reference ... + * @param _luBuffer: Double Array Reference ... + * @param _llBuffer: Double Array Reference ... + * @param _cuBuffer: Double Array Reference ... + * @param _clBuffer: Double Array Reference ... + */ +void CalculateDonchain( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + // + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, + // + double &_ouBuffer[], + double &_olBuffer[], + double &_huBuffer[], + double &_hlBuffer[], + double &_luBuffer[], + double &_llBuffer[], + double &_cuBuffer[], + double &_clBuffer[] // +) +{ + // + double iUpper = 0; + double iLower = 0; + + // + // OPEN ... + + // + int from = bar_index; + + // + iUpper = open[ArrayMaximum(open, from, _length)]; + iLower = open[ArrayMinimum(open, from, _length)]; + + // + _ouBuffer[bar_index] = iUpper; + _olBuffer[bar_index] = iLower; + + // + // HIGH ... + + // + iUpper = high[ArrayMaximum(high, from, _length)]; + iLower = high[ArrayMinimum(high, from, _length)]; + + // + _huBuffer[bar_index] = iUpper; + _hlBuffer[bar_index] = iLower; + + // + // LOW ... + + // + iUpper = low[ArrayMaximum(low, from, _length)]; + iLower = low[ArrayMinimum(low, from, _length)]; + + // + _luBuffer[bar_index] = iUpper; + _llBuffer[bar_index] = iLower; + + // + // CLOSE ... + + // + iUpper = close[ArrayMaximum(close, from, _length)]; + iLower = close[ArrayMinimum(close, from, _length)]; + + // + _cuBuffer[bar_index] = iUpper; + _clBuffer[bar_index] = iLower; +} + +/** + * Calculate VWAP Required Data Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPDataBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double price = GetAppliedPrice( + vwapAppliedTo, + open, + high, + low, + close, + bar_index // + ); + vwapPriceBuffer[bar_index] = price; + vwapVolumeBuffer[bar_index] = (double)tickVolume[bar_index]; +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPS( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapFastLength, + showVWapFast, + vwapFastBuffer, + vwapFastColorBuffer, + vwapFastStateBuffer // + ); + + // + // Mid ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapMidLength, + showVWapMedium, + vwapMidBuffer, + vwapMidColorBuffer, + vwapMidStateBuffer // + ); + + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapSlowLength, + showVWapSlow, + vwapSlowBuffer, + vwapSlowColorBuffer, + vwapSlowStateBuffer // + ); +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateDonchains( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + CalculateDonchain( + // + bar_index, + prevCalculated, + ratesTotal, + // + open, + high, + close, + low, + tickVolume, + // + donchainLength, + // + donOpenUpperBuffer, + donOpenLowerBuffer, + donHighUpperBuffer, + donHighLowerBuffer, + donLowUpperBuffer, + donLowLowerBuffer, + donCloseUpperBuffer, + donCloseLowerBuffer // + ); +} + +/** + * Calculate ATR Zones ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateAtrZones( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Select ATr Value ... + double atrValue = atrBuffer[bar_index]; + double appliedAtrMultiplierValue = atrValue * atrMultiplier; + + // + // Select Upper Price ... + double upperPrice = GetAppliedPrice( + atrUpperAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Select Lower Price ... + double lowerPrice = GetAppliedPrice( + atrLowerAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Calculate Raw Atrs ... + + // + // Upper ... + double atrUpperRawValue = upperPrice + appliedAtrMultiplierValue; + atrUpperRawBuffer[bar_index] = atrUpperRawValue; + + // + // Lower ... + double atrLowerRawValue = lowerPrice - appliedAtrMultiplierValue; + atrLowerRawBuffer[bar_index] = atrLowerRawValue; + + // + bool canSmooth = atrSmoothingMode != X_MA_MODE_NONE; + if (canSmooth) + { + // + // Upper ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrUpperRawBuffer, + atrUpperBuffer, + atrSmoothingMode // + ); + + // + // Lower ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrLowerRawBuffer, + atrLowerBuffer, + atrSmoothingMode // + ); + } + else + { + // + // Use Raw Values ... + atrUpperBuffer[bar_index] = atrUpperRawValue; + atrLowerBuffer[bar_index] = atrLowerRawValue; + } +} + +/** + * Calculate STR ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateStr( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Calculated Price ... + double price = GetAppliedPrice( + strAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + strPriceBuffer[bar_index] = price; + + // + double atr = atrBuffer[bar_index]; + + // + double appliedAtr = (atrMultiplier * atr); + double strUp = price + appliedAtr; + double strDown = price - appliedAtr; + + // + strUpBuffer[bar_index] = strUp; + strDownBuffer[bar_index] = strDown; + + // + int currIDX = bar_index; + int prevIDX = currIDX + 1; + int prevOfPrevIDX = prevIDX + 1; + + // + double prevState = strStateBuffer[prevIDX]; + bool isCloseOverUp = close[currIDX] > strUpBuffer[prevIDX]; + bool isCloseUnderDown = close[currIDX] < strUpBuffer[prevIDX]; + + // + if (isCloseOverUp) + { + // + strStateBuffer[currIDX] = 1; + if (strStateBuffer[prevIDX] == -1) + { + isStrTrendChanged = true; + } + } + else if (isCloseUnderDown) + { + // + strStateBuffer[currIDX] = -1; + if (strStateBuffer[prevIDX] == 1) + { + isStrTrendChanged = true; + } + } + else if (strStateBuffer[prevIDX] == 1) + { + // + isStrTrendChanged = false; + strStateBuffer[currIDX] = 1; + } + else if (strStateBuffer[prevIDX] == -1) + { + // + isStrTrendChanged = false; + strStateBuffer[currIDX] = -1; + } + + // + // Calculate Trend Starting ... + + // + if (strStateBuffer[currIDX] < 0 && + strStateBuffer[prevIDX] > 0) + { + isStrStartBearishTrend = true; + } + else + { + isStrStartBearishTrend = false; + } + + // + if (strStateBuffer[currIDX] > 0 && + strStateBuffer[prevIDX] < 0) + { + isStrStartBullishTrend = true; + } + else + { + isStrStartBullishTrend = false; + } + + // + // Re new Up and Down Buffer ... + + // + if (strStateBuffer[currIDX] > 0 && + strDownBuffer[currIDX] < strDownBuffer[prevIDX]) + { + strDownBuffer[currIDX] = strDownBuffer[prevIDX]; + } + + // + if (strStateBuffer[currIDX] < 0 && + strUpBuffer[currIDX] > strUpBuffer[prevIDX]) + { + strUpBuffer[currIDX] = strUpBuffer[prevIDX]; + } + + // + // Handle Strat Trends ... + + // + if (isStrStartBearishTrend) + { + strUpBuffer[currIDX] = strPriceBuffer[currIDX] + (atrMultiplier * atr); + } + + // + if (isStrStartBullishTrend) + { + strDownBuffer[currIDX] = strPriceBuffer[currIDX] - (atrMultiplier * atr); + } + + // + double clr = hideColorIDX; + double state = hideColorIDX; + + // + if (strStateBuffer[currIDX] == 1) + { + // + strBuffer[currIDX] = strDownBuffer[currIDX]; + if (isStrTrendChanged) + { + // + isStrTrendChanged = false; + strBuffer[prevIDX] = strBuffer[prevOfPrevIDX]; + } + + // + clr = bullishColorIDX; + } + else if (state == -1) + { + // + strBuffer[currIDX] = strUpBuffer[currIDX]; + if (isStrTrendChanged) + { + // + isStrTrendChanged = false; + strBuffer[prevIDX] = strBuffer[prevOfPrevIDX]; + } + + // + clr = bearishColorIDX; + } + + // + if (!showStr) + { + clr = hideColorIDX; + } + + // + strColorBuffer[bar_index] = clr; + + // +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.helper.mq5 b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.helper.mq5 new file mode 100644 index 0000000..cbb3bf1 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.helper.mq5 @@ -0,0 +1,5171 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121Helper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... +enum ENUM_X121_BUFFERS +{ + // + // Main Buffers ... + X121_PEAKS_LINE = 0, + X121_VALES_LINE = 1, + X121_SAR_LINE = 2, + X121_ATR_UPPER_LINE = 3, + X121_ATR_LOWER_LINE = 4, + X121_VWAP_FAST_LINE = 5, + X121_VWAP_MID_LINE = 7, + X121_VWAP_SLOW_LINE = 9, + X121_DON_OPEN_UPPER_LINE = 11, + X121_DON_OPEN_LOWER_LINE = 12, + X121_DON_HIGH_UPPER_LINE = 13, + X121_DON_HIGH_LOWER_LINE = 14, + X121_DON_LOW_UPPER_LINE = 15, + X121_DON_LOW_LOWER_LINE = 16, + X121_DON_CLOSE_UPPER_LINE = 17, + X121_DON_CLOSE_LOWER_LINE = 18, + X121_FIB_LEVEL_1_LINE = 19, + X121_FIB_LEVEL_2_LINE = 20, + X121_FIB_LEVEL_3_LINE = 21, + X121_FIB_LEVEL_4_LINE = 22, + X121_FIB_LEVEL_5_LINE = 23, + // + // Data Buffers ... + // + // XPV Data ... + X121_CURRENT_HH_LINE = 24, + X121_CURRENT_LL_LINE = 25, + X121_SHORT_HH_LINE = 26, + X121_SHORT_LL_LINE = 27, + X121_MEDIUM_HH_LINE = 28, + X121_MEDIUM_LL_LINE = 29, + X121_LONG_HH_LINE = 30, + X121_LONG_LL_LINE = 31, + X121_HIND_HH_LINE = 32, + X121_HIND_LL_LINE = 33, + // + // VWAP Data ... + X121_VWAP_VOLUME_LINE = 34, + X121_VWAP_PRICE_LINE = 35, + X121_VWAP_FAST_STATE_LINE = 36, + X121_VWAP_MID_STATE_LINE = 37, + X121_VWAP_SLOW_STATE_LINE = 38, + // + // ATR ... + X121_ATR_LINE = 39, + X121_ATR_UPPER_RAW_LINE = 40, + X121_ATR_LOWER_RAW_LINE = 41, +}; + +// +enum ENUM_XVWAP_STATES +{ + // + XVWAP_STATE_BULLISH = 1, + XVWAP_STATE_BEARISH = 2, + XVWAP_STATE_NEUTURAL = 3, +}; + +// +// Inputs ... +struct X121Inputs +{ + // + // Props ... + + // + // Cycles ... + + // + // Short ... + ENUM_X_PERIOD_METHOD scMethod; // How to Find Period + ENUM_TIMEFRAMES scPeriod; // Time Period + + // + // Medium ... + ENUM_X_PERIOD_METHOD mcMethod; // How to Find Period + ENUM_TIMEFRAMES mcPeriod; // Time Period + + // + // Long ... + ENUM_X_PERIOD_METHOD lcMethod; // How to Find Period + ENUM_TIMEFRAMES lcPeriod; // Time Period + + // + // Hind ... + ENUM_X_PERIOD_METHOD hcMethod; // How to Find Period + ENUM_TIMEFRAMES hcPeriod; // Time Period + + // + // Boundary Detection ... + ENUM_SERIESMODE hhMode; // Highest High Calculation Method + ENUM_SERIESMODE llMode; // Lowest Low Calculation Method + + // + // Parabolic Sar Detection ... + double sarStep; // Step + double sarMax; // Maximum + + // + // RSI ... + int rsiLength; // RSI Length + double rsiOverSoldLevel; // RSI Over Sold Level + double rsiOverBoughtLevel; // RSI Over Bought Level + + // + // Atr Detection ... + int atrLength; // Length + double atrMultiplier; // Multiplier + ENUM_APPLIED_PRICE atrUpperAppliedTo; // Upper Zone Applied To + ENUM_APPLIED_PRICE atrLowerAppliedTo; // Lower Zone Applied To + ENUM_X_MA_METHOD atrSmoothingMode; // Smoothing Method + + // + // VWap Detection ... + int vwapFastLength; // Fast Length + int vwapMidLength; // Mid Length + int vwapSlowLength; // Slow Length + ENUM_APPLIED_PRICE vwapAppliedTo; // Applied To + + // + // Donchain Detection ... + int donchainLength; // Donchain Length + + // + // Fibonacci ... + double fiboLevel1; // Fibio 1st Level + double fiboLevel2; // Fibio 2st Level + double fiboLevel3; // Fibio 3rd Level + double fiboLevel4; // Fibio 4th Level + double fiboLevel5; // Fibio 5th Level + + // + // Presentation ... + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + int sarArrowCode; // Parabolic Sar Arrow Code + int peaksArrowCode; // Peaks Arrow Code + int valesArrowCode; // Vales Arrow Code + + // + // Global ... + bool showSar; // Show Parabolic Sar + bool showAtr; // Show Atr + bool showPeaks; // Show Peaks + bool showVales; // Show Vales + bool showVWap; // Show VWap + bool showDonchain; // Show Donchain + + // + // Fibonachi Presentation ... + bool showFibo1Levels; // Show Fibo 1st Level + bool showFibo2Levels; // Show Fibo 2nd Level + bool showFibo3Levels; // Show Fibo 3rd Level + bool showFibo4Levels; // Show Fibo 4th Level + bool showFibo5Levels; // Show Fibo 5th Level + + // + // Atr Presentation ... + bool showAtrUpper; // Show Upper Zone + bool showAtrLower; // Show Lower Zone + + // + // VWap Presentation ... + bool showVWapFast; // Show VWap Fast + bool showVWapMedium; // Show VWap Medium + bool showVWapSlow; // Show VWap Slow + + // + // Donchain Presentation ... + + // + bool showUpper; // Show Upper Band + bool showLower; // Show Lower Band + + // + bool showOpen; // Show Open + bool showHigh; // Show High + bool showClose; // Show Close + bool showLow; // Show Low + + // + // Constructor ... + X121Inputs() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Cycles ... + + // + // Short ... + scMethod = X_PERIOD_NOTHING; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_NOTHING; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_NOTHING; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_NOTHING; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + + // + // RSI ... + rsiLength = 0; + rsiOverSoldLevel = 0; + rsiOverBoughtLevel = 0; + + // + // Paraboli Sar Detection ... + sarStep = 0; + sarMax = 0; + + // + // Atr Detection ... + atrLength = 0; // Length + atrMultiplier = 0; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_NONE; // Smoothing Method + + // + // VWap Detection ... + vwapFastLength = 0; + vwapMidLength = 0; + vwapSlowLength = 0; + vwapAppliedTo = PRICE_CLOSE; + + // + // Donchain Detection ... + donchainLength = 0; + + // + // Fibonacci ... + fiboLevel1 = 0; + fiboLevel2 = 0; + fiboLevel3 = 0; + fiboLevel4 = 0; + fiboLevel5 = 0; + + // + // Presentation ... + + // + startCalculationForLastBars = 0; + + // + sarArrowCode = 0; + peaksArrowCode = 0; + valesArrowCode = 0; + + // + // Globals ... + showSar = false; + showAtr = false; + showPeaks = false; + showVales = false; + showVWap = false; + showDonchain = false; + + // + // Fibonachi Presentation ... + showFibo1Levels = false; + showFibo2Levels = false; + showFibo3Levels = false; + showFibo4Levels = false; + showFibo5Levels = false; + + // + // Atr Presentation ... + showAtrUpper = false; // Show Upper Zone + showAtrLower = false; // Show Lower Zone + + // + // VWap Presentation ... + showVWapFast = false; + showVWapMedium = false; + showVWapSlow = false; + + // + // Donchain Presentation ... + + // + showUpper = false; + showLower = false; + + // + showOpen = false; + showHigh = false; + showClose = false; + showLow = false; + } + + /** + * Set Default Values ... + */ + void Default() + { + // + // Cycles ... + + // + // Short ... + scMethod = X_PERIOD_AUTO; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_AUTO; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_AUTO; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_AUTO; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + + // + // RSI ... + rsiLength = 14; + rsiOverSoldLevel = 30; + rsiOverBoughtLevel = 70; + + // + // Paraboli Sar Detection ... + sarStep = 0.02; + sarMax = 0.2; + + // + // Atr Detection ... + atrLength = 14; // Length + atrMultiplier = 1; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + + // + // VWap Detection ... + vwapFastLength = 20; + vwapMidLength = 40; + vwapSlowLength = 60; + vwapAppliedTo = PRICE_CLOSE; + + // + // Donchain Detection ... + donchainLength = 40; + + // + // Fibonacci ... + fiboLevel1 = 0.236; + fiboLevel2 = 0.382; + fiboLevel3 = 0.5; + fiboLevel4 = 0.618; + fiboLevel5 = 0.764; + + // + // Presentation ... + + // + startCalculationForLastBars = 1500; + + // + sarArrowCode = 159; + peaksArrowCode = 159; + valesArrowCode = 159; + + // + // Globals ... + showSar = true; + showAtr = true; + showPeaks = true; + showVales = true; + showVWap = true; + showDonchain = true; + + // + // Fibonachi Presentation ... + showFibo1Levels = false; + showFibo2Levels = false; + showFibo3Levels = true; + showFibo4Levels = false; + showFibo5Levels = false; + + // + // Atr Presentation ... + showAtrUpper = true; // Show Upper Zone + showAtrLower = true; // Show Lower Zone + + // + // VWap Presentation ... + showVWapFast = true; + showVWapMedium = true; + showVWapSlow = true; + + // + // Donchain Presentation ... + + // + showUpper = true; + showLower = true; + + // + showOpen = true; + showHigh = false; + showClose = true; + showLow = false; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + // RSI ... + rsiLength > 0 && + rsiOverSoldLevel > 0 && + rsiOverBoughtLevel > 0 && + rsiOverSoldLevel < rsiOverBoughtLevel && + // PSAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 && + // + // XDON ... + donchainLength > 0 && + // + // VWAP ... + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; + } + + /** + * Extract Max Input Length ... + * + * @return ( int ) + */ + int Max() + { + // + int result = 0; + + // + // VWAP ... + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapMidLength); + + // + // ATR ... + result = MathMax(result, atrLength); + result = MathMax(result, rsiLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121Conditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double sarBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double fl1Buffer[]; + double fl2Buffer[]; + double fl3Buffer[]; + double fl4Buffer[]; + double fl5Buffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + double atrBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + double rsiBuffer[]; + + // + // Conditions ... + + // + // XRSI ... + + // + bool isRSIOverBought; + bool isRSICrossedOverOverBought; + bool isRSICrossedUnderOverBought; + + // + bool isRSIOverSold; + bool isRSICrossedUnderOverSold; + bool isRSICrossedOverOverSold; + + // + // XSAR ... + + // + bool isSarBullish; + bool isSarBearish; + + // + bool isSarSwitchedToBullish; + bool isSarSwitchedToBearish; + + // + // XPV ... + + // + bool isNewPeak; + bool isNewPeakOverLast; + bool isNewPeakUnderLast; + + // + bool isNewVale; + bool isNewValeOverLast; + bool isNewValeUnderLast; + + // + // XVWAP ... + + // + bool isVWapFastBullish; + bool isVWapFastBearish; + bool isVWapFastNeutural; + + // + bool isVWapMidBullish; + bool isVWapMidBearish; + bool isVWapMidNeutural; + + // + bool isVWapSlowBullish; + bool isVWapSlowBearish; + bool isVWapSlowNeutural; + + // + bool isVWapFastOverMid; + bool isVWapMidOverSlow; + + // + bool isVWapFastUnderMid; + bool isVWapMidUnderSlow; + + // + bool isVWapBullishState; + bool isVWapBearishState; + bool isVWapNeuturalState; + + // + bool isVWapBullishOrdered; + bool isVWapBearishOrdered; + + // + bool isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered; + + // + bool isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState; + bool isVWapSwitchedToNeuturalState; + + // + // XDON ... + + // + // bool isCloseLower + + // + // XFIBONACCI ... + + // + bool isOerFib1; + bool isOerFib2; + bool isOerFib3; + bool isOerFib4; + bool isOerFib5; + + // + bool isUnderFib1; + bool isUnderFib2; + bool isUnderFib3; + bool isUnderFib4; + bool isUnderFib5; + + // + bool isCloseOerFib1; + bool isCloseOerFib2; + bool isCloseOerFib3; + bool isCloseOerFib4; + bool isCloseOerFib5; + + // + bool isCloseUnderFib1; + bool isCloseUnderFib2; + bool isCloseUnderFib3; + bool isCloseUnderFib4; + bool isCloseUnderFib5; + + // + // Constructor ... + X121Conditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(sarBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(vwapFastBuffer); + Clean(vwapMidBuffer); + Clean(vwapSlowBuffer); + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(fl1Buffer); + Clean(fl2Buffer); + Clean(fl3Buffer); + Clean(fl4Buffer); + Clean(fl5Buffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + Clean(atrBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + Clean(vwapVolumeBuffer); + Clean(vwapPriceBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapMidStateBuffer); + Clean(vwapSlowStateBuffer); + Clean(rsiBuffer); + + // + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(fl1Buffer, true); + ArraySetAsSeries(fl2Buffer, true); + ArraySetAsSeries(fl3Buffer, true); + ArraySetAsSeries(fl4Buffer, true); + ArraySetAsSeries(fl5Buffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + + // + // Conditions ... + + // + // XRSI ... + + // + isRSIOverBought = false; + isRSICrossedUnderOverBought = false; + isRSICrossedOverOverBought = false; + + // + isRSIOverSold = false; + isRSICrossedOverOverSold = false; + isRSICrossedUnderOverSold = false; + + // + // XSAR ... + + // + isSarBullish = false; + isSarBearish = false; + + // + isSarSwitchedToBullish = false; + isSarSwitchedToBearish = false; + + // + // XPV ... + + // + isNewPeak = false; + isNewPeakOverLast = false; + isNewPeakUnderLast = false; + + // + isNewVale = false; + isNewValeOverLast = false; + isNewValeUnderLast = false; + + // + // XVWAP ... + + // + isVWapFastBullish = false; + isVWapFastBearish = false; + isVWapFastNeutural = false; + + // + isVWapMidBullish = false; + isVWapMidBearish = false; + isVWapMidNeutural = false; + + // + isVWapSlowBullish = false; + isVWapSlowBearish = false; + isVWapSlowNeutural = false; + + // + isVWapFastOverMid = false; + isVWapMidOverSlow = false; + + // + isVWapFastUnderMid = false; + isVWapMidUnderSlow = false; + + // + isVWapBullishState = false; + isVWapBearishState = false; + isVWapNeuturalState = false; + + // + isVWapBullishOrdered = false; + isVWapBearishOrdered = false; + + // + isVWapSwitchedToBullishOrdered = false; + isVWapSwitchedToBearishOrdered = false; + + // + isVWapSwitchedToBullishState = false; + isVWapSwitchedToBearishState = false; + isVWapSwitchedToNeuturalState = false; + + // + // XDON ... + + // + // XFIBONACCI ... + + // + isOerFib1 = false; + isOerFib2 = false; + isOerFib3 = false; + isOerFib4 = false; + isOerFib5 = false; + + // + isUnderFib1 = false; + isUnderFib2 = false; + isUnderFib3 = false; + isUnderFib4 = false; + isUnderFib5 = false; + + // + isCloseOerFib1 = false; + isCloseOerFib2 = false; + isCloseOerFib3 = false; + isCloseOerFib4 = false; + isCloseOerFib5 = false; + + // + isCloseUnderFib1 = false; + isCloseUnderFib2 = false; + isCloseUnderFib3 = false; + isCloseUnderFib4 = false; + isCloseUnderFib5 = false; + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + // TODO: Implement this if required ... + string conditionsStr = + // + // XSAR ... + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + + ToString("isSarBearish", isSarBearish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBullish", isSarSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBearish", isSarSwitchedToBearish, ignoreFalseConditions, separator) + + // + // XPV ... + ToString("isNewPeak", isNewPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverLast", isNewPeakOverLast, ignoreFalseConditions, separator) + + ToString("isNewPeakUnderLast", isNewPeakUnderLast, ignoreFalseConditions, separator) + + ToString("isNewVale", isNewVale, ignoreFalseConditions, separator) + + ToString("isNewValeOverLast", isNewValeOverLast, ignoreFalseConditions, separator) + + ToString("isNewValeUnderLast", isNewValeUnderLast, ignoreFalseConditions, separator) + + // + // XVWAP ... + ToString("isVWapFastBullish", isVWapFastBullish, ignoreFalseConditions, separator) + + ToString("isVWapFastBearish", isVWapFastBearish, ignoreFalseConditions, separator) + + ToString("isVWapFastNeutural", isVWapFastNeutural, ignoreFalseConditions, separator) + + ToString("isVWapMidBullish", isVWapMidBullish, ignoreFalseConditions, separator) + + ToString("isVWapMidBearish", isVWapMidBearish, ignoreFalseConditions, separator) + + ToString("isVWapMidNeutural", isVWapMidNeutural, ignoreFalseConditions, separator) + + ToString("isVWapSlowBullish", isVWapSlowBullish, ignoreFalseConditions, separator) + + ToString("isVWapSlowBearish", isVWapSlowBearish, ignoreFalseConditions, separator) + + ToString("isVWapSlowNeutural", isVWapSlowNeutural, ignoreFalseConditions, separator) + + ToString("isVWapFastOverMid", isVWapFastOverMid, ignoreFalseConditions, separator) + + ToString("isVWapMidOverSlow", isVWapMidOverSlow, ignoreFalseConditions, separator) + + ToString("isVWapFastUnderMid", isVWapFastUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapMidUnderSlow", isVWapMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isVWapBullishState", isVWapBullishState, ignoreFalseConditions, separator) + + ToString("isVWapBearishState", isVWapBearishState, ignoreFalseConditions, separator) + + ToString("isVWapNeuturalState", isVWapNeuturalState, ignoreFalseConditions, separator) + + ToString("isVWapBullishOrdered", isVWapBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapBearishOrdered", isVWapBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishOrdered", isVWapSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishOrdered", isVWapSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishState", isVWapSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishState", isVWapSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToNeuturalState", isVWapSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + // XFIBONACCI ... + ToString("isOerFib1", isOerFib1, ignoreFalseConditions, separator) + + ToString("isOerFib2", isOerFib2, ignoreFalseConditions, separator) + + ToString("isOerFib3", isOerFib3, ignoreFalseConditions, separator) + + ToString("isOerFib4", isOerFib4, ignoreFalseConditions, separator) + + ToString("isOerFib5", isOerFib5, ignoreFalseConditions, separator) + + ToString("isUnderFib1", isUnderFib1, ignoreFalseConditions, separator) + + ToString("isUnderFib2", isUnderFib2, ignoreFalseConditions, separator) + + ToString("isUnderFib3", isUnderFib3, ignoreFalseConditions, separator) + + ToString("isUnderFib4", isUnderFib4, ignoreFalseConditions, separator) + + ToString("isUnderFib5", isUnderFib5, ignoreFalseConditions, separator) + + ToString("isCloseOerFib1", isCloseOerFib1, ignoreFalseConditions, separator) + + ToString("isCloseOerFib2", isCloseOerFib2, ignoreFalseConditions, separator) + + ToString("isCloseOerFib3", isCloseOerFib3, ignoreFalseConditions, separator) + + ToString("isCloseOerFib4", isCloseOerFib4, ignoreFalseConditions, separator) + + ToString("isCloseOerFib5", isCloseOerFib5, ignoreFalseConditions, separator) + + ToString("isCloseUnderFib1", isCloseUnderFib1, ignoreFalseConditions, separator) + + ToString("isCloseUnderFib2", isCloseUnderFib2, ignoreFalseConditions, separator) + + ToString("isCloseUnderFib3", isCloseUnderFib3, ignoreFalseConditions, separator) + + ToString("isCloseUnderFib4", isCloseUnderFib4, ignoreFalseConditions, separator) + + ToString("isCloseUnderFib5", isCloseUnderFib5, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Implementation ... + +class XCX121Helper : public XCBaseHelper +{ + // + public: + // + + // + // Constructors ... + XCX121Helper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121Helper() + { + IndicatorRelease(mRSIHandler); + } + + // + // Tools ... + + /** + * Initialize Indicator Helper ... + * + * @param symbol: String, Symbol ... + * @param period: ENUM_TIMEFRAMES member, Period ... + * @param inputs: X121Inputs instance, Indicator Inputs ... + * + * @return ( bool ) + */ + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121Inputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + // Validate Inputs ... + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + // Setting Arrays As Series ... + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(fl1Buffer, true); + ArraySetAsSeries(fl2Buffer, true); + ArraySetAsSeries(fl3Buffer, true); + ArraySetAsSeries(fl4Buffer, true); + ArraySetAsSeries(fl5Buffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121", + // + // Inputs ... + // + // Cycles ... + "", + // + // Short ... + "", + mInputs.scMethod, + mInputs.scPeriod, + // + // Medium ... + "", + mInputs.mcMethod, + mInputs.mcPeriod, + // + // Long ... + "", + mInputs.lcMethod, + mInputs.lcPeriod, + // + // Hind ... + "", + mInputs.hcMethod, + mInputs.hcPeriod, + // + // Boundary Detection ... + "", + mInputs.hhMode, + mInputs.llMode, + // + // Parabolic Sar Detection ... + "", + mInputs.sarStep, + mInputs.sarMax, + // + // Atr Detection ... + "", + mInputs.atrLength, + mInputs.atrMultiplier, + mInputs.atrUpperAppliedTo, + mInputs.atrLowerAppliedTo, + mInputs.atrSmoothingMode, + // + // VWap Detection ... + "", + mInputs.vwapFastLength, + mInputs.vwapMidLength, + mInputs.vwapSlowLength, + mInputs.vwapAppliedTo, + // + // Donchain Detection ... + "", + mInputs.donchainLength, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + // + // Commons ... + mInputs.showSar, + mInputs.showAtr, + mInputs.showPeaks, + mInputs.showVales, + mInputs.showVWap, + mInputs.showDonchain, + // + // Fibonachi Presentation ... + "", + mInputs.showFibo1Levels, + mInputs.showFibo2Levels, + mInputs.showFibo3Levels, + mInputs.showFibo4Levels, + mInputs.showFibo5Levels, + // + // Atr Presentation ... + "", + mInputs.showAtrUpper, + mInputs.showAtrLower, + // + // VWap Presentation ... + "", + mInputs.showVWapFast, + mInputs.showVWapMedium, + mInputs.showVWapSlow, + // + // Donchain Presentation ... + "", + mInputs.showUpper, + mInputs.showLower, + mInputs.showOpen, + mInputs.showHigh, + mInputs.showClose, + mInputs.showLow + // + // Non Important Inpust ... + // + // Fibonacci ... + // "", + // mInputs.fiboLevel1, + // mInputs.fiboLevel2, + // mInputs.fiboLevel3, + // mInputs.fiboLevel4, + // mInputs.fiboLevel5, + // // + // mInputs.sarArrowCode, + // mInputs.peaksArrowCode, + // mInputs.valesArrowCode + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + mRSIHandler = iRSI( + symbol, + period, + mInputs.rsiLength, + PRICE_CLOSE // + ); + result = mRSIHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Retrieve Current Indicator Configs ... + * + * @return ( Inputs ) + */ + X121Inputs GetInputs() + { + return mInputs; + } + + /** + * Set New Indicator Inputs ... + * + * @param inputs: X121Inputs instance, Indicator Inputs ... + * + * @return ( bool ) + */ + bool SetInputs( + X121Inputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Implement Value Getters ... + + // + // XRSI ... + + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(rsiBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return rsiBuffer[barIndex]; + } + + // + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rsiBuffer, + buffer, + forceClean + // + ); + } + + // + // SAR ... + + // + double GetSar( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sarBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sarBuffer[barIndex]; + } + + // + int CopySar( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sarBuffer, + buffer, + forceClean + // + ); + } + + // + // ATR ... + + // + // Common ... + + // + double GetAtr( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrBuffer[barIndex]; + } + + // + int CopyAtr( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperBuffer[barIndex]; + } + + // + int CopyAtrUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrUpperRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperRawBuffer[barIndex]; + } + + // + int CopyAtrUpperRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperRawBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerBuffer[barIndex]; + } + + // + int CopyAtrLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerBuffer, + buffer, + forceClean + // + ); + } + + // + double GetAtrLowerRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerRawBuffer[barIndex]; + } + + // + int CopyAtrLowerRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerRawBuffer, + buffer, + forceClean + // + ); + } + + // + // PV ... + + // + // PEAKS ... + + // + double GetPeak( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(peaksBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return peaksBuffer[barIndex]; + } + + // + int CopyPeak( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + peaksBuffer, + buffer, + forceClean + // + ); + } + + // + // VALES ... + + // + double GetVale( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(valesBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return valesBuffer[barIndex]; + } + + // + int CopyVale( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + valesBuffer, + buffer, + forceClean + // + ); + } + + // + // + // + + // + double GetHigherPeak( + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(index); + if (iValue > peak) + { + // + result = iValue; + break; + } + + // + canContinue = index < barIndex + loopback; + index++; + } + + // + return result; + } + + // + double GetLowerPeak( + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(index); + if (iValue < peak) + { + // + result = iValue; + break; + } + + // + canContinue = index < barIndex + loopback; + index++; + } + + // + return result; + } + + // + double GetHigherVale( + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(index); + if (iValue > vale) + { + // + result = iValue; + break; + } + + // + canContinue = index > barIndex + loopback; + index++; + } + + // + return result; + } + + // + double GetLowerVale( + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int index = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(index); + if (iValue < vale) + { + // + result = iValue; + break; + } + + // + canContinue = index > barIndex + loopback; + index++; + } + + // + return result; + } + + // + // + // + + // + double GetLowestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetHighestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetLowestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + double GetHighestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + // CURRENT ... + + // + // HH ... + + // + double GetCHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cHHBuffer[barIndex]; + } + + // + int CopyCHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetCLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cLLBuffer[barIndex]; + } + + // + int CopyCLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cLLBuffer, + buffer, + forceClean + // + ); + } + + // + // SHORT ... + + // + // HH ... + + // + double GetSHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sHHBuffer[barIndex]; + } + + // + int CopySHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetSLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sLLBuffer[barIndex]; + } + + // + int CopySLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sLLBuffer, + buffer, + forceClean + // + ); + } + + // + // MEDIUM ... + + // + // HH ... + + // + double GetMHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mHHBuffer[barIndex]; + } + + // + int CopyMHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetMLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mLLBuffer[barIndex]; + } + + // + int CopyMLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mLLBuffer, + buffer, + forceClean + // + ); + } + + // + // LONG ... + + // + // HH ... + + // + double GetLHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lHHBuffer[barIndex]; + } + + // + int CopyLHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetLLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lLLBuffer[barIndex]; + } + + // + int CopyLLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lLLBuffer, + buffer, + forceClean + // + ); + } + + // + // HIND ... + + // + // HH ... + + // + double GetHHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hHHBuffer[barIndex]; + } + + // + int CopyHHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetHLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hLLBuffer[barIndex]; + } + + // + int CopyHLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hLLBuffer, + buffer, + forceClean + // + ); + } + + // + // VWAP ... + + // + // FAST ... + + // + double GetVWapFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastBuffer[barIndex]; + } + + // + int CopyVWapFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE FAST ... + + // + double GetVWapFastState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastStateBuffer[barIndex]; + } + + // + int CopyVWapFastState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastStateBuffer, + buffer, + forceClean + // + ); + } + + // + // MID ... + + // + double GetVWapMid( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidBuffer[barIndex]; + } + + // + int CopyVWapMid( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE MID ... + + // + double GetVWapMidState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidStateBuffer[barIndex]; + } + + // + int CopyVWapMidState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidStateBuffer, + buffer, + forceClean + // + ); + } + + // + // SLOW ... + + // + double GetVWapSlowBuffer( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowBuffer[barIndex]; + } + + // + int CopyVWapSlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE SLOW ... + + // + double GetVWapSlowState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowStateBuffer[barIndex]; + } + + // + int CopyVWapSlowState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowStateBuffer, + buffer, + forceClean + // + ); + } + + // + // VOLUME ... + + // + double GetVWapVolume( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapVolumeBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapVolumeBuffer[barIndex]; + } + + // + int CopyVWapVolume( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapVolumeBuffer, + buffer, + forceClean + // + ); + } + + // + // PRICE ... + + // + double GetVWapPrice( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapPriceBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapPriceBuffer[barIndex]; + } + + // + int CopyVWapPrice( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapPriceBuffer, + buffer, + forceClean + // + ); + } + + // + // Converts to State ... + ENUM_XVWAP_STATES ToVWAPState(double value) + { + // + ENUM_XVWAP_STATES result = + value == 1 + ? XVWAP_STATE_BULLISH + : value == 2 + ? XVWAP_STATE_BEARISH + : XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + bool IsVWAPBullish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BULLISH; + + // + return result; + } + + // + bool IsVWAPBearish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BEARISH; + + // + return result; + } + + // + bool IsVWAPNeutural(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + // XDON ... + + // + // OPEN ... + + // + // UPPER ... + + // + double GetDonOpenUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenUpperBuffer[barIndex]; + } + + // + int CopyDonOpenUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonOpenLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenLowerBuffer[barIndex]; + } + + // + int CopyDonOpenLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // CLOSE ... + + // + // UPPER ... + + // + double GetDonCloseUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseUpperBuffer[barIndex]; + } + + // + int CopyDonCloseUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonCloseLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseLowerBuffer[barIndex]; + } + + // + int CopyDonCloseLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // HIGH ... + + // + // UPPER ... + + // + double GetDonHighUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighUpperBuffer[barIndex]; + } + + // + int CopyDonHighUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonHighLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighLowerBuffer[barIndex]; + } + + // + int CopyDonHighLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // LOW ... + + // + // UPPER ... + + // + double GetDonLowUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowUpperBuffer[barIndex]; + } + + // + int CopyDonLowUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonLoweLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowLowerBuffer[barIndex]; + } + + // + int CopyDonLoweLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // FIBONACCHI ... + + // + // LEVEL 1 ... + + // + double GetFiboLevel1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(fl1Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return fl1Buffer[barIndex]; + } + + // + int CopyFiboLevel1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // FiboLevel To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fl1Buffer, + buffer, + forceClean + // + ); + } + + // + // LEVEL 2 ... + + // + double GetFiboLevel2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(fl2Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return fl2Buffer[barIndex]; + } + + // + int CopyFiboLevel2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // FiboLevel To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fl2Buffer, + buffer, + forceClean + // + ); + } + + // + // LEVEL 3 ... + + // + double GetFiboLevel3( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(fl3Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return fl3Buffer[barIndex]; + } + + // + int CopyFiboLevel3( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // FiboLevel To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fl3Buffer, + buffer, + forceClean + // + ); + } + + // + // LEVEL 4 ... + + // + double GetFiboLevel4( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(fl4Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return fl4Buffer[barIndex]; + } + + // + int CopyFiboLevel4( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // FiboLevel To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fl4Buffer, + buffer, + forceClean + // + ); + } + + // + // LEVEL 5 ... + + // + double GetFiboLevel5( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(fl5Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return fl5Buffer[barIndex]; + } + + // + int CopyFiboLevel5( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // FiboLevel To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fl5Buffer, + buffer, + forceClean + // + ); + } + + // + // Conditions Generation ... + + bool GetConditions( + X121Conditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyRSI( + zIndex, + loopback, + conditions.rsiBuffer // + ); + + // + CopySar( + zIndex, + loopback, + conditions.sarBuffer // + ); + + // + CopyAtr( + zIndex, + loopback, + conditions.atrBuffer // + ); + + // + CopyAtrUpper( + zIndex, + loopback, + conditions.atrUpperBuffer // + ); + + // + CopyAtrUpperRaw( + zIndex, + loopback, + conditions.atrUpperRawBuffer // + ); + + // + CopyAtrLower( + zIndex, + loopback, + conditions.atrLowerBuffer // + ); + + // + CopyAtrLowerRaw( + zIndex, + loopback, + conditions.atrLowerRawBuffer // + ); + + // + CopyPeak( + zIndex, + loopback, + conditions.peaksBuffer // + ); + + // + CopyVale( + zIndex, + loopback, + conditions.valesBuffer // + ); + + // + CopyCHH( + zIndex, + loopback, + conditions.cHHBuffer // + ); + + // + CopyCLL( + zIndex, + loopback, + conditions.cLLBuffer // + ); + + // + CopySHH( + zIndex, + loopback, + conditions.sHHBuffer // + ); + + // + CopySLL( + zIndex, + loopback, + conditions.sLLBuffer // + ); + + // + CopyMHH( + zIndex, + loopback, + conditions.mHHBuffer // + ); + + // + CopyMLL( + zIndex, + loopback, + conditions.mLLBuffer // + ); + + // + CopyLHH( + zIndex, + loopback, + conditions.lHHBuffer // + ); + + // + CopyLLL( + zIndex, + loopback, + conditions.lLLBuffer // + ); + + // + CopyHHH( + zIndex, + loopback, + conditions.hHHBuffer // + ); + + // + CopyHLL( + zIndex, + loopback, + conditions.hLLBuffer // + ); + + // + CopyVWapFast( + zIndex, + loopback, + conditions.vwapFastBuffer // + ); + + // + CopyVWapFastState( + zIndex, + loopback, + conditions.vwapFastStateBuffer // + ); + + // + CopyVWapMid( + zIndex, + loopback, + conditions.vwapMidBuffer // + ); + + // + CopyVWapMidState( + zIndex, + loopback, + conditions.vwapMidStateBuffer // + ); + + // + CopyVWapSlow( + zIndex, + loopback, + conditions.vwapSlowBuffer // + ); + + // + CopyVWapSlowState( + zIndex, + loopback, + conditions.vwapSlowStateBuffer // + ); + + // + CopyVWapVolume( + zIndex, + loopback, + conditions.vwapVolumeBuffer // + ); + + // + CopyVWapPrice( + zIndex, + loopback, + conditions.vwapPriceBuffer // + ); + + // + CopyDonOpenUpper( + zIndex, + loopback, + conditions.donOpenUpperBuffer // + ); + + // + CopyDonOpenLower( + zIndex, + loopback, + conditions.donOpenLowerBuffer // + ); + + // + CopyDonCloseUpper( + zIndex, + loopback, + conditions.donCloseUpperBuffer // + ); + + // + CopyDonCloseLower( + zIndex, + loopback, + conditions.donCloseLowerBuffer // + ); + + // + CopyDonHighUpper( + zIndex, + loopback, + conditions.donHighUpperBuffer // + ); + + // + CopyDonHighLower( + zIndex, + loopback, + conditions.donHighLowerBuffer // + ); + + // + CopyDonLowUpper( + zIndex, + loopback, + conditions.donLowUpperBuffer // + ); + + // + CopyDonLoweLower( + zIndex, + loopback, + conditions.donLowLowerBuffer // + ); + + // + CopyFiboLevel1( + zIndex, + loopback, + conditions.fl1Buffer // + ); + + // + CopyFiboLevel2( + zIndex, + loopback, + conditions.fl2Buffer // + ); + + // + CopyFiboLevel3( + zIndex, + loopback, + conditions.fl3Buffer // + ); + + // + CopyFiboLevel4( + zIndex, + loopback, + conditions.fl4Buffer // + ); + + // + CopyFiboLevel5( + zIndex, + loopback, + conditions.fl5Buffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // XRSI ... + + // + bool isRSIOverBought = conditions.rsiBuffer[cIDX] > mInputs.rsiOverBoughtLevel; + bool isRSIOverBoughtPrev = conditions.rsiBuffer[pIDX] > mInputs.rsiOverBoughtLevel; + + // + bool isRSICrossedOverOverBought = isRSIOverBought && + !isRSIOverBoughtPrev; + bool isRSICrossedUnderOverBought = !isRSIOverBought && + isRSIOverBoughtPrev; + + // + bool isRSIOverSold = conditions.rsiBuffer[cIDX] < mInputs.rsiOverSoldLevel; + bool isRSIOverSoldPrev = conditions.rsiBuffer[pIDX] < mInputs.rsiOverSoldLevel; + + // + bool isRSICrossedUnderOverSold = isRSIOverSold && + !isRSIOverSoldPrev; + bool isRSICrossedOverOverSold = !isRSIOverSold && + isRSIOverSoldPrev; + + // + // XSAR ... + + // + bool isSarBullish = conditions.sarBuffer[cIDX] < cBar.low; + bool isSarBullishPrev = conditions.sarBuffer[pIDX] < pBar.low; + + // + bool isSarBearish = conditions.sarBuffer[cIDX] > cBar.high; + bool isSarBearishPrev = conditions.sarBuffer[pIDX] > pBar.high; + + // + bool isSarSwitchedToBullish = isSarBullish && + !isSarBullishPrev; + bool isSarSwitchedToBearish = isSarBearish && + !isSarBearishPrev; + + // + // XPV ... + + // + bool isNewPeak = conditions.peaksBuffer[cIDX] != conditions.peaksBuffer[pIDX]; + bool isNewPeakOverLast = isNewPeak && + conditions.peaksBuffer[cIDX] > conditions.peaksBuffer[pIDX]; + bool isNewPeakUnderLast = isNewPeak && + conditions.peaksBuffer[cIDX] < conditions.peaksBuffer[pIDX]; + + // + bool isNewVale = conditions.valesBuffer[cIDX] != conditions.valesBuffer[pIDX]; + bool isNewValeOverLast = isNewVale && + conditions.valesBuffer[cIDX] > conditions.valesBuffer[pIDX]; + bool isNewValeUnderLast = isNewVale && + conditions.valesBuffer[cIDX] < conditions.valesBuffer[pIDX]; + + // + // XVWAP ... + + // + bool isVWapFastBullish = IsVWAPBullish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBullishPrev = IsVWAPBullish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastBearish = IsVWAPBearish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBearishPrev = IsVWAPBearish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastNeutural = IsVWAPNeutural(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastNeuturalPrev = IsVWAPNeutural(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapMidBullish = IsVWAPBullish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBullishPrev = IsVWAPBullish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidBearish = IsVWAPBearish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBearishPrev = IsVWAPBearish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidNeutural = IsVWAPNeutural(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidNeuturalPrev = IsVWAPNeutural(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapSlowBullish = IsVWAPBullish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBullishPrev = IsVWAPBullish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowBearish = IsVWAPBearish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBearishPrev = IsVWAPBearish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowNeutural = IsVWAPNeutural(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowNeuturalPrev = IsVWAPNeutural(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapFastOverMid = conditions.vwapFastBuffer[cIDX] > conditions.vwapMidBuffer[cIDX]; + bool isVWapFastOverMidPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidOverSlow = conditions.vwapMidBuffer[cIDX] > conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidOverSlowPrev = conditions.vwapMidBuffer[pIDX] > conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFastUnderMid = conditions.vwapFastBuffer[cIDX] < conditions.vwapMidBuffer[cIDX]; + bool isVWapFastUnderMidPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidUnderSlow = conditions.vwapMidBuffer[cIDX] < conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidUnderSlowPrev = conditions.vwapMidBuffer[pIDX] < conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapBullishState = isVWapFastBullish && + isVWapMidBullish && + isVWapSlowBullish; + bool isVWapBullishStatePrev = isVWapFastBullishPrev && + isVWapMidBullishPrev && + isVWapSlowBullishPrev; + + // + bool isVWapBearishState = isVWapFastBearish && + isVWapMidBearish && + isVWapSlowBearish; + bool isVWapBearishStatePrev = isVWapFastBearishPrev && + isVWapMidBearishPrev && + isVWapSlowBearishPrev; + + // + bool isVWapNeuturalState = isVWapFastNeutural && + isVWapMidNeutural && + isVWapSlowNeutural; + bool isVWapNeuturalStatePrev = isVWapFastNeuturalPrev && + isVWapMidNeuturalPrev && + isVWapSlowNeuturalPrev; + + // + bool isVWapBullishOrdered = isVWapFastOverMid && + isVWapMidOverSlow; + bool isVWapBullishOrderedPrev = isVWapFastOverMidPrev && + isVWapMidOverSlowPrev; + + // + bool isVWapBearishOrdered = isVWapFastUnderMid && + isVWapMidUnderSlow; + bool isVWapBearishOrderedPrev = isVWapFastUnderMidPrev && + isVWapMidUnderSlowPrev; + + // + bool isVWapSwitchedToBullishOrdered = isVWapBullishOrdered && + !isVWapBullishOrderedPrev; + bool isVWapSwitchedToBearishOrdered = isVWapBearishOrdered && + !isVWapBearishOrderedPrev; + + // + bool isVWapSwitchedToBullishState = isVWapBullishState && + !isVWapBullishStatePrev; + bool isVWapSwitchedToBearishState = isVWapBearishState && + !isVWapBearishStatePrev; + bool isVWapSwitchedToNeuturalState = isVWapNeuturalState && + !isVWapNeuturalStatePrev; + + // + // XDON ... + + // + // XFIBONACCI ... + + // + bool isOerFib1 = cBar.low > conditions.fl1Buffer[cIDX]; + bool isOerFib2 = cBar.low > conditions.fl2Buffer[cIDX]; + bool isOerFib3 = cBar.low > conditions.fl3Buffer[cIDX]; + bool isOerFib4 = cBar.low > conditions.fl4Buffer[cIDX]; + bool isOerFib5 = cBar.low > conditions.fl5Buffer[cIDX]; + + // + bool isUnderFib1 = cBar.high < conditions.fl1Buffer[cIDX]; + bool isUnderFib2 = cBar.high < conditions.fl2Buffer[cIDX]; + bool isUnderFib3 = cBar.high < conditions.fl3Buffer[cIDX]; + bool isUnderFib4 = cBar.high < conditions.fl4Buffer[cIDX]; + bool isUnderFib5 = cBar.high < conditions.fl5Buffer[cIDX]; + + // + bool isCloseOerFib1 = cBar.close > conditions.fl1Buffer[cIDX]; + bool isCloseOerFib2 = cBar.close > conditions.fl2Buffer[cIDX]; + bool isCloseOerFib3 = cBar.close > conditions.fl3Buffer[cIDX]; + bool isCloseOerFib4 = cBar.close > conditions.fl4Buffer[cIDX]; + bool isCloseOerFib5 = cBar.close > conditions.fl5Buffer[cIDX]; + + // + bool isCloseUnderFib1 = cBar.close < conditions.fl1Buffer[cIDX]; + bool isCloseUnderFib2 = cBar.close < conditions.fl2Buffer[cIDX]; + bool isCloseUnderFib3 = cBar.close < conditions.fl3Buffer[cIDX]; + bool isCloseUnderFib4 = cBar.close < conditions.fl4Buffer[cIDX]; + bool isCloseUnderFib5 = cBar.close < conditions.fl5Buffer[cIDX]; + + // + + // + // Set ... + conditions.isRSIOverBought = isRSIOverBought; + conditions.isRSICrossedOverOverBought = isRSICrossedOverOverBought; + conditions.isRSICrossedUnderOverBought = isRSICrossedUnderOverBought; + conditions.isRSIOverSold = isRSIOverSold; + conditions.isRSICrossedUnderOverSold = isRSICrossedUnderOverSold; + conditions.isRSICrossedOverOverSold = isRSICrossedOverOverSold; + conditions.isSarBullish = isSarBullish; + conditions.isSarBearish = isSarBearish; + conditions.isSarSwitchedToBullish = isSarSwitchedToBullish; + conditions.isSarSwitchedToBearish = isSarSwitchedToBearish; + conditions.isNewPeak = isNewPeak; + conditions.isNewPeakOverLast = isNewPeakOverLast; + conditions.isNewPeakUnderLast = isNewPeakUnderLast; + conditions.isNewVale = isNewVale; + conditions.isNewValeOverLast = isNewValeOverLast; + conditions.isNewValeUnderLast = isNewValeUnderLast; + conditions.isVWapFastBullish = isVWapFastBullish; + conditions.isVWapFastBearish = isVWapFastBearish; + conditions.isVWapFastNeutural = isVWapFastNeutural; + conditions.isVWapMidBullish = isVWapMidBullish; + conditions.isVWapMidBearish = isVWapMidBearish; + conditions.isVWapMidNeutural = isVWapMidNeutural; + conditions.isVWapSlowBullish = isVWapSlowBullish; + conditions.isVWapSlowBearish = isVWapSlowBearish; + conditions.isVWapSlowNeutural = isVWapSlowNeutural; + conditions.isVWapFastOverMid = isVWapFastOverMid; + conditions.isVWapMidOverSlow = isVWapMidOverSlow; + conditions.isVWapFastUnderMid = isVWapFastUnderMid; + conditions.isVWapMidUnderSlow = isVWapMidUnderSlow; + conditions.isVWapBullishState = isVWapBullishState; + conditions.isVWapBearishState = isVWapBearishState; + conditions.isVWapNeuturalState = isVWapNeuturalState; + conditions.isVWapBullishOrdered = isVWapBullishOrdered; + conditions.isVWapBearishOrdered = isVWapBearishOrdered; + conditions.isVWapSwitchedToBullishOrdered = isVWapSwitchedToBullishOrdered; + conditions.isVWapSwitchedToBearishOrdered = isVWapSwitchedToBearishOrdered; + conditions.isVWapSwitchedToBullishState = isVWapSwitchedToBullishState; + conditions.isVWapSwitchedToBearishState = isVWapSwitchedToBearishState; + conditions.isVWapSwitchedToNeuturalState = isVWapSwitchedToNeuturalState; + conditions.isOerFib1 = isOerFib1; + conditions.isOerFib2 = isOerFib2; + conditions.isOerFib3 = isOerFib3; + conditions.isOerFib4 = isOerFib4; + conditions.isOerFib5 = isOerFib5; + conditions.isUnderFib1 = isUnderFib1; + conditions.isUnderFib2 = isUnderFib2; + conditions.isUnderFib3 = isUnderFib3; + conditions.isUnderFib4 = isUnderFib4; + conditions.isUnderFib5 = isUnderFib5; + conditions.isCloseOerFib1 = isCloseOerFib1; + conditions.isCloseOerFib2 = isCloseOerFib2; + conditions.isCloseOerFib3 = isCloseOerFib3; + conditions.isCloseOerFib4 = isCloseOerFib4; + conditions.isCloseOerFib5 = isCloseOerFib5; + conditions.isCloseUnderFib1 = isCloseUnderFib1; + conditions.isCloseUnderFib2 = isCloseUnderFib2; + conditions.isCloseUnderFib3 = isCloseUnderFib3; + conditions.isCloseUnderFib4 = isCloseUnderFib4; + conditions.isCloseUnderFib5 = isCloseUnderFib5; + + // + return result; + } + + // + protected: + // + + // + private: + // + // Props ... + X121Inputs mInputs; // Inputs ... + + // + // Buffers ... + + // + int mRSIHandler; // RSI Handler ... + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double sarBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double fl1Buffer[]; + double fl2Buffer[]; + double fl3Buffer[]; + double fl4Buffer[]; + double fl5Buffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + double atrBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + double rsiBuffer[]; + + // + // Tools ... + + /** + * Calculate Buffers ... + */ + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // RSI ... + CopyBuffer( + mRSIHandler, + 0, + 0, + totalBars, + rsiBuffer + // + ); + + // + // XSAR ... + CopyBuffer( + mHandler, + X121_SAR_LINE, + 0, + totalBars, + sarBuffer + // + ); + + // + // ATR ... + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_LINE, + 0, + totalBars, + atrUpperBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_LINE, + 0, + totalBars, + atrLowerBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LINE, + 0, + totalBars, + atrBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_RAW_LINE, + 0, + totalBars, + atrUpperRawBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_RAW_LINE, + 0, + totalBars, + atrLowerRawBuffer + // + ); + + // + // XPV ... + + // + // PEAKS ... + CopyBuffer( + mHandler, + X121_PEAKS_LINE, + 0, + totalBars, + peaksBuffer + // + ); + + // + // VALES ... + CopyBuffer( + mHandler, + X121_VALES_LINE, + 0, + totalBars, + valesBuffer + // + ); + + // + // CURRENT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_CURRENT_HH_LINE, + 0, + totalBars, + cHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_CURRENT_LL_LINE, + 0, + totalBars, + cLLBuffer + // + ); + + // + // SHORT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_SHORT_HH_LINE, + 0, + totalBars, + sHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_SHORT_LL_LINE, + 0, + totalBars, + sLLBuffer + // + ); + + // + // MEDIUM ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_MEDIUM_HH_LINE, + 0, + totalBars, + mHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_MEDIUM_LL_LINE, + 0, + totalBars, + mLLBuffer + // + ); + + // + // LONG ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_LONG_HH_LINE, + 0, + totalBars, + lHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_LONG_LL_LINE, + 0, + totalBars, + lLLBuffer + // + ); + + // + // HIND ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_HIND_HH_LINE, + 0, + totalBars, + hHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_HIND_LL_LINE, + 0, + totalBars, + hLLBuffer + // + ); + + // + // XVWAP ... + + // + // FAST ... + CopyBuffer( + mHandler, + X121_VWAP_FAST_LINE, + 0, + totalBars, + vwapFastBuffer + // + ); + + // + // FAST STATE ... + CopyBuffer( + mHandler, + X121_VWAP_FAST_STATE_LINE, + 0, + totalBars, + vwapFastStateBuffer + // + ); + + // + // MID ... + CopyBuffer( + mHandler, + X121_VWAP_MID_LINE, + 0, + totalBars, + vwapMidBuffer + // + ); + + // + // MID STATE ... + CopyBuffer( + mHandler, + X121_VWAP_MID_STATE_LINE, + 0, + totalBars, + vwapMidStateBuffer + // + ); + + // + // SLOW ... + CopyBuffer( + mHandler, + X121_VWAP_SLOW_LINE, + 0, + totalBars, + vwapSlowBuffer + // + ); + + // + // SLOW STATE ... + CopyBuffer( + mHandler, + X121_VWAP_SLOW_STATE_LINE, + 0, + totalBars, + vwapSlowStateBuffer + // + ); + + // + // VOLUME ... + CopyBuffer( + mHandler, + X121_VWAP_VOLUME_LINE, + 0, + totalBars, + vwapVolumeBuffer + // + ); + + // + // PRICE ... + CopyBuffer( + mHandler, + X121_VWAP_PRICE_LINE, + 0, + totalBars, + vwapPriceBuffer + // + ); + + // + // FIBONACCI ... + + // + // LEVEL 1 ... + CopyBuffer( + mHandler, + X121_FIB_LEVEL_1_LINE, + 0, + totalBars, + fl1Buffer + // + ); + + // + // LEVEL 2 ... + CopyBuffer( + mHandler, + X121_FIB_LEVEL_2_LINE, + 0, + totalBars, + fl2Buffer + // + ); + + // + // LEVEL 3 ... + CopyBuffer( + mHandler, + X121_FIB_LEVEL_3_LINE, + 0, + totalBars, + fl3Buffer + // + ); + + // + // LEVEL 4 ... + CopyBuffer( + mHandler, + X121_FIB_LEVEL_4_LINE, + 0, + totalBars, + fl4Buffer + // + ); + + // + // LEVEL 5 ... + CopyBuffer( + mHandler, + X121_FIB_LEVEL_5_LINE, + 0, + totalBars, + fl5Buffer + // + ); + + // + // XDON ... + + // + // OPEN ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_OPEN_UPPER_LINE, + 0, + totalBars, + donOpenUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_OPEN_LOWER_LINE, + 0, + totalBars, + donOpenLowerBuffer + // + ); + + // + // CLOSE ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_CLOSE_UPPER_LINE, + 0, + totalBars, + donCloseUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_CLOSE_LOWER_LINE, + 0, + totalBars, + donCloseLowerBuffer + // + ); + + // + // HIGH ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_HIGH_UPPER_LINE, + 0, + totalBars, + donHighUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_HIGH_LOWER_LINE, + 0, + totalBars, + donHighLowerBuffer + // + ); + + // + // LOW ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_DON_LOW_UPPER_LINE, + 0, + totalBars, + donLowUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_DON_LOW_LOWER_LINE, + 0, + totalBars, + donLowLowerBuffer + // + ); + } +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.mq5 b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.mq5 new file mode 100644 index 0000000..241e013 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.old.mq5 @@ -0,0 +1,2321 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 +// Description: Peaks and Vales ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121" + +// +// Includes Common Library ... +#include "../Classes/x-saherelm.x-poi.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +input group "Makret Cycles"; + +// +input group "Short"; +input ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES scPeriod = NULL; // Time Period + +// +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES mcPeriod = NULL; // Time Period + +// +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES lcPeriod = NULL; // Time Period + +// +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Period +input ENUM_TIMEFRAMES hcPeriod = NULL; // Time Period + +// +input group "Boundary Detection"; +input ENUM_SERIESMODE hhMode = MODE_HIGH; // Highest High Calculation Method +input ENUM_SERIESMODE llMode = MODE_LOW; // Lowest Low Calculation Method + +// +input group "Parabolic Sar Detection"; +input double sarStep = 0.02; // Step +input double sarMax = 0.2; // Maximum + +// +input group "Atr Detection"; +input int atrLength = 14; // Length +input double atrMultiplier = 1; // Multiplier +input ENUM_APPLIED_PRICE atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To +input ENUM_APPLIED_PRICE atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To +input ENUM_X_MA_METHOD atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + +// +input group "VWap Detection"; +input int vwapFastLength = 20; // Fast Length +input int vwapMidLength = 40; // Mid Length +input int vwapSlowLength = 60; // Slow Length +input ENUM_APPLIED_PRICE vwapAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Donchain Detection"; +input int donchainLength = 40; // Donchain Length + +// +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars + +// +input bool showSar = true; // Show Parabolic Sar +input bool showAtr = true; // Show Atr +input bool showPeaks = true; // Show Peaks +input bool showVales = true; // Show Vales +input bool showVWap = true; // Show VWap +input bool showDonchain = true; // Show Donchain + +// +input group "Fibonachi Presentation"; +input bool showFibo1Levels = false; // Show Fibo 1st Level +input bool showFibo2Levels = false; // Show Fibo 2nd Level +input bool showFibo3Levels = false; // Show Fibo 3rd Level +input bool showFibo4Levels = false; // Show Fibo 4th Level +input bool showFibo5Levels = false; // Show Fibo 5th Level + +// +input group "Atr Presentation"; +input bool showAtrUpper = true; // Show Upper Zone +input bool showAtrLower = true; // Show Lower Zone + +// +input group "VWap Presentation"; +input bool showVWapFast = true; // Show VWap Fast +input bool showVWapMedium = true; // Show VWap Medium +input bool showVWapSlow = true; // Show VWap Slow + +// +input group "Donchain Presentation"; +input bool showUpper = true; // Show Upper Band +input bool showLower = true; // Show Lower Band +input bool showOpen = true; // Show Open +input bool showHigh = false; // Show High +input bool showClose = true; // Show Close +input bool showLow = false; // Show Low + +// +// Non Important Inputs ... + +// +input group "Fibonacci"; +input double fiboLevel1 = 0.236; // Fibio 1st Level +input double fiboLevel2 = 0.382; // Fibio 2st Level +input double fiboLevel3 = 0.5; // Fibio 3rd Level +input double fiboLevel4 = 0.618; // Fibio 4th Level +input double fiboLevel5 = 0.764; // Fibio 5th Level + +// +input int sarArrowCode = 159; // Parabolic Sar Arrow Code +input int peaksArrowCode = 159; // Peaks Arrow Code +input int valesArrowCode = 159; // Vales Arrow Code + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 42 +#property indicator_plots 21 + +// +// PEAKS ... + +// +#define peaksBufferIndex 0 +double peaksBuffer[]; + +// +#property indicator_label1 "X121 PEAKS" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrAqua +#property indicator_width1 1 + +// +// VALES ... + +// +#define valesBufferIndex 1 +double valesBuffer[]; + +// +#property indicator_label2 "X121 VALES" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrMagenta +#property indicator_width2 1 + +// +// SAR ... + +// +#define sarBufferIndex 2 +double sarBuffer[]; + +// +#property indicator_label3 "X121 SAR" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrYellow +#property indicator_width3 1 + +// +// ATR ... + +// +// Upper ... + +// +#define atrUpperBufferIndex 3 +double atrUpperBuffer[]; + +#property indicator_label4 "X121 ATRU" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrYellow +#property indicator_style4 STYLE_DOT +#property indicator_width4 2 + +// +// Lower ... + +// +#define atrLowerBufferIndex 4 +double atrLowerBuffer[]; + +#property indicator_label5 "X121 ATRL" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrYellow +#property indicator_style5 STYLE_DOT +#property indicator_width5 2 + +// +// VWAP ... + +// +// FAST ... +#define vwapFastBufferIndex 5 +double vwapFastBuffer[]; + +#define vwapFastColorBufferIndex 6 +double vwapFastColorBuffer[]; + +// +#define vwapFastPlotBufferIndex 5 +#property indicator_label6 "X121 VWF" +#property indicator_type6 DRAW_COLOR_LINE +#property indicator_color6 CLR_NONE, clrAqua, clrMagenta, clrGray +#property indicator_style6 STYLE_SOLID +#property indicator_width6 2 + +// +// MID ... +#define vwapMidBufferIndex 7 +double vwapMidBuffer[]; + +#define vwapMidColorBufferIndex 8 +double vwapMidColorBuffer[]; + +// +#define vwapMidPlotBufferIndex 6 +#property indicator_label7 "X121 VWM" +#property indicator_type7 DRAW_COLOR_LINE +#property indicator_color7 CLR_NONE, clrGreen, clrRed, clrGray +#property indicator_style7 STYLE_SOLID +#property indicator_width7 2 + +// +// SLOW ... +#define vwapSlowBufferIndex 9 +double vwapSlowBuffer[]; + +#define vwapSlowColorBufferIndex 10 +double vwapSlowColorBuffer[]; + +// +#define vwapSlowPlotBufferIndex 7 +#property indicator_label8 "X121 VWS" +#property indicator_type8 DRAW_COLOR_LINE +#property indicator_color8 CLR_NONE, clrSteelBlue, clrDarkRed, clrGray +#property indicator_style8 STYLE_SOLID +#property indicator_width8 2 + +// +// XDON ... + +// +// Open ... + +// +#define donOpenUpperBufferIndex 11 +double donOpenUpperBuffer[]; + +// +#define donOpenUpperPlotBufferIndex 8 +#property indicator_label9 "X121 O U" +#property indicator_type9 DRAW_LINE +#property indicator_color9 clrCornflowerBlue +#property indicator_width9 1 + +// +#define donOpenLowerBufferIndex 12 +double donOpenLowerBuffer[]; + +// +#define donOpenLowerPlotBufferIndex 9 +#property indicator_label10 "X121 O L" +#property indicator_type10 DRAW_LINE +#property indicator_color10 clrCornflowerBlue +#property indicator_width10 1 + +// +// High ... + +// +#define donHighUpperBufferIndex 13 +double donHighUpperBuffer[]; + +// +#define donHighUpperPlotBufferIndex 10 +#property indicator_label11 "X121 H U" +#property indicator_type11 DRAW_LINE +#property indicator_color11 clrAquamarine +#property indicator_width11 1 + +// +#define donHighLowerBufferIndex 14 +double donHighLowerBuffer[]; + +// +#define donHighLowerPlotBufferIndex 11 +#property indicator_label12 "X121 H L" +#property indicator_type12 DRAW_LINE +#property indicator_color12 clrAquamarine +#property indicator_width12 1 + +// +// Low ... + +// +#define donLowUpperBufferIndex 15 +double donLowUpperBuffer[]; + +// +#define donLowUpperPlotBufferIndex 12 +#property indicator_label13 "X121 L U" +#property indicator_type13 DRAW_LINE +#property indicator_color13 clrDarkOrchid +#property indicator_width13 1 + +// +#define donLowLowerBufferIndex 16 +double donLowLowerBuffer[]; + +// +#define donLowLowerPlotBufferIndex 13 +#property indicator_label14 "X121 L L" +#property indicator_type14 DRAW_LINE +#property indicator_color14 clrDarkOrchid +#property indicator_width14 1 + +// +// Close ... + +// +#define donCloseUpperBufferIndex 17 +double donCloseUpperBuffer[]; + +// +#define donCloseUpperPlotBufferIndex 14 +#property indicator_label15 "X121 C U" +#property indicator_type15 DRAW_LINE +#property indicator_color15 clrCoral +#property indicator_width15 1 + +// +#define donCloseLowerBufferIndex 18 +double donCloseLowerBuffer[]; + +// +#define donCloseLowerPlotBufferIndex 15 +#property indicator_label16 "X121 C L" +#property indicator_type16 DRAW_LINE +#property indicator_color16 clrCoral +#property indicator_width16 1 + +// +// FIBONACCI ... + +// +// FIBBO Level 1 ... + +// +#define fl1BufferIndex 19 +double fl1Buffer[]; + +// +#define fl1PlotBufferIndex 16 +#property indicator_label17 "X121 FL1" +#property indicator_type17 DRAW_LINE +#property indicator_color17 clrGold +#property indicator_style17 STYLE_DASHDOTDOT +#property indicator_width17 1 + +// +// FIBBO Level 2 ... + +// +#define fl2BufferIndex 20 +double fl2Buffer[]; + +// +#define fl2PlotBufferIndex 17 +#property indicator_label18 "X121 FL2" +#property indicator_type18 DRAW_LINE +#property indicator_color18 clrGold +#property indicator_style18 STYLE_DASHDOTDOT +#property indicator_width18 1 + +// +// FIBBO Level 3 ... + +// +#define fl3BufferIndex 21 +double fl3Buffer[]; + +// +#define fl3PlotBufferIndex 18 +#property indicator_label19 "X121 FL3" +#property indicator_type19 DRAW_LINE +#property indicator_color19 clrGold +#property indicator_style19 STYLE_DASHDOTDOT +#property indicator_width19 1 + +// +// FIBBO Level 4 ... + +// +#define fl4BufferIndex 22 +double fl4Buffer[]; + +// +#define fl4PlotBufferIndex 19 +#property indicator_label20 "X121 FL4" +#property indicator_type20 DRAW_LINE +#property indicator_color20 clrGold +#property indicator_style20 STYLE_DASHDOTDOT +#property indicator_width20 1 + +// +// FIBBO Level 5 ... + +// +#define fl5BufferIndex 23 +double fl5Buffer[]; + +// +#define fl5PlotBufferIndex 20 +#property indicator_label21 "X121 FL5" +#property indicator_type21 DRAW_LINE +#property indicator_color21 clrGold +#property indicator_style21 STYLE_DASHDOTDOT +#property indicator_width21 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 23; + +// +// CURRENT ... + +// +#define cHHBufferIndex mLastBufferIndex + 1 +double cHHBuffer[]; + +// +#define cLLBufferIndex mLastBufferIndex + 2 +double cLLBuffer[]; + +// +// SHORT ... + +// +#define sHHBufferIndex mLastBufferIndex + 3 +double sHHBuffer[]; + +// +#define sLLBufferIndex mLastBufferIndex + 4 +double sLLBuffer[]; + +// +// MEDIUM ... + +// +#define mHHBufferIndex mLastBufferIndex + 5 +double mHHBuffer[]; + +// +#define mLLBufferIndex mLastBufferIndex + 6 +double mLLBuffer[]; + +// +// LONG ... + +// +#define lHHBufferIndex mLastBufferIndex + 7 +double lHHBuffer[]; + +// +#define lLLBufferIndex mLastBufferIndex + 8 +double lLLBuffer[]; + +// +// HIND ... + +// +#define hHHBufferIndex mLastBufferIndex + 9 +double hHHBuffer[]; + +// +#define hLLBufferIndex mLastBufferIndex + 10 +double hLLBuffer[]; + +// +// VOLUME ... +#define vwapVolumeBufferIndex mLastBufferIndex + 11 +double vwapVolumeBuffer[]; + +// +// Price ... +#define vwapPriceBufferIndex mLastBufferIndex + 12 +double vwapPriceBuffer[]; + +// +// Fast State ... +#define vwapFastStateBufferIndex mLastBufferIndex + 13 +double vwapFastStateBuffer[]; + +// +// Mid State ... +#define vwapMidStateBufferIndex mLastBufferIndex + 14 +double vwapMidStateBuffer[]; + +// +// Slow State ... +#define vwapSlowStateBufferIndex mLastBufferIndex + 15 +double vwapSlowStateBuffer[]; + +// +// ATR ... + +#define atrBufferIndex mLastBufferIndex + 16 +double atrBuffer[]; + +#define atrUpperRawBufferIndex mLastBufferIndex + 17 +double atrUpperRawBuffer[]; + +#define atrLowerRawBufferIndex mLastBufferIndex + 18 +double atrLowerRawBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// SAR Handler ... +int sarHandler = INVALID_HANDLE; + +// +// ATR Handler ... +int atrHandler = INVALID_HANDLE; + +// +double mHideColorIDX = 0; + +// +// XMarketCycle sc; +int mSCLength = 0; +ENUM_TIMEFRAMES mSCPeriod = NULL; + +// +// XMarketCycle mc; +int mMCLength = 0; +ENUM_TIMEFRAMES mMCPeriod = NULL; + +// +// XMarketCycle lc; +int mLCLength = 0; +ENUM_TIMEFRAMES mLCPeriod = NULL; + +// +// XMarketCycle hc; +int mHCLength = 0; +ENUM_TIMEFRAMES mHCPeriod = NULL; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // SAR ... + sarHandler = iSAR( + _Symbol, + _Period, + sarStep, + sarMax // + ); + bool isInited = sarHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength // + ); + isInited = atrHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + if (!InitMarketCycles()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(sarHandler); + IndicatorRelease(atrHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Fill All Buffers by Zero ... + if (prev_calculated == 0) + { + // + ArrayInitialize(peaksBuffer, 0); + ArrayInitialize(valesBuffer, 0); + ArrayInitialize(sarBuffer, 0); + } + + // + // Validate Calculated Bars ... + + // + // SAR ... + int sarCalculatedBars = BarsCalculated(sarHandler); + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // SAR ... + sarCalculatedBars >= maxLength && + // + // ATR... + sarCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // SAR ... + int copiedSars = CopyBuffer(sarHandler, 0, 0, limit, sarBuffer); + + // + // ATR ... + int copiedAtrs = CopyBuffer(atrHandler, 0, 0, limit, atrBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // + // SAR ... + copiedSars > 0 && + copiedAtrs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + // PSAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 && + // + // XDON ... + donchainLength > 0 && + // + // VWAP ... + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // XPV ... + result = MathMax(mSCLength, mMCLength); + result = MathMax(result, mLCLength); + result = MathMax(result, mHCLength); + + // + // XVWAP ... + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapMidLength); + result = MathMax(result, vwapSlowLength); + + // + // ATR ... + result = MathMax(result, atrLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // PEAKS ... + + // + ENUM_DRAW_TYPE peaksDrawType = showPeaks ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(peaksBuffer, true); + SetIndexBuffer(peaksBufferIndex, peaksBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peaksBufferIndex, PLOT_SHOW_DATA, showPeaks); + PlotIndexSetInteger(peaksBufferIndex, PLOT_DRAW_TYPE, peaksDrawType); + + // + PlotIndexSetDouble(peaksBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(peaksBufferIndex, PLOT_ARROW, peaksArrowCode); + + // + // VALES ... + + // + ENUM_DRAW_TYPE valesDrawType = showVales ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(valesBuffer, true); + SetIndexBuffer(valesBufferIndex, valesBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valesBufferIndex, PLOT_SHOW_DATA, showVales); + PlotIndexSetInteger(valesBufferIndex, PLOT_DRAW_TYPE, valesDrawType); + + // + PlotIndexSetDouble(valesBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(valesBufferIndex, PLOT_ARROW, valesArrowCode); + + // + // SAR ... + + // + ENUM_DRAW_TYPE sarDrawType = showSar ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(sarBufferIndex, PLOT_SHOW_DATA, showSar); + PlotIndexSetInteger(sarBufferIndex, PLOT_DRAW_TYPE, sarDrawType); + + // + PlotIndexSetDouble(sarBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(sarBufferIndex, PLOT_ARROW, sarArrowCode); + + // + // ATR ... + + // + // UPPER ... + bool canShowAtrUpper = showAtr && showAtrUpper; + ENUM_DRAW_TYPE atrUpperDrawType = canShowAtrUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrUpperBuffer, true); + SetIndexBuffer(atrUpperBufferIndex, atrUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrUpperBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_SHOW_DATA, canShowAtrUpper); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_DRAW_TYPE, atrUpperDrawType); + + // + // LOWER ... + bool canShowAtrLower = showAtr && showAtrLower; + ENUM_DRAW_TYPE atrLowerDrawType = canShowAtrLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrLowerBuffer, true); + SetIndexBuffer(atrLowerBufferIndex, atrLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrLowerBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_SHOW_DATA, canShowAtrLower); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_DRAW_TYPE, atrLowerDrawType); + + // + // XVWAP ... + + // + // Fast ... + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapFastColorBuffer, true); + SetIndexBuffer(vwapFastBufferIndex, vwapFastBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapFastColorBufferIndex, vwapFastColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Mid ... + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapMidColorBuffer, true); + SetIndexBuffer(vwapMidBufferIndex, vwapMidBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapMidColorBufferIndex, vwapMidColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Slow ... + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapSlowColorBuffer, true); + SetIndexBuffer(vwapSlowBufferIndex, vwapSlowBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapSlowColorBufferIndex, vwapSlowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // XDON ... + + // + // Open ... + + // + // UPPER ... + bool canShowCOpenUpper = showDonchain && showUpper && showOpen; + ENUM_DRAW_TYPE donOpenUpperDrawType = canShowCOpenUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenUpperBuffer, true); + SetIndexBuffer(donOpenUpperBufferIndex, donOpenUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenUpper); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_DRAW_TYPE, donOpenUpperDrawType); + + // + // LOWER ... + bool canShowCOpenLower = showDonchain && showLower && showOpen; + ENUM_DRAW_TYPE donOpenLowerDrawType = canShowCOpenLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenLowerBuffer, true); + SetIndexBuffer(donOpenLowerBufferIndex, donOpenLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenLower); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_DRAW_TYPE, donOpenLowerDrawType); + + // + // Close ... + + // + // UPPER ... + bool canShowCCloseUpper = showDonchain && showUpper && showClose; + ENUM_DRAW_TYPE donCloseUpperDrawType = canShowCCloseUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseUpperBuffer, true); + SetIndexBuffer(donCloseUpperBufferIndex, donCloseUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseUpper); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_DRAW_TYPE, donCloseUpperDrawType); + + // + // LOWER ... + bool canShowCCloseLower = showDonchain && showLower && showClose; + ENUM_DRAW_TYPE donCloseLowerDrawType = canShowCCloseLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseLowerBuffer, true); + SetIndexBuffer(donCloseLowerBufferIndex, donCloseLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseLower); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_DRAW_TYPE, donCloseLowerDrawType); + + // + // High ... + + // + // UPPER ... + bool canShowCHighUpper = showDonchain && showUpper && showHigh; + ENUM_DRAW_TYPE donHighUpperDrawType = canShowCHighUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighUpperBuffer, true); + SetIndexBuffer(donHighUpperBufferIndex, donHighUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighUpper); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_DRAW_TYPE, donHighUpperDrawType); + + // + // LOWER ... + bool canShowCHighLower = showDonchain && showLower && showHigh; + ENUM_DRAW_TYPE donHighLowerDrawType = canShowCHighLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighLowerBuffer, true); + SetIndexBuffer(donHighLowerBufferIndex, donHighLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighLower); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_DRAW_TYPE, donHighLowerDrawType); + + // + // Low ... + + // + // UPPER ... + bool canShowCLowUpper = showDonchain && showUpper && showLow; + ENUM_DRAW_TYPE donLowUpperDrawType = canShowCLowUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowUpperBuffer, true); + SetIndexBuffer(donLowUpperBufferIndex, donLowUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowUpper); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_DRAW_TYPE, donLowUpperDrawType); + + // + // LOWER ... + bool canShowCLowLower = showDonchain && showLower && showLow; + ENUM_DRAW_TYPE donLowLowerDrawType = canShowCLowLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowLowerBuffer, true); + SetIndexBuffer(donLowLowerBufferIndex, donLowLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowLower); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_DRAW_TYPE, donLowLowerDrawType); + + // + // FIBONNACI ... + + // + // LEVEL 1 ... + bool canShowFl1 = showFibo1Levels; + ENUM_DRAW_TYPE fl1DrawType = canShowFl1 ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fl1Buffer, true); + SetIndexBuffer(fl1BufferIndex, fl1Buffer, INDICATOR_DATA); + PlotIndexSetDouble(fl1PlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(fl1PlotBufferIndex, PLOT_SHOW_DATA, canShowFl1); + PlotIndexSetInteger(fl1PlotBufferIndex, PLOT_DRAW_TYPE, fl1DrawType); + + // + // LEVEL 2 ... + bool canShowFl2 = showFibo2Levels; + ENUM_DRAW_TYPE fl2DrawType = canShowFl2 ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fl2Buffer, true); + SetIndexBuffer(fl2BufferIndex, fl2Buffer, INDICATOR_DATA); + PlotIndexSetDouble(fl2PlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(fl2PlotBufferIndex, PLOT_SHOW_DATA, canShowFl2); + PlotIndexSetInteger(fl2PlotBufferIndex, PLOT_DRAW_TYPE, fl2DrawType); + + // + // LEVEL 3 ... + bool canShowFl3 = showFibo3Levels; + ENUM_DRAW_TYPE fl3DrawType = canShowFl3 ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fl3Buffer, true); + SetIndexBuffer(fl3BufferIndex, fl3Buffer, INDICATOR_DATA); + PlotIndexSetDouble(fl3PlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(fl3PlotBufferIndex, PLOT_SHOW_DATA, canShowFl3); + PlotIndexSetInteger(fl3PlotBufferIndex, PLOT_DRAW_TYPE, fl3DrawType); + + // + // LEVEL 4 ... + bool canShowFl4 = showFibo4Levels; + ENUM_DRAW_TYPE fl4DrawType = canShowFl4 ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fl4Buffer, true); + SetIndexBuffer(fl4BufferIndex, fl4Buffer, INDICATOR_DATA); + PlotIndexSetDouble(fl4PlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(fl4PlotBufferIndex, PLOT_SHOW_DATA, canShowFl4); + PlotIndexSetInteger(fl4PlotBufferIndex, PLOT_DRAW_TYPE, fl4DrawType); + + // + // LEVEL 5 ... + bool canShowFl5 = showFibo5Levels; + ENUM_DRAW_TYPE fl5DrawType = canShowFl5 ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fl5Buffer, true); + SetIndexBuffer(fl5BufferIndex, fl5Buffer, INDICATOR_DATA); + PlotIndexSetDouble(fl5PlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(fl5PlotBufferIndex, PLOT_SHOW_DATA, canShowFl5); + PlotIndexSetInteger(fl5PlotBufferIndex, PLOT_DRAW_TYPE, fl5DrawType); + + // + // Data Buffers ... + + // + // CURRENT ... + + // + ArraySetAsSeries(cHHBuffer, true); + SetIndexBuffer(cHHBufferIndex, cHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(cLLBuffer, true); + SetIndexBuffer(cLLBufferIndex, cLLBuffer, INDICATOR_CALCULATIONS); + + // + // SHORT ... + + // + ArraySetAsSeries(sHHBuffer, true); + SetIndexBuffer(sHHBufferIndex, sHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(sLLBuffer, true); + SetIndexBuffer(sLLBufferIndex, sLLBuffer, INDICATOR_CALCULATIONS); + + // + // MEDIUM ... + + // + ArraySetAsSeries(mHHBuffer, true); + SetIndexBuffer(mHHBufferIndex, mHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(mLLBuffer, true); + SetIndexBuffer(mLLBufferIndex, mLLBuffer, INDICATOR_CALCULATIONS); + + // + // LONG ... + + // + ArraySetAsSeries(lHHBuffer, true); + SetIndexBuffer(lHHBufferIndex, lHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(lLLBuffer, true); + SetIndexBuffer(lLLBufferIndex, lLLBuffer, INDICATOR_CALCULATIONS); + + // + // HIND ... + + // + ArraySetAsSeries(hHHBuffer, true); + SetIndexBuffer(hHHBufferIndex, hHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(hLLBuffer, true); + SetIndexBuffer(hLLBufferIndex, hLLBuffer, INDICATOR_CALCULATIONS); + + // + // XVWAP ... + + // + // Volumes ... + ArraySetAsSeries(vwapVolumeBuffer, true); + SetIndexBuffer(vwapVolumeBufferIndex, vwapVolumeBuffer, INDICATOR_CALCULATIONS); + + // + // Price ... + ArraySetAsSeries(vwapPriceBuffer, true); + SetIndexBuffer(vwapPriceBufferIndex, vwapPriceBuffer, INDICATOR_CALCULATIONS); + + // + // Fast State ... + ArraySetAsSeries(vwapFastStateBuffer, true); + SetIndexBuffer(vwapFastStateBufferIndex, vwapFastStateBuffer, INDICATOR_CALCULATIONS); + + // + // Mid State ... + ArraySetAsSeries(vwapMidStateBuffer, true); + SetIndexBuffer(vwapMidStateBufferIndex, vwapMidStateBuffer, INDICATOR_CALCULATIONS); + + // + // Slow State ... + ArraySetAsSeries(vwapSlowStateBuffer, true); + SetIndexBuffer(vwapSlowStateBufferIndex, vwapSlowStateBuffer, INDICATOR_CALCULATIONS); + + // + // ATR ... + + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrUpperRawBuffer, true); + SetIndexBuffer(atrUpperRawBufferIndex, atrUpperRawBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrLowerRawBuffer, true); + SetIndexBuffer(atrLowerRawBufferIndex, atrLowerRawBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + // Calculate Cycles ... + CalculateCycles(bar_index); + + // + // Calculate Peaks and Vales ... + CalculatePeaksAndVales(bar_index); + + // + CalculateDonchains( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateAtrZones( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); + + // + CalculateFibonacci( + bar_index // + ); + + // + // Calculate Required VWAP Data Buffers ... + if (ratesTotal - bar_index <= maxLength) + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // Prevent Moving Forward ... + } + else + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateVWAPS( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Initial Market Cycles ... + * + * @return ( bool ) + */ +bool InitMarketCycles() +{ + // + bool result = false; + + // + int cPeriodSeconds = PeriodSeconds(_Period); + + // + // Find Cycle Period ... + if (scMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mSCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_SHORT, + _Period // + ); + } + else + { + mSCPeriod = scPeriod; + } + + // + if (IsValid(mSCPeriod)) + { + mSCLength = PeriodSeconds(mSCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (mcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mMCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_MEDIUM, + _Period // + ); + } + else + { + mMCPeriod = mcPeriod; + } + + // + if (IsValid(mMCPeriod)) + { + mMCLength = PeriodSeconds(mMCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (lcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mLCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_LONG, + _Period // + ); + } + else + { + mLCPeriod = lcPeriod; + } + + // + if (IsValid(mLCPeriod)) + { + mLCLength = PeriodSeconds(mLCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (hcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mHCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_HIND, + _Period // + ); + } + else + { + mHCPeriod = hcPeriod; + } + + // + if (IsValid(mHCPeriod)) + { + mHCLength = PeriodSeconds(mHCPeriod) / cPeriodSeconds; + } + + // + result = mSCLength > 0 && + mMCLength > mSCLength && + mLCLength > mMCLength && + mHCLength > mLCLength; + + // + return result; +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // CURRENT ... + cHHBuffer[barIndex] = 0; + cLLBuffer[barIndex] = 0; + + // + // SHORT ... + sHHBuffer[barIndex] = 0; + sLLBuffer[barIndex] = 0; + + // + // MEDIUM ... + mHHBuffer[barIndex] = 0; + mLLBuffer[barIndex] = 0; + + // + // LONG ... + lHHBuffer[barIndex] = 0; + lLLBuffer[barIndex] = 0; + + // + // HIND ... + hHHBuffer[barIndex] = 0; + hLLBuffer[barIndex] = 0; + + // + // PEAKS ... + peaksBuffer[barIndex] = 0; + + // + // VALES ... + valesBuffer[barIndex] = 0; + + // + // SARS ... + sarBuffer[barIndex] = 0; + + // + // ATRS ... + atrBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrUpperRawBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrLowerRawBuffer[barIndex] = 0; + + // + // VWAP ... + + // + vwapFastBuffer[barIndex] = 0; + vwapMidBuffer[barIndex] = 0; + vwapSlowBuffer[barIndex] = 0; + vwapVolumeBuffer[barIndex] = 0; + vwapPriceBuffer[barIndex] = 0; + + // + vwapFastColorBuffer[barIndex] = hideColorIDX; + vwapMidColorBuffer[barIndex] = hideColorIDX; + vwapSlowColorBuffer[barIndex] = hideColorIDX; + vwapFastStateBuffer[barIndex] = hideColorIDX; + vwapMidStateBuffer[barIndex] = hideColorIDX; + vwapSlowStateBuffer[barIndex] = hideColorIDX; + + // + donOpenUpperBuffer[barIndex] = 0; + donOpenLowerBuffer[barIndex] = 0; + donCloseUpperBuffer[barIndex] = 0; + donCloseLowerBuffer[barIndex] = 0; + donHighUpperBuffer[barIndex] = 0; + donHighLowerBuffer[barIndex] = 0; + donLowUpperBuffer[barIndex] = 0; + donLowLowerBuffer[barIndex] = 0; + + // + fl1Buffer[barIndex] = 0; + fl2Buffer[barIndex] = 0; + fl3Buffer[barIndex] = 0; + fl4Buffer[barIndex] = 0; + fl5Buffer[barIndex] = 0; +} + +/** + * Calculate Specified Market Cycle Info ... + * + * @param barIndex: Integer, Bar Index ... + * @param cycle: ENUM_X_MARKET_CYCLES member, Specified Cycle ... + * @param hhBuffer: Highest High Buffer Reference ... + * @param llBuffer: Lowest Low Buffer Reference ... + */ +void CalculateCycle( + int barIndex, + ENUM_X_MARKET_CYCLES cycle, + double &hhBuffer[], + double &llBuffer[] // +) +{ + // + XOHCL bar; + bool isBarInited = bar.Init( + _Symbol, + _Period, + barIndex + // + ); + if (!isBarInited) + { + return; + } + + // + int mLength = 0; + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + mLength = mSCLength; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + mLength = mMCLength; + break; + + // + case X_MARKET_CYCLE_LONG: + mLength = mLCLength; + break; + + // + case X_MARKET_CYCLE_HIND: + mLength = mHCLength; + break; + } + + // + if (mLength == 0) + { + return; + } + + // + // Find Highest High ... + double hhValue = bar.FindHighest( + mLength, + hhMode + // + ); + hhBuffer[barIndex] = hhValue; + + // + // Find Lowest Low ... + double llValue = bar.FindLowest( + mLength, + llMode + // + ); + llBuffer[barIndex] = llValue; +} + +/** + * Claculate Cycles ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculateCycles(int barIndex) +{ + // + // SHORT ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_SHORT, + sHHBuffer, + sLLBuffer // + ); + + // + // MEDIUM ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_MEDIUM, + mHHBuffer, + mLLBuffer // + ); + + // + // LONG ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_LONG, + lHHBuffer, + lLLBuffer // + ); + + // + // HIND ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_HIND, + hHHBuffer, + hLLBuffer // + ); +} + +/** + * Calculate Peaks and Vales ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculatePeaksAndVales(int barIndex) +{ + // + int lastIndex = barIndex + 1; + int barsCount = iBars(_Symbol, _Period); + + // + // PEAKS ... + double lastPeak = + lastIndex < barsCount + ? peaksBuffer[lastIndex] + : 0; + + // + double isHH = sHHBuffer[barIndex]; + double imHH = mHHBuffer[barIndex]; + double ilHH = lHHBuffer[barIndex]; + double ihHH = hHHBuffer[barIndex]; + + // + double iHHs[4] = { + isHH, + imHH, + ilHH, + ihHH // + }; + double rValue = GetAverage(iHHs); + bool isPeak = rValue == isHH && + isHH == imHH && + imHH == ilHH && + ilHH == ihHH; + double iPeak = + isPeak + ? rValue + : lastPeak; + peaksBuffer[barIndex] = iPeak; + + // + // VALES ... + double lastVale = + lastIndex < barsCount + ? valesBuffer[lastIndex] + : 0; + + // + double isLL = sLLBuffer[barIndex]; + double imLL = mLLBuffer[barIndex]; + double ilLL = lLLBuffer[barIndex]; + double ihLL = hLLBuffer[barIndex]; + + // + double iLLs[4] = { + isLL, + imLL, + ilLL, + ihLL // + }; + double sValue = GetAverage(iLLs); + bool isVale = sValue == isLL && + isLL == imLL && + imLL == ilLL && + ilLL == ihLL; + double iVale = + isVale + ? sValue + : lastVale; + valesBuffer[barIndex] = iVale; +} + +/** + * Calculate VWAP Value for Specified Bar ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Specified VWAP Length ... + * @param _show: Boolean, Specified Show Buffer or not ... + * @param _buffer: Double Array Reference, Points to Buffer ... + * @param _colorBuffer: Double Array Reference, Points to Color Buffer ... + * @param _stateBuffer: Double Array Reference, Points to State Buffer ... + */ +void CalculateVWAP( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, // Calculation Length + bool _show, + double &_buffer[], + double &_colorBuffer[], + double &_stateBuffer[] // +) +{ + // + double vSum = 0; + double pSum = 0; + double mSum = 0; + for (int x = 0; x < _length; x++) + { + // + pSum += vwapPriceBuffer[x + bar_index]; + vSum += vwapVolumeBuffer[x + bar_index]; + mSum += vwapPriceBuffer[x + bar_index] * vwapVolumeBuffer[x + bar_index]; + } + + // + double iValue = mSum / vSum; + iValue = NormalizeDouble(iValue, _Digits); + + // + _buffer[bar_index] = iValue; + + // + bool isBullish = low[bar_index] > iValue; + bool isBearish = high[bar_index] < iValue; + + // + double iColor = + isBullish + ? bullishColorIDX + : isBearish + ? bearishColorIDX + : neuturalColorIDX; + + // + _colorBuffer[bar_index] = hideColorIDX; + _stateBuffer[bar_index] = iColor; + if (showVWap && _show) + { + _colorBuffer[bar_index] = iColor; + } +} + +/** + * Calculate Donchain ... + * + * @param bar_index: Integer, Bar Index ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Donchain Length ... + * @param _ouBuffer: Double Array Reference ... + * @param _olBuffer: Double Array Reference ... + * @param _huBuffer: Double Array Reference ... + * @param _hlBuffer: Double Array Reference ... + * @param _luBuffer: Double Array Reference ... + * @param _llBuffer: Double Array Reference ... + * @param _cuBuffer: Double Array Reference ... + * @param _clBuffer: Double Array Reference ... + */ +void CalculateDonchain( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + // + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, + // + double &_ouBuffer[], + double &_olBuffer[], + double &_huBuffer[], + double &_hlBuffer[], + double &_luBuffer[], + double &_llBuffer[], + double &_cuBuffer[], + double &_clBuffer[] // +) +{ + // + double iUpper = 0; + double iLower = 0; + + // + // OPEN ... + + // + int from = bar_index; + + // + iUpper = open[ArrayMaximum(open, from, _length)]; + iLower = open[ArrayMinimum(open, from, _length)]; + + // + _ouBuffer[bar_index] = iUpper; + _olBuffer[bar_index] = iLower; + + // + // HIGH ... + + // + iUpper = high[ArrayMaximum(high, from, _length)]; + iLower = high[ArrayMinimum(high, from, _length)]; + + // + _huBuffer[bar_index] = iUpper; + _hlBuffer[bar_index] = iLower; + + // + // LOW ... + + // + iUpper = low[ArrayMaximum(low, from, _length)]; + iLower = low[ArrayMinimum(low, from, _length)]; + + // + _luBuffer[bar_index] = iUpper; + _llBuffer[bar_index] = iLower; + + // + // CLOSE ... + + // + iUpper = close[ArrayMaximum(close, from, _length)]; + iLower = close[ArrayMinimum(close, from, _length)]; + + // + _cuBuffer[bar_index] = iUpper; + _clBuffer[bar_index] = iLower; +} + +/** + * Calculate VWAP Required Data Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPDataBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double price = GetAppliedPrice( + vwapAppliedTo, + open, + high, + low, + close, + bar_index // + ); + vwapPriceBuffer[bar_index] = price; + vwapVolumeBuffer[bar_index] = (double)tickVolume[bar_index]; +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPS( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapFastLength, + showVWapFast, + vwapFastBuffer, + vwapFastColorBuffer, + vwapFastStateBuffer // + ); + + // + // Mid ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapMidLength, + showVWapMedium, + vwapMidBuffer, + vwapMidColorBuffer, + vwapMidStateBuffer // + ); + + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapSlowLength, + showVWapSlow, + vwapSlowBuffer, + vwapSlowColorBuffer, + vwapSlowStateBuffer // + ); +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateDonchains( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + CalculateDonchain( + // + bar_index, + prevCalculated, + ratesTotal, + // + open, + high, + close, + low, + tickVolume, + // + donchainLength, + // + donOpenUpperBuffer, + donOpenLowerBuffer, + donHighUpperBuffer, + donHighLowerBuffer, + donLowUpperBuffer, + donLowLowerBuffer, + donCloseUpperBuffer, + donCloseLowerBuffer // + ); +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateAtrZones( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Select ATr Value ... + double atrValue = atrBuffer[bar_index]; + double appliedAtrMultiplierValue = atrValue * atrMultiplier; + + // + // Select Upper Price ... + double upperPrice = GetAppliedPrice( + atrUpperAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Select Lower Price ... + double lowerPrice = GetAppliedPrice( + atrLowerAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Calculate Raw Atrs ... + + // + // Upper ... + double atrUpperRawValue = upperPrice + appliedAtrMultiplierValue; + atrUpperRawBuffer[bar_index] = atrUpperRawValue; + + // + // Lower ... + double atrLowerRawValue = lowerPrice - appliedAtrMultiplierValue; + atrLowerRawBuffer[bar_index] = atrLowerRawValue; + + // + bool canSmooth = atrSmoothingMode != X_MA_MODE_NONE; + if (canSmooth) + { + // + // Upper ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrUpperRawBuffer, + atrUpperBuffer, + atrSmoothingMode // + ); + + // + // Lower ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrLowerRawBuffer, + atrLowerBuffer, + atrSmoothingMode // + ); + } + else + { + // + // Use Raw Values ... + atrUpperBuffer[bar_index] = atrUpperRawValue; + atrLowerBuffer[bar_index] = atrLowerRawValue; + } +} + +/** + * Calculate Fibonacci Levels ... + * + * @param bar_index: Integer, current Bar Index ... + */ +void CalculateFibonacci( + int bar_index // +) +{ + // + double fiboUpper = 0; + double fiboLower = 0; + + // + fiboUpper = peaksBuffer[bar_index]; + fiboLower = valesBuffer[bar_index]; + + // + // Level 1 ... + bool canCalculateFiboLevel1 = fiboLevel1 > 0; + if (canCalculateFiboLevel1) + { + // + double iFib = GetFibonacciLevel( + fiboUpper, + fiboLower, + fiboLevel1, + 1 // + ); + + // + fl1Buffer[bar_index] = iFib; + } + + // + // Level 2 ... + bool canCalculateFiboLevel2 = fiboLevel2 > 0; + if (canCalculateFiboLevel2) + { + // + double iFib = GetFibonacciLevel( + fiboUpper, + fiboLower, + fiboLevel2, + 1 // + ); + + // + fl2Buffer[bar_index] = iFib; + } + + // + // Level 3 ... + bool canCalculateFiboLevel3 = fiboLevel3 > 0; + if (canCalculateFiboLevel3) + { + // + double iFib = GetFibonacciLevel( + fiboUpper, + fiboLower, + fiboLevel3, + 1 // + ); + + // + fl3Buffer[bar_index] = iFib; + } + + // + // Level 4 ... + bool canCalculateFiboLevel4 = fiboLevel4 > 0; + if (canCalculateFiboLevel4) + { + // + double iFib = GetFibonacciLevel( + fiboUpper, + fiboLower, + fiboLevel4, + 1 // + ); + + // + fl4Buffer[bar_index] = iFib; + } + + // + // Level 5 ... + bool canCalculateFiboLevel5 = fiboLevel5 > 0; + if (canCalculateFiboLevel5) + { + // + double iFib = GetFibonacciLevel( + fiboUpper, + fiboLower, + fiboLevel5, + 1 // + ); + + // + fl5Buffer[bar_index] = iFib; + } + + // +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.xempty.mq5 b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.xempty.mq5 new file mode 100644 index 0000000..bec347c --- /dev/null +++ b/BKPS/14031106/Documents/BKP/1/x-saherelm.x121.xempty.mq5 @@ -0,0 +1,325 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 ??? +// Description: ??? ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 ??? Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 ???" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; + +// +// Presentation ... +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// Plot Buffers ... + +// +// Data Buffers ... + +// +int mLastBufferIndex = 20; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + false + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // Data Buffers ... +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Documents/BKP/2/tmp.signalling.mq5 b/BKPS/14031106/Documents/BKP/2/tmp.signalling.mq5 new file mode 100644 index 0000000..7b17600 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/2/tmp.signalling.mq5 @@ -0,0 +1,1302 @@ + + // + // X Signal ... + bool DetectXSignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_X; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXConditions.setupTime; + bool isSetuped = mXConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXSiganlSetup( + symbol, + period, + mXConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXConditions.dir; + setupTime = mXConditions.setupTime; + + // // + // bool hasPivot = mXConditions.pivotZone.IsValid(); + // if (hasPivot) + // { + // // + // XCBaseObject *drawnObjects[]; + // int drawnCount = DrawX121SMCXConditions( + // mXConditions, + // drawnObjects, + // mPOIDrawer // + // ); + // if (IsValidSize(drawnCount)) + // { + // AddObjectsIfNotExists(drawnObjects); + // } + // } + + // + if (isSetuped) + { + // + int items = AddX121SMCXConditionsIfNotExists( + mXConditions, + mXConditionsCollection // + ); + + // + mXConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXSignalConditions mTmpConditions[]; + Copy( + mXConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXSiganlTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + + // + // XPZ Signal ... + bool DetectXPZSignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XPZ; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXPZConditions.setupTime; + bool isSetuped = mXPZConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXPZConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXPZSiganlSetup( + symbol, + period, + mXPZConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXPZConditions.dir; + setupTime = mXPZConditions.setupTime; + + // + if (isSetuped) + { + // + int items = AddX121SMCXPZConditionsIfNotExists( + mXPZConditions, + mXPZConditionsCollection // + ); + + // + mXPZConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXPZConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXPZSignalConditions mTmpConditions[]; + Copy( + mXPZConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXPZSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXPZSiganlTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXPZConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXPZConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + + // + // XPVT Signal ... + bool DetectXPVTSignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XPVT; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXPVTConditions.setupTime; + bool isSetuped = mXPVTConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXPVTConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXPVTSiganlSetup( + symbol, + period, + mXPVTConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXPVTConditions.dir; + setupTime = mXPVTConditions.setupTime; + + // + if (isSetuped) + { + // + int items = AddX121SMCXPVTConditionsIfNotExists( + mXPVTConditions, + mXPVTConditionsCollection // + ); + + // + mXPVTConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXPVTConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXPVTSignalConditions mTmpConditions[]; + Copy( + mXPVTConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXPVTSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXPVTSiganlTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXPVTConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXPVTConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + + // + // XSTRPV Signal ... + bool DetectXSTRPVSignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XSTRPV; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXSTRPVConditions.setupTime; + bool isSetuped = mXSTRPVConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXSTRPVConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXSTRPVSiganlSetup( + symbol, + period, + mXSTRPVConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXSTRPVConditions.dir; + setupTime = mXSTRPVConditions.setupTime; + + // + if (isSetuped) + { + // + int items = AddX121SMCXSTRPVConditionsIfNotExists( + mXSTRPVConditions, + mXSTRPVConditionsCollection // + ); + + // + mXSTRPVConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXSTRPVConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXSTRPVSignalConditions mTmpConditions[]; + Copy( + mXSTRPVConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXSTRPVSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXSTRPVSiganlTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXSTRPVConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXSTRPVConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + + // + // XRSPVI Signal ... + bool DetectXRSPVISignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XRSPVI; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXRSPVIConditions.setupTime; + bool isSetuped = mXRSPVIConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXRSPVIConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXRSPVISiganlSetup( + symbol, + period, + mXRSPVIConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXRSPVIConditions.dir; + setupTime = mXRSPVIConditions.setupTime; + + // + if (isSetuped) + { + // + int items = AddX121SMCXRSPVIConditionsIfNotExists( + mXRSPVIConditions, + mXRSPVIConditionsCollection // + ); + + // + mXRSPVIConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXRSPVIConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXRSPVISignalConditions mTmpConditions[]; + Copy( + mXRSPVIConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXRSPVISignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXRSPVISiganlTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXRSPVIConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXRSPVIConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + +//////////////////////////////////////////////////////// + + + // + // X Signal ... + if (useXSignal && !hasSignal) + { + // + hasXSignal = DetectXSignal(conditions); + hasSignal = hasXSignal; + } + + // + // XPZ Signal ... + if (useXPZSignal && !hasSignal) + { + // + hasXPZSignal = DetectXPZSignal(conditions); + hasSignal = hasXPZSignal; + } + + // + // XPVT Signal ... + if (useXPVTSignal && !hasSignal) + { + // + hasXPVTSignal = DetectXPVTSignal(conditions); + hasSignal = hasXPVTSignal; + } + + // + // XRSPVI Signal ... + if (useXRSPVISignal && !hasSignal) + { + // + hasXRSPVISignal = DetectXRSPVISignal(conditions); + hasSignal = hasXRSPVISignal; + } + + // + // XSTRPV Signal ... + if (useXSTRPVSignal && !hasSignal) + { + // + hasXSTRPVSignal = DetectXSTRPVSignal(conditions); + hasSignal = hasXSTRPVSignal; + } + + +///////////////////////////////////////////////////////////////// + + + // + // X Guard Detection ... + if (useXSignal) + { + // + bool hasGuard = DetectX121SMCXGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // + // XPZ Guard Detection ... + if (useXPZSignal) + { + // + bool hasGuard = DetectX121SMCXPZGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // + // XPVT Guard Detection ... + if (useXPVTSignal) + { + // + bool hasGuard = DetectX121SMCXPVTGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // + // XSTRPV Guard Detection ... + if (useXSTRPVSignal) + { + // + bool hasGuard = DetectX121SMCXSTRPVGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // + // XRSPVI Guard Detection ... + if (useXRSPVISignal) + { + // + bool hasGuard = DetectX121SMCXRSPVIGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + +////////////////////////////////////////////////// + +const string X121SMCXPVTToken = "X121XPVT"; +const string X121SMCXRSPVIToken = "X121XRSPVI"; +const string X121SMCXSTRPVToken = "X121XSTRPV"; +const string X121SMCXPZToken = "X121XPZ"; + + // + switch (value) + { + // + case X_121_SMC_PROVIDER_X: + result = X121SMCXToken; + break; + + // + case X_121_SMC_PROVIDER_XPZ: + result = X121SMCXOBPVToken; + break; + + // + case X_121_SMC_PROVIDER_XPVT: + result = X121SMCXPVTToken; + break; + + // + case X_121_SMC_PROVIDER_XRSPVI: + result = X121SMCXRSPVIToken; + break; + + // + case X_121_SMC_PROVIDER_XSTRPV: + result = X121SMCXSTRPVToken; + break; + } + + // + if (Contains(X121SMCXToken, value)) + { + result = X_121_SMC_PROVIDER_X; + } + else if (Contains(X121SMCXOBPVToken, value)) + { + result = X_121_SMC_PROVIDER_XOBPV; + } + else if (Contains(X121SMCXPVTToken, value)) + { + result = X_121_SMC_PROVIDER_XPVT; + } + else if (Contains(X121SMCXRSPVIToken, value)) + { + result = X_121_SMC_PROVIDER_XRSPVI; + } + else if (Contains(X121SMCXSTRPVToken, value)) + { + result = X_121_SMC_PROVIDER_XSTRPV; + } diff --git a/BKPS/14031106/Documents/BKP/2/x-121.smc.xpvt.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/2/x-121.smc.xpvt.signal.lib.mq5 new file mode 100644 index 0000000..51ea129 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/2/x-121.smc.xpvt.signal.lib.mq5 @@ -0,0 +1,2484 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: X +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXPVTSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + double peak; + datetime peakTime; + + // + double higherPeak; + datetime higherPeakTime; + + // + double vale; + datetime valeTime; + + // + double lowerVale; + datetime lowerValeTime; + + // + ENUM_XPV_PIVOTS pvType; + + // + XPVPivot pivotZone; + + // + // Constructor ... + X121SMCStrategyXPVTSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + pvType = XPV_NONE; + + // + peak = 0; + peakTime = NULL; + + // + higherPeak = 0; + higherPeakTime = NULL; + + // + vale = 0; + valeTime = NULL; + + // + lowerVale = 0; + lowerValeTime = NULL; + + // + pivotZone.Clean(); + } + + // + bool HasPeak() + { + // + bool result = false; + + // + result = + peak > 0 && + IsValid(peakTime); + + // + return result; + } + + // + bool HasHigherPeak() + { + // + bool result = false; + + // + result = + higherPeak > 0 && + IsValid(higherPeakTime); + + // + return result; + } + + // + bool HasVale() + { + // + bool result = false; + + // + result = + vale > 0 && + IsValid(valeTime); + + // + return result; + } + + // + bool HasLowerVale() + { + // + bool result = false; + + // + result = + lowerVale > 0 && + IsValid(lowerValeTime); + + // + return result; + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXPVTSignalConditions mXPVTConditions; +X121SMCStrategyXPVTSignalConditions mXPVTConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXPVTSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXPVTSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + // zBar.Init( + // symbol, + // period, + // zIndex // + // ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + // cBar.Init( + // symbol, + // period, + // cIndex // + // ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + // pBar.Init( + // symbol, + // period, + // pIndex // + // ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // PinBar ... + ENUM_X_DIRECTION cBarPinDir; + bool isCBarPin = decisionCycleHelper + .mBarAnalyser + .IsPinBar( + cBar, + cBarPinDir, + 1 // + ); + bool isCBarBullishPin = + isCBarPin && + IsBullish(cBarPinDir); + bool isCBarBearishPin = + isCBarPin && + IsBearish(cBarPinDir); + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // Pull Back ... + ENUM_X_DIRECTION cBarPullbackDir; + bool isCBarPullbacked = + decisionCycleHelper + .mBarAnalyser + .HasPullBack( + cBarPullbackDir, + cBar // + ); + bool isCBarBullishPullbacked = + isCBarPullbacked && + IsBullish(cBarPullbackDir); + bool isCBarBearishPullbacked = + isCBarPullbacked && + IsBearish(cBarPullbackDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bars Pattern and Power and Pressures ... + + // + bool hasCBarBullishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBullishPattern( + cBar, + 2 // + ); + + // + bool hasCBarBearishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBearishPattern( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPower = + decisionCycleHelper + .mBarAnalyser + .HasBullishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPower = + decisionCycleHelper + .mBarAnalyser + .HasBearishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBullishPressure( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBearishPressure( + cBar, + 2 // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + ( + // + hasCBarBullishPattern && + isCBarHasBullishPower && + isCBarHasBullishPressure + // + ) + // + || + // + ( + // + isCBarBullishPin || + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ) + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + ( + // + hasCBarBearishPattern && + isCBarHasBearishPower && + isCBarHasBearishPressure + // + ) + // + || + // + ( + // + isCBarBearishPin || + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ) + // + ; + + // + // Now we Have to Detect Higher Peak and Lower Vale + // Zones ... + + // + bool hasPeak = conditions.HasPeak(); + bool hasVale = conditions.HasVale(); + + // + int higherPeakIDX = -1; + int higherPeakStartIDX = -1; + datetime higherPeakTime = NULL; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper + .GetHigherPeak( + higherPeakIDX, + decisionXConditions.peaksBuffer[1] // + ); + bool hasHigherPeak = + higherPeak > 0 && + IsValidIndex(higherPeakIDX); + if (hasHigherPeak) + { + // + // Detect Higher Peak Start Index ... + int idx = higherPeakIDX; + bool canContinue = true; + while (canContinue) + { + // + double iPeak = decisionCycleHelper + .mX121Helper + .xpvHelper + .GetPeak(idx); + canContinue = iPeak == higherPeak; + if (!canContinue) + { + break; + } + + // + idx++; + } + + // + if (idx > higherPeakIDX) + { + higherPeakStartIDX = idx - 1; + } + } + + // + int lowerValeIDX = -1; + int lowerValeStartIDX = -1; + datetime lowerValeTime = NULL; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper + .GetLowerVale( + lowerValeIDX, + decisionXConditions.valesBuffer[1] // + ); + bool hasLowerVale = + lowerVale > 0 && + IsValidIndex(lowerValeIDX); + if (hasLowerVale) + { + // + // Detect Lower Vale Start Index ... + int idx = lowerValeIDX; + bool canContinue = true; + while (canContinue) + { + // + double iVale = decisionCycleHelper + .mX121Helper + .xpvHelper + .GetVale(idx); + canContinue = iVale == lowerVale; + if (!canContinue) + { + break; + } + + // + idx++; + } + + // + if (idx > lowerValeIDX) + { + lowerValeStartIDX = idx - 1; + } + } + + // + if (hasHigherPeak) + { + // + XOHCL higherPeakStartBar; + bool isInited = higherPeakStartBar.Init( + symbol, + period, + higherPeakStartIDX // + ); + if (isInited) + { + higherPeakTime = higherPeakStartBar.time; + } + } + + // + if (hasLowerVale) + { + // + XOHCL lowerValeStartBar; + bool isInited = lowerValeStartBar.Init( + symbol, + period, + lowerValeStartIDX // + ); + if (isInited) + { + lowerValeTime = lowerValeStartBar.time; + } + } + + // + // Detect Pivot ... + + // + double pivotPremiumDiscount = 0; + + // + bool isPivotUpperUpBreaked = false; + bool isPivotUpperDownBreaked = false; + bool isPivotUpperDownRejected = false; + + // + bool isPivotLowerUpBreaked = false; + bool isPivotLowerUpRejected = false; + bool isPivotLowerDownBreaked = false; + + // + bool isPriceInPivotPremium = false; + bool isPriceInPivotDiscount = false; + + // + bool isPivotPremiumUpBreaked = false; + bool isPivotPremiumDownBreaked = false; + bool isPivotPremiumUpRejected = false; + bool isPivotPremiumDownRejected = false; + + // + bool isPivotDiscountUpBreaked = false; + bool isPivotDiscountDownBreaked = false; + bool isPivotDiscountUpRejected = false; + bool isPivotDiscountDownRejected = false; + + // + bool hasPivot = conditions.pivotZone.IsValid(); + + // + if (!hasPivot) + { + // + bool isSamePeaks = decisionXConditions.peaksBuffer[1] == + decisionXConditions.peaksBuffer[2] && + decisionXConditions.peaksBuffer[2] == + decisionXConditions.peaksBuffer[3]; + bool isSameCyclePeaks = decisionXConditions.peaksBuffer[1] == + analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == + verificationXConditions.peaksBuffer[1]; + // + bool isSameVales = decisionXConditions.valesBuffer[1] == + decisionXConditions.valesBuffer[2] && + decisionXConditions.valesBuffer[2] == + decisionXConditions.valesBuffer[3]; + bool isSameCycleVales = decisionXConditions.valesBuffer[1] == + analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == + verificationXConditions.valesBuffer[1]; + + // + bool isNewPeak = + !hasPeak && + hasLowerVale && + hasHigherPeak && + decisionXConditions.isNewPeakUnderLast; + if (isNewPeak) + { + // + conditions.pvType = XPV_PEAK; + + // + conditions.peakTime = cTime; + conditions.peak = decisionXConditions.peaksBuffer[1]; + + // + conditions.higherPeakTime = higherPeakTime; + conditions.higherPeak = higherPeak; + + // + conditions.valeTime = cTime; + conditions.vale = decisionXConditions.valesBuffer[1]; + + // + conditions.lowerValeTime = lowerValeTime; + conditions.lowerVale = lowerVale; + + // + hasPeak = conditions.HasPeak(); + hasVale = conditions.HasVale(); + } + + // + bool isNewVale = + !hasVale && + !isNewPeak && + hasLowerVale && + hasHigherPeak && + decisionXConditions.isNewValeOverLast; + if (isNewVale) + { + // + conditions.pvType = XPV_PEAK; + + // + conditions.peakTime = cTime; + conditions.peak = decisionXConditions.peaksBuffer[1]; + + // + conditions.higherPeakTime = higherPeakTime; + conditions.higherPeak = higherPeak; + + // + conditions.valeTime = cTime; + conditions.vale = decisionXConditions.valesBuffer[1]; + + // + conditions.lowerValeTime = lowerValeTime; + conditions.lowerVale = lowerVale; + + // + hasPeak = conditions.HasPeak(); + hasVale = conditions.HasVale(); + } + + // + if (isNewPeak || isNewVale) + { + // + XPVPivot pivot; + + // + pivot.symbol = symbol; + pivot.period = period; + + // + pivot.repetition = MathMax( + higherPeakIDX, + lowerValeIDX // + ); + pivot.type = conditions.pvType; + + // + pivot.upper = higherPeak; + pivot.lower = lowerVale; + + // + bool isHigherPeakOlder = + conditions.higherPeakTime < conditions.lowerValeTime; + + // + pivot.to = cTime; + pivot.from = + isHigherPeakOlder + ? conditions.higherPeakTime + : conditions.lowerValeTime; + + // + pivot.type = + isHigherPeakOlder + ? XPV_PEAK + : XPV_VALE; + + // + hasPivot = pivot.IsValid(); + if (hasPivot) + { + conditions.pivotZone = pivot; + } + + // + } + + // + // Has Pivot ... + hasPivot = conditions.pivotZone.IsValid(); + } + + // + if (hasPivot) + { + // + // Check Pivot Validation ... + + // + bool isPivotDied = + // + (cBar.low > conditions.pivotZone.upper && + cBar.close > conditions.pivotZone.upper) + // + || + // + (cBar.high < conditions.pivotZone.lower && + cBar.close < conditions.pivotZone.lower) + // + ; + if (isPivotDied) + { + conditions.Clean(); + } + + // + hasPivot = conditions.pivotZone.IsValid(); + if (hasPivot) + { + // + // Detect Pivot States ... + + // + XPOIState analysePivotState; + DetectPivotPOIs( + conditions.pivotZone, + analyseState, + analysePivotState // + ); + + // + XPOIState decisionPivotState; + DetectPivotPOIs( + conditions.pivotZone, + decisionState, + decisionPivotState // + ); + + // + // Combine two State ... + XPOIState combinedPivotState; + XPOIState iStates[]; + // AddRef( + // analysePivotState, + // iStates // + // ); + AddRef( + decisionPivotState, + iStates // + ); + CombineStates( + combinedPivotState, + iStates // + ); + combinedPivotState = decisionPivotState; + + // + ArrayFree(iStates); + + // + combinedPivotState.time = decisionPivotState.time; + combinedPivotState.symbol = decisionPivotState.symbol; + combinedPivotState.period = decisionPivotState.period; + + // + // Hold Only Areas Which on Upper or Lower bondary of Pivot Zone ... + FilterPivotState( + conditions.pivotZone, + combinedPivotState // + ); + + // + conditions.pivotZone.state = combinedPivotState; + + // + // Calculate Pivot Ticks Zone ... + + // + int ticksLevels = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneLevel(); + int ticksRange = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneRange(); + + // + CalculatePivotTickZone( + conditions.pivotZone, + ticksLevels, + ticksRange // + ); + + // + // Try to Fill up Pivot Conditions ... + + // + XOHCL pivotCBar; + bool isCInited = triggerCycleHelper.GetBar( + pivotCBar, + cIndex // + ); + + // + XOHCL pivotPBar; + bool isPInited = triggerCycleHelper.GetBar( + pivotPBar, + pIndex // + ); + + // + double upper = conditions.pivotZone.upper; + double lower = conditions.pivotZone.lower; + pivotPremiumDiscount = conditions.pivotZone.CalculateMid(); + + // + // Pivot Upper ... + + // + isPivotUpperUpBreaked = + isCInited && + IsBarBreak( + upper, + X_DIRECTION_BULLISH, + pivotCBar // + ); + + // + isPivotUpperDownBreaked = + isCInited && + IsBarBreak( + upper, + X_DIRECTION_BEARISH, + pivotCBar // + ); + + // + isPivotUpperDownRejected = + isCInited && + IsBarReject( + upper, + X_DIRECTION_BEARISH, + pivotCBar // + ); + + // + // Pivot Lower ... + + // + isPivotLowerUpBreaked = + isCInited && + IsBarBreak( + lower, + X_DIRECTION_BULLISH, + pivotCBar // + ); + + // + isPivotLowerUpRejected = + isCInited && + IsBarReject( + lower, + X_DIRECTION_BULLISH, + pivotCBar // + ); + + // + isPivotLowerDownBreaked = + isCInited && + IsBarBreak( + lower, + X_DIRECTION_BEARISH, + pivotCBar // + ); + + // + // Pivot Premium / Discount ... + + // + bool isPriceInPivotPremium = + isCInited && + ask < upper && + bid < upper && + ask > pivotPremiumDiscount && + bid > pivotPremiumDiscount; + + // + bool isPriceInPivotDiscount = + isCInited && + ask > lower && + bid > lower && + ask < pivotPremiumDiscount && + bid < pivotPremiumDiscount; + + // + // + // + + // + isPivotPremiumUpBreaked = + isCInited && + isPInited && + IsBarBreak( + pivotPremiumDiscount, + X_DIRECTION_BULLISH, + pivotCBar // + ) && + pivotPBar.high > pivotPremiumDiscount; + + // + isPivotPremiumDownBreaked = + isCInited && + isPInited && + IsBarBreak( + pivotPremiumDiscount, + X_DIRECTION_BEARISH, + pivotCBar // + ) && + pivotPBar.high > pivotPremiumDiscount; + + // + isPivotPremiumUpRejected = + isCInited && + isPInited && + IsBarReject( + pivotPremiumDiscount, + X_DIRECTION_BULLISH, + pivotCBar // + ) && + pivotPBar.high > pivotPremiumDiscount; + + // + isPivotPremiumDownRejected = + isCInited && + isPInited && + IsBarReject( + pivotPremiumDiscount, + X_DIRECTION_BEARISH, + pivotCBar // + ) && + pivotPBar.high > pivotPremiumDiscount; + + // + // + // + + // + isPivotDiscountUpBreaked = + isCInited && + isPInited && + IsBarBreak( + pivotPremiumDiscount, + X_DIRECTION_BULLISH, + pivotCBar // + ) && + pivotPBar.low < pivotPremiumDiscount; + + // + isPivotDiscountDownBreaked = + isCInited && + isPInited && + IsBarBreak( + pivotPremiumDiscount, + X_DIRECTION_BEARISH, + pivotCBar // + ) && + pivotPBar.low < pivotPremiumDiscount; + + // + isPivotDiscountUpRejected = + isCInited && + isPInited && + IsBarReject( + pivotPremiumDiscount, + X_DIRECTION_BULLISH, + pivotCBar // + ) && + pivotPBar.low < pivotPremiumDiscount; + + // + isPivotDiscountDownRejected = + isCInited && + isPInited && + IsBarReject( + pivotPremiumDiscount, + X_DIRECTION_BEARISH, + pivotCBar // + ) && + pivotPBar.low < pivotPremiumDiscount; + + // + // Detect Bar Patterns ... + + // + if (isCBarBullishRejected) + { + // + int count = conditions.pivotZone.state.CountBullishRejectionBars(); + isCBarBullishRejected = IsValidSize(count); + if (isCBarBullishRejected) + { + // + bool hasBar = false; + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iBar = conditions.pivotZone.state.bullishRejectionBars[i]; + + // + hasBar = iBar.BarTime() == cBar.time; + if (hasBar) + { + break; + } + } + + // + isCBarBullishRejected = hasBar; + } + } + + // + if (isCBarBearishRejected) + { + // + int count = conditions.pivotZone.state.CountBearishRejectionBars(); + isCBarBearishRejected = IsValidSize(count); + if (isCBarBearishRejected) + { + // + bool hasBar = false; + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iBar = conditions.pivotZone.state.bearishRejectionBars[i]; + + // + hasBar = iBar.BarTime() == cBar.time; + if (hasBar) + { + break; + } + } + + // + isCBarBearishRejected = hasBar; + } + } + + // + // Draw Pivot ... + // XCBaseObject *drawnObjects[]; + // triggerCycleHelper.mPOIDetector.mDrawer.DrawPivot( + // conditions.pivotZone, + // drawnObjects, + // true, // Draw State ... + // false, // State As Box ... + // true // Tick Zone ... + // ); + } + } + + // + // + // + + // + // Summarize Conditions ... + + // + bool isCondition1Bullish = + // + hasPivot && + // + // XSTR ... + decisionXConditions.isStrBullish && + // + // XCHE ... + (consolidationXConditions.isCheBullish && + consolidationXConditions.isClosedOverCheMin && + cBar.low > consolidationXConditions.cheMax) && + // + // XPV ... + (isCBarBullishRejected && + pBar.open > cBar.close && + decisionXConditions.isNewValeUnderLast && + decisionXConditions.valesBuffer[1] > conditions.pivotZone.lower) && + // + true + // + ; + + // + bool isCondition1Bearish = + // + hasPivot && + // + // XSTR ... + decisionXConditions.isStrBearish && + // + // XCHE ... + (consolidationXConditions.isCheBearish && + consolidationXConditions.isClosedUnderCheMin && + cBar.high < consolidationXConditions.cheMin) && + // + // XPV ... + (isCBarBearishRejected && + pBar.open < cBar.close && + decisionXConditions.isNewPeakOverLast && + decisionXConditions.peaksBuffer[1] < conditions.pivotZone.upper) && + // + true + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = pivotPremiumDiscount; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCondition1Bullish + ? conditions.pivotZone.upper + : conditions.pivotZone.lower; + + // + // conditions.Clean(); + // isCondition1Bullish = false; + // isCondition1Bearish = false; + } + + // + // + // + + // + isBullish = + // + isCondition1Bullish + // + ; + + // + isBearish = + // + isCondition1Bearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXPVTSiganlTrigger( + // + X121SMCStrategyXPVTSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // SAR ... + double sar = decisionXConditions.sarBuffer[1]; + + // + // STR ... + double str = decisionXConditions.strBuffer[1]; + + // + // CHE ... + double le1 = decisionXConditions.le1Buffer[1]; + double le2 = decisionXConditions.le2Buffer[1]; + double se1 = decisionXConditions.se1Buffer[1]; + double se2 = decisionXConditions.se2Buffer[1]; + + // + // ATR ... + double atrUpper = decisionXConditions.atrUpperBuffer[1]; + double atrLower = decisionXConditions.atrLowerBuffer[1]; + + // + // PV ... + double peak = decisionXConditions.peaksBuffer[1]; + double vale = decisionXConditions.valesBuffer[1]; + + // + int higherPeakIDX = -1; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper.GetHigherPeak( + higherPeakIDX, + peak // + ); + + // + int lowerValeIDX = -1; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper.GetLowerVale( + lowerValeIDX, + vale // + ); + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + // bool isPointBreaked = + // isBullish + // ? ask > point && bid > point + // : ask < point && bid < point; + bool isPointBreaked = IsBarBreak( + point, + setupDir, + cBar // + ); + + // + // Summary ... + + // + isBullish = + // + isBullish && + // isPointBreaked && + // isSlopesBullish && + cBar.IsBullish() + // + ; + + // + isBearish = + // + isBearish && + // isPointBreaked && + // isSlopesBearish && + cBar.IsBearish() + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + decisionState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + + // + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + } + target = 0; + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double momentumBarPointsDif = 30 * points; + + // + // Bullish Momentum Bar Selection ... + XOHCL bullishMomentumBar; + int bullishMomentumBarsCount = decisionState.CountBullishMomentumBars(); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.low) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bullishMomentumBar.IsValid() || + (bullishMomentumBar.IsValid() && + bullishMomentumBar.low < entry && + bullishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bullishMomentumBar = iBar; + } + } + } + + // + // Bearish Momentum Bar Selection ... + XOHCL bearishMomentumBar; + int bearishMomentumBarsCount = decisionState.CountBearishMomentumBars(); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.high) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bearishMomentumBar.IsValid() || + (bearishMomentumBar.IsValid() && + bearishMomentumBar.high > entry && + bearishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bearishMomentumBar = iBar; + } + } + } + + // + double sls[]; + Add( + sar, + sls // + ); + Add( + str, + sls // + ); + + // + if (isBullish) + { + // + Add( + atrLower, + sls // + ); + + // // + // Add( + // vale, + // sls // + // ); + + // + if (bullishMomentumBar.IsValid()) + { + // + Add( + bullishMomentumBar.low, + sls // + ); + } + + // // + // if (IsValidIndex(lowerValeIDX)) + // { + // // + // Add( + // lowerVale, + // sls // + // ); + // } + + // + if (le1 != EMPTY_VALUE) + { + // + Add( + le1, + sls // + ); + } + + // + if (le2 != EMPTY_VALUE) + { + // + Add( + le2, + sls // + ); + } + } + else + { + // + Add( + atrUpper, + sls // + ); + + // // + // Add( + // peak, + // sls // + // ); + + // + if (bearishMomentumBar.IsValid()) + { + // + Add( + bearishMomentumBar.high, + sls // + ); + } + + // + // if (IsValidIndex(higherPeakIDX)) + // { + // // + // Add( + // higherPeak, + // sls // + // ); + // } + + // + if (se1 != EMPTY_VALUE) + { + // + Add( + se1, + sls // + ); + } + + // + if (se2 != EMPTY_VALUE) + { + // + Add( + se2, + sls // + ); + } + } + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + iAtr *= 1.5; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double riskInPoints = risk / points; + if (riskInPoints >= 150) + { + // + target = + isBullish + ? entry + (points * 200) + : entry - (points * 200); + + // + target = 0; + } + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXPVTGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_X); + + // + // result = DetectX121SMCGuards( + // provider, + // guards, + // positions, + // triggerCycleHelper, + // decisionCycleHelper, + // analyseCycleHelper, + // verificationCycleHelper, + // consolidationCycleHelper, + // visionCycleHelper // + // ); + + // + return result; +} + +// +int AddX121SMCXPVTConditionsIfNotExists( + X121SMCStrategyXPVTSignalConditions &item, + X121SMCStrategyXPVTSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXPVTSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXPVTSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXPVTConditions( + X121SMCStrategyXPVTSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool hasPivot = conditions.pivotZone.IsValid(); + if (hasPivot) + { + // + XCBaseObject *pivotObjects[]; + drawer.DrawPivot( + conditions.pivotZone, + pivotObjects, + true, // State ... + false, // State as Box ... + false // Ticks Zone ... + ); + + // + Copy( + pivotObjects, + drawnObjects, + false // + ); + } + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/2/x-121.smc.xpz.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/2/x-121.smc.xpz.signal.lib.mq5 new file mode 100644 index 0000000..25d660f --- /dev/null +++ b/BKPS/14031106/Documents/BKP/2/x-121.smc.xpz.signal.lib.mq5 @@ -0,0 +1,1700 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XPZ +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXPZSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + XPriceZones priceZone; + bool isPriceZoneValidForPeak; + bool isPriceZoneValidForVale; + + // + // Constructor ... + X121SMCStrategyXPZSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + priceZone.Clean(); + isPriceZoneValidForPeak = false; + isPriceZoneValidForVale = false; + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXPZSignalConditions mXPZConditions; +X121SMCStrategyXPZSignalConditions mXPZConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXPZSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXPZSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ; + + // + // Detect Price Zone ... + + // + double pzPeak = decisionXConditions.peaksBuffer[1]; + double pzVale = decisionXConditions.valesBuffer[1]; + + // + // Detecting Decision Price ones ... + XPriceZones decisionPriceZone; + bool hasDecisionPriceZone = CalculatePriceInsideZones( + decisionPriceZone, + decisionState, + cBar // + ); + double decisionPriceZoneUpper = 0; + double decisionPriceZoneLower = 0; + bool isDecisionPriceZoneValidForPeak = false; + bool isDecisionPriceZoneValidForVale = false; + if (hasDecisionPriceZone) + { + // + bool hasBoundary = decisionPriceZone.GetBoundary( + X_DIRECTION_ALL, + decisionPriceZoneUpper, + decisionPriceZoneLower // + ); + + // + isDecisionPriceZoneValidForPeak = + hasBoundary && + pzPeak <= decisionPriceZoneUpper && + pzPeak >= decisionPriceZoneLower; + + // + isDecisionPriceZoneValidForVale = + hasBoundary && + pzVale <= decisionPriceZoneUpper && + pzVale >= decisionPriceZoneLower; + } + + // + // Detecting Analyse Price ones ... + XPriceZones analysePriceZone; + bool hasAnalysePriceZone = CalculatePriceInsideZones( + analysePriceZone, + analyseState, + cBar // + ); + double analysePriceZoneUpper = 0; + double analysePriceZoneLower = 0; + bool isAnalysePriceZoneValidForPeak = false; + bool isAnalysePriceZoneValidForVale = false; + if (hasAnalysePriceZone) + { + // + bool hasBoundary = analysePriceZone.GetBoundary( + X_DIRECTION_ALL, + analysePriceZoneUpper, + analysePriceZoneLower // + ); + + // + isAnalysePriceZoneValidForPeak = + hasBoundary && + pzPeak <= analysePriceZoneUpper && + pzPeak >= analysePriceZoneLower; + + // + isAnalysePriceZoneValidForVale = + hasBoundary && + pzVale <= analysePriceZoneUpper && + pzVale >= analysePriceZoneLower; + } + + // + // Detecting Verification Price ones ... + XPriceZones verificationPriceZone; + bool hasVerificationPriceZone = CalculatePriceInsideZones( + verificationPriceZone, + verificationState, + cBar // + ); + double verificationPriceZoneUpper = 0; + double verificationPriceZoneLower = 0; + bool isVerificationPriceZoneValidForPeak = false; + bool isVerificationPriceZoneValidForVale = false; + if (hasVerificationPriceZone) + { + // + bool hasBoundary = verificationPriceZone.GetBoundary( + X_DIRECTION_ALL, + verificationPriceZoneUpper, + verificationPriceZoneLower // + ); + + // + isVerificationPriceZoneValidForPeak = + hasBoundary && + pzPeak <= verificationPriceZoneUpper && + pzPeak >= verificationPriceZoneLower; + + // + isVerificationPriceZoneValidForVale = + hasBoundary && + pzVale <= verificationPriceZoneUpper && + pzVale >= verificationPriceZoneLower; + } + + // + // + // + + // + // Summarize Conditions ... + + // + double decisionPVMiddle = decisionXConditions.valesBuffer[1] + + (decisionXConditions.peaksBuffer[1] - decisionXConditions.valesBuffer[1]) / 2; + bool isInDecisionPremium = + // + ask > decisionPVMiddle && + bid > decisionPVMiddle && + // + ask < decisionXConditions.peaksBuffer[1] && + bid < decisionXConditions.peaksBuffer[1] + // + ; + bool isInDecisionDiscount = + // + ask < decisionPVMiddle && + bid < decisionPVMiddle && + // + ask < decisionXConditions.valesBuffer[1] && + bid < decisionXConditions.valesBuffer[1] + // + ; + + // + bool isPriceZoneBullish = + // + hasVerificationBullishTrend && + hasAnalyseBullishTrend && + hasDecisionBullishTrend && + // + hasAnalysePriceZone && + analysePriceZone.IsBullish() && + isAnalysePriceZoneValidForVale && + // + isCBarBullishFormed && + isInDecisionDiscount && + decisionXConditions.isAtrLowerUnderVale && + decisionXConditions.isAtrLowerSlopeBullish && + // + true + // + ; + + // + bool isPriceZoneBearish = + // + hasVerificationBearishTrend && + hasAnalyseBearishTrend && + hasDecisionBearishTrend && + // + hasAnalysePriceZone && + analysePriceZone.IsBearish() && + isAnalysePriceZoneValidForPeak && + // + isInDecisionPremium && + isCBarBearishFormed && + decisionXConditions.isAtrUpperOverPeak && + decisionXConditions.isAtrUpperSlopeBearish && + // + true + // + ; + + // + bool hasPriceZoneCondition = isPriceZoneBullish || + isPriceZoneBearish; + if (hasPriceZoneCondition) + { + // + ENUM_X_DIRECTION pzDir = + isPriceZoneBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + conditions.priceZone = analysePriceZone; + conditions.isPriceZoneValidForPeak = isAnalysePriceZoneValidForPeak; + conditions.isPriceZoneValidForVale = isAnalysePriceZoneValidForVale; + + // + pzPeak = analysePriceZoneUpper; + pzVale = analysePriceZoneLower; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + // point = + // isPriceZoneBullish ? pzPeak + // : pzVale; + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isPriceZoneBullish + ? pzVale + : pzPeak; + } + + // + // + // + + // + isBullish = + isPriceZoneBullish; + + // + isBearish = + isPriceZoneBearish; + + // + result = isBullish || + isBearish; + if (!result) + { + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXPZSiganlTrigger( + // + X121SMCStrategyXPZSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // SAR ... + double sar = decisionXConditions.sarBuffer[1]; + + // + // STR ... + double str = decisionXConditions.strBuffer[1]; + + // + // CHE ... + double le1 = decisionXConditions.le1Buffer[1]; + double le2 = decisionXConditions.le2Buffer[1]; + double se1 = decisionXConditions.se1Buffer[1]; + double se2 = decisionXConditions.se2Buffer[1]; + + // + // ATR ... + double atrUpper = decisionXConditions.atrUpperBuffer[1]; + double atrLower = decisionXConditions.atrLowerBuffer[1]; + + // + // PV ... + double peak = decisionXConditions.peaksBuffer[1]; + double vale = decisionXConditions.valesBuffer[1]; + + // + int higherPeakIDX = -1; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper.GetHigherPeak( + higherPeakIDX, + peak // + ); + + // + int lowerValeIDX = -1; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper.GetLowerVale( + lowerValeIDX, + vale // + ); + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = IsBarBreak( + point, + setupDir, + cBar // + ); + + // + // Summary ... + + // + isBullish = + // + isBullish && + isPointBreaked && + // isSlopesBullish && + cBar.IsBullish() + // + ; + + // + isBearish = + // + isBearish && + isPointBreaked && + // isSlopesBearish && + cBar.IsBearish() + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + decisionState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + + // + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + } + target = 0; + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double momentumBarPointsDif = 30 * points; + + // + // Bullish Momentum Bar Selection ... + XOHCL bullishMomentumBar; + int bullishMomentumBarsCount = decisionState.CountBullishMomentumBars(); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.low) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bullishMomentumBar.IsValid() || + (bullishMomentumBar.IsValid() && + bullishMomentumBar.low < entry && + bullishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bullishMomentumBar = iBar; + } + } + } + + // + // Bearish Momentum Bar Selection ... + XOHCL bearishMomentumBar; + int bearishMomentumBarsCount = decisionState.CountBearishMomentumBars(); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.high) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bearishMomentumBar.IsValid() || + (bearishMomentumBar.IsValid() && + bearishMomentumBar.high > entry && + bearishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bearishMomentumBar = iBar; + } + } + } + + // + double sls[]; + Add( + sar, + sls // + ); + Add( + str, + sls // + ); + + // + if (isBullish) + { + // + Add( + atrLower, + sls // + ); + + // // + // Add( + // vale, + // sls // + // ); + + // + if (bullishMomentumBar.IsValid()) + { + // + Add( + bullishMomentumBar.low, + sls // + ); + } + + // // + // if (IsValidIndex(lowerValeIDX)) + // { + // // + // Add( + // lowerVale, + // sls // + // ); + // } + + // + if (le1 != EMPTY_VALUE) + { + // + Add( + le1, + sls // + ); + } + + // + if (le2 != EMPTY_VALUE) + { + // + Add( + le2, + sls // + ); + } + } + else + { + // + Add( + atrUpper, + sls // + ); + + // // + // Add( + // peak, + // sls // + // ); + + // + if (bearishMomentumBar.IsValid()) + { + // + Add( + bearishMomentumBar.high, + sls // + ); + } + + // + // if (IsValidIndex(higherPeakIDX)) + // { + // // + // Add( + // higherPeak, + // sls // + // ); + // } + + // + if (se1 != EMPTY_VALUE) + { + // + Add( + se1, + sls // + ); + } + + // + if (se2 != EMPTY_VALUE) + { + // + Add( + se2, + sls // + ); + } + } + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double riskInPoints = risk / points; + if (riskInPoints >= 150) + { + // + target = + isBullish + ? entry + (points * 200) + : entry - (points * 200); + + // + target = 0; + } + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXPZGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_XPZ); + + // + result = DetectX121SMCGuards( + provider, + guards, + positions, + triggerCycleHelper, + decisionCycleHelper, + analyseCycleHelper, + verificationCycleHelper, + consolidationCycleHelper, + visionCycleHelper // + ); + + // + return result; +} + +// +int AddX121SMCXPZConditionsIfNotExists( + X121SMCStrategyXPZSignalConditions &item, + X121SMCStrategyXPZSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXPZSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXPZSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXPZConditions( + X121SMCStrategyXPZSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool hasPriceZone = conditions.priceZone.IsValid(); + if (!hasPriceZone) + { + return result; + } + + // + int zonesObjCount = drawer.DrawPriceZone( + conditions.priceZone, + drawnObjects, + conditions.dir // + ); + result = zonesObjCount; + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/2/x-121.smc.xrspvi.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/2/x-121.smc.xrspvi.signal.lib.mq5 new file mode 100644 index 0000000..8d156d5 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/2/x-121.smc.xrspvi.signal.lib.mq5 @@ -0,0 +1,2483 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XRSPVI +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +enum ENUM_X121_SMC_XRSPVI_CONDITIONS +{ + // + X121_SMC_XRSPVI_CONDITION_NONE, + X121_SMC_XRSPVI_CONDITION_1, + X121_SMC_XRSPVI_CONDITION_2, + X121_SMC_XRSPVI_CONDITION_3, + X121_SMC_XRSPVI_CONDITION_4, + X121_SMC_XRSPVI_CONDITION_5, +}; + +// +// Definitions ... +struct X121SMCStrategyXRSPVISignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + XPriceZones priceZone; + bool isPriceZoneValidForPeak; + bool isPriceZoneValidForVale; + + // + XPVPivot pivotZone; + XConsolidationZone consolidationZone; + + // + ENUM_X121_SMC_XRSPVI_CONDITIONS mode; + + // + // Constructor ... + X121SMCStrategyXRSPVISignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + pivotZone.Clean(); + priceZone.Clean(); + consolidationZone.Clean(); + isPriceZoneValidForPeak = false; + isPriceZoneValidForVale = false; + + // + mode = X121_SMC_XRSPVI_CONDITION_NONE; + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXRSPVISignalConditions mXRSPVIConditions; +X121SMCStrategyXRSPVISignalConditions mXRSPVIConditionsCollection[]; + +// +double X121SMCXRSPVIPivotPeak; +double X121SMCXRSPVIPivotVale; +datetime X121SMCXRSPVIPivotEnd; +datetime X121SMCXRSPVIPivotStart; +ENUM_XPV_PIVOTS X121SMCXRSPVIPivotType = XPV_NONE; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXRSPVISiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXRSPVISignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ; + + // + // Detect Price Zone ... + + // + double pzPeak = decisionXConditions.peaksBuffer[1]; + double pzVale = decisionXConditions.valesBuffer[1]; + + // + // Detecting Decision Price ones ... + XPriceZones decisionPriceZone; + bool hasDecisionPriceZone = CalculatePriceInsideZones( + decisionPriceZone, + decisionState, + cBar // + ); + double decisionPriceZoneUpper = 0; + double decisionPriceZoneLower = 0; + bool isDecisionPriceZoneBullish = false; + bool isDecisionPriceZoneBearish = false; + bool isDecisionPriceZoneValidForPeak = false; + bool isDecisionPriceZoneValidForVale = false; + + // + if (hasDecisionPriceZone) + { + // + bool hasBoundary = decisionPriceZone.GetBoundary( + X_DIRECTION_ALL, + decisionPriceZoneUpper, + decisionPriceZoneLower // + ); + + // + isDecisionPriceZoneValidForPeak = + hasBoundary && + pzPeak <= decisionPriceZoneUpper && + pzPeak >= decisionPriceZoneLower; + + // + isDecisionPriceZoneValidForVale = + hasBoundary && + pzVale <= decisionPriceZoneUpper && + pzVale >= decisionPriceZoneLower; + + // + isDecisionPriceZoneBullish = + hasBoundary && + decisionPriceZone.IsBullish(); + + // + isDecisionPriceZoneBearish = + hasBoundary && + decisionPriceZone.IsBearish(); + } + + // + // Detecting Analyse Price ones ... + XPriceZones analysePriceZone; + bool hasAnalysePriceZone = CalculatePriceInsideZones( + analysePriceZone, + analyseState, + cBar // + ); + double analysePriceZoneUpper = 0; + double analysePriceZoneLower = 0; + bool isAnalysePriceZoneBullish = false; + bool isAnalysePriceZoneBearish = false; + bool isAnalysePriceZoneValidForPeak = false; + bool isAnalysePriceZoneValidForVale = false; + + // + if (hasAnalysePriceZone) + { + // + bool hasBoundary = analysePriceZone.GetBoundary( + X_DIRECTION_ALL, + analysePriceZoneUpper, + analysePriceZoneLower // + ); + + // + isAnalysePriceZoneValidForPeak = + hasBoundary && + pzPeak <= analysePriceZoneUpper && + pzPeak >= analysePriceZoneLower; + + // + isAnalysePriceZoneValidForVale = + hasBoundary && + pzVale <= analysePriceZoneUpper && + pzVale >= analysePriceZoneLower; + + // + isAnalysePriceZoneBullish = + hasBoundary && + analysePriceZone.IsBullish(); + + // + isAnalysePriceZoneBearish = + hasBoundary && + analysePriceZone.IsBearish(); + } + + // + // Detecting Verification Price ones ... + XPriceZones verificationPriceZone; + bool hasVerificationPriceZone = CalculatePriceInsideZones( + verificationPriceZone, + verificationState, + cBar // + ); + double verificationPriceZoneUpper = 0; + double verificationPriceZoneLower = 0; + bool isVerificationPriceZoneBullish = false; + bool isVerificationPriceZoneBearish = false; + bool isVerificationPriceZoneValidForPeak = false; + bool isVerificationPriceZoneValidForVale = false; + + // + if (hasVerificationPriceZone) + { + // + bool hasBoundary = verificationPriceZone.GetBoundary( + X_DIRECTION_ALL, + verificationPriceZoneUpper, + verificationPriceZoneLower // + ); + + // + isVerificationPriceZoneValidForPeak = + hasBoundary && + pzPeak <= verificationPriceZoneUpper && + pzPeak >= verificationPriceZoneLower; + + // + isVerificationPriceZoneValidForVale = + hasBoundary && + pzVale <= verificationPriceZoneUpper && + pzVale >= verificationPriceZoneLower; + + // + isVerificationPriceZoneBullish = + hasBoundary && + verificationPriceZone.IsBullish(); + + // + isVerificationPriceZoneBearish = + hasBoundary && + verificationPriceZone.IsBearish(); + } + + // + // Detect Consolidation Zone ... + int decisionConsolidationLoopback = 7; + double decisionConsolidationZoneLower = 0; + double decisionConsolidationZoneUpper = 0; + bool isDecisionConsolidationZoneBreaked = false; + bool isDecisionConsolidationZoneBreakedUp = false; + bool isDecisionConsolidationZoneBreakedDown = false; + bool hasDecisionConsolidationZone = conditions.consolidationZone.IsValid(); + + // + if (!hasDecisionConsolidationZone) + { + // + XOHCL decisionCBar; + bool isInited = decisionCBar.Init( + decisionCycleHelper.GetSymbol(), + decisionCycleHelper.GetPeriod(), + cIndex // + ); + + // + if (isInited) + { + // + double upper = 0; + double lower = 0; + hasDecisionConsolidationZone = + triggerCycleHelper + .mBarAnalyser + .IsConsolidate( + decisionCBar, + upper, + lower, + decisionConsolidationLoopback // + ); + + // + if (hasDecisionConsolidationZone) + { + // + hasDecisionConsolidationZone = conditions.consolidationZone.Init( + cBar.symbol, + cBar.period, + upper, + lower, + decisionConsolidationLoopback // + ); + } + } + } + + // + if (hasDecisionConsolidationZone) + { + // + conditions.consolidationZone.Update(); + + // + decisionConsolidationZoneLower = conditions.consolidationZone.upper; + decisionConsolidationZoneUpper = conditions.consolidationZone.lower; + + // + isDecisionConsolidationZoneBreaked = conditions.consolidationZone.IsBreaked(); + isDecisionConsolidationZoneBreakedUp = + isDecisionConsolidationZoneBreaked && + IsBullish(conditions.consolidationZone.breakDirection); + isDecisionConsolidationZoneBreakedDown = + isDecisionConsolidationZoneBreaked && + IsBearish(conditions.consolidationZone.breakDirection); + + // + decisionConsolidationZoneLower = triggerXConditions.peaksBuffer[1]; + decisionConsolidationZoneUpper = triggerXConditions.valesBuffer[1]; + + // + if (isDecisionConsolidationZoneBreaked) + { + conditions.consolidationZone.Clean(); + } + } + + // + // + // + + // + double decisionPVMiddle = decisionXConditions.valesBuffer[1] + + (decisionXConditions.peaksBuffer[1] - decisionXConditions.valesBuffer[1]) / 2; + bool isInDecisionPremium = + // + ask > decisionPVMiddle && + bid > decisionPVMiddle && + // + ask < decisionXConditions.peaksBuffer[1] && + bid < decisionXConditions.peaksBuffer[1] + // + ; + bool isInDecisionDiscount = + // + ask < decisionPVMiddle && + bid < decisionPVMiddle && + // + ask < decisionXConditions.valesBuffer[1] && + bid < decisionXConditions.valesBuffer[1] + // + ; + + // + double analysePVMiddle = analyseXConditions.valesBuffer[1] + + (analyseXConditions.peaksBuffer[1] - analyseXConditions.valesBuffer[1]) / 2; + bool isInAnalysePremium = + // + ask > analysePVMiddle && + bid > analysePVMiddle && + // + ask < analyseXConditions.peaksBuffer[1] && + bid < analyseXConditions.peaksBuffer[1] + // + ; + bool isInAnalyseDiscount = + // + ask < analysePVMiddle && + bid < analysePVMiddle && + // + ask < analyseXConditions.valesBuffer[1] && + bid < analyseXConditions.valesBuffer[1] + // + ; + + // + double verificationPVMiddle = verificationXConditions.valesBuffer[1] + + (verificationXConditions.peaksBuffer[1] - verificationXConditions.valesBuffer[1]) / 2; + bool isInVerificationPremium = + // + ask > verificationPVMiddle && + bid > verificationPVMiddle && + // + ask < verificationXConditions.peaksBuffer[1] && + bid < verificationXConditions.peaksBuffer[1] + // + ; + bool isInVerificationDiscount = + // + ask < verificationPVMiddle && + bid < verificationPVMiddle && + // + ask < verificationXConditions.valesBuffer[1] && + bid < verificationXConditions.valesBuffer[1] + // + ; + + // + // Detect PV Pivot ... + + // + bool isPivotPeakZoneRejected = false; + bool isPivotPeakZoneBreakedUp = false; + bool isPivotPeakZoneBreakedDown = false; + bool isPivotValeZoneRejected = false; + bool isPivotValeZoneBreakedUp = false; + bool isPivotValeZoneBreakedDown = false; + bool hasPivot = conditions.pivotZone.IsValid(); + if (!hasPivot) + { + // + hasPivot = IsValid(X121SMCXRSPVIPivotStart); + if (!hasPivot) + { + // + bool isNewVale = decisionXConditions.isNewVale; + bool isNewValeOverLast = decisionXConditions.isNewValeOverLast; + bool isNewValeUnderLast = decisionXConditions.isNewValeUnderLast; + bool isSameVales = decisionXConditions.valesBuffer[1] == + decisionXConditions.valesBuffer[2] && + decisionXConditions.valesBuffer[2] == + decisionXConditions.valesBuffer[3]; + bool isSameCycleVales = decisionXConditions.valesBuffer[1] == + analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == + verificationXConditions.valesBuffer[1]; + + // + bool isNewPeak = decisionXConditions.isNewPeak; + bool isNewPeakOverLast = decisionXConditions.isNewPeakOverLast; + bool isNewPeakUnderLast = decisionXConditions.isNewPeakUnderLast; + bool isSamePeaks = decisionXConditions.peaksBuffer[1] == + decisionXConditions.peaksBuffer[2] && + decisionXConditions.peaksBuffer[2] == + decisionXConditions.peaksBuffer[3]; + bool isSameCyclePeaks = decisionXConditions.peaksBuffer[1] == + analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == + verificationXConditions.peaksBuffer[1]; + + // + bool isValeStart = + // isSameVales; + isSameVales && + isSameCycleVales; + bool isPeakStart = + // isSamePeaks; + isSamePeaks && + isSameCyclePeaks; + + // + bool isStart = isPeakStart || + isValeStart; + if (isStart) + { + // + X121SMCXRSPVIPivotStart = cTime; + X121SMCXRSPVIPivotType = + isPeakStart + ? XPV_PEAK + : XPV_VALE; + + // + X121SMCXRSPVIPivotPeak = decisionXConditions.peaksBuffer[1]; + X121SMCXRSPVIPivotVale = decisionXConditions.valesBuffer[1]; + } + + // + hasPivot = IsValid(X121SMCXRSPVIPivotStart); + + // + // Create XPVPivot instance ... + if (hasPivot) + { + // + conditions.pivotZone.symbol = symbol; + conditions.pivotZone.period = period; + + // + conditions.pivotZone.to = cTime; + conditions.pivotZone.repetition = 3; + + // + conditions.pivotZone.upper = X121SMCXRSPVIPivotPeak; + conditions.pivotZone.lower = X121SMCXRSPVIPivotVale; + + // + conditions.pivotZone.type = X121SMCXRSPVIPivotType; + conditions.pivotZone.from = X121SMCXRSPVIPivotStart; + } + } + } + + // + if (hasPivot) + { + // + bool isBreaked = X121SMCXRSPVIPivotType == XPV_PEAK + ? decisionXConditions.isBreakedUpPrevPeak + : decisionXConditions.isBreakedDownPrevVale; + + // + if (!isBreaked) + { + // + X121SMCXRSPVIPivotPeak = decisionXConditions.peaksBuffer[1]; + X121SMCXRSPVIPivotVale = decisionXConditions.valesBuffer[1]; + + // + conditions.pivotZone.to = cTime; + conditions.pivotZone.repetition++; + conditions.pivotZone.upper = X121SMCXRSPVIPivotPeak; + conditions.pivotZone.lower = X121SMCXRSPVIPivotVale; + } + else + { + // + X121SMCXRSPVIPivotEnd = cTime; + conditions.pivotZone.to = cTime; + } + + // + // Fill Pivot State ... + + // + XPOIState analysePivotState; + DetectPivotPOIs( + conditions.pivotZone, + analyseState, + analysePivotState // + ); + + // + XPOIState decisionPivotState; + DetectPivotPOIs( + conditions.pivotZone, + decisionState, + decisionPivotState // + ); + + // + // Combine two State ... + XPOIState combinedPivotState; + XPOIState iStates[]; + AddRef( + analysePivotState, + iStates // + ); + AddRef( + decisionPivotState, + iStates // + ); + CombineStates( + combinedPivotState, + iStates // + ); + combinedPivotState = decisionPivotState; + + // + ArrayFree(iStates); + + // + combinedPivotState.time = decisionPivotState.time; + combinedPivotState.symbol = decisionPivotState.symbol; + combinedPivotState.period = decisionPivotState.period; + + // + // Hold Only Areas Which on Upper or Lower bondary of Pivot Zone ... + FilterPivotState( + conditions.pivotZone, + combinedPivotState // + ); + + // + conditions.pivotZone.state = combinedPivotState; + + // + double peakUpper = 0; + double peakLower = 0; + double valeUpper = 0; + double valeLower = 0; + + // + datetime peakTo = NULL; + datetime valeTo = NULL; + datetime peakFrom = NULL; + datetime valeFrom = NULL; + + // + bool hasBoxData = DetectPivotStateBoxData( + conditions.pivotZone, + peakUpper, + peakLower, + peakFrom, + peakTo, + valeUpper, + valeLower, + valeFrom, + valeTo // + ); + + // + // Calculate Pivot Tick Zones ... + + // + int ticksLevels = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneLevel(); + int ticksRange = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneRange(); + + // + CalculatePivotTickZone( + conditions.pivotZone, + ticksLevels, + ticksRange // + ); + + // + isPivotPeakZoneRejected = + hasBoxData && + ( + // + IsBarReject( + peakLower, + X_DIRECTION_BEARISH, + cBar // + ) + // + || + // + IsBarReject( + peakUpper, + X_DIRECTION_BEARISH, + cBar // + ) + // + ); + isPivotPeakZoneBreakedUp = + hasBoxData && + IsBarBreak( + peakUpper, + X_DIRECTION_BULLISH, + cBar // + ); + isPivotPeakZoneBreakedDown = + hasBoxData && + IsBarBreak( + peakLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isPivotValeZoneRejected = + hasBoxData && + ( + // + IsBarReject( + valeLower, + X_DIRECTION_BULLISH, + cBar // + ) + // + || + // + IsBarReject( + valeUpper, + X_DIRECTION_BULLISH, + cBar // + ) + // + ); + isPivotValeZoneBreakedUp = + hasBoxData && + IsBarBreak( + valeUpper, + X_DIRECTION_BULLISH, + cBar // + ); + isPivotValeZoneBreakedDown = + hasBoxData && + IsBarBreak( + valeLower, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + bool isPivotEnded = IsValid(X121SMCXRSPVIPivotEnd); + if (isPivotEnded) + { + // + X121SMCXRSPVIPivotPeak = 0; + X121SMCXRSPVIPivotVale = 0; + X121SMCXRSPVIPivotEnd = NULL; + X121SMCXRSPVIPivotStart = NULL; + X121SMCXRSPVIPivotType = XPV_NONE; + + // + conditions.pivotZone.Clean(); + } + + // + // Summarize Conditions ... + + // + bool isCond1Bullish = + // + isInAnalyseDiscount && + isInDecisionDiscount && + isCBarBullishFormed && + // + hasAnalysePriceZone && + isAnalysePriceZoneBullish && + isAnalysePriceZoneValidForVale && + // + analyseXConditions.isRsiCrossedOverOverSold && + // + true + // + ; + + // + bool isCond1Bearish = + // + isInAnalysePremium && + isInDecisionPremium && + isCBarBearishFormed && + // + hasAnalysePriceZone && + isAnalysePriceZoneBearish && + isAnalysePriceZoneValidForPeak && + // + analyseXConditions.isRsiCrossedUnderOverBought && + // + true + // + ; + + // + bool hasCond1Condition = isCond1Bullish || + isCond1Bearish; + if (hasCond1Condition) + { + // + conditions.mode = X121_SMC_XRSPVI_CONDITION_1; + + // + ENUM_X_DIRECTION pzDir = + isCond1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + conditions.priceZone = analysePriceZone; + conditions.isPriceZoneValidForPeak = isAnalysePriceZoneValidForPeak; + conditions.isPriceZoneValidForVale = isAnalysePriceZoneValidForVale; + + // + pzPeak = analysePriceZoneUpper; + pzVale = analysePriceZoneLower; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCond1Bullish + ? pzVale + : pzPeak; + } + + // + // + // + + // + bool isCond2Bullish = + // + hasDecisionBullishTrend && + // + isCBarBullishFormed && + isInAnalyseDiscount && + isInVerificationDiscount && + // + hasVerificationPriceZone && + isVerificationPriceZoneBullish && + isVerificationPriceZoneValidForVale && + // + verificationXConditions.isRsiCrossedOverOverSold && + // + true + // + ; + + // + bool isCond2Bearish = + // + hasDecisionBearishTrend && + // + isCBarBearishFormed && + isInAnalysePremium && + isInVerificationPremium && + // + hasVerificationPriceZone && + isVerificationPriceZoneBearish && + isVerificationPriceZoneValidForPeak && + // + verificationXConditions.isRsiCrossedUnderOverBought && + // + true + // + ; + + // + bool hasCond2Condition = isCond2Bullish || + isCond2Bearish; + if (hasCond2Condition) + { + // + conditions.mode = X121_SMC_XRSPVI_CONDITION_2; + + // + ENUM_X_DIRECTION pzDir = + isCond2Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + conditions.priceZone = verificationPriceZone; + conditions.isPriceZoneValidForPeak = isVerificationPriceZoneValidForPeak; + conditions.isPriceZoneValidForVale = isVerificationPriceZoneValidForVale; + + // + pzPeak = verificationPriceZoneUpper; + pzVale = verificationPriceZoneLower; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCond2Bullish + ? pzVale + : pzPeak; + } + + // + // + // + + // + bool isCond3Bullish = + // + isCBarBullishFormed && + hasDecisionBullishTrend && + decisionXConditions.isSarBullish && + decisionXConditions.isStrCrossedOverVale && + // + true + // + ; + + // + bool isCond3Bearish = + // + isCBarBearishFormed && + hasDecisionBearishTrend && + decisionXConditions.isSarBearish && + decisionXConditions.isStrCrossedUnderPeak && + // + true + // + ; + + // + bool hasCond3Conditions = isCond3Bullish || + isCond3Bearish; + if (hasCond3Conditions) + { + // + conditions.mode = X121_SMC_XRSPVI_CONDITION_3; + + // + ENUM_X_DIRECTION pzDir = + isCond3Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Manipulate Conditions Point ... + + // + conditions.point = decisionXConditions.strBuffer[1]; + + // + // Manipulate Conditions Pivot ... + + // + double pivot = decisionXConditions.sarBuffer[1]; + pivot = (decisionXConditions.sarBuffer[1] + decisionXConditions.strBuffer[1]) / 2; + + // + conditions.pivot = + isCond3Bullish + ? pivot + : pivot; + } + + // + // + // + + // + bool isCond4Bullish = + // + isCBarBullishFormed && + isInDecisionDiscount && + hasDecisionBullishTrend && + hasDecisionConsolidationZone && + isDecisionConsolidationZoneBreakedUp && + // + true + // + ; + + // + bool isCond4Bearish = + // + isInDecisionPremium && + isCBarBearishFormed && + hasDecisionBearishTrend && + hasDecisionConsolidationZone && + isDecisionConsolidationZoneBreakedDown && + // + true + // + ; + + // + bool hasCond4Conditions = isCond4Bullish || + isCond4Bearish; + if (hasCond4Conditions) + { + // + conditions.mode = X121_SMC_XRSPVI_CONDITION_4; + + // + ENUM_X_DIRECTION pzDir = + isCond4Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Manipulate Conditions Point ... + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + pzPeak = decisionConsolidationZoneUpper; + pzVale = decisionConsolidationZoneLower; + + // + conditions.pivot = + isCond4Bullish + ? pzVale + : pzPeak; + } + + // + // + // + + // + bool isCond5Bullish = + // + hasDecisionBullishTrend && + isPivotValeZoneRejected + // + ; + + // + bool isCond5Bearish = + // + hasDecisionBearishTrend && + isPivotPeakZoneRejected + // + ; + + // + bool hasCond5Conditions = isCond5Bullish || + isCond5Bearish; + + // + isBullish = + isCond5Bullish && + (isCond1Bullish || + isCond2Bullish || + isCond3Bullish || + isCond4Bullish); + + // + isBearish = + isCond5Bearish && + (isCond1Bearish || + isCond2Bearish || + isCond3Bearish || + isCond4Bearish); + + // + result = isBullish || + isBearish; + if (!result) + { + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXRSPVISiganlTrigger( + // + X121SMCStrategyXRSPVISignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // SAR ... + double sar = decisionXConditions.sarBuffer[1]; + + // + // STR ... + double str = decisionXConditions.strBuffer[1]; + + // + // CHE ... + double le1 = decisionXConditions.le1Buffer[1]; + double le2 = decisionXConditions.le2Buffer[1]; + double se1 = decisionXConditions.se1Buffer[1]; + double se2 = decisionXConditions.se2Buffer[1]; + + // + // ATR ... + double atrUpper = decisionXConditions.atrUpperBuffer[1]; + double atrLower = decisionXConditions.atrLowerBuffer[1]; + + // + // PV ... + double peak = decisionXConditions.peaksBuffer[1]; + double vale = decisionXConditions.valesBuffer[1]; + + // + int higherPeakIDX = -1; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper.GetHigherPeak( + higherPeakIDX, + peak // + ); + + // + int lowerValeIDX = -1; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper.GetLowerVale( + lowerValeIDX, + vale // + ); + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = IsBarBreak( + point, + setupDir, + cBar // + ); + + // + bool isCond124 = + // + conditions.mode == X121_SMC_XRSPVI_CONDITION_1 || + conditions.mode == X121_SMC_XRSPVI_CONDITION_2 || + conditions.mode == X121_SMC_XRSPVI_CONDITION_4 + // + ; + + // + // Summary ... + + // + isBullish = + // + isBullish && + isSlopesBullish && + cBar.IsBullish() && + ( + // + (isCond124 && + isPointBreaked) + // + || + // + (!isCond124 && + decisionXConditions.isStrBullish && + decisionXConditions.isStrSlopeBullish && + decisionXConditions.strBuffer[1] > conditions.point && + decisionXConditions.strBuffer[1] > decisionXConditions.strBuffer[2]) + // + ) + // + ; + + // + isBearish = + // + isBearish && + isSlopesBearish && + cBar.IsBearish() && + ( + // + (isCond124 && + isPointBreaked) + // + || + // + (!isCond124 && + decisionXConditions.isStrBearish && + decisionXConditions.isStrSlopeBearish && + decisionXConditions.strBuffer[1] < conditions.point && + decisionXConditions.strBuffer[1] < decisionXConditions.strBuffer[2]) + // + ) + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + decisionState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + + // + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + } + target = 0; + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double momentumBarPointsDif = 30 * points; + + // + // Bullish Momentum Bar Selection ... + XOHCL bullishMomentumBar; + int bullishMomentumBarsCount = decisionState.CountBullishMomentumBars(); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.low) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bullishMomentumBar.IsValid() || + (bullishMomentumBar.IsValid() && + bullishMomentumBar.low < entry && + bullishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bullishMomentumBar = iBar; + } + } + } + + // + // Bearish Momentum Bar Selection ... + XOHCL bearishMomentumBar; + int bearishMomentumBarsCount = decisionState.CountBearishMomentumBars(); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.high) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bearishMomentumBar.IsValid() || + (bearishMomentumBar.IsValid() && + bearishMomentumBar.high > entry && + bearishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bearishMomentumBar = iBar; + } + } + } + + // + double sls[]; + Add( + sar, + sls // + ); + Add( + str, + sls // + ); + + // + if (isBullish) + { + // + Add( + atrLower, + sls // + ); + + // // + // Add( + // vale, + // sls // + // ); + + // + if (bullishMomentumBar.IsValid()) + { + // + Add( + bullishMomentumBar.low, + sls // + ); + } + + // // + // if (IsValidIndex(lowerValeIDX)) + // { + // // + // Add( + // lowerVale, + // sls // + // ); + // } + + // + if (le1 != EMPTY_VALUE) + { + // + Add( + le1, + sls // + ); + } + + // + if (le2 != EMPTY_VALUE) + { + // + Add( + le2, + sls // + ); + } + } + else + { + // + Add( + atrUpper, + sls // + ); + + // // + // Add( + // peak, + // sls // + // ); + + // + if (bearishMomentumBar.IsValid()) + { + // + Add( + bearishMomentumBar.high, + sls // + ); + } + + // + // if (IsValidIndex(higherPeakIDX)) + // { + // // + // Add( + // higherPeak, + // sls // + // ); + // } + + // + if (se1 != EMPTY_VALUE) + { + // + Add( + se1, + sls // + ); + } + + // + if (se2 != EMPTY_VALUE) + { + // + Add( + se2, + sls // + ); + } + } + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double riskInPoints = risk / points; + if (riskInPoints >= 150) + { + // + target = + isBullish + ? entry + (points * 200) + : entry - (points * 200); + + // + target = 0; + } + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXRSPVIGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_XRSPVI); + + // + result = DetectX121SMCGuards( + provider, + guards, + positions, + triggerCycleHelper, + decisionCycleHelper, + analyseCycleHelper, + verificationCycleHelper, + consolidationCycleHelper, + visionCycleHelper // + ); + + // + return result; +} + +// +int AddX121SMCXRSPVIConditionsIfNotExists( + X121SMCStrategyXRSPVISignalConditions &item, + X121SMCStrategyXRSPVISignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXRSPVISignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXRSPVISignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXRSPVIConditions( + X121SMCStrategyXRSPVISignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool hasPriceZone = conditions.priceZone.IsValid(); + if (!hasPriceZone) + { + return result; + } + + // + int zonesObjCount = drawer.DrawPriceZone( + conditions.priceZone, + drawnObjects, + conditions.dir // + ); + result = zonesObjCount; + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/BKP/2/x-121.smc.xstrpv.signal.lib.mq5 b/BKPS/14031106/Documents/BKP/2/x-121.smc.xstrpv.signal.lib.mq5 new file mode 100644 index 0000000..7f774b2 --- /dev/null +++ b/BKPS/14031106/Documents/BKP/2/x-121.smc.xstrpv.signal.lib.mq5 @@ -0,0 +1,2097 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XSTRPV +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-121.smc.guard.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXSTRPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + XPriceZones priceZone; + bool isPriceZoneValidForPeak; + bool isPriceZoneValidForVale; + + // + XPVPivot pivotZone; + + // + // Constructor ... + X121SMCStrategyXSTRPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + priceZone.Clean(); + pivotZone.Clean(); + isPriceZoneValidForPeak = false; + isPriceZoneValidForVale = false; + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXSTRPVSignalConditions mXSTRPVConditions; +X121SMCStrategyXSTRPVSignalConditions mXSTRPVConditionsCollection[]; + +// +double X121SMCXSTRPVPivotPeak; +double X121SMCXSTRPVPivotVale; +datetime X121SMCXSTRPVPivotEnd; +datetime X121SMCXSTRPVPivotStart; +ENUM_XPV_PIVOTS X121SMCXSTRPVPivotType = XPV_NONE; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXSTRPVSiganlSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXSTRPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ; + + // + // Detect PV Pivot ... + + // + bool isPivotPeakZoneRejected = false; + bool isPivotPeakZoneBreakedUp = false; + bool isPivotPeakZoneBreakedDown = false; + bool isPivotValeZoneRejected = false; + bool isPivotValeZoneBreakedUp = false; + bool isPivotValeZoneBreakedDown = false; + bool hasPivot = conditions.pivotZone.IsValid(); + if (!hasPivot) + { + // + hasPivot = IsValid(X121SMCXSTRPVPivotStart); + if (!hasPivot) + { + // + bool isNewVale = decisionXConditions.isNewVale; + bool isNewValeOverLast = decisionXConditions.isNewValeOverLast; + bool isNewValeUnderLast = decisionXConditions.isNewValeUnderLast; + bool isSameVales = decisionXConditions.valesBuffer[1] == + decisionXConditions.valesBuffer[2] && + decisionXConditions.valesBuffer[2] == + decisionXConditions.valesBuffer[3]; + bool isSameCycleVales = decisionXConditions.valesBuffer[1] == + analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == + verificationXConditions.valesBuffer[1]; + + // + bool isNewPeak = decisionXConditions.isNewPeak; + bool isNewPeakOverLast = decisionXConditions.isNewPeakOverLast; + bool isNewPeakUnderLast = decisionXConditions.isNewPeakUnderLast; + bool isSamePeaks = decisionXConditions.peaksBuffer[1] == + decisionXConditions.peaksBuffer[2] && + decisionXConditions.peaksBuffer[2] == + decisionXConditions.peaksBuffer[3]; + bool isSameCyclePeaks = decisionXConditions.peaksBuffer[1] == + analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == + verificationXConditions.peaksBuffer[1]; + + // + bool isValeStart = + // isSameVales; + isSameVales && + isSameCycleVales; + bool isPeakStart = + // isSamePeaks; + isSamePeaks && + isSameCyclePeaks; + + // + bool isStart = isPeakStart || + isValeStart; + if (isStart) + { + // + X121SMCXSTRPVPivotStart = cTime; + X121SMCXSTRPVPivotType = + isPeakStart + ? XPV_PEAK + : XPV_VALE; + + // + X121SMCXSTRPVPivotPeak = decisionXConditions.peaksBuffer[1]; + X121SMCXSTRPVPivotVale = decisionXConditions.valesBuffer[1]; + } + + // + hasPivot = IsValid(X121SMCXSTRPVPivotStart); + + // + // Create XPVPivot instance ... + if (hasPivot) + { + // + conditions.pivotZone.symbol = symbol; + conditions.pivotZone.period = period; + + // + conditions.pivotZone.to = cTime; + conditions.pivotZone.repetition = 3; + + // + conditions.pivotZone.upper = X121SMCXSTRPVPivotPeak; + conditions.pivotZone.lower = X121SMCXSTRPVPivotVale; + + // + conditions.pivotZone.type = X121SMCXSTRPVPivotType; + conditions.pivotZone.from = X121SMCXSTRPVPivotStart; + } + } + } + + // + if (hasPivot) + { + // + bool isBreaked = X121SMCXSTRPVPivotType == XPV_PEAK + ? decisionXConditions.isBreakedUpPrevPeak + : decisionXConditions.isBreakedDownPrevVale; + + // + if (!isBreaked) + { + // + X121SMCXSTRPVPivotPeak = decisionXConditions.peaksBuffer[1]; + X121SMCXSTRPVPivotVale = decisionXConditions.valesBuffer[1]; + + // + conditions.pivotZone.to = cTime; + conditions.pivotZone.repetition++; + conditions.pivotZone.upper = X121SMCXSTRPVPivotPeak; + conditions.pivotZone.lower = X121SMCXSTRPVPivotVale; + } + else + { + // + X121SMCXSTRPVPivotEnd = cTime; + conditions.pivotZone.to = cTime; + } + + // + // Fill Pivot State ... + + // + XPOIState analysePivotState; + DetectPivotPOIs( + conditions.pivotZone, + analyseState, + analysePivotState // + ); + + // + XPOIState decisionPivotState; + DetectPivotPOIs( + conditions.pivotZone, + decisionState, + decisionPivotState // + ); + + // + // Combine two State ... + XPOIState combinedPivotState; + XPOIState iStates[]; + AddRef( + analysePivotState, + iStates // + ); + AddRef( + decisionPivotState, + iStates // + ); + CombineStates( + combinedPivotState, + iStates // + ); + combinedPivotState = decisionPivotState; + + // + ArrayFree(iStates); + + // + combinedPivotState.time = decisionPivotState.time; + combinedPivotState.symbol = decisionPivotState.symbol; + combinedPivotState.period = decisionPivotState.period; + + // + // Hold Only Areas Which on Upper or Lower bondary of Pivot Zone ... + FilterPivotState( + conditions.pivotZone, + combinedPivotState // + ); + + // + conditions.pivotZone.state = combinedPivotState; + + // + double peakUpper = 0; + double peakLower = 0; + double valeUpper = 0; + double valeLower = 0; + + // + datetime peakTo = NULL; + datetime valeTo = NULL; + datetime peakFrom = NULL; + datetime valeFrom = NULL; + + // + bool hasBoxData = DetectPivotStateBoxData( + conditions.pivotZone, + peakUpper, + peakLower, + peakFrom, + peakTo, + valeUpper, + valeLower, + valeFrom, + valeTo // + ); + + // + // Calculate Pivot Tick Zones ... + + // + int ticksLevels = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneLevel(); + int ticksRange = decisionCycleHelper + .mPOIDetector + .TicksRangeZoneRange(); + + // + CalculatePivotTickZone( + conditions.pivotZone, + ticksLevels, + ticksRange // + ); + + // + isPivotPeakZoneRejected = + hasBoxData && + ( + // + IsBarReject( + peakLower, + X_DIRECTION_BEARISH, + cBar // + ) + // + || + // + IsBarReject( + peakUpper, + X_DIRECTION_BEARISH, + cBar // + ) + // + ); + isPivotPeakZoneBreakedUp = + hasBoxData && + IsBarBreak( + peakUpper, + X_DIRECTION_BULLISH, + cBar // + ); + isPivotPeakZoneBreakedDown = + hasBoxData && + IsBarBreak( + peakLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + isPivotValeZoneRejected = + hasBoxData && + ( + // + IsBarReject( + valeLower, + X_DIRECTION_BULLISH, + cBar // + ) + // + || + // + IsBarReject( + valeUpper, + X_DIRECTION_BULLISH, + cBar // + ) + // + ); + isPivotValeZoneBreakedUp = + hasBoxData && + IsBarBreak( + valeUpper, + X_DIRECTION_BULLISH, + cBar // + ); + isPivotValeZoneBreakedDown = + hasBoxData && + IsBarBreak( + valeLower, + X_DIRECTION_BEARISH, + cBar // + ); + } + + // + bool isPivotEnded = IsValid(X121SMCXSTRPVPivotEnd); + if (isPivotEnded) + { + // + X121SMCXSTRPVPivotPeak = 0; + X121SMCXSTRPVPivotVale = 0; + X121SMCXSTRPVPivotEnd = NULL; + X121SMCXSTRPVPivotStart = NULL; + X121SMCXSTRPVPivotType = XPV_NONE; + + // + conditions.pivotZone.Clean(); + } + + // + // Detect Price Zone ... + + // + double pzPeak = decisionXConditions.peaksBuffer[1]; + double pzVale = decisionXConditions.valesBuffer[1]; + + // + // Detecting Analyse Price ones ... + XPriceZones analysePriceZone; + bool hasAnalysePriceZone = CalculatePriceInsideZones( + analysePriceZone, + analyseState, + cBar // + ); + double analysePriceZoneUpper = 0; + double analysePriceZoneLower = 0; + bool isAnalysePriceZoneValidForPeak = false; + bool isAnalysePriceZoneValidForVale = false; + if (hasAnalysePriceZone) + { + // + bool hasBoundary = analysePriceZone.GetBoundary( + X_DIRECTION_ALL, + analysePriceZoneUpper, + analysePriceZoneLower // + ); + + // + isAnalysePriceZoneValidForPeak = + hasBoundary && + pzPeak <= analysePriceZoneUpper && + pzPeak >= analysePriceZoneLower; + + // + isAnalysePriceZoneValidForVale = + hasBoundary && + pzVale <= analysePriceZoneUpper && + pzVale >= analysePriceZoneLower; + } + + // + // Detecting Verification Price ones ... + XPriceZones verificationPriceZone; + bool hasVerificationPriceZone = CalculatePriceInsideZones( + verificationPriceZone, + verificationState, + cBar // + ); + double verificationPriceZoneUpper = 0; + double verificationPriceZoneLower = 0; + bool isVerificationPriceZoneValidForPeak = false; + bool isVerificationPriceZoneValidForVale = false; + if (hasVerificationPriceZone) + { + // + bool hasBoundary = verificationPriceZone.GetBoundary( + X_DIRECTION_ALL, + verificationPriceZoneUpper, + verificationPriceZoneLower // + ); + + // + isVerificationPriceZoneValidForPeak = + hasBoundary && + pzPeak <= verificationPriceZoneUpper && + pzPeak >= verificationPriceZoneLower; + + // + isVerificationPriceZoneValidForVale = + hasBoundary && + pzVale <= verificationPriceZoneUpper && + pzVale >= verificationPriceZoneLower; + } + + // + // + // + + // + // Summarize Conditions ... + + // + // Decision Conditions ... + + // + bool isDecisionBullish = + // + hasPivot && + // + hasAnalysePriceZone && + analysePriceZone.IsBullish() && + isAnalysePriceZoneValidForVale && + // + // Decision ... + hasVerificationBullishTrend && + hasAnalyseBullishTrend && + hasDecisionBullishTrend && + decisionXConditions.isBreakedDownPrevAtrUpper && + ( + // + ((decisionXConditions.isSarBullish && + decisionXConditions.isCheBullish && + decisionXConditions.isBreakedUpPrevStr && + decisionXConditions.isStrSwitchedToBullish) || + (decisionXConditions.isStrBullish && + decisionXConditions.isSarBullish && + decisionXConditions.isBreakedUpPrevCheMax && + decisionXConditions.isCheSwitchedToBullish) || + (decisionXConditions.isStrBullish && + decisionXConditions.isCheBullish && + decisionXConditions.isBreakedUpPrevSar && + decisionXConditions.isSarSwitchedToBullish)) + // + ) + // + ; + + // + bool isDecisionBearish = + // + hasPivot && + // + hasAnalysePriceZone && + analysePriceZone.IsBearish() && + isAnalysePriceZoneValidForPeak && + // + // Decision ... + hasVerificationBearishTrend && + hasAnalyseBearishTrend && + hasDecisionBearishTrend && + decisionXConditions.isBreakedDownPrevAtrLower && + ( + // + ((decisionXConditions.isSarBearish && + decisionXConditions.isCheBearish && + decisionXConditions.isBreakedDownPrevStr && + decisionXConditions.isStrSwitchedToBearish) || + (decisionXConditions.isStrBearish && + decisionXConditions.isSarBearish && + decisionXConditions.isCheSwitchedToBearish && + decisionXConditions.isBreakedDownPrevCheMin) || + (decisionXConditions.isStrBearish && + decisionXConditions.isCheBearish && + decisionXConditions.isBreakedDownPrevSar && + decisionXConditions.isSarSwitchedToBearish)) + // + ) + // + ; + + // + bool hasDecisionCondition = isDecisionBullish || + isDecisionBearish; + if (hasDecisionCondition) + { + // + conditions.priceZone = analysePriceZone; + conditions.isPriceZoneValidForPeak = isAnalysePriceZoneValidForPeak; + conditions.isPriceZoneValidForVale = isAnalysePriceZoneValidForVale; + + // + pzPeak = analysePriceZoneUpper; + pzVale = analysePriceZoneLower; + + // + double point = GetEntry( + conditions.symbol, + conditions.dir // + ); + + // + // Manipulate Conditions Point ... + + // + point = + isDecisionBullish ? pzPeak + : pzVale; + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isDecisionBullish + ? pzVale + : pzPeak; + } + + // + // Analyse Conditions ... + + // + bool isAnalyseBullish = + // + hasPivot && + // + !hasDecisionCondition && + // + hasVerificationPriceZone && + verificationPriceZone.IsBullish() && + isVerificationPriceZoneValidForVale && + // + hasConsolidationBullishTrend && + hasVerificationBullishTrend && + hasAnalyseBullishTrend && + analyseXConditions.isBreakedDownPrevAtrUpper && + // + ( + // + ((analyseXConditions.isSarBullish && + analyseXConditions.isCheBullish && + analyseXConditions.isBreakedUpPrevStr && + analyseXConditions.isStrSwitchedToBullish) || + (analyseXConditions.isStrBullish && + analyseXConditions.isSarBullish && + analyseXConditions.isBreakedUpPrevCheMax && + analyseXConditions.isCheSwitchedToBullish) || + (analyseXConditions.isStrBullish && + analyseXConditions.isCheBullish && + analyseXConditions.isBreakedUpPrevSar && + analyseXConditions.isSarSwitchedToBullish)) + // + ) + // + ; + + // + bool isAnalyseBearish = + // + hasPivot && + // + !hasDecisionCondition && + // + hasVerificationPriceZone && + verificationPriceZone.IsBearish() && + isVerificationPriceZoneValidForPeak && + // + hasConsolidationBearishTrend && + hasVerificationBearishTrend && + hasAnalyseBearishTrend && + analyseXConditions.isBreakedDownPrevAtrLower && + // + ( + // + ((analyseXConditions.isSarBearish && + analyseXConditions.isCheBearish && + analyseXConditions.isBreakedDownPrevStr && + analyseXConditions.isStrSwitchedToBearish) || + (analyseXConditions.isStrBearish && + analyseXConditions.isSarBearish && + analyseXConditions.isCheSwitchedToBearish && + analyseXConditions.isBreakedDownPrevCheMin) || + (analyseXConditions.isStrBearish && + analyseXConditions.isCheBearish && + analyseXConditions.isBreakedDownPrevSar && + analyseXConditions.isSarSwitchedToBearish)) + // + ) + // + ; + + // + bool hasAnalyseCondition = isAnalyseBullish || + isAnalyseBearish; + if (hasAnalyseCondition) + { + // + conditions.priceZone = analysePriceZone; + conditions.isPriceZoneValidForPeak = isVerificationPriceZoneValidForPeak; + conditions.isPriceZoneValidForVale = isVerificationPriceZoneValidForVale; + + // + pzPeak = analysePriceZoneUpper; + pzVale = analysePriceZoneLower; + + // + double point = GetEntry( + conditions.symbol, + conditions.dir // + ); + + // + // Manipulate Conditions Point ... + + // + point = + isAnalyseBullish ? pzPeak + : pzVale; + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isAnalyseBullish + ? pzVale + : pzPeak; + } + + // + // + // + + // + isBullish = + isAnalyseBullish || + isDecisionBullish; + + // + isBearish = + isAnalyseBearish || + isDecisionBearish; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXSTRPVSiganlTrigger( + // + X121SMCStrategyXSTRPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // SAR ... + double sar = decisionXConditions.sarBuffer[1]; + + // + // STR ... + double str = decisionXConditions.strBuffer[1]; + + // + // CHE ... + double le1 = decisionXConditions.le1Buffer[1]; + double le2 = decisionXConditions.le2Buffer[1]; + double se1 = decisionXConditions.se1Buffer[1]; + double se2 = decisionXConditions.se2Buffer[1]; + + // + // ATR ... + double atrUpper = decisionXConditions.atrUpperBuffer[1]; + double atrLower = decisionXConditions.atrLowerBuffer[1]; + + // + // PV ... + double peak = decisionXConditions.peaksBuffer[1]; + double vale = decisionXConditions.valesBuffer[1]; + + // + int higherPeakIDX = -1; + double higherPeak = decisionCycleHelper + .mX121Helper + .xpvHelper.GetHigherPeak( + higherPeakIDX, + peak // + ); + + // + int lowerValeIDX = -1; + double lowerVale = decisionCycleHelper + .mX121Helper + .xpvHelper.GetLowerVale( + lowerValeIDX, + vale // + ); + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = IsBarBreak( + point, + setupDir, + cBar // + ); + + // + // Summary ... + + // + isBullish = + // + isBullish && + isPointBreaked && + isSlopesBullish && + cBar.IsBullish() + // + ; + + // + isBearish = + // + isBearish && + isPointBreaked && + isSlopesBearish && + cBar.IsBearish() + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + // Detect Target ... + double target = CalculateTarget( + cBar, + decisionState, + setupDir // + ); + if (target == 0) + { + // + target = CalculateTarget( + cBar, + analyseState, + setupDir // + ); + + // + if (target == 0) + { + // + target = CalculateTarget( + cBar, + verificationState, + setupDir // + ); + } + } + target = 0; + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + // Filling SL Candidates ... + double momentumBarPointsDif = 30 * points; + + // + // Bullish Momentum Bar Selection ... + XOHCL bullishMomentumBar; + int bullishMomentumBarsCount = decisionState.CountBullishMomentumBars(); + if (IsValidSize(bullishMomentumBarsCount)) + { + // + for (int i = 0; i < bullishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.low) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bullishMomentumBar.IsValid() || + (bullishMomentumBar.IsValid() && + bullishMomentumBar.low < entry && + bullishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bullishMomentumBar = iBar; + } + } + } + + // + // Bearish Momentum Bar Selection ... + XOHCL bearishMomentumBar; + int bearishMomentumBarsCount = decisionState.CountBearishMomentumBars(); + if (IsValidSize(bearishMomentumBarsCount)) + { + // + for (int i = 0; i < bearishMomentumBarsCount; i++) + { + // + XCMomentumBar *iMomentum = decisionState.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isValidDistane = (MathAbs(iBar.high) - entry) >= momentumBarPointsDif; + if (!isValidDistane) + { + continue; + } + + // + bool isIndexPassed = iBar.Index() <= 5; + if (!isIndexPassed) + { + continue; + } + + // + bool canSet = + !bearishMomentumBar.IsValid() || + (bearishMomentumBar.IsValid() && + bearishMomentumBar.high > entry && + bearishMomentumBar.Index() > iBar.Index()); + if (canSet) + { + bearishMomentumBar = iBar; + } + } + } + + // + double sls[]; + Add( + sar, + sls // + ); + Add( + str, + sls // + ); + + // + if (isBullish) + { + // + Add( + atrLower, + sls // + ); + + // // + // Add( + // vale, + // sls // + // ); + + // + if (bullishMomentumBar.IsValid()) + { + // + Add( + bullishMomentumBar.low, + sls // + ); + } + + // // + // if (IsValidIndex(lowerValeIDX)) + // { + // // + // Add( + // lowerVale, + // sls // + // ); + // } + + // + if (le1 != EMPTY_VALUE) + { + // + Add( + le1, + sls // + ); + } + + // + if (le2 != EMPTY_VALUE) + { + // + Add( + le2, + sls // + ); + } + } + else + { + // + Add( + atrUpper, + sls // + ); + + // // + // Add( + // peak, + // sls // + // ); + + // + if (bearishMomentumBar.IsValid()) + { + // + Add( + bearishMomentumBar.high, + sls // + ); + } + + // + // if (IsValidIndex(higherPeakIDX)) + // { + // // + // Add( + // higherPeak, + // sls // + // ); + // } + + // + if (se1 != EMPTY_VALUE) + { + // + Add( + se1, + sls // + ); + } + + // + if (se2 != EMPTY_VALUE) + { + // + Add( + se2, + sls // + ); + } + } + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + double riskInPoints = risk / points; + if (riskInPoints >= 150) + { + // + target = + isBullish + ? entry + (points * 200) + : entry - (points * 200); + + // + target = 0; + } + + // + // Filling Conditions Props ... + conditions.sl = sl; + conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXSTRPVGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_XSTRPV); + + // + result = DetectX121SMCGuards( + provider, + guards, + positions, + triggerCycleHelper, + decisionCycleHelper, + analyseCycleHelper, + verificationCycleHelper, + consolidationCycleHelper, + visionCycleHelper // + ); + + // + return result; +} + +// +int AddX121SMCXSTRPVConditionsIfNotExists( + X121SMCStrategyXSTRPVSignalConditions &item, + X121SMCStrategyXSTRPVSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXSTRPVSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXSTRPVSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXSTRPVConditions( + X121SMCStrategyXSTRPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + bool hasPriceZone = conditions.priceZone.IsValid(); + if (!hasPriceZone) + { + return result; + } + + // + int zonesObjCount = drawer.DrawPriceZone( + conditions.priceZone, + drawnObjects, + conditions.dir // + ); + result = zonesObjCount; + + // + return result; +} + +// diff --git a/BKPS/14031106/Documents/Diagrams/Position Protection.drawio b/BKPS/14031106/Documents/Diagrams/Position Protection.drawio new file mode 100644 index 0000000..d425cb2 --- /dev/null +++ b/BKPS/14031106/Documents/Diagrams/Position Protection.drawio @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BKPS/14031106/Documents/JsModules/x-color.tools.js b/BKPS/14031106/Documents/JsModules/x-color.tools.js new file mode 100644 index 0000000..c3ac5f9 --- /dev/null +++ b/BKPS/14031106/Documents/JsModules/x-color.tools.js @@ -0,0 +1,506 @@ +/** + * XColor Tools Module ... + * a module for handle colorify text contents in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const XValueTools = require("./x-value.tools"); +//#endregion + +// +//#region Constants ... +/** + * these are available style which can applied to an string ... + */ +const AVAILABLE_STYLES = { + // + Bold: "\x1b[1m", + Dim: "\x1b[2m", + Underlined: "\x1b[4m", + Blink: "\x1b[5m", + ReverseFandB: "\x1b[7m", + Hidden: "\x1b[8m", + // + // Commonly used for reset all Styles ... + Reset: "\x1b[0m" +}; + +/** + * these are available foreground colors which can applied to an string ... + */ +const AVAILABLE_FOREGROUND_COLORS = { + Default: "\x1b[39m", + Black: "\x1b[30m", + Red: "\x1b[31m", + Green: "\x1b[32m", + Yellow: "\x1b[33m", + Blue: "\x1b[34m", + Magenta: "\x1b[35m", + Cyan: "\x1b[36m", + LightGray: "\x1b[37m", + DarkGray: "\x1b[90m", + LightRed: "\x1b[91m", + LightGreen: "\x1b[92m", + LightYellow: "\x1b[93m", + LightBlue: "\x1b[94m", + LightMagenta: "\x1b[95m", + LightCyan: "\x1b[96m", + White: "\x1b[97m", +}; + +/** + * these are available background colors which can applied to an string ... + */ +const AVAILABLE_BACKGROUND_COLORS = { + Default: "\x1b[49m", + Black: "\x1b[40m", + Red: "\x1b[41m", + Green: "\x1b[42m", + Yellow: "\x1b[43m", + Blue: "\x1b[44m", + Magenta: "\x1b[45m", + Cyan: "\x1b[46m", + LightGray: "\x1b[47m", + DarkGray: "\x1b[100m", + LightRed: "\x1b[101m", + LightGreen: "\x1b[102m", + LightYellow: "\x1b[103m", + LightBlue: "\x1b[104m", + LightMagenta: "\x1b[105m", + LightCyan: "\x1b[106m", + White: "\x1b[107m", +}; + +/** + * these are available style names, which exports from module and + * users can use them ... + */ +const STYLE_NAMES = { + Bold: "Bold", + Dim: "Dim", + Underlined: "Underlined", + Blink: "Blink", + ReverseFandB: "ReverseFandB", + Hidden: "Hidden", + Reset: "Reset", +}; + +/** + * these are available color names, which exports from module and + * users can use them ... + */ +const COLOR_NAMES = { + Default: "Default", + Black: "Black", + Red: "Red", + Green: "Green", + Yellow: "Yellow", + Blue: "Blue", + Magenta: "Magenta", + Cyan: "Cyan", + LightGray: "LightGray", + DarkGray: "DarkGray", + LightRed: "LightRed", + LightGreen: "LightGreen", + LightYellow: "LightYellow", + LightBlue: "LightBlue", + LightMagenta: "LightMagenta", + LightCyan: "LightCyan", + White: "White", +}; +//#endregion + +// +//#region Actions ... +/** + * apply specified style and color on a content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} styled content ... + */ +function apply( + content, + color, + style, + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}${AVAILABLE_STYLES.Reset}`; + } + +} + +/** + * apply specific style on a content ... + * + * @param {string} content specific content which going to styled ... + * @param {string} style a member of STYLE_NAMES which specified that which style going to applied to content ... + * @returns {string} styled content ... + */ +function applyStyle(content, style) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eStyle = AVAILABLE_STYLES[style]; + if (eStyle === undefined) { + return content; + } + + // + return `${eStyle}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific foreground color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyForegroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_FOREGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific background color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyBackgroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_BACKGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * generate style and color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} style and color applier string ... + */ +function getApplier( + style = "", + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate style applier expression ... + * + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @returns {string} style applier string ... + */ +function getStyleApplier( + style = "", + reset = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} color applier string ... + */ +function getColorApplier( + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * colorified specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} + */ +function colorifyContent( + content = "", + color = "", + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Finde Colors ... + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}`; + } + + // + if ( + result.length > 0 + && ( + XValueTools.isValidArg(eFColor) || + XValueTools.isValidArg(eBColor) + ) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * apply style on specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} style soecufic style name to use ... + * @returns {string} + */ +function stylifiyContent( + content = "", + style = "", +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}`; + } + + // + if ( + result.length > 0 + && XValueTools.isValidArg(eStyle) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + STYLE_NAMES, + COLOR_NAMES, + // + apply, + applyStyle, + getApplier, + getColorApplier, + getStyleApplier, + colorifyContent, + stylifiyContent, + applyForegroundColor, + applyBackgroundColor, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031106/Documents/JsModules/x-file.tools.js b/BKPS/14031106/Documents/JsModules/x-file.tools.js new file mode 100644 index 0000000..2a3535d --- /dev/null +++ b/BKPS/14031106/Documents/JsModules/x-file.tools.js @@ -0,0 +1,887 @@ +/** + * XFile Tools Module ... + * a module for handle all file/folder manipulating task in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const fs = require('fs'); +const os = require('os'); +const Path = require('path'); +const http = require('http'); +const https = require('https'); +const XValueTools = require('./x-value.tools'); +//#endregion + +// +//#region Constants ... +/** + * current os path separators ... + */ +const PathSeparator = Path.sep; + +/** + * current directory ... + */ +const CurrentDir = __dirname; +//#endregion + +// +//#region Actions ... +// +//#region Global ... +/** + * retrieve a path status ... + * + * @param {string} path a path value to check ... + * @returns an stat object ... + */ +function getStatus(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return undefined; + } + + // + return fs.statSync(path); +} + +/** + * retrieve user's Home path ... + * + * @returns {string} a path ... + */ +function getHomePath() { + return os.homedir(); +} +//#endregion + +// +//#region Path ... +/** + * retrieve the base name of specific address path ... + * + * @param {string} path address of file or folder ... + * @returns string ... + */ +function basename(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return ''; + } + + // + const result = Path.basename(path); + return result; +} + +/** + * join several path segments together ... + * + * @param {...string} path path params ... + * @returns a joined paths ... + */ +function joinPath(...path) { + return Path.join(...path); +} + +/** + * resolve a relative path to absolute ... + * + * @param {string[]} path a path value to check ... + * @returns {string} + */ +function resolvePath(...path) { + return Path.resolve(...path); +} +//#endregion + +// +//#region File ... +/** + * determines a path destination is a file or not ... + * + * @param {string} path a path value to check ... + * @returns a boolean value ... + */ +function isFileExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + return stat.isFile(); + } catch { + return false; + } +} + +/** + * remove a file ... + * + * @param {string} path a file path ... + * @returns {Promise} action done or not ... + */ +function removeFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(false); + } + + // + fs.unlink(path, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * copy a file to destination path ... + * + * @param {string} source source file path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +function copyFile( + source = '', + dest = '' +) { + return new Promise((resolve) => { + // + if ( + !isFileExists(source) || + !isDirectoryExists(dest) + ) { + resolve(false); + return; + } + + // + const destFilePath = Path.join(dest, Path.basename(source)); + fs.copyFile(source, destFilePath, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * reading specified file content ... + * + * @param {string} path a file path ... + * @returns {Promise} file content ... + */ +function readFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(''); + return; + } + + // + fs.readFile(path, 'utf8', (err, content) => { + // + if (err) { + resolve(undefined); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * write content to a file ... + * + * @param {string} path a file path ... + * @param {string} content the content which going to write to the file ... + * @param {bool} overwrite determines file overwrite if exists ... + * @returns {Promise} action done or not ... + */ +function writeFile( + path = '', + content = '', + overwrite = true +) { + return new Promise((resolve) => { + // + if (isFileExists(path) && !overwrite) { + // + resolve(false); + return; + } + + // + // Normalize Content ... + content = XValueTools.isValidArg(content) ? + content : + ''; + + // + fs.writeFile(path, content, (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * create a file ... + * + * @param {string} path file path ... + * @param {string} fileName file name ... + * @returns {Promise} action done or not ... + */ +function createFile( + path = '', + fileName = '' +) { + return new Promise((resolve) => { + // + const filePath = Path.join(path, fileName); + if ( + isFileExists(filePath) || + !XValueTools.isValidArg(path) || + !XValueTools.isValidArg(fileName) + ) { + // + resolve(false); + return; + } + + // + fs.writeFile(filePath, '', (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * remove a file name extension ... + * + * @param {string} name + * @returns {string} name without extension ... + */ +function removeFileExtension(name = '') { + return name.substring(0, name.lastIndexOf('.')) || name; +} + +/** + * retrieve a file extension ... + * + * @param {string} path a path which locate a file ... + * @returns {string} + */ +function getFileExtension(path = '') { + // + let result = ""; + + // + // Validate Arg ... + if ( + !XValueTools.isValidArg(path) + || !isFileExists(path) + ) { + return result; + } + + // + // Retrieve just file name ... + const fileName = basename(path); + result = fileName.replace( + removeFileExtension(fileName), + "" + ); + + // + return result; +} + +/** + * retrieve all files list recursively from specific path ... + * + * @param {string} path a source folder path ... + * @param {string[]} extensions which file extensions need to be listed, live empty for all files ... + * @returns {Promise} + */ +async function getRecursiveFilesList( + path = "", + extensions = [] +) { + // + let result = []; + + // + // Validate Args ... + if ( + !XValueTools.isValidArg(path) + || !isDirectoryExists(path) + ) { + return result; + } + + // + const contents = await getDirectoryContents(path); + for (const item of contents) { + // + const itemPath = joinPath( + path, + item + ); + + // + const isItemFile = isFileExists(itemPath); + if (isItemFile) { + // + const itemFileExtension = getFileExtension(itemPath); + const isFileInSupportedExtensions = + extensions === undefined || extensions.length === 0 + ? true + : extensions.includes(itemFileExtension) + ; + if (isFileInSupportedExtensions) { + result.push(itemPath); + } + } else if (isDirectoryExists(itemPath)) { + // + const itemPathFiles = await getRecursiveFilesList(itemPath, extensions); + result.push(...itemPathFiles); + } + } + + // + return result; +} + +/** + * Extract Specific files from a folder and it's content ... + * + * @param {string} path Folder Path ... + * @returns + */ +async function extractFiles(path = "", ext = [], excludeWorkspaceFolders = []) { + // + const result = []; + + // + if (!ext || ext.length == 0) { + return result; + } + + // + const pathContent = await getDirectoryContents(path); + if (!pathContent || pathContent.length == 0) { + return result; + } + + // + // Loop through Content ... + for (const c of pathContent) { + // + // Prepare full path ... + const cPath = joinPath(path, c); + + // + // check content path is file or not ... + const isCFile = isFileExists(cPath); + const isCDirectory = isDirectoryExists(cPath); + if (isCFile) { + // + // Check it is MQL file or not ... + const cExt = getFileExtension(cPath); + if (ext.includes(cExt)) { + result.push(cPath); + } + } else if (isCDirectory) { + // + const destFolderName = basename(cPath); + const isExcluded = excludeWorkspaceFolders.includes(destFolderName); + if (isExcluded) { + continue; + } + + // + const cFiles = await extractFiles(cPath, ext); + if (cFiles && cFiles.length > 0) { + result.push(...cFiles); + } + } + } + + // + return result; +} +//#endregion + +// +//#region Directory ... +/** + * create a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive create directories recursively ... + * @returns action done or not ... + */ +function createDirectory( + path = '', + recursive = true +) { + // + let result = false; + + // + if ( + isDirectoryExists(path) || + !XValueTools.isValidArg(path) + ) { + return false; + } + + // + try { + // + fs.mkdirSync(path, { recursive: recursive }); + result = true; + return result; + } catch { + return false; + } +} + +/** + * remove a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive removes directories recursively ... + * @returns {Promise} action done or not ... + */ +function removeDirectory( + path = '', + recursive = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve(false); + return; + } + + // + fs.rm(path, { + recursive + }, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * determines a path destination is a directory or not ... + * + * @param {string} path a folder path ... + * @returns represent destnation path is Directory or not ... + */ +function isDirectoryExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + // + const isExists = fs.existsSync(path); + if (!isExists) { + return false; + } + + // + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + const result = stat.isDirectory(); + return result; + } catch { + return false; + } +} + +/** + * retrieve a directory content ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryContents(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * retrieve a directory files ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryFiles( + path = '', + containsHiddenFiles = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + if (!containsHiddenFiles) { + content = content.filter(c => !c.startsWith('.')); + } + + // + const result = []; + content + .forEach(c => { + // + const cPath = Path.join(path, c); + if (isFileExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * retrieve a directory folders ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder names ... + */ +function getDirectoryFolders(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + const result = []; + content.forEach(c => { + // + const cPath = Path.join(path, c); + if (isDirectoryExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * copy a folder with all of it's content to dest ... + * + * @param {string} source source folder path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +async function copyFolder( + source = '', + dest = '' +) { + // + if ( + !isDirectoryExists(source) || + !XValueTools.isValidArg(dest) || + !XValueTools.isValidArg(source) + ) { + return false; + } + + // + const folderName = Path.basename(source); + const destPath = Path.join(dest, folderName); + + // + // Create Dest Path folder if not exists ... + if (!isDirectoryExists(destPath)) { + // + let result = createDirectory(destPath, true); + if (!result) { + return false; + } + } + + // + // Files ... + const files = await getDirectoryFiles(source); + if (files && files.constructor === Array && files.length > 0) { + // + const filesPromises = files.map(file => copyFile(Path.join(source, file), destPath)); + const filesResult = (await Promise.all(filesPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + // Folders ... + const folders = await getDirectoryFolders(source); + if (folders && folders.constructor === Array && folders.length > 0) { + // + const folderPromises = folders.map(folder => copyFolder(Path.join(source, folder), destPath)); + const filesResult = (await Promise.all(folderPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + return true; +} +//#endregion + +// +//#region Downloader ... +/** + * download a file from specific url and store it ... + * + * @param {string} filepath the file name and path which required to put download file on it ... + * @param {string} url the web url for downloading ... + */ +function download(filepath, url) { + // + // Validate Args ... + if ( + !XValueTools.isValidArg(url) + || !XValueTools.isValidURL(url) + || !XValueTools.isValidArg(filepath) + ) { + return; + } + + // + var file = fs.createWriteStream(filepath); + + // + if (url.startsWith('https:')) { + https.get(url, function (response) { + response.pipe(file); + }); + } else if (url.startsWith('http:')) { + http.get(url, function (response) { + response.pipe(file); + }); + } +} +//#endregion + +// +//#region JSON ... +/** + * read and parse a JSON content from a file ... + * + * @param {string} path source file path ... + * @returns {any} + */ +function readJSON(path = "") { + // + // Validate Args ... + if (!isFileExists(path)) { + return undefined; + } + + // + let result = undefined; + try { + result = require(path); + } catch { + result = undefined; + } + + // + return result; +} + +/** + * write a JSON Object content into a file ... + * + * @param {string} path dest file path ... + * @param {any} content an object which required to write to file ... + * @returns {Promise} + */ +async function writeJSON( + path = "", + content = undefined +) { + // + let result = false; + + // + // Validate Args ... + if (!XValueTools.isValidArg(path)) { + return result; + } + + // + // Normallize Content ... + if (content === undefined) { + content = {}; + } + + // + const contentString = XValueTools.beautifyJSON(content); + + // + result = await writeFile( + path, + contentString, + true + ); + + // + return result; +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + CurrentDir, + PathSeparator, + + // + getStatus, + getHomePath, + + // + basename, + joinPath, + resolvePath, + + // + download, + + // + readJSON, + writeJSON, + + // + copyFile, + readFile, + writeFile, + createFile, + removeFile, + isFileExists, + getFileExtension, + removeFileExtension, + getRecursiveFilesList, + extractFiles, + + // + copyFolder, + createDirectory, + removeDirectory, + isDirectoryExists, + getDirectoryFiles, + getDirectoryFolders, + getDirectoryContents, +}; +//#endregion \ No newline at end of file diff --git a/BKPS/14031106/Documents/JsModules/x-shell.tools.js b/BKPS/14031106/Documents/JsModules/x-shell.tools.js new file mode 100644 index 0000000..0ee13de --- /dev/null +++ b/BKPS/14031106/Documents/JsModules/x-shell.tools.js @@ -0,0 +1,219 @@ +/** + * XShell Tools Module ... + * a module for handling shell actions and retrieve OS Info in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const os = require('os'); +const process = require('process'); +const { exec } = require("child_process"); +const XFileTools = require('./x-file.tools'); +//#endregion + +// +//#region Constants ... +// +const OS = { + Aix: 'aix', + Darwin: 'darwin', + FreeBSD: 'freebsd', + Linux: 'linux', + OpenBSD: 'openbsd', + SnOS: 'sunos', + Windows: 'win32' +}; + +// +const isWindows = process.platform === OS.Windows; +//#endregion + +// +//#region Actions ... +// +//#region Pure shell commands ... +/** + * execute a command using NodeJS on shell ... + * + * @param {string} cmd command to execute ... + * @param {string} cwd working directory ... + * + * @returns Promise instance ... + */ +function execute(cmd, cwd) { + return new Promise((resolve, reject) => { + // + if (!cmd || cmd.toString().length === 0 || (cwd && !XFileTools.isDirectoryExists(cwd))) { + reject('invalid args ...'); + return; + } + + // + exec(cmd, { cwd }, (err, result, stdError) => { + // + if (err) { + reject(err); + return; + } + + // + if (stdError) { + // + // reject(stdError); + // return; + } + + // + resolve(result); + }); + }); +}; + +/** + * determines a command exists on host or not ... + * + * @param {string} name specific command name ... + * + * @returns boolean Promise ... + */ +function checkCommandExists(name) { + return new Promise(resolve => { + // + if (!name) { + resolve(false); + return; + } + + // + const cmd = isWindows ? `${name} >nul 2>&1` : `type ${name} >/dev/null 2>&1`; + execute(cmd).then(result => { + resolve(true); + }) + .catch(err => { + resolve(false); + }); + }); +} +//#endregion + +// +//#region required commands state ... +/** + * check al required commands exists or not ... + * + * @returns + */ +async function isRequiredCommandsExists() { + // + let result = false; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result = isNpmExists + && isNgExists + && isIonicExists + && isCordovaExists + ; + + // + return result; +} + +/** + * retrieve required commands state object ... + * + * @returns + */ +async function getRequiredCommandsStates() { + // + const result = {}; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result['npm'] = isNpmExists; + result['ng'] = isNgExists; + result['ionic'] = isIonicExists; + result['cordova'] = isCordovaExists; + + // + return result; +} +//#endregion + +// +//#region Commonly used Command Checkers ... +/** + * determines npm command exists or not ... + * + * @returns + */ +function isNpmCommandExists() { + return checkCommandExists('npm'); +} + +/** + * determines ng command exists or not ... + * + * @returns + */ +function isNgCommandExists() { + return checkCommandExists('ng'); +} + +/** + * determines ionic command exists or not ... + * + * @returns + */ +function isIonicCommandExists() { + return checkCommandExists('ionic'); +} + +/** + * determines cordova command exists or not ... + * + * @returns + */ +function isCordovaCommandExists() { + return checkCommandExists('cordova'); +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + execute, + checkCommandExists, + isRequiredCommandsExists, + getRequiredCommandsStates, + + // + isNgCommandExists, + isIonicCommandExists, + isCordovaCommandExists, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031106/Documents/JsModules/x-type-detector.tools.js b/BKPS/14031106/Documents/JsModules/x-type-detector.tools.js new file mode 100644 index 0000000..86ed3d8 --- /dev/null +++ b/BKPS/14031106/Documents/JsModules/x-type-detector.tools.js @@ -0,0 +1,268 @@ +/** + * DataType Tools Module ... + * a module for manipulate and detect supported data types in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Constants ... +/** + * all supported data types ... + */ +const DataTypes = { + Null: 'null', + Date: 'date', + Array: 'array', + Object: 'object', + String: 'string', + Number: 'number', + Unknown: 'unknown', + Boolean: 'boolean', + Function: 'function', + Undefined: 'undefined', +}; +//#endregion + +// +//#region Actions ... +/** + * detect type of a content ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getType(value) { + // + const type = typeof value; + + // + let result = DataTypes.Unknown; + let dateIdentifier = '[object Date]'; + let constructor = value && value.constructor ? + value.constructor.toString() : + ''; + + // + switch (type) { + // + case 'undefined': + result = DataTypes.Undefined; + break; + + // + case 'boolean': + result = DataTypes.Boolean; + break; + + // + case 'string': + result = DataTypes.String; + break; + + // + case 'number': + result = DataTypes.Number; + break; + + // + case 'function': + result = DataTypes.Function; + break; + + // + case 'object': + // + // Null ... + if (value === null) { + result = DataTypes.Null; + } else + // + // Array ... + if (Array.isArray(value)) { + result = DataTypes.Array; + } else + // + // Data ... + if ( + value instanceof Date || + isFunction(value.getMonth) || + constructor.includes(dateIdentifier) || + Object.prototype.toString.call(value) === dateIdentifier + ) { + result = DataTypes.Date; + } else + // + // Object ... + { + result = DataTypes.Object; + } + break; + + // + default: + result = DataTypes.Unknown; + break; + } + + // + return result; +} + +/** + * retrieve an object constructor ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getConstructor(value) { + // + const result = value && value.constructor ? + value.constructor.toString() : + ''; + + // + return result; +} + +/** + * retrieve an object prototype ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getPrototype(value) { + // + const result = value ? + Object.prototype.toString.call(value) : + ''; + + // + return result; +} + +/** + * check an object is null or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNull(value) { + return getType(value) === DataTypes.Null; +} + +/** + * check an object is undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isUndefined(value) { + return getType(value) === DataTypes.Undefined; +} + +/** + * check an object is null or undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNullOrUndefined(value) { + return isNull(value) || isUndefined(value); +} + +/** + * check an object is a date or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isDate(value) { + return getType(value) === DataTypes.Date; +} + +/** + * check an object is number or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNumber(value) { + return getType(value) === DataTypes.Number; +} + +/** + * check an object is string or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isString(value) { + return getType(value) === DataTypes.String; +} + +/** + * check an object is boolean or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isBoolean(value) { + return getType(value) === DataTypes.Boolean; +} + +/** + * check an object is an Array or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isArray(value) { + return getType(value) === DataTypes.Array; +} + +/** + * check an object is and Object or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isObject(value) { + return getType(value) === DataTypes.Object; +} + +/** + * check an object is a Function or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isFunction(value) { + return getType(value) === DataTypes.Function; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + DataTypes, + + // + getType, + getConstructor, + getPrototype, + isNull, + isUndefined, + isNullOrUndefined, + isDate, + isNumber, + isString, + isBoolean, + isArray, + isObject, + isFunction, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031106/Documents/JsModules/x-value.tools.js b/BKPS/14031106/Documents/JsModules/x-value.tools.js new file mode 100644 index 0000000..81cfcc4 --- /dev/null +++ b/BKPS/14031106/Documents/JsModules/x-value.tools.js @@ -0,0 +1,1528 @@ +/** + * Value Tools Module ... + * a module for Validate args and values ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const XTypeTools = require('./x-type-detector.tools'); +//#endregion + +// +//#region Actions ... +/** +* validate a value as an argument ... +* +* @param {string} value the value which going to validate ... +* @returns +*/ +function isValidArg(value) { + // + let result = false; + + // + result = value && + value.length > 0; + + // + return result; +} + +/** + * validate a collection of valuea as an arguments ... + * + * @param {string|string[]} values the value collection which going to checked ... + * @returns + */ +function isValidArgs(values) { + // + // Normalize Values ... + const normalValues = toNormalArray(values); + if (!hasChildArray(normalValues)) { + return false; + } + + // + let result = normalValues.every(nv => isValidArg(nv)); + return result; +} + +/** + * converts content to an array object ... + * + * @param {string|string[]} content the content which required to normalized ... + * @returns {string[]} array object ... + */ +function toNormalArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + const result = Array.isArray(content) ? + [...content] : + content.includes(',') && + content !== ',' ? + [...content.split(',')] : + [content]; + + // + return result; +} + +/** + * determines value is array and has atleast one child ... + * + * @param {any} value the value which going to checked ... + * @returns {boolean} result of checking ... + */ +function hasChildArray(value) { + // + let result = false; + result = value && + Array.isArray(value) && + value.length > 0; + + // + return result; +} + +/** + * check an string is ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} value specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function endsWidth( + symbol = '', + value = '', + ignoreCase = true +) { + // + if (!isValidArg(value)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + // TODO: uncomment it if necessary ... + // symbol = symbol.trim(); + + // + let result = false; + const subtractedContent = value.substring(value.length - symbol.length); + result = !!ignoreCase ? + subtractedContent + .toLowerCase() === symbol + .toLowerCase() : + subtractedContent === symbol; + + // + return result; +} + +/** + * surround specified content by provided symbol ... + * + * @param {string} symbol surround string ... + * @param {string} content used content to surrounded by symbol ... + * @returns surrounded content ... + */ +function surroundBy( + symbol = '', + content = '' +) { + // + // Validate Args ... + if (!isValidArg(content)) { + content = ''; + } + + // + if (!isValidArg(symbol)) { + symbol = ''; + } + + // + if (isSurrounded(symbol, content)) { + return content; + } + + // + const result = `${symbol}${content}${symbol}`; + return result; +} + +/** + * convert a parsed sign to clear string ... + * + * @param {string} value a parsed content ... + * @returns clear parsed signs ... + */ +function toStringExpression(value) { + // + let result = ''; + result = value; + + // + if ( + !value || + !isValidArg(value) || + !isSurroundedString(value) + ) { + return result; + } + + // + const startSymbol = value.charAt(0); + const endSymbol = value.charAt(value.length - 1); + + // + if (startSymbol !== endSymbol) { + return result; + } + + // + if ( + startSymbol === "\"" || + startSymbol === "\'" + ) { + result = clearSurround(startSymbol, value); + } + + // + return result; +} + + + +/** + * find and cleare proposed candidates from specified content ... + * + * @param {string|string[]} candidates the proposed string(s) whic going to cleared from content ... + * @param {string} content the destination content which used to find and replace candidates on it ... + * @returns cleared content ... + */ +function clearContent( + candidates, + content +) { + // + // Validate Args ... + if ( + !candidates || + !isValidArg(content) + ) { + return ''; + } + + // + // Normalize candidates ... + const normalCandidates = toNormalArray(candidates) + .filter(c => isValidArg(c)); + if (!hasChildArray(normalCandidates)) { + return content; + } + + // + // define regexp for content ... + const regExpExpression = normalCandidates.join('|'); + const regExp = new RegExp( + regExpExpression, + 'gi' + ); + + // + let result = ''; + result = content.replace(regExp, ''); + + // + return result; +} + +/** + * clear surrounded symbol from content ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified content to clear ... + * @returns + */ +function clearSurround( + symbol = '', + content = '' +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + (isValidArg(symbol) && + symbol.length >= content.length - 1) + ) { + return ''; + } + + // + // Validate Surround ... + if (!isSurrounded(symbol, content)) { + return content; + } + + // + if (!isValidArg(symbol)) { + return content; + } + + // + let result = content.substring(symbol.length, content.length - symbol.length); + return result; +} + +/** + * clear object sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearObjectSurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedObject(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth('}', content) ? + 1 : + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * clear array sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearArraySurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedArray(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth(']', content) ? + 1 : + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * slice a content to individual parts ... + * + * @param {number|number[]} indexes which indexes used to slice ... + * @param {strng} content the content which going to sliced ... + * @returns sliced parts of content ... + */ +function sliceContent(indexes, content) { + // + // Validate Args ... + if ( + !isValidArg(indexes) || + !isValidArg(content) + ) { + return []; + } + + // + // Normalize indexes ... + const normalIndexes = toNormalArray(indexes) + .filter(index => index > -1 && index < content.length); + if (!hasChildArray(normalIndexes)) { + return []; + } + + // + let result = ['']; + result.pop(); + + // + let lastIndex = 0; + for (const index of normalIndexes) { + // + const part = content.substring(lastIndex, index); + if (isValidArg(part)) { + result.push(part.trim()); + } + + // + lastIndex = index + 1; + } + + // + // check remained parts ... + if (lastIndex < content.length) { + // + const part = content.substring(lastIndex); + if (isValidArg(part)) { + result.push(part.trim()); + } + } + + // + return result; +} + + + +/** + * check an string is starts and ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function isSurrounded( + symbol = '', + content = '', + ignoreCase = true +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + symbol = symbol.trim(); + + // + let result = false; + result = (!!ignoreCase ? + content + .toLowerCase() + .startsWith(symbol.toLowerCase()) : + content.startsWith(symbol) + ) && + endsWidth(symbol, content, ignoreCase); + + // + return result; +} + +/** + * determines a content is an string surrounded value or not ... + * + * @param {string} content a content which going to check ... + * @returns + */ +function isSurroundedString(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = ( + content.startsWith('\'') && + ( + endsWidth('\'', content) || + endsWidth('\',', content) || + endsWidth('\';', content) || + endsWidth('\'\n', content) + ) || + content.startsWith('\"') && + ( + endsWidth('\"', content) || + endsWidth('\",', content) || + endsWidth('\";', content) || + endsWidth('\"\n', content) + ) || + content.startsWith('`') && + ( + endsWidth('\`', content) || + endsWidth('\`,', content) || + endsWidth('\`;', content) || + endsWidth('\`\n', content) + ) + ); + return result; +} + +/** + * check a content is an array content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('[') && + ( + endsWidth(']', content) || + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) + ); + return result; +} + +/** + * check a content is an object content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedObject(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('{') && + ( + endsWidth('}', content) || + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) + ); + return result; +} + +/** + * check an index model is contains inside anothers or not ... + * + * @param {{ start: number, end: number}} source the source index model to check ... + * @param {...{ start: number, end: number}} dest the collection of index models which going to check ... + * @returns + */ +function isIndexInside(source, ...dest) { + // + let result = false; + + // + // Validate Args ... + if (!source || !dest) { + return result; + } + + // + // Check idx is standard ... + if ( + !source || + !source.end || + !source.start || + source.start > source.end + ) { + return false; + } + + // + // Check types of destinations ... + for (let index of dest) { + // + // Check idx is standard ... + if ( + !index || + !index.end || + !index.start || + index.start > index.end + ) { + return false; + } + } + + // + if (dest.includes(source)) { + dest = dest.filter(d => d !== source); + } + + // + const insideContentIndex = dest.find(dIndex => { + // + const result = source.start >= dIndex.start && + source.start <= dIndex.end && + source.end >= dIndex.start && + source.end <= dIndex.end; + return result; + }); + + // + result = insideContentIndex; + return result; +} + +/** + * check a number exists in + * @param {number} idx the number which going to check ... + * @param {{ start: number, end: number}} index the index model + * @returns + */ +function isInsideIndex(idx = -1, index) { + // + let result = false; + + // + // Validate Args ... + if ( + !index || + !index.hasOwnProperty('end') || + !index.hasOwnProperty('start') + ) { + return result; + } + + // + result = idx > index.start && idx < index.end; + return result; +} + +/** + * determines an object is key/value and type ... + * + * @param {any} content the object which we are going to check ... + * @returns + */ +function isKeyValueType(content) { + // + const result = content && + content.hasOwnProperty('key') && + content.hasOwnProperty('type') && + content.hasOwnProperty('value'); + + // + return result; +} + + + +/** + * find all indexes of token(s) in content ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns {number[]} all occured indexes ... + */ +function findAllIndexes( + tokens, + content +) { + // + // Validate Args ... + if ( + !isValidArg(tokens) || + !isValidArg(content) + ) { + return []; + } + + // + // normalize tokens ... + const normalTokens = toNormalArray(tokens); + if (!hasChildArray(normalTokens)) { + return []; + } + + // + // Parse contents ... + let match; + const result = []; + const regExp = new RegExp( + normalTokens.join('|'), + 'g' + ); + while ((match = regExp.exec(content)) !== null) { + result.push(match.index); + } + if (!hasChildArray(result)) { + return []; + } + + // + return result; +} + +/** + * find nearest symbol in a content from specified index ... + * + * @param {string|string[]} candidates specifies which symbols to find ... + * @param {string} content te content for seasrch ... + * @param {number} startFromIndex the index of start position ... + * @returns + */ +function findNearest( + candidates, + content = '', + startFromIndex = 0 +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) || + !isValidArg(content.trim()) + ) { + return ''; + } + + // + // Normalize Content ... + content = content.trim(); + + // + // Normalize Starts From ... + startFromIndex = startFromIndex < 0 || startFromIndex > content.length - 1 ? 0 : startFromIndex; + + // + // Normalize Symbols ... + const normalCandidates = toNormalArray(candidates); + if (!hasChildArray(normalCandidates)) { + return ''; + } + + // + let nearestIndex = findNearestIndex( + normalCandidates, + content, + startFromIndex + ); + if (nearestIndex < 0) { + return ''; + } + + // + let result = content.substring( + nearestIndex, + nearestIndex + Math.max(...normalCandidates.map(nc => nc.length)) + ).trim(); + return result; +} + +/** + * search candidates in content and find nearest one and return it ... + * + * @param {string|string[]} candidates which candidates required to check ... + * @param {string} content the content which required to search candidates ... + * @param {number} startFromIndex the proposed index to start searching content from on ... + * @returns + */ +function findNearestIndex( + candidates = [''], + content = '', + startFromIndex = 0, + ignoreClosedItems = false +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) + ) { + return -1; + } + + // + // Mormalize startFromIndex value ... + startFromIndex = startFromIndex < 0 ? + 0 : + startFromIndex > content.length - 1 ? + content.length - 1 : + startFromIndex; + + // + // Normalize candidates ... + let normalCandidates = toNormalArray(candidates); + + // + if (!!ignoreClosedItems) { + normalCandidates = normalCandidates + .map(c => content.indexOf( + c, + startFromIndex + ) + ).map(c => +c) + .filter(c => +c > -1); + } else { + normalCandidates = findAllIndexesOutOfCloseds(normalCandidates, content) + .filter(c => c >= startFromIndex); + } + if (!hasChildArray(normalCandidates)) { + return -1; + } + + // + let result = -1; + result = Math.min(...normalCandidates); + + // + return result; +} + +/** + * find close index of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findCloseIndex( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = -1 +) { + // + // Validate Args ... + if ( + startsFrom < 0 || + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + openSymbol === closeSymbol || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + startsFrom > content.length - 1 + ) { + return -1; + } + + // + let result = -1; + + // + let index = startsFrom; + const openSignStack = []; + while (index < content.length) { + // + const openCandidate = content.substring(index, index + openSymbol.length); + const closeCandidate = content.substring(index, index + closeSymbol.length); + + // + if (openCandidate === openSymbol) { + openSignStack.push(index); + } else if (closeCandidate === closeSymbol) { + // + if (openSignStack.length > 0) { + openSignStack.pop(); + } + + // + if (openSignStack.length === 0) { + result = index; + break; + } + } + + // + index++; + } + + // + return result; +} + +/** + * find closed contents of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findClosedContent( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = 0, +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + openSymbol.length >= content.length || + closeSymbol.length >= content.length + ) { + return result; + } + + // + // Normalize Start From ... + startsFrom = startsFrom < 0 || startsFrom >= content.length ? 0 : startsFrom; + + // + let canContinue = true; + while (!!canContinue) { + // + let openSymbolIndex = content.indexOf(openSymbol, startsFrom); + if (openSymbolIndex < 0) { + // + canContinue = false; + continue; + } + + // + let closeSymbolIndex = findCloseIndex( + openSymbol, + closeSymbol, + content, + openSymbolIndex + ); + if (closeSymbolIndex < 0) { + // + canContinue = false; + continue; + } + if (content.charAt(closeSymbolIndex) !== closeSymbol) { + closeSymbolIndex++; + } + + // + // Prevent ${} string interpolations ... + if ( + openSymbol === '{' && + openSymbolIndex - 1 >= 0 + ) { + // + const prevChar = content.charAt(openSymbolIndex - 1); + if (prevChar === '$') { + continue; + } + } + + // + const item = content + .substring(openSymbolIndex, closeSymbolIndex + 1) + .trim(); + startsFrom = closeSymbolIndex + 1; + result.push({ + start: openSymbolIndex, + end: closeSymbolIndex, + content: item + }); + } + + // + if (!hasChildArray(result)) { + return result; + } + + // + return result; +} + +/** + * extract a collection of closed contents exists in a content ... + * + * @param symbols a collection of open and close contents ... + * @param {string} content a content for searching inside it ... + * @returns a collection of closed content ... + */ +function findClosedContents( + symbols = [ + { + openSymbol: '', + closeSymbol: '' + } + ], + content = '' +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + if ( + !isValidArg(content) || + !hasChildArray(symbols) + ) { + return []; + } + + // + symbols.forEach(symbol => { + // + const closedContent = findClosedContent( + symbol.openSymbol, + symbol.closeSymbol, + content + ); + + // + if (hasChildArray(closedContent)) { + result.push( + ...closedContent + ); + } + }); + + // + return result; +} + +/** + * find all string content closed items ... + * + * @param {string} content a content which going to search ... + * @returns a collection of index descriptors ... + */ +function findClosedStrings(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // there are 3 types of strings ... + // ' " and ` + + // + const token1 = '\''; + const token1Stack = [0]; + token1Stack.pop(); + + // + const token2 = '"'; + const token2Stack = [0]; + token2Stack.pop(); + + // + const token3 = '`'; + const token3Stack = [0]; + token3Stack.pop(); + + // + const result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + for (let i = 0; i < content.length; i++) { + // + const currentChart = content.charAt(i); + + // + //#region Token 1 ... + if (currentChart === token1) { + // + if (!hasChildArray(token1Stack)) { + token1Stack.push(i); + } else { + // + const start = token1Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 2 ... + if (currentChart === token2) { + // + if (!hasChildArray(token2Stack)) { + token2Stack.push(i); + } else { + // + const start = token2Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 3 ... + if (currentChart === token3) { + // + if (!hasChildArray(token3Stack)) { + token3Stack.push(i); + } else { + // + const start = token3Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + } + + // + return result; +} + +/** + * find container indexes from within indexes ... + * + * @param {...{start: number, end: number}} index the collection of indexes to find beiggers inside ... + * @returns + */ +function findContainerIndexes(...index) { + // + let result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + let concatedIndexes = []; + for (let idx of index) { + // + // Index Childs ... + for (let iix of idx) { + // + // Check idx is standard ... + if ( + !iix || + !iix.end || + !iix.start || + iix.start > iix.end + ) { + continue; + } + + // + // Check index inside another index ... + concatedIndexes.push(iix); + } + } + + // + if (!hasChildArray(concatedIndexes)) { + return result; + } + + // + for (let ccIdx of concatedIndexes) { + // + const isInside = isIndexInside(ccIdx, ...concatedIndexes); + if (isInside) { + continue; + } + + // + if (hasChildArray(result)) { + // + const isInsideResult = isIndexInside(ccIdx, ...result); + if (isInsideResult) { + continue; + } + } + + // + result.push(ccIdx); + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds1( + tokens, + content, +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Extract token Indexes ... + const tokensIndexes = findAllIndexes(tokens, content); + if (!hasChildArray(tokensIndexes)) { + return []; + } + + // + // Extract Closed Objects Indexes ... + const closedArrays = findClosedContent('[', ']', content); + const closedObjects = findClosedContent('{', '}', content); + const closedStrings = findClosedStrings(content); + if ( + !hasChildArray(closedObjects) && + !hasChildArray(closedArrays) && + !hasChildArray(closedStrings) + ) { + return tokensIndexes; + } + + // + // find bigger sloded ... + let containerClosedItems = findContainerIndexes( + closedArrays, + closedObjects, + closedStrings + ).filter(i => !isSurroundedString(i.content)); + + // + let result = [-1]; + result.pop(); + + // + for (let tIdx of tokensIndexes) { + // + let canAdd = true; + for (let ccIndex of containerClosedItems) { + // + canAdd = isInsideIndex(tIdx, ccIndex); + if (canAdd) { + break; + } + } + + // + if (!canAdd) { + result.push(tIdx); + } + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds( + tokens, + content, +) { + // + // Define Result ... + let result = [-1]; + result.pop(); + + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Normalize Tokens ... + const normalizeTokens = toNormalArray(tokens); + if (!hasChildArray(normalizeTokens)) { + return result; + } + + // + // Extract Closed Objects Indexes ... + let openSymbols = [ + '{', + '[', + '\'', + '"', + '`' + ]; + let closeSymbols = [ + '}', + ']', + '\'', + '"', + '`' + ]; + let openStack = []; + let lastOpenSymbol = ''; + let lastClosedIndex = -1; + for (let i = 0; i < content.length; i++) { + // + const prevChar = content.charAt(i - 1) || ''; + const char = content.charAt(i); + const nextChar = content.charAt(i + 1) || ''; + + // + const isToken = normalizeTokens.includes(char); + const isOpenSymbol = openSymbols.includes(char); + const isCloseSymbol = closeSymbols.includes(char); + + // + if (isOpenSymbol && lastOpenSymbol !== char) { + openStack.push(i); + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? char : lastOpenSymbol; + } else if (isCloseSymbol) { + // + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? '' : lastOpenSymbol; + let lastPop = openStack.pop(); + if (openStack.length === 0) { + lastClosedIndex = lastPop; + } + } else if (isToken) { + if ( + i > lastClosedIndex && + openStack.length === 0 + ) { + result.push(i); + } + } + } + + // + return result; +} +//#endregion + +// +//#region Validator Actions ... +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + * @returns {boolean} + */ +function isValidURL(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + const pattern = new RegExp( + '^([a-zA-Z]+:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$', // fragment locator + 'i' + ); + + // + const result = pattern.test(value); + return result; +} + +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + */ +function isValidEmail(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + // + const pattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gim; + + // + const result = pattern.test(value); + return result; +} +//#endregion + +// +//#region Normallizers ... +/** + * normallize an string ... + * + * @param {string} value specified value ... + * @returns {string} + */ +function toNormalString(value = "") { + // + if (!XTypeTools.isString(value)) { + value = ""; + } + + // + const result = value + .trim() + .toLowerCase(); + + // + return result; +} +//#endregion + +// +//#region Beautifiers ... +/** + * converts an object to string based on json and beautify result ... + * + * @param {any} object + * @returns {string} + */ +function beautifyJSON(object = undefined) { + // + // TODO: Complete this ... + let result = ""; + + // + // validate object ... + if (object === undefined) { + return result; + } + + // + // Convert result ... + result = JSON.stringify( + object, + null, + 4 + ); + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + endsWidth, + surroundBy, + isValidArg, + isValidArgs, + toNormalArray, + hasChildArray, + toStringExpression, + + // + sliceContent, + clearContent, + clearSurround, + clearArraySurround, + clearObjectSurround, + + // + isSurrounded, + isIndexInside, + isInsideIndex, + isKeyValueType, + isSurroundedArray, + isSurroundedString, + isSurroundedObject, + + // + findNearest, + findAllIndexes, + findCloseIndex, + findNearestIndex, + findClosedContent, + findClosedStrings, + findClosedContents, + findAllIndexesOutOfCloseds, + + // + // Validator Actions ... + isValidURL, + isValidEmail, + + // + // Normallizers ... + toNormalString, + + // + beautifyJSON, +} +//#endregion \ No newline at end of file diff --git a/BKPS/14031106/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 b/BKPS/14031106/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 new file mode 100644 index 0000000..ec3e257 --- /dev/null +++ b/BKPS/14031106/Documents/Temlates/x-saherelm.x-ea.template.ea.mq5 @@ -0,0 +1,542 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XEATemplate +// Description: a Template For Exper Advisors +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XEATemplate" +#property strict + +// +#define ShortName "XEATemplate" + +// +// Imports ... +#include "../Classes/x-saherelm.xalert.class.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Helpers/x-saherelm.xcc.helper.mq5" +#include "../Helpers/x-saherelm.xct.helper.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eAEnableAlerts = true; // Enable Alerts +input bool eALogAlerts = true; // Log Alerts +input bool eAMailAlerts = false; // Mail Alerts +input bool eAPushAlerts = false; // Push Alerts +input bool eATerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = false; // Report New Days +input bool eaReportNewHours = false; // Report New Hours + +// +// Define Local Variables ... + +// +string eaLogTag; // EA Log Prefix ... +XSCAlert *eaAlert; // Alert Provider for Expert Adviser ... +XSCTrade *eaTrader; // Trader of Expert Adviser ... +XTimeTracker eaTimeTracker; // Time Tracker for Providing Reports ... +XSCXCTHelper *eaCHelper; // Bar Timer Indicator Helper class ... +XSCXCCHelper *eaCCHelper; // Chart Styler Indicator Helper Class ... + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) { + return INIT_FAILED; + } + + // + // Initialize all Requirements ... + if (!InitEA()) + { + return INIT_FAILED; + } + + // + // Initialize all GUI Objects and Classes ... + if (!InitGUI()) + { + return INIT_FAILED; + } + + // + // Alert Initialization ... + string msg = "Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Destroy Timer ... + DestroyTimer(); + + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + UpdateGUI(); + HandleReportTime(); + UpdatePositionsState(); + + // + // TODO: Implemetn Tick Processors Algorithm ... +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrader.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + // + // TODO: Implement Time Based Functionalities ... +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + // + // Handle OnClick Event ... + if (id == CHARTEVENT_OBJECT_CLICK) + { + HandleOnClickEvent(sparam); + } +} + +// +// Custom Event Handlers ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + HandleReportBalance(); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() { + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() { + // + // TODO: Use This ... + // EventKillTimer(); +} + +/** + * Initialize all Requirements for Working Fine ... + * + * @return ( bool ) + */ +bool InitEA() +{ + // + bool result = false; + + // + // Locally Apply Changes on Prefix ... + eaLogTag = ShortName + ">" + eaLogSuffix; + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); // Default Configurations ... + eaCHelper = new XSCXCTHelper(); + result = eaCHelper.Init( + _Symbol, + _Period, + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); // Default Configurations ... + eaCCHelper = new XSCXCCHelper(); + result = eaCCHelper.Init( + _Symbol, + _Period, + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Create Instance of Alert Class and Configure it ... + eaAlert = new XSCAlert(); + eaAlert.SetPrefix(eaLogTag); + eaAlert.SetLogAlerts(eALogAlerts); + eaAlert.SetMailAlerts(eAMailAlerts); + eaAlert.SetPushAlerts(eAPushAlerts); + eaAlert.SetEnableAlerts(eAEnableAlerts); + eaAlert.SetTerminalAlerts(eATerminalAlerts); + + // + // Create Trader Instance and Configure it ... + eaTrader = new XSCTrade( + eaSlippage, + eaMagicNumber // + ); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // + return result; +} + +/** + * Destroy all Initialized EA Requirements ... + */ +void DestroyEA() +{ + // + delete eaCHelper; + delete eaCCHelper; + + // + delete eaAlert; +} + +/** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ +bool InitGUI() +{ + // + bool result = false; + + // + // TODO: Fix This ... + result = true; + + // + return result; +} + +/** + * Update GUI based on Each Ticks ... + */ +void UpdateGUI() +{ + // + // TODO: Implement this ... +} + +/** + * Destroy all Initialized GUi Requirements ... + */ +void DestroyGUI() +{ + // + // TODO: Complete this ... +} + +// +// Others ... + +/** + * Update Positions States ... + */ +void UpdatePositionsState() +{ + // + // TODO: Implement this ... +} + +/** + * Handle On Click Event for GUI Components ... + * + * @param name: Object Name ... + */ +void HandleOnClickEvent(string name) +{ + // + if (!IsValid(name)) + { + return; + } + + // + bool isClicked = false; + + // + // TODO: Implement Chart Objects On Click ... + + // + if (isClicked) + { + UpdateGUI(); + } +} + +/** + * Report Account Balance ... + */ +void HandleReportBalance() +{ + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(eaTrader.mAccount.GetBalance()); + eaAlert.Log(msg); +} + +/** + * Time Reporting based on Inputs ... + */ +void HandleReportTime() +{ + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.Alert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.Alert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.Alert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.Alert(msg); + } +} + +// diff --git a/BKPS/14031106/Documents/Temlates/x-saherelm.x-panel.ea.mq5 b/BKPS/14031106/Documents/Temlates/x-saherelm.x-panel.ea.mq5 new file mode 100644 index 0000000..c04228d --- /dev/null +++ b/BKPS/14031106/Documents/Temlates/x-saherelm.x-panel.ea.mq5 @@ -0,0 +1,575 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XPanelEA +// Description: an Exper Advisor which used Panels +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XPanelEA" +#property strict + +// +#define ShortName "XPANELEA" + +// +// Imports ... +#include "../Classes/x-saherelm.x-app-dialog.class.mq5" +#include "../Classes/x-saherelm.xalert.class.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Helpers/x-saherelm.xcc.helper.mq5" +#include "../Helpers/x-saherelm.xct.helper.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eAEnableAlerts = true; // Enable Alerts +input bool eALogAlerts = true; // Log Alerts +input bool eAMailAlerts = false; // Mail Alerts +input bool eAPushAlerts = false; // Push Alerts +input bool eATerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = false; // Report New Days +input bool eaReportNewHours = false; // Report New Hours + +// +// Define Local Variables ... + +// +string eaLogTag; // EA Log Prefix ... +XSCAlert *eaAlert; // Alert Provider for Expert Adviser ... +XSCTrade *eaTrader; // Trader of Expert Adviser ... +XTimeTracker eaTimeTracker; // Time Tracker for Providing Reports ... +XSCXCTHelper *eaCTHelper; // Bar Timer Indicator Helper class ... +XSCXCCHelper *eaCCHelper; // Chart Styler Indicator Helper Class ... + +// +XCAppDialog eaMainWindow; // EA Main Dialog ... + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Initialize all Requirements ... + if (!InitEA()) + { + return INIT_FAILED; + } + + // + // Initialize all GUI Objects and Classes ... + if (!InitGUI()) + { + return INIT_FAILED; + } + + // + // Alert Initialization ... + string msg = "Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Destroy Timer ... + DestroyTimer(); + + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + UpdateGUI(); + HandleReportTime(); + UpdatePositionsState(); + + // + // TODO: Implemetn Tick Processors Algorithm ... +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrader.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + // + // TODO: Implement Time Based Functionalities ... +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + // + // Apply Chart Event on Main Window ... + eaMainWindow.ChartEvent(id, lparam, dparam, sparam); + + // + // Handle OnClick Event ... + if (id == CHARTEVENT_OBJECT_CLICK) + { + HandleOnClickEvent(sparam); + } +} + +// +// Custom Event Handlers ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + // + HandleReportBalance(); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + HandleReportBalance(); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +/** + * Initialize all Requirements for Working Fine ... + * + * @return ( bool ) + */ +bool InitEA() +{ + // + bool result = false; + + // + // Locally Apply Changes on Prefix ... + eaLogTag = ShortName + ">" + eaLogSuffix; + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); // Default Configurations ... + eaCTHelper = new XSCXCTHelper(); + result = eaCTHelper.Init( + _Symbol, + _Period, + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); // Default Configurations ... + eaCCHelper = new XSCXCCHelper(); + result = eaCCHelper.Init( + _Symbol, + _Period, + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Create Instance of Alert Class and Configure it ... + eaAlert = new XSCAlert(); + eaAlert.SetPrefix(eaLogTag); + eaAlert.SetLogAlerts(eALogAlerts); + eaAlert.SetMailAlerts(eAMailAlerts); + eaAlert.SetPushAlerts(eAPushAlerts); + eaAlert.SetEnableAlerts(eAEnableAlerts); + eaAlert.SetTerminalAlerts(eATerminalAlerts); + + // + // Create Trader Instance and Configure it ... + eaTrader = new XSCTrade( + eaSlippage, + eaMagicNumber // + ); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // + return result; +} + +/** + * Destroy all Initialized EA Requirements ... + */ +void DestroyEA() +{ + // + delete eaCTHelper; + delete eaCCHelper; + + // + delete eaAlert; +} + +/** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ +bool InitGUI() +{ + // + bool result = false; + + // + // Initialize Application Main Window ... + result = eaMainWindow.Create( + ChartID(), + ShortName, // Dialog Name ... + 0, // SubWindow ... + 10, // X1 ... + 35, // Y1 ... + 300, // X2 ... + 200 // Y2 ... + ); + + // + // Configuring Dialog ... + // eaMainWindow.MinimizeButton(false); // Hide Minimize Button ... + // eaMainWindow.CloseButton(false); // Hide Close Button ... + eaMainWindow.BackgroundColor(clrBlack); + // result = true; + + // + // Try To Run Main Window ... + if (result) + { + eaMainWindow.Run(); + } + + // + return result; +} + +/** + * Update GUI based on Each Ticks ... + */ +void UpdateGUI() +{ + // + // TODO: Implement this ... +} + +/** + * Destroy all Initialized GUi Requirements ... + */ +void DestroyGUI() +{ + // + eaMainWindow.Destroy(); +} + +// +// Others ... + +/** + * Update Positions States ... + */ +void UpdatePositionsState() +{ + // + // TODO: Implement this ... +} + +/** + * Handle On Click Event for GUI Components ... + * + * @param name: Object Name ... + */ +void HandleOnClickEvent(string name) +{ + // + if (!IsValid(name)) + { + return; + } + + // + bool isClicked = false; + + // + // TODO: Implement Chart Objects On Click ... + + // + if (isClicked) + { + UpdateGUI(); + } +} + +/** + * Report Account Balance ... + */ +void HandleReportBalance() +{ + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(eaTrader.mAccount.GetBalance()); + eaAlert.Log(msg); +} + +/** + * Time Reporting based on Inputs ... + */ +void HandleReportTime() +{ + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.Alert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.Alert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.Alert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.Alert(msg); + } +} + +// diff --git a/BKPS/14031106/Experts/x-saherelm.x-121.smc.ea.ex5 b/BKPS/14031106/Experts/x-saherelm.x-121.smc.ea.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..0ad44f813a63088cd1f75f0440ae59362887ce10 GIT binary patch literal 393866 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˷&&?61Z#By$M!1H#=%@H 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%0A4Z~C&Teu2mfF>w6qDz>{oMK?H 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
  • Lc2;=$q{dJ#3aU=}@PFRQrRVm}PE*HOV1fP)qz-?Nc;6zn^=45KduRBBX zYkw!OGMza1Y$14wr_io7SrLKGQWgJmW)}q`7C3B@O_uU$ovuV$Qms?Mn~`WWJ{{y| z`2%+3V~@Fpltj-L%&m_+U6FGyYJ_gW|b+|%G((|z_h-c+= zEZDUN0j_A;1)>KOu|t zq!U&IQ-n$aYAtt_FebI4YHQJfvH7c$a(ddpmN5&fkDBFvaEtgDW-<>X=iIqM2;-fO zL?r&dkJzLH%|{kaxm9KrFYz=Nm^Ye4#8JDSvSB(>ybs;pyQyJMH_#-KY3u51hliiW zz68&~(|(E7KzS%iC+IHupGQ__Qpe_(M4hLziE-{BRbi-0a^=#OLaO!4!o|rXNb!bL z6|(D}2sCYwEz)79>w-QxU@OW+a7IBDX_EOR%LPUWO_GY-iXlV|+($Q?O>`!=(*g>x z!G}U&e)7?a9~3}Ujp~OZxHCmdTBxJoelUY5OR=JP4o_UK9D{qpJGY@o$MwG2!P<>ry)G#(mgtAh3QKeA>nxh#3U|2sS zJsgUWCG}zFq0YQu_GSf%1gkGPaA7v!^r5L*pCES-YoUr98!D%dULA~{K8eiuV1?VWdiQNGhnDVR@$zdBYFYH!`&3Pfoak19BnXiIBnCxSf)6) z<0moMXB9KhAjIjF<0M-vJg!c)znmvpctOE5{ihfoZ+$S-D?@XD1r_H_T8naPmm%nG zy2#RpUVC+(6a6vn=+2~uz9z67nygXd5lu6@I&$5}5-dC|W<>J9r$0NDIQ)HqUU4nI#usn~@mZw!5 z&n-UmAc|W(7C=xUVPSO$)EZ+qbh<>#e@5Iw@LDP<&iCST780(aiK|oNK@@U!Vc&G< z$K2U<%J%cx?vzU}I4=u!2kKd{k;AN0&<*f3xB37pGK!}xsUBM$>ZJO;7<|Zc;KwJQ zBrtg?$BFO?D*lZHLv=C&EWDF>4p8afgDCgn$g}UeJ>*9NyK6_3altgYxHL|z#&11Kw+6hI z*0wEz{UL0J8vpFGg3NYU!$T&FPrB-r!m-NNi=JZ%DzbwksHk-zK)Df*J-y$sY9Ag) zEHK-+NJ4!$7J1AV4QW;`EC8)1i&XNz<*mGqs^wM~X&cIs_i2i18WH~e$-$O>cg+M> z|LS(4ts1mbIMo`~Pgc;bagaC&a<|!(v1x>IN<}(8*=m85OyPp;pKpi1@9}#dM~{@F z44_yi&BZiuK)k;2J(Pi8*j_bB<*GtI%t>!31~DYeHJcx}y~T43SAd;{R`k3~U7=L| zav0c+&7=EWb}ff>1!0Ng8kNWU{ZH6-FZ%hMdJ|a-9oMo&Ca0zu;-!gpeoaAANk+uz zJ3sh%5cKGyo7YT=ReuY1ss0BDN;|IpnL+T=IokPeXeYvd;^dVHD(FFKS-0~Sf`v{* z+%Gw{#|U6%T4=(6E!lN>{OC=#oq{=kLEb~WyyO>%l`9gaaO@eWn6#Z%Zp!Yfk6o@{ z5CBnn%kmk0kJkZIhp0`OZ+`N*bidfp=|k@Gj)YppZRaohq$8vJqB&-E5Fgk>c(?PjEz`HDr*Ru}F|rq7 zQGyp{rD|E>?In7F(YQL&#{f;4|0fIg(ectwjLJJwj7#FHR{faMC9K^3wH*QIP0x}} zo>OB5qG?u=r7%Klae!C-6{r0zuzhY+uA?OI@N;IF)C_Q1|2YP#(~RTe$Le_+Ig^#s zIo)q~-#Om+PRxY6x~ELEmbX+%#E*qzy3J-{NU67J8aw zh(STNy8B~AYxHQzG`%pxZjI8eKGAF=M3^JqPI(}`xC)dnbw=bdJG%zhikP-lEjGn% z{kq?mnNctk9>XXw-O(Iibaea5fbCAXq}ziZ-Hrgxc5sPajAsm;M%n`qH&qw!jzBJP zly#B$3x}prqZr{)3t7q4l0z$@+?NanD_&8=3AyiKHRXEvZ{^{>EiwO_Z*}VaHGndD z5CYq>F1TnRJ~pgx{7e-A0e;Lv(xK-Natq)Y0>|n{(ur9-o>t<>|B)`hr{+Z1y2aoZ zB?S%O{>H1S@FHFLPojonP4s|LlkCrZY0BF!V|JiCPOEG=>L-))sHP@W(2ck;i_0Jn z@?B)fr3mG3-wp|_|0cFOi;#C>e%G70ys% z>oZx){|*+FHsbXU08irsjNO-9<4aFh6KHAgGw8XAY5T z;K|!F3QqezV~I5mAySV{MMDR&oSXiaMj60bIK}9p%{U10P^<=}b9ZBHb^h zvcY*Tbq+KJ4|xZ3tJh-(P5yjq9h?OPgRFO}8FsSA#_3Ll?IDbReNf#57nA$RCjtm$ z^~&;$rHXEE#<(b%E<__Z(g945mVMgOOIB9xq7!!RxbsQXNi-m7k2`qvzEnGP>L?PC z9ZG8UvEy)EUSbAC0Bk_z3V*6vMp#Bz_i~ghjMH6E%JmrWL0P)vJuYb`!RI7|*p&>+!@^(5F zQ!wATfgd0~mVIq^;0`2#)HD>t%aQdX)%e8#tacSlz2(>E->>>7LVadphB?aW%#PHv z=!L3S71Y$&IAz4x<`G-@_7#$_;Q^3Lw@1VbpH^}8$hV?nq+QC`NB80BvzQd|QSt8i z@k?B8y9apaxjhKjM)fH0rxT<cz$|#I?q#>b%Hz??NMjB#Roi0%Z_rV|F>*-N~fe78TBXXfPbi6j86%Ep%3g)ut~FV zmBod4V4N`fE;JXcum}djN7l`vzuwGH6Ed&3TSmdhZWtH*&bEZ)ua90eLg!D5aRH?7YA|TR=nNes@uLBTv&IP(i>+_PIqUN7V;hlQYt3v?S5$05$TM&{P=Xu&qmY z{a(r@z9OV}CCnQKM06o79g)5J)u&7qgM@N)b}V)(s7Xg4%V=nUH%p#V>oupSr3x9( zZaTkhqMZ{yDQwh&m5-uk!#T7g*}BFoAPnyAl_xGQA9dl9aU;+-9ys8T`2kt2dw>jx zBxK_PWbl%J0O3Z-a|lK7kD@AxKOoIur&cp&R|$G4ftXNWCRhu@%*$Y(poFQ^)CZWO zWq&;eguLpG5Psn)I-6DwS}K(i-$bgP&KBhYNB{Q`BN{fR#w+3^Eg8paL=Va+U1rJK zWP*Znpu&#@*)-`lnYaEM!i{xIcQWMozB%H%v(^YKpv)?*(dK8VK&Tnp=2S{@#nrJx zNUUN^nrV8^g-f#tXx^b)UWbgR*pa4UqIO7fo?OK=66e^7=L3Rz>}g)!%nkvsU$}Ga zI&@H>nxY1u1uW(0$5@U2Ru6r&wFXe%R1HS}lyc*B#0j=2C|_AB+)Y+EkcX znX8s}*xCmRZoqXFMp$@xJKI~9^XU9Qff>pNfzI8|$6GmjVc32istnw^w{k6v&f2KJi%oN?QER@Pga1mCRse`*t#fRW}1 z@CD0>G+K96M}ggX&EJW4n{2<2ZUSnFLh?#vaLMM284le#HV=gb0DIVc^|ZYO;1$n0 zc}~l}BZ@-P-8}bQPDncWXu1Pvqxe=YJw#q#nlhpq=U#|*!*u9DH7w}My%JJYn!S8C zD2z<#OOTH(;IY+ndaw_v3CTwjLN`c@26OJYZFe2KxT$U3 zPG`r2KqbYg0xL8eh3o*aV;77CeKWF5QG{~F6sR+XQl z;N~gJk_Ns4keJPsbO(A z!*3-zHsY~b`!PTU8OPj8(yn@zNH=q}jxy{ZQcfC-kH%Ms)a&W;FJ>#0T=r zr~mE*MsEe?za3>{O|zXHp+$Z~OFR+-bsCL)8o(l-QG_$e#r|WZ+?}Z0? znWKjOTAL-I0l*_bn3*AT4Z68rwzUj$Eeo2)v5~r9&b&JY+*MCW( zZ6ZPa{xzKdim>$yHI49i0CHlVMD$eblbJ$G&_L>Xy~>^H{1?^zF;XQdVB@MZ;pkh$mP}#h#QF9B58jq?m&ecii?1^3T87j2;9iqIZIUKpj+I{Bm2IjvN3&9tWI<1^JG+P9>p(g$uS}phV9ps+nR^`H*m|EN$6V&^e!H?$Af%# zY7`K0yILzj^4P3jjI}g)zch=Q4HZ$A_afr2gVvK(R^{41*&0(!HMW8HK^uh@AAjFZQi)_G%(&Cj&zHwQjR?<9n5cb7xQ z>GW0NX=jY}6x^sieSrmqts^?lnBYA`RH9|@#kXzCS2V37tW0Om^4~2ka)F*$pr;=5xGHFWs9l_y#U!;3H!)=7@#m|d*=t=$Xb-ll+k9o;%B_cEu(+PfcJl--utfaeSo zDODoCC%AB+Fn|kFYKP0e*a?M?9KK|AK~_yq@AmmP&YiVSi>AS2jfS-$a$a;3Yxk}q z;T~90W*FK92pK!8g}7uFtj{ZgPm=n-qYFmWc7kzYeh8ELL6K@L~f>} zGv1V-Ql~K%hhp_avqWEb4hiTJex;Xa#tKMB-F**0t2X^F3lO+QIcf(A^x<*eYhk^k z%cAPl{LD(S%Zeno%&+o#U38f*RweJA$bos}oiQ@?8`bIMB^8AUo09Yp^Q z#Jyb2b&>#gM=E z3Til0ne2J*7`;$l@&?%cX83g`)hOhXI@q%3a7Y9H&yLy@~?LRgxLv7yHD7b+z_rkQ_!YO zA>ukmK%7)*qG?g?9VD=a`i!1{9g6&$&4<257#6*Xr6|k-!BKYEzj>uXC?AV}O1Tqx8uV@`Hp74=8l_q>aNLh?wCD z71zb3??sX|SPrxP4gPtwjO!}mGSKo1d*Hm#WqF#y9Qew+IJxPAWUB31r zS=<9>{13%O@#7E|tki%`9pP`br%jvJDRjyVg^KtK4xK8q&5ZaZ?r$D@DNgrPgXzfC z1H-4G=)X=Js~MdeG_he0Scl?z)pRNu6t_ywJ;_)cm28Yzin28zT+D@}-nzsmibXIN z*5N%jT$4F%jz8svIvrkZvt-4#ur*zOYvF`~d%wRt0<0_+fL7cdCFDyYl9O}isdIA0 zxjB!SHS5D7V%$y|xt2^ml>jYscJjmZ8cdPJAr@6+r2a5ZiPh zEr`4qG7k5=>HdSMOT1>e;5U$0IK5#Q5JNLoW|g?*OEPDZ!Ph`xX~H?QC{1uyy6{-N zeIve=A6|8IIB+$iuYKR{m>0=0j&VSsYf@_n&S;iTS$Dg)+Jmzf6kPpb2JFV#9vtfa z&vOr6dg52$-+?{SO|)#EVWLI^v4%dOykWOqDMnfMAmtaL599AVbeNUKO|>CF7jDr* zRS>B8YE=tc+kiShnDditkE`>CrV=MeT5j!YZuSY~v3ykmZ3aQ$82*3sx-8cc-xI|i zzDezZP#@%Jt;tblKQJwA=3*Aw%Thv=K@FIhQV~S^DE6#GQ8IDz>I6T2n3rv~ZeP10 z+j818CnwCy{g)~Kxm2`wc9XnPYk^f8I%dj%RM$&s#EqmKyd&p8I&YOwm3%G_XLa>H z-|#+c<9i7ty62Q6;Oho9KZ94{p9?RYT;W2bADfU!#MnijTbEF=U_<~P)h^JvTRKS+ zX|Ph_!pQ!1eXrYcV3U&cG~j*$D5iEdAV#_If@13rW`>5t-|)!Ce@~&ep^`y2O^!SJ zh6py`t~x2(0;^Ww0S>yBniFoIJp?5q34FkMXoqGM5YE7Y)rWap752;XvJWk)`dQdX z1t5Lfs@1X{$q)GdK)~6|Nc%pk6lV1$zPaSP6KQenvVMlXcb=xyZ=>|f=mt< zIKSqtV3L*(xi#I(X*36`##)=5`wPB@+n=kK_TB5d{l)QQbtRtkXvFl>an z(>W6U$W6P9yRcK6$G@Z1k;<|8G1aiu4RQrbl9k|YghfCM@JcJsTf(6?sO_9@ED1n* zB@J{Ra^EiHPSnp|+~CnrItFzf80Eak{ke6C4g7d-C4I8;q^#^oK%MJS!e{C#TPBe7 z8`OW5?1aQ4VETvvpw5r9i7oEHV9GUU>N!(pIRN*L1h0<#5hoF|DQ`F$KiFE-cy2^f z=d%N3FuWH3o7bh`0;!lphe&sO18pu(ou?c&a+LUeQA6{>UK`~#Z-78CI04zr+~ zpYU>1E8loOcEtC0iv>C8m2c=xD#04?+^5gG%q^_RF0)t*;UzrPslZY*K{k3n!D#Z6 zvjcP_Q#XH!c4!xBsrLe%olgK9{R8!LT}*$L-)RQan_V@JSnfsXJUPM{r`3cw%p2PjTtn8eF3)#CsoINhH_haFBPRF@oZd+*kol}O zuzRECes?;{CN?NPT}{g|rzZh|EJ+vA<9-nIIK36U7*!8$TjiY$&FP1f+rA5{a(m%r zl<<66VzZ2Gml}6bv2h%XbUsK|rL%BZA#97-%d)Et>#M(EPCAuHJzI2J6G!AHPOId) zy#{5GuZ<6&mjAK#WYPz+6Vh9nz$hGcDVhp316TbdtqmiH_`Q4lVNkF#0 zp)FiQOdn$8O#m-iY_k7TL_Aosys|lhjr9vIVZ24YUJ_wwdC>T8!Hp@X2=ah0Nwhzt{3$r@lD|l%{sGv(kpH@BMxYE+xUKWwf3(D zEUH%WlZmnIV%7b{L_o5^`(XX~B~K#QQ9x@gZ^y|$Rgt;$fe$fqhX1DJ{<*JvZMnk4 z=DOie2mkOmq=E2&TZ2T46~+4Y{HCl?J5SyOz;qtQ;3@6UW0wG$1*{hFnq`*vvhc~< zZi&=|y~pifg8amtz*>yR3_HrHjJKk*il?9|qf0HwZg=@hCkUCSIJjWeO*FXma2~Ux zkhOoJ-!f@>VbTV_By=G_&G&Cbp_1^M1E*n$0UAx1=U2&5_)8)V#{yNh(70{PJ>RGO zDMJ0(3Q}AYw`)8*l(3D&(nZXr@$|*hW?~Z{)e@ljYi>g4})gzb;R4)eo)qjK}pKd==-|pQnG<@+dn4MdS?Gu>b`n#GKHKtykSyi z7-QYYO&}e)eo3m#$_}GJ=u?rlJBRPZgIJ^aCdK#LvjjXTcX*r@z6h>@X|kEy+bEJX zjVdCZTX7N;Vb#4L+M~BTXpU|jzBDk0qNbU51nU7eLb2$YMKr1yV2fqI zSm`OIWi-o(m7IU+VKfM4vX2`K~|-X3(w!{P=B-+&dyq(lG$f<|bNn#ueXRbk1Xoue25waA~(NW^`)EH#0f})nTR19CVx=?oNX?#rQIZfHh);+?lXN}Y10t?!F zBnE!ZKWCaEMc`6QMWHF zM!n?vvV@h5O%l`w%Xj=iQkRu8X`Q-3$zo@j=v6s4;p`m~s+srDADeXf0E3r|fI2di zO)SANLM<$(8k6*|gM^mv>?>&x%fS!$p%I$aJqUD+V?w8B0S!IYmu>i7u7*>Y>MUw% z5NJoISRL*uP#M`6l?Wt`7e6xAFZ3M`bKjl4VPY>D-YcMw9vpvh%d;BczM*)Aji!k4g!+phD5BI46@~kwYamqbRMD|GZ zqGdU+G|c&)iA-rWbMP@`(){kUO{_M_HauVQ!e=tpp1jyo!q7w*bNR^sfDhxUQ3f>T zf$ZS2F-|$N2c|?BmQrdU>*_(fv5K-TDu~JsILAjipf7uk?JcF*j;sD-@}{Qrr~WuB z&_sy^!O0ZI^6NI=J*z^lDK_{*l3AFVX400j#ciV1%cvPE>Riw=*kTI%3X9d%wcKBz z0Rs39!m6}<#u?q2x2mfA6&!0+vui$mh^jsZDrKnK`1k8gB8wsHvDrtaUGbw76{+dN zoIf6F3ZUBg)V2VL8KI@#?o9Z$VP;B$b{FKw;{9E&2*$82u7+S2dj#e?$mZ-p^RP~| zLSiHL02G{lS&T|{$wxCdHG}9~?>SID+td?J!_~Y89GK+Jr>_l=dK1~0obZeC&+^a- z&mflV(F2}In%4Ys&fiZ*fHkHvIsl)SzQl>LSU)tgIB#LN6<>6fSC=DX0@s>m7vv%o zU0FsiR{7Su03ngB7=&mo?hMUU%+QgaSfFsdTI}Gey3r7nhF7ik(b~xN^(69dY+}z_ z9Tv@!&5Sx(cWXBBWN|X|@Uat!#O#@z9==(dqyXSQ;UIVQ;&5v_*iOwrdHj2=|4ans zh?^uW|7=>m-03v12XYuEbcP_Sh!Al)sSs*j@ zrPGzKAN!n$tRM(LayAz}o*$Wkg;hVfgyXIEiDl;}Cf0y@mH!UqdaXq~Mu{O~c@tG~ zJ52wjO8QsaMDer{sOle!G_M*PR|xcl;t-CyO@nJ7q zOXx$4&(G4ha?^g2foAFjxyF+ z>;`#x${|U=l-ZqfGMcG;{WFdtLz_`#jYiHKqEk5Q>?9>n;1L#du^tYBz^FI4VD<1Q zC^a55;o8nh@A-3DYdyw|(H8+^=v(hCg@c7Oks4Fx0X8pLein?|^-0e^ox2Dj=iX;$IG zmE2GR4Si%ZeS7N&21fIMD@u#&sE_~dZP13d0qZWOLJqT`e>~@-)(@6_$|kBzW-*nH zCY@R|J=_hoTiob{v4Z?%%WjavqD$CA=>yN8dKD%Fa{k27N%)rnpe?=7N=2f>_v&Az zCl}zDFhqELQBc#e{`VRJ_6z#?i-_u)$|$-FFx+>8tjm^Y@SY5tU5T4}iHmaVO^mHN z3}?|+hfyC}Y@z$5l1v1p8=aDpna!a(ZaelZ(6i%5hMG-M+ZO#$Y>g0g8wKE^AW(rm zVKY{=_wBR?FGcHC{I0G$vO-m2C}m_1+HOL)UAXSA&wpS4Hv#x9n{l|6Wmw8uM>StxtrjlM1L1&Om#C}_&*Vz-kmt(rX^OP_0x3R zuBw4vrU5->LOHRf{u#lML6jOw^TpqT>0I&S{+^mC-u>0t-iSajO0CJh{LgvPAWX8f z*bsVitR2gY@e{EQLr#G_l%U_H72osuEiY6i#aT8sp3hdRgkcR_<;~6!P~YmriKH1t z{dWdZgCV=merUp~6en`#CP~iTCKo?&I<1hHj^Xh&}pST}s zLCMWoEer7Hs(8W%8Iv1kMa;`}R>GKM3by!EFHT-vc%>Wn120Klde@`m^4BD}s_!t!!8EkON!Acr$?o3;`oXVMw?B7w6nBt)cax zY5fj{o$Y0m`YqSwE%q~_L-yK7HMR`$Ai1y5dbLio&GeW`XhI#=q+G^^{$a2pa}&Su z>Vt${+$v;Vv3*BoGW87H#WVxcQ`X%8pWwB%=P6cVPFd7~0oiR66KfxEw$wPO<0*p!kKz1(&O5 zI!89zQ95D65qyJi1(_1#7+naRd^5-$b&s-p8|{;989_p^Kie6Sb4z=USJFwrpcd+h z3|3Y(wLsF*N?(31q{aGmyO*Inrd@#QEuhe`Z#S{zl?^4??BD(>``!87zPE{|t<259 zL7QUhrRJu~n%QGmch80#Yw$FJQf>g5(*?s~x6E#d;m|J1#E0Jt>h%3;O@3(YbTk!a zFcoY??^DL;O^F0x?Yu@+9ZXbX1OQa=sFZ@ zOS$YP(xO+Zxg8U_)`_fP;t9yfnuOf6C-<42lBvyDfu;)I)*WgoEhudG%kqNQ{I{DG zSj&@2MFh>g1zoKVDut;rUAXla{pOh<&yZWSI`Gn^Hl{2@k_$iwrKD$BE!YQZpKZKc z`j<|k&ZF^pCh6#p-0MMH-cN?05POKXFN}>)wX^cX2ZILElZXyPoB&Ey{x#qfN-2U4 zVy8pS@htHpzzOL-47-Y8a`69D=1100_G>K7$GSMp8L-K|GRe!7Vw)7?R-63+ETeB5 zsz^WcC`ZW!2yK^EHNj^1?;ufDrsTGuDGU(IkGvU}7=61APqO~lq5id&02AY61u37; z;g=issr4jl>65ccvn_Ofi7r&Kp>Cs=Dgx=3u-YW z9=0jncZ{nxN>nE|-NIy|DN*V!`mFoUy@t;z?X->f9Q4l0JO0}~ zdHuA!k65lOo+-fLLA2K?H51*rbl>PnFG2`wPsu3I_ZhuAox4A%LN6{1mZVq62X^Y- zKm+5BM-?$TP)N()0}+NIh7VPnYvz3ER=I~Et;%cZg0)YnhZl49>L<~Q5J z2X-d;gniB*FNz=mRTp!LLMP!4rmrC2Fh7UO@Y(*5Nb^baFiK!Oom_i6cur!R367)q z5z)}BWw6>Ng!=kTKKspU6kCo7AAOilGS56|6T-~iRuliZZPUNB@o*-<$^n!g2*93O z5uIZVf$2y~ORxqcpndM-7dG~Yz>B+K?^5}d!Yt@<^eiH9~~xn=n@dFz}1Xhxd)p$v5Thr&aW#w zSn8PvBgRVP#(DJ^Suj}muEml0y~NLdnGOJhOrGAN3}76;!g&V`(Kn*p6@QR{esrOU zx94fYdJFX=z+ypr(2X|NQWP^qRkKD5!+)$5k~ zz0plOk&YxStZ}^$#z|D0tUe$xr4)wAEEAvC0riF*Q$IHRC>^%NLtBL737@!z_u(gP z?aK6S@V9npax#WWA(m9voe^SbJ9bv1L7K4>p?pSoz1nvbp*42iwoxm5){Jut4E!uM zHk|JD-W?bH!;3fupO)a_AI4jUv4@bZCDN)6*`GO>#&w~vUdB9W*eAMX=?75nq=M&G zfZ;7QzMNG{0y0|#v}SYvr8eS9`s7P#2CwMcqJtqnoMwkpn8CeIk34%_CYNnNji!?g zVlNw26wQW|mY0^q+6#avntd37S@p%;q8jy>fxx5;Gs>2?O#xD$JxnQ#C9r4^5ekHy zC>&@B~f~F~Ww&phbw&GLGM3s2JUS!10xfWI;J?ekd;ee|5 zsWIWBN%l@={EMcz(@Sh`a*N%CNgA~Lk~ny;&TOad8M(JWCD1978N;&8@DQ|z=74_` zI|6UD3d05Xgx33i`#9nzVPXf4>)@3pvFM91Ftj)wR;O*XAi1UES`&u@9{3T65q1AD?RfP2ccFt}D{w85100c^dF0~y~JY$9#`%r+X10uNhjJAxpIX~+J z{QD;7Ctr@*_}J(bw`il?!RQ?HssoGjFF}LdKQ8TTV2Sr`J;EV0^299g<9CaN zXyK#iAZk1*`MaNWNBTTa-sKTfTXMRvM7Z_iZEt%&!Q^=rqwbJKz%+WSTWhKFfxY`n zMX`IOl#63TevxEE=&lhF^rUx~_!l(BdQ)xvGs(Veg!0ln+QqQj*l_G2O1Tq;ri`Z0 z`*&0^+$Sm@Wp$B}zhmSFF_=S$ez^51CW%3CQE5-giD&|5B!PzQSfnXOgKz6nf%_6d z^+=<~9a;CaS(ikN*E20tDfD%h6{s2N*)#iHdigquF15S({VJ-9zN8b9#Q$Yvr9FOq zMXyFnB^gvJnMiP3c3TdoI^Q1Yk}>GxZCH2%a7htP^JiKnb#zO-1pj~*K2Mv>%V8#F zP5%{VUYM8dn@xUdJ3>rpTXGZNnu4G*Cwauas5lxg_VjelpXC4j` zS|W{~`{+NJSO8ZY?F1OGDuxtd4M@`Y)9*tK7d1`n!*qV4fo)m^AxL@_U>$9y zPiQwC4+#OAe(kP2QODP0kYaZ4occF(z6bp;rC;z45JJk0F<)keL*e?)7|HUxQ}a10KDtBa`P397RpI=1uk!1)y*!dj@LiAKqy}bj;sdEzb zFG^Sro&3HD4^#iJ+av`Ua5>J~SF%dsWdG>I>1Z8nHk>!t4y_%y){{Ta(UN1 zxRPq_JQX+9iTD)}c(^6hT!BWB7kCK9vHh4jO!;9NkqHT7mZNyA3G5C?=s0hnUnvmh z9|wA+)wQ+}p))|S22F(mNjbpKy*20WXgPShK;+IxFL@M++x8%r0MhuM3MS8vb*AEY zA-Px1UKdct4K(IqWgAZ9kk$k^t{z4&FrwLot83FD2vYWu?z0_jgx-U}WPrh8(osnK zF3~Wz>*mBH#lDY@32IE$)GPCorH$j0(4{8neLyJm)&n8W3Xsl^bEpu+Tu` z*7@9%UsZ$f_TkdS=Md5oIP=wuwe!r$?8mNtR6AZZX$!2+Nflr~KRk7Fr5*G@)1}70 zBh?$APP=ODuWYpIO1;f0cJ+2Xj`BcMqd=QmWo=u_Fo6MGfv8@&fAUhF-m!ujUcH_E zS4wwHTyxM}%&{4?6cF%%3556A&gus65!|_{$QTUaDisk2&iMK@L(#;a>02`V(>X>d z`JYH9Lk6V3yGP{jxlU#dIZs9=VuIkbGPO;|i^_&xiS9rr6!c}Su9#IjX;bDP^S_Y` zkj7I=ui&`xU$ywD*N?jOnhxW4mayb&Buj6+gaL|$v(e}XIkjKG(eyp+3x3lr%pFGy zntpoXC?5!XPlD386QxxUA#>aBP-qU)7bZ>rzFKdn#xMwVmsJFYR>32K!tK`kOeg(B z!!*{Fuc0yFCIiKEVILR%XFk!@z;mbWryx#euKMOURmJP8h#6QOJK~5zRH?7i7<(_m=AcK?;9O%7N zzb|1cZiQ}c6YqZQ*hbZnrB1(#*F^%+WNcRBbWYEOEFOJ^;}o}z`l4-3)X>PegecJ4 zlhz81_KkIP**N(bHH)(}JHOjUg;^9EB5lP1Ak3&5I(ZU3 zM_XBvDmF1H@N~qM%tNd^?@RHhm$P6ro;3Ir#1xKwllWH!$I^^Ja}!{oG42ooMBEx) zj;}O8RoUOUckZZa-(8P3<~nc7sa_oY3e+>KK$qoD3Xf_k-yX0p(^gpAPSPSc@73X&;;s4|1?Ix@@OM;d&Vv~+D#$%@5l;k9v0s2Ylf)K}d8L5tl~d#B-#f%T=3TeFnujRCL; zz8`&@@Ed-_=HTa9GGtk~N`YUCFv3uc;|3-kSj^Aw9e<`wAkpc~pQyUbOj_Im1-Uv- zI}l!DY+xX47M0y&8&y*WGQ4TN7~62svu(UW|H+zv$I)yzWA8#wDs|g|T-jTsUUl!Jf;Q`2yFC{;;cYs`ISPdZ+qW!(^t}qJ%F)ZB zsv6>eo5(zYbFoU+$pUPi)a zTL4qcV!-iJ*n;!;Rr`|aO;85Hi$T-s3kxB-`6@6=bjc0&txo+8X&VF2nxq zBC7x4EXDSLTk<3BW-%$_Kh79L40j}z7r=Cw-!DxEi!oFm;U2KjM_-vflWK=fDktYo!PWaV z3%YGLS`XeJU({cGKQ8-J4hc=%EMS~CEn`%a@idt)vwjhmC*m_)>*SV;l%7&X)2aaz zc__hCPo10t!%W{z0O%=VXjX?Anr>*Fin#RLD0k~S(1MWQy7-&0vQr)4;Ap=3Hf-`v z;nyRI?)B*%_u8=e{ObK*JfYA)`h}``WkZ7kdXvlhhDX zVc)2AhwqX}pf09m6K`P%y(=2cxan&DPg^x@9j3Otn4Apx6+G+Ope5G^fXbI+7!+eb z{i9vw*d|c#ppKvPA3@jI6PZzBYz zNLZOe*1tk63aGIIhViAhQY4`lxzm23`S$~W$B}J^P=KZ4+d-pc)Bi;zU}DQ8%T>jU z$Uia|zgbe;TJwld7OSlnMolETSbK`<{8xUez2Zcx-L*-jKS2!~VbEz@dDoWcKq}MH zNnz>6o$HQv;f4yL;DIf4&@t#JOHj+Jr_)l|j5K73I8IYR)P)UvBGlDG@i&Cpyn(kp z_N|5Zd`?BAL>?IH-kfA&!0BRAlVX^>>i(Mgh=ei40wEvly;ZOSddWFaRJ;GGD*Z)X zM{8ez{%Q}#+;L|m=g^eD7}@n6ZL0Ip$FqZIR_^J@XR=wNVn8XIUU`<8X&#jet7BdJ zHB$mFtCq3FH5|D63HkO4KG;&1hb+3Ee-af;ul`#2_%+(Ti>=kRRyMM}NUx#%d^es9 zUb||!MJd(So8&T#B`#$ebtpW9Nkp-Bt;5lD1LOcGB?3fe3dg>MN6ry97Q2S(brkJJ zJsxC6WgTS$N2e17!|wf)2<B`2-^bI()N#EJ^eW_d z!@YT|1w+8F4hlsDB%;`Pf#+Sp#DQYz6$8o$+i@}rUasmd(J@h5DH(>K1Rfam0oI0@ z={d^#5<(e%k91c*=e^@KTUJ<9Uud_{Z_RQybIsI~%A(Dv;;Ctj3K*#|)8-dFck)Nw zpv>_|U7z|?{^|G^8lTO!UN{+NpDfZ1Dw$WC+FZ@-HLL|}q~G61yp!Ek6i0{;w3Bf3 z5M^~gwnG|ZwCAuAz4FY=Er5P;b5YP_r6|(G6$Njxxu?o33=y zIx<*rgBV2BI-mgCbqYmVdoOX(KQFJ|jvX9D+GNWqgpm&}ED_0OHWx{j z+xdZBPPfPgiviLl-%I4nofV7;|RRM6l^4wBKR z(Ql4I{$k(Q{Dq-7GsWJB3GUo2bGFZ!R#^(0^*AbVT31JA6X$N*!eE?Y%RZ|+j~2}7 zg}hZsMK_HM+Z6g9^Th<);?GW{m2%BtTW%Z7oTvf-Moi^kKD#+52AH>G&o?@_+4m@f zESkz{%N-B4BCtly)jZMTDw0ua< z{}DJ6srAZjb2Axs8d9?^=`|7EB4~x-3%7kz<*TDxO%(eWu&`yK^c&WcT(C6x(!?w7 zF%udVK1Z|-XV|Xxx4^pM`_9*>C zKMA0Y(ae??xR4CNmIz(2EBY9uE_6-#zvh7kV^7@T1D_D;Qzsz)`GJpd^>?8q|q*;V;?Xo}Sc1i%NclkZ24b=htoPG%Irju&K@aocp6VEv044Qw8T0$b2jKz>%$m>E$G3S;I z<*`>;T9}K&P%tseKiJ}dQ6gHOz*{i8kathJqb)}_g*F~@UuD8BhzVa`Qg|GLg&p)i zOK86C?CeI}MNM#R2*NwJ@le#fIIr9^KN)l`@#SEulNM7oDTB{SU9rMe%z7_nA#3J{ zX?;2|s(r$~lUNhTOr@BrP^d*8um_))y+|>h_u#@iIm|pP01eEc%BinvllLTL(X(=?LhG#uZc}S_f3P2M>I8EZ=m!6)<3AkyjwHrU#ZQ80=(rm8Fd={>5R8(wW|#e_n(huApV3u{K~mF+)=NEOv~7aQ zPQKY`WiStq&*03~7a}kMy|g-K1A|JYK@5iTUYppw(l~+VVUkV)VL9Z7sky4D>di*BtW%7h3EF;x*jI%Y*bk;A!+DsE|o}LHt+)4oS z0Os#GOo7r5bOnjDj}brORStdYka4Zu9t9pRB%5Q<<41XI$~4m&zKRxjDKUOAlos&S zTA4|Gpb$PT!bGqoi%lO|mYQGOtn!nhEPQ11Nw!c>EPuuSg)e9)!G+dXugBhPGC<7i|m;g=}=RhcwzzOH1!+38FG(12aMg{dQ z2rqJ`mzP$%90@U}eMIJN?laN?LRxrtevh>P+0Ma7uq=_JQfF&^4Q7Z&x(PNPm+yaR%dOk&jXlrJGw;yIs?1xuW@*4y%ZNcBxPmw3?%S zO}|z--`U4XnZDcfEyO`3u}z`&Cy6$ODAy>1siPc%t(eu8rEgHuzGmX!-)q0fV^ipz$~45=Bj4af(u!o_UPWukChXo#VLt_Jz;#SG+GpCcmiVCZzBYXS6ugXTLJ*^$wswdv-tPrrQyrntZzJjXBGqgV=e*}U`V4-c( zASi^Cf9#^1+Y?<46C4F_X9~<;qDD`GL$R>eg|+L=#y~s!_CdB-aDPpW_)FG{H6c1f z%V?PYZFM_{hs8DGa=Zl>qW+;4_8$axmrw3?gOOwP=K^S!M_lmmGln!b6XgTIO0&op zvbQr(vW>FTe2hoGH(Y%3?_Y0f*`c!+aRBaf@anR4gb7U+`l%Qx^rqG+;t8W71qqzu z@9F`u`t;iiGg7c+XS)3?S?~2e!zxJFbT$icUr8jEj(FNUQuCo%PxI--s-G#Zng+3o zb{h_sP~*V|YWXifp)bi8o1mRE*&6HaY`56J`^%lcJyDsXV}Dxtl{T{Dw^bQut27Hb z&%;_g-HopZi&3Y6V|VW7N&@B`K~9O<9&m7T@htdRIkzlw3hN!n6U#10ys>`?$`Z zqobBOC11b({iH`$?upU7J6<0I5K?!nYGV197*ETFmgU|UciS=#+W%O^vJkG^ z-W0v(@N(x06w;a+CuLCh7KD|6{e57jhlQs-#QZm2Imbv9Bb?N~ECU8e0B^Y(VP^pZ zz&x~}ye2^gmTpgCELYoJ(y{xYXUjq-+FSebV-amGO=0mnmOX6dD6m`W?llm9iQAR| zn%D~`j(!Cyu;gvM%|G>%4>k@%8*MF9KikxL_C0W`#kk_NL^%=yp+3r7#)hwo90Q|| z)k)O;yQ1Qz1dLaz=H6A-Uv$Me_5Y^)WlsDc9^1Djdy0{WPtYjE-0K$XrE)69EVM z(f*9Cu2W(aKd`YkJ8D-CSk)e0#&T>}qY!6imN-x{xz}J#UMK#|vjs@9JZG3VoEKsT z>xdDUmyj!3(5u`^6X9E9+3|y)6lT>XH>sgLPmvOAp!(NP`l5!)0s)zh$!o3>>skd6A~cYucBata+SkYm!meOqg+HsT1L)Hr=Z?s+yAWp^Qh<<8M&6D2D#-U5-F${oxvx}omyzr{pb_#+8)a~_%${dp zAG_kk*}AvUef|6C)dyDgxpU1jwXUl_3m5Y255oG0Kp^sD7ePowX34b5=g!nEk z{rEO#HP3|EdsTC|WX&ro$@qX5C*!OuS^*T?X4qVPvhHN$bRxTB@4{Q^0KWNa zD5_=zRpWo7`xuc}zE=J{Ee+_)WC_k0q-f9BD82Wn0ONL>+FFq{hs;ymShSk>S;a?X z#q#Wyye2uEC_(0YV2V_Hv+#7lzZ780%%xe%)Eo#R`;nrJ+6iTs3c>Pj*KHeqC^Y*g zEWE+DZQxYf`Ws5uz#k>I+{NzLZkOS%a@p_7!QzeiM-g79+K| zOnLE4rd=o6BWoL#sf!6=>twA4&%4s_%H>wCrFqbMkf|1p$yWcI zy;?NTbiNbmo8Qxm;u!JYM$Khi+4<~T;8KRJ6}UeQT*_9%|GdMjVhAk>I0VGmuPt|K z1^mq(nDc_;G5PL|R1IMUDGR1L)=I#t){x6$8b}8>e7?aw@n!C%OHQ9^t$}61HIz+4 z5o0u}YSX39l`vQGBC1sUc5F>leI? z)7hRDv9pCRdv^{Z)$Dqoe+L4F+rXtpC93#$$=u{tKVmE+xVkD!J?_2*YaLXWhW_izP*wXX-e9#ce~5d+;5?ywQ8N~fZLwKYafwVU{zI; z1?~a+t&^N1?P3qd-#+fr5YvoU$9PNFO4(IJ8KN)Lmvw4eRC2pdBkZt-yU=d8 z@Q&#W6g;#+N*VXeO^8j|)?CXsHVaig$@-&z&+q#%L4WEsUN+Wcu_F<=+Pvu z(NNSSTG-2lcZ9M>w)4_fU!@1=%+qMfN)jeMlC}sg>VY`bG|_NOT_7D_oMG_^@SShA zpGJ}1o^#<4Sa6!PcGr{o`J|3yQR(2vTi6*rGdi_Y$Fc?_R`8i55_G?T<_RnKY(6+7 zuOvV)ICGyRG^v4{n8jb!{4{9RxINx0oydL8NVBc@a@zEq8{5e{U|dEZsSp=n+X_N5 z?F`2Oumu-F+j{YT9x-$@tQS#E0mwJg%kh*jjj~k17$i3w9i~wB1;T>`L01}Foe6kh zy3eQK!Z%~l5?SHoK0=*JF?xNoC_Z&Ak(%ED#a=zuDb}YRFt60T{gQQP)m4F=;|;+% z@5RmQtOE@1Qy$#kKW8S~ay9uPZ^V`FuW@t=_q1bI9NA6KE$%gf`uY-C%Gm-^xrGv3 zSi}~?`z~Uwk?};)ar63VQyKF!al2d6Rz~syw>|hj!v%=eKltzVV@Tq(>2ISzA#Lxa zCZf?oCwU@A6?EO>fy0L_ZEkHGF#O}xmo7+5albKg*VwJJlIYzdE$*^_rgc{mpqgId;coB}*DwxFS zg0Yas^U^Pp_@yKftEdjIS6iPw-pI&@yhNZ2|F?NsY^mD%C^D0clHq@>7|#^8zGRFq zJPSJ~ByW@5n{%hR_LRO}HdA^#&)VE>$pBH6_(y_dl>z}={k9)&>G_Xu}KQWXNEYVcM|&zCJN|Gvfn#O13CjM*w%{*HiVZekhx z!R&$R7p+l%^&trl09ds^KPSP>pvKQR-s$J<>FK%jRLB zwd-mK3GXR}@ne+$3of7KOvXiW#s=CIMLet=7jdtsO)Nh5cd7PI6HPqs)|Z_kmcxIW zA|6IU^lA6Ga93!K4HhDsCZZrr=7p|AhYs|_B01^5SI>m| zD;()41S;L?o56k|Mn`I+ivsqCtY*!I{FE7$N*5aUAbW7syDy%}MeoOf+q08D$58Cm z*}0)tG34!eTu<$*>Ol(___&9keD?Htl&Xy_R9(D)lU zVvO&}sPu~_%V!YGE#dzL9C^zYkDXpC`%{}qQr6tXKl%TKY`dUhhM9;o7J|tmZu=6)*0ah68wRD} z-yh7f^Gh435bCRGwQjxWWMj`$Za_oar5pl4WO}5;R%LvQ%`)*+OApKgeU)E&@2R^k zM_Kp}wXdjTfpz&WJPANpY$HdDylQ6}yU^@mTI$YCxj7Z@-<1DG{*9twmts-lO1WU% z2w{8K=L+Jc#n>RJH=Aeu3n5_cNe@GXPPIxV0KaXN-&Kb}sxXFnv@IeS2>yY%<@d16 zRJS`*I^5lR+2L_ppyC`!2{OsmcUsp4S@3u0#roGcD4xyn7u#L4{6 zaJ!W)KjnFMch8X*Cbtt8B2J7JDSs}x%vBVspoktrjYlGgls;#1VBgSuecS^Iu|x8w+Z!bX4` zQVFbsy@tkJXmbKU?nZlBx5e7hpjvEYfj}((WYM+25K*)W_a@`Kk-ac=n(VcTrz>Vg zkXN;cu5kIW;8~)-7X5r(xf;z^?LxffI??u(GwzdK{lo4%Z6e)EEM+xGOsdmiB?zz{ zA*K)ji;eBame=etkUS@)y+bvBkB9gIv7{Z#T8;wasd9SfMf?^mi>RA>a z;^oBlrR=1?zUEy;OwhhKA7H}$?$?2K2|pX;X1_yil6doFd?pOU1nETcpIFQ}1(9A> z9M{G~sxFU%xP)97V1U@QfK28s8?of-{t7qO8cGk>MBvcl2(3PCl&Z||%I)N-BM1A5 zCRPV2gH_Q?7mkoAq<5a&%~IvYIl99Z?K(vr2ZXnv9x40c<* z*K59DG`eZJ@Hh&=_N6qPlJ)Pa=3g_MI;b-VwmkwYnHVo}laYEWx0VDh3B4v~X=Z{D z+v;$<5n6Z7OMS-*1h7dzpSU^f=&Eo3b=!@iIT}SsG#d`oGXXKg@1+%iJYBkm%4aS= zjra+Y=SF78^IfmoK<@&1u%pMK{WQ$eFM3gKHs z#+P%ldkph<>U!wwj!9)_6ag6eUF++B#Jp~1Gr zHmqQQoF0zcV}T?dx`lMv^-?!K{CgrkoC8}O5MP7R_u6V9u3)9&-AB#juL=cPnh^#( zNF$+69c4k5fn9UCQ>A@kjZ0Kl*GSQH4Qg@R5_&so8T#PsEo^z!P z!@)vmt`4UbG;S=C=sQrf?}L*6gY&}46?rDAMde#-veqQhH#tT8YI6grxVES6{$E1) z!Kco{TC z;K#r&deaLNN8h$F4!!yGJ}7w9jkIqK0x$VNY;YyY=BrM3NbLkV-NPpK<3)^4lV)@v zjl=*wII13TVmXUH3>_^!GqQL;+*#MOJ@LtpaR?0JuJl}GV=d>)y)`lxY-bvYTK!u zf-+lomv#UtwbZxg992@l>HH(0RoR=6T|#mS^?&_>C43wgiD`5ot!!=J>9~uKOBSaM ztckQBIwp>%FbU!b^j+v22>r|`K~dheG@U6cQHV-eL`w!b%=~@&P!i}JV>fEO{CY+z z==GMlvSQ+7R=?QERSM8G6L^g#Q#i7(k9pN_f8N9yorHFoZiMd6)z7H!hAe5dTSz{_~TOqqA= zei8~PD!sR?FN)>uZR3h)twSOD9NBqeflLB!d5?WcsqE7VW0Oix$<76? zbdj`^W3|!~Dq@zG7}{0#(%~7sl_aJ5Y^Ut}P{EmvOWyCs{|!+!hSZ`)BefVRA?&rk zjLVX0;#qPe8f_tp=8)=B#6Xyk^XVhA@AVCd9u;CN`Ke$Ktmac|809_y$7LBR>^8^s zKdeTC`~nMJ`3)`TY;Fu&|7gFC_v5wR3cdH?_aN1vb1vozT3Bw;`1gIX5wF( zVdo+t2tmDGn1=?{RvEyEqaNSKnffb{0r|s zV(RzMEw)~ZqH`7zk?|PzuJJBuJoE^aBEx1s1?T~bBl2Jj)F5IX#PqcHJMzY$yHRhJUlp_^h934aY~S{5DwAMz3focv zSa=x%lM;#1I>OZB>mZLLL*%JMt9NG@a_=rzddhmN5N~c-BptSzDy1)YUS?{F3Sib<{X@w9 zjyq!isSatul-tV-mhjp%M@kd&7Jq44XBALH2>F^3Q?+r)#t z>Fr~)<(uj3;&nb9JXg)F=|mcJZOZ^x4D%9QiCP;IzefN0+K=Ru0R<+OaiOUjTQeA} zCfbyxe2p}At1R|_C$MuQ_JW2a(|19AUZ_ue`Z3PY7`>%ZerO2_a=Zm|Uw9eVz9svP z-;m^oP`Z|ELGLwk`B89jmQu~rPziFbeoX#B5c{z8T{J6s?M)TcM%wDuQ`nCEg80zlgub}`b9Skpl+`d|TXg6Xo>HwBxwt&T{NnhvWe^W$f zD*Lv#ZKbKYj+J$wuqgzMPry9_`s2OCl>;$rD&MZ(vg>C_%(_kzpx z^8YM?7mQ)(8i>|K+1O@SzS?_ifIIp{z`e@Hyq4&D8*5+-dx=wgYJqCiGm&#|DbJJN z6#`D1@IhtW&g@A33fUtWTh$D_3|5z}%FZks9f?YhpvS#7oaZ%?M}XKl+=2o^As%l$ zf~t#)lRH3IL}!t}_oxEV$bT8{BiO1r8HwCJLT!{iU6p8lwj#T5VI!gA9jSO2&gSdP zcNd8+l_+*pYfyA1M)2TVt3iJjn~6ag{3FaI=!Q83k4(G37^M}&KXRmvdX=1q`cyY^ zsCSNR{>mQ|s7@x0(xf}@Oq=O7mBCezwO)`el&|9zW~;qoL}m^KQx}p)7biaq%D@i1(<0~x zCe&dt;SxeYfkEBWSN=#GE;?HF zP(qOhQ5_2FN|PA-)irE;PaOA{^fnu1i|0M0YC( zI|HJYiCk5YhjR5L*;Ts}BNitue#elBfkte}v$UcxPA<%H?ki|%=-Y$4WpLkJLNT#P z95^#dJOD_*owTZFVP#mqb}Uh7gQ=+}TL27#XAkfPALC|`N*%?n6~Cj#b(G4Gz+Mvm z1JLS{G6UbQ{E3t!T%+ubS%`qs7kgbHhc%u?qVn0Kd5Bf}TNh908#NLv?S%Cx(UpU8 z_lRN^jV3<@Cs$gw@B2T~^HYvf%4IuPQNt-aGPyWHW?S~6tJu-NyoNVFT~V-5Tt(%t zLQ5(y)^GooZPCtOuJoTXs}Tt#@*C-2O($P6WUp<d~5%nwplzgh$MH%w4yG>Ac&?N8S#N%5Wv^ zR2e#NT`Ccm06`ig&l_VgDmljcThj@nC@%!SVal2-sjH`6#wj2oOwvI_00glVBT*Jx z8FN5`2j^ODqWXB9fYkHP!fdQPH0z+o86ZoeO&u2_i+=M1Ri|xKRA;fPfI9AKwaHm< zi&P()JOr+(Cw+&Dszek!N91X>Xm7)Oa)P=`yVh?R}l9o_yvV9tS-O~37)ce1%kD+>!GikBV3nMl=d@Ujr5ac3Y;X}EqNf4

    o#Y*(&akiJh75?dsuFI|1PJUt#Hwa>^lkPvgbtf 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

    DeNv2PD3X%NDH43tzGG(xbruF7izKJ%UTOw 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

    b|xi2%TjH6Erks~f| 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ϐ%OFX$*-F#cu#{&&w`AmXqOx_Gh~TQ!C^6CY>9g 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 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.helper.mq5 new file mode 100644 index 0000000..0c9a0d3 --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.helper.mq5 @@ -0,0 +1,2932 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121Helper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Helpers/x-saherelm.x121.xatr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xdon.helper.mq5" +#include "../Helpers/x-saherelm.x121.xpv.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xvwap.helper.mq5" + +// +// Inputs ... +struct X121Inputs +{ + // + // Props ... + bool showRSI; + X121XPVInputs xpvInputs; + X121XATRInputs xatrInputs; + X121XSTRInputs xstrInputs; + X121XCHEInputs xcheInputs; + X121XDONInputs xdonInputs; + X121XVWAPInputs xvwapInputs; + + // + // Constructor ... + X121Inputs() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + xpvInputs.Clean(); + xatrInputs.Clean(); + xstrInputs.Clean(); + xcheInputs.Clean(); + xdonInputs.Clean(); + xvwapInputs.Clean(); + } + + /** + * Set Default Values ... + */ + void Default() + { + // + xpvInputs.Default(); + xatrInputs.Default(); + xstrInputs.Default(); + xcheInputs.Default(); + xdonInputs.Default(); + xvwapInputs.Default(); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + xpvInputs.IsValid() && + xatrInputs.IsValid() && + xstrInputs.IsValid() && + xcheInputs.IsValid() && + xdonInputs.IsValid() && + xvwapInputs.IsValid() + // + ; + + // + return result; + } + + /** + * Extract Max Input Length ... + * + * @return ( int ) + */ + int Max() + { + // + int result = 0; + + // + int xpvMax = xpvInputs.Max(); + int xatrMax = xatrInputs.Max(); + int xstrMax = xstrInputs.Max(); + int xcheMax = xcheInputs.Max(); + int xdonMax = xdonInputs.Max(); + int xvwapMax = xvwapInputs.Max(); + + // + result = MathMax(xpvMax, xatrMax); + result = MathMax(result, xstrMax); + result = MathMax(result, xcheMax); + result = MathMax(result, xdonMax); + result = MathMax(result, xvwapMax); + + // + return result; + } +}; + +// +// Conditions ... +struct X121Conditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double rsiBuffer[]; + double atrBuffer[]; + double strBuffer[]; + double le1Buffer[]; + double se1Buffer[]; + double le2Buffer[]; + double se2Buffer[]; + double sarBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + long volumeBuffer[]; + double peaksBuffer[]; + double valesBuffer[]; + double strUpBuffer[]; + double strDownBuffer[]; + double vwapMidBuffer[]; + double le1StartBuffer[]; + double se1StartBuffer[]; + double le2StartBuffer[]; + double se2StartBuffer[]; + double strPriceBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double strStateBuffer[]; + double vwapFastBuffer[]; + double vwapSlowBuffer[]; + double vwapPriceBuffer[]; + double vwapVolumeBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double vwapMidStateBuffer[]; + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double vwapFastStateBuffer[]; + double vwapSlowStateBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + + // + double rsiSlope; + double strSlope; + double atrUpperSlope; + double atrLowerSlope; + double vwapFastSlope; + double vwapMidSlope; + double vwapSlowSlope; + + // + // Conditions ... + + // + bool isRsiSlopeBullish; + bool isStrSlopeBullish; + bool isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish; + bool isStrSlopeBearish; + bool isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish; + + // + bool isRsiOverSold; + bool isRsiOverBought; + bool isRsiCrossedOverOverSold; + bool isRsiCrossedUnderOverSold; + bool isRsiCrossedOverOverBought; + bool isRsiCrossedUnderOverBought; + + // + bool isClosedOverAtrUpper; + bool isClosedOverAtrLower; + bool isClosedUnderAtrUpper; + bool isClosedUnderAtrLower; + + // + bool isRejectedUpAtrUpper; + bool isRejectedDownAtrUpper; + + // + bool isRejectedUpAtrLower; + bool isRejectedDownAtrLower; + + // + bool isBreakedUpAtrUpper; + bool isBreakedDownAtrUpper; + + // + bool isBreakedUpAtrLower; + bool isBreakedDownAtrLower; + + // + bool isRejectedDonOpenUpper; + bool isRejectedDonHighUpper; + bool isRejectedDonLowUpper; + bool isRejectedDonCloseUpper; + + // + bool isRejectedDonOpenLower; + bool isRejectedDonHighLower; + bool isRejectedDonLowLower; + bool isRejectedDonCloseLower; + + // + bool isBreakedDonOpenUpper; + bool isBreakedDonHighUpper; + bool isBreakedDonLowUpper; + bool isBreakedDonCloseUpper; + + // + bool isBreakedDonOpenLower; + bool isBreakedDonHighLower; + bool isBreakedDonLowLower; + bool isBreakedDonCloseLower; + + // + bool isSarBullish; + bool isSarBearish; + bool isSarSwitchedToBullish; + bool isSarSwitchedToBearish; + + // + bool isNewPeak; + bool isNewPeakOverLast; + bool isNewPeakUnderLast; + bool isRejectedPrevPeak; + bool isBreakedUpPrevPeak; + + // + bool isNewVale; + bool isNewValeOverLast; + bool isNewValeUnderLast; + bool isRejectedPrevVale; + bool isBreakedDownPrevVale; + + // + bool isStrBullish; + bool isStrBearish; + bool isStrSwitchedToBullish; + bool isStrSwitchedToBearish; + + // + bool isChe1Bullish; + bool isChe1Bearish; + bool isChe1SwitchedToBullish; + bool isChe1SwitchedToBearish; + + // + bool isChe2Bullish; + bool isChe2Bearish; + bool isChe2SwitchedToBullish; + bool isChe2SwitchedToBearish; + + // + bool isCheBullish; + bool isCheBearish; + bool isCheSwitchedToBullish; + bool isCheSwitchedToBearish; + + // + bool isVWapMidBullish; + bool isVWapMidBearish; + bool isVWapFastBullish; + bool isVWapFastBearish; + bool isVWapMidNeutural; + bool isVWapSlowBullish; + bool isVWapSlowBearish; + bool isVWapFastOverMid; + bool isVWapMidOverSlow; + bool isVWapFastNeutural; + bool isVWapSlowNeutural; + bool isVWapFastUnderMid; + bool isVWapMidUnderSlow; + bool isVWapBullishState; + bool isVWapBearishState; + bool isVWapNeuturalState; + bool isVWapBullishOrdered; + bool isVWapBearishOrdered; + bool isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState; + bool isVWapSwitchedToNeuturalState; + bool isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered; + + // + // Complex Conditions ... + double cheMin; + double cheMax; + double vwapMin; + double vwapMax; + + // + bool isBreakedUpPrevCheMin; + bool isBreakedUpPrevCheMax; + bool isBreakedDownPrevCheMin; + bool isBreakedDownPrevCheMax; + bool isBreakedUpPrevCheLE1; + bool isBreakedUpPrevCheLE2; + bool isBreakedUpPrevCheSE1; + bool isBreakedUpPrevCheSE2; + bool isBreakedDownPrevCheLE1; + bool isBreakedDownPrevCheLE2; + bool isBreakedDownPrevCheSE1; + bool isBreakedDownPrevCheSE2; + + // + bool isClosedOverCheMin; + bool isClosedOverCheMax; + bool isClosedUnderCheMin; + bool isClosedUnderCheMax; + + // + bool isSarIncreased; + bool isSarDecreased; + + // + bool isVWapMinBreakedUp; + bool isVWapMaxBreakedUp; + + // + bool isVWapMinBreakedDown; + bool isVWapMaxBreakedDown; + + // + bool isClosedOverVWapMin; + bool isClosedUnderVWapMin; + + // + bool isClosedOverVWapMax; + bool isClosedUnderVWapMax; + + // + bool isVWapFastCrossedOverMid; + bool isVWapFastCrossedUnderMid; + + // + bool isVWapFastCrossedOverSlow; + bool isVWapFastCrossedUnderSlow; + + // + bool isBreakedUpPrevSar; + bool isBreakedDownPrevSar; + + // + bool isBreakedUpPrevStr; + bool isBreakedDownPrevStr; + + // + bool isBreakedUpPrevAtrUpper; + bool isBreakedDownPrevAtrUpper; + + // + bool isBreakedUpPrevAtrLower; + bool isBreakedDownPrevAtrLower; + + // + bool isRejectedUpPrevAtrUpper; + bool isRejectedDownPrevAtrUpper; + + // + bool isRejectedUpPrevAtrLower; + bool isRejectedDownPrevAtrLower; + + // + bool isSarEqualsToPeak; + bool isSarEqualsToVale; + + // + bool isSarCrossedUnderPeak; + bool isSarCrossedOverVale; + + // + bool isStrEqualsToPeak; + bool isStrEqualsToVale; + + // + bool isStrCrossedUnderPeak; + bool isStrCrossedOverVale; + + // + bool isPeakOverAtrUpper; + bool isValeUnderAtrLower; + + // + bool isNewPeakOverAtrUpper; + bool isNewValeUnderAtrLower; + + // + bool isStrUpperOverPeak; + bool isStrUpperUnderPeak; + + // + bool isStrUpperCrossedOverPeak; + bool isStrUpperCrossedUnderPeak; + + // + bool isStrLowerOverVale; + bool isStrLowerUnderVale; + + // + bool isStrLowerCrossedOverVale; + bool isStrLowerCrossedUnderVale; + + // + bool isDonHighUpperEqualsToPeak; + bool isDonLowLowerEqualsToVale; + + // + bool isStrUpperOverAtrUpper; + bool isStrUpperUnderAtrUpper; + + // + bool isStrLowerOverAtrLower; + bool isStrLowerUnderAtrLower; + + // + bool isStrUpperCrossedOverAtrUpper; + bool isStrUpperCrossedUnderAtrUpper; + + // + bool isStrLowerCrossedOverAtrLower; + bool isStrLowerCrossedUnderAtrLower; + + // + bool isStrUpperOverDonHighUpper; + bool isStrUpperUnderDonHighUpper; + + // + bool isStrLowerOverDonLowLower; + bool isStrLowerUnderDonLowLower; + + // + bool isStrUpperCrossedOverDonHighUpper; + bool isStrUpperCrossedUnderDonHighUpper; + + // + bool isStrLowerCrossedOverDonLowLower; + bool isStrLowerCrossedUnderDonLowLower; + + // + bool isAtrUpperOverPeak; + bool isAtrUpperEqualsToPeak; + bool isAtrUpperCrossedUpPeak; + bool isAtrUpperCrossedDownPeak; + + // + bool isAtrLowerUnderVale; + bool isAtrLowerEqualsToVale; + bool isAtrLowerCrossedUpVale; + bool isAtrLowerCrossedDownVale; + + // + // Constructor ... + X121Conditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(rsiBuffer); + Clean(atrBuffer); + Clean(strBuffer); + Clean(le1Buffer); + Clean(se1Buffer); + Clean(le2Buffer); + Clean(se2Buffer); + Clean(sarBuffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(strUpBuffer); + Clean(volumeBuffer); + Clean(strDownBuffer); + Clean(vwapMidBuffer); + Clean(le1StartBuffer); + Clean(se1StartBuffer); + Clean(le2StartBuffer); + Clean(se2StartBuffer); + Clean(strPriceBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(strStateBuffer); + Clean(vwapFastBuffer); + Clean(vwapSlowBuffer); + Clean(vwapPriceBuffer); + Clean(vwapVolumeBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(vwapMidStateBuffer); + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapSlowStateBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + + // + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(le1Buffer, true); + ArraySetAsSeries(se1Buffer, true); + ArraySetAsSeries(le2Buffer, true); + ArraySetAsSeries(se2Buffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(strUpBuffer, true); + ArraySetAsSeries(volumeBuffer, true); + ArraySetAsSeries(strDownBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(le1StartBuffer, true); + ArraySetAsSeries(se1StartBuffer, true); + ArraySetAsSeries(le2StartBuffer, true); + ArraySetAsSeries(se2StartBuffer, true); + ArraySetAsSeries(strPriceBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + + // + cheMin = 0; + cheMax = 0; + vwapMin = 0; + vwapMax = 0; + + // + // Slopes ... + + rsiSlope = 0; + strSlope = 0; + atrUpperSlope = 0; + atrLowerSlope = 0; + vwapFastSlope = 0; + vwapMidSlope = 0; + vwapSlowSlope = 0; + + // + // Conditions ... + + // + isRsiSlopeBullish = false; + isStrSlopeBullish = false; + isAtrUpperSlopeBullish = false; + isAtrLowerSlopeBullish = false; + isVwapFastSlopeBullish = false; + isVwapMidSlopeBullish = false; + isVwapSlowSlopeBullish = false; + + // + isRsiSlopeBearish = false; + isStrSlopeBearish = false; + isAtrUpperSlopeBearish = false; + isAtrLowerSlopeBearish = false; + isVwapFastSlopeBearish = false; + isVwapMidSlopeBearish = false; + isVwapSlowSlopeBearish = false; + + // + // RSI ... + + // + isRsiOverBought = false; + isRsiCrossedOverOverBought = false; + isRsiCrossedUnderOverBought = false; + + // + isRsiOverSold = false; + isRsiCrossedUnderOverSold = false; + isRsiCrossedOverOverSold = false; + + // + // ATR ... + + // + isClosedOverAtrUpper = false; + isClosedOverAtrLower = false; + + // + isClosedUnderAtrUpper = false; + isClosedUnderAtrLower = false; + + // + isRejectedUpAtrUpper = false; + isRejectedDownAtrUpper = false; + + // + isRejectedUpAtrLower = false; + isRejectedDownAtrLower = false; + + // + isBreakedUpAtrUpper = false; + isBreakedDownAtrUpper = false; + + // + isBreakedUpAtrLower = false; + isBreakedDownAtrLower = false; + + // + // DON ... + + // + isRejectedDonOpenUpper = false; + isRejectedDonHighUpper = false; + isRejectedDonLowUpper = false; + isRejectedDonCloseUpper = false; + + // + isRejectedDonOpenLower = false; + isRejectedDonHighLower = false; + isRejectedDonLowLower = false; + isRejectedDonCloseLower = false; + + // + isBreakedDonOpenUpper = false; + isBreakedDonHighUpper = false; + isBreakedDonLowUpper = false; + isBreakedDonCloseUpper = false; + + // + isBreakedDonOpenLower = false; + isBreakedDonHighLower = false; + isBreakedDonLowLower = false; + isBreakedDonCloseLower = false; + + // + // SAR ... + + // + isSarBullish = false; + isSarBearish = false; + + // + isSarSwitchedToBullish = false; + isSarSwitchedToBearish = false; + + // + // PV ... + + // + isNewPeak = false; + isNewPeakOverLast = false; + isNewPeakUnderLast = false; + isRejectedPrevPeak = false; + isBreakedUpPrevPeak = false; + + // + isNewVale = false; + isNewValeOverLast = false; + isNewValeUnderLast = false; + isRejectedPrevVale = false; + isBreakedDownPrevVale = false; + + // + // STR ... + + // + isStrBullish = false; + isStrBearish = false; + + // + isStrSwitchedToBullish = false; + isStrSwitchedToBearish = false; + + // + // VWAP ... + + // + isVWapFastBullish = false; + isVWapFastBearish = false; + isVWapFastNeutural = false; + + // + isVWapMidBullish = false; + isVWapMidBearish = false; + isVWapMidNeutural = false; + + // + isVWapSlowBullish = false; + isVWapSlowBearish = false; + isVWapSlowNeutural = false; + + // + isVWapFastOverMid = false; + isVWapMidOverSlow = false; + + // + isVWapFastUnderMid = false; + isVWapMidUnderSlow = false; + + // + isVWapBullishState = false; + isVWapBearishState = false; + isVWapNeuturalState = false; + + // + isVWapBullishOrdered = false; + isVWapBearishOrdered = false; + + // + isVWapSwitchedToBullishState = false; + isVWapSwitchedToBearishState = false; + + // + isVWapSwitchedToNeuturalState = false; + isVWapSwitchedToBullishOrdered = false; + isVWapSwitchedToBearishOrdered = false; + + // + // CHE ... + + // + isChe1Bullish = false; + isChe1Bearish = false; + + // + isChe1SwitchedToBullish = false; + isChe1SwitchedToBearish = false; + + // + isChe2Bullish = false; + isChe2Bearish = false; + + // + isChe2SwitchedToBullish = false; + isChe2SwitchedToBearish = false; + + // + isCheBullish = false; + isCheBearish = false; + + // + isCheSwitchedToBullish = false; + isCheSwitchedToBearish = false; + + // + isClosedOverCheMin = false; + isClosedOverCheMax = false; + + // + isClosedUnderCheMin = false; + isClosedUnderCheMax = false; + + // + // Complex Conditions ... + + // + isVWapMinBreakedUp = false; + isVWapMaxBreakedUp = false; + + // + isVWapMinBreakedDown = false; + isVWapMaxBreakedDown = false; + + // + isClosedOverVWapMin = false; + isClosedUnderVWapMin = false; + + // + isClosedOverVWapMax = false; + isClosedUnderVWapMax = false; + + // + isVWapFastCrossedOverMid = false; + isVWapFastCrossedUnderMid = false; + + // + isVWapFastCrossedOverSlow = false; + isVWapFastCrossedUnderSlow = false; + + // + isBreakedUpPrevSar = false; + isBreakedDownPrevSar = false; + + // + isBreakedUpPrevStr = false; + isBreakedDownPrevStr = false; + + // + isBreakedUpPrevAtrUpper = false; + isBreakedDownPrevAtrUpper = false; + + // + isRejectedUpPrevAtrUpper = false; + isRejectedDownPrevAtrUpper = false; + + // + isBreakedUpPrevAtrLower = false; + isBreakedDownPrevAtrLower = false; + + // + isRejectedUpPrevAtrLower = false; + isRejectedDownPrevAtrLower = false; + + // + isBreakedUpPrevCheMin = false; + isBreakedUpPrevCheMax = false; + isBreakedDownPrevCheMin = false; + isBreakedDownPrevCheMax = false; + isBreakedUpPrevCheLE1 = false; + isBreakedUpPrevCheLE2 = false; + isBreakedUpPrevCheSE1 = false; + isBreakedUpPrevCheSE2 = false; + isBreakedDownPrevCheLE1 = false; + isBreakedDownPrevCheLE2 = false; + isBreakedDownPrevCheSE1 = false; + isBreakedDownPrevCheSE2 = false; + + // + isSarIncreased = false; + isSarDecreased = false; + + // + isSarEqualsToPeak = false; + isSarEqualsToVale = false; + + // + isSarCrossedUnderPeak = false; + isSarCrossedOverVale = false; + + // + isStrEqualsToPeak = false; + isStrEqualsToVale = false; + + // + isStrCrossedUnderPeak = false; + isStrCrossedOverVale = false; + + // + isPeakOverAtrUpper = false; + isValeUnderAtrLower = false; + + // + isNewPeakOverAtrUpper = false; + isNewValeUnderAtrLower = false; + + // + isStrUpperOverPeak = false; + isStrUpperUnderPeak = false; + + // + isStrUpperCrossedOverPeak = false; + isStrUpperCrossedUnderPeak = false; + + // + isStrLowerOverVale = false; + isStrLowerUnderVale = false; + + // + isAtrUpperOverPeak = false; + isAtrUpperEqualsToPeak = false; + isAtrUpperCrossedUpPeak = false; + isAtrUpperCrossedDownPeak = false; + + // + isAtrLowerUnderVale = false; + isAtrLowerEqualsToVale = false; + isAtrLowerCrossedUpVale = false; + isAtrLowerCrossedDownVale = false; + + // + isStrLowerCrossedOverVale = false; + isStrLowerCrossedUnderVale = false; + + // + isDonHighUpperEqualsToPeak = false; + isDonLowLowerEqualsToVale = false; + + // + isStrUpperOverAtrUpper = false; + isStrUpperUnderAtrUpper = false; + + // + isStrLowerOverAtrLower = false; + isStrLowerUnderAtrLower = false; + + // + isStrUpperCrossedOverAtrUpper = false; + isStrUpperCrossedUnderAtrUpper = false; + + // + isStrLowerCrossedOverAtrLower = false; + isStrLowerCrossedUnderAtrLower = false; + + // + isStrUpperOverDonHighUpper = false; + isStrUpperUnderDonHighUpper = false; + + // + isStrLowerOverDonLowLower = false; + isStrLowerUnderDonLowLower = false; + + // + isStrUpperCrossedOverDonHighUpper = false; + isStrUpperCrossedUnderDonHighUpper = false; + + // + isStrLowerCrossedOverDonLowLower = false; + isStrLowerCrossedUnderDonLowLower = false; + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + "-----------------------" + separator + + "SAR ..." + separator + + "-----------------------" + separator + + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + + ToString("isSarBearish", isSarBearish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBullish", isSarSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBearish", isSarSwitchedToBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "STR ..." + separator + + "-----------------------" + separator + + ToString("isStrBullish", isStrBullish, ignoreFalseConditions, separator) + + ToString("isStrBearish", isStrBearish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBullish", isStrSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBearish", isStrSwitchedToBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "PV ..." + separator + + "-----------------------" + separator + + ToString("isNewPeak", isNewPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverLast", isNewPeakOverLast, ignoreFalseConditions, separator) + + ToString("isNewPeakUnderLast", isNewPeakUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevPeak", isRejectedPrevPeak, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevPeak", isBreakedUpPrevPeak, ignoreFalseConditions, separator) + + ToString("isNewVale", isNewVale, ignoreFalseConditions, separator) + + ToString("isNewValeOverLast", isNewValeOverLast, ignoreFalseConditions, separator) + + ToString("isNewValeUnderLast", isNewValeUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevVale", isRejectedPrevVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevVale", isBreakedDownPrevVale, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "> RSI ..." + separator + + "-----------------------" + separator + + ToString("isRsiOverBought", isRsiOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverBought", isRsiCrossedOverOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverBought", isRsiCrossedUnderOverBought, ignoreFalseConditions, separator) + + ToString("isRsiOverSold", isRsiOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverSold", isRsiCrossedUnderOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverSold", isRsiCrossedOverOverSold, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "ATR ..." + separator + + "-----------------------" + separator + + ToString("isClosedOverAtrUpper", isClosedOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedOverAtrLower", isClosedOverAtrLower, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrUpper", isClosedUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrLower", isClosedUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrUpper", isRejectedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrUpper", isRejectedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrLower", isRejectedUpAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrLower", isRejectedDownAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrUpper", isBreakedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDownAtrUpper", isBreakedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrLower", isBreakedUpAtrLower, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "DON ..." + separator + + "-----------------------" + separator + + ToString("isBreakedDownAtrLower", isBreakedDownAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonOpenUpper", isRejectedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighUpper", isRejectedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowUpper", isRejectedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseUpper", isRejectedDonCloseUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonOpenLower", isRejectedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighLower", isRejectedDonHighLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowLower", isRejectedDonLowLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseLower", isRejectedDonCloseLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonOpenUpper", isBreakedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighUpper", isBreakedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowUpper", isBreakedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseUpper", isBreakedDonCloseUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonOpenLower", isBreakedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighLower", isBreakedDonHighLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowLower", isBreakedDonLowLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseLower", isBreakedDonCloseLower, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "VWAP ..." + separator + + "-----------------------" + separator + + ToString("isVWapFastBullish", isVWapFastBullish, ignoreFalseConditions, separator) + + ToString("isVWapFastBearish", isVWapFastBearish, ignoreFalseConditions, separator) + + ToString("isVWapFastNeutural", isVWapFastNeutural, ignoreFalseConditions, separator) + + ToString("isVWapMidBullish", isVWapMidBullish, ignoreFalseConditions, separator) + + ToString("isVWapMidBearish", isVWapMidBearish, ignoreFalseConditions, separator) + + ToString("isVWapMidNeutural", isVWapMidNeutural, ignoreFalseConditions, separator) + + ToString("isVWapSlowBullish", isVWapSlowBullish, ignoreFalseConditions, separator) + + ToString("isVWapSlowBearish", isVWapSlowBearish, ignoreFalseConditions, separator) + + ToString("isVWapSlowNeutural", isVWapSlowNeutural, ignoreFalseConditions, separator) + + ToString("isVWapFastOverMid", isVWapFastOverMid, ignoreFalseConditions, separator) + + ToString("isVWapMidOverSlow", isVWapMidOverSlow, ignoreFalseConditions, separator) + + ToString("isVWapFastUnderMid", isVWapFastUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapMidUnderSlow", isVWapMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isVWapBullishState", isVWapBullishState, ignoreFalseConditions, separator) + + ToString("isVWapBearishState", isVWapBearishState, ignoreFalseConditions, separator) + + ToString("isVWapNeuturalState", isVWapNeuturalState, ignoreFalseConditions, separator) + + ToString("isVWapBullishOrdered", isVWapBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapBearishOrdered", isVWapBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishOrdered", isVWapSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishOrdered", isVWapSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishState", isVWapSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishState", isVWapSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToNeuturalState", isVWapSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "CHE ..." + separator + + "-----------------------" + separator + + ToString("isChe1Bullish", isChe1Bullish, ignoreFalseConditions, separator) + + ToString("isChe1Bearish", isChe1Bearish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBullish", isChe1SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBearish", isChe1SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isChe2Bullish", isChe2Bullish, ignoreFalseConditions, separator) + + ToString("isChe2Bearish", isChe2Bearish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBullish", isChe2SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBearish", isChe2SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isCheBullish", isCheBullish, ignoreFalseConditions, separator) + + ToString("isCheBearish", isCheBearish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBullish", isCheSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBearish", isCheSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMin", isClosedOverCheMin, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMax", isClosedOverCheMax, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMin", isClosedUnderCheMin, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMax", isClosedUnderCheMax, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "Slopes ..." + separator + + "-----------------------" + separator + + ToString("isRsiSlopeBullish", isRsiSlopeBullish, ignoreFalseConditions, separator) + + ToString("isStrSlopeBullish", isStrSlopeBullish, ignoreFalseConditions, separator) + + ToString("isAtrUpperSlopeBullish", isAtrUpperSlopeBullish, ignoreFalseConditions, separator) + + ToString("isAtrLowerSlopeBullish", isAtrLowerSlopeBullish, ignoreFalseConditions, separator) + + ToString("isVwapFastSlopeBullish", isVwapFastSlopeBullish, ignoreFalseConditions, separator) + + ToString("isVwapMidSlopeBullish", isVwapMidSlopeBullish, ignoreFalseConditions, separator) + + ToString("isVwapSlowSlopeBullish", isVwapSlowSlopeBullish, ignoreFalseConditions, separator) + + ToString("isRsiSlopeBearish", isRsiSlopeBearish, ignoreFalseConditions, separator) + + ToString("isStrSlopeBearish", isStrSlopeBearish, ignoreFalseConditions, separator) + + ToString("isAtrUpperSlopeBearish", isAtrUpperSlopeBearish, ignoreFalseConditions, separator) + + ToString("isAtrLowerSlopeBearish", isAtrLowerSlopeBearish, ignoreFalseConditions, separator) + + ToString("isVwapFastSlopeBearish", isVwapFastSlopeBearish, ignoreFalseConditions, separator) + + ToString("isVwapMidSlopeBearish", isVwapMidSlopeBearish, ignoreFalseConditions, separator) + + ToString("isVwapSlowSlopeBearish", isVwapSlowSlopeBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + + "Coplex ..." + separator + + "-----------------------" + separator + + ToString("isSarIncreased", isSarIncreased, ignoreFalseConditions, separator) + + ToString("isSarDecreased", isSarDecreased, ignoreFalseConditions, separator) + + ToString("isSarEqualsToPeak", isSarEqualsToPeak, ignoreFalseConditions, separator) + + + ToString("isStrEqualsToPeak", isStrEqualsToPeak, ignoreFalseConditions, separator) + + ToString("isStrEqualsToVale", isStrEqualsToVale, ignoreFalseConditions, separator) + + ToString("isPeakOverAtrUpper", isPeakOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevSar", isBreakedUpPrevSar, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevStr", isBreakedUpPrevStr, ignoreFalseConditions, separator) + + ToString("isVWapMinBreakedUp", isVWapMinBreakedUp, ignoreFalseConditions, separator) + + ToString("isVWapMaxBreakedUp", isVWapMaxBreakedUp, ignoreFalseConditions, separator) + + ToString("isStrUpperOverPeak", isStrUpperOverPeak, ignoreFalseConditions, separator) + + ToString("isStrLowerOverVale", isStrLowerOverVale, ignoreFalseConditions, separator) + + ToString("isAtrUpperOverPeak", isAtrUpperOverPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerUnderVale", isAtrLowerUnderVale, ignoreFalseConditions, separator) + + ToString("isClosedOverVWapMin", isClosedOverVWapMin, ignoreFalseConditions, separator) + + ToString("isClosedOverVWapMax", isClosedOverVWapMax, ignoreFalseConditions, separator) + + ToString("isStrUpperUnderPeak", isStrUpperUnderPeak, ignoreFalseConditions, separator) + + ToString("isValeUnderAtrLower", isValeUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isStrLowerUnderVale", isStrLowerUnderVale, ignoreFalseConditions, separator) + + ToString("isVWapMinBreakedDown", isVWapMinBreakedDown, ignoreFalseConditions, separator) + + ToString("isVWapMaxBreakedDown", isVWapMaxBreakedDown, ignoreFalseConditions, separator) + + ToString("isClosedUnderVWapMin", isClosedUnderVWapMin, ignoreFalseConditions, separator) + + ToString("isClosedUnderVWapMax", isClosedUnderVWapMax, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevSar", isBreakedDownPrevSar, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevStr", isBreakedDownPrevStr, ignoreFalseConditions, separator) + + ToString("isSarCrossedOverVale", isSarCrossedOverVale, ignoreFalseConditions, separator) + + ToString("isStrCrossedOverVale", isStrCrossedOverVale, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheLE1", isBreakedUpPrevCheLE1, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheLE2", isBreakedUpPrevCheLE2, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheSE1", isBreakedUpPrevCheSE1, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheSE2", isBreakedUpPrevCheSE2, ignoreFalseConditions, separator) + + ToString("isSarCrossedUnderPeak", isSarCrossedUnderPeak, ignoreFalseConditions, separator) + + ToString("isStrCrossedUnderPeak", isStrCrossedUnderPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverAtrUpper", isNewPeakOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheMin", isBreakedUpPrevCheMin, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevCheMax", isBreakedUpPrevCheMax, ignoreFalseConditions, separator) + + ToString("isNewValeUnderAtrLower", isNewValeUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isStrUpperOverAtrUpper", isStrUpperOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerOverAtrLower", isStrLowerOverAtrLower, ignoreFalseConditions, separator) + + ToString("isAtrUpperEqualsToPeak", isAtrUpperEqualsToPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerEqualsToVale", isAtrLowerEqualsToVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheMin", isBreakedDownPrevCheMin, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheMax", isBreakedDownPrevCheMax, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheLE1", isBreakedDownPrevCheLE1, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheLE2", isBreakedDownPrevCheLE2, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheSE1", isBreakedDownPrevCheSE1, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevCheSE2", isBreakedDownPrevCheSE2, ignoreFalseConditions, separator) + + ToString("isAtrUpperCrossedUpPeak", isAtrUpperCrossedUpPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerCrossedUpVale", isAtrLowerCrossedUpVale, ignoreFalseConditions, separator) + + ToString("isStrUpperUnderAtrUpper", isStrUpperUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerUnderAtrLower", isStrLowerUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevAtrUpper", isBreakedUpPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevAtrLower", isBreakedUpPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedOverMid", isVWapFastCrossedOverMid, ignoreFalseConditions, separator) + + ToString("isRejectedUpPrevAtrUpper", isRejectedUpPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedUpPrevAtrLower", isRejectedUpPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isAtrUpperCrossedDownPeak", isAtrUpperCrossedDownPeak, ignoreFalseConditions, separator) + + ToString("isAtrLowerCrossedDownVale", isAtrLowerCrossedDownVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevAtrUpper", isBreakedDownPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevAtrLower", isBreakedDownPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedUnderMid", isVWapFastCrossedUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedOverSlow", isVWapFastCrossedOverSlow, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedOverPeak", isStrUpperCrossedOverPeak, ignoreFalseConditions, separator) + + ToString("isStrLowerOverDonLowLower", isStrLowerOverDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedOverVale", isStrLowerCrossedOverVale, ignoreFalseConditions, separator) + + ToString("isDonLowLowerEqualsToVale", isDonLowLowerEqualsToVale, ignoreFalseConditions, separator) + + ToString("isRejectedDownPrevAtrUpper", isRejectedDownPrevAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDownPrevAtrLower", isRejectedDownPrevAtrLower, ignoreFalseConditions, separator) + + ToString("isVWapFastCrossedUnderSlow", isVWapFastCrossedUnderSlow, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedUnderPeak", isStrUpperCrossedUnderPeak, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedUnderVale", isStrLowerCrossedUnderVale, ignoreFalseConditions, separator) + + ToString("isDonHighUpperEqualsToPeak", isDonHighUpperEqualsToPeak, ignoreFalseConditions, separator) + + ToString("isStrUpperOverDonHighUpper", isStrUpperOverDonHighUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerUnderDonLowLower", isStrLowerUnderDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrUpperUnderDonHighUpper", isStrUpperUnderDonHighUpper, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedOverAtrUpper", isStrUpperCrossedOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedOverAtrLower", isStrLowerCrossedOverAtrLower, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedUnderAtrUpper", isStrUpperCrossedUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedUnderAtrLower", isStrLowerCrossedUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedOverDonLowLower", isStrLowerCrossedOverDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedOverDonHighUpper", isStrUpperCrossedOverDonHighUpper, ignoreFalseConditions, separator) + + ToString("isStrLowerCrossedUnderDonLowLower", isStrLowerCrossedUnderDonLowLower, ignoreFalseConditions, separator) + + ToString("isStrUpperCrossedUnderDonHighUpper", isStrUpperCrossedUnderDonHighUpper, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Implementation ... +class XCX121Helper : public XCBase +{ + // + public: + // + + // + // Helpers ... + XCX121XPVHelper *xpvHelper; + XCX121XATRHelper *xatrHelper; + XCX121XSTRHelper *xstrHelper; + XCX121XCHEHelper *xcheHelper; + XCX121XDONHelper *xdonHelper; + XCX121XVWAPHelper *xvwapHelper; + + // + // Constructors ... + XCX121Helper() + { + } + + // + // Deconstructor ... + ~XCX121Helper() + { + // + delete xpvHelper; + delete xatrHelper; + delete xstrHelper; + delete xcheHelper; + delete xdonHelper; + delete xvwapHelper; + } + + // + string GetSymbol() + { + return mSymbol; + } + + // + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Tools ... + + /** + * Initialize Indicator Helper ... + * + * @param symbol: String, Symbol ... + * @param period: ENUM_TIMEFRAMES member, Period ... + * @param inputs: X121Inputs instance, Indicator Inputs ... + * + * @return ( bool ) + */ + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121Inputs &inputs // Inputs + ) + { + // + bool result = false; + + // + result = + IsValid(symbol) && + IsValid(period) && + inputs.IsValid(); + if (!result) + { + return result; + } + + // + mSymbol = symbol; + mPeriod = period; + + // + // Setting Inputs ... + + // + mInputs = inputs; + xpvInputs = inputs.xpvInputs; + xatrInputs = inputs.xatrInputs; + xstrInputs = inputs.xstrInputs; + xcheInputs = inputs.xcheInputs; + xdonInputs = inputs.xdonInputs; + xvwapInputs = inputs.xvwapInputs; + + // + // Initial Helpers ... + + // + // XPV ... + xpvHelper = new XCX121XPVHelper(); + result = xpvHelper.Init( + symbol, + period, + xpvInputs // + ); + if (!result) + { + return result; + } + + // + // XATR ... + xatrHelper = new XCX121XATRHelper(); + result = xatrHelper.Init( + symbol, + period, + xatrInputs // + ); + if (!result) + { + return result; + } + + // + // XSTR ... + xstrHelper = new XCX121XSTRHelper(); + result = xstrHelper.Init( + symbol, + period, + xstrInputs // + ); + if (!result) + { + return result; + } + + // + // XCHE ... + xcheHelper = new XCX121XCHEHelper(); + result = xcheHelper.Init( + symbol, + period, + xcheInputs // + ); + if (!result) + { + return result; + } + + // + // XDON ... + xdonHelper = new XCX121XDONHelper(); + result = xdonHelper.Init( + symbol, + period, + xdonInputs // + ); + if (!result) + { + return result; + } + + // + // XVWAP ... + xvwapHelper = new XCX121XVWAPHelper(); + result = xvwapHelper.Init( + symbol, + period, + xvwapInputs // + ); + if (!result) + { + return result; + } + + // + if (inputs.showRSI) + { + // + mRSIHandler = iRSI( + symbol, + period, + xatrInputs.rsiLength, + xatrInputs.rsiAppliedTo // + ); + + // + result = mRSIHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Conditions Readers ... + + // + // XPV ... + bool GetPVConditions( + X121XPVConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xpvHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XATR ... + bool GetATRConditions( + X121XATRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xatrHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XSTR ... + bool GetSTRConditions( + X121XSTRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xstrHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XCHE ... + bool GetCHEConditions( + X121XCHEConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xcheHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XDON ... + bool GetDONConditions( + X121XDONConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xdonHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + // XVWAP ... + bool GetVWAPConditions( + X121XVWAPConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = false; + + // + result = xvwapHelper.GetConditions( + conditions, + barIndex, + loopback // + ); + + // + return result; + } + + // + bool GetConditions( + X121Conditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // XPV ... + X121XPVConditions xpvConditions; + result = GetPVConditions( + xpvConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XATR ... + X121XATRConditions xatrConditions; + result = GetATRConditions( + xatrConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XSTR ... + X121XSTRConditions xstrConditions; + result = GetSTRConditions( + xstrConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XCHE ... + X121XCHEConditions xcheConditions; + result = GetCHEConditions( + xcheConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XDON ... + X121XDONConditions xdonConditions; + result = GetDONConditions( + xdonConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // XVWAP ... + X121XVWAPConditions xvwapConditions; + result = GetVWAPConditions( + xvwapConditions, + barIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Fill Volume Buffer ... + for (int i = barIndex; i < barIndex + loopback; i++) + { + // + // Reading Bar Valuem ... + long iVol = iVolume( + mSymbol, + mPeriod, + i // + ); + + // + Add( + iVol, + conditions.volumeBuffer // + ); + } + + // + // Fill X121 Conditions Reference by Using + // Retrieved Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // XPV ... + + // + // Buffers ... + + // + Copy( + xpvConditions.peaksBuffer, + conditions.peaksBuffer // + ); + + // + Copy( + xpvConditions.valesBuffer, + conditions.valesBuffer // + ); + + // + Copy( + xpvConditions.sarBuffer, + conditions.sarBuffer // + ); + + // + Copy( + xpvConditions.cHHBuffer, + conditions.cHHBuffer // + ); + + // + Copy( + xpvConditions.cLLBuffer, + conditions.cLLBuffer // + ); + + // + Copy( + xpvConditions.sHHBuffer, + conditions.sHHBuffer // + ); + + // + Copy( + xpvConditions.sLLBuffer, + conditions.sLLBuffer // + ); + + // + Copy( + xpvConditions.mHHBuffer, + conditions.mHHBuffer // + ); + + // + Copy( + xpvConditions.mLLBuffer, + conditions.mLLBuffer // + ); + + // + Copy( + xpvConditions.lHHBuffer, + conditions.lHHBuffer // + ); + + // + Copy( + xpvConditions.lLLBuffer, + conditions.lLLBuffer // + ); + + // + Copy( + xpvConditions.hHHBuffer, + conditions.hHHBuffer // + ); + + // + Copy( + xpvConditions.hLLBuffer, + conditions.hLLBuffer // + ); + + // + // Conditions ... + + // + conditions.isNewPeak = xpvConditions.isNewPeak; + conditions.isNewVale = xpvConditions.isNewVale; + conditions.isSarBullish = xpvConditions.isSarBullish; + conditions.isSarBearish = xpvConditions.isSarBearish; + conditions.isNewPeakOverLast = xpvConditions.isNewPeakOverLast; + conditions.isNewValeOverLast = xpvConditions.isNewValeOverLast; + conditions.isNewPeakUnderLast = xpvConditions.isNewPeakUnderLast; + conditions.isNewValeUnderLast = xpvConditions.isNewValeUnderLast; + conditions.isRejectedPrevVale = xpvConditions.isRejectedPrevVale; + conditions.isRejectedPrevPeak = xpvConditions.isRejectedPrevPeak; + conditions.isBreakedUpPrevPeak = xpvConditions.isBreakedUpPrevPeak; + conditions.isBreakedDownPrevVale = xpvConditions.isBreakedDownPrevVale; + conditions.isSarSwitchedToBullish = xpvConditions.isSarSwitchedToBullish; + conditions.isSarSwitchedToBearish = xpvConditions.isSarSwitchedToBearish; + + // + // XATR ... + + // + // Buffers ... + + // + Copy( + xatrConditions.atrUpperBuffer, + conditions.atrUpperBuffer // + ); + + // + Copy( + xatrConditions.atrLowerBuffer, + conditions.atrLowerBuffer // + ); + + // + Copy( + xatrConditions.atrUpperRawBuffer, + conditions.atrUpperRawBuffer // + ); + + // + Copy( + xatrConditions.atrLowerRawBuffer, + conditions.atrLowerRawBuffer // + ); + + // + Copy( + xatrConditions.atrBuffer, + conditions.atrBuffer // + ); + + // + Copy( + xatrConditions.rsiBuffer, + conditions.rsiBuffer // + ); + + // + // Conditions ... + + // + conditions.isRsiOverSold = xatrConditions.isRsiOverSold; + conditions.isRsiOverBought = xatrConditions.isRsiOverBought; + conditions.isBreakedUpAtrUpper = xatrConditions.isBreakedUpAtrUpper; + conditions.isBreakedUpAtrLower = xatrConditions.isBreakedUpAtrLower; + conditions.isClosedOverAtrUpper = xatrConditions.isClosedOverAtrUpper; + conditions.isRejectedUpAtrUpper = xatrConditions.isRejectedUpAtrUpper; + conditions.isRejectedUpAtrLower = xatrConditions.isRejectedUpAtrLower; + conditions.isClosedOverAtrLower = xatrConditions.isClosedOverAtrLower; + conditions.isBreakedDownAtrUpper = xatrConditions.isBreakedDownAtrUpper; + conditions.isBreakedDownAtrLower = xatrConditions.isBreakedDownAtrLower; + conditions.isClosedUnderAtrUpper = xatrConditions.isClosedUnderAtrUpper; + conditions.isClosedUnderAtrLower = xatrConditions.isClosedUnderAtrLower; + conditions.isRejectedDownAtrUpper = xatrConditions.isRejectedDownAtrUpper; + conditions.isRejectedDownAtrLower = xatrConditions.isRejectedDownAtrLower; + conditions.isRsiCrossedOverOverSold = xatrConditions.isRsiCrossedOverOverSold; + conditions.isRsiCrossedUnderOverSold = xatrConditions.isRsiCrossedUnderOverSold; + conditions.isRsiCrossedOverOverBought = xatrConditions.isRsiCrossedOverOverBought; + conditions.isRsiCrossedUnderOverBought = xatrConditions.isRsiCrossedUnderOverBought; + + // + // XSTR ... + + // + // Buffers ... + + // + Copy( + xstrConditions.strBuffer, + conditions.strBuffer // + ); + + // + Copy( + xstrConditions.strPriceBuffer, + conditions.strPriceBuffer // + ); + + // + Copy( + xstrConditions.strUpBuffer, + conditions.strUpBuffer // + ); + + // + Copy( + xstrConditions.strDownBuffer, + conditions.strDownBuffer // + ); + + // + Copy( + xstrConditions.strStateBuffer, + conditions.strStateBuffer // + ); + + // + // Conditions ... + + // + conditions.isStrBullish = xstrConditions.isStrBullish; + conditions.isStrBearish = xstrConditions.isStrBearish; + conditions.isStrSwitchedToBullish = xstrConditions.isStrSwitchedToBullish; + conditions.isStrSwitchedToBearish = xstrConditions.isStrSwitchedToBearish; + + // + // XCHE ... + + // + // Buffers ... + + // + Copy( + xcheConditions.le1Buffer, + conditions.le1Buffer // + ); + + // + Copy( + xcheConditions.se1Buffer, + conditions.se1Buffer // + ); + + // + Copy( + xcheConditions.le2Buffer, + conditions.le2Buffer // + ); + + // + Copy( + xcheConditions.se2Buffer, + conditions.se2Buffer // + ); + + // + Copy( + xcheConditions.le1StartBuffer, + conditions.le1StartBuffer // + ); + + // + Copy( + xcheConditions.se1StartBuffer, + conditions.se1StartBuffer // + ); + + // + Copy( + xcheConditions.le2StartBuffer, + conditions.le2StartBuffer // + ); + + // + Copy( + xcheConditions.se2StartBuffer, + conditions.se2StartBuffer // + ); + + // + // Conditions ... + + conditions.isCheBullish = xcheConditions.isCheBullish; + conditions.isCheBearish = xcheConditions.isCheBearish; + conditions.isChe1Bullish = xcheConditions.isChe1Bullish; + conditions.isChe1Bearish = xcheConditions.isChe1Bearish; + conditions.isChe2Bullish = xcheConditions.isChe2Bullish; + conditions.isChe2Bearish = xcheConditions.isChe2Bearish; + conditions.isClosedOverCheMin = xcheConditions.isClosedOverCheMin; + conditions.isClosedOverCheMax = xcheConditions.isClosedOverCheMax; + conditions.isClosedUnderCheMin = xcheConditions.isClosedUnderCheMin; + conditions.isClosedUnderCheMax = xcheConditions.isClosedUnderCheMax; + conditions.isCheSwitchedToBullish = xcheConditions.isCheSwitchedToBullish; + conditions.isCheSwitchedToBearish = xcheConditions.isCheSwitchedToBearish; + conditions.isChe1SwitchedToBullish = xcheConditions.isChe1SwitchedToBullish; + conditions.isChe1SwitchedToBearish = xcheConditions.isChe1SwitchedToBearish; + conditions.isChe2SwitchedToBullish = xcheConditions.isChe2SwitchedToBullish; + conditions.isChe2SwitchedToBearish = xcheConditions.isChe2SwitchedToBearish; + + // + // XDON ... + + // + // Buffers ... + + // + Copy( + xdonConditions.donOpenUpperBuffer, + conditions.donOpenUpperBuffer // + ); + + // + Copy( + xdonConditions.donOpenLowerBuffer, + conditions.donOpenLowerBuffer // + ); + + // + Copy( + xdonConditions.donHighUpperBuffer, + conditions.donHighUpperBuffer // + ); + + // + Copy( + xdonConditions.donHighLowerBuffer, + conditions.donHighLowerBuffer // + ); + + // + Copy( + xdonConditions.donLowUpperBuffer, + conditions.donLowUpperBuffer // + ); + + // + Copy( + xdonConditions.donLowLowerBuffer, + conditions.donLowLowerBuffer // + ); + + // + Copy( + xdonConditions.donCloseUpperBuffer, + conditions.donCloseUpperBuffer // + ); + + // + Copy( + xdonConditions.donCloseLowerBuffer, + conditions.donCloseLowerBuffer // + ); + + // + // Conditions ... + + // + conditions.isBreakedDonLowUpper = xdonConditions.isBreakedDonLowUpper; + conditions.isBreakedDonLowLower = xdonConditions.isBreakedDonLowLower; + conditions.isRejectedDonLowUpper = xdonConditions.isRejectedDonLowUpper; + conditions.isRejectedDonLowLower = xdonConditions.isRejectedDonLowLower; + conditions.isBreakedDonOpenUpper = xdonConditions.isBreakedDonOpenUpper; + conditions.isBreakedDonHighUpper = xdonConditions.isBreakedDonHighUpper; + conditions.isBreakedDonOpenLower = xdonConditions.isBreakedDonOpenLower; + conditions.isBreakedDonHighLower = xdonConditions.isBreakedDonHighLower; + conditions.isRejectedDonOpenUpper = xdonConditions.isRejectedDonOpenUpper; + conditions.isRejectedDonHighUpper = xdonConditions.isRejectedDonHighUpper; + conditions.isRejectedDonOpenLower = xdonConditions.isRejectedDonOpenLower; + conditions.isRejectedDonHighLower = xdonConditions.isRejectedDonHighLower; + conditions.isBreakedDonCloseUpper = xdonConditions.isBreakedDonCloseUpper; + conditions.isBreakedDonCloseLower = xdonConditions.isBreakedDonCloseLower; + conditions.isRejectedDonCloseUpper = xdonConditions.isRejectedDonCloseUpper; + conditions.isRejectedDonCloseLower = xdonConditions.isRejectedDonCloseLower; + + // + // XVWAP ... + + // + // Buffers ... + + // + Copy( + xvwapConditions.vwapFastBuffer, + conditions.vwapFastBuffer // + ); + + // + Copy( + xvwapConditions.vwapMidBuffer, + conditions.vwapMidBuffer // + ); + + // + Copy( + xvwapConditions.vwapSlowBuffer, + conditions.vwapSlowBuffer // + ); + + // + Copy( + xvwapConditions.vwapVolumeBuffer, + conditions.vwapVolumeBuffer // + ); + + // + Copy( + xvwapConditions.vwapPriceBuffer, + conditions.vwapPriceBuffer // + ); + + // + Copy( + xvwapConditions.vwapFastStateBuffer, + conditions.vwapFastStateBuffer // + ); + + // + Copy( + xvwapConditions.vwapMidStateBuffer, + conditions.vwapMidStateBuffer // + ); + + // + Copy( + xvwapConditions.vwapSlowStateBuffer, + conditions.vwapSlowStateBuffer // + ); + + // + // Conditions ... + + // + conditions.isVWapMidBullish = xvwapConditions.isVWapMidBullish; + conditions.isVWapMidBearish = xvwapConditions.isVWapMidBearish; + conditions.isVWapFastBullish = xvwapConditions.isVWapFastBullish; + conditions.isVWapFastBearish = xvwapConditions.isVWapFastBearish; + conditions.isVWapMidNeutural = xvwapConditions.isVWapMidNeutural; + conditions.isVWapSlowBullish = xvwapConditions.isVWapSlowBullish; + conditions.isVWapSlowBearish = xvwapConditions.isVWapSlowBearish; + conditions.isVWapFastOverMid = xvwapConditions.isVWapFastOverMid; + conditions.isVWapMidOverSlow = xvwapConditions.isVWapMidOverSlow; + conditions.isVWapFastNeutural = xvwapConditions.isVWapFastNeutural; + conditions.isVWapSlowNeutural = xvwapConditions.isVWapSlowNeutural; + conditions.isVWapFastUnderMid = xvwapConditions.isVWapFastUnderMid; + conditions.isVWapMidUnderSlow = xvwapConditions.isVWapMidUnderSlow; + conditions.isVWapBullishState = xvwapConditions.isVWapBullishState; + conditions.isVWapBearishState = xvwapConditions.isVWapBearishState; + conditions.isVWapNeuturalState = xvwapConditions.isVWapNeuturalState; + conditions.isVWapBullishOrdered = xvwapConditions.isVWapBullishOrdered; + conditions.isVWapBearishOrdered = xvwapConditions.isVWapBearishOrdered; + conditions.isVWapSwitchedToBullishState = xvwapConditions.isVWapSwitchedToBullishState; + conditions.isVWapSwitchedToBearishState = xvwapConditions.isVWapSwitchedToBearishState; + conditions.isVWapSwitchedToNeuturalState = xvwapConditions.isVWapSwitchedToNeuturalState; + conditions.isVWapSwitchedToBullishOrdered = xvwapConditions.isVWapSwitchedToBullishOrdered; + conditions.isVWapSwitchedToBearishOrdered = xvwapConditions.isVWapSwitchedToBearishOrdered; + + // + // Slopes ... + + // + double rsiSlope = GetSlope(conditions.rsiBuffer, pIDX, cIDX); + double strSlope = GetSlope(conditions.strBuffer, pIDX, cIDX); + double atrUpperSlope = GetSlope(conditions.atrUpperBuffer, pIDX, cIDX); + double atrLowerSlope = GetSlope(conditions.atrLowerBuffer, pIDX, cIDX); + double vwapFastSlope = GetSlope(conditions.vwapFastBuffer, pIDX, cIDX); + double vwapMidSlope = GetSlope(conditions.vwapMidBuffer, pIDX, cIDX); + double vwapSlowSlope = GetSlope(conditions.vwapSlowBuffer, pIDX, cIDX); + + // + bool isRsiSlopeBullish = rsiSlope > 0; + bool isStrSlopeBullish = strSlope > 0; + bool isAtrUpperSlopeBullish = atrUpperSlope > 0; + bool isAtrLowerSlopeBullish = atrLowerSlope > 0; + bool isVwapFastSlopeBullish = vwapFastSlope > 0; + bool isVwapMidSlopeBullish = vwapMidSlope > 0; + bool isVwapSlowSlopeBullish = vwapSlowSlope > 0; + + // + bool isRsiSlopeBearish = rsiSlope < 0; + bool isStrSlopeBearish = strSlope < 0; + bool isAtrUpperSlopeBearish = atrUpperSlope < 0; + bool isAtrLowerSlopeBearish = atrLowerSlope < 0; + bool isVwapFastSlopeBearish = vwapFastSlope < 0; + bool isVwapMidSlopeBearish = vwapMidSlope < 0; + bool isVwapSlowSlopeBearish = vwapSlowSlope < 0; + + // + conditions.rsiSlope = rsiSlope; + conditions.strSlope = strSlope; + conditions.vwapMidSlope = vwapMidSlope; + conditions.vwapSlowSlope = vwapSlowSlope; + conditions.atrUpperSlope = atrUpperSlope; + conditions.atrLowerSlope = atrLowerSlope; + conditions.vwapFastSlope = vwapFastSlope; + conditions.isRsiSlopeBearish = isRsiSlopeBearish; + conditions.isStrSlopeBearish = isStrSlopeBearish; + conditions.isRsiSlopeBullish = isRsiSlopeBullish; + conditions.isStrSlopeBullish = isStrSlopeBullish; + conditions.isVwapMidSlopeBearish = isVwapMidSlopeBearish; + conditions.isVwapMidSlopeBullish = isVwapMidSlopeBullish; + conditions.isAtrUpperSlopeBearish = isAtrUpperSlopeBearish; + conditions.isAtrLowerSlopeBearish = isAtrLowerSlopeBearish; + conditions.isVwapFastSlopeBearish = isVwapFastSlopeBearish; + conditions.isVwapSlowSlopeBearish = isVwapSlowSlopeBearish; + conditions.isAtrUpperSlopeBullish = isAtrUpperSlopeBullish; + conditions.isAtrLowerSlopeBullish = isAtrLowerSlopeBullish; + conditions.isVwapFastSlopeBullish = isVwapFastSlopeBullish; + conditions.isVwapSlowSlopeBullish = isVwapSlowSlopeBullish; + + // + // Complex Conditions ... + + // + double vwapFast = conditions.vwapFastBuffer[cIDX]; + double vwapMid = conditions.vwapMidBuffer[cIDX]; + double vwapSlow = conditions.vwapSlowBuffer[cIDX]; + + // + double vwaps[3] = { + vwapFast, + vwapMid, + vwapSlow // + }; + + // + double vwapMin = GetMin(vwaps); + double vwapMax = GetMax(vwaps); + + // + bool isVWapMinBreakedUp = IsBarBreak( + vwapMin, + X_DIRECTION_BULLISH, + cBar // + ); + bool isVWapMinBreakedDown = IsBarBreak( + vwapMin, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isVWapMaxBreakedUp = IsBarBreak( + vwapMax, + X_DIRECTION_BULLISH, + cBar // + ); + bool isVWapMaxBreakedDown = IsBarBreak( + vwapMax, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isVWapFatsOverMid = conditions.vwapFastBuffer[cIDX] > conditions.vwapMidBuffer[cIDX]; + bool isVWapFatsOverMidPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapFatsUnderMid = conditions.vwapFastBuffer[cIDX] < conditions.vwapMidBuffer[cIDX]; + bool isVWapFatsUnderMidPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapFatsOverSlow = conditions.vwapFastBuffer[cIDX] > conditions.vwapSlowBuffer[cIDX]; + bool isVWapFatsOverSlowPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFatsUnderSlow = conditions.vwapFastBuffer[cIDX] < conditions.vwapSlowBuffer[cIDX]; + bool isVWapFatsUnderSlowPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFastCrossedOverMid = isVWapFatsOverMid && + !isVWapFatsOverMidPrev; + bool isVWapFastCrossedUnderMid = isVWapFatsUnderMid && + !isVWapFatsUnderMidPrev; + + // + bool isVWapFastCrossedOverSlow = isVWapFatsOverSlow && + !isVWapFatsOverSlowPrev; + bool isVWapFastCrossedUnderSlow = isVWapFatsUnderSlow && + !isVWapFatsUnderSlowPrev; + + // + bool isClosedOverVWapMin = cBar.close > vwapMin; + bool isClosedUnderVWapMin = cBar.close < vwapMin; + + // + bool isClosedOverVWapMax = cBar.close > vwapMax; + bool isClosedUnderVWapMax = cBar.close < vwapMax; + + // + bool isSarEqualsToPeak = + conditions.sarBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + bool isSarEqualsToVale = + conditions.sarBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isSarIncreased = conditions.sarBuffer[cIDX] > conditions.sarBuffer[pIDX]; + bool isSarDecreased = conditions.sarBuffer[cIDX] < conditions.sarBuffer[pIDX]; + + // + double prevSar = conditions.sarBuffer[pIDX]; + double prevStr = conditions.strBuffer[pIDX]; + double prevCheLE1 = conditions.le1Buffer[pIDX]; + double prevCheLE2 = conditions.le2Buffer[pIDX]; + double prevCheSE1 = conditions.se1Buffer[pIDX]; + double prevCheSE2 = conditions.se2Buffer[pIDX]; + double prevAtrUpper = conditions.atrUpperBuffer[pIDX]; + double prevAtrLower = conditions.atrLowerBuffer[pIDX]; + + // + double ches[]; + if (prevCheLE1 != EMPTY_VALUE) + { + // + Add( + prevCheLE1, + ches // + ); + } + if (prevCheLE2 != EMPTY_VALUE) + { + // + Add( + prevCheLE2, + ches // + ); + } + if (prevCheSE1 != EMPTY_VALUE) + { + // + Add( + prevCheSE1, + ches // + ); + } + if (prevCheSE2 != EMPTY_VALUE) + { + // + Add( + prevCheSE2, + ches // + ); + } + + // + double cheMin = GetMin(ches); + double cheMax = GetMax(ches); + + // + bool isBreakedUpPrevSar = IsBarBreak( + prevSar, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevSar = IsBarBreak( + prevSar, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevStr = IsBarBreak( + prevStr, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevStr = IsBarBreak( + prevStr, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedUpPrevAtrUpper = IsBarReject( + prevAtrUpper, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isRejectedDownPrevAtrUpper = IsBarReject( + prevAtrUpper, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedUpPrevAtrLower = IsBarReject( + prevAtrLower, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isRejectedDownPrevAtrLower = IsBarReject( + prevAtrLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevAtrUpper = IsBarBreak( + prevAtrUpper, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevAtrUpper = IsBarBreak( + prevAtrUpper, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevAtrLower = IsBarBreak( + prevAtrLower, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevAtrLower = IsBarBreak( + prevAtrLower, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevCheLE1 = IsBarBreak( + prevCheLE1, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpPrevCheLE2 = IsBarBreak( + prevCheLE2, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpPrevCheSE1 = IsBarBreak( + prevCheSE1, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedUpPrevCheSE2 = IsBarBreak( + prevCheSE2, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isBreakedDownPrevCheLE1 = IsBarBreak( + prevCheLE1, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownPrevCheLE2 = IsBarBreak( + prevCheLE2, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownPrevCheSE1 = IsBarBreak( + prevCheSE1, + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDownPrevCheSE2 = IsBarBreak( + prevCheSE2, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevCheMin = IsBarBreak( + cheMin, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevCheMin = IsBarBreak( + cheMin, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpPrevCheMax = IsBarBreak( + cheMax, + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevCheMax = IsBarBreak( + cheMax, + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isSarCrossedUnderPeak = + conditions.sarBuffer[cIDX] < conditions.peaksBuffer[cIDX] && + !(conditions.sarBuffer[pIDX] < conditions.peaksBuffer[pIDX]); + bool isSarCrossedOverVale = + conditions.sarBuffer[cIDX] > conditions.valesBuffer[cIDX] && + !(conditions.sarBuffer[pIDX] > conditions.valesBuffer[pIDX]); + + // + bool isStrEqualsToPeak = + conditions.strBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + bool isStrEqualsToVale = + conditions.strBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isStrCrossedUnderPeak = + conditions.strBuffer[cIDX] < conditions.peaksBuffer[cIDX] && + !(conditions.strBuffer[pIDX] < conditions.peaksBuffer[pIDX]); + bool isStrCrossedOverVale = + conditions.strBuffer[cIDX] > conditions.valesBuffer[cIDX] && + !(conditions.strBuffer[pIDX] > conditions.valesBuffer[pIDX]); + + // + bool isPeakOverAtrUpper = + conditions.peaksBuffer[cIDX] > conditions.atrUpperBuffer[cIDX]; + bool isValeUnderAtrLower = + conditions.valesBuffer[cIDX] > conditions.atrLowerBuffer[cIDX]; + + // + bool isNewPeakOverAtrUpper = + isPeakOverAtrUpper && + conditions.isNewPeak; + bool isNewValeUnderAtrLower = + isValeUnderAtrLower && + conditions.isNewVale; + + // + bool isStrUpperOverPeak = + conditions.strBuffer[cIDX] > conditions.peaksBuffer[cIDX]; + bool isStrUpperOverPeakPrev = + conditions.strBuffer[pIDX] > conditions.peaksBuffer[pIDX]; + + // + bool isStrUpperUnderPeak = + conditions.strBuffer[cIDX] < conditions.peaksBuffer[cIDX]; + bool isStrUpperUnderPeakPrev = + conditions.strBuffer[pIDX] < conditions.peaksBuffer[pIDX]; + + // + bool isStrUpperCrossedOverPeak = isStrUpperOverPeak && + !isStrUpperOverPeakPrev; + bool isStrUpperCrossedUnderPeak = isStrUpperUnderPeak && + !isStrUpperUnderPeakPrev; + + // + bool isStrLowerOverVale = + conditions.strBuffer[cIDX] > conditions.valesBuffer[cIDX]; + bool isStrLowerOverValePrev = + conditions.strBuffer[pIDX] > conditions.valesBuffer[pIDX]; + + // + bool isStrLowerUnderVale = + conditions.strBuffer[cIDX] < conditions.valesBuffer[cIDX]; + bool isStrLowerUnderValePrev = + conditions.strBuffer[pIDX] < conditions.valesBuffer[pIDX]; + + // + bool isStrLowerCrossedOverVale = isStrLowerOverVale && + !isStrLowerOverValePrev; + bool isStrLowerCrossedUnderVale = isStrLowerUnderVale && + !isStrLowerUnderValePrev; + + // + bool isDonHighUpperEqualsToPeak = + conditions.donHighUpperBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + bool isDonLowLowerEqualsToVale = + conditions.donLowLowerBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isStrUpperOverAtrUpper = + conditions.strUpBuffer[cIDX] > conditions.atrUpperBuffer[cIDX]; + bool isStrUpperOverAtrUpperPrev = + conditions.strUpBuffer[pIDX] > conditions.atrUpperBuffer[pIDX]; + bool isStrUpperCrossedOverAtrUpper = isStrUpperOverAtrUpper && + !isStrUpperOverAtrUpperPrev; + + // + bool isStrUpperUnderAtrUpper = + conditions.strUpBuffer[cIDX] < conditions.atrUpperBuffer[cIDX]; + bool isStrUpperUnderAtrUpperPrev = + conditions.strUpBuffer[pIDX] < conditions.atrUpperBuffer[pIDX]; + bool isStrUpperCrossedUnderAtrUpper = isStrUpperUnderAtrUpper && + !isStrUpperUnderAtrUpperPrev; + + // + bool isStrLowerOverAtrLower = + conditions.strDownBuffer[cIDX] > conditions.atrLowerBuffer[cIDX]; + bool isStrLowerOverAtrLowerPrev = + conditions.strDownBuffer[pIDX] > conditions.atrLowerBuffer[pIDX]; + bool isStrLowerCrossedOverAtrLower = isStrLowerOverAtrLower && + !isStrLowerOverAtrLowerPrev; + + // + bool isStrLowerUnderAtrLower = + conditions.strDownBuffer[cIDX] < conditions.atrLowerBuffer[cIDX]; + bool isStrLowerUnderAtrLowerPrev = + conditions.strDownBuffer[pIDX] < conditions.atrLowerBuffer[pIDX]; + bool isStrLowerCrossedUnderAtrLower = isStrLowerUnderAtrLower && + !isStrLowerUnderAtrLowerPrev; + + // + bool isStrUpperOverDonHighUpper = + conditions.strUpBuffer[cIDX] > conditions.donHighUpperBuffer[cIDX]; + bool isStrUpperOverDonHighUpperPrev = + conditions.strUpBuffer[pIDX] > conditions.donHighUpperBuffer[pIDX]; + bool isStrUpperCrossedOverDonHighUpper = isStrUpperOverDonHighUpper && + !isStrUpperOverDonHighUpperPrev; + + // + bool isStrUpperUnderDonHighUpper = + conditions.strUpBuffer[cIDX] < conditions.donHighUpperBuffer[cIDX]; + bool isStrUpperUnderDonHighUpperPrev = + conditions.strUpBuffer[pIDX] < conditions.donHighUpperBuffer[pIDX]; + bool isStrUpperCrossedUnderDonHighUpper = isStrUpperUnderDonHighUpper && + !isStrUpperUnderDonHighUpperPrev; + + // + bool isStrLowerOverDonLowLower = + conditions.strDownBuffer[cIDX] > conditions.donLowLowerBuffer[cIDX]; + bool isStrLowerOverDonLowLowerPrev = + conditions.strDownBuffer[pIDX] > conditions.donLowLowerBuffer[pIDX]; + bool isStrLowerCrossedOverDonLowLower = isStrLowerOverDonLowLower && + !isStrLowerOverDonLowLowerPrev; + + // + bool isStrLowerUnderDonLowLower = + conditions.strDownBuffer[cIDX] < conditions.donLowLowerBuffer[cIDX]; + bool isStrLowerUnderDonLowLowerPrev = + conditions.strDownBuffer[pIDX] < conditions.donLowLowerBuffer[pIDX]; + bool isStrLowerCrossedUnderDonLowLower = isStrLowerUnderDonLowLower && + !isStrLowerUnderDonLowLowerPrev; + + // + bool isAtrUpperOverPeak = conditions.atrUpperBuffer[cIDX] > conditions.peaksBuffer[cIDX]; + bool isAtrUpperEqualsToPeak = conditions.atrUpperBuffer[cIDX] == conditions.peaksBuffer[cIDX]; + + // + bool isAtrUpperCrossedUpPeak = conditions.atrUpperBuffer[cIDX] > conditions.peaksBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] > conditions.peaksBuffer[cIDX]); + bool isAtrUpperCrossedDownPeak = conditions.atrUpperBuffer[cIDX] < conditions.peaksBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] < conditions.peaksBuffer[cIDX]); + + // + bool isAtrLowerUnderVale = conditions.atrUpperBuffer[cIDX] < conditions.valesBuffer[cIDX]; + bool isAtrLowerEqualsToVale = conditions.atrUpperBuffer[cIDX] == conditions.valesBuffer[cIDX]; + + // + bool isAtrLowerCrossedUpVale = conditions.atrUpperBuffer[cIDX] > conditions.valesBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] > conditions.valesBuffer[cIDX]); + bool isAtrLowerCrossedDownVale = conditions.atrUpperBuffer[cIDX] < conditions.valesBuffer[cIDX] && + !(conditions.atrUpperBuffer[cIDX] < conditions.valesBuffer[cIDX]); + + // + conditions.cheMin = cheMin; + conditions.cheMax = cheMax; + conditions.vwapMin = vwapMin; + conditions.vwapMax = vwapMax; + + // + conditions.isSarIncreased = isSarIncreased; + conditions.isSarDecreased = isSarDecreased; + conditions.isSarEqualsToPeak = isSarEqualsToPeak; + conditions.isSarEqualsToVale = isSarEqualsToVale; + conditions.isStrEqualsToPeak = isStrEqualsToPeak; + conditions.isStrEqualsToVale = isStrEqualsToVale; + conditions.isStrUpperOverPeak = isStrUpperOverPeak; + conditions.isPeakOverAtrUpper = isPeakOverAtrUpper; + conditions.isStrLowerOverVale = isStrLowerOverVale; + conditions.isVWapMinBreakedUp = isVWapMinBreakedUp; + conditions.isVWapMaxBreakedUp = isVWapMaxBreakedUp; + conditions.isBreakedUpPrevSar = isBreakedUpPrevSar; + conditions.isBreakedUpPrevStr = isBreakedUpPrevStr; + conditions.isAtrUpperOverPeak = isAtrUpperOverPeak; + conditions.isAtrLowerUnderVale = isAtrLowerUnderVale; + conditions.isStrLowerUnderVale = isStrLowerUnderVale; + conditions.isStrUpperUnderPeak = isStrUpperUnderPeak; + conditions.isValeUnderAtrLower = isValeUnderAtrLower; + conditions.isClosedOverVWapMin = isClosedOverVWapMin; + conditions.isClosedOverVWapMax = isClosedOverVWapMax; + conditions.isClosedUnderVWapMin = isClosedUnderVWapMin; + conditions.isClosedUnderVWapMax = isClosedUnderVWapMax; + conditions.isVWapMinBreakedDown = isVWapMinBreakedDown; + conditions.isVWapMaxBreakedDown = isVWapMaxBreakedDown; + conditions.isSarCrossedOverVale = isSarCrossedOverVale; + conditions.isStrCrossedOverVale = isStrCrossedOverVale; + conditions.isBreakedDownPrevStr = isBreakedDownPrevStr; + conditions.isBreakedDownPrevSar = isBreakedDownPrevSar; + conditions.isSarCrossedUnderPeak = isSarCrossedUnderPeak; + conditions.isStrCrossedUnderPeak = isStrCrossedUnderPeak; + conditions.isNewPeakOverAtrUpper = isNewPeakOverAtrUpper; + conditions.isBreakedUpPrevCheLE1 = isBreakedUpPrevCheLE1; + conditions.isBreakedUpPrevCheLE2 = isBreakedUpPrevCheLE2; + conditions.isBreakedUpPrevCheSE1 = isBreakedUpPrevCheSE1; + conditions.isBreakedUpPrevCheSE2 = isBreakedUpPrevCheSE2; + conditions.isBreakedUpPrevCheMin = isBreakedUpPrevCheMin; + conditions.isBreakedUpPrevCheMax = isBreakedUpPrevCheMax; + conditions.isAtrUpperEqualsToPeak = isAtrUpperEqualsToPeak; + conditions.isAtrLowerEqualsToVale = isAtrLowerEqualsToVale; + conditions.isNewValeUnderAtrLower = isNewValeUnderAtrLower; + conditions.isStrUpperOverAtrUpper = isStrUpperOverAtrUpper; + conditions.isStrLowerOverAtrLower = isStrLowerOverAtrLower; + conditions.isBreakedDownPrevCheMin = isBreakedDownPrevCheMin; + conditions.isBreakedDownPrevCheMax = isBreakedDownPrevCheMax; + conditions.isBreakedDownPrevCheLE1 = isBreakedDownPrevCheLE1; + conditions.isBreakedDownPrevCheLE2 = isBreakedDownPrevCheLE2; + conditions.isBreakedDownPrevCheSE1 = isBreakedDownPrevCheSE1; + conditions.isBreakedDownPrevCheSE2 = isBreakedDownPrevCheSE2; + conditions.isStrUpperUnderAtrUpper = isStrUpperUnderAtrUpper; + conditions.isStrLowerUnderAtrLower = isStrLowerUnderAtrLower; + conditions.isBreakedUpPrevAtrUpper = isBreakedUpPrevAtrUpper; + conditions.isBreakedUpPrevAtrLower = isBreakedUpPrevAtrLower; + conditions.isAtrUpperCrossedUpPeak = isAtrUpperCrossedUpPeak; + conditions.isAtrLowerCrossedUpVale = isAtrLowerCrossedUpVale; + conditions.isVWapFastCrossedOverMid = isVWapFastCrossedOverMid; + conditions.isRejectedUpPrevAtrUpper = isRejectedUpPrevAtrUpper; + conditions.isRejectedUpPrevAtrLower = isRejectedUpPrevAtrLower; + conditions.isAtrUpperCrossedDownPeak = isAtrUpperCrossedDownPeak; + conditions.isAtrLowerCrossedDownVale = isAtrLowerCrossedDownVale; + conditions.isBreakedDownPrevAtrUpper = isBreakedDownPrevAtrUpper; + conditions.isBreakedDownPrevAtrLower = isBreakedDownPrevAtrLower; + conditions.isVWapFastCrossedUnderMid = isVWapFastCrossedUnderMid; + conditions.isDonLowLowerEqualsToVale = isDonLowLowerEqualsToVale; + conditions.isStrUpperCrossedOverPeak = isStrUpperCrossedOverPeak; + conditions.isStrLowerCrossedOverVale = isStrLowerCrossedOverVale; + conditions.isStrLowerOverDonLowLower = isStrLowerOverDonLowLower; + conditions.isVWapFastCrossedOverSlow = isVWapFastCrossedOverSlow; + conditions.isRejectedDownPrevAtrUpper = isRejectedDownPrevAtrUpper; + conditions.isRejectedDownPrevAtrLower = isRejectedDownPrevAtrLower; + conditions.isVWapFastCrossedUnderSlow = isVWapFastCrossedUnderSlow; + conditions.isStrUpperOverDonHighUpper = isStrUpperOverDonHighUpper; + conditions.isStrLowerUnderDonLowLower = isStrLowerUnderDonLowLower; + conditions.isDonHighUpperEqualsToPeak = isDonHighUpperEqualsToPeak; + conditions.isStrUpperCrossedUnderPeak = isStrUpperCrossedUnderPeak; + conditions.isStrLowerCrossedUnderVale = isStrLowerCrossedUnderVale; + conditions.isStrUpperUnderDonHighUpper = isStrUpperUnderDonHighUpper; + conditions.isStrLowerCrossedOverAtrLower = isStrLowerCrossedOverAtrLower; + conditions.isStrUpperCrossedOverAtrUpper = isStrUpperCrossedOverAtrUpper; + conditions.isStrUpperCrossedUnderAtrUpper = isStrUpperCrossedUnderAtrUpper; + conditions.isStrLowerCrossedUnderAtrLower = isStrLowerCrossedUnderAtrLower; + conditions.isStrLowerCrossedOverDonLowLower = isStrLowerCrossedOverDonLowLower; + conditions.isStrUpperCrossedOverDonHighUpper = isStrUpperCrossedOverDonHighUpper; + conditions.isStrLowerCrossedUnderDonLowLower = isStrLowerCrossedUnderDonLowLower; + conditions.isStrUpperCrossedUnderDonHighUpper = isStrUpperCrossedUnderDonHighUpper; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + string mSymbol; // Trading Symbol + ENUM_TIMEFRAMES mPeriod; // Trading Period + + // + // Inputs ... + X121Inputs mInputs; + X121XPVInputs xpvInputs; + X121XATRInputs xatrInputs; + X121XDONInputs xdonInputs; + X121XSTRInputs xstrInputs; + X121XCHEInputs xcheInputs; + X121XVWAPInputs xvwapInputs; + + // + int mRSIHandler; +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.xatr.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.xatr.helper.mq5 new file mode 100644 index 0000000..8ee75d0 --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.xatr.helper.mq5 @@ -0,0 +1,1215 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XATRHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XATR_BUFFERS +{ + // + X121_ATR_UPPER_LINE = 0, + X121_ATR_LOWER_LINE = 1, + X121_ATR_LINE = 2, + X121_ATR_UPPER_RAW_LINE = 3, + X121_ATR_LOWER_RAW_LINE = 4, + X121_RSI_LINE = 5, +}; + +// +// Input Models ... +struct X121XATRInputs +{ + // + // Props ... + + // + // RSI ... + int rsiLength; // Length + double rsiOverSoldLevel; // Over Sold Level + double rsiOverBoughtLevel; // Over Bought Level + ENUM_APPLIED_PRICE rsiAppliedTo; // Applied To + + // + // ATR Detection ... + int atrLength; // Length + double atrMultiplier; // Multiplier + ENUM_APPLIED_PRICE atrUpperAppliedTo; // Upper Zone Applied To + ENUM_APPLIED_PRICE atrLowerAppliedTo; // Lower Zone Applied To + ENUM_X_MA_METHOD atrSmoothingMode; // Smoothing Method + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showATRUpper; // Show Upper Zone + bool showATRLower; // Show Lower Zone + + // + // Constructor(s) ... + X121XATRInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + // RSI ... + rsiLength = 0; + rsiOverSoldLevel = 0; + rsiOverBoughtLevel = 0; + rsiAppliedTo = PRICE_CLOSE; + + // + // ATR ... + atrLength = 0; // Length + atrMultiplier = 0; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_NONE; // Smoothing Method + + // + startCalculationForLastBars = 0; + + // + showATRUpper = false; // Show Upper Zone + showATRLower = false; // Show Lower Zone + } + + // + // Default ... + void Default() + { + // + // RSI ... + rsiLength = 14; + rsiOverSoldLevel = 30; + rsiOverBoughtLevel = 70; + rsiAppliedTo = PRICE_CLOSE; + + // + // ATR ... + atrLength = 14; // Length + atrMultiplier = 1; // Multiplier + atrUpperAppliedTo = PRICE_HIGH; // Upper Zone Applied To + atrLowerAppliedTo = PRICE_LOW; // Lower Zone Applied To + atrSmoothingMode = X_MA_MODE_EMA; // Smoothing Method + + // + startCalculationForLastBars = 1500; + showATRUpper = true; // Show Upper Zone + showATRLower = true; // Show Lower Zone + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + atrLength > 0 && + rsiLength > 0 && + atrMultiplier > 0 && + rsiOverSoldLevel > 0 && + rsiOverBoughtLevel > 0 && + startCalculationForLastBars > 0 && + rsiOverSoldLevel < rsiOverBoughtLevel + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(atrLength, rsiLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XATRConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + double rsiBuffer[]; + double atrBuffer[]; + + // + // Conditions ... + + // + // RSI ... + + // + bool isRsiOverBought; + bool isRsiCrossedOverOverBought; + bool isRsiCrossedUnderOverBought; + + // + bool isRsiOverSold; + bool isRsiCrossedUnderOverSold; + bool isRsiCrossedOverOverSold; + + // + // ATR ... + + // + bool isClosedOverAtrUpper; + bool isClosedOverAtrLower; + + // + bool isClosedUnderAtrUpper; + bool isClosedUnderAtrLower; + + // + bool isRejectedUpAtrUpper; + bool isRejectedDownAtrUpper; + + // + bool isRejectedUpAtrLower; + bool isRejectedDownAtrLower; + + // + bool isBreakedUpAtrUpper; + bool isBreakedDownAtrUpper; + + // + bool isBreakedUpAtrLower; + bool isBreakedDownAtrLower; + + // + // bool isCloseLower + + // + // Constructor ... + X121XATRConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(rsiBuffer); + Clean(atrBuffer); + Clean(atrUpperBuffer); + Clean(atrLowerBuffer); + Clean(atrUpperRawBuffer); + Clean(atrLowerRawBuffer); + + // + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + + // + // Conditions ... + + // + // RSI ... + + // + isRsiOverBought = false; + isRsiCrossedOverOverBought = false; + isRsiCrossedUnderOverBought = false; + + // + isRsiOverSold = false; + isRsiCrossedUnderOverSold = false; + isRsiCrossedOverOverSold = false; + + // + // ATR ... + + // + isClosedOverAtrUpper = false; + isClosedOverAtrLower = false; + + // + isClosedUnderAtrUpper = false; + isClosedUnderAtrLower = false; + + // + isRejectedUpAtrUpper = false; + isRejectedDownAtrUpper = false; + + // + isRejectedUpAtrLower = false; + isRejectedDownAtrLower = false; + + // + isBreakedUpAtrUpper = false; + isBreakedDownAtrUpper = false; + + // + isBreakedUpAtrLower = false; + isBreakedDownAtrLower = false; + + // + // XDON ... + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + // RSI ... + ToString("isRsiOverBought", isRsiOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverBought", isRsiCrossedOverOverBought, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverBought", isRsiCrossedUnderOverBought, ignoreFalseConditions, separator) + + ToString("isRsiOverSold", isRsiOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedUnderOverSold", isRsiCrossedUnderOverSold, ignoreFalseConditions, separator) + + ToString("isRsiCrossedOverOverSold", isRsiCrossedOverOverSold, ignoreFalseConditions, separator) + + // + // ATR ... + ToString("isClosedOverAtrUpper", isClosedOverAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedOverAtrLower", isClosedOverAtrLower, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrUpper", isClosedUnderAtrUpper, ignoreFalseConditions, separator) + + ToString("isClosedUnderAtrLower", isClosedUnderAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrUpper", isRejectedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrUpper", isRejectedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isRejectedUpAtrLower", isRejectedUpAtrLower, ignoreFalseConditions, separator) + + ToString("isRejectedDownAtrLower", isRejectedDownAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrUpper", isBreakedUpAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDownAtrUpper", isBreakedDownAtrUpper, ignoreFalseConditions, separator) + + ToString("isBreakedUpAtrLower", isBreakedUpAtrLower, ignoreFalseConditions, separator) + + ToString("isBreakedDownAtrLower", isBreakedDownAtrLower, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XATRHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XATRHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XATRHelper() + { + // + ArrayFree(rsiBuffer); + ArrayFree(atrUpperBuffer); + ArrayFree(atrLowerBuffer); + ArrayFree(atrBuffer); + ArrayFree(atrUpperRawBuffer); + ArrayFree(atrLowerRawBuffer); + + // + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XATRInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(atrUpperBuffer, true); + ArraySetAsSeries(atrLowerBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrUpperRawBuffer, true); + ArraySetAsSeries(atrLowerRawBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xatr", + // + // Inputs ... + // + // Market ... + "", + // + // RSI Detection ... + "", + mInputs.rsiLength, + mInputs.rsiAppliedTo, + // + // ATR Detection ... + "", + mInputs.atrLength, + mInputs.atrMultiplier, + mInputs.atrUpperAppliedTo, + mInputs.atrLowerAppliedTo, + mInputs.atrSmoothingMode, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + mInputs.showATRUpper, + mInputs.showATRLower + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XATRInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XATRInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // RSI ... + + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(rsiBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return rsiBuffer[barIndex]; + } + + // + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rsiBuffer, + buffer, + forceClean + // + ); + } + + // + // ATR ... + + // + double GetATR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrBuffer[barIndex]; + } + + // + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperBuffer[barIndex]; + } + + // + int CopyATRUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRUpperRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrUpperRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrUpperRawBuffer[barIndex]; + } + + // + int CopyATRUpperRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrUpperRawBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerBuffer[barIndex]; + } + + // + int CopyATRLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerBuffer, + buffer, + forceClean + // + ); + } + + // + double GetATRLowerRaw( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrLowerRawBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrLowerRawBuffer[barIndex]; + } + + // + int CopyATRLowerRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrLowerRawBuffer, + buffer, + forceClean + // + ); + } + + // + bool GetConditions( + X121XATRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyRSI( + zIndex, + loopback, + conditions.rsiBuffer // + ); + + // + CopyATR( + zIndex, + loopback, + conditions.atrBuffer // + ); + + // + CopyATRUpper( + zIndex, + loopback, + conditions.atrUpperBuffer // + ); + + // + CopyATRUpperRaw( + zIndex, + loopback, + conditions.atrUpperRawBuffer // + ); + + // + CopyATRLower( + zIndex, + loopback, + conditions.atrLowerBuffer // + ); + + // + CopyATRLowerRaw( + zIndex, + loopback, + conditions.atrLowerRawBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // RSI ... + + // + bool isRsiOverBought = conditions.rsiBuffer[cIDX] > mInputs.rsiOverBoughtLevel; + bool isRsiOverBoughtPrev = conditions.rsiBuffer[pIDX] > mInputs.rsiOverBoughtLevel; + + // + bool isRsiCrossedOverOverBought = isRsiOverBought && + !isRsiOverBoughtPrev; + bool isRsiCrossedUnderOverBought = !isRsiOverBought && + isRsiOverBoughtPrev; + + // + bool isRsiOverSold = conditions.rsiBuffer[cIDX] < mInputs.rsiOverSoldLevel; + bool isRsiOverSoldPrev = conditions.rsiBuffer[pIDX] < mInputs.rsiOverSoldLevel; + + // + bool isRsiCrossedUnderOverSold = isRsiOverSold && + !isRsiOverSoldPrev; + bool isRsiCrossedOverOverSold = !isRsiOverSold && + isRsiOverSoldPrev; + + // + // ATR ... + + // + bool isClosedOverAtrUpper = cBar.close > conditions.atrUpperBuffer[cIDX]; + bool isClosedOverAtrLower = cBar.close > conditions.atrLowerBuffer[cIDX]; + + // + bool isClosedUnderAtrUpper = cBar.close < conditions.atrUpperBuffer[cIDX]; + bool isClosedUnderAtrLower = cBar.close < conditions.atrLowerBuffer[cIDX]; + + // + bool isRejectedUpAtrUpper = IsBarReject( + atrUpperBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDownAtrUpper = IsBarReject( + atrUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedUpAtrLower = IsBarReject( + atrLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + ; + bool isRejectedDownAtrLower = IsBarReject( + atrLowerBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + ; + + // + bool isBreakedUpAtrUpper = IsBarBreak( + atrUpperBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownAtrUpper = IsBarBreak( + atrUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedUpAtrLower = IsBarBreak( + atrLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownAtrLower = IsBarBreak( + atrLowerBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + conditions.isRsiOverSold = isRsiOverSold; + conditions.isRsiOverBought = isRsiOverBought; + conditions.isRejectedUpAtrUpper = isRejectedUpAtrUpper; + conditions.isRejectedUpAtrLower = isRejectedUpAtrLower; + conditions.isBreakedUpAtrUpper = isBreakedUpAtrUpper; + conditions.isBreakedUpAtrLower = isBreakedUpAtrLower; + conditions.isRejectedDownAtrUpper = isRejectedDownAtrUpper; + conditions.isRejectedDownAtrLower = isRejectedDownAtrLower; + conditions.isClosedOverAtrUpper = isClosedOverAtrUpper; + conditions.isClosedOverAtrLower = isClosedOverAtrLower; + conditions.isBreakedDownAtrUpper = isBreakedDownAtrUpper; + conditions.isBreakedDownAtrLower = isBreakedDownAtrLower; + conditions.isClosedUnderAtrUpper = isClosedUnderAtrUpper; + conditions.isClosedUnderAtrLower = isClosedUnderAtrLower; + conditions.isRsiCrossedOverOverSold = isRsiCrossedOverOverSold; + conditions.isRsiCrossedUnderOverSold = isRsiCrossedUnderOverSold; + conditions.isRsiCrossedOverOverBought = isRsiCrossedOverOverBought; + conditions.isRsiCrossedUnderOverBought = isRsiCrossedUnderOverBought; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XATRInputs mInputs; // Inputs ... + + // + // Buffers ... + double rsiBuffer[]; + double atrUpperBuffer[]; + double atrLowerBuffer[]; + double atrBuffer[]; + double atrUpperRawBuffer[]; + double atrLowerRawBuffer[]; + + // + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // RSI ... + CopyBuffer( + mHandler, + X121_RSI_LINE, + 0, + totalBars, + rsiBuffer + // + ); + + // + // ATR ... + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_LINE, + 0, + totalBars, + atrUpperBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_LINE, + 0, + totalBars, + atrLowerBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LINE, + 0, + totalBars, + atrBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_UPPER_RAW_LINE, + 0, + totalBars, + atrUpperRawBuffer + // + ); + + // + CopyBuffer( + mHandler, + X121_ATR_LOWER_RAW_LINE, + 0, + totalBars, + atrLowerRawBuffer + // + ); + } +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.xche.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.xche.helper.mq5 new file mode 100644 index 0000000..cdb73c2 --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.xche.helper.mq5 @@ -0,0 +1,1314 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XCHEHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XCHE_BUFFERS +{ + // + X121_XCHE_LE_1_LINE = 0, + X121_XCHE_SE_1_LINE = 1, + X121_XCHE_LE_2_LINE = 2, + X121_XCHE_SE_2_LINE = 3, + X121_XCHE_LE_1_S_LINE = 4, + X121_XCHE_SE_1_S_LINE = 5, + X121_XCHE_LE_2_S_LINE = 6, + X121_XCHE_SE_2_S_LINE = 7, +}; + +// +// Input Models ... +struct X121XCHEInputs +{ + // + // Props ... + + int cheLength; // Length + int cheLoopback; // Loopback + double cheMultiplier1; // 1st Multiplier + double cheMultiplier2; // 2nd Multiplier + ENUM_APPLIED_PRICE cheUpperAppliedTo; // Upper Zone Applied to + ENUM_APPLIED_PRICE cheLowerAppliedTo; // Lower Zone Applied to + + // + int cheArrowCode; // CHE Arrow Code + + // + bool showLE1; // Show 1st Long Exit + bool showSE1; // Show 1st Short Exit + bool showLE2; // Show 2st Long Exit + bool showSE2; // Show 2st Short Exit + + // + // Constructor(s) ... + X121XCHEInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + cheLength = 0; + cheLoopback = 0; + cheMultiplier1 = 0; + cheMultiplier2 = 0; + cheUpperAppliedTo = PRICE_HIGH; + cheLowerAppliedTo = PRICE_LOW; + + // + cheArrowCode = 0; + + // + showLE1 = false; + showSE1 = false; + showLE2 = false; + showSE2 = false; + } + + // + // Default ... + void Default() + { + // + cheLength = 35; + cheLoopback = 26; + cheMultiplier1 = 3.0; + cheMultiplier2 = 3.5; + cheUpperAppliedTo = PRICE_HIGH; + cheLowerAppliedTo = PRICE_LOW; + + // + cheArrowCode = 159; + + // + showLE1 = true; + showSE1 = true; + showLE2 = true; + showSE2 = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = true; + + // + result = + cheLength >= 9 && + cheLoopback >= 0; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(cheLength, cheLoopback); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XCHEConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double le1Buffer[]; + double se1Buffer[]; + double le2Buffer[]; + double se2Buffer[]; + double le1StartBuffer[]; + double se1StartBuffer[]; + double le2StartBuffer[]; + double se2StartBuffer[]; + + // + // Conditions ... + + // + bool isChe1Bullish; + bool isChe1Bearish; + + // + bool isChe1SwitchedToBullish; + bool isChe1SwitchedToBearish; + + // + bool isChe2Bullish; + bool isChe2Bearish; + + // + bool isChe2SwitchedToBullish; + bool isChe2SwitchedToBearish; + + // + bool isCheBullish; + bool isCheBearish; + + // + bool isCheSwitchedToBullish; + bool isCheSwitchedToBearish; + + // + bool isClosedOverCheMin; + bool isClosedOverCheMax; + + // + bool isClosedUnderCheMin; + bool isClosedUnderCheMax; + + // + // Constructor ... + X121XCHEConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(le1Buffer); + Clean(se1Buffer); + Clean(le2Buffer); + Clean(se2Buffer); + Clean(le1StartBuffer); + Clean(se1StartBuffer); + Clean(le2StartBuffer); + Clean(se2StartBuffer); + + // + ArraySetAsSeries(le1Buffer, true); + ArraySetAsSeries(se1Buffer, true); + ArraySetAsSeries(le2Buffer, true); + ArraySetAsSeries(se2Buffer, true); + ArraySetAsSeries(le1StartBuffer, true); + ArraySetAsSeries(se1StartBuffer, true); + ArraySetAsSeries(le2StartBuffer, true); + ArraySetAsSeries(se2StartBuffer, true); + + // + // Conditions ... + + // + isChe1Bullish = false; + isChe1Bearish = false; + + // + isChe1SwitchedToBullish = false; + isChe1SwitchedToBearish = false; + + // + isChe2Bullish = false; + isChe2Bearish = false; + + // + isChe2SwitchedToBullish = false; + isChe2SwitchedToBearish = false; + + // + isCheBullish = false; + isCheBearish = false; + + // + isCheSwitchedToBullish = false; + isCheSwitchedToBearish = false; + + // + isClosedOverCheMin = false; + isClosedOverCheMax = false; + + // + isClosedUnderCheMin = false; + isClosedUnderCheMax = false; + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isChe1Bullish", isChe1Bullish, ignoreFalseConditions, separator) + + ToString("isChe1Bearish", isChe1Bearish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBullish", isChe1SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe1SwitchedToBearish", isChe1SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isChe2Bullish", isChe2Bullish, ignoreFalseConditions, separator) + + ToString("isChe2Bearish", isChe2Bearish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBullish", isChe2SwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isChe2SwitchedToBearish", isChe2SwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isCheBullish", isCheBullish, ignoreFalseConditions, separator) + + ToString("isCheBearish", isCheBearish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBullish", isCheSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isCheSwitchedToBearish", isCheSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMin", isClosedOverCheMin, ignoreFalseConditions, separator) + + ToString("isClosedOverCheMax", isClosedOverCheMax, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMin", isClosedUnderCheMin, ignoreFalseConditions, separator) + + ToString("isClosedUnderCheMax", isClosedUnderCheMax, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XCHEHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCHEHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCHEHelper() + { + // + mInputs.Clean(); + + // + ArrayFree(le1Buffer); + ArrayFree(se1Buffer); + ArrayFree(le2Buffer); + ArrayFree(se2Buffer); + ArrayFree(le1StartBuffer); + ArrayFree(se1StartBuffer); + ArrayFree(le2StartBuffer); + ArrayFree(se2StartBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCHEInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(le1Buffer, true); + ArraySetAsSeries(se1Buffer, true); + ArraySetAsSeries(le2Buffer, true); + ArraySetAsSeries(se2Buffer, true); + ArraySetAsSeries(le1StartBuffer, true); + ArraySetAsSeries(se1StartBuffer, true); + ArraySetAsSeries(le2StartBuffer, true); + ArraySetAsSeries(se2StartBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + mInputs.cheLength, + mInputs.cheLoopback, + mInputs.cheMultiplier1, + mInputs.cheMultiplier2, + mInputs.cheUpperAppliedTo, + mInputs.cheLowerAppliedTo, + // + // Presentation ... + "", + mInputs.cheArrowCode, + mInputs.showLE1, + mInputs.showSE1, + mInputs.showLE2, + mInputs.showSE2 + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCHEInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCHEInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + double GetLE1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le1Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le1Buffer[barIndex]; + } + + // + int CopyLE1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le1Buffer, + buffer, + forceClean + // + ); + } + + // + double GetLE1Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le1StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le1StartBuffer[barIndex]; + } + + // + int CopyLE1Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le1StartBuffer, + buffer, + forceClean + // + ); + } + + // + double GetLE2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le2Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le2Buffer[barIndex]; + } + + // + int CopyLE2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le2Buffer, + buffer, + forceClean + // + ); + } + + // + double GetLE2Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(le2StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return le2StartBuffer[barIndex]; + } + + // + int CopyLE2Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + le2StartBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSE1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se1Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se1Buffer[barIndex]; + } + + // + int CopySE1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se1Buffer, + buffer, + forceCsean + // + ); + } + + // + double GetSE1Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se1StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se1StartBuffer[barIndex]; + } + + // + int CopySE1Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se1StartBuffer, + buffer, + forceCsean + // + ); + } + + // + double GetSE2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se2Buffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se2Buffer[barIndex]; + } + + // + int CopySE2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se2Buffer, + buffer, + forceCsean + // + ); + } + + // + double GetSE2Start( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(se2StartBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return se2StartBuffer[barIndex]; + } + + // + int CopySE2Start( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceCsean = true // Force To Csean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + se2StartBuffer, + buffer, + forceCsean + // + ); + } + + // + bool GetConditions( + X121XCHEConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyLE1( + zIndex, + loopback, + conditions.le1Buffer // + ); + + // + CopySE1( + zIndex, + loopback, + conditions.se1Buffer // + ); + + // + CopyLE2( + zIndex, + loopback, + conditions.le2Buffer // + ); + + // + CopySE2( + zIndex, + loopback, + conditions.se2Buffer // + ); + + // + CopyLE1Start( + zIndex, + loopback, + conditions.le1StartBuffer // + ); + + // + CopySE1Start( + zIndex, + loopback, + conditions.se1StartBuffer // + ); + + // + CopyLE2Start( + zIndex, + loopback, + conditions.le2StartBuffer // + ); + + // + CopySE2Start( + zIndex, + loopback, + conditions.se2StartBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isChe1Bullish = le1Buffer[cIDX] != EMPTY_VALUE && + se1Buffer[cIDX] == EMPTY_VALUE; + bool isChe1BullishPrev = le1Buffer[cIDX] != EMPTY_VALUE && + se1Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe1Bearish = se1Buffer[cIDX] != EMPTY_VALUE && + le1Buffer[cIDX] == EMPTY_VALUE; + bool isChe1BearishPrev = se1Buffer[pIDX] != EMPTY_VALUE && + le1Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe1SwitchedToBullish = isChe1Bullish && + !isChe1BullishPrev; + bool isChe1SwitchedToBearish = isChe1Bearish && + !isChe1BearishPrev; + + // + bool isChe2Bullish = le2Buffer[cIDX] != EMPTY_VALUE && + se2Buffer[cIDX] == EMPTY_VALUE; + bool isChe2BullishPrev = le2Buffer[pIDX] != EMPTY_VALUE && + se2Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe2Bearish = se2Buffer[cIDX] != EMPTY_VALUE && + le2Buffer[cIDX] == EMPTY_VALUE; + bool isChe2BearishPrev = se2Buffer[pIDX] != EMPTY_VALUE && + le2Buffer[pIDX] == EMPTY_VALUE; + + // + bool isChe2SwitchedToBullish = isChe2Bullish && + !isChe2BullishPrev; + bool isChe2SwitchedToBearish = isChe2Bearish && + !isChe2BearishPrev; + + // + bool isCheBullish = isChe1Bullish && + isChe2Bullish; + bool isCheBullishPrev = isChe1BullishPrev && + isChe2BullishPrev; + + // + bool isCheBearish = isChe1Bearish && + isChe2Bearish; + bool isCheBearishPrev = isChe1BearishPrev && + isChe2BearishPrev; + + // + bool isCheSwitchedToBullish = isCheBullish && + !isCheBullishPrev; + bool isCheSwitchedToBearish = isCheBearish && + !isCheBearishPrev; + + // + double ches[]; + double prevCheLE1 = le1Buffer[pIDX]; + double prevCheLE2 = le2Buffer[pIDX]; + double prevCheSE1 = se1Buffer[pIDX]; + double prevCheSE2 = se2Buffer[pIDX]; + if (prevCheLE1 != EMPTY_VALUE) + { + // + Add( + prevCheLE1, + ches // + ); + } + if (prevCheLE2 != EMPTY_VALUE) + { + // + Add( + prevCheLE2, + ches // + ); + } + if (prevCheSE1 != EMPTY_VALUE) + { + // + Add( + prevCheSE1, + ches // + ); + } + if (prevCheSE2 != EMPTY_VALUE) + { + // + Add( + prevCheSE2, + ches // + ); + } + + // + double cheMin = GetMin(ches); + double cheMax = GetMax(ches); + + // + bool isClosedOverCheMin = cBar.close > cheMin; + bool isClosedOverCheMax = cBar.close > cheMax; + bool isClosedUnderCheMin = cBar.close < cheMin; + bool isClosedUnderCheMax = cBar.close < cheMax; + + // + conditions.isChe1Bullish = isChe1Bullish; + conditions.isChe1Bearish = isChe1Bearish; + conditions.isChe1SwitchedToBullish = isChe1SwitchedToBullish; + conditions.isChe1SwitchedToBearish = isChe1SwitchedToBearish; + conditions.isChe2Bullish = isChe2Bullish; + conditions.isChe2Bearish = isChe2Bearish; + conditions.isChe2SwitchedToBullish = isChe2SwitchedToBullish; + conditions.isChe2SwitchedToBearish = isChe2SwitchedToBearish; + conditions.isCheBullish = isCheBullish; + conditions.isCheBearish = isCheBearish; + conditions.isCheSwitchedToBullish = isCheSwitchedToBullish; + conditions.isCheSwitchedToBearish = isCheSwitchedToBearish; + conditions.isClosedOverCheMin = isClosedOverCheMin; + conditions.isClosedOverCheMax = isClosedOverCheMax; + conditions.isClosedUnderCheMin = isClosedUnderCheMin; + conditions.isClosedUnderCheMax = isClosedUnderCheMax; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCHEInputs mInputs; // Inputs ... + + // + // Buffers ... + double le1Buffer[]; + double se1Buffer[]; + double le2Buffer[]; + double se2Buffer[]; + double le1StartBuffer[]; + double se1StartBuffer[]; + double le2StartBuffer[]; + double se2StartBuffer[]; + + // + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // LE1 Start ... + CopyBuffer( + mHandler, + X121_XCHE_LE_1_S_LINE, + 0, + totalBars, + le1StartBuffer // + ); + + // + // LE1 ... + CopyBuffer( + mHandler, + X121_XCHE_LE_1_LINE, + 0, + totalBars, + le1Buffer // + ); + + // + // LE2 Start ... + CopyBuffer( + mHandler, + X121_XCHE_LE_2_S_LINE, + 0, + totalBars, + le2StartBuffer // + ); + + // + // LE2 ... + CopyBuffer( + mHandler, + X121_XCHE_LE_2_LINE, + 0, + totalBars, + le2Buffer // + ); + + // + // SE1 Start ... + CopyBuffer( + mHandler, + X121_XCHE_SE_1_S_LINE, + 0, + totalBars, + se1StartBuffer // + ); + + // + // SE1 ... + CopyBuffer( + mHandler, + X121_XCHE_SE_1_LINE, + 0, + totalBars, + se1Buffer // + ); + + // + // SE2 Start ... + CopyBuffer( + mHandler, + X121_XCHE_SE_2_S_LINE, + 0, + totalBars, + se2StartBuffer // + ); + + // + // SE2 ... + CopyBuffer( + mHandler, + X121_XCHE_SE_2_LINE, + 0, + totalBars, + se2Buffer // + ); + } +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.xdon.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.xdon.helper.mq5 new file mode 100644 index 0000000..d56bc3d --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.xdon.helper.mq5 @@ -0,0 +1,1337 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XDONHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XDON_BUFFERS +{ + // + X121_XDON_OPEN_UPPER_LINE = 0, + X121_XDON_OPEN_LOWER_LINE = 1, + X121_XDON_HIGH_UPPER_LINE = 2, + X121_XDON_HIGH_LOWER_LINE = 3, + X121_XDON_LOW_UPPER_LINE = 4, + X121_XDON_LOW_LOWER_LINE = 5, + X121_XDON_CLOSE_UPPER_LINE = 6, + X121_XDON_CLOSE_LOWER_LINE = 7, +}; + +// +// Input Models ... +struct X121XDONInputs +{ + // + // Props ... + + // + int donchainLength; // Donchain Length + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showUpper; // Show Upper Band + bool showLower; // Show Lower Band + + // + bool showOpen; // Show Open + bool showHigh; // Show High + bool showClose; // Show Close + bool showLow; // Show Low + + // + // Constructor(s) ... + X121XDONInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + donchainLength = 0; + + // + startCalculationForLastBars = 0; + + // + showUpper = false; + showLower = false; + + // + showOpen = false; + showHigh = false; + showClose = false; + showLow = false; + } + + // + // Default ... + void Default() + { + // + donchainLength = 40; + + // + startCalculationForLastBars = 1000; + + // + showUpper = true; + showLower = true; + + // + showOpen = true; + showHigh = true; + showClose = true; + showLow = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + donchainLength > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(1, donchainLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XDONConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + + // + // Conditions ... + + // + bool isRejectedDonOpenUpper; + bool isRejectedDonHighUpper; + bool isRejectedDonLowUpper; + bool isRejectedDonCloseUpper; + + // + bool isRejectedDonOpenLower; + bool isRejectedDonHighLower; + bool isRejectedDonLowLower; + bool isRejectedDonCloseLower; + + // + bool isBreakedDonOpenUpper; + bool isBreakedDonHighUpper; + bool isBreakedDonLowUpper; + bool isBreakedDonCloseUpper; + + // + bool isBreakedDonOpenLower; + bool isBreakedDonHighLower; + bool isBreakedDonLowLower; + bool isBreakedDonCloseLower; + + // + // Constructor ... + X121XDONConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(donOpenUpperBuffer); + Clean(donOpenLowerBuffer); + Clean(donHighUpperBuffer); + Clean(donHighLowerBuffer); + Clean(donLowUpperBuffer); + Clean(donLowLowerBuffer); + Clean(donCloseUpperBuffer); + Clean(donCloseLowerBuffer); + + // + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + + // + // Conditions ... + + // + isRejectedDonOpenUpper = false; + isRejectedDonHighUpper = false; + isRejectedDonLowUpper = false; + isRejectedDonCloseUpper = false; + + // + isRejectedDonOpenLower = false; + isRejectedDonHighLower = false; + isRejectedDonLowLower = false; + isRejectedDonCloseLower = false; + + // + isBreakedDonOpenUpper = false; + isBreakedDonHighUpper = false; + isBreakedDonLowUpper = false; + isBreakedDonCloseUpper = false; + + // + isBreakedDonOpenLower = false; + isBreakedDonHighLower = false; + isBreakedDonLowLower = false; + isBreakedDonCloseLower = false; + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isRejectedDonOpenUpper", isRejectedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighUpper", isRejectedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowUpper", isRejectedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseUpper", isRejectedDonCloseUpper, ignoreFalseConditions, separator) + + // + ToString("isRejectedDonOpenLower", isRejectedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonHighLower", isRejectedDonHighLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonLowLower", isRejectedDonLowLower, ignoreFalseConditions, separator) + + ToString("isRejectedDonCloseLower", isRejectedDonCloseLower, ignoreFalseConditions, separator) + + // + ToString("isBreakedDonOpenUpper", isBreakedDonOpenUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighUpper", isBreakedDonHighUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowUpper", isBreakedDonLowUpper, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseUpper", isBreakedDonCloseUpper, ignoreFalseConditions, separator) + + // + ToString("isBreakedDonOpenLower", isBreakedDonOpenLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonHighLower", isBreakedDonHighLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonLowLower", isBreakedDonLowLower, ignoreFalseConditions, separator) + + ToString("isBreakedDonCloseLower", isBreakedDonCloseLower, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XDONHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XDONHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XDONHelper() + { + // + mInputs.Clean(); + + // + ArrayFree(donOpenUpperBuffer); + ArrayFree(donOpenLowerBuffer); + ArrayFree(donHighUpperBuffer); + ArrayFree(donHighLowerBuffer); + ArrayFree(donLowUpperBuffer); + ArrayFree(donLowLowerBuffer); + ArrayFree(donCloseUpperBuffer); + ArrayFree(donCloseLowerBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XDONInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(donOpenUpperBuffer, true); + ArraySetAsSeries(donOpenLowerBuffer, true); + ArraySetAsSeries(donHighUpperBuffer, true); + ArraySetAsSeries(donHighLowerBuffer, true); + ArraySetAsSeries(donLowUpperBuffer, true); + ArraySetAsSeries(donLowLowerBuffer, true); + ArraySetAsSeries(donCloseUpperBuffer, true); + ArraySetAsSeries(donCloseLowerBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xdon", + // + // Inputs ... + // + // Market ... + "", + mInputs.donchainLength, + // + // Presentation ... + "", + mInputs.startCalculationForLastBars, + // + mInputs.showUpper, + mInputs.showLower, + // + mInputs.showOpen, + mInputs.showHigh, + mInputs.showClose, + mInputs.showLow + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XDONInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XDONInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // OPEN ... + + // + // UPPER ... + + // + double GetDonOpenUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenUpperBuffer[barIndex]; + } + + // + int CopyDonOpenUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonOpenLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donOpenLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donOpenLowerBuffer[barIndex]; + } + + // + int CopyDonOpenLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donOpenLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // CLOSE ... + + // + // UPPER ... + + // + double GetDonCloseUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseUpperBuffer[barIndex]; + } + + // + int CopyDonCloseUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonCloseLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donCloseLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donCloseLowerBuffer[barIndex]; + } + + // + int CopyDonCloseLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donCloseLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // HIGH ... + + // + // UPPER ... + + // + double GetDonHighUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighUpperBuffer[barIndex]; + } + + // + int CopyDonHighUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonHighLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donHighLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donHighLowerBuffer[barIndex]; + } + + // + int CopyDonHighLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donHighLowerBuffer, + buffer, + forceClean + // + ); + } + + // + // LOW ... + + // + // UPPER ... + + // + double GetDonLowUpper( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowUpperBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowUpperBuffer[barIndex]; + } + + // + int CopyDonLowUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowUpperBuffer, + buffer, + forceClean + // + ); + } + + // + // LOWER ... + + // + double GetDonLoweLower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(donLowLowerBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return donLowLowerBuffer[barIndex]; + } + + // + int CopyDonLoweLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + donLowLowerBuffer, + buffer, + forceClean + // + ); + } + + // + bool GetConditions( + X121XDONConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyDonOpenUpper( + zIndex, + loopback, + conditions.donOpenUpperBuffer // + ); + + // + CopyDonOpenLower( + zIndex, + loopback, + conditions.donOpenLowerBuffer // + ); + + // + CopyDonCloseUpper( + zIndex, + loopback, + conditions.donCloseUpperBuffer // + ); + + // + CopyDonCloseLower( + zIndex, + loopback, + conditions.donCloseLowerBuffer // + ); + + // + CopyDonHighUpper( + zIndex, + loopback, + conditions.donHighUpperBuffer // + ); + + // + CopyDonHighLower( + zIndex, + loopback, + conditions.donHighLowerBuffer // + ); + + // + CopyDonLowUpper( + zIndex, + loopback, + conditions.donLowUpperBuffer // + ); + + // + CopyDonLoweLower( + zIndex, + loopback, + conditions.donLowLowerBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isRejectedDonOpenUpper = IsBarReject( + donOpenUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDonHighUpper = IsBarReject( + donHighUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDonLowUpper = IsBarReject( + donLowUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isRejectedDonCloseUpper = IsBarReject( + donCloseUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isRejectedDonOpenLower = IsBarReject( + donOpenLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDonHighLower = IsBarReject( + donHighLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDonLowLower = IsBarReject( + donLowLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isRejectedDonCloseLower = IsBarReject( + donCloseLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isBreakedDonOpenUpper = IsBarBreak( + donOpenUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDonHighUpper = IsBarBreak( + donHighUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDonLowUpper = IsBarBreak( + donLowUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedDonCloseUpper = IsBarBreak( + donCloseUpperBuffer[cIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + bool isBreakedDonOpenLower = IsBarBreak( + donOpenLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDonHighLower = IsBarBreak( + donHighLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDonLowLower = IsBarBreak( + donLowLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDonCloseLower = IsBarBreak( + donCloseLowerBuffer[cIDX], + X_DIRECTION_BULLISH, + cBar // + ); + + // + conditions.isBreakedDonLowUpper = isBreakedDonLowUpper; + conditions.isBreakedDonLowLower = isBreakedDonLowLower; + conditions.isRejectedDonLowUpper = isRejectedDonLowUpper; + conditions.isRejectedDonLowLower = isRejectedDonLowLower; + conditions.isBreakedDonOpenUpper = isBreakedDonOpenUpper; + conditions.isBreakedDonHighUpper = isBreakedDonHighUpper; + conditions.isBreakedDonOpenLower = isBreakedDonOpenLower; + conditions.isBreakedDonHighLower = isBreakedDonHighLower; + conditions.isRejectedDonOpenUpper = isRejectedDonOpenUpper; + conditions.isRejectedDonOpenLower = isRejectedDonOpenLower; + conditions.isRejectedDonHighUpper = isRejectedDonHighUpper; + conditions.isRejectedDonHighLower = isRejectedDonHighLower; + conditions.isBreakedDonCloseUpper = isBreakedDonCloseUpper; + conditions.isBreakedDonCloseLower = isBreakedDonCloseLower; + conditions.isRejectedDonCloseUpper = isRejectedDonCloseUpper; + conditions.isRejectedDonCloseLower = isRejectedDonCloseLower; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XDONInputs mInputs; // Inputs ... + + // + // Buffers ... + double donOpenUpperBuffer[]; + double donOpenLowerBuffer[]; + double donHighUpperBuffer[]; + double donHighLowerBuffer[]; + double donLowUpperBuffer[]; + double donLowLowerBuffer[]; + double donCloseUpperBuffer[]; + double donCloseLowerBuffer[]; + + // + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + // + // OPEN ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_OPEN_UPPER_LINE, + 0, + totalBars, + donOpenUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_OPEN_LOWER_LINE, + 0, + totalBars, + donOpenLowerBuffer + // + ); + + // + // CLOSE ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_CLOSE_UPPER_LINE, + 0, + totalBars, + donCloseUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_CLOSE_LOWER_LINE, + 0, + totalBars, + donCloseLowerBuffer + // + ); + + // + // HIGH ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_HIGH_UPPER_LINE, + 0, + totalBars, + donHighUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_HIGH_LOWER_LINE, + 0, + totalBars, + donHighLowerBuffer + // + ); + + // + // LOW ... + + // + // Upper ... + CopyBuffer( + mHandler, + X121_XDON_LOW_UPPER_LINE, + 0, + totalBars, + donLowUpperBuffer + // + ); + + // + // Lower ... + CopyBuffer( + mHandler, + X121_XDON_LOW_LOWER_LINE, + 0, + totalBars, + donLowLowerBuffer + // + ); + } +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.xpv.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.xpv.helper.mq5 new file mode 100644 index 0000000..6840ca5 --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.xpv.helper.mq5 @@ -0,0 +1,2274 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XPVHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XPV_BUFFERS +{ + // + X121_XPV_PEAK_LINE = 0, + X121_XPV_VALE_LINE = 1, + X121_XPV_SAR_LINE = 2, + X121_XPV_C_HH_LINE = 3, + X121_XPV_C_LL_LINE = 4, + X121_XPV_S_HH_LINE = 5, + X121_XPV_S_LL_LINE = 6, + X121_XPV_M_HH_LINE = 7, + X121_XPV_M_LL_LINE = 8, + X121_XPV_L_HH_LINE = 9, + X121_XPV_L_LL_LINE = 10, + X121_XPV_H_HH_LINE = 11, + X121_XPV_H_LL_LINE = 12, +}; + +// +// Input Models ... +struct X121XPVInputs +{ + // + // Props ... + + // + // Short ... + ENUM_X_PERIOD_METHOD scMethod; // How to Find Period + ENUM_TIMEFRAMES scPeriod; // Time Period + + // + // Medium ... + ENUM_X_PERIOD_METHOD mcMethod; // How to Find Period + ENUM_TIMEFRAMES mcPeriod; // Time Period + + // + // Long ... + ENUM_X_PERIOD_METHOD lcMethod; // How to Find Period + ENUM_TIMEFRAMES lcPeriod; // Time Period + + // + // Hind ... + ENUM_X_PERIOD_METHOD hcMethod; // How to Find Period + ENUM_TIMEFRAMES hcPeriod; // Time Period + + // + // Boundary Detection ... + ENUM_SERIESMODE hhMode; // Highest High Calculation Method + ENUM_SERIESMODE llMode; // Lowest Low Calculation Method + + // + // Parabolic Sar Detection ... + double sarStep; // Step + double sarMax; // Maximum + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + int sarArrowCode; // Parabolic Sar Arrow Code + int peaksArrowCode; // Peaks Arrow Code + int valesArrowCode; // Vales Arrow Code + + // + bool showSar; // Show Parabolic Sar + bool showPeaks; // Show Peaks + bool showVales; // Show Vales + + // + // Constructor(s) ... + X121XPVInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + // Short ... + scMethod = X_PERIOD_NOTHING; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_NOTHING; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_NOTHING; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_NOTHING; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + + // + sarStep = 0; + sarMax = 0; + + // + startCalculationForLastBars = 0; + + // + sarArrowCode = 0; + peaksArrowCode = 0; + valesArrowCode = 0; + + // + showSar = false; + showPeaks = false; + showVales = false; + } + + // + // Default ... + void Default() + { + // + // Short ... + scMethod = X_PERIOD_AUTO; + scPeriod = NULL; + + // + // Medium ... + mcMethod = X_PERIOD_AUTO; + mcPeriod = NULL; + + // + // Long ... + lcMethod = X_PERIOD_AUTO; + lcPeriod = NULL; + + // + // Hind ... + hcMethod = X_PERIOD_AUTO; + hcPeriod = NULL; + + // + // Boundary Detection ... + hhMode = MODE_HIGH; + llMode = MODE_LOW; + + // + sarStep = 0.02; + sarMax = 0.2; + + // + startCalculationForLastBars = 1000; + + // + sarArrowCode = 159; + peaksArrowCode = 159; + valesArrowCode = 159; + + // + showSar = true; + showPeaks = true; + showVales = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + // SAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(1, 1); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XPVConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double sarBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + + // + // Conditions ... + + // + // SAR ... + + // + bool isSarBullish; + bool isSarBearish; + + // + bool isSarSwitchedToBullish; + bool isSarSwitchedToBearish; + + // + // XPV ... + + // + bool isNewPeak; + bool isNewPeakOverLast; + bool isNewPeakUnderLast; + bool isRejectedPrevPeak; + bool isBreakedUpPrevPeak; + + // + bool isNewVale; + bool isNewValeOverLast; + bool isNewValeUnderLast; + bool isRejectedPrevVale; + bool isBreakedDownPrevVale; + + // + // Constructor ... + X121XPVConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(peaksBuffer); + Clean(valesBuffer); + Clean(sarBuffer); + Clean(cHHBuffer); + Clean(cLLBuffer); + Clean(sHHBuffer); + Clean(sLLBuffer); + Clean(mHHBuffer); + Clean(mLLBuffer); + Clean(lHHBuffer); + Clean(lLLBuffer); + Clean(hHHBuffer); + Clean(hLLBuffer); + + // + // Clean(bullishTrendBuffer); + // Clean(bearishTrendBuffer); + + // + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + + // + // Conditions ... + + // + isSarBullish = false; + isSarBearish = false; + + // + isSarSwitchedToBullish = false; + isSarSwitchedToBearish = false; + + // + isNewPeak = false; + isNewPeakOverLast = false; + isNewPeakUnderLast = false; + isRejectedPrevPeak = false; + isBreakedUpPrevPeak = false; + // + isNewVale = false; + isNewValeOverLast = false; + isNewValeUnderLast = false; + isRejectedPrevVale = false; + isBreakedDownPrevVale = false; + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + + ToString("isSarBearish", isSarBearish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBullish", isSarSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isSarSwitchedToBearish", isSarSwitchedToBearish, ignoreFalseConditions, separator) + + ToString("isNewPeak", isNewPeak, ignoreFalseConditions, separator) + + ToString("isNewPeakOverLast", isNewPeakOverLast, ignoreFalseConditions, separator) + + ToString("isNewPeakUnderLast", isNewPeakUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevPeak", isRejectedPrevPeak, ignoreFalseConditions, separator) + + ToString("isBreakedUpPrevPeak", isBreakedUpPrevPeak, ignoreFalseConditions, separator) + + ToString("isNewVale", isNewVale, ignoreFalseConditions, separator) + + ToString("isNewValeOverLast", isNewValeOverLast, ignoreFalseConditions, separator) + + ToString("isNewValeUnderLast", isNewValeUnderLast, ignoreFalseConditions, separator) + + ToString("isRejectedPrevVale", isRejectedPrevVale, ignoreFalseConditions, separator) + + ToString("isBreakedDownPrevVale", isBreakedDownPrevVale, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XPVHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XPVHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XPVHelper() + { + // + mInputs.Clean(); + + // + ArrayFree(peaksBuffer); + ArrayFree(valesBuffer); + ArrayFree(sarBuffer); + ArrayFree(cHHBuffer); + ArrayFree(cLLBuffer); + ArrayFree(sHHBuffer); + ArrayFree(sLLBuffer); + ArrayFree(mHHBuffer); + ArrayFree(mLLBuffer); + ArrayFree(lHHBuffer); + ArrayFree(lLLBuffer); + ArrayFree(hHHBuffer); + ArrayFree(hLLBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XPVInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(peaksBuffer, true); + ArraySetAsSeries(valesBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(cHHBuffer, true); + ArraySetAsSeries(cLLBuffer, true); + ArraySetAsSeries(sHHBuffer, true); + ArraySetAsSeries(sLLBuffer, true); + ArraySetAsSeries(mHHBuffer, true); + ArraySetAsSeries(mLLBuffer, true); + ArraySetAsSeries(lHHBuffer, true); + ArraySetAsSeries(lLLBuffer, true); + ArraySetAsSeries(hHHBuffer, true); + ArraySetAsSeries(hLLBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xpv", + // + // Inputs ... + // + // Market ... + "", + // + // Short ... + "", + mInputs.scMethod, + mInputs.scPeriod, + // + // Medium ... + "", + mInputs.mcMethod, + mInputs.mcPeriod, + // + // Long ... + "", + mInputs.lcMethod, + mInputs.lcPeriod, + // + // Hind ... + "", + mInputs.hcMethod, + mInputs.hcPeriod, + // + // Boundary Detection ... + "", + mInputs.hhMode, + mInputs.llMode, + // + // SAr Detection ... + "", + mInputs.sarStep, + mInputs.sarMax, + // + // Presentation ... + "", + // + mInputs.startCalculationForLastBars, + mInputs.sarArrowCode, + mInputs.peaksArrowCode, + mInputs.valesArrowCode, + // + mInputs.showSar, + mInputs.showPeaks, + mInputs.showVales + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XPVInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XPVInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // SAR ... + + // + double GetSar( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sarBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sarBuffer[barIndex]; + } + + // + int CopySar( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sarBuffer, + buffer, + forceClean + // + ); + } + + // + // PV ... + + // + // PEAKS ... + + // + double GetPeak( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(peaksBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return peaksBuffer[barIndex]; + } + + // + int CopyPeak( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + peaksBuffer, + buffer, + forceClean + // + ); + } + + // + // VALES ... + + // + double GetVale( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(valesBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return valesBuffer[barIndex]; + } + + // + int CopyVale( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + valesBuffer, + buffer, + forceClean + // + ); + } + + // + // + // + + // + double GetHigherPeak( + int &index, // Bar Index + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(sIndex); + if (iValue > peak) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + double GetLowerPeak( + int &index, // Bar Index + double peak, // Peak Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (peak <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetPeak(sIndex); + if (iValue < peak) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + double GetHigherVale( + int &index, // Bar Index + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(sIndex); + if (iValue > vale) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + double GetLowerVale( + int &index, // Bar Index + double vale, // Vale Source + int barIndex = 0, // Bar Index + int loopback = 576 // Max Allowed Loopback + ) + { + // + double result = 0; + + // + index = -1; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + if (vale <= 0) + { + return result; + } + + // + double iValue = 0; + int sIndex = barIndex; + bool canContinue = true; + while (canContinue) + { + // + iValue = GetVale(sIndex); + if (iValue < vale) + { + // + index = sIndex; + result = iValue; + break; + } + + // + canContinue = sIndex < barIndex + loopback; + sIndex++; + } + + // + return result; + } + + // + // CURRENT ... + + // + // HH ... + + // + double GetCHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cHHBuffer[barIndex]; + } + + // + int CopyCHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetCLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(cLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return cLLBuffer[barIndex]; + } + + // + int CopyCLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cLLBuffer, + buffer, + forceClean + // + ); + } + + // + // SHORT ... + + // + // HH ... + + // + double GetSHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sHHBuffer[barIndex]; + } + + // + int CopySHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetSLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(sLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return sLLBuffer[barIndex]; + } + + // + int CopySLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sLLBuffer, + buffer, + forceClean + // + ); + } + + // + // MEDIUM ... + + // + // HH ... + + // + double GetMHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mHHBuffer[barIndex]; + } + + // + int CopyMHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetMLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(mLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return mLLBuffer[barIndex]; + } + + // + int CopyMLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + mLLBuffer, + buffer, + forceClean + // + ); + } + + // + // LONG ... + + // + // HH ... + + // + double GetLHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lHHBuffer[barIndex]; + } + + // + int CopyLHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetLLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(lLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return lLLBuffer[barIndex]; + } + + // + int CopyLLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + lLLBuffer, + buffer, + forceClean + // + ); + } + + // + // HIND ... + + // + // HH ... + + // + double GetHHH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hHHBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hHHBuffer[barIndex]; + } + + // + int CopyHHH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hHHBuffer, + buffer, + forceClean + // + ); + } + + // + // LL ... + + // + double GetHLL( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(hLLBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return hLLBuffer[barIndex]; + } + + // + int CopyHLL( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + hLLBuffer, + buffer, + forceClean + // + ); + } + + // + // Tools Function ... + + // + double GetLowestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetHighestPeak( + int barIndex, + int &index, + double &vale, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + vale = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetPeak(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + vale = GetVale(index); + } + } + + // + return result; + } + + // + double GetLowestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result >= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + double GetHighestVale( + int barIndex, + int &index, + double &peak, + int loopback = 576 // + ) + { + // + double result = 0; + + // + index = -1; + peak = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 576) + { + loopback = 576; + } + + // + Calculate(); + + // + for (int i = 0; i < barIndex + loopback; i++) + { + // + double iPeak = GetVale(i); + if (iPeak == 0) + { + break; + } + + // + if (iPeak > 0 && (result == 0 || + result <= iPeak)) + { + // + index = i; + result = iPeak; + peak = GetPeak(index); + } + } + + // + return result; + } + + // + bool GetConditions( + X121XPVConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopySar( + zIndex, + loopback, + conditions.sarBuffer // + ); + + // + CopyPeak( + zIndex, + loopback, + conditions.peaksBuffer // + ); + + // + CopyVale( + zIndex, + loopback, + conditions.valesBuffer // + ); + + // + CopyCHH( + zIndex, + loopback, + conditions.cHHBuffer // + ); + + // + CopyCLL( + zIndex, + loopback, + conditions.cLLBuffer // + ); + + // + CopySHH( + zIndex, + loopback, + conditions.sHHBuffer // + ); + + // + CopySLL( + zIndex, + loopback, + conditions.sLLBuffer // + ); + + // + CopyMHH( + zIndex, + loopback, + conditions.mHHBuffer // + ); + + // + CopyMLL( + zIndex, + loopback, + conditions.mLLBuffer // + ); + + // + CopyLHH( + zIndex, + loopback, + conditions.lHHBuffer // + ); + + // + CopyLLL( + zIndex, + loopback, + conditions.lLLBuffer // + ); + + // + CopyHHH( + zIndex, + loopback, + conditions.hHHBuffer // + ); + + // + CopyHLL( + zIndex, + loopback, + conditions.hLLBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // SAR ... + + // + bool isSarBullish = conditions.sarBuffer[cIDX] < cBar.low; + bool isSarBullishPrev = conditions.sarBuffer[pIDX] < pBar.low; + + // + bool isSarBearish = conditions.sarBuffer[cIDX] > cBar.high; + bool isSarBearishPrev = conditions.sarBuffer[pIDX] > pBar.high; + + // + bool isSarSwitchedToBullish = isSarBullish && + !isSarBullishPrev; + bool isSarSwitchedToBearish = isSarBearish && + !isSarBearishPrev; + + // + // XPV ... + + // + bool isNewPeak = conditions.peaksBuffer[cIDX] != conditions.peaksBuffer[pIDX]; + bool isNewPeakOverLast = isNewPeak && + conditions.peaksBuffer[cIDX] > conditions.peaksBuffer[pIDX]; + bool isNewPeakUnderLast = isNewPeak && + conditions.peaksBuffer[cIDX] < conditions.peaksBuffer[pIDX]; + bool isRejectedPrevPeak = IsBarReject( + conditions.peaksBuffer[pIDX], + X_DIRECTION_BEARISH, + cBar // + ); + bool isBreakedUpPrevPeak = IsBarBreak( + conditions.peaksBuffer[pIDX], + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isNewVale = conditions.valesBuffer[cIDX] != conditions.valesBuffer[pIDX]; + bool isNewValeOverLast = isNewVale && + conditions.valesBuffer[cIDX] > conditions.valesBuffer[pIDX]; + bool isNewValeUnderLast = isNewVale && + conditions.valesBuffer[cIDX] < conditions.valesBuffer[pIDX]; + bool isRejectedPrevVale = IsBarReject( + conditions.valesBuffer[pIDX], + X_DIRECTION_BULLISH, + cBar // + ); + bool isBreakedDownPrevVale = IsBarBreak( + conditions.valesBuffer[pIDX], + X_DIRECTION_BEARISH, + cBar // + ); + + // + conditions.isSarBullish = isSarBullish; + conditions.isSarBearish = isSarBearish; + conditions.isSarSwitchedToBullish = isSarSwitchedToBullish; + conditions.isSarSwitchedToBearish = isSarSwitchedToBearish; + conditions.isNewPeak = isNewPeak; + conditions.isNewPeakOverLast = isNewPeakOverLast; + conditions.isNewPeakUnderLast = isNewPeakUnderLast; + conditions.isRejectedPrevPeak = isRejectedPrevPeak; + conditions.isBreakedUpPrevPeak = isBreakedUpPrevPeak; + conditions.isNewVale = isNewVale; + conditions.isNewValeOverLast = isNewValeOverLast; + conditions.isNewValeUnderLast = isNewValeUnderLast; + conditions.isRejectedPrevVale = isRejectedPrevVale; + conditions.isBreakedDownPrevVale = isBreakedDownPrevVale; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XPVInputs mInputs; // Inputs ... + + // + // Buffers ... + double peaksBuffer[]; + double valesBuffer[]; + double sarBuffer[]; + double cHHBuffer[]; + double cLLBuffer[]; + double sHHBuffer[]; + double sLLBuffer[]; + double mHHBuffer[]; + double mLLBuffer[]; + double lHHBuffer[]; + double lLLBuffer[]; + double hHHBuffer[]; + double hLLBuffer[]; + + // + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // SAR ... + CopyBuffer( + mHandler, + X121_XPV_SAR_LINE, + 0, + totalBars, + sarBuffer + // + ); + + // + // XPV ... + + // + // PEAKS ... + CopyBuffer( + mHandler, + X121_XPV_PEAK_LINE, + 0, + totalBars, + peaksBuffer + // + ); + + // + // VALES ... + CopyBuffer( + mHandler, + X121_XPV_VALE_LINE, + 0, + totalBars, + valesBuffer + // + ); + + // + // CURRENT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_C_HH_LINE, + 0, + totalBars, + cHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_C_LL_LINE, + 0, + totalBars, + cLLBuffer + // + ); + + // + // SHORT ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_S_HH_LINE, + 0, + totalBars, + sHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_S_LL_LINE, + 0, + totalBars, + sLLBuffer + // + ); + + // + // MEDIUM ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_M_HH_LINE, + 0, + totalBars, + mHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_M_LL_LINE, + 0, + totalBars, + mLLBuffer + // + ); + + // + // LONG ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_L_HH_LINE, + 0, + totalBars, + lHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_L_LL_LINE, + 0, + totalBars, + lLLBuffer + // + ); + + // + // HIND ... + + // + // HH ... + CopyBuffer( + mHandler, + X121_XPV_H_HH_LINE, + 0, + totalBars, + hHHBuffer + // + ); + + // + // LL ... + CopyBuffer( + mHandler, + X121_XPV_H_LL_LINE, + 0, + totalBars, + hLLBuffer + // + ); + } +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.xstr.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.xstr.helper.mq5 new file mode 100644 index 0000000..1ac9dcb --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.xstr.helper.mq5 @@ -0,0 +1,1054 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XSTRHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XSTR_BUFFERS +{ + // + X121_XSTR_LINE = 0, + X121_XSTR_UP_LINE = 2, + X121_XSTR_DOWN_LINE = 3, + X121_XSTR_ATR_LINE = 4, + X121_XSTR_PRICE_LINE = 5, + X121_XSTR_STATE_LINE = 6, +}; + +// +// Input Models ... +struct X121XSTRInputs +{ + // + // Props ... + + int strLength; // Length + double strMultiplier; // Multiplier + ENUM_APPLIED_PRICE strAppliedTo; // Applied To + + // + bool showStr; // Show Upper Zone + bool showStrUpper; // Show Str Upper + bool showStrLower; // Show Str Lower + + // + // Constructor(s) ... + X121XSTRInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + strLength = 0; + strMultiplier = 0.0; + strAppliedTo = PRICE_MEDIAN; + + // + showStr = false; + showStrUpper = false; + showStrLower = false; + } + + // + // Default ... + void Default() + { + // + strLength = 14; + strMultiplier = 3.0; + strAppliedTo = PRICE_MEDIAN; + + // + showStr = true; + showStrUpper = true; + showStrLower = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + strLength > 0 && + strMultiplier > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(1, strLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XSTRConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double strBuffer[]; + double atrBuffer[]; + double strPriceBuffer[]; + double strUpBuffer[]; + double strDownBuffer[]; + double strStateBuffer[]; + + // + // Conditions ... + + // + bool isStrBullish; + bool isStrBearish; + + // + bool isStrSwitchedToBullish; + bool isStrSwitchedToBearish; + + // + // bool isCloseLower + + // + // Constructor ... + X121XSTRConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(strBuffer); + Clean(atrBuffer); + Clean(strPriceBuffer); + Clean(strUpBuffer); + Clean(strDownBuffer); + Clean(strStateBuffer); + + // + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(strPriceBuffer, true); + ArraySetAsSeries(strUpBuffer, true); + ArraySetAsSeries(strDownBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + + // + // Conditions ... + + // + isStrBullish = false; + isStrBearish = false; + + // + isStrSwitchedToBullish = false; + isStrSwitchedToBearish = false; + + // + // XDON ... + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isStrBullish", isStrBullish, ignoreFalseConditions, separator) + + ToString("isStrBearish", isStrBearish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBullish", isStrSwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isStrSwitchedToBearish", isStrSwitchedToBearish, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XSTRHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XSTRHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XSTRHelper() + { + // + mInputs.Clean(); + + // + ArrayFree(strBuffer); + ArrayFree(atrBuffer); + ArrayFree(strPriceBuffer); + ArrayFree(strUpBuffer); + ArrayFree(strDownBuffer); + ArrayFree(strStateBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XSTRInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(strBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(strPriceBuffer, true); + ArraySetAsSeries(strUpBuffer, true); + ArraySetAsSeries(strDownBuffer, true); + ArraySetAsSeries(strStateBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // Market ... + "", + mInputs.strLength, + mInputs.strMultiplier, + mInputs.strAppliedTo, + // + // Presentation ... + "", + mInputs.showStr, + mInputs.showStrUpper, + mInputs.showStrLower + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XSTRInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XSTRInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + // ATR ... + + // + double GetATR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(atrBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return atrBuffer[barIndex]; + } + + // + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strBuffer[barIndex]; + } + + // + int CopySTR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strStateBuffer[barIndex]; + } + + // + int CopySTRState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strStateBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRPrice( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strPriceBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strPriceBuffer[barIndex]; + } + + // + int CopySTRPrice( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strPriceBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRUp( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strUpBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strUpBuffer[barIndex]; + } + + // + int CopySTRUp( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strUpBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTRDown( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(strDownBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return strDownBuffer[barIndex]; + } + + // + int CopySTRDown( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + strDownBuffer, + buffer, + forceClean + // + ); + } + + // + double GetLastSTR( + ENUM_X_DIRECTION dir, + int barIndex = 0 // + ) + { + // + double result = 0; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (!HasDirection(dir)) + { + return result; + } + + // + int index = barIndex; + bool isBullish = IsBullish(dir); + + // + bool canContinue = true; + while (canContinue) + { + // + double iStr = GetSTR(index); + double iState = GetSTRState(index); + + // + canContinue = + isBullish + ? iState < 0 + : iState > 0; + if (!canContinue) + { + // + result = iStr; + break; + } + + // + index++; + } + + // + return result; + } + + // + bool GetConditions( + X121XSTRConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyATR( + zIndex, + loopback, + conditions.atrBuffer // + ); + + // + CopySTR( + zIndex, + loopback, + conditions.strBuffer // + ); + + // + CopySTRState( + zIndex, + loopback, + conditions.strStateBuffer // + ); + + // + CopySTRPrice( + zIndex, + loopback, + conditions.strPriceBuffer // + ); + + // + CopySTRUp( + zIndex, + loopback, + conditions.strUpBuffer // + ); + + // + CopySTRDown( + zIndex, + loopback, + conditions.strDownBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + bool isStrBullish = strStateBuffer[cIDX] > 0; + bool isStrBullishPrev = strStateBuffer[pIDX] > 0; + + // + bool isStrBearish = strStateBuffer[cIDX] < 0; + bool isStrBearishPrev = strStateBuffer[pIDX] < 0; + + // + bool isStrSwitchedToBullish = isStrBullish && + !isStrBullishPrev; + bool isStrSwitchedToBearish = isStrBearish && + !isStrBearishPrev; + + // + conditions.isStrBullish = isStrBullish; + conditions.isStrBearish = isStrBearish; + conditions.isStrSwitchedToBullish = isStrSwitchedToBullish; + conditions.isStrSwitchedToBearish = isStrSwitchedToBearish; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XSTRInputs mInputs; // Inputs ... + + // + // Buffers ... + double strBuffer[]; + double atrBuffer[]; + double strPriceBuffer[]; + double strUpBuffer[]; + double strDownBuffer[]; + double strStateBuffer[]; + + // + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // STR ... + CopyBuffer( + mHandler, + X121_XSTR_LINE, + 0, + totalBars, + strBuffer + // + ); + + // + // State ... + CopyBuffer( + mHandler, + X121_XSTR_STATE_LINE, + 0, + totalBars, + strStateBuffer + // + ); + + // + // Price ... + CopyBuffer( + mHandler, + X121_XSTR_PRICE_LINE, + 0, + totalBars, + strPriceBuffer + // + ); + + // + // Up ... + CopyBuffer( + mHandler, + X121_XSTR_UP_LINE, + 0, + totalBars, + strUpBuffer + // + ); + + // + // STR ... + CopyBuffer( + mHandler, + X121_XSTR_DOWN_LINE, + 0, + totalBars, + strDownBuffer + // + ); + + // + // ATR ... + + // + CopyBuffer( + mHandler, + X121_XSTR_ATR_LINE, + 0, + totalBars, + atrBuffer + // + ); + } +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.x121.xvwap.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.x121.xvwap.helper.mq5 new file mode 100644 index 0000000..0bd0806 --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.x121.xvwap.helper.mq5 @@ -0,0 +1,1435 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XVWAPHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X121_XVWAP_BUFFERS +{ + // + X121_XVWAP_FAST_LINE = 0, + X121_XVWAP_FAST_STATE_LINE = 8, + X121_XVWAP_MID_LINE = 2, + X121_XVWAP_MID_STATE_LINE = 9, + X121_XVWAP_SLOW_LINE = 4, + X121_XVWAP_SLOW_STATE_LINE = 10, + X121_XVWAP_VOLUME_LINE = 6, + X121_XVWAP_PRICE_LINE = 7, +}; + +// +enum ENUM_XVWAP_STATES +{ + XVWAP_STATE_BULLISH = 1, + XVWAP_STATE_BEARISH = 2, + XVWAP_STATE_NEUTURAL = 3, +}; + +// +// Input Models ... +struct X121XVWAPInputs +{ + // + // Props ... + + int vwapFastLength; // Fast Length + int vwapMidLength; // Mid Length + int vwapSlowLength; // Slow Length + ENUM_APPLIED_PRICE vwapAppliedTo; // Applied To + + // + int startCalculationForLastBars; // Calculate Last n Bars + + // + bool showVWapFast; // Show VWap Fast + bool showVWapMedium; // Show VWap Medium + bool showVWapSlow; // Show VWap Slow + + // + // Constructor(s) ... + X121XVWAPInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + vwapFastLength = 0; + vwapMidLength = 0; + vwapSlowLength = 0; + vwapAppliedTo = PRICE_CLOSE; + + // + startCalculationForLastBars = 0; + + // + showVWapFast = false; + showVWapMedium = false; + showVWapSlow = false; + } + + // + // Default ... + void Default() + { + // + vwapFastLength = 20; + vwapMidLength = 40; + vwapSlowLength = 60; + vwapAppliedTo = PRICE_CLOSE; + + // + startCalculationForLastBars = 1000; + + // + showVWapFast = true; + showVWapMedium = true; + showVWapSlow = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(vwapFastLength, vwapMidLength); + result = MathMax(result, vwapSlowLength); + + // + return result; + } +}; + +// +// Conditions ... +struct X121XVWAPConditions +{ + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Buffers ... + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + + // + // Conditions ... + + // + bool isVWapFastBullish; + bool isVWapFastBearish; + bool isVWapFastNeutural; + + // + bool isVWapMidBullish; + bool isVWapMidBearish; + bool isVWapMidNeutural; + + // + bool isVWapSlowBullish; + bool isVWapSlowBearish; + bool isVWapSlowNeutural; + + // + bool isVWapFastOverMid; + bool isVWapMidOverSlow; + + // + bool isVWapFastUnderMid; + bool isVWapMidUnderSlow; + + // + bool isVWapBullishState; + bool isVWapBearishState; + bool isVWapNeuturalState; + + // + bool isVWapBullishOrdered; + bool isVWapBearishOrdered; + + // + bool isVWapSwitchedToBullishOrdered; + bool isVWapSwitchedToBearishOrdered; + + // + bool isVWapSwitchedToBullishState; + bool isVWapSwitchedToBearishState; + bool isVWapSwitchedToNeuturalState; + + // + // Constructor ... + X121XVWAPConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + symbol = NULL; + period = NULL; + time = NULL; + + // + // Buffers ... + + // + Clean(vwapFastBuffer); + Clean(vwapMidBuffer); + Clean(vwapSlowBuffer); + Clean(vwapVolumeBuffer); + Clean(vwapPriceBuffer); + Clean(vwapFastStateBuffer); + Clean(vwapMidStateBuffer); + Clean(vwapSlowStateBuffer); + + // + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + + // + // Conditions ... + + // + isVWapFastBullish = false; + isVWapFastBearish = false; + isVWapFastNeutural = false; + + // + isVWapMidBullish = false; + isVWapMidBearish = false; + isVWapMidNeutural = false; + + // + isVWapSlowBullish = false; + isVWapSlowBearish = false; + isVWapSlowNeutural = false; + + // + isVWapFastOverMid = false; + isVWapMidOverSlow = false; + + // + isVWapFastUnderMid = false; + isVWapMidUnderSlow = false; + + // + isVWapBullishState = false; + isVWapBearishState = false; + isVWapNeuturalState = false; + + // + isVWapBullishOrdered = false; + isVWapBearishOrdered = false; + + // + isVWapSwitchedToBullishOrdered = false; + isVWapSwitchedToBearishOrdered = false; + + // + isVWapSwitchedToBullishState = false; + isVWapSwitchedToBearishState = false; + isVWapSwitchedToNeuturalState = false; + } + + /** + * Generate Conditions Scores ... + * + * @param bullishScore: Double, Directional Scores Reference ... + * @param bearishScore: Double, Directional Scores Reference ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + // TODO: Implement if Required ... + } + + /** + * Generate Summary String for Represent Conditions State ... + * + * @param onlyCommons: Boolean, Just Generate Only Commons Conditions ... + * @param onlyConditions: Boolean, Just Generate Only Conditions ... + * @param includeScores: Boolean, Attach Scores Representations on Result ... + * @param ignoreFalseConditions: Boolean, Ignore False Conditions on Result ... + * @param separator: String, Separate Lines ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string scoresStr = + // + "Scores: " + separator + + "---------------" + separator + + "Bullish: " + ToString(bullishScore) + separator + + "Bearish: " + ToString(bearishScore) + separator + + "" + // + ; + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores // + ); + + // + string conditionsStr = + // + ToString("isVWapFastBullish", isVWapFastBullish, ignoreFalseConditions, separator) + + ToString("isVWapFastBearish", isVWapFastBearish, ignoreFalseConditions, separator) + + ToString("isVWapFastNeutural", isVWapFastNeutural, ignoreFalseConditions, separator) + + ToString("isVWapMidBullish", isVWapMidBullish, ignoreFalseConditions, separator) + + ToString("isVWapMidBearish", isVWapMidBearish, ignoreFalseConditions, separator) + + ToString("isVWapMidNeutural", isVWapMidNeutural, ignoreFalseConditions, separator) + + ToString("isVWapSlowBullish", isVWapSlowBullish, ignoreFalseConditions, separator) + + ToString("isVWapSlowBearish", isVWapSlowBearish, ignoreFalseConditions, separator) + + ToString("isVWapSlowNeutural", isVWapSlowNeutural, ignoreFalseConditions, separator) + + ToString("isVWapFastOverMid", isVWapFastOverMid, ignoreFalseConditions, separator) + + ToString("isVWapMidOverSlow", isVWapMidOverSlow, ignoreFalseConditions, separator) + + ToString("isVWapFastUnderMid", isVWapFastUnderMid, ignoreFalseConditions, separator) + + ToString("isVWapMidUnderSlow", isVWapMidUnderSlow, ignoreFalseConditions, separator) + + ToString("isVWapBullishState", isVWapBullishState, ignoreFalseConditions, separator) + + ToString("isVWapBearishState", isVWapBearishState, ignoreFalseConditions, separator) + + ToString("isVWapNeuturalState", isVWapNeuturalState, ignoreFalseConditions, separator) + + ToString("isVWapBullishOrdered", isVWapBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapBearishOrdered", isVWapBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishOrdered", isVWapSwitchedToBullishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishOrdered", isVWapSwitchedToBearishOrdered, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBullishState", isVWapSwitchedToBullishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToBearishState", isVWapSwitchedToBearishState, ignoreFalseConditions, separator) + + ToString("isVWapSwitchedToNeuturalState", isVWapSwitchedToNeuturalState, ignoreFalseConditions, separator) + + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + (onlyConditions + ? "" + : commonStr) + + (!includeScores + ? "" + : scoresStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Retrieve nique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetTypeName(this); + } + + // +}; + +// +// Class ... +class XCX121XVWAPHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XVWAPHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XVWAPHelper() + { + // + mInputs.Clean(); + + // + ArrayFree(vwapFastBuffer); + ArrayFree(vwapMidBuffer); + ArrayFree(vwapSlowBuffer); + ArrayFree(vwapVolumeBuffer); + ArrayFree(vwapPriceBuffer); + ArrayFree(vwapFastStateBuffer); + ArrayFree(vwapMidStateBuffer); + ArrayFree(vwapSlowStateBuffer); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XVWAPInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapVolumeBuffer, true); + ArraySetAsSeries(vwapPriceBuffer, true); + ArraySetAsSeries(vwapFastStateBuffer, true); + ArraySetAsSeries(vwapMidStateBuffer, true); + ArraySetAsSeries(vwapSlowStateBuffer, true); + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xvwap", + // + // Inputs ... + // + // Market ... + "", + mInputs.vwapFastLength, + mInputs.vwapMidLength, + mInputs.vwapSlowLength, + mInputs.vwapAppliedTo, + // + // Presentation ... + "", + // + mInputs.startCalculationForLastBars, + // + mInputs.showVWapFast, + mInputs.showVWapMedium, + mInputs.showVWapSlow + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XVWAPInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XVWAPInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Readers ... + + // + double GetVWapFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastBuffer[barIndex]; + } + + // + int CopyVWapFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE FAST ... + + // + double GetVWapFastState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapFastStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapFastStateBuffer[barIndex]; + } + + // + int CopyVWapFastState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapFastStateBuffer, + buffer, + forceClean + // + ); + } + + // + // MID ... + + // + double GetVWapMid( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidBuffer[barIndex]; + } + + // + int CopyVWapMid( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE MID ... + + // + double GetVWapMidState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapMidStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapMidStateBuffer[barIndex]; + } + + // + int CopyVWapMidState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapMidStateBuffer, + buffer, + forceClean + // + ); + } + + // + // SLOW ... + + // + double GetVWapSlowBuffer( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowBuffer[barIndex]; + } + + // + int CopyVWapSlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowBuffer, + buffer, + forceClean + // + ); + } + + // + // STATE SLOW ... + + // + double GetVWapSlowState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapSlowStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapSlowStateBuffer[barIndex]; + } + + // + int CopyVWapSlowState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapSlowStateBuffer, + buffer, + forceClean + // + ); + } + + // + // VOLUME ... + + // + double GetVWapVolume( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapVolumeBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapVolumeBuffer[barIndex]; + } + + // + int CopyVWapVolume( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapVolumeBuffer, + buffer, + forceClean + // + ); + } + + // + // PRICE ... + + // + double GetVWapPrice( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + int count = ArraySize(vwapPriceBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return vwapPriceBuffer[barIndex]; + } + + // + int CopyVWapPrice( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + vwapPriceBuffer, + buffer, + forceClean + // + ); + } + + // + // Converts to State ... + ENUM_XVWAP_STATES ToVWAPState(double value) + { + // + ENUM_XVWAP_STATES result = + value == 1 + ? XVWAP_STATE_BULLISH + : value == 2 + ? XVWAP_STATE_BEARISH + : XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + bool IsVWAPBullish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BULLISH; + + // + return result; + } + + // + bool IsVWAPBearish(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_BEARISH; + + // + return result; + } + + // + bool IsVWAPNeutural(double value) + { + // + bool result = false; + + // + result = ToVWAPState(value) == XVWAP_STATE_NEUTURAL; + + // + return result; + } + + // + bool GetConditions( + X121XVWAPConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + int zIndex = barIndex; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL zBar; + result = zBar.Init( + mSymbol, + mPeriod, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!result) + { + return result; + } + + // + // Buffers ... + + // + CopyVWapFast( + zIndex, + loopback, + conditions.vwapFastBuffer // + ); + + // + CopyVWapFastState( + zIndex, + loopback, + conditions.vwapFastStateBuffer // + ); + + // + CopyVWapMid( + zIndex, + loopback, + conditions.vwapMidBuffer // + ); + + // + CopyVWapMidState( + zIndex, + loopback, + conditions.vwapMidStateBuffer // + ); + + // + CopyVWapSlow( + zIndex, + loopback, + conditions.vwapSlowBuffer // + ); + + // + CopyVWapSlowState( + zIndex, + loopback, + conditions.vwapSlowStateBuffer // + ); + + // + CopyVWapVolume( + zIndex, + loopback, + conditions.vwapVolumeBuffer // + ); + + // + CopyVWapPrice( + zIndex, + loopback, + conditions.vwapPriceBuffer // + ); + + // + // Conditions ... + + // + int cIDX = 1; + int pIDX = cIDX + 1; + + // + // SAR ... + + // + bool isVWapFastBullish = IsVWAPBullish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBullishPrev = IsVWAPBullish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastBearish = IsVWAPBearish(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastBearishPrev = IsVWAPBearish(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapFastNeutural = IsVWAPNeutural(conditions.vwapFastStateBuffer[cIDX]); + bool isVWapFastNeuturalPrev = IsVWAPNeutural(conditions.vwapFastStateBuffer[pIDX]); + + // + bool isVWapMidBullish = IsVWAPBullish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBullishPrev = IsVWAPBullish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidBearish = IsVWAPBearish(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidBearishPrev = IsVWAPBearish(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapMidNeutural = IsVWAPNeutural(conditions.vwapMidStateBuffer[cIDX]); + bool isVWapMidNeuturalPrev = IsVWAPNeutural(conditions.vwapMidStateBuffer[pIDX]); + + // + bool isVWapSlowBullish = IsVWAPBullish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBullishPrev = IsVWAPBullish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowBearish = IsVWAPBearish(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowBearishPrev = IsVWAPBearish(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapSlowNeutural = IsVWAPNeutural(conditions.vwapSlowStateBuffer[cIDX]); + bool isVWapSlowNeuturalPrev = IsVWAPNeutural(conditions.vwapSlowStateBuffer[pIDX]); + + // + bool isVWapFastOverMid = conditions.vwapFastBuffer[cIDX] > conditions.vwapMidBuffer[cIDX]; + bool isVWapFastOverMidPrev = conditions.vwapFastBuffer[pIDX] > conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidOverSlow = conditions.vwapMidBuffer[cIDX] > conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidOverSlowPrev = conditions.vwapMidBuffer[pIDX] > conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapFastUnderMid = conditions.vwapFastBuffer[cIDX] < conditions.vwapMidBuffer[cIDX]; + bool isVWapFastUnderMidPrev = conditions.vwapFastBuffer[pIDX] < conditions.vwapMidBuffer[pIDX]; + + // + bool isVWapMidUnderSlow = conditions.vwapMidBuffer[cIDX] < conditions.vwapSlowBuffer[cIDX]; + bool isVWapMidUnderSlowPrev = conditions.vwapMidBuffer[pIDX] < conditions.vwapSlowBuffer[pIDX]; + + // + bool isVWapBullishState = isVWapFastBullish && + isVWapMidBullish && + isVWapSlowBullish; + bool isVWapBullishStatePrev = isVWapFastBullishPrev && + isVWapMidBullishPrev && + isVWapSlowBullishPrev; + + // + bool isVWapBearishState = isVWapFastBearish && + isVWapMidBearish && + isVWapSlowBearish; + bool isVWapBearishStatePrev = isVWapFastBearishPrev && + isVWapMidBearishPrev && + isVWapSlowBearishPrev; + + // + bool isVWapNeuturalState = isVWapFastNeutural && + isVWapMidNeutural && + isVWapSlowNeutural; + bool isVWapNeuturalStatePrev = isVWapFastNeuturalPrev && + isVWapMidNeuturalPrev && + isVWapSlowNeuturalPrev; + + // + bool isVWapBullishOrdered = isVWapFastOverMid && + isVWapMidOverSlow; + bool isVWapBullishOrderedPrev = isVWapFastOverMidPrev && + isVWapMidOverSlowPrev; + + // + bool isVWapBearishOrdered = isVWapFastUnderMid && + isVWapMidUnderSlow; + bool isVWapBearishOrderedPrev = isVWapFastUnderMidPrev && + isVWapMidUnderSlowPrev; + + // + bool isVWapSwitchedToBullishOrdered = isVWapBullishOrdered && + !isVWapBullishOrderedPrev; + bool isVWapSwitchedToBearishOrdered = isVWapBearishOrdered && + !isVWapBearishOrderedPrev; + + // + bool isVWapSwitchedToBullishState = isVWapBullishState && + !isVWapBullishStatePrev; + bool isVWapSwitchedToBearishState = isVWapBearishState && + !isVWapBearishStatePrev; + bool isVWapSwitchedToNeuturalState = isVWapNeuturalState && + !isVWapNeuturalStatePrev; + + // + conditions.isVWapFastBullish = isVWapFastBullish; + conditions.isVWapFastBearish = isVWapFastBearish; + conditions.isVWapFastNeutural = isVWapFastNeutural; + conditions.isVWapMidBullish = isVWapMidBullish; + conditions.isVWapMidBearish = isVWapMidBearish; + conditions.isVWapMidNeutural = isVWapMidNeutural; + conditions.isVWapSlowBullish = isVWapSlowBullish; + conditions.isVWapSlowBearish = isVWapSlowBearish; + conditions.isVWapSlowNeutural = isVWapSlowNeutural; + conditions.isVWapFastOverMid = isVWapFastOverMid; + conditions.isVWapMidOverSlow = isVWapMidOverSlow; + conditions.isVWapFastUnderMid = isVWapFastUnderMid; + conditions.isVWapMidUnderSlow = isVWapMidUnderSlow; + conditions.isVWapBullishState = isVWapBullishState; + conditions.isVWapBearishState = isVWapBearishState; + conditions.isVWapNeuturalState = isVWapNeuturalState; + conditions.isVWapBullishOrdered = isVWapBullishOrdered; + conditions.isVWapBearishOrdered = isVWapBearishOrdered; + conditions.isVWapSwitchedToBullishOrdered = isVWapSwitchedToBullishOrdered; + conditions.isVWapSwitchedToBearishOrdered = isVWapSwitchedToBearishOrdered; + conditions.isVWapSwitchedToBullishState = isVWapSwitchedToBullishState; + conditions.isVWapSwitchedToBearishState = isVWapSwitchedToBearishState; + conditions.isVWapSwitchedToNeuturalState = isVWapSwitchedToNeuturalState; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XVWAPInputs mInputs; // Inputs ... + + // + // Buffers ... + double vwapFastBuffer[]; + double vwapMidBuffer[]; + double vwapSlowBuffer[]; + double vwapVolumeBuffer[]; + double vwapPriceBuffer[]; + double vwapFastStateBuffer[]; + double vwapMidStateBuffer[]; + double vwapSlowStateBuffer[]; + + // + void Calculate() + { + // + int totalBars = CountBars(); + if (totalBars > 1000) + { + totalBars = 1000; + } + + // + // Buffers ... + + // + // FAST ... + CopyBuffer( + mHandler, + X121_XVWAP_FAST_LINE, + 0, + totalBars, + vwapFastBuffer + // + ); + + // + // FAST STATE ... + CopyBuffer( + mHandler, + X121_XVWAP_FAST_STATE_LINE, + 0, + totalBars, + vwapFastStateBuffer + // + ); + + // + // MID ... + CopyBuffer( + mHandler, + X121_XVWAP_MID_LINE, + 0, + totalBars, + vwapMidBuffer + // + ); + + // + // MID STATE ... + CopyBuffer( + mHandler, + X121_XVWAP_MID_STATE_LINE, + 0, + totalBars, + vwapMidStateBuffer + // + ); + + // + // SLOW ... + CopyBuffer( + mHandler, + X121_XVWAP_SLOW_LINE, + 0, + totalBars, + vwapSlowBuffer + // + ); + + // + // SLOW STATE ... + CopyBuffer( + mHandler, + X121_XVWAP_SLOW_STATE_LINE, + 0, + totalBars, + vwapSlowStateBuffer + // + ); + + // + // VOLUME ... + CopyBuffer( + mHandler, + X121_XVWAP_VOLUME_LINE, + 0, + totalBars, + vwapVolumeBuffer + // + ); + + // + // PRICE ... + CopyBuffer( + mHandler, + X121_XVWAP_PRICE_LINE, + 0, + totalBars, + vwapPriceBuffer + // + ); + } +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.xcc.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.xcc.helper.mq5 new file mode 100644 index 0000000..7f7032e --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.xcc.helper.mq5 @@ -0,0 +1,249 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCXCCHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct XCCInputs +{ + // + // Props ... + + // + // Chart Style ... + ENUM_CHART_MODE mode; // Mode + color upColor; // Up Color + color downColor; // Down Color + color lineColor; // Line mode and Doji candlestick Color + color bearishColor; // Bullish Color + color bullishColor; // Bearish Color + color volumesColor; // Volumes Color + + // + // Presentation ... + bool showCandles; // Show Candles + + // + // Constructor(s) ... + XCCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + mode = CHART_CANDLES; + + // + upColor = CLR_NONE; + downColor = CLR_NONE; + lineColor = CLR_NONE; + bearishColor = CLR_NONE; + bullishColor = CLR_NONE; + volumesColor = CLR_NONE; + + // + showCandles = false; + } + + // + // Default ... + void Default() + { + // + mode = CHART_CANDLES; + + // + upColor = clrLime; + downColor = clrRed; + lineColor = clrLime; + bearishColor = clrRed; + bullishColor = clrLime; + volumesColor = clrGreen; + // + showCandles = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCXCCHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCXCCHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCXCCHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + XCCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.xcc", + // + // Inputs ... + // + // Chart Style ... + "", + mInputs.mode, // Mode + mInputs.upColor, // Up Color + mInputs.downColor, // Down Color + mInputs.lineColor, // Line mode and Doji candlestick Color + mInputs.bearishColor, // Bullish Color + mInputs.bullishColor, // Bearish Color + mInputs.volumesColor, // Volumes Color + // + // Presentation ... + "", + mInputs.showCandles // Show Candles + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + XCCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + XCCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + XCCInputs mInputs; // Inputs ... +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Helpers/x-saherelm.xct.helper.mq5 b/BKPS/14031106/Helpers/x-saherelm.xct.helper.mq5 new file mode 100644 index 0000000..cf4d7f4 --- /dev/null +++ b/BKPS/14031106/Helpers/x-saherelm.xct.helper.mq5 @@ -0,0 +1,231 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCXCTHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct XCTInputs +{ + // + // Props ... + + // + string font; // Font + int fontSize; // Font Size; + color clr; // Text Color + ENUM_BASE_CORNER corner; // Text Position + + // + // Presentation ... + bool showCandleTime; // Show Candle Time + + // + // Constructor(s) ... + XCTInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + font = NULL; + fontSize = 15; + clr = CLR_NONE; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = false; + } + + // + // Default ... + void Default() + { + // + font = "Arial"; + fontSize = 15; + clr = clrYellow; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = true; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCXCTHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCXCTHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCXCTHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + XCTInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.xct", + // + // Inputs ... + mInputs.fontSize, // Font Size ... + mInputs.font, // Font ... + mInputs.clr, // Text Color ... + mInputs.corner, // Text Position ... + // + // Presentation ... + "", + mInputs.showCandleTime // Show Candle Time + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + XCTInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + XCTInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + XCTInputs mInputs; // Inputs ... +}; + +// +// Tools ... \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xatr.ex5 b/BKPS/14031106/Indicators/x-saherelm.x121.xatr.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..0873655491cb249923efa156efa22fec8a3e3275 GIT binary patch literal 20850 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 maxLength && + // + // ATR ... + atrCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // RSI ... + int copiedRsis = CopyBuffer(rsiHandler, 0, 0, limit, rsiBuffer); + + // + // ATR ... + int copiedAtrs = CopyBuffer(atrHandler, 0, 0, limit, atrBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // + // RSI ... + copiedRsis > 0 && + // + // ATR ... + copiedAtrs > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + // RSI ... + rsiLength > 0 && + // + // ATR ... + atrLength > 0 && + atrMultiplier > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(rsiLength, atrLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // ATR ... + + // + // UPPER ... + bool canShowAtrUpper = showAtrUpper; + ENUM_DRAW_TYPE atrUpperDrawType = canShowAtrUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrUpperBuffer, true); + SetIndexBuffer(atrUpperBufferIndex, atrUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrUpperBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_SHOW_DATA, canShowAtrUpper); + PlotIndexSetInteger(atrUpperBufferIndex, PLOT_DRAW_TYPE, atrUpperDrawType); + + // + // LOWER ... + bool canShowAtrLower = showAtrLower; + ENUM_DRAW_TYPE atrLowerDrawType = canShowAtrLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(atrLowerBuffer, true); + SetIndexBuffer(atrLowerBufferIndex, atrLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(atrLowerBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_SHOW_DATA, canShowAtrLower); + PlotIndexSetInteger(atrLowerBufferIndex, PLOT_DRAW_TYPE, atrLowerDrawType); + + // + // Data Buffers ... + + // + // ATR ... + + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrUpperRawBuffer, true); + SetIndexBuffer(atrUpperRawBufferIndex, atrUpperRawBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrLowerRawBuffer, true); + SetIndexBuffer(atrLowerRawBufferIndex, atrLowerRawBuffer, INDICATOR_CALCULATIONS); + + // + // RSI ... + + // + ArraySetAsSeries(rsiBuffer, true); + SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateAtrZones( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // RSIS ... + rsiBuffer[barIndex] = 0; + + // + // ATRS ... + atrBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrUpperRawBuffer[barIndex] = 0; + atrUpperBuffer[barIndex] = 0; + atrLowerRawBuffer[barIndex] = 0; +} + +/** + * Calculate ATR Zones ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateAtrZones( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Select ATr Value ... + double atrValue = atrBuffer[bar_index]; + double appliedAtrMultiplierValue = atrValue * atrMultiplier; + + // + // Select Upper Price ... + double upperPrice = GetAppliedPrice( + atrUpperAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Select Lower Price ... + double lowerPrice = GetAppliedPrice( + atrLowerAppliedTo, + open, + high, + low, + close, + bar_index // + ); + + // + // Calculate Raw Atrs ... + + // + // Upper ... + double atrUpperRawValue = upperPrice + appliedAtrMultiplierValue; + atrUpperRawBuffer[bar_index] = atrUpperRawValue; + + // + // Lower ... + double atrLowerRawValue = lowerPrice - appliedAtrMultiplierValue; + atrLowerRawBuffer[bar_index] = atrLowerRawValue; + + // + bool canSmooth = atrSmoothingMode != X_MA_MODE_NONE; + if (canSmooth) + { + // + // Upper ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrUpperRawBuffer, + atrUpperBuffer, + atrSmoothingMode // + ); + + // + // Lower ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + atrLength, + atrLowerRawBuffer, + atrLowerBuffer, + atrSmoothingMode // + ); + } + else + { + // + // Use Raw Values ... + atrUpperBuffer[bar_index] = atrUpperRawValue; + atrLowerBuffer[bar_index] = atrLowerRawValue; + } +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xche.ex5 b/BKPS/14031106/Indicators/x-saherelm.x121.xche.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..d6665e72857ee8c5d4b7807bca9243365937a267 GIT binary patch literal 19730 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 z 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 9 && + cheLoopback >= 0; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(cheLength, cheLoopback); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // LEVEL 1 ... + + // + // Long Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE le1DrawType = showLE1 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE le1StartDrawType = showLE1 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(le1BufferIndex, le1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(le1BufferIndex, PLOT_SHOW_DATA, showLE1); + PlotIndexSetInteger(le1BufferIndex, PLOT_DRAW_TYPE, le1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(le1StartBufferIndex, le1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(le1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(le1StartBufferIndex, PLOT_DRAW_TYPE, le1StartDrawType); + PlotIndexSetInteger(le1StartBufferIndex, PLOT_ARROW, cheArrowCode); + + // + // Short Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE se1DrawType = showSE1 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE se1StartDrawType = showSE1 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(se1BufferIndex, se1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(se1BufferIndex, PLOT_SHOW_DATA, showSE1); + PlotIndexSetInteger(se1BufferIndex, PLOT_DRAW_TYPE, se1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(se1StartBufferIndex, se1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(se1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(se1StartBufferIndex, PLOT_DRAW_TYPE, se1StartDrawType); + PlotIndexSetInteger(se1StartBufferIndex, PLOT_ARROW, cheArrowCode); + + // + // LEVEL 2 ... + + // + // Long Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE le2DrawType = showLE2 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE le2StartDrawType = showLE2 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(le2BufferIndex, le2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(le2BufferIndex, PLOT_SHOW_DATA, showLE2); + PlotIndexSetInteger(le2BufferIndex, PLOT_DRAW_TYPE, le2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(le2StartBufferIndex, le2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(le2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(le2StartBufferIndex, PLOT_DRAW_TYPE, le2StartDrawType); + PlotIndexSetInteger(le2StartBufferIndex, PLOT_ARROW, cheArrowCode); + + // + // Short Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE se2DrawType = showSE2 ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE se2StartDrawType = showSE2 ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(se2BufferIndex, se2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(se2BufferIndex, PLOT_SHOW_DATA, showSE2); + PlotIndexSetInteger(se2BufferIndex, PLOT_DRAW_TYPE, se2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(se2StartBufferIndex, se2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(se2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(se2StartBufferIndex, PLOT_DRAW_TYPE, se2StartDrawType); + PlotIndexSetInteger(se2StartBufferIndex, PLOT_ARROW, cheArrowCode); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Buffers ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + int prevCalculated, // Previous Calculated + int ratesTotal, // Total Rates + const double &open[], // Rates Open ... + const double &high[], // Rates High ... + const double &low[], // Rates Low ... + const double &close[] // Rates Close ... +) +{ + // + // Cleanup Buffers ... + le1Buffer[bar_index] = le1StartBuffer[bar_index] = se1Buffer[bar_index] = se1StartBuffer[bar_index] = EMPTY_VALUE; + le2Buffer[bar_index] = le2StartBuffer[bar_index] = se2Buffer[bar_index] = se2StartBuffer[bar_index] = EMPTY_VALUE; + + // + int start = MathMax(bar_index - cheLoopback, 0); + + // + // Calculate ATR Value ... + double atrValue = 0; + for (int k = 1; k <= cheLength && (bar_index - k - 1) >= 0; k++) + { + // + atrValue += MathMax(high[bar_index - k], close[MathMax(bar_index - k - 1, 0)]) - + MathMin(low[bar_index - k], close[MathMax(bar_index - k - 1, 0)]); + } + atrValue /= (double)cheLength; + + // + // Retrieve Highest High and Lowest Lows ... + double cheLoopbackMax = high[ArrayMaximum(high, start, cheLoopback)]; + double cheLoopbackMin = low[ArrayMinimum(low, start, cheLoopback)]; + + // + // Fill Multi Dimesional Working Array ... + work[bar_index][hi1Idx] = cheLoopbackMax - cheMultiplier1 * atrValue; + work[bar_index][lo1Idx] = cheLoopbackMin + cheMultiplier1 * atrValue; + work[bar_index][hi2Idx] = cheLoopbackMax - cheMultiplier2 * atrValue; + work[bar_index][lo2Idx] = cheLoopbackMin + cheMultiplier2 * atrValue; + work[bar_index][trend1Idx] = (bar_index > 0) ? work[bar_index - 1][trend1Idx] : 0; + work[bar_index][trend2Idx] = (bar_index > 0) ? work[bar_index - 1][trend2Idx] : 0; + + // + if (bar_index > 0) + { + // + // Calculate Trends ... + if (close[bar_index] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][trend1Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][trend1Idx] = -1; + } + + // + if (close[bar_index] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][trend2Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][trend2Idx] = -1; + } + + // + // Calculate Exit Values ... + + // + // Exit 1 ... + + // + // Long ... + if (cheMultiplier1 > 0 && work[bar_index][trend1Idx] == 1) + { + // + if (work[bar_index][hi1Idx] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][hi1Idx] = work[bar_index - 1][hi1Idx]; + } + + // + le1Buffer[bar_index] = work[bar_index][hi1Idx]; + + // + if (le1Buffer[bar_index - 1] == EMPTY_VALUE) + { + le1StartBuffer[bar_index] = le1Buffer[bar_index]; + } + } + + // + // Short ... + if (cheMultiplier1 > 0 && work[bar_index][trend1Idx] == -1) + { + // + if (work[bar_index][lo1Idx] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][lo1Idx] = work[bar_index - 1][lo1Idx]; + } + + // + se1Buffer[bar_index] = work[bar_index][lo1Idx]; + + // + if (se1Buffer[bar_index - 1] == EMPTY_VALUE) + { + se1StartBuffer[bar_index] = se1Buffer[bar_index]; + } + } + + // + // Exit 2 ... + + // + // Long ... + if (cheMultiplier2 > 0 && work[bar_index][trend2Idx] == 1) + { + if (work[bar_index][hi2Idx] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][hi2Idx] = work[bar_index - 1][hi2Idx]; + } + + // + le2Buffer[bar_index] = work[bar_index][hi2Idx]; + + // + if (le2Buffer[bar_index - 1] == EMPTY_VALUE) + { + le2StartBuffer[bar_index] = le2Buffer[bar_index]; + } + } + + // + // Short ... + if (cheMultiplier2 > 0 && work[bar_index][trend2Idx] == -1) + { + // + if (work[bar_index][lo2Idx] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][lo2Idx] = work[bar_index - 1][lo2Idx]; + } + + // + se2Buffer[bar_index] = work[bar_index][lo2Idx]; + + // + if (se2Buffer[bar_index - 1] == EMPTY_VALUE) + { + se2StartBuffer[bar_index] = se2Buffer[bar_index]; + } + } + } +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xdon.ex5 b/BKPS/14031106/Indicators/x-saherelm.x121.xdon.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..7d266b1b7194c1ed136413a283481603a073f551 GIT binary patch literal 15582 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 R@j_fC3m{~?Cp|ER{$I6hDK`KB literal 0 HcmV?d00001 diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xdon.mq5 b/BKPS/14031106/Indicators/x-saherelm.x121.xdon.mq5 new file mode 100644 index 0000000..49785d4 --- /dev/null +++ b/BKPS/14031106/Indicators/x-saherelm.x121.xdon.mq5 @@ -0,0 +1,692 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XDON +// Description: XDON ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XDON Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XDON" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; +input int donchainLength = 40; // Donchain Length + +// +// Presentation ... +input group "Presentation"; + +// +input int startCalculationForLastBars = 1000; // Calculate Last n Bars + +// +input bool showUpper = true; // Show Upper Band +input bool showLower = true; // Show Lower Band + +// +input bool showOpen = true; // Show Open +input bool showHigh = true; // Show High +input bool showClose = true; // Show Close +input bool showLow = true; // Show Low + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 8 +#property indicator_plots 8 + +// +// Plot Buffers ... + +// +// Open ... + +// +#define donOpenUpperBufferIndex 0 +double donOpenUpperBuffer[]; + +// +#define donOpenUpperPlotBufferIndex 0 +#property indicator_label1 "X121 O U" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrCornflowerBlue +#property indicator_width1 1 + +// +#define donOpenLowerBufferIndex 1 +double donOpenLowerBuffer[]; + +// +#define donOpenLowerPlotBufferIndex 1 +#property indicator_label2 "X121 O L" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrCornflowerBlue +#property indicator_width2 1 + +// +// High ... + +// +#define donHighUpperBufferIndex 2 +double donHighUpperBuffer[]; + +// +#define donHighUpperPlotBufferIndex 2 +#property indicator_label3 "X121 H U" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrAquamarine +#property indicator_width3 1 + +// +#define donHighLowerBufferIndex 3 +double donHighLowerBuffer[]; + +// +#define donHighLowerPlotBufferIndex 3 +#property indicator_label4 "X121 H L" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrAquamarine +#property indicator_width4 1 + +// +// Low ... + +// +#define donLowUpperBufferIndex 4 +double donLowUpperBuffer[]; + +// +#define donLowUpperPlotBufferIndex 4 +#property indicator_label5 "X121 L U" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrDarkOrchid +#property indicator_width5 1 + +// +#define donLowLowerBufferIndex 5 +double donLowLowerBuffer[]; + +// +#define donLowLowerPlotBufferIndex 5 +#property indicator_label6 "X121 L L" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrDarkOrchid +#property indicator_width6 1 + +// +// Close ... + +// +#define donCloseUpperBufferIndex 6 +double donCloseUpperBuffer[]; + +// +#define donCloseUpperPlotBufferIndex 6 +#property indicator_label7 "X121 C U" +#property indicator_type7 DRAW_LINE +#property indicator_color7 clrCoral +#property indicator_width7 1 + +// +#define donCloseLowerBufferIndex 7 +double donCloseLowerBuffer[]; + +// +#define donCloseLowerPlotBufferIndex 7 +#property indicator_label8 "X121 C L" +#property indicator_type8 DRAW_LINE +#property indicator_color8 clrCoral +#property indicator_width8 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 7; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + donchainLength > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + // + // Open ... + + // + // UPPER ... + bool canShowCOpenUpper = showUpper && showOpen; + ENUM_DRAW_TYPE donOpenUpperDrawType = canShowCOpenUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenUpperBuffer, true); + SetIndexBuffer(donOpenUpperBufferIndex, donOpenUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenUpper); + PlotIndexSetInteger(donOpenUpperPlotBufferIndex, PLOT_DRAW_TYPE, donOpenUpperDrawType); + + // + // LOWER ... + bool canShowCOpenLower = showLower && showOpen; + ENUM_DRAW_TYPE donOpenLowerDrawType = canShowCOpenLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donOpenLowerBuffer, true); + SetIndexBuffer(donOpenLowerBufferIndex, donOpenLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donOpenLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCOpenLower); + PlotIndexSetInteger(donOpenLowerPlotBufferIndex, PLOT_DRAW_TYPE, donOpenLowerDrawType); + + // + // Close ... + + // + // UPPER ... + bool canShowCCloseUpper = showUpper && showClose; + ENUM_DRAW_TYPE donCloseUpperDrawType = canShowCCloseUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseUpperBuffer, true); + SetIndexBuffer(donCloseUpperBufferIndex, donCloseUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseUpper); + PlotIndexSetInteger(donCloseUpperPlotBufferIndex, PLOT_DRAW_TYPE, donCloseUpperDrawType); + + // + // LOWER ... + bool canShowCCloseLower = showLower && showClose; + ENUM_DRAW_TYPE donCloseLowerDrawType = canShowCCloseLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donCloseLowerBuffer, true); + SetIndexBuffer(donCloseLowerBufferIndex, donCloseLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donCloseLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCCloseLower); + PlotIndexSetInteger(donCloseLowerPlotBufferIndex, PLOT_DRAW_TYPE, donCloseLowerDrawType); + + // + // High ... + + // + // UPPER ... + bool canShowCHighUpper = showUpper && showHigh; + ENUM_DRAW_TYPE donHighUpperDrawType = canShowCHighUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighUpperBuffer, true); + SetIndexBuffer(donHighUpperBufferIndex, donHighUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighUpper); + PlotIndexSetInteger(donHighUpperPlotBufferIndex, PLOT_DRAW_TYPE, donHighUpperDrawType); + + // + // LOWER ... + bool canShowCHighLower = showLower && showHigh; + ENUM_DRAW_TYPE donHighLowerDrawType = canShowCHighLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donHighLowerBuffer, true); + SetIndexBuffer(donHighLowerBufferIndex, donHighLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donHighLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCHighLower); + PlotIndexSetInteger(donHighLowerPlotBufferIndex, PLOT_DRAW_TYPE, donHighLowerDrawType); + + // + // Low ... + + // + // UPPER ... + bool canShowCLowUpper = showUpper && showLow; + ENUM_DRAW_TYPE donLowUpperDrawType = canShowCLowUpper ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowUpperBuffer, true); + SetIndexBuffer(donLowUpperBufferIndex, donLowUpperBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowUpperPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowUpper); + PlotIndexSetInteger(donLowUpperPlotBufferIndex, PLOT_DRAW_TYPE, donLowUpperDrawType); + + // + // LOWER ... + bool canShowCLowLower = showLower && showLow; + ENUM_DRAW_TYPE donLowLowerDrawType = canShowCLowLower ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(donLowLowerBuffer, true); + SetIndexBuffer(donLowLowerBufferIndex, donLowLowerBuffer, INDICATOR_DATA); + PlotIndexSetDouble(donLowLowerPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_SHOW_DATA, canShowCLowLower); + PlotIndexSetInteger(donLowLowerPlotBufferIndex, PLOT_DRAW_TYPE, donLowLowerDrawType); + + // + // Data Buffers ... +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateDonchains( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + donOpenUpperBuffer[barIndex] = EMPTY_VALUE; + donOpenLowerBuffer[barIndex] = EMPTY_VALUE; + donCloseUpperBuffer[barIndex] = EMPTY_VALUE; + donCloseLowerBuffer[barIndex] = EMPTY_VALUE; + donHighUpperBuffer[barIndex] = EMPTY_VALUE; + donHighLowerBuffer[barIndex] = EMPTY_VALUE; + donLowUpperBuffer[barIndex] = EMPTY_VALUE; + donLowLowerBuffer[barIndex] = EMPTY_VALUE; +} + +/** + * Calculate Donchain ... + * + * @param bar_index: Integer, Bar Index ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Donchain Length ... + * @param _ouBuffer: Double Array Reference ... + * @param _olBuffer: Double Array Reference ... + * @param _huBuffer: Double Array Reference ... + * @param _hlBuffer: Double Array Reference ... + * @param _luBuffer: Double Array Reference ... + * @param _llBuffer: Double Array Reference ... + * @param _cuBuffer: Double Array Reference ... + * @param _clBuffer: Double Array Reference ... + */ +void CalculateDonchain( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + // + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, + // + double &_ouBuffer[], + double &_olBuffer[], + double &_huBuffer[], + double &_hlBuffer[], + double &_luBuffer[], + double &_llBuffer[], + double &_cuBuffer[], + double &_clBuffer[] // +) +{ + // + double iUpper = 0; + double iLower = 0; + + // + // OPEN ... + + // + int from = bar_index; + + // + iUpper = open[ArrayMaximum(open, from, _length)]; + iLower = open[ArrayMinimum(open, from, _length)]; + + // + _ouBuffer[bar_index] = iUpper; + _olBuffer[bar_index] = iLower; + + // + // HIGH ... + + // + iUpper = high[ArrayMaximum(high, from, _length)]; + iLower = high[ArrayMinimum(high, from, _length)]; + + // + _huBuffer[bar_index] = iUpper; + _hlBuffer[bar_index] = iLower; + + // + // LOW ... + + // + iUpper = low[ArrayMaximum(low, from, _length)]; + iLower = low[ArrayMinimum(low, from, _length)]; + + // + _luBuffer[bar_index] = iUpper; + _llBuffer[bar_index] = iLower; + + // + // CLOSE ... + + // + iUpper = close[ArrayMaximum(close, from, _length)]; + iLower = close[ArrayMinimum(close, from, _length)]; + + // + _cuBuffer[bar_index] = iUpper; + _clBuffer[bar_index] = iLower; +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateDonchains( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + CalculateDonchain( + // + bar_index, + prevCalculated, + ratesTotal, + // + open, + high, + close, + low, + tickVolume, + // + donchainLength, + // + donOpenUpperBuffer, + donOpenLowerBuffer, + donHighUpperBuffer, + donHighLowerBuffer, + donLowUpperBuffer, + donLowLowerBuffer, + donCloseUpperBuffer, + donCloseLowerBuffer // + ); +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xpv.ex5 b/BKPS/14031106/Indicators/x-saherelm.x121.xpv.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..818ecc25795a51dfc2941ff045779dd403f4b508 GIT binary patch literal 40166 zcmdSAV~{UA@GdyEZQHhO+qP}nwr$%wW7}tpGc&)jweNpx?^fOYaKCS-I_Re>l_#lG zs*;Yl7CV?TP%4TL7!VN<5HQdQ7|{PF{_Q=fU%_`-0 zNa{qP=*-u`4f&4e5yHP3zeOP*mhoNIHXxl!xpIpwiD*9|A;XC7O18xWi=LuYB>9;y zlT+v2F5sQN?ND;vajgA5_?h+4^-yT57xfw7x7-6?`ij7(eB400#vGWCI(aAUu(ZM@ z<(8~mTz|quQ|nf*rtzO^S0X>c2T1E09(lvQ2x%I|T;KI943Jvu>%ftBhYh7j41iiM z5C!tsI06B&R?{8719Je5??A@$F?$7MB+9n~E~3WeiwB?HLz4 zx1oJGEeojoT9V2OT$B)o2eAOs%wp$EU^1N40drz1dryR3A@1jgk89WiK|f^S%jni~%!2T$Mtw9aMJB zahowykrk?Tm4ZJSPL-2hbtk9@qOeHMskcIA(v1Qb2x1t_Af4S%zP`g$b7}f%kxF#d z?kk^O35~?36<~|s%3fK0d1-SCM?i(b&hap*h%Z0vD8Y&9_Gh1}cl}MR%%-f4KkM8> z8=|E5GB!5(kt!-upyc%|o{`bGC?8Az%>Aw}RBoj@c#wngfAyQ%Ys-V1{YsK{r-nQ) zok_{|HfOr8mu<3Eag!q^Bs{^65=#Z!O#~G-tgg3eZ9 zCishSFyobG!5WsJrF7Bq>5aOn{nVtkm|TaN>ItHAz@F(OfkGR#77be!)u$Ll94IQDCt$yBg%Tjp z0-29_$m?0QjPG=d*4|Ua!Ug>dfp=#>@c}Fl+>H)XjMeFpiG+Nu{SS$^EPiW;nPe5;Tq*#;CDY$~QC|3KpZkBYm zM-UP72}-X$9W-NdFE*tD(nB6!zadt^Jk<^i$H%qhs_+J*Jb@RWZG5mXF(F7xJlkBA z5<-Z`is&b6C;{mIrKtV9eF6q9N?pyNrug+t`Pfb{+hjLX8=UWvipqwB#hN&)uzdVt ze2yTQJ@I)mY5H%wvBl#t%b5~ER(8V;#=_>M;MqHgCgq6d@4rvFGV!M7Y&O=4cYPz` z8Bsi+AO#+U24j{}rHHoGw0ge)>+4^-_;_e7V5pZ{O0;n+9kzt)>CX#7$a0^HEs_Ih zCsv~9#J6j#hsNt3J?w}HG zC{pJZFQisc({!{azM`^)7|@mJj1J&$>GymB>q@r}|D7h%s6q1VkX%`PZ$5znN;f+c zD$C8p_X66mN*F?NQ-;A=x|E0$HND?ZWyRQC*Yz}5C{9CweVXJ_OAI3ynogzR+pk}RWfnX`Drj~rfz zQ$+Ukz0pf2v@46%P=)fGQ=?>rRfJ&L zI5ol9X!U=>lX3nA>IY5oX~d<^6%l7l?=yHTxsWZhs4g(~B^OALP7?s_t`3OE+%vxl z(;Hi+T%s5&7_h^lM}Sv+uEZ^gnF~EoB@P*46TUq_9iimR`CQpZlAAd}<_t27qE%ii zUALd&;Ce+=0*axihHE|pmcwtLN2gZFKWV3_YIwyZkE@Px94<>Wk1M6iIg?4L zJetGWTj$BY5FGpsyLe_FkF87NfU6hG%asOelILtUu8qhZJgN!v(s*Ln$mv>fnlag~ zNW!^$P+6D02#8$&bKh)X3xL8nUBdgcFmlSZR@wU{MnV)SdA0VTo~$+Xjztj>*Xz@< z9vH0%iyxJCc^oR=tsmD!(kl;!HVLgBxnFwiSWgYCf`cy$kk^zgu-A5)mwMpMS>F#Y z@pp#AbaBi6@30e0;U$CMn-mW%`H`c3_<|F_=^y;m1;`KymcD`;5b_(io?ne#-jY-J z4l1ufQ}w~1X#2eghsqT}&=r$-j9%{j>;>hXLQ1bhuVT~a{CX;gL*efH=2TZVgjd41?faOespQA1VP){ z-eSachs1HX9^70e%dapvPerDqByd%-xd6e&fqyRL)h_=FoCWOOhFM;KJE&YYKQy@V z(P6QiXN<$f>{M3p6!U8KWk;Fq>mbc?J2#J>OuWyW&a@n|Ja{5*w$+|ZAdqIkxd)$s zM>HMZSRJUn%}Ii*GA;pST|b^_54%x}>yn`-=tt1l>qy56E8~q{#M1z0!ZlV(Mki^k zq!|0a{}5w}XKVV=ZZ^kQg5%bU?4>a5ksA`-(HqQWnaCogcE|S>OJ{f0fAlw+B$A!x zBM_-y?ZPMKi5b?oUTTW`Wvp@#v(Bo)9p~72l)x0F#{dj?j zxC@F`j#FO;#qm-E3XHVex!oA4L2bAD9zseH9|~>}cfABaS3B%p)@w>!bkec=m*wC? zs@GncfqGaeq0jYQ(W}HNQl8X2Fj4X!#O{5HGQT_6Y-C@2AOFM{so+w2UVIr59?;6?3M}^EV*i)s2$dBq)MWl_041VvMk9 z@Xp%1-xTG8=o@sM6Pum}zy;|9y%MUrg%hl`eU-#5AYWUSc*setW79fp9meJSej zx?B6eh3V@szzCn2r8gGvWh$|TA})1ns~cQtyyb3` z_CXC;O|GH2(mHVFmR zuAI4589PsWnjk@4g-OL`=&VEBOy?HEe0fDL#2AX&_mr%x)rF?TfGz8b)w|{pR5=r z{B1&a*$Wq2F|lNK370UGSi@Jp#UCDONC4`$B5&WLzlp5;_>%&Okc zKyhHGYA?b^93$8m%1PmyIOVF;m|WWg4Hc_Obk1AADyINq;Rd4&D}z?$HCe&;AYll` zb=&9cRbbz9*|@Uj9nFplgn+p&kqdbVi6HdowVNWrn3@0dNat7TgaSWMUsOz zhE&a0{-jdIwGIepH9(x&xFle$t4s9!gGWK5KU&kGuBDzjIrmS8E!-gdkr0q^0+VoD zXOM}G;8R`n#9bz;TnyI>tAFX=BjG;$iB3t2#kGH$k~0TU-O;5xrqF2EHb67L?RG0{5`Y<4 zIHT`mQ#mP}F?iVPi^Sj3S=y0%5enXldN$4rWhean#^ue4jFW5{!7=e?G$aser?Ohiu zq#Z@=$}BoOWMVo7X`DD$$_Ay?_YOo~jx%bpr7=jRLYW*W55-6g$b$U5!2o{HMF7(O zfn3WNmE^~RwDWOy$BW2{-DNd7DAJsG(YgQ~gZzcrCYZ$M@iMGJdA+%HLFyL##6n4W z!j4raV^-3jZY;_DhZl?M*^;5VIh~*_IT4?*sg<;?bBe=gC25Vs>dee<*DqaVf=#%J zbO{PdQgpjYz7^GQMqvLlez0WkVZlo!{jrp9mi%W!>qs~~TgXAhbz(Qw=$Tz`Gw2y+ zv6*XU+nmLKaSdKwFT51FX+IW(-qYF z;0jdYxQdA}JjH`gp^W)EFtod4$}wMf@{z@!C&5^SJ@BeN-g+fEhm7`1b9wPww3m}NFO2*u>6S>15NH1NnY zGYF|)BL!LS+>na4XiGc+qW`b?FA6z}ykEUKgV8q;y7bR2VUXEJMj;y-Sper$d{8wF zHuVI^$d;KeyuX`AKW>y1j>{cVwk-Wo(GcS z$OMh+=Vgn^T~2ObzsAD@en0YQcK)B7$YwpjQEYq`gx+L%1HA=wD6l$a_Er3M&Q7@Cy3agE^7GK*c-` zMiJ1D1|>Q_hK$JLqi5B+^I~#C=w1nJ%doU&^7<^Y z01xuPSGX!W|M!PRDeWV2__YNX(%taT&Yj0^x3 z)`H%14t-mwVACA7g z1i^3rs{U#tKX1n3Dq=-d+s(tJ{A1^80nh8iLvrv0GL7BFq*owYC>sulUe%#Yev=}W z)JI4cM=COQCO6$eOewb({AtXH=dxWK+=^N5I$x|o@+oaNL-||kuyC*)tn@lSc9q$* zON-NfI_WZxk+7P~%*0a?Ui8k+Aq!~T1 z_~BVMLdH!~&&B31ob?q*+y6q?M~SY@0vt_e#SM~6;n2;g00^aRDO>p3YU17YQ6PD@ z&1pjd2dGDE9EfxvkdZ*zYHXeqTz!DD=Lq{%`mae2zD!3K6cb9$L#L|@gHGMxSxmwr z-DFG4ut|(!5lD;CM351$@AtQslxwE}y;NwsGu}20?(GceMK0*w#CtQvS%$1Se5#?p z+!;~#n@wh)W4+7?akzJ&CKxZ_<3>quv)3Vt!Rg(t>eYL5Lab|Ps&P3!w}jm2T&tY3 zeW%vq@oK_6#*^SAC&C{<#zWu`ndI350?wP)6t~iknKNMP$zx)HWs`GyK6en_Y>RED z5tvdZR&xp|e)@)z95s%4i{R~A`h>>&;?u4{0|rdiGgy+|Tf?@CZ~qYM6t$qL!CR3F zK(VPkS$k9@rO|D7NVEj@V%cs!YjLoOXnIBecKM9>?X7kNzTMxD9d${=cHWo$!mS5%VtZ3JQ_MT*~pmMfLa2h<6Ni`X}^Nu(b8@^T4Q@A_;OE<5dp|-DTfrH!m ztRhy+ezf^v<8l7l4O?|G>Er#2gL*DJ|0&$C_Q8OUGmN|DkIeMzPuhd|-Wi=2ta9-} z5y>pGnR{-mf=UMLqCY&{r432ZEN5smvvaywG1Ows@(fiZbw=~)T!Nj4TqbSo?b6ot zSWj=b220U0;pokQ0+l}*EK^0uMT)-XhHI*q)SMsfk%09{ooc79rRyiXzH~>5V%02G zNzp&taIzK4SmaVDf>TKK zwOnw-DU;=0`0J;IMVZ2Ax%1K^C|(e{xi8qpHJ`9L}Ik$~3@sUsxy3-vaJ z;)6%lS!cLPd|%c`M;?;}GzidPA3`d(oJ_LEZ21#<|BZ-ZEDykm7h;Z+8sE+vvb7>X zU$f;dp2=ezzJ@HoZba{t2KJqtyFP0isDW4N0>w>=rz|5~^<+lXm6N5Au~yUsg^=!X zY1OJ=qnSAaCOd$E12A|3+(b}Z@wh1`UhgI6@({f82hAqj9>3JE>%f( z%FBjPH0oq5p-1bZwN|G&Zn{5y;Ei=`>1?nXmfm{phHSi4U?aKc@Il4%iQXBX1g(hP;b zqHHw*!};vzLQ$BZr``Er;oYXpFPjJ>E5#mP)X>S%KADfoiD4YeHp#)T1NO;d8sx7R z)3*%o08D;|16lVq3goI3j?b`}WA&7OG)K_Vgk%LfO)+S~J0rSihm4rA#pa0RE}o?S zIl6~oxT%nS;t^>@<7wZ1v4b{ltf4k1&J?k&qy$ALIU-85azomasz-sm6ZVkJFju7C zLHZ;)j0F+F6i`Etr7KVL$)W;43}}u3Vv^=myJ~{7Tm^S2wsutegZMMsN?|Od6mP&i zHq+kw;bdzo^nm19Z{OXlEE8vcgl>}-!1~22j*4QGDlJx2+s_}Y(Of&o0+76D5f}bs zQr0iaDGq6G^<@W0J4-V4pl~LOWL{0~teu&Is;fPacwqcMs0d2hV92`~a4tOPmU)st zAinN+FqisJCK4^=5{K@xdBtQn3HhZp4EurPhL(J&{#6S0IJ`U=OZjWcs^kdw>3Cm` zL1uF9!g$rG!L*L(6uy#RbRC688eZ6AnS0%ldduTYZ3-pnY4GEN>ZFfzVD z;G)jOd61Zq1t^eDwFUAJ>eKq?8!ZF6q?cVaoc}0Ijr5&F^^~+^JMG?W?^kKAG7%-?iQxsFjbilj~ue~EcwFnzil{-=% z5q^(H{9kR8D0Fm3j_w>HZbQE^4XlpxJ9q- z^yBE_5K@z|Amn3l@Y5XGopSVugXka_anndTXog^Y>%nY&-E2*_{ooxp|O^+Vi6zJrMB;sCaqfxUB^i1 zbZ0hZ4J)fcqX+UHZBCebNbV!Pe>1?cYhE7WBn#R7qm(<68Z9fvG#rY1lqvN~8NBg? zq(0q4d5e3?RTll-REGkk9Z-iKU6;HuQ!4ROWBVmU?b|ukMbKraLJ7zp4^oR6+Nev` zvX{pdgB-yXyzo-#ybvSAO*n(=vQ8KiqtXV%Ygo`XhGBpH7`W*7dWZl_|32%3l6JUE z2)#UVf&5{(?pu1|5hw>&uv1u5*{>WP;+cdm-2)}|=NjfB4m&}Ha`aCaIQ{P+_fnFU zhhsh_W&2_6?=S3odp#_G`2PLs4*Qzz+ft0U;J7Q;m>s`(*2Xt^KFRNy(#<%QJ+ zi8-e&Yu@G&xZ8=Z)Sk9og3__}VeL;NsUsuR}t!3bRKTPPFR!GZ3e)HSjGr$YNh7cEnSxl%;?s%@UEo3NJ|4{BkbpL_b5L zzC4I%=$mkstB6*XsJy~z6NFBg^)@X3X^Cv0E@wJ{#VO@|dG}ATFHSr-8nPYVZLj~a zQ1YdE&J-j4un0ll#W3j*-r3hpeDcz(=9y!TYL)B-Vfv`j!JIJEU#GJ8P5^R2F?n*P z4-8;KczmG9QTg!f!79?)%|46`7G6zUD2&D!@DLsZ3c>(>*TjK-$y)%tyEx5S&VDbQ z81*RM=qj}M+Cnxq!E*~3fbxLKXyMj5y@?lBBD*K8l4%g>Be|?1KQM^Upp(MhcP2Urq#4X3*hkne*g9As&WSJ+G}Qp`5eIC3d>z6(xPVX?$)XnZ{3r zSQQ>rlELl%qN6Tmjr6xM=u-O27%$(A5(@wgYl>L2CTjPUHp-;?aWTk?4g&vvfj#c& zcju>%f;`4^$dB~R^&{V65zO}No*|yaRw=SpjR$v$fjQNMdh>-j50jS7_$> zJ0!#bVl`gRJWRiV0(_*RrJJ%QYQS5JB*Pha`#4N-otPF^5SDYmYFngbC`CY1?_!Bc zEE8tq{m_@O=b0bivr*ppL)U=-JcHRX+JPJ-w$O(~R}a3jU(g_QL>umWX`0MWTtV-Y z!^ieB6P+7vb%53AG8!@@*r-;@PCqmud_m@i;>TB`vw1*jB3eq^U?EMSTHvaLtTP?=AKRQL8as)+1D7hEmij1{;dBfjj7C00QyE{C_YEkD ze>#a_but$Y8IUh%)BY8VyCoohq=Ib&$cjrM$DKPty)kY`-nRM&2P?!T+&;4_{M-3N zKZRsqOW5$8Q9cU<4C5dv>z#DjW=DnB>Q$lMNd0WEw55ArS-p$;uBk!tQljKpzLpnFjo^_6&CmuL0lJ zW77LPw_^_Cde^?B|FD-vVvd0wY|1W=!ppR|px;rz8i{hTcStG5Uj@!LZjra9y1S_G zN9+Jq;4P51(yZU~=HfSqm>qmQ4?K1%b-fl_vdy!(!_KIT9)`{>@)Gyd`iz>Pzy zlVirGLQK6k40@oS)%AW90)-G6dAe=OAiOxP>15@~;|!jgWj^l?T7b=KDYs2FNvEC; zfB9#5;&fe0;t}Ve?X21@W;@1&}C(zvd-ZfvLQPf4_XeOp(8vZ*HG}qt$ z;7$$SC*wP66RSfG^q`d{N;MRWG)K&juV~s`5*M9kS9}i#8PB{aRNcoaAW-1YvrEU1 z>^K|9L75*!@I{qA9+##p&=>T(y3(q@Nh_!jb!T1?krXPS&vSNc_$pgaApgwIVy7XN zGObmtIs8t-Xkk>jAKWb8{c^NUl&5A)mxf;e)3N| zN16mYo=ka0Vs4O5OnVpHzkWLjR&!ZxHK3a{0M0vY@)Oafg73a+`fMWOkn27w zk_*5;3-4R3hY+^LbvF;1$D1SE#N`Qn)BDWRf(RELV)U0^R_~i1Z)He8o_vp+lDk9^ zhhW z0>euA*0G9ecF8k%KoMl^rWodmvCH8?Ii3}~vE!FLF7xJeBJVDm|Lvcu+S_5L+9Pc{ z{L}^O0pZ6T#*>@RK5^+?ae0Fl#1ZL3A&f?dT;(0kzl2T_tiJ_?|KWm1867rRFa7$?iP*7>i??A#H1$4n9A9ldB;C9ni$Ccc^KRgkB!piIDzR9m z(7P{Xj6wq~n#K79D!f$r-q1R;`BNUk*3XR^;Y%>z4D>gi4^Rpe~v!gZ&7k$SFnU- zd_TLYa)>H5k5p^59f!@mlEPJn&B4T zlnH1N_I+giHR&Lq*q!KpYDqk6#-ZDJqyy^buY${OnY3HndyaN59zMi!&CcUf3vzu^ zY}36LQ$|Anh2^pFrZ1QycrYUD{!mrQsrWI~RuhUwWRnc=^jOZBiut-;%9`I8=Eb-; zub-{$Gtc;&ycEU+mvVs>IKilSg@-5y^EwfbDPm@9K*>EB4ea3fV+8wF9k=Fo)NSYW zp`*Gqv{W5dQeS#-bgq0Ur|aP>=&fWLd*uvOGV~KV-=9*VG2(>;nlxE&tJeW|(TK8Q z&I|`9w8bZRUp6;gq%eYmjg(V;gj){qIIWeuGqmxBaC{i@f*m1Ido{xmx~6>Z{-mGs zMU#F+Kqj+sRBXhp1$r~mYvqE=Kt@eR9Fwtq%elP$U8Gei{E0RUi5*}Z9G>RP3460j zlikSi3BN|N;|Z8Rlb>QT%c=Vv z;c7Bq*oP;&n=Rc5rX93rvens|;RG>JTC^8l2C;ytwD*lI*x|)Mgx=N( zMdTlEk|<>;Ck*jv`eK+#9BOBP)xmKj+0Ov z$im(rM^7Z@g!Kya%qQp1=ZhgS1BeWUR@BFj7;~qOGRvFOFKy}AX;0%<3kkqT?T-gL zp_-ytz5_2TNZf_r^!%9N^t3pmQVXNf(NK{}IVWVGfJTpCtCWh&NV)HdH{+oaC=rDN zoe|Brp}m^>i6p9qm1=d!ORZqO1jocxWyUM-3fQ9fnH=Uz?AFP`>M#yIdD*8M9vfF0 zWIm&SYLBM-`L*+m?`9Wj%>gAKy#GZg--PBQ)0zz%NvBl}(`2WjHzpbKvo`LA zN-TjU|Ivhw)mjL#1IeqUU3pqu9b)6QQnK)oOpy~AQutrlp# z=)}TVGrIxI7`bgvw&T0ue7yo*v-2~o z9nd&a2ga<|4JW2OPXwpv_z{wljyUHA{h*rf#w%57C!M zi-E78FTIl-*_{R~|4yALe4z?A2dt|XA({-2VbINdw#@uJaDxc%me6gzcqR8ADecKy zweH_^oB@Qx=|_Omp4MUR?osX2P?}26OL*NX`_B)gDkC%eaZpR4;Mn1a~H zNA8Ku+*y7Gr&@@9Vy1>b+-c{bk|Zq1DTm=S9u6{&6-G4X{oMtH=R-y*ho^oalaGpvxhR1kNIn~d+$mp;p z9!8XGb(BQn^rd`mOdCEdp1+2nU3P&bm9w@AeFAdXhn042!NAmFO&Eu>dBQ=0d7kWo zdc@xv>1Yx4bVTmMC#L*o4JL8(!k}{VfE=f@73_i7iDhyanCxrn>DSarn&0Eqgkf9; zDF*xNS+e`$SI5S6N4s1O?Xmpd(gc*N8gD`7b336^p9^{_m;RsL=h0H&>QK_}!OB4bu9?kNeU1! z3*GMqTLnf{sW`+tiNhpYNMp}#0<|Yx8HQilH(=|9OEXkB(mVI%OhX`i;R?~l|b zZ?WFmKfVejfj`|tU43hG7)mh0@VRTznWlUZX zuvUz(=Ufzelu%Yb+IOMEBWGL~`F#4p8&7#Vxc5+qXA&_AbAI9m59)N2P%dZ3Ls6nw zlvjTBON$@1ILe;%+;fYz;g&jQ*%JQlt^H4rtoI)SP9@FH8#ia{Zi1|TD^o28$2WPj zl5EUXx8;QZ95$iQzB@2gT6o{T8>s1JY~u z27J?Sw+1N}{=B#d{hW6_9dXLYq}_#VU`*QJ{0-l#5R%WL7je>kizG>_%m_Jin@4ZO zj$f>(CW^s^JA)|t^qaoqF4^@ZGd}*r;UO=1e)^a~7cLCkJZ#qK3MgMNHea)*!*9OEsDlS_}Sd@E7T6h%9 zq42i#vB5YiDE0^V+bL)L3q>KPzJ`p$qH`YaO)7Fdq_pq!)H#L=K*DJ(g{`hhOPB$~F3tWGI{) zpggX*!z}j;DRAz{i%7TWf-ktA2+!i%%qW=;(ix-ZFC>KB?*Pwi;Q0O098;iKjwb8C5gXG+x!6i2N=x-U zan{`@vVoqvh4)JO&_Fo82ZV~>Aq>jp^NMtxc{VNPo}MNzSnx@g4u3B;3 zcO7LU@yn|)k9-z63&AE`hk`{o`iC3s;m;gHkN}l|j%Jtp<8k|m4Huuff^H(E`)9r$ zl?FU3=zisdsgceVByuqY#PD-J+&|gz`l0z-Rl{*tB+wQ*aL4dWS<>y>W~M!;X)jBQ zrEc!WOreG_zQ9o!BRz8i%#GUx>CersF%_J-RrsFQC7`0q>~-S2FQtv@niBh2YkBTU zB=8WP_3w|;quB_%cFTQNk7t_u1E`)2p}7>uR!!5w1S;V+dm5aY)Etse_KB{c9*GEw za$xJX@ulviZD>Y#Vk~a2(n>xDTW0Zq(gK!bR+AZhNLSX%uN1g-Cc8VS0$?5AYRK|i z&Yd*!Ah4S&5pxR?pFc$wm%z1P_hRN~%M4CtCVHlgf_%@0+~rnI{`bHfyGNjc>~~Wv3w3_~ab$Ew0RQwKW@9;;nIUU+dhx$BrYgHR^GJ?%QwrS~1gN@#cT1K( z>4St>y`jVD08IqK6cjHN zC|F_|DFY~O8G*ZHO~MUP&Wo1DO^`nqM>K&wb9Fd@&xWkPdU3l|n@5Y_(wU`esSq%Lmm>MhG|_=FZS9EiEIFRyOl*$1N^r zyi2m^j(*noJJ z`Igf?snKqgI;yST^r`*t6((V0af+@+-3AU-;NbA7>%Ka3m=YU{j}`Z_5M;f^{<&u%b9+4Cgj=Mus}1zgKnPuRaR>TvV52RemG z$`AIpy=~4R(JKlc&NQoQy}Hh8D}Kt{KjpE;ca&s(?N()Lp&))@B0Dlm>Itt<+3xoK zf>BdvOoW^KEY%#(Q0_&11m1MS_Z?+tvY2?2)VTSz>}D*-pcc5*ciK~U{m&U z3W>Dh(owx&KM8e8P(VYb(&myIAki46I=3e7)$Y{1m$}CE!S}T~&z3xY?5?q#BeC&6 zTythyUl#7ffnUOEXFI@*Kj!(h9TM2Zw2zYGqEk5+7|-P8T{<`U-_$h0zMwh+;cdP;QHs4CWv8vo8guPZ{);>P zQzt~E%Qcxa;uvy#<_cr=8jdF+Vu;gtTgW4wI%H*UGuX5=w}I@;l}RF0)Dmh)E=b@&O~U&~eiiHf)JH$xTK1 zy@#`SCum%YE^KLP^G=Wd{u+$3IZcw#IJCFkyJdFYl#Bg@5WE!!zNGeN^{TGfbglNA|j(TfypRv*v$Bo!8cq5R3r zvbOMM-SvlHP@+KeSE!Pj(@=&QAF*%80=`RmC@fb?@4#08ldq!SmGhlRJkDQd48{rk z-9aLJZ?^cY4AmxofjR|eIe}^nl#`uc3apGW>7XSp_B?5|U;i(18eY;8^zPY2ACe1J zZKOCP@XX6^p+X4mK2|>-J$sDUdGIXh`-a%9vz!oqEejwIeV#18_Q0m*B^N#A1ZB{^ zCGB`WI1uZA*r9eWEaP&rD&^(Nu(q`eaSqi?gZ~&9-?WbCQ(U!y!eA6<7xFY)5xVIb zCz_PW9R8!W*0gN^ks*%|oa>b%>EiqsEFP2cOi>1UttJ&hu1S}M6A+4I+%xe@k%yf3 zYPZ$Z$cgpp^{|XQZQhs2y!$WYmcpvYtCuY&r;-co+FKrp-!0{s*>|7Bq6Bc(~ z8-1gLAR#bhS=4ftlpl1W?R8Grv-|@7e077_usJ1F6jKpfHBgGcXnz~&Xx%zJ zpTYYyfcUDW!ay2RJvNG7{@;?JSXsMzyHo`SD>uP%GaP zywKk_t($plQA3Hh$wJV2Hkk%k-&B>Iz7eA37lfn)o@FEyEW^ zOY5Q~40e9;HJa)H=#*MYr0M#Hs{f0we_-#UU*mq^*ftv5wi?^EjmEZZ z+eTwGwr#UXV>{W&x~{H!-Osc43+ORNXMX=VzxbRJ{9#}-I|^+>DE&fI8TIGK>?=Ov zHizv7OxzBUk6J{CPSX+@aU29UH*oNxVA1vxLVC5>#B|ZyRrs9er7{pS5U10jHutlf zY-FJc|LvLm@{Ah`X9!h97vwp6KiOT!8={?Y>bt0WNV;#TB2(l28QMKZwj@AWupo<< zIms`1SIit$%0k4lK_eB|dOjxYODDy$Hfe*@nO;hnkTS$n#_6`iw<_I8SB9^4bwJt^ zD@`(Q*9&=$UXt}{C@Ce_w%npZb#xq1!M)1JKLhm*Uwwv?VJhy{)~1rLEMc zUV353N9Jd>9^bjIbfritl;;82Dxz?aP12k=1AIk}4z#>McX#b5O*sLa_K3s2$^V`W zj1N@IwN~l_1)0(%g$tdEhz@W=w%PE+(Xe3AI`fZ!H_h25vZ>oeGD;eS<+Uk*$;eId zqQxHsRQoyb4GRl%P17@`Lx|0~948gSRG3QA*2F{$yT-irz4-AR6T?==DyoXKSFs}S zHM(^!jJK~dSTj@`MLS&I=(6sP8ok5vcG0WXgK@(c<;QW6U!ILu0r|(twW(z z_)nO6+`!*36d#cF58`y4s~#tObTNhErW&ZO;0&z2DUwHA**QE<0tNjj$dilaPHS4w ze=0NprWftjub?)W&m}syY8g>Fdt%t@gPb6+`$ozPZKUlwr?Du0P$`h5sd@ zR-OxtfCztU_BsuT7V`I$wSXpWeJjCo#UNoutb{vN&OGO@C(V=T6qP#*tO_;$88)+Y z2WV$x`M&pTel(?s7l-pK-2AYX$g#Fd*aP&L5o=(hYJv%2w7d2wF<9s2otA>5j>X??FO?k;98OND4b;DJWKMFJ9KP6Fq?h8%`}{y zJ7#wGA|o*EVM1slH&-Y_KX8~xIEjV2xS#rjW^g$7k(^p-rN8TjoI@7on1U(<)sALt z#R|v0#J|^*E{ixU6Ts@yDu^_Qvn8QYGu|Ov%I*^c$Oe?{0e`cctr&G^fbDMr7M!4$4u5&${TZtHtlTFH(Dq>l%gW8chL% z@F$nOzfkeRka{s2SZvPygCK`W9oh;%AVw5GWkF{(-TR?|#1sa=WQscfjc_ew>ug~K zJ60D^tq}fE-re#|#pv&k?$p%EthLw22h2^T+XTv)FRJ!zl^@ByPISt(Om7A; z0D8WT#}5?()~NQc=U?L()>a@Es~yX~ff)DzTNNg;9XmxIV&8Fn_!4~Zk*;J%5j3L8 zb{K!(WzLYiW)j47!JXLeycBW%Tql}=Rq*XZ6n2!uBexLBVOk__&`0q&kj1XvK_KBz z9*o~=q!(T2v=M;sGSO%WK2w7e<3X@4L}}4()P7Arws=ZX+y_Li{?4d*?K|u5faZHk zKZ3i{rA-`%h3^^Dlzd~9-`7-r1Gf@XMR6ZVp>~CwGW_bZqj8@FYCt`fQbVW(4TLS= zr}_SBTp}f0fnxVtz!YDKB8@{PHr-q#Oa9jkrKVIZlqUje(gt~b?D1=*wd6bO;ZbP$ z?{i@U63_C-`)j>m+$~+P-*ldZ%2y<*&;&hBx=YrTus<}4R++^Ym?aJ#Pqak0tcmB4 zoHamBx14uI ziKuaYXx&>?(HZ~b!mtZuxnGWmGBJaoG_@J{e1l7vrkj)JfEvhijv;Sjj2NfE_$0AV zgc#!a?+DVmRYTyELEyGJ#*JXnv_F;rn<{@aVzKtb@MQfFuxCmXt9We?&*C27g*B%; z)y(Q0q)xgv>pRLLIriuo0Jr7aVV~k8@(gl@(EkAp5!wm)35RY(%QEaI#9Q8KrasHN zMn$!Ix?_jch(3hcA*dCdWpmo>C|N+67yuF*&M;-aGDPH3N91wif#%?Jh*K;F9@T0R zg-)pH0!6Ya_%bGlmN(e|t1jw-9;VMpRb3>8o~t%c29+C<`9!fCkVI>LsGOo*;M3n`X6g-f~(_V+WYU)3>Uw*kqzkoP}YZr&z}F_wS# z*%qL2tpfj63Xap_5Gz)A zAIxe7in8ci3=yN;I2{-=4I7*wz5vk-TUwamgVo&2oUxt3rCP_4-&f_?xZNafi@o9| zLz66O6Dev}nQ^Z^J#|$BuSeewS7?3>DOQTzU@=B_h56yZG=h^!VhK^Wl8mhlgzUD< z*NDJ!o^HA}gs$12z!FIm?J~VGTDU0#KP=%prot4N6Z!f4A*bm)v-`*LU8DAq^mH_a z!Ac~kUD3J2cH$*{d~fss)&|rsXk$(m2~=JXGG7?RLkhK8Uc)Ug2Pm#HjYi;Z;tpUcQdn@JSb8Rf$4DXx!Hy{kOD>79;%BBk2)4O}5)=iYzk zAzs>o(7RWTekLr-z8XAACO4Tv@ztZ<;q8j+H#Lx z=^f6bMK)q!I%l>sqT1H?i5AB)BKDu~5(mCn$Uj!iNEZ&o8P{*sUxJr{$er?MxB2hX zjJ{d-35=CV$dnk}v8~@}_7kLBqfeg_QH06IJ&#!Ss`poc!2@Vi+O~@jdB$Yw z^54d(b)CXlIY@wF+2x#_{8lcgISsFoO5A~LQwe{w4JIYIOquoCB!WW`A6!GW-}X>< zmMH$?Ds+{X zL62^Ryo(aq%E`o+Y&7rMz6a)cN!g6!Ig*bG#1Ta|bDStV=bqT!)@n5kc=-e(Y9W6$ zf=qLgU-iLZWFrZ}a-s#8J-&n~zEtoQafHPDVJX;tF-LrY-U+}Dr@M1>Ccp^7(uJ-c zBL!dmS72o$saaIqgI)(ybiGwy2&S%K5!{AulXQ#M{Kn)S92AYtrb{o*Gpl&0xWJvI z5Ml2=0ZXK+RcI3k(593<)R-jm9Jblt`J*q{r=I$xDH1n`&(ed>Iulu@-vJo&19z16 zA}SU>caK13wtN~f6m`h291MDE8$hbAHUND zS~l`FWP--Ff1m$%z`bM=fH#A2NT0>U6NA|D(lHJn^lV%kSgz3dAV8K!%l$wJ<^jz+ zmGvPc(Yz*syk>=Ki0*HC=aXLM6UpD_xqP8BU0E2y!ntvJi0O~KX5?1FCmOSYA2@Uj zh8dzkbOU+1UGMtYf)VijS8Uh%aY)gT)YWymp!s3^bz8A7Mmk-%l;lf2*8 z{AvCHqPC*-`V<8(noAV9 zkRk`EMR)F$&1{A+tbMaU7~Ij^1IZHmsjMb)>8l4wk{B346A1`~*B(W1^sy=aSd4H) z%na6X#4cl2@YZmvWMQ3%0y@m0|(}JWIQO!2*L9N_pXgpg~gV9jaJzG!+Uotj5)1C47mqIe-Uhv?LDkAR!tz~&Pndn(As7l~;P{y$M0FkOJ{}3)a?!VVBKCyck007sa z;7#g7gok$fd;I}tBoX7)%UG0gQ<gp&yBcSfEMXI{4%6%ZlEq&+oTn~Qc#b@ zmj)xOm+S0pg3B$|eAxJtIDZst^|NdHckzWfc*5BPCvr9fq`G-Tj31n`#q)&t-@<>2 zL5A5QsuxfCV9WNhNS@?`0j4anr3Frb=s1|N*VYsArQXVJEQfqA#O$j;z$~oP(61&{ zk*owX`Zf=xQ_3)y6suyoXqSAaSq`q<5-VP66+Zpz9byT`5!yLm^Y=1=7zW-Ww>{5B z8#3uqsyj{Kq!iR89cz@Db^rBuUd~c5xteY#G@XjMKzt?a$b5m$bakzaR_x%OdpYAP zITOgz0YvN9aL@)2Go|-ID#gvW3Tn3*z=YdUX!I$g7Pf8<2qVhhDybbkWU*(4oqL)1 z`_8|*fh;-KnMPS~U3~3;wJhF&16o1ot{d3fJh(3+jYWS;hu=yXxKykN2}raw%ldo- zlUTRyCeRr!itBz@DvcZDeV+eScyn(kb04hyDDdfF+;^H0n)_U{38W;e=*5AanVDB>8`nbp21`)?{Cpj^R-=b{?W zrj0D{r@AO7WY1GTS>i?K+k)#q<4yA4KEQxu*Y1^vkAU5LWUyF z=DqcW+~@1OJU)&`th_gKeZ(!T;RGu`$Q;OV#Aig}x&&e3X3yi5hiu;z8jC(d?(PQ` z?+KVr;Bc7E&o&VgwIjyCS7#g{^k~O{xJ1#!xnGA4k%v3^Ho_CvB9QhV15M}b5dhMU z(?1nhPNSCMsfW=k1+%9~|NP|$sl9IOER<_P6hHseK@@qc+qRWz3-)pUY`sXbL_0u_ zY42e~i`>zyw~JwTK1R%TR2IQ|H#K9IFug?EI;j#^U%MsEyLj(RHVCI#q;gFwiI(h*O4Xls6{fB^2$GclBS&hOu5c;rKE>Z1?UUuFOP#m zV);g>)Fx73F%Tn`ZxT7%{DgLJE?kdm-aGb7Ig{DlyL`KX6jZlDK=-wUnL zw}iq_xK2uLr95e4fKBWvyO86t!z^@?6%!XUS4?kEs;O4aZmxv0L~k12)?<4`sE{HqVf*HW-)*!?nM1Un>O}4Y_C6 zCJ4Ed{)A9fHe;*!g|@^}D16cVE&C^$V!hC%qhSQ1Fz#gZk>(oBe)skp1^0~-RQ6zq zBqhYWQC{-EKTep`*XU)h%p;?KDd+FcF+*qqkCc&1?kv z9)RTy=~NP~44HnIn5y-@h$RiY)@_rh`mM~k4vO;G3(Vg*s}e3ntjjiep9J(joOCm>*=79KQ5<4u6q{!f&c5$aPc(qJ7qq* z%Q7d4ZP5ox?g#2m%h2zc+cq+9Ww49BzSubn`Eu56-qoNc=Hrh)LDY(97Ycu{1l^)> zdF~SXC7e6c)w?9|WNnC`Hp3MmJSk{O*$m8?TAdPFw%I!bwOW92e&tW$j;H?J1OYZrw4qsdDpugAz?ef&m(w2=@XP)ZHMc%T z$xOZt`!`A+n-zxPn{+KYH1GYr4Bz+(LcaWepC>>+mYz{D?7GjQ^>Pmu5lZm~Y+f;` zRtY1#nFsaRlz*Is6%4JV{YYXN0IjFH^FCC*;oi7qJ;0+XOqc$=KVfTu6_9?fqwW|0 zIZr9L4_4dK9^W5Vu0Ks!KQ#nPb120hEI>bV9czZfT(vX)ZhnKJte|Xod1v=+@#1eT znaW|ZJ7iSWi$&l%cX~;ucZcmH2V*eXXgmMgv zi{>1;Q~Yg3z&uXk6TgI8HbOk5>ORBXWd{QvwuA*kfvYUQQAh5)L%UesXVIJ~zun{~ z&<=%Sl4`Ph1&jru;EEbl?=|_#nQ*vSqw?xYzv`N&K3bpUXdjcVGrvWZW9H3vpLqJK zxnNz$!TEbFLrzpmznZs~2Wv@}!d@2?t+E+^T!jI4ne+7E_ry8oWWUHBY5*1YL@IFXY#%{ak(L7(S8)NA@h$Dz|W!uRom z9F@HWXaKHo($xqrA|4BWoEJ`l`E}6jn}mqxa^5(;HGhLlTn}gPz9)^o=q1rcog$ji zn9E-m+K`EDY{d&b&}>>u%q9+*a$&Kis>|rC~l2{LL=`X^FBc0aGoEItrKlL=A8HZ8* z@kTgwh+Zu6Up@RTy|8}-RltYKwWC$4KHj92s19EqNu3<5RsmAgS9O3w)tNFXP5zLxRlq~6 z(1I*^`HjB>!FrF^@Y`pJyu5BYjrXtrwOKBrBe{1hzw^~@8gb{snf@Uzc>*gTU&iN&R}P(b+3*ZfJ0kA5u|1PQc;QOXPBoQLo@7e9VIq#v}MQQ+Cf z#A9y7pdHaV<8ZKiSqo=PH-uf_^nr@wc@oK<^xaut7kZ65Fgm-rsTm54nsPLoWJ`oH z4wpoi_4>b_KdDy)9&zC+$>jto$DfL*?+ZD<&c~g-l>W`XRg22*V~a$h*MJ-30v{}V z@fW%Xn(tLx3onRq7{@3XC!W#E!HDY)llY5lFt&xmQP=CGJt02l51^4Pc?V)FCYG!I zqU^7CBC@D^MO6C~IWeB)%3Aw1$`$${Mr=nfn_P?iY@atKZ^%PF1>pW-_3eg{80*p+ zu$e<1%a*1({2?1INLtwxqcn*_tSA7qCV%A%L+=efN~dyAtYT2gf!q%E#9BT({8pTJ z?l1q%G@Yepg*Q|8@BNQh=L4r=&f9~4v0r1ahNS(yS0rZk^HQCBl%RzO#@I&JefJ&z z>5b|AU;TNCym03r9vHD()r%?mHUBlubIzelFL{j7>JEdR5q_TjR#KCsh`3h@+j|V$ z`|2N1Y!eA(-}}h2#f(Qiz`mcaka}0^^*Al>XEFqVL`7Imk+BmPLSXtF3Adwh-NssP z44^7^M$rZ1gxZbH_47)%^`oXtU=;YSoMvkCUDtQC9W5qi*pu@l_9DPRx#}2nt>AWn zD|yn4yxHzOr6qZXJ?)E@C2pbE1i;$_;#s%bjw57CzlNSZ<^!Ac$zTlL3%=9-AOFFS zBJyUkgvl#Viul>T7~!BE33Kd}BO4%^eOM?~HWp7KaI^k4&N#G_DQUB$hU*D!)v%Qb zi~a0haHWhhO(~CmO8Ydd5S;&g{+`$O7Ebf51Xg)p`5$7Xu8)|2#-B+qiYNn^TlF~| zlwJhw?#o5C=&NXvHM(jx+lq{kR8UbX+eN-iB(s@usv>BfSv-C0oa5EDhs>egwhWh4>za19T!o8MVBrZ<^#V*@{C&fqE1kXhSX={ zzxg}HfA#;2hhXWlVZI!HbW9hXFMnabr{gel2P^33KPfl}&j7R-;z{jrM!G0~pF;MO zJQG?Ip$m=k|K@dTQ$u4|&4KpA|DrBY^mTu1h3w>d#4q^_+uYP}1~1wgntT9O!=Gsi z*!lP)=VYsRb$~e7?$?#19(_~+uZqBQ_U?A~Mf7#MF-`o8mIuWgzFMfu@_`uV^|eSX z=VFmP`<+qo*c40li|yEDnV%!U0_Y-NG>Ip&w`uoC+v%d~AEw&hj2-DWV9l-?utHdd z2Wwaau7YYc8&nh|2}iXmMsfLnnnyj*B|8~JOX>@G8LMDy)C*Ub#O9gA_rYlk&(7S` zAsR4tA{1NRLa(a7{Qn}`8m|T6vrHk)a7wV0*Qul}xb-4a83@I$4t38ChudzgVmW`M zcy3v`%TDbBKC=bOLLD^jRIEM8dSqoeg6x<6`6vHXIb81az|gB&2qsiP4bS~vSt4Xs zlJ#McyFe#2O((qVP$uZ6e>UMs9;y5>L~ZwKh#tqJ8pM?;S062M%#%qnm!G2TxF_cX z>(Gk!q2a@>L=eYtOcAdStZ}6!oL!RY5Ay=Ls1&}S$CF&9f&KRL?f0*9gw>sv$Fmn}fYu92|ItvYs5&RiZZA$^ z_+5Oy77AxF#*Vnc_sxUfGhnr-4UsP@;uD=-o8CpIcI5y2`@54;gUEQ-lT02X;T$C4 zT0DkryF7AK0n={x`H2cms~B~gr)E${_T)YjDsocC|$7UL13aB7;Pxj0!IZ`Teix{QxO{9 zrRe7BOp}1p1(9?JUMrAg2GsQgFfS|0{r*_2JZT&CMkB6B?b(X_w$-`$4G8Exe* z&6obIb5Mrxk*B7Nom!-Mgf)ua-dq)fPbNYnHLdZiHF#$%!k~>VuLAcl86ZQ_jz0yA zIt9wwCgwqo_|*R@Z2>e;v6K?zmyXVDRF>ooR`+xOMcnOYcjoEmt#m_aI zn_e_)m)$X98r(HduL4K8VEK{a52U_86U^>h-$7;v_nFLE2-ZM?iOQSfOnS zh9Wx>Zc+u*8xPtq?4;591BL?=`n80EH50LAff=qat0NT{UAuaABJUQytP1m|FAh-! z?l`$W(|dp+C#c_v&%0)c&i3s`#G4ay#CF0!fjK@;j_0f1a)9 z;M(Jvf?nIN{I4Emn2PNpa9MR*3F!!L{h52`Z~wFJuPd0bC5B#R^Yah9g%5o%Hb!Lt zFs4ySVBG+4|9r?nXSbez*C5X0)ykj!?R5#U=;w%1;iy%hdf9+4{k1;GJCE$R*aO3# z@sm5FRtkLHfj;7p1O2c6R#8)x@UGP9`m28=FrBy_P0J={hbQM7FHSU1vZD;z#A*TR zAakK_rBy^*WrR|*a15$2?x1jLY^gTS2HD6PVNW`IlTNW3epX_+;cHqb2t}&L32Y(- zJ;GH3{j|Kemaoq~K5u6Ft{1kp_1b`-wA*Wk>Lzg7h^707ZJulZ=cOuIp|Qse&S1x4 zPe6a!f;2@?v8UfllC*IU@(`J+W))w}pxg*E0L&{r zI2D8=a{r8$uXF>yZD@-e(75L-UJxZi;&l~pSB}ho=D#`Zxk50X`RBrQIhe$9iz$*b z-*GLP<{@bPk6$Q4_o~p@%Ga(;(i9=4*8Y1ZG_!yE??#f_c@Uv0Ph2M$7roZrdSRP@ zBP44rwZ7cP&;EmUXS(b#cnHM!*9`=laeZwS_6}k0q$Px07O1vF%%-9_q!T@kfc7t3 z$baGxdzRvylA(CW3U%jI*|`<lg zJNz!n)i!K~@vW%Kjtz71$3lo14}p?Xmq5mIE?F;;EjUe~n=B5x(%r0cJrO8o%;q zf2=i4;eF1K8ogKg0yNo+#cqjh>q+JB2Uq~8c>rj&R$=^EJ3nOK1#%>iz|5;Tk{uuJ zq}#1!fRc2M{U}xNITTN|2L6XX0_a!C%-xm5`h{GM`mU-cUw@zUAN?PIvQJi^=jwE+)Qt7w=GG!#QZ*3(xMAYBx^8Ir8}BMeiZ2`(B-r zCTvIy`W9W!zy4dAG9Xz5{5Vq{>o=>Kt_cqwb3`jRDBzDGL1nV>PyXicfH`gYv;VC~ zf-l+^PVzm$XOpT$5ZgO}Xh2}-I?WKRKvfu|uz9*X#mS)4hPNdSNs!!OY2fLMIG$SZVn?FD+x!}K*+?8gHNeye4#ntNIbLy5P_e&H8JIW{z2qF>v^j|#Q z*_4H!`47Y#f!smxB(~sfZ2y=3Lwa?DO1f449??y~`$rt93J|vig{J)?n=XNFB@aw; z@vcC(@~i)P)3YLOg^m3D^8&3t+!bd?XpvBpfAw$R`4R9FGgthXotK8=XaD_A{!n(0H*J-R9GuC0xvFqP7W!uazv#>VkaTOh zdaXDDMRLX8k2$Gz*u7$p1kF-vz*rLm#)@q){N$*!V+7|?HnZ0sqK^XB3El8q;Pm*nRhz0VixmzLqBeHbcbePbdas|`I|BFW#yE9gL2zVM67Qz-Xk2_naF#pV`dHZppPz#AJ#Nw9C$lbl zdqO3amQ{#YN80ewY8-as{5ItcBmJNIuWdi_AS}pNHJ4Ga&Pf_a06Dd}7yg0Tc)TYe zAN%RQRU!_agAZPkuasqkl(t9RNWu(Z49jLM)>_!;&K@(^t(L8cT9S>E(G%3eU{%*Kn$`1ta|%5u4CW9cAnH3Hr0|uD#b|wm zd``hRKlN``$~;Ew)rkjnji%il7h1)1|3Cfv#&?1Q=nM}^){6!m(uf_aR#RZP1Jr8x zDg<+aUbIU$KeVQ-{UMtfyZaK-4-#tGz1iHAl^(cSL`}25bWV+Wwfm zC$*T%7s~kR-;Y)*PQ|IueiU75%Hs4?Tgw6={yB}TKDieEH-9ybAlf&QK4tbRD{n<| zM_LNyCe3Dc_&0yZdPS<5S}&}<)BFAd#+GBR0zrBEL;G-i?Y0GTf*yXzsvED=itD}q zLTBMQ{E|D(bLq7)OMbGb4BmCfoSt2)?Gy@xbv|#6yYrUstN-W^GR2|*0x28>hSI0z zPaQ--g7eHDb%cgiHjw+9|8K`hz{OoE@Pu}tQ@4EH|A1VzhR0wN)SdSAj%oyy-uPd>Y^}Api15|MqXr zK{|Q>gt{gjq1If<*oQcdt;F-D27uzpoj;)Y>PflRyVIFmn=chQzVdI`>VDmFdN=l5 zYM6F#Wb<9;72L96XGWhzuolb#a^_RN1(h6(-*#;Cf)m$iA2{y*8+Me{_M(REA7*TS z^EUu>(-#2WCcsGZ-i2UMiuDubkz`R1FRGn;X^)YiK8A<+#TGAIllrwta;+%=wa3cj zfAZJ$oqkej#pKDwKBCFV=9EF>k$7&9&-wTG_FT3B-$S^_A^aA9XnbxuNKj%lM=JSa z!Fi6&$iOyXanQUDi;kqajrv1P9gTAij$a%2n zkkujW3(>r7A^Ki&n0oGFUQ+6Y^e-5f`fmU~*PT>$F_#%{k z#QhdKKjXUWQIyO$ko0mR9Kl?oGX*6uXweV|v;mDk+7K!-ycbb?*l(E6>yuW!_8h7I zfbXj!X@Ak`EIY(@3P*E_Al-RyLQ>i9cffP#i!ZtxsId|KZfKe$TB_AG7Jy-O;&}E8 zV>1Iv%Fby`C=cB}2P0E&6oJ_}#l*A|KLSh_8z%cfg!#ZU>*$NWv8F}no2{sl{!v*E zg*uVKtn4&Cub4H?is z3EfKWZZ5O~u-CPO_o?0T@_V5Cp|*Sz|9|xV1IjqL)$?i?OPT@9JclOcPS=ek6VFCYBnZV@C@wn6Lrs3ib=bC0fjw2SoyP726ba)0|D z1DDBH2{EC%W#7&oW$4QP@>joix(}Z;I>?REZXgnGAPYZ4f88H`@wW%^AWWu;1mDlg zA7p(P;zi0Dt-tu+fx_g|GE9vR6!*RFO^B=)4nxJrM+-ea{^rl@aV#TKvcWT29Pvde z=*<>r7eOR+R#*npBs;Vkk$m`H{7LM-;prX2sctvTkHl18Eir?x{Vak5 zmyR#~XP&B;2Hn=p;#Jx3;nlP5O{}lxKm1|y`E`85RU=H(n3Q`*`=St7HdFmU;5a7# zb#yOFX{V0D%5E5n%SylQpQ{JmU$fTa!f)zXRM2gvV~Mx_()rwc1s9JUiO>8iOJyyG!NsG4^e*K*=yHXTi@NhSlz!Ub-pp%BBM0li-t-?e!z9aT-LZg7Upj{ofR{Q)2w7|9A^wEw;JzFthY;ICy-Hn$2r5|HEI|H@G|# zAgrn^Lyh%wwX|hV!#Kur$zr*8)_wo#-M=mCb^MFJ+>xlSWQa56 z|MH)}fNz!z@d)1SYPn~qgZfDj9{B=`-A>R%fuRm#0JMVTkYD4GMOVGz_-Ah)K-)>DWVyFI@{j*Oj;BF!`rJQh0RF>In6U8tZZtvp|K>kxC>?e)YH14){|ZTcrwEKK-)13TQ`}pZ({-h~9Djt;4I+Cx1m4H~08vI8KrCjJN#P|B%B! z#1_4R-Xk0dl0G<9-23S?kAC&Po6W829{Hs{61q+MjP%s$)0y1zhapqn0visFLO$~^ z1F3$E)F*ARgkcnlq+8M5Tf`Dz#_st5iE5B)=e4aQlr*#`4oe(w#-u#;bAcX-zWDP7 zyKO>I$yzKIhEM((;a$R8Cm(v%>R>4Tm$L}OL_TwdfVGzZEYB)Tze8$u&i{KMM(?}fgc?YlO}qC`L!k== z9khxMZ*cqu#Rszmbnfpe-wnvTw2!SB`XFItTSC70CyT!Ejt0hG+bIxyP=EQ~zvmBz zz_s}H`dsTP{}9@va{W91JT$26elo{&Lwb{r~y?%|aj@bWgl-mQWJ^FMoVbeIgox zIqZVwZU~$DM%C1AE|=w33ubCIwiL5A{d15H&Vv3-E4y!qCi&)T|D~rbPc`IBwfKua z&wB>GMXRFz&+{knG7Q--3FDR|CLR3Zk7Nwnj#!!Lv-`DhvcC9B1=280q>wBgj@+s` zn#l7NV)goA<%UsX0^WOtWMYIa%c*iD>bQHqvkcyds17U-&CVLrn9uod#1x~91Zw?-rTkIwV5lt+5C8R4c;}xY=kU1W!sOdrFlUF#a;LE7)ODo&n2N35>xR z_n+W7lVk#awe~uTh%K&u85}phSAihPfB7#+o-ybKqe9sA^PaOZna}= zb;SNdsrmoxKP}9?*UL1n=j-dk6Zb%>c+-u2*dM%P$a2(*2LBdk_Gy44s(~Z!8jZvF zkNyJO!DC++3{!F-IOV9_S>w(D@?dI%i$aUhY4hc&JV!>4f=s(?AjN0z`_6g@V%08@ z$NrhWpKs0Bar5TjC}vZD>Dm+R54wfMS>60u#t-G{VhezU1a-iO5wO=>!aez`Kb=7M z{?k8b+qrtqGl=dEn3g~Mc2NbZL)!|IZ+ZzXRDi*>%hT^wX^j$Y{8V94T4QlC9RRDF zLRC<{YXGf0fC(!bc%iCKa=#V060@Q!xP;AZdhUC;c{b3nH@h7ugL$aqC+4Z{p$%fU zHdaKfKn8?qCr}N-xt5^4ufR*Nf1f(oOweI9{_y-y|NDeCNon)C9`TpIpjb-SW;es+ zJpWuw%(x(}5k&)^cr;!805+ecEBqkdFsJDPg_LXv_}l-k-zW57rA}f7{=R#1WSVsCf{wI&)TLQ%)T7G2d}%LU%K&+2>W<;#Io90qrPb zh_ues?Tci6H!NjRxKz{?3mN?6k3JqEw=Hj_ztP{XOFrT#w#ru%`xI&`lLmQweuku4 zP8BgA0eO!KhsJf6tM!6&ApZrf%hv#v`0XR7=N(jwj60zR9v0FiYrqW*LC#dt2(|V= zZEVLciFhjm%y_8ojWIHhCNiJr5p{yX`jbB)W!wWpa%vNf{55fsGvTwH_yF84S4eVh z%35dv?tF>ryiOlwH}22X6%a`Fz*Xn~x;E5jJ2pR{`m<9(Wf4a8YyV=uD1=j-khuTw zOMl0qw>>~TrFN>Ir}*NTHmpZcXv26VFp0u7zi}6V*;QV)8J>xm!HdmZ$fSO7XlQumE=PJez} zssmzT8A+e7ylr*3w1GIxEJdlskLpG(i~RTG$YW%u?M%?oZ6$vaN){SwbVbS&+c*5+ zO|F1VqIL39L{(bb3ils_+QYR_$p0sQP?gQ9jf(v>R#+@zR#XW*xyNbN+*pf;lHe>t zcf$$JejL>L#os>3A&M(~^4ECl0sq-Qxknx&`|6(vf@B`MNi6PAdcDVp6hTcasG&(s zTiJUA(!T%m{x3#nE(gV)cjXSBZhXKz3g2z-@^iI;o-x&M&7sZ|`Q z)#4xoD=co{zmo-2ww-#HcjN#1FHoozmub=>+CY}wEW=%5aq0SRZWj_i$YC%l7+73p zat&H>LUCQrw?K73KKn1l?63XHul!YtjETor|9oL{LH_rUf5$~6I4hB zasJ8QF2ymcHne{;F4P$~i9ts4$&f9EDcOYM#%TrU*jkw_ZXxEO3@B&)LGIT}T$3^Y z8jKOKst_tcI-Bj_Lw5`(Y0=GxkHPz>{?cEM+W9m>*VQkI0W8T9Rjqbl8Y>1F;mUtJ zjwog4>dPK#;h0WsnFnDI6xzdS0_kVF0 z>>ukV$^e`6ksjsZo7)M(e`~jFB%7elmR9CNslTiY^f*r}4yg;&{Nm;R%Kyi=uIiqv zM)C)YPsjz+zcGC6f4y7XG=Q_=Uvoj^# zmCB@1KCrRe-~FRKfEERNKbPd_CEAu$kGGWm(+HRA#F6=e%^4WiaV~s`H5D@kk-PwM8?f(?c0=zeq z5VoNvL6-;5Wy_x6C4hbV^`$@4p0z~dhraY5+w4BzC@F9p?gY9AcrAeOh>|_QI(}yo zS?afvoVtuNt2^&3nHQrOWOn-G53N}m1!&KTjp}Y7VU*m5=%-ySAr@8c4}*4&A8o>f z?F={sum9u!$DhSSY&VI2(f_=RX$8}SSw}cj|MtsPW7ez$!U8ok@b&-lpV?weTw5X$ zXkL~?w!@F*&|QSIhaOWhOLBM~{O{H^^MCUfwwI{6B}{+$ZMI2{cV!(}@1+BO*9RI` zbT`w8?a%y8wF62sZ+(yRpZ&*u1y_V!14}48tGDWZ_{-gKwh0*PsWwo~#Impa31HWl z*9+z}!*VKB0P05rpBjfTVDVCz1+HJzXZ~8nTI0Q%t33|qki#7URQS1n|2O}DrrNHO z$Scn62_w{_9^B3$N_F8MN=XtK{-hLxzMQ$a6RpE>cIbJw?>9KF}z8N{+8M$D? z`;WrI@~sjO}R{XgWvW+t?uis!JoGfTsa{7Wb>|A+H$Og%v;k5z2tVb#h3 zXV!{)ou&3jPs4+qMv)mss&RBrDu}yx0+zsi{fCmc zSL?7qB_&ry-)C8s*BqhVysNeg=O2g6oAQo=^HBZtrZv zb9~Xo6Ig#e`_@_UY8)G92S>4gzQ2tPHI!2G*%Y9n0|9fq>NTCuOMaXb=@5r8ggq4g z`au$}EvTlGadS9Pf_M(nu=@(&zpPO@D!(o_?)byspiOgJegIoV#{QUF3|j$pDt0_7 zbZem4kJ<3qnqcAt%Nr-n&>FpxovcPD8;N$LS%W@tl@E;g|M`Q!jkg7|;_P-FWy6g< zlxDh%Zxq{MX^21}xeVD{?{p1e;u%%tWidk}``kG98&vRQ%pB)m{Bvu>W`*r6si;;9 ztv}OW>u+yzzEKk3@5&PK^`Qtn0a!Z{+Mt0_BU=fnb&#Y&{``EosJgQJN9CQs6STs8 zevDS#$loquPZ4*`F9)XwlvfBXUZYybtyK*d{Km;5=%s{;Z1*x^ru^%F=&k#fgba|R zQD@lpMaq4=qBIX48B0GW`}#16-rlK>Y&UA{&Bo}z^S63V+XndjjsJQ+HplZdiJ+I? zG(^hEoeOwAjr3JW-1ye;zz$pTSHOSDC8kr*ZXiTd3Ya_gnLCP*HfIdJ3Y9%S(sZW^ zKa`mW;)tA;1o)qik140^I)wYXoH#*L0Dr$KSBn$0gwh`DInY4~@Za6U)uhNqmO9(w zs%zUeIi>UdH`~%Eo9QJ1fwa=l@MX>ilBxXM?77jFH18srTspVXxNPQBEKr)>k=7ik z)n#u}ct#Ne{^=S*vvxWI&qgglikS6?#gPxwCa0U>NkxzcFQsF**ynf4;T^^JI^KR8 zD&^EZ`36h>`frMfbvJy8S<$M*xEhfdq7fGpOu|Ps3DV`>&;^7~JT5YZ9hkuZZ}*mE zdM~INVZ*0|Vs2XoP7iyl=-Yt)|IYl=JWXU%k4Gar`FG-DmE?mg1I{GAk%R{5wJ@-j z`*g&?6_CF|@{Vj*2J185o7@5nmoe$QK3}AMy_|Qz{{O?@mEHdG2)Y^F+)yK5)Fiwt zXNsri4elDC+<|EaPK*un8~&b@mtN_C&9;T~Zi8IZrQ zsesoWyvuw}(4&|(j&N;g+SB6V{#meB7)$)zah_6A0?7Z^6t|-CmHbAwywL2)5=a{C zFfiWT1R0;9EnO<(e*DrGay%KF^vV&J-N8Mo^T5i5oERTkB8C`XhoPQxzF)@Yxed!9 zm1+X~TQ$LuRsyC*0_OgJ9G$xJAPc-s+Wi!h9`wXIQ&I-MYTYKK>eF&apeF+64{6Ln z-Vm*dfamxA8PnUApNzJX`H~szS;2sR`iFl}KT_+@Q=_F?SY@2whQ}`|ii(@Df^DJ@hsTyMT zgw)3`uc$EtN%We@KocNScXaEw#B-N5SW(26#b_{>d;e<>>+N6s&oJOWhpVz=rgs!z zVA?G5n-I+r#N7K2m;nE){JuKxNM3gj*Gb=Ss)p^p{_}EtTLm$*5q&`AQFwB^Z{Sb- zU0-5_k*CpQb~oT0tHM;_lV0kjf%LLThCGIyKUvOAJ+9_Tw-dR){AueG%i}-ae*&){ zp$WReXYbv|38y4J{D4_xT%f-=cn{B?pv=ACU&@1$e`n)oY6}F*Cp?siC%@9LB%Eos zf2*T+Nvdn|LF~0$91?K%~YC%py%^mPq%~vDRHGF0qG6$wi!g(yfxM%REaCaUSZ_g!kV{ zD0&!BfbXyOi1+R|F5xRa<-*A)l%!#m(x4DW9GwEi>D|kZPem4ywiO;l9jOa}{;hvd z7wq_66I{Ez?em;5KKUQ|1`%hc5re(|JsYYD`9KP zQoJw(kEYy+4IgFezlX6di}#Us#9gV5>iWyY6m>wHQwZG_1ZuI^cjL=?{)_*3+WFbo zeAWIVGddDMrGpc#6ou16lgt^`q*BYom8Cg(N3_9v|LoVAu_sS?x0x}T_an7hJea)i z?7{2V!*D4x68C0VhH2<#wLW#ou#P+J5=&5n)j%S0Z!}D8Oi#T;@Yors|M@{b`j>(I zzsK{IV;A0keSU7HP*9Q09F#!MTn_gy{1dr;73m?(wHd+pAMCMhD%^jL{$X*?e=96X zhcTp8sVF=cJUEsp#5IWBfko{6&d_#Y3K`PlD{iI#5+A(%tZ61#JZ6({knwG4YUwIh zz0faU{$(*mAn?EQFZ~+$`@cK%|Gwqz58S`NWhg|0;Ups+sh4TfcmnZEqE`$gL{?u@ zA;|==>Z@jGzcubG`@6# z1M}yVB?=yz;34h8LH1a|zt(?O>_7K^zM23&m$9?TTI88SR+qUlr2>H>c>Yo(*>tic z;J+`n;xo*qd$T?V`Bby|1_S-agf1K`i^)_-DB5xCjD-cuKkGli=PcqgQg8&wlYFcH(@9Egi_e+b@b4Q19Uf_}>h> zhC@s%M^hKIy%^Om$SU6(acSWEg)kv;(+?s__a|umkK39W!3wLxipICJPRIGe&hY#v z;o0hzD}%P;UEdFMuSVDXhI|58D)@*8TxaqW9(%UQTH%jVxEJX*RXhwG?F9Tc^RoJ| zbb!B*t0HiL*FT=t6+{D=Zju{9QzG#G7nY?fkbn0HJI#G`B|(#W`(k|3C23+7a*b=1 zv9-&wszv*wYY<#!BWxdqG8ZqV*a(cV{FA;Q!uIw`}oxuh&aw7h?TV(Ul7)k<~Gr zdt?-3(LNp^0iKZwWTVbq+z>(|cg;UK*wKAUFs&oHNaL6)7uRbt5d^N!<{tK0P!rsx z!lLe?Qrmmq<2^%G8qT*a_oy}Sul2tmri79X^dB6A)1Q+A_3xkaSDU2#=P%y8zvlnB zoP5CiuQ&f1yTi{6pY|5+U!xe(3&P(&x4cV-h}M=TdE_7`;-*J1NfAprrpw)45F@@O=7K*w%4FU2`;y0!v2-QkQLy-sca|Cs~>OtSIdZ;v);BpQ>H7(8!0yG>tRgy*`^J`LG0>Kahbi^q+CFbebr6 zUv-DJLIvrLg7cA3k9DK^=N>uj1i|aSILb_gbAzeOPWqSU-;R2h*Ma^24}Y@ba>SGH zCE`lZ&FfktazWrZah#pEiwD4eb30!K*I_(HE=m|nQ2hK`;h*~N=-mepy72R?g2U!r zr5_v*kIW_jAbG#IWZkR60Zk<-9r066Uah10;@Ua{Lm+v|ze31V54M;@nNCPw7!O=Jtk$4L~gc1)x_Zon)IZl4kh&wFdwsA=MenvyXj z4AQIGj^a1+WAW)ITx%z%g^G~8rY>u_ufj$r@!|d-*y%k2`c>rm$?E{b!TqodtYwFB z<=;QK2UBHyd|1#|`!U}emh2pR4m6n{eYpGKb~IlzkF9Y<{u1_SzFX7GR;a3P4oBzk zOjGS8h=iBi?_*9nVsk4U3sELkPXs=%WlVGJb;xl_1_s+>U(rlceq(7V(>Ej4Q7f~w z8Mj=Femmta1zR;qqbxyZks=;2Fw}0{peNkAQ-rz=bkgW+FO*EaLFsCRC@k?ciaAsb zW@$xl6*%wsekF|0ig#h=w2n{EGHBVt_w$dHxY+IljAu`ABO%h6jnQ;aWrUo{BNR!7 zpxZZCV850y^bd5?JyT;XyT>|ogu3SGV3&?ujOW}dee4TygmZCr1nOzD2>SLE!2Anp zXaaj;Y}po?h1IuD0OwDUph=uTtffUA*nZgafrH8dka+C4Ahrz5r6jC{&~`eS00G`@ zo4uNlF&mDs{j+=iQePUBV!Z3mtW9k>JZrX6jWYtVWAVU?m%sCEufaGO9=5!!X_^Y!!G`!t)5vQnb5*>jI9yL+r6cnjoH6Pcu>gAf#q7ze%(X`;Y$6Ls(~#s zQ`3x=3c`604zPWYqWOrkIt{a?+vLPd;8uUJ4d!9DWu&9-J2vL?WXkRQ!*KbWw#uF^ ze~?bm**k=Avd+*mS^7j9ZSf-q0amM;a|E2{vSr=;GJ))pO9OO_1n5!~Zvy8LyLp{^ z7y{JH@?Nl(w?XenWIO*;{~+#}o^z*MtwSutONXWp!X!<%+7M#mJCo2L^pC>XC9@l1 zX@eAzvZ@b2;*3z37tX)_)ok~-FKyc=S`7I5rkONuZTVdwp8_I>Z(7u zwV4Nro9h#!$v=oMstLs_{(>ihT6z7=i=NKYXE+zj4JoMNLINS~S*41iqArJv&0==W z*zTi>T^XYInRb2UQcLt4P2$yTmau&uC!b0C+Dz>U7S1x_COjU$N^+X!3otV;%KP@Iq^d?(wj%#3l=(WRzhQ>Vn*hw!TJ_k9YAYgi2*F@2^{F z`htgd)3aU~GmG2^1oj!*z;7hLZ3M|=El%xu>H#05n+{`0QIyvnI= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // SAR ... + int copiedSars = CopyBuffer(sarHandler, 0, 0, limit, sarBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // SAR ... + copiedSars > 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // SAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // XPV ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // PEAKS ... + + // + ENUM_DRAW_TYPE peaksDrawType = showPeaks ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(peaksBuffer, true); + SetIndexBuffer(peaksBufferIndex, peaksBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peaksBufferIndex, PLOT_SHOW_DATA, showPeaks); + PlotIndexSetInteger(peaksBufferIndex, PLOT_DRAW_TYPE, peaksDrawType); + + // + PlotIndexSetDouble(peaksBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(peaksBufferIndex, PLOT_ARROW, peaksArrowCode); + + // + // VALES ... + + // + ENUM_DRAW_TYPE valesDrawType = showVales ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(valesBuffer, true); + SetIndexBuffer(valesBufferIndex, valesBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valesBufferIndex, PLOT_SHOW_DATA, showVales); + PlotIndexSetInteger(valesBufferIndex, PLOT_DRAW_TYPE, valesDrawType); + + // + PlotIndexSetDouble(valesBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(valesBufferIndex, PLOT_ARROW, valesArrowCode); + + // + // SAR ... + + // + ENUM_DRAW_TYPE sarDrawType = showSar ? DRAW_ARROW : DRAW_NONE; + + // + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(sarBufferIndex, PLOT_SHOW_DATA, showSar); + PlotIndexSetInteger(sarBufferIndex, PLOT_DRAW_TYPE, sarDrawType); + + // + PlotIndexSetDouble(sarBufferIndex, PLOT_EMPTY_VALUE, 0); + PlotIndexSetInteger(sarBufferIndex, PLOT_ARROW, sarArrowCode); + + // + // Data Buffers ... + + // + // CURRENT ... + + // + ArraySetAsSeries(cHHBuffer, true); + SetIndexBuffer(cHHBufferIndex, cHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(cLLBuffer, true); + SetIndexBuffer(cLLBufferIndex, cLLBuffer, INDICATOR_CALCULATIONS); + + // + // SHORT ... + + // + ArraySetAsSeries(sHHBuffer, true); + SetIndexBuffer(sHHBufferIndex, sHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(sLLBuffer, true); + SetIndexBuffer(sLLBufferIndex, sLLBuffer, INDICATOR_CALCULATIONS); + + // + // MEDIUM ... + + // + ArraySetAsSeries(mHHBuffer, true); + SetIndexBuffer(mHHBufferIndex, mHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(mLLBuffer, true); + SetIndexBuffer(mLLBufferIndex, mLLBuffer, INDICATOR_CALCULATIONS); + + // + // LONG ... + + // + ArraySetAsSeries(lHHBuffer, true); + SetIndexBuffer(lHHBufferIndex, lHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(lLLBuffer, true); + SetIndexBuffer(lLLBufferIndex, lLLBuffer, INDICATOR_CALCULATIONS); + + // + // HIND ... + + // + ArraySetAsSeries(hHHBuffer, true); + SetIndexBuffer(hHHBufferIndex, hHHBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(hLLBuffer, true); + SetIndexBuffer(hLLBufferIndex, hLLBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + // Calculate Cycles ... + CalculateCycles(bar_index); + + // + // Calculate Peaks and Vales ... + CalculatePeaksAndVales(bar_index); + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Initial Market Cycles ... + * + * @return ( bool ) + */ +bool InitMarketCycles() +{ + // + bool result = false; + + // + int cPeriodSeconds = PeriodSeconds(_Period); + + // + // Find Cycle Period ... + if (scMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mSCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_SHORT, + _Period // + ); + } + else + { + mSCPeriod = scPeriod; + } + + // + if (IsValid(mSCPeriod)) + { + mSCLength = PeriodSeconds(mSCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (mcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mMCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_MEDIUM, + _Period // + ); + } + else + { + mMCPeriod = mcPeriod; + } + + // + if (IsValid(mMCPeriod)) + { + mMCLength = PeriodSeconds(mMCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (lcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mLCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_LONG, + _Period // + ); + } + else + { + mLCPeriod = lcPeriod; + } + + // + if (IsValid(mLCPeriod)) + { + mLCLength = PeriodSeconds(mLCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (hcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mHCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_HIND, + _Period // + ); + } + else + { + mHCPeriod = hcPeriod; + } + + // + if (IsValid(mHCPeriod)) + { + mHCLength = PeriodSeconds(mHCPeriod) / cPeriodSeconds; + } + + // + result = mSCLength > 0 && + mMCLength > mSCLength && + mLCLength > mMCLength && + mHCLength > mLCLength; + + // + return result; +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // CURRENT ... + cHHBuffer[barIndex] = EMPTY_VALUE; + cLLBuffer[barIndex] = EMPTY_VALUE; + + // + // SHORT ... + sHHBuffer[barIndex] = EMPTY_VALUE; + sLLBuffer[barIndex] = EMPTY_VALUE; + + // + // MEDIUM ... + mHHBuffer[barIndex] = EMPTY_VALUE; + mLLBuffer[barIndex] = EMPTY_VALUE; + + // + // LONG ... + lHHBuffer[barIndex] = EMPTY_VALUE; + lLLBuffer[barIndex] = EMPTY_VALUE; + + // + // HIND ... + hHHBuffer[barIndex] = EMPTY_VALUE; + hLLBuffer[barIndex] = EMPTY_VALUE; + + // + // PEAKS ... + peaksBuffer[barIndex] = EMPTY_VALUE; + + // + // VALES ... + valesBuffer[barIndex] = EMPTY_VALUE; + + // + // SARS ... + sarBuffer[barIndex] = EMPTY_VALUE; +} + +/** + * Calculate Specified Market Cycle Info ... + * + * @param barIndex: Integer, Bar Index ... + * @param cycle: ENUM_X_MARKET_CYCLES member, Specified Cycle ... + * @param hhBuffer: Highest High Buffer Reference ... + * @param llBuffer: Lowest Low Buffer Reference ... + */ +void CalculateCycle( + int barIndex, + ENUM_X_MARKET_CYCLES cycle, + double &hhBuffer[], + double &llBuffer[] // +) +{ + // + XOHCL bar; + bool isBarInited = bar.Init( + _Symbol, + _Period, + barIndex + // + ); + if (!isBarInited) + { + return; + } + + // + int mLength = 0; + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + mLength = mSCLength; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + mLength = mMCLength; + break; + + // + case X_MARKET_CYCLE_LONG: + mLength = mLCLength; + break; + + // + case X_MARKET_CYCLE_HIND: + mLength = mHCLength; + break; + } + + // + if (mLength == 0) + { + return; + } + + // + // Find Highest High ... + double hhValue = bar.FindHighest( + mLength, + hhMode + // + ); + hhBuffer[barIndex] = hhValue; + + // + // Find Lowest Low ... + double llValue = bar.FindLowest( + mLength, + llMode + // + ); + llBuffer[barIndex] = llValue; +} + +/** + * Claculate Cycles ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculateCycles(int barIndex) +{ + // + // SHORT ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_SHORT, + sHHBuffer, + sLLBuffer // + ); + + // + // MEDIUM ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_MEDIUM, + mHHBuffer, + mLLBuffer // + ); + + // + // LONG ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_LONG, + lHHBuffer, + lLLBuffer // + ); + + // + // HIND ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_HIND, + hHHBuffer, + hLLBuffer // + ); +} + +/** + * Calculate Peaks and Vales ... + * + * @param barIndex: Integer, Bar Index ... + */ +void CalculatePeaksAndVales(int barIndex) +{ + // + int lastIndex = barIndex + 1; + int barsCount = iBars(_Symbol, _Period); + + // + // PEAKS ... + double lastPeak = + lastIndex < barsCount + ? peaksBuffer[lastIndex] + : 0; + + // + double isHH = sHHBuffer[barIndex]; + double imHH = mHHBuffer[barIndex]; + double ilHH = lHHBuffer[barIndex]; + double ihHH = hHHBuffer[barIndex]; + + // + double iHHs[4] = { + isHH, + imHH, + ilHH, + ihHH // + }; + double rValue = GetAverage(iHHs); + bool isPeak = rValue == isHH && + isHH == imHH && + imHH == ilHH && + ilHH == ihHH; + double iPeak = + isPeak + ? rValue + : lastPeak; + peaksBuffer[barIndex] = iPeak; + + // + // VALES ... + double lastVale = + lastIndex < barsCount + ? valesBuffer[lastIndex] + : 0; + + // + double isLL = sLLBuffer[barIndex]; + double imLL = mLLBuffer[barIndex]; + double ilLL = lLLBuffer[barIndex]; + double ihLL = hLLBuffer[barIndex]; + + // + double iLLs[4] = { + isLL, + imLL, + ilLL, + ihLL // + }; + double sValue = GetAverage(iLLs); + bool isVale = sValue == isLL && + isLL == imLL && + imLL == ilLL && + ilLL == ihLL; + double iVale = + isVale + ? sValue + : lastVale; + valesBuffer[barIndex] = iVale; +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xstr.ex5 b/BKPS/14031106/Indicators/x-saherelm.x121.xstr.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..4eb09ac27739b01fdbd9beafc8ffbde37c57a1ca GIT binary patch literal 16008 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 V)D6MX&LlNZ>O#a^wkKjD`Co)6)))W) literal 0 HcmV?d00001 diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xstr.mq5 b/BKPS/14031106/Indicators/x-saherelm.x121.xstr.mq5 new file mode 100644 index 0000000..cccce4f --- /dev/null +++ b/BKPS/14031106/Indicators/x-saherelm.x121.xstr.mq5 @@ -0,0 +1,636 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121 XSTR +// Description: XSTR ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XSTR Indicator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121 XSTR" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Market ... +input group "Market"; +input int strLength = 14; // Length +input double strMultiplier = 3; // Multiplier +input ENUM_APPLIED_PRICE strAppliedTo = PRICE_MEDIAN; // Applied To + +// +input group "Presentation"; + +// +input bool showStr = true; // Show Str +input bool showStrUpper = true; // Show Str Upper +input bool showStrLower = true; // Show Str Lower + +// +// Buffers ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#property indicator_chart_window + +// +#property indicator_buffers 7 +#property indicator_plots 3 + +// +// STR ... +#define strBufferIndex 0 +double strBuffer[]; + +#define strColorBufferIndex 1 +double strColorBuffer[]; + +// +#define strPlotBufferIndex 0 +#property indicator_label1 "X121 STR" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 CLR_NONE, clrLime, clrRed, clrGray +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +// +// Up ... +#define strUpBufferIndex 2 +double strUpBuffer[]; + +// +#define strUpPlotBufferIndex 1 +#property indicator_label2 "X121 STR U" +#property indicator_type2 DRAW_LINE +#property indicator_color2 C'255,106,0' +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +// Down ... +#define strDownBufferIndex 3 +double strDownBuffer[]; + +// +#define strDownPlotBufferIndex 2 +#property indicator_label3 "X121 STR D" +#property indicator_type3 DRAW_LINE +#property indicator_color3 C'255,106,0' +#property indicator_style3 STYLE_SOLID +#property indicator_width3 1 + +// +// Data Buffers ... + +// +int mLastBufferIndex = 3; + +// +// STR ... + +// +// Atr ... +#define atrBufferIndex mLastBufferIndex + 1 +double atrBuffer[]; + +// +// Price ... +#define strPriceBufferIndex mLastBufferIndex + 2 +double strPriceBuffer[]; + +// +// Trend ... +#define strStateBufferIndex mLastBufferIndex + 3 +double strStateBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// ATR Handler ... +int atrHandler = INVALID_HANDLE; + +// +bool isStrTrendChanged; +bool isStrStartBearishTrend; +bool isStrStartBullishTrend; + +// +int changeOfTrend; +int startBearishTrend; +int startBullishTrend; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + strLength // + ); + bool isInited = atrHandler != INVALID_HANDLE; + if (!isInited) + { + return INIT_FAILED; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(atrHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + + // + // Validate Calculated Bars ... + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // ATR ... + atrCalculatedBars >= 0 + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + // + // checking for the limit start of calculation of an indicator ... + limit = + (prev_calculated > rates_total || prev_calculated <= 0) + ? maxLength + : prev_calculated - 1; + + // + // Buffers Copy ... + + // + // ATR ... + int copiedAtrs = CopyBuffer(atrHandler, 0, 0, rates_total, atrBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // ATR ... + copiedAtrs >= 0 + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = + // + // STR ... + strLength > 0 && + strMultiplier > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(1, strLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // STR ... + SetIndexBuffer(strBufferIndex, strBuffer, INDICATOR_DATA); + SetIndexBuffer(strColorBufferIndex, strColorBuffer, INDICATOR_COLOR_INDEX); + + // + ENUM_DRAW_TYPE strUpDrawType = showStrUpper ? DRAW_LINE : DRAW_NONE; + SetIndexBuffer(strUpBufferIndex, strUpBuffer, INDICATOR_DATA); + PlotIndexSetDouble(strUpPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(strUpPlotBufferIndex, PLOT_SHOW_DATA, showStrUpper); + PlotIndexSetInteger(strUpPlotBufferIndex, PLOT_DRAW_TYPE, strUpDrawType); + + // + ENUM_DRAW_TYPE strDownDrawType = showStrLower ? DRAW_LINE : DRAW_NONE; + SetIndexBuffer(strDownBufferIndex, strDownBuffer, INDICATOR_DATA); + PlotIndexSetDouble(strDownPlotBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(strDownPlotBufferIndex, PLOT_SHOW_DATA, showStrLower); + PlotIndexSetInteger(strDownPlotBufferIndex, PLOT_DRAW_TYPE, strDownDrawType); + + // + // Data Buffers ... + + // + // STR ... + + // + SetIndexBuffer(strPriceBufferIndex, strPriceBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(strStateBufferIndex, strStateBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + CalculateStr( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low // + ); +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // STR ... + strBuffer[barIndex] = 0; + strUpBuffer[barIndex] = 0; + strDownBuffer[barIndex] = 0; + strPriceBuffer[barIndex] = 0; + strColorBuffer[barIndex] = hideColorIDX; + strStateBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate STR ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + */ +void CalculateStr( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + // Calculated Price ... + double price = GetAppliedPrice( + strAppliedTo, + open, + high, + low, + close, + bar_index // + ); + strPriceBuffer[bar_index] = price; + + // + double atr = atrBuffer[bar_index]; + + // + // Up ... + strUpBuffer[bar_index] = price + (strMultiplier * atr); + + // + // Down ... + strDownBuffer[bar_index] = price - (strMultiplier * atr); + + // + if (close[bar_index] > strUpBuffer[bar_index - 1]) + { + // + strStateBuffer[bar_index] = 1; + if (strStateBuffer[bar_index - 1] == -1) + { + changeOfTrend = 1; + } + } + else if (close[bar_index] < strDownBuffer[bar_index - 1]) + { + // + strStateBuffer[bar_index] = -1; + if (strStateBuffer[bar_index - 1] == 1) + { + changeOfTrend = 1; + } + } + else if (strStateBuffer[bar_index - 1] == 1) + { + // + strStateBuffer[bar_index] = 1; + changeOfTrend = 0; + } + else if (strStateBuffer[bar_index - 1] == -1) + { + // + strStateBuffer[bar_index] = -1; + changeOfTrend = 0; + } + + // + // Down Trend Starting ... + if (strStateBuffer[bar_index] < 0 && strStateBuffer[bar_index - 1] > 0) + { + startBearishTrend = 1; + } + else + { + startBearishTrend = 0; + } + + // + // Up Trend Starting ... + if (strStateBuffer[bar_index] > 0 && strStateBuffer[bar_index - 1] < 0) + { + startBullishTrend = 1; + } + else + { + startBullishTrend = 0; + } + + // + if (strStateBuffer[bar_index] > 0 && strDownBuffer[bar_index] < strDownBuffer[bar_index - 1]) + { + strDownBuffer[bar_index] = strDownBuffer[bar_index - 1]; + } + + // + if (strStateBuffer[bar_index] < 0 && strUpBuffer[bar_index] > strUpBuffer[bar_index - 1]) + { + strUpBuffer[bar_index] = strUpBuffer[bar_index - 1]; + } + + // + if (startBearishTrend == 1) + { + strUpBuffer[bar_index] = strPriceBuffer[bar_index] + (strMultiplier * atr); + } + + // + if (startBullishTrend == 1) + { + strDownBuffer[bar_index] = strPriceBuffer[bar_index] - (strMultiplier * atr); + } + + // + // Draw the indicator ... + + // + double colorIDX = hideColorIDX; + strColorBuffer[bar_index] = colorIDX; + + // + if (strStateBuffer[bar_index] == 1) + { + // + strBuffer[bar_index] = strDownBuffer[bar_index]; + if (changeOfTrend == 1) + { + strBuffer[bar_index - 1] = strBuffer[bar_index - 2]; + changeOfTrend = 0; + } + + // + colorIDX = bullishColorIDX; + } + else if (strStateBuffer[bar_index] == -1) + { + // + strBuffer[bar_index] = strUpBuffer[bar_index]; + if (changeOfTrend == 1) + { + // + strBuffer[bar_index - 1] = strBuffer[bar_index - 2]; + changeOfTrend = 0; + } + + // + colorIDX = bearishColorIDX; + } + + // + if (showStr) + { + strColorBuffer[bar_index] = colorIDX; + } +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.x121.xvwap.ex5 b/BKPS/14031106/Indicators/x-saherelm.x121.xvwap.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..4b604a738a81f57eee33f79c5cb685aff36b602c GIT binary patch literal 16238 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 rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + vwapFastLength > 2 && + vwapMidLength > vwapFastLength && + vwapSlowLength > vwapMidLength + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // XVWAP ... + result = MathMax(result, vwapFastLength); + result = MathMax(result, vwapMidLength); + result = MathMax(result, vwapSlowLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // Fast ... + ArraySetAsSeries(vwapFastBuffer, true); + ArraySetAsSeries(vwapFastColorBuffer, true); + SetIndexBuffer(vwapFastBufferIndex, vwapFastBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapFastColorBufferIndex, vwapFastColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Mid ... + ArraySetAsSeries(vwapMidBuffer, true); + ArraySetAsSeries(vwapMidColorBuffer, true); + SetIndexBuffer(vwapMidBufferIndex, vwapMidBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapMidColorBufferIndex, vwapMidColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Slow ... + ArraySetAsSeries(vwapSlowBuffer, true); + ArraySetAsSeries(vwapSlowColorBuffer, true); + SetIndexBuffer(vwapSlowBufferIndex, vwapSlowBuffer, INDICATOR_DATA); + SetIndexBuffer(vwapSlowColorBufferIndex, vwapSlowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Data Buffers ... + + // + // Volumes ... + ArraySetAsSeries(vwapVolumeBuffer, true); + SetIndexBuffer(vwapVolumeBufferIndex, vwapVolumeBuffer, INDICATOR_CALCULATIONS); + + // + // Price ... + ArraySetAsSeries(vwapPriceBuffer, true); + SetIndexBuffer(vwapPriceBufferIndex, vwapPriceBuffer, INDICATOR_CALCULATIONS); + + // + // Fast State ... + ArraySetAsSeries(vwapFastStateBuffer, true); + SetIndexBuffer(vwapFastStateBufferIndex, vwapFastStateBuffer, INDICATOR_CALCULATIONS); + + // + // Mid State ... + ArraySetAsSeries(vwapMidStateBuffer, true); + SetIndexBuffer(vwapMidStateBufferIndex, vwapMidStateBuffer, INDICATOR_CALCULATIONS); + + // + // Slow State ... + ArraySetAsSeries(vwapSlowStateBuffer, true); + SetIndexBuffer(vwapSlowStateBufferIndex, vwapSlowStateBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + // Calculate Required VWAP Data Buffers ... + if (ratesTotal - bar_index <= maxLength) + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // Prevent Moving Forward ... + } + else + { + // + CalculateVWAPDataBuffers( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + CalculateVWAPS( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + } + else + { + FillBuffersZero(bar_index); + } +} + +// +// Custom ... + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + vwapFastBuffer[barIndex] = EMPTY_VALUE; + vwapMidBuffer[barIndex] = EMPTY_VALUE; + vwapSlowBuffer[barIndex] = EMPTY_VALUE; + vwapVolumeBuffer[barIndex] = EMPTY_VALUE; + vwapPriceBuffer[barIndex] = EMPTY_VALUE; + + // + vwapFastColorBuffer[barIndex] = hideColorIDX; + vwapMidColorBuffer[barIndex] = hideColorIDX; + vwapSlowColorBuffer[barIndex] = hideColorIDX; + vwapFastStateBuffer[barIndex] = hideColorIDX; + vwapMidStateBuffer[barIndex] = hideColorIDX; + vwapSlowStateBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate VWAP Value for Specified Bar ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + * @param _length: Integer, Specified VWAP Length ... + * @param _show: Boolean, Specified Show Buffer or not ... + * @param _buffer: Double Array Reference, Points to Buffer ... + * @param _colorBuffer: Double Array Reference, Points to Color Buffer ... + * @param _stateBuffer: Double Array Reference, Points to State Buffer ... + */ +void CalculateVWAP( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[], + // + int _length, // Calculation Length + bool _show, + double &_buffer[], + double &_colorBuffer[], + double &_stateBuffer[] // +) +{ + // + double vSum = 0; + double pSum = 0; + double mSum = 0; + for (int x = 0; x < _length; x++) + { + // + pSum += vwapPriceBuffer[x + bar_index]; + vSum += vwapVolumeBuffer[x + bar_index]; + mSum += vwapPriceBuffer[x + bar_index] * vwapVolumeBuffer[x + bar_index]; + } + + // + double iValue = mSum / vSum; + iValue = NormalizeDouble(iValue, _Digits); + + // + _buffer[bar_index] = iValue; + + // + bool isBullish = low[bar_index] > iValue; + bool isBearish = high[bar_index] < iValue; + + // + double iColor = + isBullish + ? bullishColorIDX + : isBearish + ? bearishColorIDX + : neuturalColorIDX; + + // + _colorBuffer[bar_index] = hideColorIDX; + _stateBuffer[bar_index] = iColor; + if (_show) + { + _colorBuffer[bar_index] = iColor; + } +} + +/** + * Calculate VWAP Required Data Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPDataBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double price = GetAppliedPrice( + vwapAppliedTo, + open, + high, + low, + close, + bar_index // + ); + vwapPriceBuffer[bar_index] = price; + vwapVolumeBuffer[bar_index] = (double)tickVolume[bar_index]; +} + +/** + * Calculate Different VWaps ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateVWAPS( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapFastLength, + showVWapFast, + vwapFastBuffer, + vwapFastColorBuffer, + vwapFastStateBuffer // + ); + + // + // Mid ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapMidLength, + showVWapMedium, + vwapMidBuffer, + vwapMidColorBuffer, + vwapMidStateBuffer // + ); + + // + // Fast ... + CalculateVWAP( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume, + // + vwapSlowLength, + showVWapSlow, + vwapSlowBuffer, + vwapSlowColorBuffer, + vwapSlowStateBuffer // + ); +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Indicators/x-saherelm.xcc.ex5 b/BKPS/14031106/Indicators/x-saherelm.xcc.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..5dc9dc1a669775c619eea08817b1ff0f6239d3d7 GIT binary patch literal 12988 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 z rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = true; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ +} + +// +// Apply Custom Chart Style ... +void ApplyCustomChartStyle() +{ + // + // Read Current Chart Config and Store it ... + ReadChartStyle(); + + // + // After Reading Current Chart Style ... + // we have to Save Configs and Change Styles ... + clearStyle = chartStyle; + + // + clearStyle.upColor = CLR_NONE; + clearStyle.downColor = CLR_NONE; + clearStyle.lineColor = CLR_NONE; + clearStyle.bullishColor = CLR_NONE; + clearStyle.bearishColor = CLR_NONE; + + // + // Decide to Show or not Candles based on User Input ... + if (showCandles) + { + SetChartStyle(chartStyle); + } + else + { + SetChartStyle(clearStyle); + } +} + +// +// Read Previous Chart Style ... +void ReadChartStyle() +{ + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + chartStyle.chartId = chartId; + + // + // Retrieve Chart Mode ... + chartStyle.mode = (ENUM_CHART_MODE)ChartGetInteger(chartId, CHART_MODE); + + // + chartStyle.showBidLine = (bool)ChartGetInteger(chartId, CHART_SHOW_BID_LINE); + chartStyle.showAskLine = (bool)ChartGetInteger(chartId, CHART_SHOW_ASK_LINE); + chartStyle.showGrid = (bool)ChartGetInteger(chartId, CHART_SHOW_GRID); + chartStyle.showVolumes = (bool)ChartGetInteger(chartId, CHART_SHOW_VOLUMES); + chartStyle.showTradeLevels = (bool)ChartGetInteger(chartId, CHART_SHOW_TRADE_LEVELS); + chartStyle.autoScroll = (bool)ChartGetInteger(chartId, CHART_AUTOSCROLL); + chartStyle.quickNavigation = (bool)ChartGetInteger(chartId, CHART_QUICK_NAVIGATION); + + // + chartStyle.foreGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND); + chartStyle.backGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_BACKGROUND); + chartStyle.upColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_UP); + chartStyle.downColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_DOWN); + chartStyle.bullishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BULL); + chartStyle.bearishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BEAR); + chartStyle.gridColor = (color)ChartGetInteger(chartId, CHART_COLOR_GRID); + chartStyle.bidLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_BID); + chartStyle.askLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_ASK); + chartStyle.stopColor = (color)ChartGetInteger(chartId, CHART_COLOR_STOP_LEVEL); + chartStyle.lineColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_LINE); + chartStyle.volumesColor = (color)ChartGetInteger(chartId, CHART_COLOR_VOLUME); + + // + chartStyle.mode = mode; + chartStyle.upColor = upColor; + chartStyle.downColor = downColor; + chartStyle.lineColor = lineColor; + chartStyle.bearishColor = bearishColor; + chartStyle.bullishColor = bullishColor; + chartStyle.volumesColor = volumesColor; +} + +// +// Set Chart Style ... +void SetChartStyle( + XChartStyle &mChartStyle // Chart Style to Apply +) +{ + // + ApplyChartStyle( + mChartStyle.chartId, + mChartStyle.mode, + mChartStyle.showBidLine, + mChartStyle.showAskLine, + mChartStyle.showGrid, + mChartStyle.showVolumes, + mChartStyle.showTradeLevels, + mChartStyle.autoScroll, + mChartStyle.quickNavigation, + mChartStyle.foreGroundColor, + mChartStyle.backGroundColor, + mChartStyle.upColor, + mChartStyle.downColor, + mChartStyle.bullishColor, + mChartStyle.bearishColor, + mChartStyle.gridColor, + mChartStyle.bidLineColor, + mChartStyle.askLineColor, + mChartStyle.lineColor, + mChartStyle.stopColor, + mChartStyle.volumesColor); +} + +// +// END Functions ... +// diff --git a/BKPS/14031106/Indicators/x-saherelm.xct.ex5 b/BKPS/14031106/Indicators/x-saherelm.xct.ex5 new file mode 100644 index 0000000000000000000000000000000000000000..c742c4fe19b8c7e2a3eceae1b77069f51ea9596a GIT binary patch literal 17034 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 literal 0 HcmV?d00001 diff --git a/BKPS/14031106/Indicators/x-saherelm.xct.mq5 b/BKPS/14031106/Indicators/x-saherelm.xct.mq5 new file mode 100644 index 0000000..ebb08a4 --- /dev/null +++ b/BKPS/14031106/Indicators/x-saherelm.xct.mq5 @@ -0,0 +1,262 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: XCT +// Description: Trend Magic Indicator ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XCT Indicator" +#property strict + +// +// START Constants ... +// + +// +#define ShortName "XCT" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input int fontSize = 15; // Font Size +input string font = "Arial"; // Font +input color clr = clrYellow; // Text Color +input ENUM_BASE_CORNER corner = CORNER_RIGHT_LOWER; // Text Position + +// +input group "Presentation"; +input bool showTimer = true; // Show Candle Time + +// +// END Inputs ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +bool isCreatedObject; +string tag; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + + // + tag = ShortName + _Symbol + ToString(_Period); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Delete Object ... + ObjectDelete(0, tag); + + // + Comment(""); +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + if (!showTimer) + { + return rates_total; + } + + // + XBarRemainsTime barRemains; + barRemains.Init( + _Symbol, + _Period + // + ); + + // + string msg = barRemains + .ToString( + "", + "", + "", + "", + "", + ":", + true + // + ); + + // + long mSpread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD); + + // + string _sp = ""; + if (mSpread < 10) + _sp = ".."; + else if (mSpread < 100) + _sp = "."; + + // + string objText = "Spread: " + IntegerToString(mSpread) + _sp + ", Next Bar in: " + msg; + + // + if (IsValid(tag) && !isCreatedObject) + { + CreateIndicatorObject(); + } + + // + if (isCreatedObject) + { + ObjectSetString(0, tag, OBJPROP_TEXT, objText); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +void CreateIndicatorObject() +{ + // + if (!showTimer || + !IsValid(tag)) + { + return; + } + + // + isCreatedObject = ObjectCreate(0, tag, OBJ_LABEL, 0, 0, 0); + ObjectSetInteger(0, tag, OBJPROP_CORNER, corner); + ObjectSetInteger(0, tag, OBJPROP_XDISTANCE, 10); + ObjectSetInteger(0, tag, OBJPROP_YDISTANCE, 2); + + // + ENUM_ANCHOR_POINT Anchor = ANCHOR_LEFT_UPPER; + switch (corner) + { + case CORNER_LEFT_UPPER: + Anchor = ANCHOR_LEFT_UPPER; + break; + case CORNER_RIGHT_UPPER: + Anchor = ANCHOR_RIGHT_UPPER; + break; + case CORNER_LEFT_LOWER: + Anchor = ANCHOR_LEFT_LOWER; + break; + case CORNER_RIGHT_LOWER: + Anchor = ANCHOR_RIGHT_LOWER; + break; + } + + // + int mFontSize = fontSize > 0 + ? fontSize + : 10; + + // + string mFont = IsValid(font) + ? font + : "Arial"; + + // + ObjectSetString(0, tag, OBJPROP_FONT, mFont); + ObjectSetInteger(0, tag, OBJPROP_COLOR, clr); + ObjectSetInteger(0, tag, OBJPROP_ANCHOR, Anchor); + ObjectSetInteger(0, tag, OBJPROP_FONTSIZE, mFontSize); +} + +// +// END Functions ... +// diff --git a/BKPS/14031106/Libraries/x-saherelm.common.lib.mq5 b/BKPS/14031106/Libraries/x-saherelm.common.lib.mq5 new file mode 100644 index 0000000..2480adf --- /dev/null +++ b/BKPS/14031106/Libraries/x-saherelm.common.lib.mq5 @@ -0,0 +1,10115 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XCommonLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-md5.class.mq5" + +// +#include + +// +// Models ... + +// +// Specified Price Type ... +enum ENUM_X_PRICE +{ + X_PRICE_HIGH, + X_PRICE_OPEN, + X_PRICE_CLOSE, + X_PRICE_LOW, + X_PRICE_UP, + X_PRICE_DOWN +}; + +// +enum ENUM_X_DIRECTION +{ + X_DIRECTION_ALL, // All + X_DIRECTION_NONE, // None + X_DIRECTION_BULLISH, // Bullish + X_DIRECTION_BEARISH, // Bearish +}; + +// +enum ENUM_X_FIBO_LEVELS +{ + X_FIBO_LEVEL_236, + X_FIBO_LEVEL_382, + X_FIBO_LEVEL_500, + X_FIBO_LEVEL_618, + X_FIBO_LEVEL_764, +}; + +// +double GetFiboLevelValue(ENUM_X_FIBO_LEVELS value) +{ + // + double result = 0; + + // + switch (value) + { + // + case X_FIBO_LEVEL_236: + result = 0.236; + break; + + // + case X_FIBO_LEVEL_382: + result = 0.382; + break; + + // + case X_FIBO_LEVEL_500: + result = 0.500; + break; + + // + case X_FIBO_LEVEL_618: + result = 0.618; + break; + + // + case X_FIBO_LEVEL_764: + result = 0.764; + break; + } + + // + return result; +} + +// +string ToString(ENUM_X_DIRECTION value) +{ + // + string result = NULL; + + // + switch (value) + { + case X_DIRECTION_ALL: + result = "ALL"; + break; + case X_DIRECTION_NONE: + result = "NONE"; + break; + case X_DIRECTION_BULLISH: + result = "BULLISH"; + break; + case X_DIRECTION_BEARISH: + result = "BEARISH"; + break; + } + + // + return result; +} + +// +// Swing Types Enum ... +enum ENUM_X_SWING_TYPE +{ + X_NO_SWING = 0, + X_SWING_HIGH = 1, + X_SWING_LOW = -1, +}; + +// +ENUM_SERIESMODE ToSeriesMode(ENUM_X_SWING_TYPE value) +{ + // + ENUM_SERIESMODE result = MODE_HIGH; + + // + switch (value) + { + // + case X_SWING_HIGH: + result = MODE_HIGH; + break; + + // + case X_SWING_LOW: + result = MODE_LOW; + break; + } + + // + return result; +} + +// +// Find Swing Points ... +int FindSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_X_SWING_TYPE mMode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (StringLen(mSymbol) == 0 || (mMode != X_SWING_HIGH && mMode != X_SWING_LOW)) + { + return result; + } + + // + int current = bar_index; + int founded = FindNextSwing( + mSymbol, + mPeriod, + mMode, + (mLength * 2) + 1, + current - mLength); + + // + while (founded != current) + { + // + current = FindNextSwing( + mSymbol, + mPeriod, + mMode, + mLength, + current + 1); + + // + founded = FindNextSwing( + mSymbol, + mPeriod, + mMode, + (mLength * 2) + 1, + current - mLength); + } + + // + result = current; + + // + return result; +} + +// +// Find Next Swing ... +int FindNextSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_X_SWING_TYPE mMode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (bar_index < 0) + { + mLength += bar_index; + bar_index = 0; + } + + // + ENUM_SERIESMODE mSeriesMode = ToSeriesMode(mMode); + + // + result = mMode == X_SWING_HIGH + ? iHighest( + mSymbol, + mPeriod, + mSeriesMode, + mLength, + bar_index) + : iLowest( + mSymbol, + mPeriod, + mSeriesMode, + mLength, + bar_index); + + // + return result; +} + +// +// XPERIOD Calculation Method ... +enum ENUM_X_PERIOD_METHOD +{ + // + X_PERIOD_NOTHING, // Nothing + X_PERIOD_AUTO, // Auto Select + X_PERIOD_MANUALLY // Manually +}; + +// +// Available Market Cycles ... +enum ENUM_X_MARKET_CYCLES +{ + // + X_MARKET_CYCLE_UNKNOWN, // Unknown Cycle + X_MARKET_CYCLE_SHORT, // Short Cycle + X_MARKET_CYCLE_MEDIUM, // Medium Cycle + X_MARKET_CYCLE_LONG, // Long Cycle + X_MARKET_CYCLE_HIND, // Hind Cycle +}; + +// +// Structs ... + +// +// Model Specified Ticks Info ... +struct XTick +{ + // + string symbol; // Symbol ... + datetime time; // Time ... + double bid; // Bid ... + double ask; // Ask ... + double spread; // Spread ... + long volume; // Volume ... + + // + // Constructor ... + void XTick() + { + Clean(); + } + + // + // Tools Functions ... + + /** + * Initial ... + * + * @param _symbol: Symbol ... + * @param _time: Time ... + * @param _bid: Bid Price ... + * @param _ask: Ask Price ... + * @param _volume: Tick Volume ... + */ + bool Init( + string _symbol, + datetime _time, + double _bid, + double _ask, + double _spread, + long _volume // + ) + { + // + bool result = false; + + // + result = IsValid(_symbol) && + IsValid(_time) && + _bid > 0 && + _ask > 0; + if (!result) + { + return result; + } + + // + bid = _bid; + ask = _ask; + time = _time; + symbol = _symbol; + spread = _spread; + + // + result = IsValid(); + + // + return result; + } + + /** + * Init Tick by Symbol ... + * + * @param _symbol: String ... + * + * @return ( bool ) + */ + bool Init(string _symbol) + { + // + bool result = false; + + // + result = IsValid(_symbol); + if (!result) + { + return result; + } + + // + datetime _time = TimeCurrent(); + double _bid = GetBid(_symbol); + double _ask = GetAsk(_symbol); + double _spread = GetSpread(_symbol); + long _volume = iTickVolume(_symbol, PERIOD_M1, 0); + + // + result = Init( + _symbol, + _time, + _bid, + _ask, + _spread, + _volume // + ); + + // + return result; + } + + /** + * Cleanup ... + */ + void Clean() + { + // + bid = 0; + ask = 0; + volume = 0; + time = NULL; + symbol = NULL; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(symbol) && + IsValid(time) && + bid > 0 && + ask > 0 && + volume >= 0; + + // + return result; + } + + // +}; + +// +// Model a Bar Remains Time ... +struct XBarRemainsTime +{ + // + int days; + int hours; + int minutes; + int seconds; + + // + // Constructor ... + XBarRemainsTime() + { + Clean(); + } + + // + // Always Calculate Current 0 Bar Timing ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetBarTime( + mSymbol, + mPeriod, + 0 + // + ); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result = true; + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + days = 0; + hours = 0; + minutes = 0; + seconds = 0; + } + + // + // To String Representation ... + string ToString( + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true + // + ) + { + // + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || days > 0) + { + result += dayId + idSeparator + (string)days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || hours > 0) + { + // + string strHour = ToString(hours); + if (StringLen(strHour) == 1) + { + strHour = "0" + strHour; + } + + // + result += hourId + idSeparator + strHour + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || minutes > 0) + { + // + string strMinute = ToString(minutes); + if (StringLen(strMinute) == 1) + { + strMinute = "0" + strMinute; + } + + // + result += minuteId + idSeparator + strMinute + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || seconds > 0) + { + // + string strSec = ToString(seconds); + if (StringLen(strSec) == 1) + { + strSec = "0" + strSec; + } + + // + result += secondId + idSeparator + strSec; + } + + // + return result; + } +}; + +// +// Describe an Specific Candle ... +struct XOHCL +{ + // + // Props ... + + // + double high; + double open; + double close; + double low; + + // + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOHCL() + { + Clean(); + } + + // + // Init a Bar ... + // Using Bar Index ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex // + ); + + // + open = iOpen( + mSymbol, + mPeriod, + barIndex // + ); + open = NormalizePrice(open, mSymbol); + + // + close = iClose( + mSymbol, + mPeriod, + barIndex // + ); + close = NormalizePrice(close, mSymbol); + + // + high = iHigh( + mSymbol, + mPeriod, + barIndex // + ); + high = NormalizePrice(high, mSymbol); + + // + low = iLow( + mSymbol, + mPeriod, + barIndex // + ); + low = NormalizePrice(low, mSymbol); + + // + bool result = IsValid(); + + // + return result; + } + + // + // Init a Bar ... + // Using Bar Time ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + datetime mTime = NULL // Bar Time + ) + { + // + mTime = NormalizeTime(mTime); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false // + ); + + // + bool result = Init( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; + } + + // + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + double mOpen = 0, // Open + double mHigh = 0, // High + double mClose = 0, // Close + double mLow = 0, // Low + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + open = mOpen; + high = mHigh; + close = mClose; + low = mLow; + + // + return IsValid(); + } + + // + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + double mOpen = 0, // Open + double mHigh = 0, // High + double mClose = 0, // Close + double mLow = 0, // Low + datetime mTime = NULL // Bar Time + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + int barIndex = iBarShift( + symbol, + period, + mTime); + + // + time = iTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + open = mOpen; + high = mHigh; + close = mClose; + low = mLow; + + // + return IsValid(); + } + + // + // Tools ... + + // + void Clean() + { + // + high = 0; + open = 0; + close = 0; + low = 0; + + // + time = NULL; + symbol = NULL; + period = NULL; + } + + // + // Validate Bar ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + high > 0 && + open > 0 && + close > 0 && + low > 0 + // + ; + + // + return result; + } + + // + int TotalBars() + { + // + int result = 0; + + // + result = iBars( + symbol, + period // + ); + + // + return result; + } + + // + // Calculate X_PRICE Specified Type ... + double GetPrice(ENUM_X_PRICE mPType) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + switch (mPType) + { + // + case X_PRICE_OPEN: + result = open; + break; + // + case X_PRICE_HIGH: + result = high; + break; + // + case X_PRICE_CLOSE: + result = close; + break; + // + case X_PRICE_LOW: + result = low; + break; + // + case X_PRICE_UP: + result = GetUp(); + break; + // + case X_PRICE_DOWN: + result = GetDown(); + break; + } + + // + return result; + } + + // + // Retrieve Price base On Series Mode ... + double GetPrice(ENUM_SERIESMODE mMode) + { + // + ENUM_X_PRICE mXMode = ToPrice(mMode); + + // + return GetPrice(mXMode); + } + + // + // Calculate Applied Price ... + double GetPrice( + ENUM_APPLIED_PRICE mAppliedTo // Select Application Method + ) + { + // + double result = 0; + + // + // Calculate Applied Price ... + switch (mAppliedTo) + { + // + case PRICE_CLOSE: + result = close; + break; + + // + case PRICE_OPEN: + result = open; + break; + + // + case PRICE_HIGH: + result = high; + break; + + // + case PRICE_LOW: + result = low; + break; + + // + case PRICE_MEDIAN: + result = (high + low) / 2; + break; + + // + case PRICE_TYPICAL: + result = (high + low + close) / 3; + break; + + // + case PRICE_WEIGHTED: + result = (high + low + close + close) / 4; + break; + } + + // + return result; + } + + // + // Find Specific Price ... + bool FindHigherPriceBar( + XOHCL &bar, + double price, + ENUM_X_PRICE _type = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = TotalBars(); + result = IsValidSize(totalBars); + if (!result) + { + return result; + } + + // + int start = Index(); + int maxAllowedLoopback = totalBars / 5; + for (int i = start; i < maxAllowedLoopback; i++) + { + // + result = bar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + break; + } + + // + double iPrice = bar.GetPrice(_type); + + // + result = + // + iPrice > 0 && + iPrice > price + // + ; + if (result) + { + break; + } + } + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Find Specific Price ... + bool FindLowerPriceBar( + XOHCL &bar, + double price, + ENUM_X_PRICE _type = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = TotalBars(); + result = IsValidSize(totalBars); + if (!result) + { + return result; + } + + // + int start = Index(); + int maxAllowedLoopback = totalBars / 5; + for (int i = start; i < maxAllowedLoopback; i++) + { + // + result = bar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + break; + } + + // + double iPrice = bar.GetPrice(_type); + + // + result = + // + iPrice > 0 && + iPrice < price + // + ; + if (result) + { + break; + } + } + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Calculate Bar Mid Line ... + double GetMid() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = (high + low) / 2; + + // + return result; + } + + // + // Calculate up Price ... + double GetUp() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMax(open, close); + + // + return result; + } + + // + // Calculate Down Price ... + double GetDown() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMin(open, close); + + // + return result; + } + + // + // Calculate Bar Body ... + double GetBody() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetUp() - GetDown(); + + // + return result; + } + + // + // Calculate Bar Range ... + double GetRange() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = high - low; + + // + return result; + } + + // + // Calculate Bar Shadows ... + double GetShadows() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetRange() - GetBody(); + + // + return result; + } + + // + // Calculate Bar High Shadow ... + double GetHighShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + high - GetUp() + // + ; + + // + return result; + } + + // + // Calculate Bar Low Shadow ... + double GetLowShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetDown() - low; + // + ; + + // + return result; + } + + // + // Check Bar is Bullish ... + bool IsBullish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open < close; + + // + return result; + } + + // + // Check Bar is Bearish ... + bool IsBearish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open > close; + + // + return result; + } + + // + // Get Direction of Bar ... + ENUM_X_DIRECTION GetDirection() + { + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + bool isBullish = IsBullish(); + bool isBearish = IsBearish(); + + // + result = + isBullish && isBearish + ? X_DIRECTION_ALL + : !isBullish && !isBearish + ? X_DIRECTION_NONE + : isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Find Next Bar Time ... + datetime NextAt() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time + prSeconds; + + // + return result; + } + + // + // Find Prev Bar Time ... + datetime BeforeOn() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time - prSeconds; + + // + return result; + } + + // + // Calculate Last Bar Open Time in Smaller Period ... + datetime GetLastBarTimeOfPeriod( + ENUM_TIMEFRAMES smallerPeriod // + ) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int sourceSeconds = PeriodSeconds(period); + int destSeconds = PeriodSeconds(smallerPeriod); + if (destSeconds >= sourceSeconds) + { + // + result = time; + return result; + } + + // + result = (datetime)((((int)time) + sourceSeconds) - destSeconds); + + // + return result; + } + + // + // Calculate Close Time ... + datetime GetCloseTime() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int seconds = PeriodSeconds(period); + + // + result = (datetime)(((int)time) + seconds); + + // + return result; + } + + // + bool BarAt( + int index, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + if (index < 0) + { + index = 0; + } + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + // + bool BarIn( + ENUM_TIMEFRAMES _period, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid() && + IsSpecifiedValid(_period); + if (!result) + { + return result; + } + + // + int index = Index(_period); + result = bar.Init( + symbol, + _period, + index // + ); + + // + return result; + } + + // + // Find Current Bar Index on Chart ... + int Index() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + time + // + ); + + // + return result; + } + + // + int Index(datetime value) + { + // + int result = -1; + + // + value = NormalizeTime(value); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + value // + ); + + // + return result; + } + + // + int Index(ENUM_TIMEFRAMES value) + { + // + int result = -1; + + // + result = IsValid() && + IsSpecifiedValid(value); + if (!result) + { + return result; + } + + // + result = iBarShift( + symbol, + value, + time // + ); + + // + return result; + } + + // + bool GetNextBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + result = idx > 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + this.symbol, + this.period, + idx - 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + bool GetPreviousBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + + // + result = bar.Init( + this.symbol, + this.period, + idx + 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Find Highest Bar Index ... + int FindHighestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iHighest( + symbol, + period, + mMode, + mLength, + Index()); + + // + return result; + } + + // + // Find Highest ... + double FindHighest( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindHighestIndex( + mLength, + mMode); + if (idx <= -1) + { + return result; + } + + // + XOHCL iH; + result = iH.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iH.GetPrice(mMode); + + // + return result; + } + + // + // Find Highest ... + double FindHighestUp( + int mLength // Loopback ... + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = FindHighest(mLength, MODE_OPEN); + result = MathMax(mLength, FindHighest(mLength, MODE_CLOSE)); + + // + return result; + } + + // + // Find Lowest Bar Index ... + int FindLowestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iLowest( + symbol, + period, + mMode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindLowest( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindLowestIndex( + mLength, + mMode); + if (idx <= -1) + { + return result; + } + + // + XOHCL iL; + result = iL.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iL.GetPrice(mMode); + + // + return result; + } + + // + // Find Lowest ... + double FindLowesttDown( + int mLength // Loopback ... + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = FindLowest(mLength, MODE_OPEN); + result = MathMax(mLength, FindLowest(mLength, MODE_CLOSE)); + + // + return result; + } + + // + // Other ... + string GetTag(string prefix = "") + { + // + string result = NULL; + + // + result = + (IsValid(prefix) + ? prefix + "_" + : "") + + "XOHCL_" + symbol + "_" + ToString(period) + "_" + ToFormatString(time); + + // + return result; + } + + // + // Convert to String Representation ... + string ToString() + { + // + string result = ""; + + // + result = GetTypeName(this) + + "(O(" + ToString(open) + "),H(" + ToString(high) + "),C(" + ToString(close) + "),L(" + ToString(low) + "))"; + + // + return result; + } +}; + +// +// Tracking Times ... +struct XTimeTracker +{ + // + // Props ... + int xMonth; + int xDayOfWeek; + int xForWeekDay; + int xDay; + int xHour; + int xMinute; + + // + // Constructor ... + XTimeTracker() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + xDay = -1; + xHour = -1; + xMonth = -1; + xMinute = -1; + xDayOfWeek = -1; + xForWeekDay = -1; + } + + // + // Detecting New Minute ... + bool IsNewMinute() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.min != xMinute; + if (result) + { + xMinute = timeStruct.min; + } + + // + return result; + } + + // + // Detecting New Houre ... + bool IsNewHour() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; + } + + // + // Detecting New Day ... + bool IsNewDay() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; + } + + // + // Detecting New Week ... + bool IsNewWeek() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; + } + + // + // Detecting End Of Week ... + bool IsWeekEnd() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; + } + + // + // Detecting New Month ... + bool IsNewMonth() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; + } +}; + +// +// Tracking Bars on Specified Environment ... +struct XBarTracker +{ + // + string symbol; // Tracking Symbol + ENUM_TIMEFRAMES period; // Tracking Time Frame + + // + int lastTrackedBar; // Last Tracked Bar ... + + // + bool waitsUntilNext; // Waits Until Next Bar ... + + // + // Constructor ... + XBarTracker() + { + Clean(); + } + + // + // Initializer ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + this.symbol = mSymbol; + this.period = mPeriod; + + // + this.lastTrackedBar = 0; + + // + result = true; + + // + return result; + } + + // + // Retrieve all Bars ... + int CountBars() + { + // + return iBars( + symbol, + period + // + ); + } + + // + // Check if it's New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + int currentBars = CountBars(); + + // + result = currentBars > lastTrackedBar; + if (result) + { + lastTrackedBar = currentBars; + } + + // + return result; + } + + // + bool CanProcessBar() + { + // + bool _isInTestMode = IsRunningOnTestMode(); + + // + bool isNewBar = IsNewBar(); + + // + bool result = + _isInTestMode + ? isNewBar + : !waitsUntilNext + ? true + : isNewBar; + if (result && waitsUntilNext) + { + waitsUntilNext = false; + } + + // + return result; + } + + // + void Waits() + { + this.waitsUntilNext = true; + } + + // + // Tools ... + void Clean() + { + // + symbol = NormalizeSymbol(NULL); + period = NormalizePeriod(NULL); + } + + // + bool GetBar( + XOHCL &bar, + int index = 0 // + ) + { + // + bool result = false; + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + // + bool GetBar( + XOHCL &bar, + datetime time = NULL // + ) + { + // + bool result = false; + + // + NormalizeTime(time); + + // + int barIndex = iBarShift( + symbol, + period, + time, + false // + ); + + // + result = barIndex >= 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + symbol, + period, + barIndex // + ); + + // + return result; + } + + // + int Index(datetime time = NULL) + { + // + int result = 0; + + // + NormalizeTime(time); + + // + result = iBarShift( + symbol, + period, + time, + false // + ); + + // + return result; + } +}; + +// +// Model a Market Cycle ... +struct XMarketCycle +{ + // + // Props ... + + // + string prefix; // Prefix Trag ... + + // + string symbol; // Market Symbol ... + + // + ENUM_TIMEFRAMES period; // Period of Cycle ... + ENUM_X_PERIOD_METHOD method; // Period Selection Method ... + ENUM_X_MARKET_CYCLES cycle; // Cycles of MArket ... + + // + int length; // Number Of Candles per Current Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Current Time Frame ... + + // + datetime lastStart; // Last Candle Bar Time ... + + // + XBarTracker barTracker; // Bar Tracker ... + XBarRemainsTime remains; // Current Bar Remains Model ... + + // + // Constructor ... + XMarketCycle() + { + Clean(); + } + + // + // Init Cycle ... + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mHostPeriod = NormalizePeriod(mHostPeriod); + + // + result = IsValid(mCycle); + if (!result) + { + return result; + } + + // + this.cycle = mCycle; + + // + // Set Automatically Prefix ... + if (StringLen(mPrefix) == 0) + { + this.prefix = ToString(cycle); + } + + // + result = IsValid( + method, + period // + ); + if (!result) + { + return result; + } + + // + this.symbol = mSymbol; + this.hostPeriod = mHostPeriod; + + // + // Find Cycle Period ... + if (method == X_PERIOD_AUTO) + { + // + // Select Period ... + this.period = GetCyclePeriod( + this.cycle, + this.hostPeriod); + } + + // + // Set Prefix if Provided ... + if (StringLen(mPrefix) > 0) + { + this.prefix = mPrefix; + } + + // + // Calculate Required Info ... + + // + // Length ... + this.length = PeriodSeconds(this.period) / PeriodSeconds(this.hostPeriod); + + // + // Update Additional Data ... + result = this.Update(0); + + // + return result; + } + + // + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + ENUM_X_PERIOD_METHOD mMethod, // Period Selection Method + ENUM_TIMEFRAMES mPeriod, // Provided Period + string mPrefix = "" // Prefix + ) + { + // + this.period = mPeriod; + this.method = mMethod; + + // + return Init( + mSymbol, + mHostPeriod, + mCycle, + mPrefix + // + ); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + length = 0; + lastStart = 0; + + // + cycle = NULL; + prefix = NULL; + symbol = NULL; + period = NULL; + method = NULL; + hostPeriod = NULL; + + // + remains.Clean(); + barTracker.Clean(); + } + + // + // Check Structure Valid ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid( + method, + period); + if (!result) + { + return result; + } + + // + result = + // + length > 0 && + symbol != NULL && + period != NULL && + method != NULL && + hostPeriod != NULL && + method != X_PERIOD_NOTHING + // + ; + + // + return result; + } + + // + // Update Market Cycle Additional Info ... + bool Update(int hostBarIndex) + { + // + bool result = false; + + // + result = this.IsValid(); + if (!result) + { + return result; + } + + // + // Init Remains ... + result = remains.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + // Init Bar Tracker ... + result = barTracker.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Count Bars ... + int CountBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.CountBars(); + + // + return result; + } + + // + // Check New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.IsNewBar(); + + // + return result; + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + return result; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + // + result = totalBars - 1; + return result; + } + + // + datetime hostBarTime = iTime( + this.symbol, + this.hostPeriod, + barIndex + // + ); + + // + result = iBarShift( + this.symbol, + this.period, + hostBarTime + // + ); + + // + return result; + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + XOHCL result; + result.Init( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Extract Specific Range of Bars ... + // using Start Bar Index ... + int GetBars( + XOHCL &result[], // Hold Result + int from = 0, // Start Bar Index + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + if (from < 0) + { + from = 0; + } + + // + int total = Bars( + symbol, + period); + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + if (forceClean) + { + Clean(result); + } + + // + int beforeSize = ArraySize(result); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + symbol, + period, + i + // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + result + // + ); + } + } + + // + int afterSize = ArraySize(result); + + // + mResult = afterSize - beforeSize; + + // + return mResult; + } + + // + // Extract Specific Range of Bars ... + // using Start Bar Time ... + int GetBars( + XOHCL &result[], // Hold Result + datetime from = NULL, // Start Bar Time + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array + ) + { + // + from = NormalizeTime(from); + + // + int barIndex = iBarShift( + symbol, + period, + from, + false + // + ); + + // + return GetBars( + result, + symbol, + period, + barIndex, + count, + forceClean + // + ); + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + result = iTime( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Find Chart ID ... + ulong GetChartID() + { + // + ulong result = 0; + + // + long firstChart = ChartFirst(); + result = firstChart; + + // + while (result >= 0) + { + // + string chSymbol = ChartSymbol(result); + ENUM_TIMEFRAMES chPeriod = ChartPeriod(result); + + // + bool isOwnChart = + // + symbol == chSymbol && + period == chPeriod + // + ; + if (isOwnChart) + { + break; + } + + // + result = ChartNext(result); + if (result < 0) + { + break; + } + } + + // + return result; + } + + // + // Create and String Representation for Unique Taging ... + string ToString() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = + GetTypeName(this) + "(" + + "PRFX(" + this.prefix + ")" + + "SMBL(" + this.symbol + ")" + + "CYC(" + ToString(this.cycle) + ")" + + "PRD(" + ToString(this.period) + ")" + + "PRDHST(" + ToString(this.hostPeriod) + ")" + + "MTH(" + EnumToString(this.method) + ")" + + ")"; + + // + return result; + } + + // + // Here we Produce a Summary brief of + // state of Cycle ... + string GenerateSummary() + { + // + string result = ""; + + // + bool hasPrefix = + StringLen(this.prefix) > 0 && + this.prefix != ToString(this.cycle); + result += (hasPrefix ? this.prefix + "[" : "") + + ToString(this.cycle) + + (hasPrefix ? "]" : "") + "\n"; + + // + result += " - PR: " + ToString(this.period) + "\n"; + + // + XOHCL cBar = GetBar(0); + + // + result += " - State: " + (cBar.IsBullish() ? "Bullish" : cBar.IsBearish() ? "Bearish" + : "Neutural"); + + // + return result; + } +}; + +// +// Linear Regression ... + +// +struct XLinearRegressionWorkStruct +{ + // + struct sDataStruct + { + // + double value; + double sumY; + double sumXY; + }; + + // + sDataStruct data[]; + + // + int dataSize; + int period; + double sumX; + double sumXX; + double divisor; + + // + // Constructor ... + XLinearRegressionWorkStruct() + : dataSize(-1), period(-1) + { + } +}; + +// +struct XLinearRegression +{ + // + XLinearRegressionWorkStruct m_work; + + // + // Calculate Linear Regression ... + double Calculate( + double value, + int period, + double &_slope, + double &_intercept, + int r, + int bars // + ) + { + // + if (m_work.dataSize <= bars) + { + m_work.dataSize = ArrayResize(m_work.data, bars + 500, 2000); + } + + // + if (period < 1) + { + period = 1; + } + + // + if (m_work.period != (int)period) + { + // + m_work.period = (int)period; + m_work.sumX = m_work.period * (m_work.period - 1.0) / 2.0; + m_work.sumXX = m_work.period * (m_work.period - 1.0) * (2.0 * m_work.period - 1.0) / 6.0; + m_work.divisor = m_work.sumX * m_work.sumX - m_work.period * m_work.sumXX; + + // + if (m_work.divisor) + { + m_work.divisor = 1.0 / m_work.divisor; + } + } + + // + m_work.data[r].value = value; + + // + if (r >= m_work.period) + { + // + m_work.data[r].sumY = m_work.data[r - 1].sumY + value - m_work.data[r - m_work.period].value; + m_work.data[r].sumXY = m_work.data[r - 1].sumXY + m_work.data[r].sumY - m_work.data[r - m_work.period].value * (m_work.period - 1.0) - value; + } + else + { + // + m_work.data[r].sumY = value; + m_work.data[r].sumXY = 0; + + // + for (int _k = 1; _k < m_work.period && r >= _k; _k++) + { + // + m_work.data[r].sumY += m_work.data[r - _k].value; + m_work.data[r].sumXY += _k * m_work.data[r - _k].value; + } + } + + // + _slope = (m_work.period * m_work.data[r].sumXY - m_work.sumX * m_work.data[r].sumY) * m_work.divisor; + _intercept = (m_work.data[r].sumY - _slope * m_work.sumX) / (double)m_work.period; + + // + double result = (_intercept + _slope * (m_work.period - 1.0)); + + // + return result; + } + + // +}; + +// +// Use To Parse Symbols for +// Ignore Brokers Additional Suffixes ... +struct XSymbolParser +{ + // + string version; // Temp ... + + // + // Symbol Parsing ... + + // + // Forext ... + + // + bool IsEURUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDJPY(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "JPY" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURJPY(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "JPY" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDCHF(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "CHF" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURCHF(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "CHF" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsGBPUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "GBP", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURGBP(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "GBP" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsAUDUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "AUD", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURAUD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "AUD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDCAD(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "CAD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURCAD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "CAD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsNZDUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "NZD", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURNZD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "NZD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + // Metals ... + + // + bool IsXAUUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "XAU", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsXAGUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "XAG", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + // Indexes ... + + // + bool IsDowJones(string symbol) + { + // + bool result = Contains( + "DowJones30", + symbol // + ); + + // + return result; + } + + // + // Oil ... + + // + bool IsBrent(string symbol) + { + // + bool result = Contains( + "BRENT", + symbol // + ); + + // + return result; + } + + // + // Symbol Finder ... + string GetEURUSDSymbol() + { + // + string result = NULL; + + // + string symbols[]; + int symbolsCount = GetAllSymbols( + symbols // + ); + if (!IsValidSize(symbolsCount)) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = symbols[i]; + if (IsEURUSD(iSymbol)) + { + // + result = iSymbol; + break; + } + } + + // + return result; + } +}; + +// +struct XSymbolSessionParser +{ + // + string version; // Temp ... + + // + // Check Market Is Open for Specific Symbol + // in Current Time ... + bool CanTrade( + string symbol // Trading Symbol + ) + { + // + bool result = false; + + // + result = IsValid(symbol); + if (!result) + { + return result; + } + + // + MqlDateTime timeStruct; + result = TimeCurrent(timeStruct); + if (!result) + { + return result; + } + + // + ENUM_DAY_OF_WEEK dayOfWeek = (ENUM_DAY_OF_WEEK)timeStruct.day_of_week; + + // + datetime cTime = TimeCurrent(); + + // + datetime from; + datetime to; + result = SymbolInfoSessionTrade( + symbol, + dayOfWeek, + 0, // Session Index ... + from, + to // + ); + if (!result) + { + return result; + } + + // + result = cTime > from && cTime < to; + + // + return result; + } +}; + +// +// Parsing Market Names ... +struct XMarketParser +{ + // + string _version; // Temp ... + + // + bool IsIngot(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // + bool IsErrante(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // + bool IsAMarkets(string market) + { + // + bool result = false; + + // + result = IsValid(market) && + market == "AMarkets LLC"; + + // + return result; + } + + // + bool IsIFCMarkets(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // + bool IsOtetMarkets(string market) + { + // + bool result = false; + + // + // result = IsValid(market) && + // market == ""; + + // + return result; + } + + // +}; + +// +// Functions ... + +// +// Validators ... + +// +// Validate an String has length and not NULL ... +bool IsValid(string value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + StringLen(value) > 0 + // + ; + + // + return result; +} +bool IsSpecifiedValid(string value) +{ + return IsValid(value); +} + +// +// Validate a Date ... +bool IsValid(datetime value) +{ + // + bool result = false; + + // + result = NotEmpty(value) && value != NULL; + + // + return result; +} +bool IsSpecifiedValid(datetime value) +{ + return IsValid(value); +} + +// +// Validate a Period Param ... +bool IsValid(ENUM_TIMEFRAMES value) +{ + // + bool result = false; + + // + result = + // + value != NULL + // + ; + + // + return result; +} +bool IsSpecifiedValid(ENUM_TIMEFRAMES value) +{ + // + return IsValid(value); +} + +// +// Validate Specified Cycle ... +bool IsValid(ENUM_X_MARKET_CYCLES value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_MARKET_CYCLE_UNKNOWN + // + ; + + // + return result; +} + +// +// Validate Specific Period Mode ... +bool IsValid( + ENUM_X_PERIOD_METHOD mMethod, // Period Select Method + ENUM_TIMEFRAMES mPeriod // Selected Period +) +{ + // + bool result = false; + + // + result = + // + mMethod == X_PERIOD_NOTHING + ? false + : mMethod == X_PERIOD_MANUALLY + ? mPeriod != NULL + : mMethod == X_PERIOD_AUTO + ? true + : false + // + ; + + // + return result; +} + +// +bool IsSpecifiedValid( + ENUM_X_PERIOD_METHOD mMethod, // Period Select Method + ENUM_TIMEFRAMES mPeriod // Selected Period +) +{ + return IsValid(mMethod, + mPeriod // + ); +} + +// +// Validate Swing Mode ... +bool IsValid(ENUM_X_SWING_TYPE value) +{ + // + bool result = false; + + // + result = + // + value == X_SWING_HIGH || + value == X_SWING_LOW + // + ; + + // + return result; +} + +// +// As IS ... + +// +// Determine a Position type is Long or not ... +bool IsLong(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_BUY; + + // + return result; +} +bool IsLong(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_BUY; + + // + return result; +} + +// +// Determine a Position type is Short or not ... +bool IsShort(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_SELL; + + // + return result; +} +bool IsShort(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_SELL; + + // + return result; +} + +// +// Retrieve Opposit Direction Type ... +ENUM_POSITION_TYPE GetOpposit(ENUM_POSITION_TYPE type) +{ + // + ENUM_POSITION_TYPE result = NULL; + + // + bool isLong = IsLong(type); + result = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + + // + return result; +} +ENUM_ORDER_TYPE GetOpposit(ENUM_ORDER_TYPE type) +{ + // + ENUM_ORDER_TYPE result = NULL; + + // + bool isLong = IsLong(type); + result = isLong + ? ORDER_TYPE_SELL + : ORDER_TYPE_BUY; + + // + return result; +} + +// +string ToString(ENUM_POSITION_TYPE value) +{ + // + string result = NULL; + + // + result = + // + IsLong(value) + ? "Long" + : "Short" + // + ; + + // + return result; +} +string ToString(ENUM_ORDER_TYPE value) +{ + // + string result = NULL; + + // + result = + // + IsLong(value) + ? "Long" + : "Short" + // + ; + + // + return result; +} + +// +// Check Expert Running in Testing Mode or not ... +bool IsRunningOnTestMode() +{ + // + bool result = false; + + // + // check programm mode ... + result = MQL5InfoInteger(MQL5_TESTING); + + // + return result; +} + +// +// Find Chart ID ... +long FindChartID( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period +) +{ + // + long result = ChartFirst(); + long first = result; + + // + while (result > 0) + { + // + string chSymbol = ChartSymbol(result); + ENUM_TIMEFRAMES chPeriod = ChartPeriod(result); + + // + bool isOwn = + // + chSymbol == mSymbol && + chPeriod == mPeriod + // + ; + if (isOwn) + { + break; + } + + // + result = ChartNext(result); + } + + // + return result; +} + +// +// Normalizers ... + +// +// Check a Symbol provided or not ... +// if not use Default ... +string NormalizeSymbol(string value) +{ + // + string result = value; + + // + if (!IsValid(result)) + { + result = _Symbol; + } + + // + return result; +} + +// +// Check a Datetime provided or not ... +// if not use Current ... +datetime NormalizeTime(datetime value) +{ + // + datetime result = value; + + // + if (!IsValid(result)) + { + result = TimeCurrent(); + } + + // + return result; +} + +// +// Check a Period provided or not ... +// if not use Default ... +ENUM_TIMEFRAMES NormalizePeriod(ENUM_TIMEFRAMES value) +{ + // + ENUM_TIMEFRAMES result = value; + + // + if (!IsValid(value)) + { + result = _Period; + } + + // + return result; +} + +// +// Normalize Cycle ... +ENUM_X_MARKET_CYCLES NormalizeCycle(ENUM_X_MARKET_CYCLES value) +{ + // + ENUM_X_MARKET_CYCLES result = value; + + // + if (!IsValid(result)) + { + result = X_MARKET_CYCLE_SHORT; + } + + // + return value; +} + +// +// Validate a Buffer Size for Looping or etc ... +bool IsValidSize(int size) +{ + // + bool result = size > 0; + + // + return result; +} + +template +bool IsValidSize(T &buffer[]) +{ + // + bool result = false; + + // + result = + // + IsValidSize(ArraySize(buffer)) + // + ; + + // + return result; +} + +// +// Check a Given Index is Valid or not ... +bool IsValidIndex(int index) +{ + return index >= 0; +} + +// +// Normalize Index Based On Specified Buffer ... +template +void NormalizeIndex( + int &index, + T &buffer[] // +) +{ + // + int bufferSize = ArraySize(buffer); + + // + if (bufferSize <= 0) + { + index = 0; + } + + // + if (index <= 0) + { + index = 0; + } + + // + if (index > bufferSize - 1) + { + index = bufferSize - 1; + } +} + +// +// Normalize Start and Count based on Specified Buffer ... +template +void NormalizeCount( + int &start, + int &count, + T &buffer[] // +) +{ + // + // Validate Buffer Size ... + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return; + } + + // + // Normalization Start ... + NormalizeIndex( + start, + buffer // + ); + + // + if (count < start) + { + count = (start - count); + } + + // + // Normalization Count ... + + // + if (count < 0) + { + count = start; + } + + // + if (count > bufferSize) + { + count = bufferSize; + } +} + +// +// Normalize a give Volume ... +double NormalizeVolume( + double mVolume, // desired volume to normalize + string mSymbol = NULL, // Trading Symbol + int mLength = 2 // Length of Digits +) +{ + // + double result = mVolume; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + // Normalize Digits ... + int digits = GetDigits(mSymbol); + + // + mLength = + mLength == 0 || mLength > digits + ? digits + : MathMin(mLength, digits); + + // + // Normalize Volume ... + result = NormalizeDouble(result, mLength); + + // + double maxAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MIN); + + // + // Validate Result ... + if (result > maxAvailableVolume) + { + result = maxAvailableVolume; + } + else if (result < minAvailableVolume) + { + result = minAvailableVolume; + } + + // + return result; +} + +// +// Normallize Price ... +double NormalizePrice( + double mPrice, // desired Price for normalization + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double tickSize = 0; + result = SymbolInfoDouble(mSymbol, SYMBOL_TRADE_TICK_SIZE, tickSize); + + // + int digits = GetDigits(mSymbol); + result = NormalizeDouble(MathRound(mPrice / tickSize) * tickSize, digits); + + // + return result; +} + +// +// Prices ... + +// +// Retrieve Ask Price ... +double GetAsk( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + + // + return result; +} + +// +// Retrieve Bid Price ... +double GetBid( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_BID); + + // + return result; +} + +// +// Retrieve Spread Price ... +double GetSpread( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double ask = GetAsk(mSymbol); + double bid = GetBid(mSymbol); + + // + double result = MathAbs(ask - bid); + + // + return result; +} + +// +// Retrieve Point Value ... +double GetPoints( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_POINT); + + // + return result; +} + +// +// Retrieve Point Digits ... +int GetDigits( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int result = (int)SymbolInfoInteger(mSymbol, SYMBOL_DIGITS); + + // + return result; +} + +// +// Retrieve Entry Price ... +double GetEntry( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetEntry( + string mSymbol = NULL, // Trading Symbol + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsBullish(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Retrieve Exit Price ... +double GetExit( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetExit( + string mSymbol = NULL, // Trading Symbol + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsBullish(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Get 1 Pip in Price Value ... +double GetPipPrice( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double symbolPoint = GetPoints(mSymbol); + int symbolDigits = GetDigits(mSymbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) + { + result *= 10; + } + + // + return result; +} + +// +// Converts Pips To Price ... +double PipsToPrice( + double mPips, // pips amount + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipValue = GetPipPrice(mSymbol); + double result = mPips * pipValue; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Price to Pips ... +double PriceToPips( + double mPrice, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPrice = NormalizePrice(mPrice, mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipPrice = GetPipPrice(mSymbol); + + // + double result = mPrice / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Convert Price to Point ... +double PriceToPoint( + double price, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + price = NormalizePrice(price, mSymbol); + + // + double point = GetPoints(mSymbol); + result = price / point; + + // + return result; +} + +// +// Converts Point to Price ... +double PointToPrice( + double points, // Points Amount + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double point = GetPoints(mSymbol); + result = points * point; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Series Mode to XPRICE ... +ENUM_X_PRICE ToPrice( + ENUM_SERIESMODE mMode // Specified Series Mode ... +) +{ + // + ENUM_X_PRICE result = X_PRICE_CLOSE; + + // + switch (mMode) + { + // + // High ... + case MODE_HIGH: + result = X_PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = X_PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = X_PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: + default: + result = X_PRICE_CLOSE; + break; + } + + // + return result; +} + +// +// Retrieve Applied Price ... +template +double GetAppliedPrice( + ENUM_APPLIED_PRICE tprice, // Type of Price Selection + T &open[], // Open Prices + T &high[], // High Preices + T &low[], // Low Prices + T &close[], // Close Prices + int i // Bar Index +) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} + +// +double iGetPrice( + int tprice, + double open, + double high, + const double low, + const double close // +) +{ + // + switch (tprice) + { + case PRICE_CLOSE: + return (close); + case PRICE_OPEN: + return (open); + case PRICE_HIGH: + return (high); + case PRICE_LOW: + return (low); + case PRICE_MEDIAN: + return ((high + low) / 2.0); + case PRICE_TYPICAL: + return ((high + low + close) / 3.0); + case PRICE_WEIGHTED: + return ((high + low + close + close) / 4.0); + } + + // + return (0); +} + +/** + * Calculates Price Change Percentage based on + * Several Params ... + * + * @param _symbol: Symbol ... + * @param _period: Time Frame ... + * @param _from: start Bar Index ... + * @param _length: Length of Bars ... + * + * @return ( double ) + */ +double GetPriceChanged( + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + int _from = 0, + int _length = 3 // +) +{ + // + double result = 0; + + // + NormalizeSymbol(_symbol); + NormalizePeriod(_period); + + // + if (_from < 0) + { + _from = 0; + } + + // + if (_length < 2) + { + _length = 2; + } + + // + double closes[]; + int copiedCloses = CopyClose( + _symbol, + _period, + _from, + _length, + closes // + ); + if (copiedCloses < _length) + { + return result; + } + ArrayReverse(closes); + + // + double change = (closes[0] - closes[_length - 1]) / closes[_length - 1] * 100; + result = change; + + // + return result; +} + +// +// Calculate TP/SL for Specified Type of Positions ... +void CalculateTPSL( + double &mSL, // Hold SL + double &mTP, // Hold TP + ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell) + double mEntry, // Entry Price + double mR2R = 1, // Provided Risk To Reward Ratio + double slPrice = 0, // Provided SL Price + double tpPrice = 0, // Provided TP Price + double priceToRisk = 0, // If Entry equal to Provided SL Price Risk Point + double priceToReward = 0 // If Entry equal to Provided TP Price Reward Point +) +{ + // + // if Both TP and SL Provided, ignore R2R and Calculate direct ... + // if SL provided, Calculate TP based on Provided R2R ... + // if TP provided, Calculate SL based on Provided R2R ... + // default R2R is set to 1 ... + + // + mSL = 0; + mTP = 0; + + // + bool isLong = IsLong(mType); + + // + // Set Default R2R ... + if (mR2R < 1) + { + mR2R = 1; + } + + // + if (mEntry <= 0 || + (tpPrice <= 0 && slPrice <= 0)) + { + return; + } + + // + double risk = 0; + double reward = 0; + + // + bool canCalculateBasedOnSL = slPrice > 0 && + (isLong + ? slPrice <= mEntry + : slPrice >= mEntry); + + // + bool canCalculateBasedOnTP = tpPrice > 0 && + (isLong + ? tpPrice >= mEntry + : tpPrice <= mEntry); + + // + if (canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + risk = MathAbs(mEntry - slPrice); + if (risk == 0) + { + risk = priceToRisk; + } + reward = risk * mR2R; + } + else if (!canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = MathAbs(mEntry - tpPrice); + if (reward == 0) + { + reward = priceToReward; + } + risk = reward / mR2R; + } + else if (!canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + bool canSetTPPrice = isLong + ? tpPrice > mEntry + : tpPrice < mEntry; + if (canSetTPPrice) + { + mTP = tpPrice; + } + + // + bool canSetSLPrice = isLong + ? slPrice < mEntry + : slPrice > mEntry; + if (canSetSLPrice) + { + mSL = slPrice; + } + + // + return; + } + else if (canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + bool canSetTPPrice = isLong + ? tpPrice > mEntry + : tpPrice < mEntry; + if (canSetTPPrice) + { + mTP = tpPrice; + } + + // + bool canSetSLPrice = isLong + ? slPrice < mEntry + : slPrice > mEntry; + if (canSetSLPrice) + { + mSL = slPrice; + } + + // + return; + } + + // + mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + mSL = isLong + ? mEntry - risk + : mEntry + risk; +} + +// +bool CalculateTPSLByPoint( + double &mSL, // Hold SL + double &mTP, // Hold TP + ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell) + double mEntry, // Entry Price + double mPointValue, // Point Value + double mR2R = 1, // Provided Risk To Reward Ratio + double slPoint = 0, // Provided SL Point + double tpPoint = 0 // Provided TP Point +) +{ + // + bool result = false; + + // + mSL = 0; + mTP = 0; + + // + bool isLong = IsLong(mType); + + // + // Set Default R2R ... + if (mR2R < 1) + { + mR2R = 1; + } + + // + if (mEntry <= 0 || + mPointValue <= 0 || + (slPoint <= 0 && tpPoint <= 0)) + { + return result; + } + + // + double risk = 0; + double reward = 0; + + // + bool canCalculateBasedOnSL = slPoint > 0; + + // + bool canCalculateBasedOnTP = tpPoint > 0; + + // + if (!canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + return result; + } + + // + if (canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = tpPoint * mPointValue; + risk = slPoint * mPointValue; + } + else if (!canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = tpPoint * mPointValue; + risk = reward / mR2R; + } + else if (canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + risk = slPoint * mPointValue; + reward = risk * mR2R; + } + + // + result = risk > 0 && reward > 0; + if (!result) + { + return result; + } + + // + mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + return result; +} + +// +bool CalculateTPSLByPrice( + double &mSL, // Hold SL + double &mTP, // Hold TP + ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell) + double mEntry, // Entry Price + double mR2R = 1 // Provided Risk To Reward Ratio +) +{ + // + bool result = false; + + // + bool isLong = IsLong(mType); + + // + // Set Default R2R ... + if (mR2R < 1) + { + mR2R = 1; + } + + // + if (mEntry <= 0 || + (mSL <= 0 && mTP <= 0)) + { + return result; + } + + // + double risk = 0; + double reward = 0; + + // + bool canCalculateBasedOnSL = mSL > 0; + bool canCalculateBasedOnTP = mTP > 0; + + // + if ( + !canCalculateBasedOnSL && + !canCalculateBasedOnTP) + { + return result; + } + + // + if (!canCalculateBasedOnSL && canCalculateBasedOnTP) + { + // + reward = MathAbs(mTP - mEntry); + risk = reward / mR2R; + } + else if (canCalculateBasedOnSL && !canCalculateBasedOnTP) + { + // + risk = MathAbs(mEntry - mSL); + reward = risk * mR2R; + } + + // + result = risk > 0 && reward > 0; + if (!result) + { + return result; + } + + // + mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + return result; +} + +/** + * Retrieve Current Tick ... + */ +bool GetTick( + string mSymbol, + MqlTick &tick // +) +{ + return SymbolInfoTick(mSymbol, tick); +} + +/** + * Retrieve Tick Entry ... + */ +double GetTickEntry( + MqlTick &mTick, + ENUM_POSITION_TYPE type, + string mSymbol = NULL // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? mTick.ask + : mTick.bid; + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +/** + * Retrieve Tick Exit ... + */ +double GetTickExit( + MqlTick &mTick, + ENUM_POSITION_TYPE type, + string mSymbol = NULL // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? mTick.bid + : mTick.ask; + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +/** + * Calculate Momentum Changes based on Given Price + */ +double CalculateMomentum( + double currentPrice, + double previousPrice // +) +{ + // + double result = 0; + + // + return result; +} + +/** + * Detect Possible Momentum Changes + * Using MqlTick ... + */ +bool DetectMomentumChange( + ENUM_POSITION_TYPE type, + string mSymbol = NULL, + int mLength = 14 // +) +{ + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + MqlTick ticks[]; + int copied = CopyTicks( + mSymbol, + ticks, + COPY_TICKS_ALL, + 0, + mLength + 1 // + ); + + // + result = copied > mLength; + if (!result) + { + return result; + } + + // + double previousPrice = GetTickExit( + ticks[mLength], + type, + mSymbol // + ); + for (int i = mLength - 1; i >= 0; i--) + { + // + double currentPrice = GetTickExit( + ticks[i], + type, + mSymbol // + ); + + // + double momentum = CalculateMomentum( + currentPrice, + previousPrice // + ); + + // + if (fabs(momentum) > 1.0) + { + // + result = true; + break; + } + } + + // + return result; +} + +// +// Fill Specified Applied Prices ... +int FillPrice( + double &buffer[], + ENUM_APPLIED_PRICE _mAppliedTo = PRICE_CLOSE, + string _mSymbol = NULL, + ENUM_TIMEFRAMES _mPeriod = NULL, + int _mStart = 0, + int _mLoopback = 10 // +) +{ + // + int result = 0; + + // + if (_mStart < 0) + { + _mStart = 0; + } + + // + if (_mLoopback < 7) + { + _mLoopback = 7; + } + + // + _mSymbol = NormalizeSymbol(_mSymbol); + _mPeriod = NormalizePeriod(_mPeriod); + + // + Clean(buffer); + ArraySetAsSeries(buffer, true); + + // + double open[]; + result = CopyOpen( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + open // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + double high[]; + result = CopyHigh( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + high // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + double low[]; + result = CopyLow( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + low // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + double close[]; + result = CopyClose( + _mSymbol, + _mPeriod, + _mStart, + _mLoopback, + close // + ); + if (!IsValidSize(result)) + { + return result; + } + + // + for (int i = 0; i < result; i++) + { + // + double iPrice = GetAppliedPrice( + _mAppliedTo, + open, + high, + low, + close, + i // + ); + + // + Add( + iPrice, + buffer // + ); + } + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Symbols ... + +// +// Retrieve Available Symbols ... +int GetAllSymbols( + string &symbols[], // Hold Result + bool onlyInWatchList = false, // Specified Retrieve only Symbols which in Watch List + bool forceClean = true // Force To Clean Result Array +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(symbols); + } + + // + int beforeSize = ArraySize(symbols); + + // + int symbolsCount = SymbolsTotal(onlyInWatchList); + if (symbolsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = SymbolName( + i, + onlyInWatchList + // + ); + if (!IsValid(iSymbol)) + { + continue; + } + + // + Add( + iSymbol, + symbols + // + ); + } + + // + int afterSize = ArraySize(symbols); + + // + result = afterSize - beforeSize; + + // + return result; +} + +// +// This is a Global Way to Filter Symbols +// you can pass Specific string as Query or a List String for Filtering ... +int FilterSymbols( + string query, // Which Query to Search Symbol + string &symbols[], // Hold Result + bool onlyInWatchList = false, // Specified Retrieve only Symbols which in Watch List + bool forceClean = true, // Force To Clean Result Array + bool ignoreCase = true, // Ignore Case + string querySeparator = "," // If Provided means query is a COllection of Queries and need to be Splitted +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(symbols); + } + + // + if (!IsValid(query)) + { + return result; + } + + // + // Check Query is an String array or not ... + string mQueries[]; + int queriesCount = 0; + if (IsValid(querySeparator) && Contains(querySeparator, query, true)) + { + // + queriesCount = SplitContent( + mQueries, + query, + querySeparator + // + ); + } + + // + int beforeSize = ArraySize(symbols); + + // + string allSymbols[]; + int allSymbolsCount = GetAllSymbols( + allSymbols, + onlyInWatchList, + forceClean); + if (allSymbolsCount <= 0) + { + return result; + } + + // + // Loop Through all Symbols ... + for (int i = 0; i < allSymbolsCount; i++) + { + // + string iSymbol = allSymbols[i]; + + // + bool isFilterPassed = false; + if (queriesCount == 0) + { + // + isFilterPassed = Contains( + query, + iSymbol, + ignoreCase + // + ); + } + else if (queriesCount > 0) + { + // + isFilterPassed = Contains( + mQueries, + iSymbol, + ignoreCase + // + ); + } + + // + if (isFilterPassed) + { + // + Add( + iSymbol, + symbols + // + ); + } + } + + // + int afterSize = ArraySize(symbols); + + // + result = afterSize - beforeSize; + + // + return result; +} + +// +int FilterUSDSymbols( + string &symbols[], // Hold Result + bool onlyInWatchList = false, // Specified Retrieve only Symbols which in Watch List + bool forceClean = true, // Force To Clean Result Array + bool ignoreCase = true, // Ignore Case + string querySeparator = "," // If Provided means query is a COllection of Queries and need to be Splitted +) +{ + // + return FilterSymbols( + "USD", + symbols, + onlyInWatchList, + forceClean, + ignoreCase, + querySeparator + // + ); +} + +// +// Time / Date ... + +// +// 0 => Sunday +// 1 => Monday +// 2 => Tuesday +// 3 => Wednesday +// 4 => Thursday +// 5 => Friday +// 6 => Saturday +enum ENUM_X_WEEK_DAYS +{ + X_WEEK_DAY_NONE = -1, + X_WEEK_DAY_SUNDAY = 0, + X_WEEK_DAY_MONDAY = 1, + X_WEEK_DAY_TUESDAY = 2, + X_WEEK_DAY_WEDNESDAY = 3, + X_WEEK_DAY_THURSDAY = 4, + X_WEEK_DAY_FRIDAY = 5, + X_WEEK_DAY_SATURDAY = 6, +}; + +// +// Retrieve Day of Week ... +ENUM_X_WEEK_DAYS GetDayOfWeek( + datetime time = NULL // +) +{ + // + ENUM_X_WEEK_DAYS result = X_WEEK_DAY_NONE; + + // + time = NormalizeTime(time); + MqlDateTime timeStruct; + bool hasDate = TimeToStruct( + time, + timeStruct // + ); + if (!hasDate) + { + return result; + } + + // + result = (ENUM_X_WEEK_DAYS)timeStruct.day_of_week; + + // + return result; +} + +// +// Representation of Time Struct ... +// struct MqlDateTime +// { +// int year; // Year +// int mon; // Month +// int day; // Day +// int hour; // Hour +// int min; // Minutes +// int sec; // Seconds +// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) +// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero) +// }; + +// +// Converts Time to Seconds ... +ulong TimeToSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = (ulong)time; + + // + return result; +} +ulong TimeToSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToSeconds(dTime); + + // + return result; +} + +// +// Converts Seconds To Time ... +datetime SecondsToTime( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime result = (datetime)seconds; + + // + return result; +} +MqlDateTime SecondsToStruct( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime dTime = SecondsToTime(seconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Time to MilliSeconds ... +ulong TimeToMilliSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = TimeToSeconds(time) * 1000; + + // + return result; +} +ulong TimeToMilliSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToMilliSeconds(dTime); + + // + return result; +} + +// +// Converts MillisSeconds to Time ... +datetime MilliSecondsToTiem( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + ulong seconds = milliSeconds / 1000; + + // + datetime result = SecondsToTime(seconds); + + // + return result; +} +MqlDateTime MilliSecondsToStruct( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + datetime dTime = MilliSecondsToTiem(milliSeconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Hours to Seconds ... +int HoursToSeconds(int value) +{ + // + int result = 0; + + // + if (value < 0) + { + value = 0; + } + + // + if (value == 0) + { + return result; + } + + // + result = value * 60 * 60; + + // + return result; +} + +// +// Retrieve DateTime Structure ... +MqlDateTime GetCurrentTime() +{ + // + MqlDateTime result = {}; + + // + datetime cTime = TimeCurrent(); + TimeToStruct(cTime, result); + + // + return result; +} + +// +// Retrieve Current Time as Seconds ... +ulong GetCurrentTimeAsSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Current Time as MilliSeconds ... +ulong GetCurrentTimeAsMilliSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +int GetLocalOffset() +{ + // + MqlDateTime cTimeStruct; + datetime cTime = TimeCurrent(cTimeStruct); + + // + MqlDateTime cLTimeStruct; + datetime cLTime = TimeLocal(cLTimeStruct); + + // + cTimeStruct.sec = 0; + cTime = StructToTime(cTimeStruct); + + // + cLTimeStruct.sec = 0; + cLTime = StructToTime(cLTimeStruct); + + // + int result = ((int)cLTime - (int)cTime); + + // + return result; +} + +// +int GetUTCRequiredTimeOffset() +{ + // + int utcOffset = TimeGMTOffset(); + int localOffset = GetLocalOffset(); + + // + int result = utcOffset + localOffset; + + // + return result; +} + +// +datetime GetUTCTime( + datetime time = NULL, + bool applyTradeServerTime = false // +) +{ + // + datetime result = NULL; + + // + NormalizeTime(time); + + // + datetime cTime = TimeCurrent(); + datetime cTimeLocal = TimeLocal(); + + // + int cLocalOffset = ((int)cTimeLocal - (int)cTime); + int gmtOffset = TimeGMTOffset(); + int offsetDelte = gmtOffset + cLocalOffset; + int requiredUTCOffset = GetUTCRequiredTimeOffset(); + if (requiredUTCOffset > 0) + { + requiredUTCOffset = -1 * requiredUTCOffset; + } + + // + int timeSeconds = (int)time; + int resultSeconds = timeSeconds + requiredUTCOffset; + + // + result = (datetime)(resultSeconds); + + // + return result; +} + +// +// Retrieve only Hour and Minute as String ... +string GetTimeString( + datetime time = NULL // +) +{ + // + NormalizeTime(time); + + // + string result = NULL; + + // + MqlDateTime tStruct; + bool isStructed = TimeToStruct(time, tStruct); + if (!isStructed) + { + return result; + } + + // + string hour = ToString(tStruct.hour); + hour = + StringLen(hour) == 1 + ? "0" + hour + : hour; + + // + string minute = ToString(tStruct.min); + minute = + StringLen(minute) == 1 + ? "0" + minute + : minute; + + // + result = hour + ":" + minute; + + // + return result; +} + +// +// Converts a Date time to File Format ... +string ToFormatString( + datetime mTime, + string separator = "_" // +) +{ + // + string result = NULL; + + // + if (!IsValid(mTime)) + { + return result; + } + + // + MqlDateTime timeStruct; + bool isConverts = TimeToStruct( + mTime, + timeStruct // + ); + if (!isConverts) + { + return result; + } + + // + string year = ToString(timeStruct.year); + string month = ToString(timeStruct.mon); + string day = ToString(timeStruct.day); + string hour = ToString(timeStruct.hour); + string minute = ToString(timeStruct.min); + string second = ToString(timeStruct.sec); + + // + result = + // + // Year ... + year + separator + + // + // Month ... + (StringLen(month) == 1 + ? "0" + month + : month) + + separator + + // + // Day ... + (StringLen(day) == 1 + ? "0" + day + : day) + + separator + + // + // Hour ... + (StringLen(hour) == 1 + ? "0" + hour + : hour) + + separator + + // + // Minute ... + (StringLen(minute) == 1 + ? "0" + minute + : minute) + + separator + + // + // Seconds ... + (StringLen(second) == 1 + ? "0" + second + : second) + + separator + + // + "" + // + ; + + // + return result; +} + +/** + * Converts an String Represetation of Time (00:00) to Date Time .. + * + * @param value: String ... + * + * @return ( datetime ) + */ +datetime ParseDateTimeFromTimeString(string value) +{ + // + datetime result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + // Check Signalling Time ... + MqlDateTime cTime; + bool isTimeRecieved = TimeCurrent(cTime); + if (!isTimeRecieved) + { + return result; + } + + // + // Split ... + string parts[]; + int partsCount = SplitContent( + parts, + value, + ":" + // + ); + if (!IsValidSize(partsCount)) + { + return result; + } + + // + int hour = 0; + int minute = 0; + if (partsCount >= 1) + { + hour = (int)(parts[0]); + } + if (partsCount >= 2) + { + minute = (int)(parts[1]); + } + + // + cTime.day_of_week = 0; + cTime.day_of_year = 0; + + // + cTime.hour = hour; + cTime.min = minute; + + // + result = StructToTime(cTime); + + // + return result; +} + +// +// Check Specific Time in Range of another Time ... +bool IsTimeInRange( + datetime currentTime = NULL, + datetime startTime = NULL, + datetime stopTime = NULL // +) +{ + // + bool result = false; + + // + // Normallize Current Time ... + currentTime = NormalizeTime(currentTime); + + // + result = !IsValid(startTime) && + !IsValid(stopTime); + if (result) + { + return result; + } + + // + result = IsValid(startTime) && + IsValid(stopTime); + if (!result) + { + // + result = IsValid(startTime) && + currentTime >= startTime; + + // + return result; + } + + // + result = currentTime >= startTime && + currentTime < stopTime; + + // + return result; +} +bool IsTimeInRange( + datetime currentTime, + string startTime, + string endTime // +) +{ + // + bool result = false; + + // + result = IsValid(startTime) && + IsValid(endTime); + if (!result) + { + // + // Here Since there isnot provide any + // data source we pass result as true ... + result = true; + return result; + } + + // + // Converts String Representation to Time ... + datetime st = ParseDateTimeFromTimeString(startTime); + datetime et = ParseDateTimeFromTimeString(endTime); + + // + result = IsTimeInRange( + currentTime, + st, + et // + ); + + // + return result; +} + +// +// Bar Times ... + +// +// Retrieve Specified Bar Time ... +datetime GetBarTime( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Validate and Normalize Args ... + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + // Retrieve Bar Time ... + datetime result = iTime( + mSymbol, + mPeriod, + barIndex); + + // + return result; +} + +// +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsMilliSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve a Bar Time Structure ... +MqlDateTime GetBarTimeStruct( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + MqlDateTime result = {}; + + // + // Retrieve Bar Time ... + datetime barTime = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + // Convert to Structure ... + TimeToStruct(barTime, result); + + // + return result; +} + +// +// Retrieve Last Available Bar Time of +// Dest Period inside Source Period ... +datetime GetLastBarTime( + ENUM_TIMEFRAMES sourcePeriod, + ENUM_TIMEFRAMES destPeriod // +) +{ + // + datetime result = NULL; + + // + if (!IsValid(sourcePeriod) || + !IsValid(destPeriod)) + { + return result; + } + + // + int sourceSeconds = PeriodSeconds(sourcePeriod); + int destSeconds = PeriodSeconds(destPeriod); + if (sourceSeconds < destSeconds) + { + return result; + } + + // + XOHCL sourceBar; + bool isInited = sourceBar.Init( + _Symbol, + sourcePeriod, + 0 // + ); + if (!isInited) + { + return result; + } + + // + result = (datetime)((((int)sourceBar.time) + sourceSeconds) - destSeconds); + + // + return result; +} + +// +// Other Tools ... + +// +template +bool IsSame( + T &buffer[], // Search Buffer + int count = 5, // Number of Searchs + int start = 0 // Start ... +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + result = bufferSize > 0; + if (!result) + { + return result; + } + + // + // Validate Count ... + result = start + count < bufferSize; + if (!result) + { + return result; + } + + // + T iTem = buffer[start]; + for (int i = start; i < start + count; i++) + { + // + if (iTem != buffer[i]) + { + result = false; + break; + } + + // + if (!result) + { + result = true; + } + } + + // + return result; +} + +// +// Check first Cross Over second at index ... +bool IsCrossedOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + !(first[index + 1] > second[index + 1]); + + // + return result; +} + +// +// Check first is Over second at index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + first[index + 1] > second[index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at index ... +bool IsCrossedUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + !(first[index + 1] < second[index + 1]); + + // + return result; +} + +// +// Check first is Under second at index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + first[index + 1] < second[index + 1]; + + // + return result; +} + +// +// Check if a Value Increasing in Loopback ... +bool IsIncreasing( + const double &buffer[], // the Buffer which required to search + int from = -1, // Last Time Index + int to = -1 // Fisrs Tima Index +) +{ + // + bool result = false; + + // + if (from == -1) + { + from = ArraySize(buffer) - 1; + } + + // + if (to == -1) + { + to = 0; + } + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue >= fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue >= iValue; + + // + bool isIIncreasing = IsIncreasing( + buffer, + from, + i // + ); + + // + // Check Result ... + result = result && isPassed && isIIncreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Check if a Value Decreasing in Loopback ... +bool IsDecreasing( + const double &buffer[], // the Buffer which required to search + int from = -1, // Last Time Index + int to = -1 // Fisrs Tima Index +) +{ + // + bool result = false; + + // + if (from == -1) + { + from = ArraySize(buffer) - 1; + } + + // + if (to == -1) + { + to = 0; + } + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue <= fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue <= iValue; + + // + bool isIDecreasing = IsDecreasing( + buffer, + from, + i // + ); + + // + // Check Result ... + result = result && isPassed && isIDecreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +bool IsTrendingUp( + const double &buffer1[], // First Buffer + const double &buffer2[] // Seccend Buffer +) +{ + // + bool result = false; + + // + int buffer1Count = ArraySize(buffer1); + int buffer2Count = ArraySize(buffer2); + if (buffer1Count <= 0 || buffer2Count <= 0) + { + return result; + } + + // + int count = MathMin(buffer1Count, buffer2Count); + if (count <= 1) + { + return result; + } + + // + int upCounts = 0; + int downCounts = 0; + double value = MathAbs(buffer1[0] - buffer2[0]); + for (int i = 1; i < count; i++) + { + // + double iValue = MathAbs(buffer1[i] - buffer2[i]); + + // + if (value > iValue) + { + upCounts++; + } + + // + if (value < iValue) + { + downCounts++; + } + } + + // + result = upCounts > 1 && upCounts > downCounts; + + // + return result; +} + +// +bool IsTrendingDown( + const double &buffer1[], // First Buffer + const double &buffer2[] // Seccend Buffer +) +{ + // + bool result = false; + + // + int buffer1Count = ArraySize(buffer1); + int buffer2Count = ArraySize(buffer2); + if (buffer1Count <= 0 || buffer2Count <= 0) + { + return result; + } + + // + int count = MathMin(buffer1Count, buffer2Count); + if (count <= 1) + { + return result; + } + + // + int upCounts = 0; + int downCounts = 0; + double value = MathAbs(buffer1[0] - buffer2[0]); + for (int i = 1; i < count; i++) + { + // + double iValue = MathAbs(buffer1[i] - buffer2[i]); + + // + if (value > iValue) + { + upCounts++; + } + + // + if (value < iValue) + { + downCounts++; + } + } + + // + result = downCounts > 1 && downCounts > upCounts; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + const double &buffer[], // Buffer + int from, // In Past Index ... + int to // In Past Index ... +) +{ + // + double result = 0; + + // + if (from > ArraySize(buffer) || to > ArraySize(buffer)) + { + return result; + } + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// Check Bar Reject Specified Value ... +bool IsBarReject( + double value, + ENUM_X_DIRECTION dir, + XOHCL &bar // +) +{ + // + bool result = false; + + // + result = value > 0 && + bar.IsValid() && + HasDirection(dir); + if (!result) + { + return result; + } + + // + bool isUp = IsBullish(dir); + bool isDown = IsBearish(dir); + + // + result = + // + isUp + ? bar.IsBullish() && + bar.low < value && + bar.GetDown() > value + : isDown + ? bar.IsBearish() && + bar.high > value && + bar.GetUp() < value + : false + // + ; + + // + return result; +} + +// +// Check Bar Break Specified Value ... +bool IsBarBreak( + double value, + ENUM_X_DIRECTION dir, + XOHCL &bar // +) +{ + // + bool result = false; + + // + result = value > 0 && + bar.IsValid() && + HasDirection(dir); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + bool isUp = IsBullish(dir); + bool isDown = IsBearish(dir); + + // + result = + isUp + ? bar.IsBullish() && + ((bar.GetDown() < value && + bar.GetUp() > value) || + (bar.close > value && + pBar.close < value)) + : isDown + ? bar.IsBearish() && + ((bar.GetUp() > value && + bar.GetDown() < value) || + (bar.close < value && + pBar.close > value)) + : false; + + // + return result; +} + +// +// Calculate Fib Level ... +double GetFibonacciLevel( + double upPrice, // Upper Bound + double downPrice, // Downer Bound + double level, // Level Multiplier Factor + int direction // From Down to Up < 0, other wise Vice Versa + // +) +{ + // + double ling = upPrice - downPrice; + double pLevel = (ling / 100) * (level * 100); + + // + double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; + + // + return result; +} + +// +// Method 1 +// Normalize between 1 and 0 ... +template +double GetNormalizedValueMethod1( + T &buffer[], // Array which required to Normalize + int mLength, // Length of Normalization + int mStart = 0, // start index + int digits = 5 // Normalization Digits +) +{ + // + double result = 0; + + // + if (digits <= 5) + { + digits = 5; + } + + // + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return result; + } + + // + // Normalize Count ... + NormalizeCount( + mStart, + mLength, + buffer // + ); + + // + T max = 0; + T min = 0; + + // + if (bufferSize != mLength) + { + // + T tmp[]; + Copy( + mStart, + mLength, + buffer, + tmp // + ); + + // + max = GetMax(tmp); + min = GetMin(tmp); + } + + // + if (bufferSize == mLength) + { + // + max = GetMax(buffer); + min = GetMin(buffer); + } + + // + T iValue = buffer[mStart]; + + // + double minMaxDiff = (max - min); + if (minMaxDiff <= 0) + { + return result; + } + + // + result = (iValue - min) / minMaxDiff; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Method 2 +// Normalize Between Specified Upper and Lower ... +template +double GetNormalizedValueMethod2( + T &buffer[], // Array which required to Normalize + int mLength, // Length of Normalization + int mUpper, // Specified Upper Value + int mLower, // Specified Lower Value + int mStart = 0, // start index + int digits = 5 // Normalization Digits +) +{ + // + double result = 0; + + // + if (digits <= 5) + { + digits = 5; + } + + // + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return result; + } + + // + // Normalize Count ... + NormalizeCount( + mStart, + mLength, + buffer // + ); + + // + T max = 0; + T min = 0; + + // + if (bufferSize != mLength) + { + // + T tmp[]; + Copy( + mStart, + mLength, + buffer, + tmp // + ); + + // + max = GetMax(tmp); + min = GetMin(tmp); + } + + // + if (bufferSize == mLength) + { + // + max = GetMax(buffer); + min = GetMin(buffer); + } + + // + T iValue = buffer[mStart]; + + // + double minMaxDiff = (max - min); + double boundaryDiff = (mUpper - mLower); + if (minMaxDiff <= 0 || boundaryDiff <= 0) + { + return result; + } + + // + result = boundaryDiff / (minMaxDiff * (iValue - max) + max); + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +void NormalizeBuffer( + double &source[], // Source Buffer + double &dest[], // Result Buffer + double upper = 100, // Upper Value to Normalize + double lower = -100, // Lower Value to Normalize + int size = -1, // Size Of Normalization + int digits = 5 // Digits for Result +) +{ + // + if (size <= 0) + { + size = ArraySize(source); + } + + // + bool asSeriesFlag = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(source, false); + ArraySetAsSeries(dest, false); + + // + double min = ArrayMinimum(source, 0, size); + double max = ArrayMaximum(source, 0, size); + + // + for (int i = 0; i < size; i++) + { + // + double iNormal = lower + ((source[i] - min) / (max - min)) * (upper - lower); + + // + if (digits > 0) + { + iNormal = NormalizeDouble(iNormal, digits); + } + + // + dest[i] = iNormal; + } + + // + ArraySetAsSeries(source, asSeriesFlag); + ArraySetAsSeries(dest, asSeriesFlag); +} + +// +// Templates ... + +// +// Retrieve Specific Object Types Name ... +template +string GetTypeName(const T &t) +{ + return typename(T); +} + +// +template +string GetToken(T &item) +{ + // + string mType = GetTypeName(item); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; +} + +// +// Same as Get Token for Use in Classes ... +template +string GetSpecificToken(T &item) +{ + // + string mType = GetTypeName(item); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; +} + +// +// Generate Unique Tags ... +template +string GenerateTag(T &model) +{ + // + string result = ""; + + // + string tag = model.ToString(); + if (StringLen(tag) == 0) + { + return result; + } + + // + static XSCMD5 md5; + + // + result = md5.Hash(tag); + + // + return result; +} + +// +// Hash Specified Content ... +template +string ToMD5(T content) +{ + // + string result = ""; + + // + string strContent = ToString(content); + if (StringLen(strContent) == 0) + { + return result; + } + + // + static XCMD5 md5; + + // + result = md5.Hash(strContent); + + // + return result; +} + +// +// Check a Value Not Empty ... +template +bool NotEmpty(T value) +{ + return value != EMPTY_VALUE; +} + +// +// Check a Value Not Empty and Zero ... +template +bool NotEmptyZero(T value) +{ + return value != EMPTY_VALUE && value != 0; +} + +// +// Add Specified Item to Array ... +template +int Add( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} +template +int AddSpecific( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + return Add( + item, + buffer // + ); +} +template +int AddRef( + T &item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Check Specified Array Has Childs or not ... +template +bool HasChild(T &buffer[]) +{ + return IsValidSize(ArraySize(buffer)); +} +template +bool SpecificHasChild(T &buffer[]) +{ + return HasChild(buffer); +} + +// +// Remove Specified Item from an Array ... +template +bool Remove( + T item, + T &buffer[]) +{ + // + bool result = false; + + // + int itemIndex = FindIndex( + item, + buffer); + if (itemIndex < 0) + { + return result; + } + + // + result = ArrayRemove( + buffer, + itemIndex, + 1); + + // + return result; +} + +// +// Clean Specified Array ... +template +void Clean(T &buffer[]) +{ + // + ArrayResize(buffer, 0); + ArrayFree(buffer); +} +template +void SpecificClean(T &buffer[]) +{ + Clean(buffer); +} + +// +// Copy Whole Content of Source to Dest array ... +template +void Copy( + T &source[], // Source Buffer ... + T &dest[], // Dest Buffer ... + bool cleanDest = true // Force Clen Dest Buffer ... +) +{ + // + if (cleanDest) + { + Clean(dest); + } + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + AddRef( + iSource, + dest); + } +} + +// +// Copy Items from a Buffer ... +template +int Copy( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true, // Force To Clean buffer + bool forceStart = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0 && forceStart) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + if (count == 0) + { + count = ArraySize(source) - 1 - start; + } + + // + if (start + count > ArraySize(source)) + { + return result; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + ArrayCopy( + dest, + source, + 0, + start, + count + // + ); + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Copy Items from a Buffer ... +template +int CopyRef( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + for (int i = start; i < start + count; i++) + { + // + AddRef( + source[i], + dest + // + ); + } + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Retrive Last Item of Specified Buffer ... +template +bool GetLastItem( + T &item, // Holds Result + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +// Remove Last Item of Specified Buffer ... +template +bool RemoveLastItem( + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int count = ArraySize(buffer); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + ArrayRemove( + buffer, + count - 1, + 1 // + ); + + // + return result; +} + +template +void CleanupArray( + T &buffer[], // Buffer to Cleanup ... + int maxAllowed = 0 // Max Allowed Number of items ... +) +{ + // + if (maxAllowed <= 0) + { + return; + } + + // + int count = ArraySize(buffer); + if (!IsValidSize(count) || + count <= maxAllowed) + { + return; + } + + // + int mustRemove = count - maxAllowed; + if (!IsValidSize(mustRemove)) + { + return; + } + + // + ArrayRemove( + buffer, + 0, + mustRemove // + ); +} + +// +// Search Array For Specific Item ... +template +int FindIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + int result = -1; + + // + int count = ArraySize(buffer); + if (count <= 0) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T iT = buffer[i]; + + // + if (iT == item) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +// Check an Array Contains Specified Value ... +template +bool Contains( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + bool result = false; + + // + int idx = FindIndex( + item, + buffer); + result = idx > -1; + + // + return result; +} + +// +// Calculate a Buffer's Sum ... +template +double GetSum( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + return result; +} + +// +// Calculate a Buffer's Average ... +template +double GetAverage( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + // Calculate Average ... + result = result / tmpCount; + + // + return result; +} + +// +// Get Max of Specific Loopback of a Buffer ... +template +T GetMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} +template +T GetSpecifiedMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMax( + buffer, + start, + count // + ); +} + +// +// Get Min of Specific Loopback of a Buffer ... +template +T GetMin( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} +template +T GetSpecifiedMin( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMin( + buffer, + start, + count // + ); +} + +// +// Find a Value less than Specified ... +template +T FindLesserThan( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindBiggerThan( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find Same Values in Array ... +template +void FindSames( + T &result[], // Holds Result ... + T &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + T mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + T iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3 // +) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// Bar XOHCL ... + +// +// Extract Specific Range of Bars ... +// using Start Bar Index ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + int from = 0, // Start Bar Index + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + int mResult = 0; + + // + if (from < 0) + { + from = 0; + } + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int total = Bars( + mSymbol, + mPeriod); + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + if (forceClean) + { + Clean(result); + } + + // + int beforeSize = ArraySize(result); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + mSymbol, + mPeriod, + i + // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + result + // + ); + } + } + + // + int afterSize = ArraySize(result); + + // + mResult = afterSize - beforeSize; + + // + return mResult; +} + +// +// Extract Specific Range of Bars ... +// using Start Bar Time ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + datetime from = NULL, // Start Bar Time + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + from = NormalizeTime(from); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + from, + false + // + ); + + // + return GetBars( + result, + mSymbol, + mPeriod, + barIndex, + count, + forceClean + // + ); +} + +// +// String ... + +// +// Search a Content Contains Specific String or not ... +bool Contains( + string mQuery, // Search String + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + // + bool result = false; + + // + // Validate Query ... + result = IsValid(mQuery); + if (!result) + { + return result; + } + + // + // Validate Content ... + result = IsValid(mContent); + if (!result) + { + return result; + } + + // + // Normalize Inputs ... + string query = mQuery; + string content = mContent; + if (ignoreCase) + { + // + StringToLower(query); + StringToLower(content); + } + + // + int queryIdx = StringFind( + content, + query); + + // + result = queryIdx >= 0; + + // + return result; +} + +// +bool Contains( + string &mQueries[], // Search Strings + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + // + bool result = false; + + // + // Validate Queries ... + int queriesCount = ArraySize(mQueries); + result = queriesCount > 0; + if (!result) + { + return result; + } + + // + // Validate Content ... + result = IsValid(mContent); + if (!result) + { + return result; + } + + // + int containsCount = 0; + for (int i = 0; i < queriesCount; i++) + { + // + bool isContains = Contains( + mQueries[i], + mContent, + ignoreCase); + + // + if (!isContains) + { + // + result = false; + break; + } + + // + containsCount++; + } + + // + result = containsCount == queriesCount; + + // + return result; +} + +// +int FindIndexes( + string mQuery, // Search String + string mContent, // Search Content + int &result[], // Holding Results + bool ignoreCase = false // Ignore Case +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Inputs ... + if (!IsValid(mQuery) || + !IsValid(mContent)) + { + return mResult; + } + + // + // Apply Ignore Case if Provided ... + if (ignoreCase) + { + // + bool isConverted = StringToLower(mQuery); + if (!isConverted) + { + return mResult; + } + + // + isConverted = StringToLower(mContent); + if (!isConverted) + { + return mResult; + } + } + + // + // Search First Index ... + int lastPos = 0; + int idx = StringFind( + mContent, + mQuery, + lastPos // + ); + while (idx >= 0) + { + // + // Add Position to Result ... + Add( + idx, + result // + ); + + // + lastPos = idx + StringLen(mQuery); + idx = StringFind( + mContent, + mQuery, + lastPos // + ); + } + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Convert From String ... +template +T FromString(string value) +{ + // + T result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + result = (T)value; + + // + return result; +} + +// +// Converts an item to String ... +template +string ToString(T value) +{ + return (string)value; +} + +// +// Used In Report or Summary Generators ... +string ToString( + string prefix, // Title + bool value, // Value + bool ignoreFalseConditions = true, // Ignore False Conditions + string lineSeparator = "\n", // Line Separator + string prefixSeparator = ":" // Title Separator +) +{ + // + string result = NULL; + + // + result = (value || !ignoreFalseConditions) + ? prefix + + prefixSeparator + " " + + ToString(value) + + lineSeparator + : ""; + + // + return result; +} + +// +template +string ToString( + string prefix, // Title + T value, // Value + string lineSeparator = "\n", // Line Separator + string prefixSeparator = ":" // Title Separator +) +{ + // + string result = NULL; + + // + result = prefix + + prefixSeparator + " " + + ToString(value) + + lineSeparator; + + // + return result; +} + +// +string SetLabel( + string mLabel, // Provided Label ... + string value, // Source Value ... + string separator = "\n", // Line Separator + bool addTopEmptyLine = true // Add Empty Line On top +) +{ + // + string result = value; + + // + if (StringLen(mLabel) <= 0) + { + return result; + } + + // + result = (StringLen(value) > 0) + ? (addTopEmptyLine ? separator : "") + + mLabel + + separator + + "-----------------------------" + + separator + + value + : value; + + // + return result; +} + +// +// Converts a Buffer to String Representation ... +template +string ToString( + const T &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} + +// +// Converts String to boolean ... +bool ToBoolean(string value) +{ + // + bool result = false; + + // + if (StringLen(value) <= 0) + { + return result; + } + + // + StringToLower(value); + result = value == "true"; + + // + return result; +} + +// +// Split an String Representation of an Array ... +int SplitContent( + string &result[], // Hold Result ... + string content, // Source ... + string separator = ",", // Separator ... + bool forceCleanResult = true // Clean Result ... +) +{ + // + int mResult = 0; + + // + if (forceCleanResult) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + if (separator == NULL || StringLen(separator) == 0) + { + separator = ","; + } + + // + if (StringLen(content) == 0) + { + return mResult; + } + + // + StringSplit( + content, + StringGetCharacter( + separator, + 0), + result); + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Extract an Array of Contents ... +int ExtractStrings( + string &result[], // Hold Result + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Args ... + int sourceLength = StringLen(source); + int startLength = StringLen(startString); + int endLength = StringLen(endString); + + // + int minRequiredLength = startLength + endLength; + + // + if ( + endLength <= 0 || + startLength <= 0 || + sourceLength <= 0 || + sourceLength < minRequiredLength) + { + return mResult; + } + + // + // Make a Copy of Source for Manipulating ... + string workStr = source; + + // + // Define a Loop ... + while (StringLen(workStr) > minRequiredLength) + { + // + // Find Item ... + string item = ExtractString( + workStr, + startString, + endString); + + // + // Breakout when couldn't find anymore item ... + int itemLength = StringLen(item); + if (itemLength <= 0) + { + break; + } + + // + // Prepare Item Source String for Replacing in Work String ... + string itemSource = startString + item + endString; + + // + // Add Item to Result Array ... + Add( + item, + result); + + // + // Replace Item Soure in Work String ... + StringReplace( + workStr, + itemSource, + ""); + } + + // + // Calculate Size of Array ... + mResult = ArraySize(result); + + // + return mResult; +} + +// +string ExtractSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + return ExtractString( + surrounded, + mToken + startString, + endString + // + ); +} + +// +int ParseIntSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (int)strContent; + + // + return result; +} +long ParseLongSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + long result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (long)strContent; + + // + return result; +} +string ParseStringSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (string)strContent; + + // + return result; +} +double ParseDoubleSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + double result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (double)strContent; + + // + return result; +} +datetime ParseTimeSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + datetime result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (datetime)strContent; + + // + return result; +} + +// +int ParseIntArraySurrounded( + int &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + int iValue = (int)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseLongArraySurrounded( + long &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + long iValue = (long)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseDoubleArraySurrounded( + double &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + double iValue = (double)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseTimeArraySurrounded( + datetime &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + datetime iValue = (datetime)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +// +// Surround an String by Specific Token ... +template +string Surround( + string mToken, // an String which used to Tokenize + T &value, // a Value for Tokenize it + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string strValue = ToString(value); + if (!IsValid(strValue)) + { + return result; + } + + // + result = + // + (IsValid(mToken) + ? mToken + : "") + + // + startString + + strValue + + endString + // + ; + + // + return result; +} + +// +template +string SurroundArray( + string mToken, + T &value[], + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string valueStr = ToString(value); + if (!IsValid(valueStr)) + { + return result; + } + + // + result = Surround( + mToken, + valueStr, + startString, + endString + // + ); + + // + return result; +} + +// +// Periods / Cycles ... + +// +// Converts an String to TimeFrame ... +ENUM_TIMEFRAMES ToPeriod(string value) +{ + // + if (StringLen(value) == 0) + { + return _Period; + } + + // + StringTrimLeft(value); + StringTrimRight(value); + + // + ENUM_TIMEFRAMES result = _Period; + + // + if (value == "M1") + { + result = PERIOD_M1; + } + else if (value == "M2") + { + result = PERIOD_M2; + } + else if (value == "M3") + { + result = PERIOD_M3; + } + else if (value == "M4") + { + result = PERIOD_M4; + } + else if (value == "M5") + { + result = PERIOD_M5; + } + else if (value == "M6") + { + result = PERIOD_M6; + } + else if (value == "M10") + { + result = PERIOD_M10; + } + else if (value == "M12") + { + result = PERIOD_M12; + } + else if (value == "M15") + { + result = PERIOD_M15; + } + else if (value == "M20") + { + result = PERIOD_M20; + } + else if (value == "M30") + { + result = PERIOD_M30; + } + else if (value == "H1") + { + result = PERIOD_H1; + } + else if (value == "H2") + { + result = PERIOD_H2; + } + else if (value == "H3") + { + result = PERIOD_H3; + } + else if (value == "H4") + { + result = PERIOD_H4; + } + else if (value == "H6") + { + result = PERIOD_H6; + } + else if (value == "H8") + { + result = PERIOD_H8; + } + else if (value == "H12") + { + result = PERIOD_H12; + } + else if (value == "D1") + { + result = PERIOD_D1; + } + else if (value == "W1") + { + result = PERIOD_W1; + } + else if (value == "MN1") + { + result = PERIOD_MN1; + } + + // + return result; +} + +// +// Converts Period to String ... +string ToString(ENUM_TIMEFRAMES mPeriod) +{ + // + string result = ""; + + // + string mPStr = EnumToString(mPeriod); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[1]; + + // + return result; +} + +// +// Retrieve All Available Period as an Array ...s +int GetAllAvailablePeriods( + ENUM_TIMEFRAMES &result[] // Holds Result ... +) +{ + // + Clean(result); + + // + Add( + PERIOD_M1, + result + // + ); + + // + Add( + PERIOD_M2, + result + // + ); + + // + Add( + PERIOD_M3, + result + // + ); + + // + Add( + PERIOD_M4, + result + // + ); + + // + Add( + PERIOD_M5, + result + // + ); + + // + Add( + PERIOD_M6, + result + // + ); + + // + Add( + PERIOD_M10, + result + // + ); + + // + Add( + PERIOD_M12, + result + // + ); + + // + Add( + PERIOD_M15, + result + // + ); + + // + Add( + PERIOD_M20, + result + // + ); + + // + Add( + PERIOD_M30, + result + // + ); + + // + Add( + PERIOD_H1, + result + // + ); + + // + Add( + PERIOD_H2, + result + // + ); + + // + Add( + PERIOD_H3, + result + // + ); + + // + Add( + PERIOD_H4, + result + // + ); + + // + Add( + PERIOD_H6, + result + // + ); + + // + Add( + PERIOD_H8, + result + // + ); + + // + Add( + PERIOD_H12, + result + // + ); + + // + Add( + PERIOD_D1, + result + // + ); + + // + Add( + PERIOD_W1, + result + // + ); + + // + Add( + PERIOD_MN1, + result + // + ); + + // + int mResult = ArraySize(result); + + // + return mResult; +} + +// +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time of Host Period ... +) +{ + // + // Normalize Arg ... + mTime = NormalizeTime(mTime); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false + // + ); + + // + datetime result = GetBarTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; +} + +// +// Converts an String to it's related Market Cycle ... +ENUM_X_MARKET_CYCLES ToCycle(string value) +{ + // + ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN; + + // + ENUM_X_MARKET_CYCLES cycles[]; + int count = GetAllMarketCycles(cycles); + for (int i = 0; i < count; i++) + { + // + ENUM_X_MARKET_CYCLES iCycle = cycles[i]; + string iStr = ToString(iCycle); + + // + if (value == iStr) + { + // + result = iCycle; + break; + } + } + + // + return result; +} + +// +// Converts a Cycle to it's String Representation ... +string ToString(ENUM_X_MARKET_CYCLES cycle) +{ + // + string result = ""; + + // + string mPStr = EnumToString(cycle); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[3]; + + // + return result; +} + +// +// Retrieve all Available Cycles ... +int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &result[]) +{ + // + int mResult = 0; + + // + Clean(result); + + // + ENUM_X_MARKET_CYCLES tmp[] = { + X_MARKET_CYCLE_UNKNOWN, + X_MARKET_CYCLE_SHORT, + X_MARKET_CYCLE_MEDIUM, + X_MARKET_CYCLE_LONG, + X_MARKET_CYCLE_HIND}; + + // + Copy( + tmp, + result // + ); + + // + Clean(tmp); + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Retrieve Nearest Period base on Given Period ... +ENUM_TIMEFRAMES GetNearestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M5; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_M10; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_M20; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H1; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H3; + break; + + // + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H4: + result = PERIOD_H6; + break; + + // + case PERIOD_H6: + result = PERIOD_H8; + break; + + // + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Mediest Period base on Given Period ... +ENUM_TIMEFRAMES GetMediestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M10; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_M15; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_M30; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H4; + break; + + // + case PERIOD_H3: + result = PERIOD_H6; + break; + + // + case PERIOD_H4: + result = PERIOD_H8; + break; + + // + case PERIOD_H6: + result = PERIOD_H12; + break; + + // + case PERIOD_H8: + result = PERIOD_D1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Longest Period base on Given Period ... +ENUM_TIMEFRAMES GetLongestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M30; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_H1; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H2; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H6; + break; + + // + case PERIOD_H3: + result = PERIOD_H8; + break; + + // + case PERIOD_H4: + result = PERIOD_H12; + break; + + // + case PERIOD_H6: + result = PERIOD_D1; + break; + + // + case PERIOD_H8: + result = PERIOD_W1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Hindmost Period base on Given Period ... +ENUM_TIMEFRAMES GetHindMostPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_H1; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_H2; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H4; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H6; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H8; + break; + + // + case PERIOD_H3: + result = PERIOD_H12; + break; + + // + case PERIOD_H4: + result = PERIOD_D1; + break; + + // + case PERIOD_H6: + result = PERIOD_W1; + break; + + // + case PERIOD_H8: + result = PERIOD_MN1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Specified Cycles Period related to Host Period ... +ENUM_TIMEFRAMES GetCyclePeriod( + ENUM_X_MARKET_CYCLES mCycle = NULL, // Specified Cycle + ENUM_TIMEFRAMES mPeriod = NULL // Host Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + mPeriod = NormalizePeriod(mPeriod); + mCycle = NormalizeCycle(mCycle); + + // + switch (mCycle) + { + // + // Short ... + case X_MARKET_CYCLE_SHORT: + result = GetNearestPeriod(mPeriod); + break; + + // + // Medium ... + case X_MARKET_CYCLE_MEDIUM: + result = GetMediestPeriod(mPeriod); + break; + + // + // Long ... + case X_MARKET_CYCLE_LONG: + result = GetLongestPeriod(mPeriod); + break; + + // + // Hind ... + case X_MARKET_CYCLE_HIND: + result = GetHindMostPeriod(mPeriod); + break; + } + + // + return result; +} + +// +// Calculate a Cycle Length based on Host Period ... +int GetCycleLengthOn( + ENUM_TIMEFRAMES _hostPeriod, + ENUM_X_MARKET_CYCLES _cycle, + ENUM_X_PERIOD_METHOD _method, + ENUM_TIMEFRAMES _period // +) +{ + // + int result = 0; + + // + // Validate ... + bool isValid = + // + IsValid(_hostPeriod) && + IsValid(_method, _Period) + // + ; + if (!isValid) + { + return result; + } + + // + // Calculate Period ... + isValid = + _method != X_PERIOD_NOTHING && + _cycle != X_MARKET_CYCLE_UNKNOWN; + if (!isValid) + { + return result; + } + + // + if (_method == X_PERIOD_AUTO) + { + // + _period = GetCyclePeriod( + _cycle, + _hostPeriod // + ); + } + isValid = IsValid(_period); + if (!isValid) + { + return result; + } + + // + int _hostPeriodSeconds = PeriodSeconds(_hostPeriod); + int _periodSeconds = PeriodSeconds(_period); + + // + isValid = _periodSeconds >= _hostPeriodSeconds; + if (!isValid) + { + return result; + } + + // + result = _periodSeconds / _hostPeriodSeconds; + + // + return result; +} + +// +// Direction ... + +// +bool HasDirection(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value != X_DIRECTION_NONE && + value != X_DIRECTION_ALL; + + // + return result; +} + +// +bool IsBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} +bool IsSpecifiedBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} + +// +bool IsBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} +bool IsSpecifiedBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} + +// +ENUM_X_DIRECTION Opposit(ENUM_X_DIRECTION value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + if (!HasDirection(value)) + { + return result; + } + + // + result = + IsBullish(value) + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + + // + return result; +} + +// +// Moving Average ... + +enum ENUM_X_MA_METHOD +{ + X_MA_MODE_NONE, // None + X_MA_MODE_SMA, // SMA + X_MA_MODE_EMA, // EMA + X_MA_MODE_LWMA, // LWMA + X_MA_MODE_SMMA, // SMMA +}; + +/** + * Calculate Sspecified Buffer's Moving Averages ... + * + * @param rates_total: Integer, number of items ... + * @param prev_calculated: Integer, Previous Calculate Items ... + * @param begin: Integer, Bar Index ... + * @param period: Integer, Moving Average Length ... + * @param source: Double Array, Specified Array for Calculating Moving Averages ... + * @param buffer: Double Array, Specified Array to Apply Calculated Moving Average on it ... + * @param method: ENUM_MA_METHOD member Specified Moving Average Calculation Method ... + * + * @return ( int ) + */ +int iMAOnBuffer( + const int _rates_total, + const int _prev_calculated, + const int _begin, + const int _period, + const double &_source[], + double &_buffer[], + ENUM_X_MA_METHOD _method = X_MA_MODE_SMA // +) +{ + // + int result = 0; + + // + if ( + _period < 0 || + _rates_total <= 0 || + _prev_calculated < 0 || + _method == X_MA_MODE_NONE || + _prev_calculated > _rates_total) + { + return result; + } + + // + switch (_method) + { + // + case X_MA_MODE_SMA: + result = SimpleMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_EMA: + result = ExponentialMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_LWMA: + result = LinearWeightedMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_SMMA: + result = SmoothedMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031106/Libraries/x-saherelm.draw.lib.mq5 b/BKPS/14031106/Libraries/x-saherelm.draw.lib.mq5 new file mode 100644 index 0000000..aeb124e --- /dev/null +++ b/BKPS/14031106/Libraries/x-saherelm.draw.lib.mq5 @@ -0,0 +1,2620 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Draw Library +// -------------------------------------- +// Name: XDraw +// Description: provides Draw abilities ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Global Definitions: Variables, Properties and etc ... + +// +// Retrieve Chart Size in Pixel ... +struct XSize +{ + long width; + long height; + + // + int x; + int y; + int w; + int h; + + // + int wStep; + int hStep; +}; + +// +// Define a Draw Specifications ... +struct XDrawSpecifications +{ + // + // Props ... + + // + bool draw; // Draw or Not ... + + // + int width; // Draw Witdth ... + color clr; // Draw Color ... + ENUM_LINE_STYLE style; // Draw Style ... + + // + bool back; // in the background + bool fill; // fill object if supported + bool selection; // highlight to move + bool rayRight; // line's continuation to the right + bool hidden; // hidden in the object list + long zOrder; // priority for mouse click + + // + string label; // Label ... + color labelColor; // Label Color ... + double labelAngel; // Label Angle ... + string labelFont; // Label Font ... + int labelFontSize; // Label Font Size ... + ENUM_ANCHOR_POINT labelAnchor; // Label Anchor Point ... + + // + // Constructor ... + XDrawSpecifications() + { + Clean(); + } + + // + // Operator ... + void operator=(const XDrawSpecifications &value) + { + // + clr = value.clr; + draw = value.draw; + width = value.width; + style = value.style; + + // + back = value.back; + hidden = value.hidden; + zOrder = value.zOrder; + rayRight = value.rayRight; + selection = value.selection; + + // + fill = value.fill; + + // + label = value.label; + labelColor = value.labelColor; + labelAngel = value.labelAngel; + labelFont = value.labelFont; + labelFontSize = value.labelFontSize; + labelAnchor = value.labelAnchor; + } + + // + // Functions ... + + // + void Clean() + { + // + draw = false; + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + back = false; + hidden = false; + rayRight = false; + selection = false; + fill = false; + + // + zOrder = 0; + + // + label = ""; + labelColor = CLR_NONE; + labelAngel = 0; + labelFont = "Arial"; + labelFontSize = 20; + labelAnchor = ANCHOR_LEFT_UPPER; + } + + // + void Label( + string mLabel = "", // Label ... + color mLabelColor = CLR_NONE, // Label Color ... + string mLabelFont = "Arial", // Label Font ... + int mLabelFontSize = 20, // Label Font Size ... + ENUM_ANCHOR_POINT mLabelAnchor = ANCHOR_LEFT_UPPER, // Label Anchor Point ... + double mLabelAngel = 0 // Label Angle ... + ) + { + // + label = mLabel; + labelFont = mLabelFont; + labelColor = mLabelColor; + labelAngel = mLabelAngel; + labelAnchor = mLabelAnchor; + labelFontSize = mLabelFontSize; + } +}; + +// +// Candle Draw Specifications ... +struct XOHCLDrawSpecification +{ + // + // Props ... + XDrawSpecifications openStyle; + XDrawSpecifications highStyle; + XDrawSpecifications closeStyle; + XDrawSpecifications lowStyle; + + // + // Constructors ... + XOHCLDrawSpecification() + { + Clean(); + } + + // + // Operators ... + void operator=(const XOHCLDrawSpecification &value) + { + // + lowStyle = value.lowStyle; + openStyle = value.openStyle; + highStyle = value.highStyle; + closeStyle = value.closeStyle; + } + + // + // Functions ... + + // + void Clean() + { + // + lowStyle.Clean(); + openStyle.Clean(); + highStyle.Clean(); + closeStyle.Clean(); + } + + // + void Default() + { + // + // Open ... + openStyle.width = 1; + openStyle.draw = true; + openStyle.clr = clrLime; + openStyle.style = STYLE_SOLID; + openStyle.Label( + "O", + openStyle.clr); + + // + // High ... + highStyle.width = 1; + highStyle.draw = true; + highStyle.clr = clrAqua; + highStyle.style = STYLE_SOLID; + highStyle.Label( + "H", + highStyle.clr); + + // + // Close ... + closeStyle.width = 1; + closeStyle.draw = true; + closeStyle.clr = clrRed; + closeStyle.style = STYLE_SOLID; + closeStyle.Label( + "C", + closeStyle.clr); + + // + // Low ... + lowStyle.width = 1; + lowStyle.draw = true; + lowStyle.clr = clrMagenta; + lowStyle.style = STYLE_SOLID; + lowStyle.Label( + "L", + lowStyle.clr); + } + + // + void Width(int value) + { + // + lowStyle.width = value; + openStyle.width = value; + highStyle.width = value; + closeStyle.width = value; + } + + // + void Style(ENUM_LINE_STYLE value) + { + // + lowStyle.style = value; + openStyle.style = value; + highStyle.style = value; + closeStyle.style = value; + } + + // + void Color(color value) + { + // + lowStyle.clr = value; + openStyle.clr = value; + highStyle.clr = value; + closeStyle.clr = value; + } + + // + void RayRight(bool value) + { + // + lowStyle.rayRight = value; + openStyle.rayRight = value; + highStyle.rayRight = value; + closeStyle.rayRight = value; + } + + // + void Draw(bool value) + { + // + lowStyle.draw = value; + openStyle.draw = value; + highStyle.draw = value; + closeStyle.draw = value; + } + + // + void Back(bool value) + { + // + lowStyle.back = value; + openStyle.back = value; + highStyle.back = value; + closeStyle.back = value; + } + + // + void Fill(bool value) + { + // + lowStyle.fill = value; + openStyle.fill = value; + highStyle.fill = value; + closeStyle.fill = value; + } + + // + void Label(string value) + { + // + lowStyle.Label(value); + openStyle.Label(value); + highStyle.Label(value); + closeStyle.Label(value); + } + + // + void SetLabelPrefix(string value) + { + // + lowStyle.label = value + " " + lowStyle.label; + openStyle.label = value + " " + openStyle.label; + highStyle.label = value + " " + highStyle.label; + closeStyle.label = value + " " + closeStyle.label; + } +}; + +// +string drawPrefix = "X-OBJ"; + +// +// Common Draw Functions ... + +// +// remove drawn objects ... +void RemoveDraws( + string tag = NULL, + long chartId = -1, + int subWindow = -1 // +) +{ + // + // Normalize Args ... + // + if (tag == NULL) + { + tag = drawPrefix; + } + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, tag) >= 0) + { + ObjectDelete(chartId, on); + } + } + + // + // Redraw Chart ... + ChartRedraw(); +} + +// +bool RemoveDraw( + string name, + long chartId = -1, + int subWindow = -1 // +) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + string objName = ""; + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, name) >= 0) + { + // + objName = on; + break; + } + } + + // + if (StringLen(objName) > 0) + { + result = ObjectDelete(chartId, objName); + } + + // + return result; +} + +// +// Deselect All Draws ... +void DeselectAllDraws() +{ + // + int objs = ObjectsTotal(ChartID(), 0); + for (int o = 0; o < objs; o++) + { + ObjectSetInteger(ChartID(), ObjectName(ChartID(), o, 0), OBJPROP_SELECTED, false); + } + + // + ChartRedraw(); +} + +// +// Check Object Exists ... +bool IsDrawExists( + string name, + long chartId = -1, + int subWindow = -1 // +) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + result = StringFind(on, name) >= 0; + if (result) + { + break; + } + } + + // + return result; +} + +// +// Find Specific Object Name ... +string FindObjectName( + string suggest, + long chartId = 0, + int subWindow = 0 // +) +{ + // + string result = NULL; + + // + int objectsCount = ObjectsTotal(chartId, subWindow); + if (objectsCount <= 0) + { + return result; + } + + // + for (int i = objectsCount - 1; i >= 0; i--) + { + // + string iObjectName = ObjectName(chartId, i, subWindow); + bool isExists = StringFind(iObjectName, suggest) >= 0; + if (isExists) + { + // + result = iObjectName; + break; + } + } + + // + return result; +} + +// +// Regular Draws ... + +// +// Arrow Functions ... + +// +// Draw an Arrow Object on Chart ... +bool DrawArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // arrow name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const uchar arrowCode = 252, // arrow code + const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position + const color clr = clrAqua, // arrow color + const ENUM_LINE_STYLE style = STYLE_SOLID, // border line style + const int width = 3, // arrow size + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // Order Object ... +) +{ + // + bool result = false; + + // + // set anchor point coordinates if they are not set ... + ChangeArrowEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create an arrow ... + result = ObjectCreate(chartID, objName, OBJ_ARROW, subWindow, time, price); + if (!result) + { + return result; + } + + // + // set the arrow code ... + ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, arrowCode); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set the arrow color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set the border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set the arrow's size ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the arrow by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is false by default, if you want making it possible to highlight and move the object + // change it to true ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the anchor point of Arrow ... +bool MoveArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, 0, time, price); + + // + return result; +} + +// +// Delete an arrow ... +bool DeleteArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow" // arrow name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete an arrow ... + result = !ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Change the arrow code ... +bool ArrowCodeChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const uchar code = 252 // arrow code +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change the arrow code ... + result = ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, code); + + // + return result; +} + +// +// Change anchor type ... +bool ArrowAnchorChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const ENUM_ARROW_ANCHOR anchor = ANCHOR_TOP // anchor type +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change anchor type ... + result = !ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + return result; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeArrowEmptyPoint( + datetime &time, + double &price // +) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// Horizontal Line Functions ... + +// +// Create, Draw the horizontal line ... +bool DrawHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + const int subWindow = 0, // subwindow index + double price = 0, // line price + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // if the price is not set, set it at the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a horizontal line ... + result = ObjectCreate(chartID, objName, OBJ_HLINE, subWindow, 0, price); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move horizontal line ... +bool MoveHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + double price = 0 // line price +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if the line price is not set, move it to the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // move a horizontal line ... + result = ObjectMove(chartID, objName, 0, 0, price); + + // + return result; +} + +// +// Delete a horizontal line ... +bool DeleteHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete a horizontal line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Vertical Line Functions ... + +// +// Create the vertical line ... +bool DrawVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + const int subWindow = 0, // subwindow index + datetime time = 0, // line time + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // if the line time is not set, draw it via the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a vertical line ... + result = ObjectCreate(chartID, objName, OBJ_VLINE, subWindow, time, 0); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the vertical line ... +bool MoveVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + datetime time = 0 // line time +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if line time is not set, move the line to the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // move the vertical line ... + result = ObjectMove(chartID, objName, 0, time, 0); + + // + return result; +} + +// +// Delete the vertical line ... +bool DeleteVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the vertical line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Rectangle Functions ... + +// +// Create rectangle by the given coordinates ... +bool DrawRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // down first point time + double price1 = 0, // down first point price + datetime time2 = 0, // up second point time + double price2 = 0, // up second point price + const color clr = clrRed, // rectangle color + const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines + const int width = 1, // width of rectangle lines + const bool fill = false, // filling rectangle with color + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Set anchor points' coordinates if they are not set ... + ChangeRectangleEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create a rectangle by the given coordinates ... + result = ObjectCreate( + chartID, + objName, + OBJ_RECTANGLE, + subWindow, + time1, + price1, + time2, + price2 // + ); + if (!result) + { + return result; + } + + // + // Set rectangle color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // Set the style of rectangle lines + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // Set width of the rectangle lines ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // Enable (true) or disable (false) the mode of filling the rectangle ... + ObjectSetInteger(chartID, objName, OBJPROP_FILL, fill); + + // + // Display in the foreground (false) or background (true) ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // Enable (true) or disable (false) the mode of highlighting the rectangle for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + + // + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // Hide (true) or display (false) graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // Set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Successful execution + return result; +} + +// +// Move the rectangle anchor point ...s +bool RectanglePointChange( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Move the anchor point ... + result = ObjectMove(chartID, objName, pointIndex, time, price); + + // + return result; +} + +// +// Delete the rectangle ... +bool DeleteRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle" // rectangle name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of rectangle's anchor points and set default +// values for empty ones +void ChangeRectangleEmptyPoints( + datetime &time1, double &price1, + datetime &time2, double &price2 // +) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, move it 300 points lower than the first one ... + if (!price2) + { + price2 = price1 - 300 * SymbolInfoDouble(Symbol(), SYMBOL_POINT); + } +} + +// +// RectangleLabel Functions ... + +// +// Create Rectangle Label Object ... +bool DrawRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // width + const int height = 18, // height + const color bgColor = clrWhiteSmoke, // background color + const ENUM_BORDER_TYPE border = BORDER_SUNKEN, // border type + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const color clr = clrRed, // flat border color (Flat) + const ENUM_LINE_STYLE style = STYLE_SOLID, // flat border style + const int lineWidth = 1, // flat border width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a rectangle label + result = ObjectCreate(chartID, objName, OBJ_RECTANGLE_LABEL, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set label coordinates ... + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set label size ... + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set background color ... + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border type ... + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + // set the chart's corner, relative to which point coordinates are defined ... + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set flat border color (in Flat mode) ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set flat border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set flat border width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, lineWidth); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the label by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move Rectangle Label .. +bool MoveRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // move the rectangle label ... + result = ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Delete the rectangle label ... +bool DeleteRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel" // label name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the label ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Change Rectangle Label Size ... +bool ChangeSizeRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int width = 50, // label width + const int height = 18 // label height +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change label size ... + result = ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change rectangle label border type ... +bool RectLabelChangeBorderType( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const ENUM_BORDER_TYPE border = BORDER_SUNKEN // border type +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change border type ... + result = ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + return result; +} + +// +// TrendLine Funcions ... + +// +// Create a trend line by the given coordinates ... +bool DrawTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrYellow, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool rayRight = false, // line's continuation to the right + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeTrendLineEmptyPoints( + time1, + price1, + time2, + price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a trend line by the given coordinates ... + result = ObjectCreate(chartID, objName, OBJ_TREND, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the line's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move trend line anchor point ... | +bool ChangeTrendLinePoint( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int pointindex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // move trend line's anchor point ... + result = ObjectMove(chartID, objName, pointindex, time, price); + + // + return result; +} + +// +// The function deletes the trend line from the chart ... +bool DeleteTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete a trend line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of trend line's anchor points and set default ... +// values for empty ones ... +void ChangeTrendLineEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2 // +) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, it is equal to the first point's one ... + if (!price2) + { + price2 = price1; + } +} + +// +// Text Functions ... + +// +// Create and Draw a Text Object ... +bool DrawText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const string text = "Text", // the text itself + const string font = "Arial", // font + const int fontSize = 10, // font size + const color clr = clrRed, // color + const double angle = 0.0, // text slope + const ENUM_ANCHOR_POINT anchor = ANCHOR_CENTER, // anchor type + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor point coordinates if they are not set ... + ChangeTextEmptyPoint(time, price); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create Text object + result = ObjectCreate(chartID, objName, OBJ_TEXT, subWindow, time, price); + if (!result) + { + return result; + } + + // + // set the text ... + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font ... + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size ... + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set the slope angle of the text ... + ObjectSetDouble(chartID, objName, OBJPROP_ANGLE, angle); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the object by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the anchor point ... +bool MoveText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // if point position is not set, move it to the current bar having Bid price + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, 0, time, price); + + // + return result; +} + +// +// Change the object text ... +bool ChangeText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text ... + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete Text object ... +bool DeleteText( + const long chartID = 0, // chart's ID + const string name = "Text" // object name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeTextEmptyPoint( + datetime &time, + double &price // +) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// Fibonacchi Functions ... + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawFibonacci( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // object color + const ENUM_LINE_STYLE style = STYLE_SOLID, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + result = ObjectCreate(chartID, objName, OBJ_FIBO, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawCustomFibonacci( + // + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + // + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrAqua, // object color + const ENUM_LINE_STYLE style = STYLE_DOT, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + result = ObjectCreate(chartID, name, OBJ_FIBO, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Change Levels Of Fibonacci ... + result = FibonacciLevelsSet( + levels, + values, + colors, + styles, + widths, + descriptions, + chartID, + objName); + + // + // successful execution ... + return result; +} + +// +// Set number of levels and their parameters ... +bool FibonacciLevelsSet( + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + bool result = false; + + // + // check array sizes ... + result = levels == ArraySize(colors) && + levels == ArraySize(styles) && + levels == ArraySize(widths) && + levels == ArraySize(widths); + if (!result) + { + return result; + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // set the number of levels ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELS, levels); + + // + // set the properties of levels in the loop ... + for (int i = 0; i < levels; i++) + { + // + // level value ... + ObjectSetDouble(chartID, objName, OBJPROP_LEVELVALUE, i, values[i]); + + // + // level color ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELCOLOR, i, colors[i]); + + // + // level style ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELSTYLE, i, styles[i]); + + // + // level width ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELWIDTH, i, widths[i]); + + // + // level description ... + // ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, DoubleToString(100 * values[i], 1)); + ObjectSetString(chartID, objName, OBJPROP_LEVELTEXT, i, descriptions[i]); + } + + // + // successful execution ... + return result; +} + +// +// Move Fibonacci Retracement anchor point ... +bool FibonacciPointChange( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, pointIndex, time, price); + + // + return result; +} + +// +// Delete Fibonacci Retracement ... +bool DeleteFibonachi( + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of Fibonacci Retracement anchor points and set +// default values for empty ones ... +void ChangeFibonacciEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2 // +) +{ + // + // if the second point's time is not set, it will be on the current bar ... + if (!time2) + { + time2 = TimeCurrent(); + } + + // + // if the second point's price is not set, it will have Bid value ... + if (!price2) + { + price2 = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // if the first point's time is not set, it is located 9 bars left from the second one ... + if (!time1) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time2, 10, temp); + + // + // set the first point 9 bars left from the second one ... + time1 = temp[0]; + } + + // + // if the first point's price is not set, move it 200 points below the second one ... + if (!price1) + { + price1 = price2 - 200 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); + } +} + +// +// Event Functions ... + +// +// Create an Event ... +bool EventCreate( + const long chartID = 0, // chart's ID + const string name = "Event", // object name + const int subWindow = 0, // subwindow index + const string text = "Content", // event text + datetime time = 0, // anchor point time + const color clr = clrRed, // color + const int width = 1, // point width when highlighted + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + if (!time) + { + time = TimeCurrent(); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectCreate(chartID, objName, OBJ_EVENT, subWindow, time, 0); + if (!result) + { + return result; + } + + // + // set event text + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set color + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set anchor point width if the object is highlighted + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving event by mouse + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution + return result; +} + +// +// Change Event object text +bool EventTextChange( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + const string text = "Content" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Move Event object +bool EventMove( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + datetime time = 0 // time +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if time is not set, move event to the last bar + if (!time) + { + time = TimeCurrent(); + } + + // + // move the object + result = ObjectMove(chartID, objName, 0, time, 0); + + // + return result; +} + +// +// Delete Event object +bool EventDelete( + const long chartID = 0, // chart's ID + const string name = "Event" // event name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Button Functions ... + +// +// Create the button ... +bool ButtonCreate( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // button width + const int height = 15, // button height + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const string text = "Button", // text + const string font = "Arial", // font + const int fontSize = 8, // font size + const color clr = clrBlack, // text color + const color bgColor = clrLightGray, // background color + const color borderColor = clrNONE, // border color + const bool state = false, // pressed/released + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create the button + result = ObjectCreate(chartID, objName, OBJ_BUTTON, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set button coordinates + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set button size + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set the text + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set text color + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set background color + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border color + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_COLOR, borderColor); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // set button state + ObjectSetInteger(chartID, objName, OBJPROP_STATE, state); + + // + // enable true or disable false the mode of moving the button by mouse + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + return result; +} + +// +// Move the button ... +bool ButtonMove( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // move the button + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Change button size ... +bool ButtonChangeSize( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int width = 50, // button width + const int height = 18 // button height +) +{ + // + bool result = false; + + // + // change the button size + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change corner of the chart for binding the button ... +bool ButtonChangeCorner( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER // chart corner for anchoring +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change anchor corner + result = ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + return result; +} + +// +// Change button text ... +bool ButtonTextChange( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete the button ... +bool ButtonDelete( + const long chartID = 0, // chart's ID + const string name = "Button" // button name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the button + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Chart Style Drawers ... + +// +// Apply Styles On Chart ... +void ApplyChartStyle( + long mChartId = -1, // chart's ID + ENUM_CHART_MODE mMode = CHART_CANDLES, // chart's mMode + bool mShowBidLine = true, // show bid line + bool mShowAskLine = true, // show ask line + bool mShowGrid = false, // show grids on chart + bool mShowVolumes = false, // show volumes + bool mShowTradeLevels = true, // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true, // chart autoscroll + bool mQuickNavigation = true, // chart quick navigation state + color mForeGroundColor = clrWhite, // chart's foreground color + color mBackGroundColor = clrBlack, // chart's background color + color mUpColor = clrGreen, // Up Color + color mDownColor = clrRed, // Down Color + color mBullishColor = clrGreen, // Bullish color + color mBearishColor = clrRed, // Bearish color + color mGridColor = clrGray, // grid color + color mBidLineColor = clrGray, // bid line color + color mAskLineColor = clrRed, // ask line color + color mLineColor = clrLime, // line mMode and doji candlestick color + color mStopColor = clrGold, // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen // volumes color +) +{ + // + // Validate Args ... + if (mChartId == -1) + { + mChartId = 0; + } + + // + ChartSetInteger(mChartId, CHART_MODE, mMode); + ChartSetInteger(mChartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(mChartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(mChartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(mChartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(mChartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(mChartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(mChartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(mChartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(mChartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(mChartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(mChartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(mChartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(mChartId, CHART_COLOR_VOLUME, mVolumesColor); +} + +// +// Tools ... + +// +// Retrieve Chart Size ... +bool GetChartSize( + XSize &result, // Holds Result ... + long chartID = 0 // Specified Chart ID ... +) +{ + // + bool mResult = false; + + // + mResult = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, result.width); + if (!mResult) + { + return mResult; + } + + // + mResult = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, result.height); + + // + return mResult; +} diff --git a/BKPS/14031106/Libraries/x-saherelm.x-poi.lib.mq5 b/BKPS/14031106/Libraries/x-saherelm.x-poi.lib.mq5 new file mode 100644 index 0000000..049be86 --- /dev/null +++ b/BKPS/14031106/Libraries/x-saherelm.x-poi.lib.mq5 @@ -0,0 +1,11521 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XPOILib +// Description: All models related to POIs ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright `023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include + +// +// Definitions ... + +// +// Definitions ... + +// +// All Available POI(s) ... +enum ENUM_XPOIS +{ + // + X_POI_NONE, + // + X_POI_TICKS_ZONES, // Ticks Zone ... + // + // Trading Day ... + X_POI_TRADING_DAY, // Trading Day ... + // + // Market Session ... + X_POI_MARKET_SESSION, // Market Session ... + // + // Momentum Bar ... + X_POI_MOMENTUM_BAR, // Momentum Bar ... + // + // Rejection Bar ... + X_POI_REJECTION_BAR, // Rejection Bar ... + // + // Swings ... + X_POI_SWING_HIGH, // Simple Swing High ... + X_POI_SWING_LOW, // Simple Swing Low ... + // + // Support nad Resistance ... + X_POI_SUPPORT_ZONE, // Support Zone ... + X_POI_RESISTANCE_ZONE, // Resistance Zone ... + // + // Supply and Demand Zones ... + X_POI_SUPPLY_ZONE, // Supply Zone ... + X_POI_DEMAND_ZONE, // Demand Zone ... + // + // Order Blocks ... + X_POI_BULLISH_ORDERBLOCK, // Bullish Order Block ... + X_POI_BEARISH_ORDERBLOCK, // Bearish Order Block ... + // + // Fair Value Gaps ... + X_POI_BULLISH_FVG, // Bullish Order Block ... + X_POI_BEARISH_FVG, // Bearish Order Block ... +}; + +// +// Event Types ... +enum ENUM_XPOI_EVENTS +{ + // + // Trading Days ... + X_TRADE_DAY_FIRST_BAR, // Trading Day First Bar ... + X_TRADE_DAY_LAST_BAR, // Trading Day Last Bar ... + // + // Session ... + X_SESSION_FIRST_BAR, // Session First Bar ... + X_SESSION_LAST_BAR, // Session Last Bar ... + // + // Momentum Bar ... + X_BULLISH_MOMENTUM_BAR_DETECTED, + X_BEARISH_MOMENTUM_BAR_DETECTED, + // + // Rejection Bar ... + X_BULLISH_REJECTION_BAR_DETECTED, + X_BEARISH_REJECTION_BAR_DETECTED, + // + // Swings ... + X_SWING_HIGH_DETECTED, + X_SWING_LOW_DETECTED, + // + // Support nad Resistance ... + X_SUPPORT_ZONE_DETECTED, // Support Zone ... + X_RESISTANCE_ZONE_DETECTED, // Resistance Zone ... + // + // Supply nad Demand ... + X_SUPPLY_ZONE_DETECTED, // Supply Zone ... + X_DEMAND_ZONE_DETECTED, // Demand Zone ... + // + // Order Blocks ... + X_BULLISH_ORDERBLOCK_DETECTED, // Bullish Order Block ... + X_BEARISH_ORDERBLOCK_DETECTED, // Bearish Order Block ... + // + // Fair Value Gaps ... + X_BULLISH_FVG_DETECTED, // Bullish Fair Value GapÙ‘ ... + X_BEARISH_FVG_DETECTED, // Bearish Fair Value GapÙ‘ ... +}; + +// +// Forext Sessions ... +enum ENUM_XSESSION +{ + X_TOKYO, + X_SYDNEY, + X_LONDON, + X_NEW_YORK, + X_FRANKFORT, +}; + +// +// Implementation ... + +// +// Base POI Model Class ... +class XCBasePOI : public XCBase +{ + // + public: + // + + // + // Constructor ... + void XCBasePOI() + { + // + Clean(); + + // + mSep = "_"; + mLineSep = "\n"; + } + + // + // Deconstructor ... + void ~XCBasePOI() + { + Clean(); + } + + // + // Virtual ... + + /** + * Cleanup ... + */ + virtual void Clean() + { + mType = X_POI_NONE; + } + + /** + * Validate ... + * + * @return ( virtual bool ) + */ + virtual bool IsValid() + { + return false; + } + + /** + * Retrieve POI Type ... + * + * @return ( virtual ENUM_XPOIS member ) + */ + virtual ENUM_XPOIS Type() + { + return mType; + } + + /** + * Retrieve POI Type ... + * + * @return ( virtual string ) + */ + virtual string TypeAsString() + { + return ToString(mType); + } + + /** + * Retrieve POI Tag ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + return NULL; + } + + /** + * Retrieve POI Tooltip ... + * + * @return ( virtual string ) + */ + virtual string GetTooltip() + { + return NULL; + } + + // + protected: + // + // Props ... + string mSep; // Separator ... + string mLineSep; // Line Separator ... + ENUM_XPOIS mType; // Type ... + + // + private: + // +}; + +// +// Zone POI Class ... +class XCZone : public XCBasePOI +{ + // + public: + // + + // + // Constructor ... + void XCZone() + { + } + + // + // Deconstructor ... + void ~XCZone() + { + } + + // + // Tools ... + + // + // Getter(s) / Setter(s) ... + + /** + * Get Zone Upper Boundary ... + * + * @return ( double ) + */ + double Upper() + { + return mUpper; + } + + /** + * Set Zone Upper Boundary ... + */ + void Upper(double value) + { + mUpper = value; + } + + /** + * Get Zone Lower Boundary ... + * + * @return ( double ) + */ + double Lower() + { + return mLower; + } + + /** + * Set Zone Lower Boundary ... + */ + void Lower(double value) + { + mLower = value; + } + + /** + * Retrieve Zone Range ... + * + * @return ( double ) + */ + double Range() + { + // + double result = 0; + + // + double upper = Upper(); + double lower = Lower(); + + // + if (upper > 0 && lower > 0 && upper > lower) + { + result = upper - lower; + } + + // + return result; + } + + double RangePercent() + { + // + double result = 0; + + // + double range = Range(); + if (range > 0) + { + result = range / 100; + } + + // + return result; + } + + // + // Virtuals ... + + /** + * Get Zone Start Date ... + * + * @return ( virtual datetime ) + */ + virtual datetime From() + { + return NULL; + } + + /** + * Get Zone End Date ... + * + * @return ( virtual datetime ) + */ + virtual datetime To() + { + return NULL; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + // + // Validators ... + + /** + * Validate Upper and Lower of Zone ... + * + * @return ( bool ) + */ + bool IsValidBoundary() + { + // + bool result = false; + + // + result = + // + mUpper > 0 && + mLower > 0 && + mUpper >= mLower + // + ; + + // + return result; + } + + /** + * Check From Date of Zone is Valid ... + * + * @return ( bool ) + */ + bool IsValidFrom() + { + // + bool result = false; + + // + datetime from = From(); + result = IsSpecifiedValid(from); + + // + return result; + } + + // + protected: + // + // Props ... + double mUpper; // Zone Upper ... + double mLower; // Zone Lower ... + + // + private: + // + // Props ... + + // +}; + +// +// From To Zone ... +class XCFromToZone : public XCBasePOI +{ + // + public: + // + + // + // Constructor ... + void XCFromToZone() + { + } + + // + // Deconstructor ... + void ~XCFromToZone() + { + } + + // + // Tools ... + + bool InitFromTo( + ENUM_XPOIS type, + string title, + datetime from // + ) + { + // + bool result = false; + + // + result = type != X_POI_NONE && + IsSpecifiedValid(from) && + IsSpecifiedValid(title); + + // + mType = type; + mFrom = from; + mTitle = title; + mTo = TimeCurrent(); + + // + result = IsValid(); + + // + return result; + } + + bool InitFromTo( + ENUM_XPOIS type, + string title, + datetime from, + datetime to // + ) + { + // + bool result = false; + + // + result = IsValid(); + + // + result = InitFromTo( + type, + title, + from // + ); + if (!result) + { + return result; + } + + // + to = NormalizeTime(to); + mTo = to; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Zone Start Time ... + * + * @return ( datetime ) + */ + datetime From() + { + return mFrom; + } + + /** + * Set Zone Start Time ... + * + * @param value: Datetime + */ + void From(datetime value) + { + // + value = NormalizeTime(value); + + // + mFrom = value; + } + + /** + * Get Zone End Time ... + * + * @return ( datetime ) + */ + datetime To() + { + return mTo; + } + + /** + * Set Zone End Time ... + * + * @param value: Datetime + */ + void To(datetime value) + { + // + value = NormalizeTime(value); + + // + mTo = value; + } + + /** + * Get Title ... + * + * @return ( string ) + */ + string Title() + { + return mTitle; + } + + /** + * Set Title ... + * + * @param value: String ... + */ + // void Title(string value) + // { + // mTitle = value; + // } + + // + // Overrides ... + + void Clean() override + { + // + mTo = NULL; + mFrom = NULL; + mType = X_POI_NONE; + } + + bool IsValid() override + { + // + bool result = false; + + // + result = + // + mType != X_POI_NONE && + IsSpecifiedValid(mTo) && + IsSpecifiedValid(mFrom) && + IsSpecifiedValid(mTitle) + // + ; + + // + return result; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + string hash = TypeAsString() + mSep + ToString(From()) + mSep + Title(); + hash = ToMD5(hash); + + // + result = TypeAsString() + "[" + Title() + "]" + mSep + hash; + + // + return result; + } + + // + protected: + // + + // + private: + // + // Props ... + datetime mFrom; // Start Date + datetime mTo; // End Date + string mTitle; // Zone Title + + // +}; + +// +// Bar Zone ... +class XCBarZone : public XCZone +{ + // + public: + // + + // + // Constructor ... + void XCBarZone() + { + } + + // + // Deconstructor ... + void ~XCBarZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param type: ENUM_XPOIS member ... + * @param upperPrice: ENUM_X_PRICE member ... + * @param lowerPrice: ENUM_X_PRICE member ... + * + * @return ( bool ) + */ + bool InitBarZone( + XOHCL &bar, + ENUM_XPOIS type, + ENUM_X_PRICE upperPrice, + ENUM_X_PRICE lowerPrice // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + type != X_POI_NONE && + upperPrice != lowerPrice; + if (!result) + { + return result; + } + + // + mBar = bar; + mType = type; + mUpperPrice = upperPrice; + mLowerPrice = lowerPrice; + mUpper = bar.GetPrice(upperPrice); + mLower = bar.GetPrice(lowerPrice); + + // + result = IsValidBarZone(); + if (result) + { + // + From(bar.time); + To(TimeCurrent()); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Fill Bar as XOHCL struct ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillBar( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + bar = mBar; + result = mBar.IsValid(); + + // + return result; + } + + /** + * Set From Date ... + * + * @param value: DateTime ... + */ + void From(datetime value) + { + // + if (!IsValidBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mFrom = value; + } + + /** + * Set To Date ... + * + * @param value: DateTime ... + */ + void To(datetime value) + { + // + if (!IsValidBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mTo = value; + } + + /** + * Retrieve Bar Time ... + * + * @return ( datetime ) + */ + datetime BarTime() + { + return mBar.time; + } + + /** + * Get Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + // + string result = NULL; + + // + if (!mBar.IsValid()) + { + return result; + } + + // + return mBar.symbol; + + // + return result; + } + + /** + * Get Period ... + * + * @return ( int ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + if (!mBar.IsValid()) + { + return result; + } + + // + return mBar.period; + + // + return result; + } + + // + // Overrides ... + + void Clean() override + { + // + mBar.Clean(); + mUpper = 0; + mLower = 0; + mType = X_POI_NONE; + } + + datetime From() override + { + return mFrom; + } + + datetime To() override + { + return mTo; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValidBarZone()) + { + return result; + } + + // + string hash = ToMD5(mBar.GetTag()); + + // + result = + // + TypeAsString() + mSep + + ToString(mBar.period) + mSep + + hash + // + ; + + // + return result; + } + + string GetTooltip() override + { + // + string result = NULL; + + // + if (!IsValidBarZone()) + { + return result; + } + + // + return result; + } + + // + protected: + // + // Props ... + XOHCL mBar; // Bar ... + ENUM_X_PRICE mUpperPrice; // Upper Price Selection + ENUM_X_PRICE mLowerPrice; // Lower Price Selection + + /** + * Check Bar Zone Validation ... + * + * @return ( bool ) + */ + bool IsValidBarZone() + { + // + bool result = false; + + // + result = mBar.IsValid() && + mType != X_POI_NONE && + IsValidBoundary(); + + // + return result; + } + + // + private: + // + // Props ... + datetime mFrom; + datetime mTo; + + // +}; +class XCTwoBarZone : public XCZone +{ + // + public: + // + + // + // Constructor ... + void XCTwoBarZone() + { + } + + // + // Deconstructor ... + void ~XCTwoBarZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param type: ENUM_XPOIS member ... + * @param upperPrice: ENUM_X_PRICE member ... + * @param lowerPrice: ENUM_X_PRICE member ... + * + * @return ( bool ) + */ + bool InitTwoBarZone( + XOHCL &startBar, + XOHCL &endBar, + ENUM_XPOIS type, + bool useStartBarForUpper, + ENUM_X_PRICE upperPrice, + ENUM_X_PRICE lowerPrice // + ) + { + // + bool result = false; + + // + result = startBar.IsValid() && + endBar.IsValid() && + startBar.symbol == endBar.symbol && + startBar.period == endBar.period && + startBar.time < endBar.time && + type != X_POI_NONE; + if (!result) + { + return result; + } + + // + mType = type; + mEndBar = endBar; + mStartBar = startBar; + mUpperPrice = upperPrice; + mLowerPrice = lowerPrice; + mUseStartBarForUpper = useStartBarForUpper; + + mUpper = + useStartBarForUpper + ? startBar.GetPrice(upperPrice) + : endBar.GetPrice(upperPrice); + mLower = + useStartBarForUpper + ? endBar.GetPrice(lowerPrice) + : startBar.GetPrice(lowerPrice); + + // + result = IsValidTwoBarZone(); + if (result) + { + // + From(startBar.time); + To(endBar.time); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set From Date ... + * + * @param value: DateTime ... + */ + void From(datetime value) + { + // + if (!IsValidTwoBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mFrom = value; + } + + /** + * Set To Date ... + * + * @param value: DateTime ... + */ + void To(datetime value) + { + // + if (!IsValidTwoBarZone()) + { + return; + } + + // + value = NormalizeTime(value); + + // + mTo = value; + } + + /** + * Fill Start Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillStartBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bar = mStartBar; + + // + return result; + } + + /** + * Fill End Bar ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillEndBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValidTwoBarZone(); + if (!result) + { + return result; + } + + // + bar = mEndBar; + + // + return result; + } + + /** + * Get Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + // + string result = NULL; + + // + if (!mStartBar.IsValid()) + { + return result; + } + + // + return mStartBar.symbol; + + // + return result; + } + + /** + * Get Period ... + * + * @return ( int ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + if (!mStartBar.IsValid()) + { + return result; + } + + // + return mStartBar.period; + + // + return result; + } + + // + // Overrides ... + + void Clean() override + { + // + mStartBar.Clean(); + mEndBar.Clean(); + mUpper = 0; + mLower = 0; + mUseStartBarForUpper = false; + mType = X_POI_NONE; + } + + datetime From() override + { + return mFrom; + } + + datetime To() override + { + return mTo; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValidTwoBarZone()) + { + return result; + } + + // + string hash = ToMD5(mStartBar.GetTag() + mSep + mEndBar.GetTag()); + + // + result = + // + TypeAsString() + mSep + + ToString(mStartBar.period) + mSep + + hash + // + ; + + // + return result; + } + + string GetTooltip() override + { + // + string result = NULL; + + // + if (!IsValidTwoBarZone()) + { + return result; + } + + // + return result; + } + + // + protected: + // + // Props ... + XOHCL mStartBar; // Start (Oldest) Bar ... + XOHCL mEndBar; // End (Newest) Bar ... + bool mUseStartBarForUpper; // Use Start Bar for Upper Calculation ... + ENUM_X_PRICE mUpperPrice; // Upper Price Selection + ENUM_X_PRICE mLowerPrice; // Lower Price Selection + + /** + * Check Two Bar Zone Validation ... + * + * @return ( bool ) + */ + bool IsValidTwoBarZone() + { + // + bool result = false; + + // + result = mStartBar.IsValid() && + mEndBar.IsValid() && + mStartBar.symbol == mEndBar.symbol && + mStartBar.period == mEndBar.period && + mStartBar.time < mEndBar.time && + mType != X_POI_NONE && + IsValidBoundary(); + + // + return result; + } + + // + private: + // + // Props ... + datetime mFrom; + datetime mTo; + + // +}; + +// +// Swing Class ... +class XCSwing : public XCBasePOI +{ + // + public: + // + + // + // Constructor ... + void XCSwing() + { + } + + // + // Deconstructor ... + void ~XCSwing() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param type: ENUM_XPOIS member ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + ENUM_XPOIS type // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + (type == X_POI_SWING_HIGH || + type == X_POI_SWING_LOW); + if (!result) + { + return result; + } + + // + mBar = bar; + mType = type; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Fill Bar as XOHCL struct ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool FillBar( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + bar = mBar; + result = mBar.IsValid(); + + // + return result; + } + + /** + * Get Time of Swing ... + * + * @return ( datetime ) + */ + datetime GetTime() + { + // + datetime result = NULL; + + // + if (!IsValid() || !mBar.IsValid()) + { + return result; + } + + // + result = mBar.time; + + // + return result; + } + + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOHCL bar; + bool isFilled = FillBar(bar); + if (!isFilled) + { + return result; + } + + // + result = bar.period; + + // + return result; + } + + /** + * Check Swing High or not ... + * + * @return ( bool ) + */ + bool IsSwingHigh() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = + Type() == X_POI_SWING_HIGH; + + // + return result; + } + + /** + * Check Swing Low or not ... + * + * @return ( bool ) + */ + bool IsSwingLow() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = + Type() == X_POI_SWING_LOW; + + // + return result; + } + + /** + * Get Swing Value ... + * + * @return ( double ) + */ + double GetValue() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsSwingHigh() + ? mBar.high + : mBar.low; + + // + return result; + } + + // + // Overrides ... + + void Clean() override + { + // + mBar.Clean(); + mType = X_POI_NONE; + } + + bool IsValid() override + { + // + bool result = false; + + // + result = mBar.IsValid() && + (mType == X_POI_SWING_HIGH || + mType == X_POI_SWING_LOW); + + // + return result; + } + + string GetTag() override + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + string hash = ToMD5(mBar.GetTag()); + + // + string subType = IsSwingHigh() + ? "High" + : "Low"; + + // + result = + // + TypeAsString() + mSep + + subType + mSep + + ToString(mBar.period) + mSep + + hash + // + ; + + // + return result; + } + + string GetTooltip() override + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + return result; + } + + // + protected: + // + // Props ... + XOHCL mBar; // Swing Bar ... + + // + private: + // +}; + +// +// Supply Zone ... +class XCSupplyZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCSupplyZone() + { + } + + // + // Deconstructor ... + void ~XCSupplyZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_SUPPLY_ZONE, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = (datetime)((int)time - (range * periodSeconds)); + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_SUPPLY_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Demand Zone ... +class XCDemandZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCDemandZone() + { + } + + // + // Deconstructor ... + void ~XCDemandZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_DEMAND_ZONE, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = (datetime)((int)time - (range * periodSeconds)); + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_DEMAND_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Support Zone ... +class XCSupportZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCSupportZone() + { + } + + // + // Deconstructor ... + void ~XCSupportZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_SUPPORT_ZONE, + X_PRICE_DOWN, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = (datetime)((int)time - (range * periodSeconds)); + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_SUPPORT_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Resistance Zone ... +class XCResistanceZone : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCResistanceZone() + { + } + + // + // Deconstructor ... + void ~XCResistanceZone() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param range: Integer, Detection Range ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + int range = 0 // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_RESISTANCE_ZONE, + X_PRICE_HIGH, + X_PRICE_UP // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + if (result && + range > 0) + { + // + datetime time = bar.time; + int periodSeconds = PeriodSeconds(bar.period); + + // + datetime from = (datetime)((int)time - (range * periodSeconds)); + datetime to = (datetime)((int)time + (range * periodSeconds)); + + // + From(from); + To(to); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_RESISTANCE_ZONE; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Order Block ... +class XCOrderBlock : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCOrderBlock() + { + } + + // + // Deconstructor ... + void ~XCOrderBlock() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar, + ENUM_X_DIRECTION dir // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + (dir == X_DIRECTION_BULLISH || + dir == X_DIRECTION_BEARISH); + if (!result) + { + return result; + } + + // + ENUM_XPOIS mTT = + IsSpecifiedBullish(dir) + ? X_POI_BULLISH_ORDERBLOCK + : X_POI_BEARISH_ORDERBLOCK; + + // + result = InitBarZone( + bar, + mTT, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BULLISH_ORDERBLOCK; + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BEARISH_ORDERBLOCK; + + // + return result; + } + + /** + * Detect Order Blocks Breaker Bar ... + * + * @param breakerBar: XOHCL instance Reference ... + * + * @return ( bool ) + */ + bool DetectBreakerBar(XOHCL &breakerBar) + { + // + bool result = false; + + // + breakerBar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL fromBar; + result = FillBar(fromBar); + if (!result) + { + return result; + } + + // + int fromIndex = fromBar.Index(); + result = fromIndex > 0; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(); + ENUM_X_DIRECTION dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + double value = + isBullish + ? Upper() + : Lower(); + + // + for (int i = fromIndex - 1; i >= 0; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + fromBar.symbol, + fromBar.period, + i // + ); + if (!isInited) + { + continue; + } + + // + isInited = IsBarBreak( + value, + dir, + iBar // + ); + if (isInited) + { + // + breakerBar = iBar; + break; + } + } + + // + result = breakerBar.IsValid(); + + // + return result; + } + + /** + * Check Order Block is Hunted or not ... + * + * @param huntedBar: XOHCL instance Reference ... + * + * @return ( bool ) + */ + bool IsHunted(XOHCL &huntedBar) + { + // + bool result = false; + + // + huntedBar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL breakerBar; + result = DetectBreakerBar(breakerBar); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(); + + // + int breakerIndex = breakerBar.Index(); + for (int i = breakerIndex - 1; i >= 0; i--) + { + // + XOHCL iBar; + result = iBar.Init( + breakerBar.symbol, + breakerBar.period, + i // + ); + + // + double price = + isBullish + ? iBar.low + : iBar.high; + + // + result = IsPriceInsideZone( + price, + Upper(), + Lower() // + ); + if (result) + { + // + huntedBar = iBar; + break; + } + } + + // + result = huntedBar.IsValid(); + + // + return result; + } + + /** + * Check Order Block Validation ... + * + * @return ( bool ) + */ + bool IsValidOrderBlock() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + XOHCL breakerBar; + result = DetectBreakerBar(breakerBar); + if (!result) + { + return result; + } + int breakerBarIndex = breakerBar.Index(); + + // + XOHCL huntedBar; + bool isHunted = IsHunted(huntedBar); + result = !isHunted; + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(); + + // + for (int i = breakerBarIndex - 1; i >= 0; i--) + { + // + XOHCL iBar; + result = iBar.Init( + breakerBar.symbol, + breakerBar.period, + i // + ); + if (!result) + { + continue; + } + + // + double price = + isBullish + ? iBar.low + : iBar.high; + + // + result = + isBullish + ? price > Upper() + : price < Lower(); + if (!result) + { + return result; + } + } + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + (mType == X_POI_BULLISH_ORDERBLOCK || + mType == X_POI_BEARISH_ORDERBLOCK); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Rejection Bar ... +class XCRejectionBar : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCRejectionBar() + { + } + + // + // Deconstructor ... + void ~XCRejectionBar() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = + bar.GetLowShadow() > bar.GetHighShadow(); + bool isBearish = + bar.GetHighShadow() > bar.GetLowShadow(); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + ENUM_X_PRICE upPrice = isBullish + ? X_PRICE_HIGH + : X_PRICE_DOWN; + // + ENUM_X_PRICE loPrice = isBullish + ? X_PRICE_UP + : X_PRICE_LOW; + + // + result = InitBarZone( + bar, + X_POI_REJECTION_BAR, + upPrice, + loPrice // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_REJECTION_BAR && + mBar.GetLowShadow() > mBar.GetHighShadow(); + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_REJECTION_BAR && + mBar.GetHighShadow() > mBar.GetLowShadow(); + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_REJECTION_BAR; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Momentum Bar ... +class XCMomentumBar : public XCBarZone +{ + // + public: + // + + // + // Constructor ... + void XCMomentumBar() + { + } + + // + // Deconstructor ... + void ~XCMomentumBar() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param bar: XOHCL instance ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &bar // + ) + { + // + bool result = false; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = bar.IsBullish(); + bool isBearish = bar.IsBearish(); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + result = InitBarZone( + bar, + X_POI_MOMENTUM_BAR, + X_PRICE_HIGH, + X_PRICE_LOW // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + mBar.IsBullish() && + Type() == X_POI_MOMENTUM_BAR; + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + mBar.IsBearish() && + Type() == X_POI_MOMENTUM_BAR; + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidBarZone() && + mType == X_POI_MOMENTUM_BAR; + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Fair Value Gap ... +class XCFVG : public XCTwoBarZone +{ + // + public: + // + + // + // Constructor ... + void XCFVG() + { + } + + // + // Deconstructor ... + void ~XCFVG() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param startBar: XOHCL instance ... + * @param endBar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &startBar, + XOHCL &endBar, + ENUM_X_DIRECTION dir // + ) + { + // + bool result = false; + + // + result = endBar.IsValid() && + startBar.IsValid() && + (dir == X_DIRECTION_BULLISH || + dir == X_DIRECTION_BEARISH); + if (!result) + { + return result; + } + + // + bool isDirBullish = IsSpecifiedBullish(dir); + ENUM_XPOIS mTT = + isDirBullish + ? X_POI_BULLISH_FVG + : X_POI_BEARISH_FVG; + + // + bool useFistForUpper = isDirBullish + ? false + : true; + ENUM_X_PRICE upPrice = isDirBullish + ? X_PRICE_LOW + : X_PRICE_HIGH; + ENUM_X_PRICE loPrice = isDirBullish + ? X_PRICE_HIGH + : X_PRICE_LOW; + + // + result = InitTwoBarZone( + startBar, + endBar, + mTT, + useFistForUpper, + upPrice, + loPrice // + ); + if (!result) + { + return result; + } + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Check is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BULLISH_FVG; + + // + return result; + } + + /** + * Check is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + Type() == X_POI_BEARISH_FVG; + + // + return result; + } + + // + // Overrides ... + + bool IsValid() override + { + // + bool result = false; + + // + result = IsValidTwoBarZone() && + (mType == X_POI_BULLISH_FVG || + mType == X_POI_BEARISH_FVG); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // +}; + +// +// Ticks Zones ... + +// +class XCTickZone : public CObject +{ + // + // Public ... + public: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + + // + double high; + double low; + int ticks; + double percent; + + // + ulong volume; + double volumePercent; + + // + // Compare Two Zone With Each Other ... + virtual int Compare( + const CObject *node, + const int mode = 0 // + ) const + { + // + const XCTickZone *other = (XCTickZone *)node; + + // + return other.ticks - ticks; + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = high > 0 && + low > 0 && + high > low && + ticks > 0 && + percent > 0; + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // +}; + +// +class XCTicksZone : public XCTwoBarZone +{ + // + public: + // + + // + // Constructor ... + void XCTicksZone() + { + Default(); + } + + // + // Deconstructor ... + void ~XCTicksZone() + { + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Number of Ticks Levels ... + * + * @return ( int ) + */ + int Levels() + { + return mLevels; + } + + /** + * Set Number of Ticks Levels ... + * + * @return ( int ) + */ + void Levels(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mLevels = value; + } + + /** + * Apply Default Config ... + */ + virtual void Default() + { + // + Levels(10); + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @param startBar: XOHCL instance ... + * @param endBar: XOHCL instance ... + * + * @return ( bool ) + */ + bool Init( + XOHCL &startBar, + XOHCL &endBar // + ) + { + // + bool result = false; + + // + result = endBar.IsValid() && + startBar.IsValid(); + if (!result) + { + return result; + } + + // + // Calculate Start and End Time ... + datetime from = startBar.time; + datetime to = endBar.time; + ulong fromM = ((ulong)startBar.time * 1000); + ulong toM = ((ulong)endBar.time * 1000); + + // + // Symbol and Period ... + string symbol = startBar.symbol; + ENUM_TIMEFRAMES period = startBar.period; + + // + // Prepare Zones Array ... + mZones.Clear(); + + // + // Retrieve Ticks between Times ... + SpecificClean(mTicks); + CopyTicksRange( + symbol, + mTicks, + COPY_TICKS_ALL, + fromM, + toM // + ); + + // + // Ticks Volumes ... + int ticksVolumeCount = CopyTickVolume( + symbol, + PERIOD_M1, + from, + to, + mTickVolumes // + ); + if (IsValidSize(ticksVolumeCount)) + { + // + mVolumes = 0; + for (int i = 0; i < ticksVolumeCount; i++) + { + mVolumes += mTickVolumes[i]; + } + } + + // + // Retrieve Highs ... + SpecificClean(mHighs); + CopyHigh( + symbol, + period, + from, + to, + mHighs // + ); + + // + // Retrieve Lows ... + SpecificClean(mLows); + CopyLow( + symbol, + period, + from, + to, + mLows // + ); + + // + // Find Highest Value in Range ... + int highIDX = ArrayMaximum(mHighs); + mRangeHigh = mHighs[highIDX]; + + // + // Find Lowest Value in Range ... + int lowIDX = ArrayMinimum(mLows); + mRangeLow = mLows[lowIDX]; + + // + datetime mTimes[]; + CopyTime( + symbol, + period, + from, + to, + mTimes // + ); + mRangeHighTime = mTimes[highIDX]; + mRangeLowTime = mTimes[lowIDX]; + + // + double mRangeSize = mRangeHigh - mRangeLow; + + // + // Create Zones ... + for (int i = 0; i < Levels(); i++) + { + // + // Instance a New Zone ... + XCTickZone *iZone = new XCTickZone(); + + // + iZone.symbol = symbol; + iZone.period = period; + + // + // Calculate Each Zones High / Low based on Range ... + double iH = mRangeHigh - mRangeSize * i / Levels(); + double iL = mRangeHigh - mRangeSize * (i + 1) / Levels(); + + // + // Set Zone High Low Properties ... + iZone.low = iL; + iZone.high = iH; + + // + // Add Zone to Zone Array Objects ... + mZones.Add(iZone); + } + + // + // Calculate Each Zone Ticks ... + int ticksCount = ArraySize(mTicks); + for (int i = 0; i < ticksCount; i++) + { + // + // Retrieve Tick ... + MqlTick iTick = mTicks[i]; + + // + // Loop through Zones ... + for (int j = 0; j < Levels(); j++) + { + // + // Rejrieve j indexed Zone Object ... + XCTickZone *jZone = mZones.At(j); + + // + bool isInRange = IsTickInZoneRange( + iTick, + jZone // + ); + if (isInRange) + { + // + jZone.ticks++; + break; + } + } + } + + // + // Calculating Zone Percents ... + for (int i = 0; i < Levels(); i++) + { + // + XCTickZone *iZone = mZones.At(i); + + // + double percent = CalculateZoneTickPercent(iZone); + iZone.percent = percent; + } + + // + // Sort Zones Based on Percents ... + mZones.Sort(); + + // + mUpper = mRangeHigh; + mLower = mRangeLow; + mType = X_POI_TICKS_ZONES; + mEndBar = endBar; + mStartBar = startBar; + From(startBar.time); + To(endBar.time); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + // Try to Find Out PERIOD_1M times in each zone ... + datetime to1M = (datetime)((int)endBar.time + PeriodSeconds(period) - 60); + int to1MIndex = iBarShift( + symbol, + PERIOD_M1, + to1M // + ); + int from1MIndex = iBarShift( + symbol, + PERIOD_M1, + from // + ); + for (int i = from1MIndex; i > to1MIndex; i--) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + symbol, + PERIOD_M1, + i // + ); + if (!isInited) + { + continue; + } + ulong iVolume = iTickVolume( + symbol, + PERIOD_M1, + i // + ); + + // + // Loop through Zones ... + for (int j = 0; j < Levels(); j++) + { + // + XCTickZone *jZone = mZones.At(j); + if (!jZone.IsValid()) + { + continue; + } + + // + // Check iBar is Inside jZone ... + bool isIBarInside = + iBar.GetUp() < jZone.high && + iBar.GetDown() > jZone.low; + // iBar.low < jZone.high || + // iBar.high > jZone.low; + if (isIBarInside) + { + jZone.volume += iVolume; + } + } + } + + // + // Calculate Volume Percent ... + for (int i = 0; i < Levels(); i++) + { + // + XCTickZone *iZone = mZones.At(i); + + // + iZone.volumePercent = (double)(iZone.volume * 100 / mVolumes); + } + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + /** + * Retrieve Zones Count ... + * + * @return ( int ) + */ + int Count() + { + return mZones.Total(); + } + + /** + * Retrieve Specified Sorted Zones ... + * + * @param index: Integer ... + * + * @return ( XCTickZone * ) + */ + XCTickZone *GetZone(int index) + { + // + if (!IsValidIndex(index)) + { + return NULL; + } + + // + return mZones.At(index); + } + + /** + * Calculate Liquidity Percent for Specified Direction ... + * + * @param forDirection: ENUM_X_DIRECTION member, Specified Liquidity ... + * @param price: Double, Specified Price ... + * + * @return ( double ) + */ + double CalculateLiquidityPercent( + ENUM_X_DIRECTION forDirection, + double price // + ) + { + // + double result = 0; + + // + int count = Count(); + if (price <= 0 || + !IsValid() || + !IsValidSize(count) || + forDirection == X_DIRECTION_ALL || + forDirection == X_DIRECTION_NONE) + { + return result; + } + + // + bool isBullish = forDirection == X_DIRECTION_BULLISH; + + // + for (int i = 0; i < count; i++) + { + // + XCTickZone *iZone = GetZone(i); + + // + if (iZone.IsValid()) + { + // + result += !isBullish && + price > iZone.high + ? iZone.percent + : isBullish && + price < iZone.low + ? iZone.percent + : 0; + } + } + + // + return result; + } + + // + // Overrides ... + bool IsValid() override + { + // + bool result = false; + + // + result = + IsValidFrom() && + IsValidTwoBarZone() && + Levels() > 0 && + mZones.Total() == Levels() && + mRangeHigh > 0 && + mRangeLow > 0; + + // + return result; + } + + // + protected: + // + + // + private: + // + // Props ... + + // + MqlTick mTicks[]; + double mHighs[]; + double mLows[]; + ulong mVolumes; + ulong mTickVolumes[]; + double mRangeHigh; + datetime mRangeHighTime; + double mRangeLow; + datetime mRangeLowTime; + + // + int mLevels; // Number of Ticks Levels ... + + // + CArrayObj mZones; + + /** + * Check a Tick is in a Zone rage or not ... + * + * @param tick: MqlTick instance ... + * @param zone: XCTickZone instance ... + * + * @return ( bool ) + */ + bool IsTickInZoneRange( + MqlTick &tick, + XCTickZone *zone // + ) + { + // + bool result = false; + + // + result = + // + tick.bid >= zone.low && + tick.bid <= zone.high + // + ; + + // + return result; + } + + /** + * Calculate Zone Tick Percent ... + * + * @param zone: XCTickZone instance ... + * @param normalizationDigits: Integer ... + * + * @return ( double ) + */ + double CalculateZoneTickPercent( + XCTickZone *zone, + int normalizationDigits = 2 // + ) + { + // + double result = 0; + + // + if (normalizationDigits < 2 || normalizationDigits > 5) + { + normalizationDigits = 2; + } + + // + int ticksCount = ArraySize(mTicks); + if (ticksCount <= 0) + { + return result; + } + + // + result = (double)zone.ticks / ticksCount * 100; + result = NormalizeDouble(result, normalizationDigits); + + // + return result; + } + + // +}; + +// +// Trading Day ... +class XCDay : public XCFromToZone +{ + // + public: + // + + // + // Constructor ... + void XCDay() + { + } + + // + // Deconstructor ... + void ~XCDay() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @return ( bool ) + */ + bool Init() + { + // + bool result = false; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + // + protected: + // + + // + private: + // + + // +}; + +// +// Trading Session ... +class XCSession : public XCFromToZone +{ + // + public: + // + + // + // Constructor ... + void XCSession() + { + } + + // + // Deconstructor ... + void ~XCSession() + { + } + + // + // Tools ... + + /** + * Initialize POI ... + * + * @return ( bool ) + */ + bool Init() + { + // + bool result = false; + + // + result = IsValid(); + + // + return result; + } + + // + // Getter(s) / Setter(s) ... + + // + // Overrides ... + + // + protected: + // + + // + private: + // + + // +}; + +// +// +// Model Exists Founded POIs ... +struct XPOIState +{ + // + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + XCTicksZone *ticksZone; // Ticks Zone ... + + // + XCSwing *swingHighs[]; // Holds Founded Swing Highs ... + XCSwing *swingLows[]; // Holds Founded Swing Lows ... + XCMomentumBar *bullishMomentumBars[]; // Holds Founded Bullish Momentum Bars ... + XCMomentumBar *bearishMomentumBars[]; // Holds Founded Bearish Momentum Bars ... + XCRejectionBar *bullishRejectionBars[]; // Holds Founded Bullish Rejection Bars ... + XCRejectionBar *bearishRejectionBars[]; // Holds Founded Bearish Rejection Bars ... + XCSupportZone *supportZones[]; // Holds Founded Support Zones ... + XCResistanceZone *resistanceZones[]; // Holds Founded Resistance Zones ... + XCSupplyZone *supplyZones[]; // Holds Founded Supply Zones ... + XCDemandZone *demandZones[]; // Holds Founded Demand Zones ... + XCOrderBlock *bullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ... + XCOrderBlock *bearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ... + XCFVG *bullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ... + XCFVG *bearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ... + + // + // Constructor ... + void XPOIState() + { + Clean(); + } + + // + // Actions ... + + /** + * Cleanup all props ... + */ + void Clean() + { + // + symbol = NULL; + period = NULL; + time = NULL; + + // + ticksZone = NULL; + + // + Clean(swingHighs); + Clean(swingLows); + Clean(bullishMomentumBars); + Clean(bearishMomentumBars); + Clean(bullishRejectionBars); + Clean(bearishRejectionBars); + Clean(supportZones); + Clean(resistanceZones); + Clean(supplyZones); + Clean(demandZones); + Clean(bullishOrderBlocks); + Clean(bearishOrderBlocks); + Clean(bullishFairValueGaps); + Clean(bearishFairValueGaps); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + + // + return result; + } + + /** + * Check State has Childs or not ... + * + * @return ( bool ) + */ + bool HasChild() + { + // + bool result = false; + + // + result = + // + IsValidSize(CountSwingHighs()) || + IsValidSize(CountSwingLows()) || + IsValidSize(CountBullishMomentumBars()) || + IsValidSize(CountBearishMomentumBars()) || + IsValidSize(CountBullishRejectionBars()) || + IsValidSize(CountBearishRejectionBars()) || + IsValidSize(CountSupportZones()) || + IsValidSize(CountResistanceZones()) || + IsValidSize(CountSupplyZones()) || + IsValidSize(CountDemandZones()) || + IsValidSize(CountBullishOrderBlocks()) || + IsValidSize(CountBearishOrderBlocks()) || + IsValidSize(CountBullishFairValueGaps()) || + IsValidSize(CountBearishFairValueGaps()) + // + ; + + // + return result; + } + + /** + * Fill Dest State by Current State's Data ... + * + * @param dest: XPOIState instance, reference to specified dest ... + * + */ + void Fill(XPOIState &dest) + { + // + if (!IsValid() || + !HasChild()) + { + return; + } + + // + dest.symbol = symbol; + dest.period = period; + dest.time = time; + + // + Copy( + swingHighs, + dest.swingHighs, + false // + ); + Copy( + swingLows, + dest.swingLows, + false // + ); + Copy( + bullishMomentumBars, + dest.bullishMomentumBars, + false // + ); + Copy( + bearishMomentumBars, + dest.bearishMomentumBars, + false // + ); + Copy( + bullishRejectionBars, + dest.bullishRejectionBars, + false // + ); + Copy( + bearishRejectionBars, + dest.bearishRejectionBars, + false // + ); + Copy( + supportZones, + dest.supportZones, + false // + ); + Copy( + resistanceZones, + dest.resistanceZones, + false // + ); + Copy( + supplyZones, + dest.supplyZones, + false // + ); + Copy( + demandZones, + dest.demandZones, + false // + ); + Copy( + bullishOrderBlocks, + dest.bullishOrderBlocks, + false // + ); + Copy( + bearishOrderBlocks, + dest.bearishOrderBlocks, + false // + ); + Copy( + bullishFairValueGaps, + dest.bullishFairValueGaps, + false // + ); + Copy( + bearishFairValueGaps, + dest.bearishFairValueGaps, + false // + ); + + // + } + + /** + * Calculate Liquidity Percent for Specified Direction ... + * + * @param forDirection: ENUM_X_DIRECTION member, Specified Liquidity ... + * @param price: Double, Specified Price ... + * + * @return ( double ) + */ + double CalculateLiquidityPercent( + ENUM_X_DIRECTION forDirection, + double price = 0 // + ) + { + // + double result = 0; + + // + if (!IsValid() || + ticksZone == NULL) + { + return result; + } + + // + // Normalize Price for Actions ... + if (price <= 0) + { + // + MqlTick mTick; + bool isTickRetrieved = GetTick( + symbol, + mTick // + ); + if (isTickRetrieved) + { + price = mTick.bid; + } + } + + // + result = ticksZone + .CalculateLiquidityPercent( + forDirection, + price // + ); + + // + return result; + } + + // + // Counters ... + + // + int CountSwingHighs() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(swingHighs); + + // + return result; + } + + // + int CountSwingLows() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(swingLows); + + // + return result; + } + + // + int CountBullishMomentumBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishMomentumBars); + + // + return result; + } + + // + int CountBearishMomentumBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishMomentumBars); + + // + return result; + } + + // + int CountBullishRejectionBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishRejectionBars); + + // + return result; + } + + // + int CountBearishRejectionBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishRejectionBars); + + // + return result; + } + + // + int CountSupportZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(supportZones); + + // + return result; + } + + // + int CountResistanceZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(resistanceZones); + + // + return result; + } + + // + int CountSupplyZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(supplyZones); + + // + return result; + } + + // + int CountDemandZones() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(demandZones); + + // + return result; + } + + // + int CountBullishOrderBlocks() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishOrderBlocks); + + // + return result; + } + + // + int CountBearishOrderBlocks() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishOrderBlocks); + + // + return result; + } + + // + int CountBullishFairValueGaps() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bullishFairValueGaps); + + // + return result; + } + + // + int CountBearishFairValueGaps() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = ArraySize(bearishFairValueGaps); + + // + return result; + } + + // +}; + +// +// +// + +// +// Pivot Types ... +enum ENUM_XPV_PIVOTS +{ + XPV_NONE, + XPV_PEAK, + XPV_VALE, +}; + +// +// Model a Pivot structure ... +struct XPVPivot +{ + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double upper; + double lower; + + // + datetime from; + datetime to; + + // + int repetition; + + // + ENUM_XPV_PIVOTS type; + + // + // Combined all States ... + XPOIState state; + + // + XPVPivot() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + upper = 0; + lower = 0; + + // + to = NULL; + from = NULL; + symbol = NULL; + period = NULL; + + // + repetition = 0; + + // + type = XPV_NONE; + + // + state.Clean(); + } + + /** + * Validation ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(to) && + IsValid(from) && + IsValid(symbol) && + IsValid(period) && + repetition > 0 && + type != XPV_NONE && + (upper > 0 || lower > 0) + // + ; + + // + return result; + } + + /** + * Check Pivot is Peak ... + * + * @return ( bool ) + */ + bool IsPeak() + { + // + bool result = false; + + // + result = IsValid() && + type == XPV_PEAK; + + // + return result; + } + + /** + * Check Pivot is Vale ... + * + * @return ( bool ) + */ + bool IsVale() + { + // + bool result = false; + + // + result = IsValid() && + type == XPV_VALE; + + // + return result; + } + + /** + * Calculate Lower for Peaks ... + * + * @return ( double ) + */ + double CalculateLower() + { + // + double result = 0; + + // + if (!IsValid() || + !IsPeak()) + { + return result; + } + + // + int fromIndex = iBarShift( + symbol, + period, + from // + ); + + // + int toIndex = iBarShift( + symbol, + period, + to // + ); + + // + int count = + fromIndex - toIndex; + + // + int llIDX = iLowest( + symbol, + period, + MODE_LOW, + count, + toIndex // + ); + + // + result = + iLow( + symbol, + period, + llIDX // + ); + + // + return result; + } + + /** + * Calculate Upper for Vales ... + * + * @return ( double ) + */ + double CalculateUpper() + { + // + double result = 0; + + // + if (!IsValid() || + !IsVale()) + { + return result; + } + + // + int fromIndex = iBarShift( + symbol, + period, + from // + ); + + // + int toIndex = iBarShift( + symbol, + period, + to // + ); + + // + int count = + fromIndex - toIndex; + + // + int hhIDX = iHighest( + symbol, + period, + MODE_HIGH, + count, + toIndex // + ); + + // + result = + iHigh( + symbol, + period, + hhIDX // + ); + + // + return result; + } + + /** + * Calculate Range of Pivot ... + * + * @return ( double ) + */ + double CalculateRange() + { + // + double result = 0; + + // + if (!IsValid() || + upper <= 0 || + lower <= 0) + { + return result; + } + + // + result = upper - lower; + + // + return result; + } + + /** + * Calculate Middle of Pivot ... + * Used for + * @return ( double ) + */ + double CalculateMid() + { + // + double result = 0; + + // + double range = CalculateRange(); + if (range <= 0) + { + return result; + } + + // + result = lower + (range / 2); + + // + return result; + } + + /** + * Calculate Liquidity Percent for Specified Direction ... + * + * @param forDirection: ENUM_X_DIRECTION member, Specified Liquidity ... + * @param price: Double, Specified Price ... + * + * @return ( double ) + */ + double CalculateLiquidityPercent( + ENUM_X_DIRECTION forDirection, + double price = 0 // + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = state + .CalculateLiquidityPercent( + forDirection, + price // + ); + + // + return result; + } + + /** + * Check Price in Premium or not ... + * + * @return ( bool ) + */ + bool IsPriceInPremium() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + + // + double mid = CalculateMid(); + + // + result = + // + ask > mid && + bid > mid + // + ; + + // + return result; + } + + /** + * Check Price in Discount or not ... + * + * @return ( bool ) + */ + bool IsPriceInDiscount() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + + // + double mid = CalculateMid(); + + // + result = + // + ask > mid && + bid > mid + // + ; + + // + return result; + } + + // + + /** + * Get Unique Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + string hash = symbol + "_" + + ToString(period) + "_" + + ToString(upper) + "," + + ToString(lower) + "_" + + ToString(from) + "," + + ToString(to); + hash = ToMD5(hash); + + // + string typeStr = + type == XPV_PEAK + ? "Peak" + : "Vale"; + + // + result = + // + "XPV_" + + typeStr + "_" + + symbol + "_" + + ToString(period) + + "_" + hash + // + ; + + // + return result; + } + + // +}; + +// +// Pivots ... +struct XPVPivotPoint +{ + // + // Props ... + double value; + int repetition; + datetime time; + ENUM_XPV_PIVOTS type; + + // + // Constructor ... + XPVPivotPoint() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + value = 0; + time = NULL; + repetition = 0; + type = XPV_NONE; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + value > 0 && + IsValid(time) && + repetition > 0 && + type != XPV_NONE + // + ; + + // + return result; + } + + /** + * Check current Pivot Point is Peak or not ... + * + * @return ( bool ) + */ + bool IsPeak() + { + // + bool result = false; + + // + result = IsValid() && + type == XPV_PEAK; + + // + return result; + } + + /** + * Check current Pivot Point is Vale or not ... + * + * @return ( bool ) + */ + bool IsVale() + { + // + bool result = false; + + // + result = IsValid() && + type == XPV_VALE; + + // + return result; + } + + // +}; + +// +// +// + +// +// Consolidation Zone ... +struct XConsolidationZone +{ + // + // Props ... + + // + string symbol; // Symbol ... + ENUM_TIMEFRAMES period; // Period ... + + // + double upper; // Upper ... + double lower; // Lower ... + + // + datetime initTime; + int loopback; // Loopback ... + + // + ENUM_X_DIRECTION breakDirection; // Break Direction ... + XOHCL breakerBar; // Breaker Bar ... + + // + // Constructor ... + XConsolidationZone() + { + Clean(); + } + + // + // Tools ... + + /** + * Initialize Zone ... + * + * @param _symbol: String ... + * @param _period: ENUM_TIMEFRAMES member ... + * @param _upper: Double ... + * @param _lower: Double ... + * @param _loopback: Integer ... + * + * @return ( bool ) + */ + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + double _upper, + double _lower, + int _loopback // + ) + { + // + bool result = false; + + // + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + + // + result = + // + _upper > 0 && + _lower > 0 && + _loopback > 0 + // + ; + if (!result) + { + return result; + } + + // + upper = _upper; + lower = _lower; + symbol = _symbol; + period = _period; + loopback = _loopback; + + // + result = IsValid(); + if (result) + { + initTime = TimeCurrent(); + } + + // + return result; + } + + /** + * Update Breaked State ... + */ + void Update() + { + // + if (!IsValid()) + { + return; + } + + // + if (IsBreaked()) + { + return; + } + + // + XOHCL cBar; + bool isInited = cBar.Init( + symbol, + period, + 0 // + ); + if (!isInited) + { + return; + } + + // + XOHCL pBar; + isInited = cBar.GetPreviousBar(pBar); + if (!isInited) + { + return; + } + + // + // Check Consolidation Hounts ... + bool isHountTop = cBar.high > upper && + cBar.low < upper && + cBar.GetUp() < upper; + bool isHountBottom = cBar.low < lower && + cBar.high > lower && + cBar.GetDown() > lower; + bool isHounted = isHountTop || + isHountBottom; + if (isHounted) + { + // + if (isHountTop) + { + upper = cBar.high; + } + + // + if (isHountBottom) + { + lower = cBar.low; + } + + // + return; + } + + // + // Check Consolidation Breaks ... + bool isBreakTop = (cBar.GetUp() > upper && + cBar.GetDown() < upper) || + (cBar.low > upper && + cBar.high > upper); + bool isBreakBottom = (cBar.GetDown() < lower && + cBar.GetUp() > lower) || + (cBar.high < lower && + cBar.low < lower); + bool isBreaked = isBreakTop || + isBreakBottom; + if (!isBreaked) + { + return; + } + + // + // Calculate Break Direction ... + breakerBar = cBar; + breakDirection = isBreakTop + ? X_DIRECTION_BULLISH + : isBreakBottom + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + /** + * Cleanup ... + */ + void Clean() + { + // + upper = 0; + lower = 0; + loopback = 0; + symbol = NULL; + period = NULL; + initTime = NULL; + breakerBar.Clean(); + breakDirection = X_DIRECTION_NONE; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + IsValid(period) && + upper > 0 && + lower > 0 && + loopback > 0 + // + ; + + // + return result; + } + + /** + * Check Zone is Breaked or not ... + * + * @return ( bool ) + */ + bool IsBreaked() + { + // + bool result = false; + + // + result = breakerBar.IsValid() && + HasDirection(breakDirection); + + // + return result; + } + + /** + * Detect Supply Zone if Exists ... + * + * @return ( bool ) + */ + bool HasSupplyZone( + XCSupplyZone *&zone // + ) + { + // + bool result = false; + + // + result = IsBreaked() && + breakDirection == X_DIRECTION_BEARISH; + if (!result) + { + return result; + } + + // + // Implment Zone Finding ... + int index = breakerBar.Index(); + int hhIDX = iHighest( + symbol, + period, + MODE_HIGH, + loopback, + index // + ); + result = IsValidIndex(hhIDX); + if (!result) + { + return result; + } + + // + XOHCL hhBar; + result = hhBar.Init( + symbol, + period, + hhIDX // + ); + if (!result) + { + return result; + } + + // + zone = new XCSupplyZone(); + result = zone.Init( + hhBar, + loopback // + ); + + // + return result; + } + + /** + * Detect Demand Zone if Exists ... + * + * @return ( bool ) + */ + bool HasDemandZone( + XCDemandZone *&zone // + ) + { + // + bool result = false; + + // + result = IsBreaked() && + breakDirection == X_DIRECTION_BULLISH; + if (!result) + { + return result; + } + + // + // Implment Zone Finding ... + int index = breakerBar.Index(); + int llIDX = iLowest( + symbol, + period, + MODE_LOW, + loopback, + index // + ); + result = IsValidIndex(llIDX); + if (!result) + { + return result; + } + + // + XOHCL llBar; + result = llBar.Init( + symbol, + period, + llIDX // + ); + if (!result) + { + return result; + } + + // + zone = new XCDemandZone(); + result = zone.Init( + llBar, + loopback // + ); + + // + return result; + } + + /** + * Retrieve Start Time ... + * + * @return ( datetime ) + */ + datetime From() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int startIndex = iBarShift( + symbol, + period, + initTime // + ); + + // + result = iTime( + symbol, + period, + loopback + startIndex // + ); + + // + return result; + } + + /** + * Retrieve Unique Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = + // + GetTypeName(this) + "_" + + symbol + "_" + + ToString(period) + "_" + + ToString(upper) + "_" + + ToString(lower) + // + ; + + // + return result; + } + + // +}; + +/** + * Converts a Consolidation Zone ... + * + * @param zone: XConsolidationZone instance Reference ... + * @param dest: XCZone pointer Reference ... + * + * @return ( bool ) + */ +bool ToZone( + XConsolidationZone &zone, + XCZone *&dest // +) +{ + // + bool result = false; + + // + dest = NULL; + + // + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + dest = new XCZone(); + dest.Upper(zone.upper); + dest.Lower(zone.lower); + result = dest.IsValidBoundary(); + + // + return result; +} + +// +// Model Value Changed ... +struct XValueChange +{ + // + // Props ... + double before; // Before Change Value ... + double after; // After Change Value ... + datetime time; // Change Time ... + ENUM_X_DIRECTION dir; // Change Direction ... + + // + // Constructor ... + XValueChange() + { + Clean(); + } + + // + // Tools ... + + /** + * Initialize ... + * + * @param _before: Double, Value Before Change ... + * @param _after: Double, Value After Change ... + * @param _time: Datetime, Change Time ... + * @param _dir: ENUM_X_DIRECTION member, Specified Changed Direction ... + * + * @return ( bool ) + */ + bool Init( + double _before, // Before Change Value ... + double _after, // After Change Value ... + ENUM_X_DIRECTION _dir, // Change Direction ... + datetime _time = NULL // Change Time ... + ) + { + // + bool result = false; + + // + _time = NormalizeTime(_time); + + // + // Validate Inputs ... + result = + // + _after > 0 && + _before > 0 && + IsValid(_time) && + _after != _before && + HasDirection(_dir) + // + ; + if (!result) + { + return result; + } + + // + // Set Validated Values ... + dir = _dir; + time = _time; + after = _after; + before = _before; + + // + result = IsValid(); + + // + return result; + } + + /** + * Cleaning Up ... + */ + void Clean() + { + // + after = 0; + before = 0; + time = NULL; + dir = X_DIRECTION_NONE; + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + after > 0 && + before > 0 && + IsValid(time) && + after != before && + HasDirection(dir) + // + ; + + // + return result; + } + + /** + * Fill Change Bar ... + * + * @param bar: XOHCL instance Reference, holds Change Bar ... + * @param _symbol: String, Specified Symbol ... + * @param _period: ENUM_TIMEFRAMES _period member, Specified Period ... + * + * @return ( bool ) + */ + bool FillBar( + XOHCL &bar, + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL // + ) + { + // + bool result = false; + + // + bar.Clean(); + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + + // + result = IsValid() && + IsValid(_symbol) && + IsValid(_period); + if (!result) + { + return result; + } + + // + result = bar.Init( + _symbol, + _period, + time // + ); + + // + return result; + } + + // +}; + +// +// Price Zones Model ... +struct XPriceZones +{ + // + XOHCL bar; // if Based On Bar it's Filled ... + double price; // if Based on Price, it's Filled ... + + // + int count; // Exists Zones Count ... + + // + XCFVG *fairValueGap; // Exists Fair Value Gap ... + XCSupplyZone *supplyZone; // Exists Supply Zone ... + XCDemandZone *demandZone; // Exists Demand Zone ... + XCOrderBlock *orderBlock; // Exists Order Block ... + XCSupportZone *supportZone; // Exists Support Zone ... + XCResistanceZone *resistanceZone; // Exists Resistance Zone ...Ù‘ + + // + // Constructor ... + XPriceZones() + { + Clean(); + } + + /** + * Cleanup ... + */ + void Clean() + { + // + bar.Clean(); + price = 0; + + // + supplyZone = NULL; + demandZone = NULL; + orderBlock = NULL; + supportZone = NULL; + fairValueGap = NULL; + resistanceZone = NULL; + } + + /** + * Check Zone is Valid ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + (IsBasedOnBar() || + IsBasedOnPrice()) && + IsValidSize(count) + // + ; + + // + return result; + } + + /** + * Check Zones Base on Bar ... + * + * @return ( bool ) + */ + bool IsBasedOnBar() + { + return bar.IsValid(); + } + + /** + * Check Zones Based on Price ... + * + * @return ( bool ) + */ + bool IsBasedOnPrice() + { + return price > 0; + } + + /** + * Check Has Supply Zone ... + * + * @return ( bool ) + */ + bool HasSupplyZone() + { + // + return IsValidSize(count) && + supplyZone != NULL && + supplyZone.IsValid(); + } + + /** + * Check Has Demand Zone ... + * + * @return ( bool ) + */ + bool HasDemandZone() + { + // + return IsValidSize(count) && + demandZone != NULL && + demandZone.IsValid(); + } + + /** + * Check Has OrderBlock ... + * + * @return ( bool ) + */ + bool HasOrderBlock() + { + // + return IsValidSize(count) && + orderBlock != NULL && + orderBlock.IsValid(); + } + + /** + * Check Has Support Zone ... + * + * @return ( bool ) + */ + bool HasSupportZone() + { + // + return IsValidSize(count) && + supportZone != NULL && + supportZone.IsValid(); + } + + /** + * Check Has FairValueGap ... + * + * @return ( bool ) + */ + bool HasFairValueGap() + { + // + return IsValidSize(count) && + fairValueGap != NULL && + fairValueGap.IsValid(); + } + + /** + * Check Has Resistance Zone ... + * + * @return ( bool ) + */ + bool HasResistanceZone() + { + // + return IsValidSize(count) && + resistanceZone != NULL && + resistanceZone.IsValid(); + } + + /** + * Check Zones are Overal Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = + // + HasDemandZone() + // + || + // + HasSupportZone() + // + || + // + (HasOrderBlock() && + orderBlock.IsBullish()) + // + || + // + (HasFairValueGap() && + fairValueGap.IsBullish()) + // + ; + + // + return result; + } + + /** + * Check Zones are Overal Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = + // + HasSupplyZone() + // + || + // + HasResistanceZone() + // + || + // + (HasOrderBlock() && + orderBlock.IsBearish()) + // + || + // + (HasFairValueGap() && + fairValueGap.IsBearish()) + // + ; + + // + return result; + } + + /** + * Fill Zones Based On required Direction ... + * + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( int ) + */ + int FillZones( + ENUM_X_DIRECTION dir, + XCZone *&zones[] // + ) + { + // + int result = 0; + + // + Clean(zones); + + // + bool isBullish = IsBullish(dir); + bool isBoth = dir == X_DIRECTION_ALL || + dir == X_DIRECTION_NONE; + + // + if (isBoth || isBullish) + { + // + if (HasSupportZone()) + { + // + Add( + (XCZone *)supportZone, + zones // + ); + } + + // + if (HasDemandZone()) + { + // + Add( + (XCZone *)demandZone, + zones // + ); + } + + // + if (HasOrderBlock() && + orderBlock.IsBullish()) + { + // + Add( + (XCZone *)orderBlock, + zones // + ); + } + + // + if (HasFairValueGap() && + fairValueGap.IsBullish()) + { + // + Add( + (XCZone *)fairValueGap, + zones // + ); + } + } + + // + if (isBoth || !isBullish) + { + // + if (HasResistanceZone()) + { + // + Add( + (XCZone *)resistanceZone, + zones // + ); + } + + // + if (HasSupplyZone()) + { + // + Add( + (XCZone *)supplyZone, + zones // + ); + } + + // + if (HasOrderBlock() && + orderBlock.IsBearish()) + { + // + Add( + (XCZone *)orderBlock, + zones // + ); + } + + // + if (HasFairValueGap() && + fairValueGap.IsBearish()) + { + // + Add( + (XCZone *)fairValueGap, + zones // + ); + } + } + + // s + result = ArraySize(zones); + + // + return result; + } + + /** + * Calculate Boundary of Zones ... + * + * @param dir: ENUM_X_DIRECTION Member, Specified Direction ... + * @param upper: Double ... + * @param lower: Double ... + * + * @return ( bool ) + */ + bool GetBoundary( + ENUM_X_DIRECTION dir, + double &upper, + double &lower // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + XCZone *zones[]; + int mCount = FillZones(dir, zones); + result = IsValidSize(mCount); + if (!result) + { + return result; + } + + // + for (int i = 0; i < mCount; i++) + { + // + XCZone *iZone = zones[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + + // + upper = + upper == 0 + ? iUpper + : iUpper > upper + ? iUpper + : upper; + + // + lower = + lower == 0 + ? iLower + : iLower < lower + ? iLower + : lower; + } + + // + return result; + } + + /** + * Calculate Lifetime of Zones ... + * + * @param dir: ENUM_X_DIRECTION Member, Specified Direction ... + * @param from: DateTime ... + * @param to: DateTime ... + * + * @return ( bool ) + */ + bool GetLifetime( + ENUM_X_DIRECTION dir, + datetime &from, + datetime &to // + ) + { + // + bool result = false; + + // + to = NULL; + from = NULL; + + // + XCZone *zones[]; + int mCount = FillZones(dir, zones); + result = IsValidSize(mCount); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(dir); + bool isAll = dir == X_DIRECTION_NONE || + dir == X_DIRECTION_ALL; + + // + if (isAll || isBullish) + { + // + // Support Zone ... + bool hasSupportZone = HasSupportZone(); + if (hasSupportZone) + { + // + XCSupportZone *zone = supportZone; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + + // + // Demand Zone ... + bool hasDemandZone = HasDemandZone(); + if (hasDemandZone) + { + // + XCDemandZone *zone = demandZone; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + + // + // Order Block ... + bool hasOrderBlock = HasOrderBlock() && + orderBlock.IsBullish(); + if (hasOrderBlock) + { + // + XCOrderBlock *zone = orderBlock; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + + // + // Fair Value Gap ... + bool hasFairValueGap = HasFairValueGap() && + fairValueGap.IsBullish(); + if (hasFairValueGap) + { + // + XCFVG *zone = fairValueGap; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + } + + // + if (isAll || !isBullish) + { + // + // Resistance Zone ... + bool hasResistanceZone = HasResistanceZone(); + if (hasResistanceZone) + { + // + XCResistanceZone *zone = resistanceZone; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + + // + // Supply Zone ... + bool hasSupplyZone = HasSupplyZone(); + if (hasSupplyZone) + { + // + XCSupplyZone *zone = supplyZone; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + + // + // Order Block ... + bool hasOrderBlock = HasOrderBlock() && + orderBlock.IsBearish(); + if (hasOrderBlock) + { + // + XCOrderBlock *zone = orderBlock; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + + // + // Fair Value Gap ... + bool hasFairValueGap = HasFairValueGap() && + fairValueGap.IsBearish(); + if (hasFairValueGap) + { + // + XCFVG *zone = fairValueGap; + + // + from = + !IsValid(from) || + from > zone.From() + ? zone.From() + : from; + + // + to = + !IsValid(to) || + to < zone.To() + ? zone.To() + : from; + } + } + + // + result = + to > from && + IsValid(to) && + IsValid(from); + + // + return result; + } + + /** + * Calculate Box Model Data ... + * + * @param dir: ENUM_X_DIRECTION Member, Specified Direction ... + * @param upper: Double ... + * @param lower: Double ... + * @param from: DateTime ... + * @param to: DateTime ... + * + * @return ( bool ) + */ + bool GetBoxData( + ENUM_X_DIRECTION dir, + double &upper, + double &lower, + datetime &from, + datetime &to // + ) + { + // + bool result = false; + + // + bool hasBoundary = GetBoundary( + dir, + upper, + lower // + ); + + // + bool hasLifetime = GetLifetime( + dir, + from, + to // + ); + + // + result = + hasBoundary && + hasLifetime; + + // + return result; + } + + // +}; + +// +// Market Strucutre Model ... +struct XMarketStructure +{ + // + string symbol; + ENUM_TIMEFRAMES period; + + // + ENUM_X_DIRECTION bias; + + // + XPVPivotPoint vales[]; + XPriceZones valePriceZones[]; + + // + XPVPivotPoint peaks[]; + XPriceZones peakPriceZones[]; + + // + XOHCL lowestValeBar; + XOHCL lowestValePeakBreakeUpBar; + XOHCL valeAboveLowestValePeakBar; + + // + XOHCL highestPeakBar; + XOHCL peakBelowHighestPeakValeBar; + XOHCL highestPeakValeBreakeDownBar; + + // + XMarketStructure() + { + Clean(); + } + + /** + * Cleanup ... + */ + void Clean() + { + // + symbol = NULL; + period = NULL; + bias = X_DIRECTION_NONE; + + // + Clean(vales); + Clean(peaks); + Clean(valePriceZones); + Clean(peakPriceZones); + + // + lowestValeBar.Clean(); + lowestValePeakBreakeUpBar.Clean(); + valeAboveLowestValePeakBar.Clean(); + + // + highestPeakBar.Clean(); + peakBelowHighestPeakValeBar.Clean(); + highestPeakValeBreakeDownBar.Clean(); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + IsValid(symbol) && + IsValid(period) && + bias != X_DIRECTION_NONE; + + // + return result; + } + + /** + * Check Bullish Trend ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = + // + IsValid() && + IsBullish(bias) && + HasChild(peaks) && + HasDirection(bias) && + lowestValeBar.IsValid() && + HasChild(peakPriceZones) && + lowestValePeakBreakeUpBar.IsValid() && + valeAboveLowestValePeakBar.IsValid() + // + ; + + // + return result; + } + + /** + * Check Bearish Trend ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = + // + IsValid() && + IsBearish(bias) && + HasChild(vales) && + HasDirection(bias) && + highestPeakBar.IsValid() && + HasChild(valePriceZones) && + peakBelowHighestPeakValeBar.IsValid() && + highestPeakValeBreakeDownBar.IsValid() + // + ; + + // + return result; + } + + /** + * Check Has Trend ... + * + * @return ( bool ) + */ + bool HasTrend() + { + // + bool result = false; + + // + result = IsValid() && + (IsBullish() || + IsBearish()); + + // + return result; + } + + // +}; + +struct XStateZones +{ + // + XCSupportZone *supportZones[]; // Holds Founded Support Zones ... + XCResistanceZone *resistanceZones[]; // Holds Founded Resistance Zones ... + XCSupplyZone *supplyZones[]; // Holds Founded Supply Zones ... + XCDemandZone *demandZones[]; // Holds Founded Demand Zones ... + XCOrderBlock *bullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ... + XCOrderBlock *bearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ... + XCFVG *bullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ... + XCFVG *bearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ... + + // + XStateZones() + { + Clean(); + } + + /** + * Cleaning Model ... + */ + void Clean() + { + // + Clean(supportZones); + Clean(resistanceZones); + Clean(supplyZones); + Clean(demandZones); + Clean(bullishOrderBlocks); + Clean(bearishOrderBlocks); + Clean(bullishFairValueGaps); + Clean(bearishFairValueGaps); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValidSize(CountSupportZones()) || + IsValidSize(CountResistanceZones()) || + IsValidSize(CountSupplyZones()) || + IsValidSize(CountDemandZones()) || + IsValidSize(CountBullishOrderBlocks()) || + IsValidSize(CountBearishOrderBlocks()) || + IsValidSize(CountBullishFairValueGaps()) || + IsValidSize(CountBearishFairValueGaps()) + // + ; + + // + return result; + } + + // + // Tools ... + + // + int CountSupportZones() + { + // + int result = 0; + + // + result = ArraySize(supportZones); + + // + return result; + } + + // + int CountResistanceZones() + { + // + int result = 0; + + // + result = ArraySize(resistanceZones); + + // + return result; + } + + // + int CountSupplyZones() + { + // + int result = 0; + + // + result = ArraySize(supplyZones); + + // + return result; + } + + // + int CountDemandZones() + { + // + int result = 0; + + // + result = ArraySize(demandZones); + + // + return result; + } + + // + int CountBullishOrderBlocks() + { + // + int result = 0; + + // + result = ArraySize(bullishOrderBlocks); + + // + return result; + } + + // + int CountBearishOrderBlocks() + { + // + int result = 0; + + // + result = ArraySize(bearishOrderBlocks); + + // + return result; + } + + // + int CountBullishFairValueGaps() + { + // + int result = 0; + + // + result = ArraySize(bullishFairValueGaps); + + // + return result; + } + + // + int CountBearishFairValueGaps() + { + // + int result = 0; + + // + result = ArraySize(bearishFairValueGaps); + + // + return result; + } +}; + +struct XFVGOrderBlock +{ + // + // Props ... + XCOrderBlock *orderBlock; + XCFVG *fairValueGap; + // XStateZones stateZones; + + // + XFVGOrderBlock() + { + Clean(); + } + + /** + * Cleanup Model ... + */ + void Clean() + { + // + orderBlock = NULL; + fairValueGap = NULL; + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + orderBlock != NULL && + fairValueGap != NULL && + // stateZones.IsValid() && + ((orderBlock.IsBullish() && + fairValueGap.IsBullish()) || + ((orderBlock.IsBearish() && + fairValueGap.IsBearish()))) + // + ; + + // + return result; + } + + /** + * Get Model Direction ... + * + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool GetDirection( + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + dir = orderBlock.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Retrieve Boundary of Zone ... + * + * @param upper: Upper Boundary ...Ù‘ + * @param lower: Lower Bondary ... + * @return ( bool ) + */ + bool GetBoundary( + double &upper, + double &lower // + ) + { + // + bool result = false; + + // + upper = 0; + lower = 0; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + upper = orderBlock.Upper(); + upper = MathMax(upper, fairValueGap.Upper()); + + // + lower = orderBlock.Lower(); + lower = MathMax(lower, fairValueGap.Lower()); + + // + result = lower > 0 && + upper > 0 && + upper > lower; + + // + return result; + } + + /** + * Check Model is same as another Istance ... + * + * @param value: XFVGOrderBlock instance Reference ... + * + * @return ( bool ) + */ + bool IsSameAs(XFVGOrderBlock &value) + { + // + bool result = false; + + // + result = + IsValid() && + value.IsValid(); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION dir; + result = GetDirection(dir); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION valueDir; + result = value.GetDirection(valueDir); + if (!result) + { + return result; + } + + // + result = + // + dir == valueDir + // + && + // + orderBlock.From() == value.orderBlock.From() && + orderBlock.Upper() == value.orderBlock.Upper() && + orderBlock.Lower() == value.orderBlock.Lower() + // + && + // + fairValueGap.From() == value.fairValueGap.From() && + fairValueGap.Upper() == value.fairValueGap.Upper() && + fairValueGap.Lower() == value.fairValueGap.Lower() + // + ; + + // + return result; + } + // +}; + +// +// Extensions ... + +/** + * Converts ENUM_XPOI value to String Representation ... + * + * @param value: ENUM_XPOI member ... + * + * @return ( string ) + */ +string ToString(ENUM_XPOIS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_POI_TRADING_DAY: + result = "XTDAY"; + break; + + // + case X_POI_MARKET_SESSION: + result = "XMSESS"; + break; + + // + case X_POI_MOMENTUM_BAR: + result = "XMNTMB"; + break; + + // + case X_POI_REJECTION_BAR: + result = "XRJCTB"; + break; + + // + case X_POI_SWING_HIGH: + result = "XSPH"; + break; + + // + case X_POI_SWING_LOW: + result = "XSPL"; + break; + + // + case X_POI_SUPPORT_ZONE: + result = "XSUP"; + break; + + // + case X_POI_RESISTANCE_ZONE: + result = "XRES"; + break; + + // + case X_POI_SUPPLY_ZONE: + result = "XSUPPLY"; + break; + + // + case X_POI_DEMAND_ZONE: + result = "XDEMAND"; + break; + + // + case X_POI_BULLISH_ORDERBLOCK: + result = "XBULLOB"; + break; + + // + case X_POI_BEARISH_ORDERBLOCK: + result = "XBEAROB"; + break; + + // + case X_POI_BULLISH_FVG: + result = "XBULLFVG"; + break; + + // + case X_POI_BEARISH_FVG: + result = "XBEARFVG"; + break; + + // + case X_POI_TICKS_ZONES: + result = "XTKSZ"; + break; + } + + // + return result; +} + +/** + * Converts ENUM_XSESSION value to String Representation ... + * + * @param value: ENUM_XSESSION member ... + * + * @return ( string ) + */ +string ToString(ENUM_XSESSION value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_SYDNEY: + result = "Sydney"; + break; + + // + case X_TOKYO: + result = "Tokyo"; + break; + + // + case X_FRANKFORT: + result = "FrankGurt"; + break; + + // + case X_LONDON: + result = "London"; + break; + + // + case X_NEW_YORK: + result = "NewYork"; + break; + } + + // + return result; +} + +/** + * Generate General Event Messages ... + * + * @param value: ENUM_XPOI_EVENTS member ... + * + * @return ( string ) + */ +string ToString(ENUM_XPOI_EVENTS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_TRADE_DAY_FIRST_BAR: + result = "First Bar of Day"; + break; + + // + case X_TRADE_DAY_LAST_BAR: + result = "Last Bar of Day"; + break; + + // + case X_SESSION_FIRST_BAR: + result = "First Bar of Session"; + break; + + // + case X_SESSION_LAST_BAR: + result = "Last Bar of Session"; + break; + + // + case X_BULLISH_MOMENTUM_BAR_DETECTED: + result = "Bullish Momentum Bar Detected"; + break; + + // + case X_BEARISH_MOMENTUM_BAR_DETECTED: + result = "Bearish Momentum Bar Detected"; + break; + + // + case X_BULLISH_REJECTION_BAR_DETECTED: + result = "Bullish Rejection Bar Detected"; + break; + + // + case X_BEARISH_REJECTION_BAR_DETECTED: + result = "Bearish Rejection Bar Detected"; + break; + + // + case X_SWING_HIGH_DETECTED: + result = "Swing High Detected"; + break; + + // + case X_SWING_LOW_DETECTED: + result = "Swing Low Detected"; + break; + + // + case X_SUPPORT_ZONE_DETECTED: + result = "Support Zone Detected"; + break; + + // + case X_RESISTANCE_ZONE_DETECTED: + result = "Resistance Zone Detected"; + break; + + // + case X_SUPPLY_ZONE_DETECTED: + result = "Supply Zone Detected"; + break; + + // + case X_DEMAND_ZONE_DETECTED: + result = "Demand Zone Detected"; + break; + + // + case X_BULLISH_ORDERBLOCK_DETECTED: + result = "Bullish Order Block Detected"; + break; + + // + case X_BEARISH_ORDERBLOCK_DETECTED: + result = "Bearish Orer Block Detected"; + break; + + // + case X_BULLISH_FVG_DETECTED: + result = "Bullish FVG Detected"; + break; + + // + case X_BEARISH_FVG_DETECTED: + result = "Bearish FVg Detected"; + break; + } + + // + return result; +} + +// +// +// + +/** + * Find Oldest Pivot Index ... + * + * @param pivots: XPVPivot instance ... + * @return ( int ) + */ +int FindOldestPivotIndex( + XPVPivot &pivots[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(pivots); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XPVPivot iPivot = pivots[i]; + + // + bool isOldest = true; + for (int j = 0; j < count; j++) + { + // + XPVPivot jPivot = pivots[j]; + + // + isOldest = iPivot.from <= jPivot.from; + if (!isOldest) + { + break; + } + } + + // + if (isOldest) + { + // + result = i; + break; + } + } + + // + return result; +} + +/** + * Sort Pivots Based On From Date ... + * + * @param pivots: XPVPivot instance Collection reference ... + */ +void SortPivots( + XPVPivot &pivots[] // +) +{ + // + XPVPivot tmp[]; + Copy( + pivots, + tmp // + ); + + // + Clean(pivots); + + // + while (ArraySize(tmp) > 0) + { + // + if (ArraySize(tmp) == 1) + { + // + AddRef( + tmp[0], + pivots // + ); + + // + ArrayRemove( + tmp, + 0, + 1); + } + else + { + // + int idx = FindOldestPivotIndex(tmp); + if (IsValidIndex(idx)) + { + // + AddRef( + tmp[idx], + pivots // + ); + + // + ArrayRemove( + tmp, + idx, + 1 // + ); + } + } + } + + // + Clean(tmp); +} + +bool IsPivotBreaked( + XPVPivot &pivot, + XPVPivot &pivots[] // +) +{ + // + bool result = false; + + // + result = pivot.IsValid(); + if (!result) + { + return result; + } + + // + int count = ArraySize(pivots); + result = IsValidSize(pivots); + if (!result) + { + return result; + } + + // + // For Peaks Highs Must not Broked ... + // For Vales Lows Must not Broked ... + bool isPeak = pivot.IsPeak(); + + // + for (int i = 0; i < count; i++) + { + // + XPVPivot iPivot = pivots[i]; + + // + result = isPeak + ? iPivot.upper > pivot.upper + : iPivot.lower < pivot.lower; + if (result) + { + break; + } + } + + // + return result; +} + +/** + * Filter Broken Pivots for Detect Order Flow ... + * + * @param pivots: XPVPivot instance Collection reference ... + */ +void FilterBrokenPivots( + XPVPivot &pivots[] // +) +{ + // + XPVPivot tmp[]; + Copy( + pivots, + tmp // + ); + + // + Clean(pivots); + + // + while (ArraySize(tmp) > 0) + { + // + if (ArraySize(tmp) == 1) + { + // + AddRef( + tmp[0], + pivots // + ); + + // + ArrayRemove( + tmp, + 0, + 1 // + ); + } + else + { + // + XPVPivot pivot = tmp[0]; + + // + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + bool isBreaked = IsPivotBreaked( + pivot, + tmp // + ); + if (!isBreaked) + { + // + AddRef( + pivot, + pivots // + ); + } + } + } + + // + Clean(tmp); +} + +/** + * Calculate Order Flow Direction ... + * + * @param orderFlow: XPVPivot instance Collection reference ... + * @param dir: ENUM_X_DIRECTION member reference, Hold's Calculated Direction ... + * + * @return ( bool ) + */ +bool DetectPivotDirection( + XPVPivot &orderFlow[], + ENUM_X_DIRECTION &dir // +) +{ + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + int count = ArraySize(orderFlow); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + // For Bullish Direction all Exists lowers must be Greater or Equal Prev ... + bool isBullish = false; + bool canLookupForBullish = true; + + // + // For Bearish Direction all Exists uppers must be Lesser or Equal Prev ... + bool isBearish = false; + bool canLookupForBearish = true; + + // + for (int i = 0; i < count; i++) + { + // + XPVPivot iPivot = orderFlow[i]; + + // + XPVPivot tmp[]; + Copy( + orderFlow, + tmp // + ); + ArrayRemove( + tmp, + 0, + i + 1 // + ); + + // + int tmpCount = ArraySize(tmp); + if (IsValidSize(tmpCount)) + { + // + for (int j = 0; j < tmpCount; j++) + { + // + XPVPivot jPivot = tmp[j]; + + // + // Check Bullish Direction ... + isBullish = + canLookupForBullish && + jPivot.lower >= iPivot.lower; + if (!isBullish) + { + canLookupForBullish = false; + } + + // + // Check Bearish Direction ... + isBearish = + canLookupForBearish && + jPivot.upper <= iPivot.upper; + if (!isBearish) + { + canLookupForBearish = false; + } + + // + if (!canLookupForBullish && + !canLookupForBearish) + { + break; + } + } + } + Clean(tmp); + } + + // + if (isBullish && + !isBearish) + { + dir = X_DIRECTION_BULLISH; + } + else if (isBearish && + !isBullish) + { + dir = X_DIRECTION_BEARISH; + } + + // + result = dir != X_DIRECTION_NONE; + + // + return result; +} + +/** + * Detect all POIs which inside a Pivot ... + * + * @param pivot: XPVPivot instance, Specified Pivot ... + * @param source: XPOIState instance, Reference to Source State ... + * @param state: XPOIState instance, Reference to Detected Pivots ... + * @param lookupSwingHighs: Boolean ... + * @param lookupSwingLows: Boolean ... + * @param lookupSupportZones: Boolean ... + * @param lookupResistanceZones: Boolean ... + * @param lookupSupplyZones: Boolean ... + * @param lookupDemandZones: Boolean ... + * @param lookupBullishOrderBlocks: Boolean ... + * @param lookupBearishOrderBlocks: Boolean ... + * @param lookupBullishFairValueGaps: Boolean ... + * @param lookupBearishFairValueGaps: Boolean ... + * @param lookupBullishRejectionBars: Boolean ... + * @param lookupBearishRejectionBars: Boolean ... + * @param lookupBullishMomentumBars: Boolean ... + * @param lookupBearishMomentumBars: Boolean ... + */ +void DetectPivotPOIs( + XPVPivot &pivot, + XPOIState &source, + XPOIState &state, + bool lookupSwingHighs = true, + bool lookupSwingLows = true, + bool lookupSupportZones = true, + bool lookupResistanceZones = true, + bool lookupSupplyZones = true, + bool lookupDemandZones = true, + bool lookupBullishOrderBlocks = true, + bool lookupBearishOrderBlocks = true, + bool lookupBullishFairValueGaps = true, + bool lookupBearishFairValueGaps = true, + bool lookupBullishRejectionBars = true, + bool lookupBearishRejectionBars = true, + bool lookupBullishMomentumBars = true, + bool lookupBearishMomentumBars = true // +) +{ + // + state.Clean(); + + // + if (!pivot.IsValid()) + { + return; + } + + // + int count = 0; + + // + state.symbol = pivot.symbol; + state.period = pivot.period; + state.time = TimeCurrent(); + + // + // Swings ... + + // + // Swing High ... + if (lookupSwingHighs) + { + // + count = ArraySize(source.swingHighs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = source.swingHighs[i]; + + // + XOHCL iBar; + bool isFilled = iSwing.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isInside = iBar.high <= pivot.upper; + if (isInside) + { + // + // iSwing.To(pivot.to); + + // + Add( + iSwing, + state.swingHighs // + ); + } + } + } + } + + // + // Swing Low ... + if (lookupSwingLows) + { + // + count = ArraySize(source.swingLows); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSwing *iSwing = source.swingLows[i]; + + // + XOHCL iBar; + bool isFilled = iSwing.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isInside = iBar.low >= pivot.lower; + if (isInside) + { + // + // iSwing.To(pivot.to); + + // + Add( + iSwing, + state.swingLows // + ); + } + } + } + } + + // + // Support and Resistance Zones ... + + // + // Support Zones ... + if (lookupSupportZones) + { + // + count = ArraySize(source.supportZones); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = source.supportZones[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.supportZones // + ); + } + } + } + } + + // + // Resistance Zones ... + if (lookupResistanceZones) + { + // + count = ArraySize(source.resistanceZones); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = source.resistanceZones[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.resistanceZones // + ); + } + } + } + } + + // + // Supply and Demand Zones ... + + // + // Supply Zones ... + if (lookupSupplyZones) + { + // + count = ArraySize(source.supplyZones); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = source.supplyZones[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.supplyZones // + ); + } + } + } + } + + // + // Demand Zones ... + if (lookupDemandZones) + { + // + count = ArraySize(source.demandZones); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = source.demandZones[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.demandZones // + ); + } + } + } + } + + // + // Order Blocks ... + + // + // Bullish Order Blocks ... + if (lookupBullishOrderBlocks) + { + // + count = ArraySize(source.bullishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = source.bullishOrderBlocks[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.bullishOrderBlocks // + ); + } + } + } + } + + // + // Bearish Order Blocks ... + if (lookupBearishOrderBlocks) + { + // + count = ArraySize(source.bearishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = source.bearishOrderBlocks[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.bearishOrderBlocks // + ); + } + } + } + } + + // + // Fair Value Gaps ... + + // + // Bullish Fair Value Gaps ... + if (lookupBullishFairValueGaps) + { + // + count = ArraySize(source.bullishFairValueGaps); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = source.bullishFairValueGaps[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.bullishFairValueGaps // + ); + } + } + } + } + + // + // Bearish Fair Value Gaps ... + if (lookupBearishFairValueGaps) + { + // + count = ArraySize(source.bearishFairValueGaps); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = source.bearishFairValueGaps[i]; + + // + bool isInside = + iZone.Upper() <= pivot.upper && + iZone.Lower() >= pivot.lower; + if (isInside) + { + // + iZone.To(pivot.to); + + // + Add( + iZone, + state.bearishFairValueGaps // + ); + } + } + } + } + + // + // Rejection Bars ... + + // + // Bullish Rejection Bars ... + if (lookupBullishRejectionBars) + { + // + count = ArraySize(source.bullishRejectionBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iRejection = source.bullishRejectionBars[i]; + + // + XOHCL iBar; + bool isFilled = iRejection.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isInside = iBar.low <= pivot.upper && + iBar.low >= pivot.lower; + if (isInside) + { + // + iRejection.To(pivot.to); + + // + Add( + iRejection, + state.bullishRejectionBars // + ); + } + } + } + } + + // + // Bearish Rejection Bars ... + if (lookupBearishRejectionBars) + { + // + count = ArraySize(source.bearishRejectionBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCRejectionBar *iRejection = source.bearishRejectionBars[i]; + + // + XOHCL iBar; + bool isFilled = iRejection.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isInside = iBar.high <= pivot.upper && + iBar.high >= pivot.lower; + if (isInside) + { + // + iRejection.To(pivot.to); + + // + Add( + iRejection, + state.bearishRejectionBars // + ); + } + } + } + } + + // + // Momentum Bars ... + + // + // Bullish Momentum Bars ... + if (lookupBullishMomentumBars) + { + // + count = ArraySize(source.bullishMomentumBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCMomentumBar *iMomentum = source.bullishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isInside = iBar.low <= pivot.upper && + iBar.low >= pivot.lower; + if (isInside) + { + // + iMomentum.To(pivot.to); + + // + Add( + iMomentum, + state.bullishMomentumBars // + ); + } + } + } + } + + // + // Bearish Momenum Bars ... + if (lookupBearishMomentumBars) + { + // + count = ArraySize(source.bearishMomentumBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCMomentumBar *iMomentum = source.bearishMomentumBars[i]; + + // + XOHCL iBar; + bool isFilled = iMomentum.FillBar(iBar); + if (!isFilled) + { + continue; + } + + // + bool isInside = iBar.high <= pivot.upper && + iBar.high >= pivot.lower; + if (isInside) + { + // + iMomentum.To(pivot.to); + + // + Add( + iMomentum, + state.bearishMomentumBars // + ); + } + } + } + } +} + +/** + * Fill Pivot Tick Zone ... + * + * @param pivot: XPVPivot instance Reference ... + */ +void CalculatePivotTickZone( + XPVPivot &pivot, + int ticksLevels, + int ticksRange, + ENUM_TIMEFRAMES _period = NULL // +) +{ + // + string symbol = pivot.symbol; + ENUM_TIMEFRAMES period = IsValid(_period) + ? _period + : pivot.period; + + // + bool isInited = false; + + // + datetime from = pivot.from; + XOHCL iFromBar; + int iFromBarIndex = iBarShift( + symbol, + period, + from // + ); + isInited = iFromBar.Init( + symbol, + period, + iFromBarIndex // + ); + if (!isInited) + { + return; + } + + // + datetime to = pivot.to; + XOHCL iToBar; + int iToBarIndex = iBarShift( + symbol, + period, + to // + ); + isInited = iToBar.Init( + symbol, + period, + iToBarIndex // + ); + if (!isInited) + { + return; + } + + // + if (iFromBarIndex <= iToBarIndex) + { + return; + } + + // + XCTicksZone *iZone; + iZone = new XCTicksZone(); + + // + isInited = ticksLevels > 0 && + ticksRange > 0; + if (!isInited) + { + return; + } + + // + isInited = iZone.Init( + iFromBar, + iToBar // + ); + if (!isInited) + { + return; + } + + // + pivot.state.ticksZone = iZone; +} + +/** + * Filter State based on Pivot ... + * + * @param pivot: XPVPivot instance Reference ... + * @param state: XPOIState instance Reference ... + */ +void FilterPivotState( + XPVPivot &pivot, + XPOIState &state // +) +{ + // + bool isValid = + pivot.IsValid() && + state.IsValid() && + state.HasChild(); + if (!isValid) + { + return; + } + + // + int count = 0; + + // + double upper = pivot.upper; + double lower = pivot.lower; + + // + // + // + + // + // Resistance ... + count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + XCResistanceZone *tmp[]; + Copy( + state.resistanceZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + upper, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.resistanceZones, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // Supply ... + count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + XCSupplyZone *tmp[]; + Copy( + state.supplyZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + upper, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.supplyZones, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // Bearish Order Block ... + count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + XCOrderBlock *tmp[]; + Copy( + state.bearishOrderBlocks, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + upper, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.bearishOrderBlocks, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // Bearish Fair Value Gap ... + count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + XCFVG *tmp[]; + Copy( + state.bearishFairValueGaps, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCFVG *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + upper, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.bearishFairValueGaps, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // + // + + // + // Support ... + count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + XCSupportZone *tmp[]; + Copy( + state.supportZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + lower, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.supportZones, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // Demand ... + count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + XCDemandZone *tmp[]; + Copy( + state.demandZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + lower, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.demandZones, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // Bullish Order Block ... + count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + XCOrderBlock *tmp[]; + Copy( + state.bullishOrderBlocks, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + lower, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.bullishOrderBlocks, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } + + // + // Bullish Fair Value Gap ... + count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + XCFVG *tmp[]; + Copy( + state.bullishFairValueGaps, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCFVG *item = tmp[i]; + + // + bool isValid = IsPriceInsideZone( + lower, + item // + ); + if (!isValid) + { + // + ArrayRemove( + state.bullishFairValueGaps, + i, + 1 // + ); + } + } + + // + ArrayFree(tmp); + } +} + +/** + * Detect Box Date of Specified Pivot ... + */ +bool DetectPivotStateBoxData( + XPVPivot &pivot, + double &peakUpper, + double &peakLower, + datetime &peakFrom, + datetime &peakTo, + double &valeUpper, + double &valeLower, + datetime &valeFrom, + datetime &valeTo // +) +{ + // + bool result = false; + + // + peakUpper = 0; + peakLower = 0; + valeUpper = 0; + valeLower = 0; + + // + peakFrom = NULL; + peakTo = NULL; + valeFrom = NULL; + valeTo = NULL; + + // + result = pivot.IsValid(); + if (!result) + { + return result; + } + + // + int count = 0; + + // + // + // + + // + // Resistance ... + count = pivot.state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + XCResistanceZone *tmp[]; + Copy( + pivot.state.resistanceZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *item = tmp[i]; + + // + if (peakUpper == 0 || + peakUpper < item.Upper()) + { + peakUpper = item.Upper(); + } + + // + if (peakLower == 0 || + peakLower > item.Lower()) + { + peakLower = item.Lower(); + } + + // + if (!IsValid(peakFrom) || + peakFrom > item.From()) + { + peakFrom = item.From(); + } + + // + if (!IsValid(peakTo) || + peakTo < item.To()) + { + peakTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // Supply ... + count = pivot.state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + XCSupplyZone *tmp[]; + Copy( + pivot.state.supplyZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *item = tmp[i]; + + // + if (peakUpper == 0 || + peakUpper < item.Upper()) + { + peakUpper = item.Upper(); + } + + // + if (peakLower == 0 || + peakLower > item.Lower()) + { + peakLower = item.Lower(); + } + + // + if (!IsValid(peakFrom) || + peakFrom > item.From()) + { + peakFrom = item.From(); + } + + // + if (!IsValid(peakTo) || + peakTo < item.To()) + { + peakTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // Bearish Order Block ... + count = pivot.state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + XCOrderBlock *tmp[]; + Copy( + pivot.state.bearishOrderBlocks, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *item = tmp[i]; + + // + if (peakUpper == 0 || + peakUpper < item.Upper()) + { + peakUpper = item.Upper(); + } + + // + if (peakLower == 0 || + peakLower > item.Lower()) + { + peakLower = item.Lower(); + } + + // + if (!IsValid(peakFrom) || + peakFrom > item.From()) + { + peakFrom = item.From(); + } + + // + if (!IsValid(peakTo) || + peakTo < item.To()) + { + peakTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // Bearish Fair Value Gap ... + count = pivot.state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + XCFVG *tmp[]; + Copy( + pivot.state.bearishFairValueGaps, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCFVG *item = tmp[i]; + + // + if (peakUpper == 0 || + peakUpper < item.Upper()) + { + peakUpper = item.Upper(); + } + + // + if (peakLower == 0 || + peakLower > item.Lower()) + { + peakLower = item.Lower(); + } + + // + if (!IsValid(peakFrom) || + peakFrom > item.From()) + { + peakFrom = item.From(); + } + + // + if (!IsValid(peakTo) || + peakTo < item.To()) + { + peakTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // + // + + // + // Support ... + count = pivot.state.CountSupportZones(); + if (IsValidSize(count)) + { + // + XCSupportZone *tmp[]; + Copy( + pivot.state.supportZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *item = tmp[i]; + + // + if (valeUpper == 0 || + valeUpper < item.Upper()) + { + valeUpper = item.Upper(); + } + + // + if (valeLower == 0 || + valeLower > item.Lower()) + { + valeLower = item.Lower(); + } + + // + if (!IsValid(valeFrom) || + valeFrom > item.From()) + { + valeFrom = item.From(); + } + + // + if (!IsValid(valeTo) || + valeTo < item.To()) + { + valeTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // Demand ... + count = pivot.state.CountDemandZones(); + if (IsValidSize(count)) + { + // + XCDemandZone *tmp[]; + Copy( + pivot.state.demandZones, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *item = tmp[i]; + + // + if (valeUpper == 0 || + valeUpper < item.Upper()) + { + valeUpper = item.Upper(); + } + + // + if (valeLower == 0 || + valeLower > item.Lower()) + { + valeLower = item.Lower(); + } + + // + if (!IsValid(valeFrom) || + valeFrom > item.From()) + { + valeFrom = item.From(); + } + + // + if (!IsValid(valeTo) || + valeTo < item.To()) + { + valeTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // Bullish Order Block ... + count = pivot.state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + XCOrderBlock *tmp[]; + Copy( + pivot.state.bullishOrderBlocks, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *item = tmp[i]; + + // + if (valeUpper == 0 || + valeUpper < item.Upper()) + { + valeUpper = item.Upper(); + } + + // + if (valeLower == 0 || + valeLower > item.Lower()) + { + valeLower = item.Lower(); + } + + // + if (!IsValid(valeFrom) || + valeFrom > item.From()) + { + valeFrom = item.From(); + } + + // + if (!IsValid(valeTo) || + valeTo < item.To()) + { + valeTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + // Bullish Fair Value Gap ... + count = pivot.state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + XCFVG *tmp[]; + Copy( + pivot.state.bullishFairValueGaps, + tmp // + ); + + // + for (int i = 0; i < count; i++) + { + // + XCFVG *item = tmp[i]; + + // + if (valeUpper == 0 || + valeUpper < item.Upper()) + { + valeUpper = item.Upper(); + } + + // + if (valeLower == 0 || + valeLower > item.Lower()) + { + valeLower = item.Lower(); + } + + // + if (!IsValid(valeFrom) || + valeFrom > item.From()) + { + valeFrom = item.From(); + } + + // + if (!IsValid(valeTo) || + valeTo < item.To()) + { + valeTo = item.To(); + } + } + + // + ArrayFree(tmp); + } + + // + result = peakUpper > 0 && + peakLower > 0 && + valeUpper > 0 && + valeLower > 0 && + IsValid(peakTo) && + IsValid(valeTo) && + IsValid(peakFrom) && + IsValid(valeFrom) && + peakTo > peakFrom && + valeTo > valeFrom && + peakUpper > peakLower && + valeUpper > valeLower; + + // + return result; +} + +/** + * Detect Price Inside Zones ... + * + * @param state: XPOIState instance Reference ... + * @param bar: XOHCL instance Reference ... + * @param hasSupport: Boolean ... + * @param hasResistanceZone: Boolean ... + * @param hasSupplyZone: Boolean ... + * @param hasDemandZone: Boolean ... + * @param hasOrderBlock: Boolean ... + * @param hasFairValueGap: Boolean ... + * @return ( bool ) + */ +bool DetectPriceInsideZones( + XPOIState &state, + XOHCL &bar, + int &zonesCount, + bool &hasSupportZone, + XCSupportZone *&supportZone, + bool &hasResistanceZone, + XCResistanceZone *&resistanceZone, + bool &hasSupplyZone, + XCSupplyZone *&supplyZone, + bool &hasDemandZone, + XCDemandZone *&demandZone, + bool &hasOrderBlock, + XCOrderBlock *&orderBlock, + bool &hasFairValueGap, + XCFVG *&fairValueGap // +) +{ + // + bool result = false; + + // + zonesCount = 0; + + // + hasSupportZone = false; + hasResistanceZone = false; + hasSupplyZone = false; + hasDemandZone = false; + hasOrderBlock = false; + hasFairValueGap = false; + + // + supportZone = NULL; + resistanceZone = NULL; + supplyZone = NULL; + demandZone = NULL; + orderBlock = NULL; + fairValueGap = NULL; + + // + datetime cTime = TimeCurrent(); + + // + result = bar.IsValid() && + state.IsValid() && + state.HasChild(); + if (!result) + { + return result; + } + + // + int count = 0; + + // + // Support Zone ... + count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCSupportZone *iZone = state.supportZones[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + supportZone = iZone; + } + } + + // + hasSupportZone = supportZone != NULL && + supportZone.IsValid(); + if (hasSupportZone) + { + // + zonesCount++; + supportZone.To(cTime); + } + } + + // + // Resistance Zone ... + count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCResistanceZone *iZone = state.resistanceZones[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + resistanceZone = iZone; + } + } + + // + hasResistanceZone = resistanceZone != NULL && + resistanceZone.IsValid(); + if (hasResistanceZone) + { + // + zonesCount++; + resistanceZone.To(cTime); + } + } + + // + // Supply Zone ... + count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCSupplyZone *iZone = state.supplyZones[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + supplyZone = iZone; + } + } + + // + hasSupplyZone = supplyZone != NULL && + supplyZone.IsValid(); + if (hasSupplyZone) + { + // + zonesCount++; + supplyZone.To(cTime); + } + } + + // + // Demand Zone ... + count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCDemandZone *iZone = state.demandZones[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + demandZone = iZone; + } + } + + // + hasDemandZone = demandZone != NULL && + demandZone.IsValid(); + if (hasDemandZone) + { + // + zonesCount++; + demandZone.To(cTime); + } + } + + // + // OrderBlock ... + count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCOrderBlock *iZone = state.bullishOrderBlocks[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + orderBlock = iZone; + } + } + + // + hasOrderBlock = orderBlock != NULL && + orderBlock.IsValid(); + if (hasOrderBlock) + { + // + zonesCount++; + orderBlock.To(cTime); + } + } + if (!hasOrderBlock) + { + // + count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCOrderBlock *iZone = state.bearishOrderBlocks[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + orderBlock = iZone; + } + } + + // + hasOrderBlock = orderBlock != NULL && + orderBlock.IsValid(); + if (hasOrderBlock) + { + // + zonesCount++; + orderBlock.To(cTime); + } + } + } + + // + // Fair Value Gap ... + count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iZone = state.bullishFairValueGaps[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + fairValueGap = iZone; + } + } + + // + hasFairValueGap = fairValueGap != NULL && + fairValueGap.IsValid(); + if (hasFairValueGap) + { + // + zonesCount++; + fairValueGap.To(cTime); + } + } + if (!hasFairValueGap) + { + // + count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iZone = state.bearishFairValueGaps[i]; + + // + bool isValid = IsPriceInsideZone(bar, iZone); + if (isValid) + { + // + fairValueGap = iZone; + } + } + + // + hasFairValueGap = fairValueGap != NULL && + fairValueGap.IsValid(); + if (hasFairValueGap) + { + // + zonesCount++; + fairValueGap.To(cTime); + } + } + } + + // + result = + // + hasSupportZone || + hasResistanceZone || + hasSupplyZone || + hasDemandZone || + hasOrderBlock || + hasFairValueGap + // + ; + + // + return result; +} + +/** + * Detect Price Inside Zones ... + * + * @param state: XPOIState instance Reference ... + * @param price: Double ... + * @param hasSupport: Boolean ... + * @param hasResistanceZone: Boolean ... + * @param hasSupplyZone: Boolean ... + * @param hasDemandZone: Boolean ... + * @param hasOrderBlock: Boolean ... + * @param hasFairValueGap: Boolean ... + * @return ( bool ) + */ +bool DetectPriceInsideZones( + XPOIState &state, + double price, + int &zonesCount, + bool &hasSupportZone, + XCSupportZone *&supportZone, + bool &hasResistanceZone, + XCResistanceZone *&resistanceZone, + bool &hasSupplyZone, + XCSupplyZone *&supplyZone, + bool &hasDemandZone, + XCDemandZone *&demandZone, + bool &hasOrderBlock, + XCOrderBlock *&orderBlock, + bool &hasFairValueGap, + XCFVG *&fairValueGap // +) +{ + // + bool result = false; + + // + zonesCount = 0; + + // + hasSupportZone = false; + hasResistanceZone = false; + hasSupplyZone = false; + hasDemandZone = false; + hasOrderBlock = false; + hasFairValueGap = false; + + // + supportZone = NULL; + resistanceZone = NULL; + supplyZone = NULL; + demandZone = NULL; + orderBlock = NULL; + fairValueGap = NULL; + + // + datetime cTime = TimeCurrent(); + + // + result = price > 0 && + state.IsValid() && + state.HasChild(); + if (!result) + { + return result; + } + + // + int count = 0; + + // + // Support Zone ... + count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCSupportZone *iZone = state.supportZones[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + supportZone = iZone; + } + } + + // + hasSupportZone = supportZone != NULL && + supportZone.IsValid(); + if (hasSupportZone) + { + // + zonesCount++; + supportZone.To(cTime); + } + } + + // + // Resistance Zone ... + count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCResistanceZone *iZone = state.resistanceZones[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + resistanceZone = iZone; + } + } + + // + hasResistanceZone = resistanceZone != NULL && + resistanceZone.IsValid(); + if (hasResistanceZone) + { + // + zonesCount++; + resistanceZone.To(cTime); + } + } + + // + // Supply Zone ... + count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCSupplyZone *iZone = state.supplyZones[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + supplyZone = iZone; + } + } + + // + hasSupplyZone = supplyZone != NULL && + supplyZone.IsValid(); + if (hasSupplyZone) + { + // + zonesCount++; + supplyZone.To(cTime); + } + } + + // + // Demand Zone ... + count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCDemandZone *iZone = state.demandZones[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + demandZone = iZone; + } + } + + // + hasDemandZone = demandZone != NULL && + demandZone.IsValid(); + if (hasDemandZone) + { + // + zonesCount++; + demandZone.To(cTime); + } + } + + // + // OrderBlock ... + count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCOrderBlock *iZone = state.bullishOrderBlocks[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + orderBlock = iZone; + } + } + + // + hasOrderBlock = orderBlock != NULL && + orderBlock.IsValid(); + if (hasOrderBlock) + { + // + zonesCount++; + orderBlock.To(cTime); + } + } + if (!hasOrderBlock) + { + // + count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCOrderBlock *iZone = state.bearishOrderBlocks[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + orderBlock = iZone; + } + } + + // + hasOrderBlock = orderBlock != NULL && + orderBlock.IsValid(); + if (hasOrderBlock) + { + // + zonesCount++; + orderBlock.To(cTime); + } + } + } + + // + // Fair Value Gap ... + count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iZone = state.bullishFairValueGaps[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + fairValueGap = iZone; + } + } + + // + hasFairValueGap = fairValueGap != NULL && + fairValueGap.IsValid(); + if (hasFairValueGap) + { + // + zonesCount++; + fairValueGap.To(cTime); + } + } + if (!hasFairValueGap) + { + // + count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iZone = state.bearishFairValueGaps[i]; + + // + bool isValid = IsPriceInsideZone(price, iZone); + if (isValid) + { + // + fairValueGap = iZone; + } + } + + // + hasFairValueGap = fairValueGap != NULL && + fairValueGap.IsValid(); + if (hasFairValueGap) + { + // + zonesCount++; + fairValueGap.To(cTime); + } + } + } + + // + result = + // + hasSupportZone || + hasResistanceZone || + hasSupplyZone || + hasDemandZone || + hasOrderBlock || + hasFairValueGap + // + ; + + // + return result; +} + +bool CalculatePriceInsideZones( + XPriceZones &zone, + XPOIState &state, + double price // +) +{ + // + bool result = false; + + // + zone.Clean(); + + // + int zonesCount = 0; + bool hasSupplyZone = false; + bool hasDemandZone = false; + bool hasOrderBlock = false; + bool hasSupportZone = false; + bool hasFairValueGap = false; + bool hasResistanceZone = false; + + // + result = DetectPriceInsideZones( + state, + price, + zone.count, + hasSupportZone, + zone.supportZone, + hasResistanceZone, + zone.resistanceZone, + hasSupplyZone, + zone.supplyZone, + hasDemandZone, + zone.demandZone, + hasOrderBlock, + zone.orderBlock, + hasFairValueGap, + zone.fairValueGap // + ); + if (!result) + { + return result; + } + + // + zone.price = price; + + // + result = zone.IsValid(); + + // + return result; +} + +bool CalculatePriceInsideZones( + XPriceZones &zone, + XPOIState &state, + XOHCL &bar // +) +{ + // + bool result = false; + + // + zone.Clean(); + + // + int zonesCount = 0; + bool hasSupplyZone = false; + bool hasDemandZone = false; + bool hasOrderBlock = false; + bool hasSupportZone = false; + bool hasFairValueGap = false; + bool hasResistanceZone = false; + + // + result = DetectPriceInsideZones( + state, + bar, + zone.count, + hasSupportZone, + zone.supportZone, + hasResistanceZone, + zone.resistanceZone, + hasSupplyZone, + zone.supplyZone, + hasDemandZone, + zone.demandZone, + hasOrderBlock, + zone.orderBlock, + hasFairValueGap, + zone.fairValueGap // + ); + if (!result) + { + return result; + } + + // + zone.bar = bar; + + // + result = zone.IsValid(); + + // + return result; +} + +/** + * Calculate Zone by Providing Specified Data ... + * + * @param zones: XStateZone instance Reference ... + * @param source: XPOIState instance Reference ... + * @param upper: Double ... + * @param lower: Double ... + * @param from: DateTime ... + * + * @return ( bool ) + */ +bool CalculateStateZones( + XStateZones &zones, + XPOIState &source, + double upper, + double lower, + datetime from // +) +{ + // + bool result = false; + + // + zones.Clean(); + + // + datetime cTime = TimeCurrent(); + + // + result = + // + upper > 0 && + lower > 0 && + upper > lower && + IsValid(from) && + source.IsValid() && + source.HasChild() + // + ; + if (!result) + { + return result; + } + + // + int count = 0; + + // + // Support ... + count = source.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupportZone *iZone = source.supportZones[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.supportZones // + ); + } + } + } + + // + // Resistance ... + count = source.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCResistanceZone *iZone = source.resistanceZones[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.resistanceZones // + ); + } + } + } + + // + // Supply ... + count = source.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCSupplyZone *iZone = source.supplyZones[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.supplyZones // + ); + } + } + } + + // + // Demand ... + count = source.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCDemandZone *iZone = source.demandZones[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.demandZones // + ); + } + } + } + + // + // Bullish OrderBlocks ... + count = source.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = source.bullishOrderBlocks[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.bullishOrderBlocks // + ); + } + } + } + + // + // Bearish OrderBlocks ... + count = source.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iZone = source.bearishOrderBlocks[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.bearishOrderBlocks // + ); + } + } + } + + // + // Bullish FairValueGaps ... + count = source.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = source.bullishFairValueGaps[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.bullishFairValueGaps // + ); + } + } + } + + // + // Bearish FairValueGaps ... + count = source.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XCFVG *iZone = source.bearishFairValueGaps[i]; + + // + double iUpper = iZone.Upper(); + double iLower = iZone.Lower(); + datetime iFrom = iZone.From(); + + // + bool isAbove = iUpper > upper && + iLower <= upper; + + // + bool isInside = iUpper <= upper && + iLower >= lower; + + // + bool isBelow = iUpper >= lower && + iLower < lower; + + // + bool isValid = + // + iFrom > from && + (isAbove || + isBelow || + isInside) + // + ; + if (isValid) + { + // + iZone.To(cTime); + Add( + iZone, + zones.bearishFairValueGaps // + ); + } + } + } + + // + result = zones.IsValid(); + + // + return result; +} + +/** + * Add Value Change instance to Exists Collection if it's not Exists ... + * + * @param item: XValueChange instance Reference ... + * @param items: XValueChange instance Array Reference ... + * + * @return ( int ) + */ +int AddIfNotExists( + XValueChange &item, + XValueChange &items[] // +) +{ + // + int result = 0; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + bool canAdd = false; + int count = ArraySize(items); + if (!IsValidSize(count)) + { + canAdd = true; + } + else + { + // + XValueChange last; + bool hasItem = GetLastItem( + last, + items // + ); + if (!hasItem) + { + canAdd = true; + } + else + { + // + // Compare Last Item with Current ... + canAdd = item.time > last.time; + } + } + + // + // Add Item if Allowed ... + if (canAdd) + { + // + AddRef( + item, + items // + ); + } + + // + result = ArraySize(items); + + // + return result; +} + +/** + * Combine a Collection of States into dest ... + * + * @param dest: XPOIState instance ... + * @param source: XPOIState Collection ... + */ +void CombineStates( + XPOIState &dest, + XPOIState &source[] // +) +{ + // + dest.Clean(); + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XPOIState iState = source[i]; + + // + if (dest.ticksZone == NULL) + { + dest.ticksZone = iState.ticksZone; + } + + // + Copy( + iState.swingHighs, + dest.swingHighs, + false // + ); + + // + Copy( + iState.swingLows, + dest.swingLows, + false // + ); + + // + Copy( + iState.bullishMomentumBars, + dest.bullishMomentumBars, + false // + ); + + // + Copy( + iState.bearishMomentumBars, + dest.bearishMomentumBars, + false // + ); + + // + Copy( + iState.bullishRejectionBars, + dest.bullishRejectionBars, + false // + ); + + // + Copy( + iState.bearishRejectionBars, + dest.bearishRejectionBars, + false // + ); + + // + Copy( + iState.supportZones, + dest.supportZones, + false // + ); + + // + Copy( + iState.resistanceZones, + dest.resistanceZones, + false // + ); + + // + Copy( + iState.supplyZones, + dest.supplyZones, + false // + ); + + // + Copy( + iState.demandZones, + dest.demandZones, + false // + ); + + // + Copy( + iState.bullishOrderBlocks, + dest.bullishOrderBlocks, + false // + ); + + // + Copy( + iState.bearishOrderBlocks, + dest.bearishOrderBlocks, + false // + ); + + // + Copy( + iState.bullishFairValueGaps, + dest.bullishFairValueGaps, + false // + ); + + // + Copy( + iState.bearishFairValueGaps, + dest.bearishFairValueGaps, + false // + ); + + // + } +} + +/** + * Check Price Above Specified Zone ... + * + * @param bar: XOHCL instance Reference ... + * + * @return ( bool ) + */ +bool IsPriceAboveZone( + XOHCL &bar, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + zone != NULL && + bar.IsValid() && + zone.IsValidBoundary(); + if (!result) + { + return result; + } + + // + result = + // + bar.low > zone.Upper() + // + ; + + // + return result; +} + +/** + * Check Price Above Specified Zone ... + * + * @return ( bool ) + */ +bool IsPriceAboveZone( + double price, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + price > 0 && + zone != NULL && + zone.IsValidBoundary(); + if (!result) + { + return result; + } + + // + result = + // + price > zone.Upper() + // + ; + + // + return result; +} + +/** + * Check Price Below Specified Zone ... + * + * @param bar: XOHCL instance Reference ... + * + * @return ( bool ) + */ +bool IsPriceBelowZone( + XOHCL &bar, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + zone != NULL && + bar.IsValid() && + zone.IsValidBoundary(); + if (!result) + { + return result; + } + + // + result = + // + bar.high < zone.Lower() + // + ; + + // + return result; +} + +/** + * Check Price Below Specified Zone ... + * + * @return ( bool ) + */ +bool IsPriceBelowZone( + double price, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + price > 0 && + zone != NULL && + zone.IsValidBoundary(); + if (!result) + { + return result; + } + + // + result = + // + price < zone.Lower() + // + ; + + // + return result; +} + +/** + * Check Price Inside Specified Zone ... + * + * @param bar: XOHCL instance Reference ... + * + * @return ( bool ) + */ +bool IsPriceInsideZone( + XOHCL &bar, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + zone != NULL && + bar.IsValid() && + zone.IsValidBoundary(); + if (!result) + { + return result; + } + + // + result = + // + bar.low <= zone.Upper() + // + && + // + bar.low >= zone.Lower() + // + ; + + // + return result; +} +bool IsPriceInsideZone( + XOHCL &bar, + double upper, + double lower // +) +{ + // + bool result = false; + + // + result = + upper > 0 && + lower > 0 && + upper > lower && + bar.IsValid(); + if (!result) + { + return result; + } + + // + result = + // + bar.low <= upper + // + && + // + bar.low >= lower + // + ; + + // + return result; +} + +/** + * Check Price Inside Specified Zone ... + * + * @return ( bool ) + */ +bool IsPriceInsideZone( + double price, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + price > 0 && + zone != NULL && + zone.IsValidBoundary(); + if (!result) + { + return result; + } + + // + result = + // + price <= zone.Upper() + // + && + // + price >= zone.Lower() + // + ; + + // + return result; +} +bool IsPriceInsideZone( + double price, + double upper, + double lower // +) +{ + // + bool result = false; + + // + result = + price > 0 && + upper > 0 && + lower > 0 && + upper > lower; + if (!result) + { + return result; + } + + // + result = + // + price <= upper + // + && + // + price >= lower + // + ; + + // + return result; +} + +/** + * Calculate Target for Specified Direction ... + * + * @param bar: XOHCL instance Reference ... + * @param state: XPOIState instance Reference ... + * @param forDir: ENUM_S_DIRECTION member ... + * + * @return ( double ) + */ +double CalculateTarget( + XOHCL &bar, + XPOIState &state, + ENUM_X_DIRECTION forDir // +) +{ + // + double result = 0; + + // + if (!state.IsValid() || + !state.HasChild() || + !HasDirection(forDir)) + { + return result; + } + + // + XCFVG *iFVG = NULL; + XCOrderBlock *iOB = NULL; + XCSupplyZone *iSupply = NULL; + XCDemandZone *iDemand = NULL; + XCSupportZone *iSupport = NULL; + XCResistanceZone *iResistance = NULL; + + // + bool hasOB = false; + bool hasFVG = false; + bool hasSupply = false; + bool hasDemand = false; + bool hasSupport = false; + bool hasResistance = false; + + // + int count = 0; + + // + if (IsBearish(forDir)) + { + // + // FVG ... + count = state.CountBullishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iZone = state.bullishFairValueGaps[i]; + + // + bool isValid = IsPriceAboveZone( + bar, + iZone // + ); + if (isValid) + { + // + iFVG = iZone; + hasFVG = true; + break; + } + } + } + + // + // OB ... + count = state.CountBullishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCOrderBlock *iZone = state.bullishOrderBlocks[i]; + + // + bool isValid = IsPriceAboveZone( + bar, + iZone // + ); + if (isValid) + { + // + iOB = iZone; + hasOB = true; + break; + } + } + } + + // + // SUPPORT ... + count = state.CountSupportZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCSupportZone *iZone = state.supportZones[i]; + + // + bool isValid = IsPriceAboveZone( + bar, + iZone // + ); + if (isValid) + { + // + iSupport = iZone; + hasSupport = true; + break; + } + } + } + + // + // DEMAND ... + count = state.CountDemandZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCDemandZone *iZone = state.demandZones[i]; + + // + bool isValid = IsPriceAboveZone( + bar, + iZone // + ); + if (isValid) + { + // + iDemand = iZone; + hasDemand = true; + break; + } + } + } + + // + // Summary ... + result = + hasFVG + ? iFVG.Upper() + : hasOB + ? iOB.Upper() + : hasSupport + ? iSupport.Upper() + : hasDemand + ? iDemand.Upper() + : 0; + if (hasFVG) + { + result = MathMax(result, iFVG.Upper()); + } + if (hasOB) + { + result = MathMax(result, iOB.Upper()); + } + if (hasSupport) + { + result = MathMax(result, iSupport.Upper()); + } + if (hasDemand) + { + result = MathMax(result, iDemand.Upper()); + } + } + + // + if (IsBullish(forDir)) + { + // + // FVG ... + count = state.CountBearishFairValueGaps(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iZone = state.bearishFairValueGaps[i]; + + // + bool isValid = IsPriceBelowZone( + bar, + iZone // + ); + if (isValid) + { + // + iFVG = iZone; + hasFVG = true; + break; + } + } + } + + // + // OB ... + count = state.CountBearishOrderBlocks(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCOrderBlock *iZone = state.bearishOrderBlocks[i]; + + // + bool isValid = IsPriceBelowZone( + bar, + iZone // + ); + if (isValid) + { + // + iOB = iZone; + hasOB = true; + break; + } + } + } + + // + // RESISTANCE ... + count = state.CountResistanceZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCResistanceZone *iZone = state.resistanceZones[i]; + + // + bool isValid = IsPriceBelowZone( + bar, + iZone // + ); + if (isValid) + { + // + iResistance = iZone; + hasResistance = true; + break; + } + } + } + + // + // SUPPLY ... + count = state.CountSupplyZones(); + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCSupplyZone *iZone = state.supplyZones[i]; + + // + bool isValid = IsPriceBelowZone( + bar, + iZone // + ); + if (isValid) + { + // + iSupply = iZone; + hasSupply = true; + break; + } + } + } + + // + // Summary ... + result = + hasFVG + ? iFVG.Lower() + : hasOB + ? iOB.Lower() + : hasSupport + ? iSupport.Lower() + : hasDemand + ? iDemand.Lower() + : 0; + if (hasFVG) + { + result = MathMin(result, iFVG.Lower()); + } + if (hasOB) + { + result = MathMin(result, iOB.Lower()); + } + if (hasSupport) + { + result = MathMin(result, iSupport.Lower()); + } + if (hasDemand) + { + result = MathMin(result, iDemand.Lower()); + } + } + + // + return result; +} + +/** + * Detect Valid Order Blocks ... + * + * @param forDir: ENUM_X_DIRECTION member ... + * @param source: XPOIState instance Reference ... + * + * @return ( int ) + */ +int DetectDirectionOrderBlocks( + ENUM_X_DIRECTION forDir, + XPOIState &source, + XCOrderBlock *&orderBlocks[] // +) +{ + // + int result = 0; + + // + Clean(orderBlocks); + + // + bool isValid = + // + source.IsValid() && + source.HasChild() && + HasDirection(forDir) + // + ; + if (!isValid) + { + return result; + } + + // + datetime cTime = TimeCurrent(); + + // + XOHCL cBar; + bool isInited = cBar.Init( + source.symbol, + source.period, + 1 // + ); + if (!isInited) + { + return result; + } + + // + int count = 0; + + // + // Bullish ... + count = source.CountBullishOrderBlocks(); + isValid = IsValidSize(count) && + IsBullish(forDir); + if (isValid) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iOB = source.bullishOrderBlocks[i]; + + // + // Update Order Block Time ... + iOB.To(cTime); + + // + // Check Order Block Validation ... + isValid = IsValid( + iOB, + forDir, + cBar.symbol, + cBar.period // + ); + if (isValid) + { + // + Add( + iOB, + orderBlocks // + ); + } + } + } + + // + // Bearish ... + count = source.CountBearishOrderBlocks(); + isValid = IsValidSize(count) && + IsBearish(forDir); + if (isValid) + { + // + for (int i = 0; i < count; i++) + { + // + XCOrderBlock *iOB = source.bearishOrderBlocks[i]; + + // + // Update Order Block Time ... + iOB.To(cTime); + + // + // Check Order Block Validation ... + isValid = IsValid( + iOB, + forDir, + cBar.symbol, + cBar.period // + ); + if (isValid) + { + // + Add( + iOB, + orderBlocks // + ); + } + } + } + + // + result = ArraySize(orderBlocks); + + // + return result; +} + +/** + * Test Market for Detect Order Block FVG ... + * + * @param forDir: Direction + * @param bullishOrderBlocks: Detected Bullish Order Blocks ... + * @param bearishOrderBlocks: Detected Bearish Order Blocks ... + * @param orderBlockState: Order Block Detection POIState ... + * @param fairValueGapState: Fair Value Gap Detection POIState ... + * @param barIndex: Bar Index ... + * + * @return ( bool ) + */ +bool DetectFVGOB( + ENUM_X_DIRECTION &forDir, // Test For Specified Direction ... + XFVGOrderBlock &bullishOrderBlocks[], // Bullish Order Blocks ... + XFVGOrderBlock &bearishOrderBlocks[], // Bearish Order Blocks ... + XPOIState &orderBlockState, // Order Block Detection TF POI(s) ... + XPOIState &fairValueGapState, // Fair Value Gap Detection TF POI(s) ... + int barIndex = 0 // Bar Index ... +) +{ + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + forDir = X_DIRECTION_NONE; + + // + // Validate Args ... + result = + orderBlockState.HasChild() && + fairValueGapState.HasChild(); + if (!result) + { + return result; + } + + // + string symbol = orderBlockState.symbol; + ENUM_TIMEFRAMES period = orderBlockState.period; + + // + // Retrieve Bars ... + XOHCL triggerCBar; + result = triggerCBar.Init( + symbol, + period, + barIndex // + ); + + // + // Select Order Blocks Which Has Big Changes ... + int count = 0; + datetime cTime = TimeCurrent(); + + // + XOHCL jBar; + result = jBar.Init( + fairValueGapState.symbol, + fairValueGapState.period, + barIndex // + ); + if (!result) + { + return result; + } + double jBarLL = jBar.FindLowest(3, MODE_LOW); + double jBarHH = jBar.FindHighest(3, MODE_HIGH); + + // + // Bullish ... + int bullishOrderBlocksCount = orderBlockState.CountBullishOrderBlocks(); + count = bullishOrderBlocksCount; + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iFVG = NULL; + XStateZones iStateZones; + XCOrderBlock *iOb = orderBlockState.bullishOrderBlocks[i]; + iOb.To(cTime); + + // + // Find Exit Bar of Bullish OrderBlock Upper ... + XOHCL breakerBar; + bool hasBreakerBar = iOb.DetectBreakerBar(breakerBar); + if (!hasBreakerBar) + { + continue; + } + + // + // Detect Order Block is Hunted Or Not ... + XOHCL huntedBar; + bool isHunted = iOb.IsHunted(huntedBar); + if (isHunted) + { + continue; + } + + // + // Check Validation of Order Block ... + bool isValid = iOb.IsValidOrderBlock(); + if (!isValid) + { + continue; + } + + // + // Check Order Block Has Fair Value Gap ... + int fvgsCount = fairValueGapState.CountBullishFairValueGaps(); + bool hasFVG = IsValidSize(fvgsCount); + if (!hasFVG) + { + continue; + } + + // + // Detect an FVG for Order Block ... + for (int j = fvgsCount - 1; j >= 0; j--) + { + // + XCFVG *jFVG = fairValueGapState.bullishFairValueGaps[j]; + + // + bool isValid = + // + jFVG.IsBullish() && + jBarLL > jFVG.Upper() && + jBar.low > jFVG.Upper() && + jFVG.From() >= iOb.From() && + ((jFVG.Upper() > iOb.Upper() && + jFVG.Lower() <= iOb.Upper()) || + (jFVG.Upper() <= iOb.Upper() && + jFVG.Lower() >= iOb.Lower())) + // + ; + if (isValid) + { + // + jFVG.To(cTime); + iFVG = jFVG; + break; + } + } + + // + hasFVG = iFVG != NULL; + result = hasFVG; + if (!result) + { + continue; + } + + // // + // double upper = MathMax(iOb.Upper(), iFVG.Upper()); + // double lower = MathMin(iOb.Lower(), iFVG.Lower()); + // datetime from = iFVG.From(); + + // // + // // Detect Price Zones ... + // // Based On Decision State ... + // bool hasStateZones = CalculateStateZones( + // iStateZones, + // decisionState, + // upper, + // lower, + // from // + // ); + // result = hasStateZones; + // if (!result) + // { + // continue; + // } + + // + XFVGOrderBlock iModel; + iModel.orderBlock = iOb; + iModel.fairValueGap = iFVG; + // iModel.stateZones = iStateZones; + + // + AddRef( + iModel, + bullishOrderBlocks // + ); + } + } + + // + // Bearish ... + int bearishOrderBlocksCount = orderBlockState.CountBearishOrderBlocks(); + count = bearishOrderBlocksCount; + if (IsValidSize(count)) + { + // + for (int i = count - 1; i >= 0; i--) + { + // + XCFVG *iFVG = NULL; + XStateZones iStateZones; + XCOrderBlock *iOb = orderBlockState.bearishOrderBlocks[i]; + iOb.To(cTime); + + // + // Find Exit Bar of Bullish OrderBlock Upper ... + XOHCL breakerBar; + bool hasBreakerBar = iOb.DetectBreakerBar(breakerBar); + if (!hasBreakerBar) + { + continue; + } + + // + // Detect Order Block is Hunted Or Not ... + XOHCL huntedBar; + bool isHunted = iOb.IsHunted(huntedBar); + if (isHunted) + { + continue; + } + + // + // Check Validation of Order Block ... + bool isValid = iOb.IsValidOrderBlock(); + if (!isValid) + { + continue; + } + + // + // Check Order Block Has Fair Value Gap ... + int fvgsCount = fairValueGapState.CountBearishFairValueGaps(); + bool hasFVG = IsValidSize(fvgsCount); + if (!hasFVG) + { + continue; + } + + // + // Detect an FVG for Order Block ... + for (int j = fvgsCount - 1; j >= 0; j--) + { + // + XCFVG *jFVG = fairValueGapState.bearishFairValueGaps[j]; + + // + bool isValid = + // + jFVG.IsBearish() && + jBarHH < jFVG.Lower() && + jBar.high < jFVG.Lower() && + jFVG.From() >= iOb.From() && + ((jFVG.Upper() > iOb.Lower() && + jFVG.Lower() <= iOb.Lower()) || + (jFVG.Upper() <= iOb.Upper() && + jFVG.Lower() >= iOb.Lower())) + // + ; + if (isValid) + { + // + jFVG.To(cTime); + iFVG = jFVG; + break; + } + } + + // + hasFVG = iFVG != NULL; + result = hasFVG; + if (!result) + { + continue; + } + + // + double upper = MathMax(iOb.Upper(), iFVG.Upper()); + double lower = MathMin(iOb.Lower(), iFVG.Lower()); + datetime from = iFVG.From(); + + // // + // // Detect Price Zones ... + // // Based On Decision State ... + // bool hasStateZones = CalculateStateZones( + // iStateZones, + // decisionState, + // upper, + // lower, + // from // + // ); + // result = hasStateZones; + // if (!result) + // { + // continue; + // } + + // + XFVGOrderBlock iModel; + iModel.orderBlock = iOb; + iModel.fairValueGap = iFVG; + // iModel.stateZones = iStateZones; + + // + AddRef( + iModel, + bearishOrderBlocks // + ); + } + } + + // + // Check Order Blocks ... + bullishOrderBlocksCount = ArraySize(bullishOrderBlocks); + bool hasBullishOrderBlocks = IsValidSize(bullishOrderBlocksCount); + + // + // Check Order Blocks ... + bearishOrderBlocksCount = ArraySize(bearishOrderBlocks); + bool hasBearishOrderBlocks = IsValidSize(bearishOrderBlocksCount); + + // + result = + // + hasBullishOrderBlocks || + hasBearishOrderBlocks + // + ; + if (!result) + { + return result; + } + + // + bool isBullish = hasBullishOrderBlocks && !hasBearishOrderBlocks; + bool isBearish = hasBearishOrderBlocks && !hasBullishOrderBlocks; + + // + forDir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + + // + result = forDir != X_DIRECTION_NONE; + if (!result) + { + return result; + } + + // + return result; +} + +/** + * Detect a Zone Breaker Bar ... + * + * @param toBar: XOHCL instance Reference ... + * @param fromBar: XOHCL instance Reference ... + * @param breakerBar: XOHCL instance Reference ... + * @param forDir: ENUM_X_DIRECTION member ... + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + * + * @return ( bool ) + */ +bool HasBreakerBar( + XOHCL &toBar, + XOHCL &fromBar, + XOHCL &breakerBar, + ENUM_X_DIRECTION forDir, + string symbol, + ENUM_TIMEFRAMES period, + XCZone *zone // +) +{ + // + bool result = false; + + // + toBar.Clean(); + fromBar.Clean(); + breakerBar.Clean(); + + // + result = + // + zone != NULL && + IsValid(zone.To()) && + IsValid(zone.From()) && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + result = fromBar.Init( + symbol, + period, + zone.From() // + ); + if (!result) + { + return result; + } + + // + result = toBar.Init( + symbol, + period, + zone.To() // + ); + if (!result) + { + return result; + } + + // + int toIndex = toBar.Index(); + int fromIndex = fromBar.Index(); + + // + double upper = zone.Upper(); + double lower = zone.Lower(); + + // + // Detect Zone BreakerBar ... + for (int i = fromIndex; i >= toIndex; i--) + { + // + XOHCL iBar; + result = iBar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + continue; + } + + // + result = + // + IsBullish(forDir) + ? + // + iBar.low < upper && + iBar.high > upper && + iBar.GetUp() > upper + // + : + // + iBar.high > lower && + iBar.low < lower && + iBar.GetDown() < lower + // + ; + if (result) + { + // + breakerBar = iBar; + break; + } + } + + // + result = breakerBar.IsValid(); + + // + return result; +} + +/** + * Check a Zone is Valid for Specified Direction ... + * + * @param toBar: XOHCL instance Reference ... + * @param fromBar: XOHCL instance Reference ... + * @param breakerBar: XOHCL instance Reference ... + * @param forDir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ +bool IsValid( + XOHCL &toBar, + XOHCL &fromBar, + XOHCL &breakerBar, + ENUM_X_DIRECTION forDir, + XCZone *zone // +) +{ + // + bool result = false; + + // + result = + // + zone != NULL && + toBar.IsValid() && + fromBar.IsValid() && + breakerBar.IsValid() && + HasDirection(forDir) + // + ; + if (!result) + { + return result; + } + + // + int toIndex = toBar.Index(); + int fromIndex = fromBar.Index(); + int breakerIndex = breakerBar.Index(); + + // + double upper = zone.Upper(); + double lower = zone.Lower(); + + // + bool isBreaked = false; + for (int i = breakerIndex - 1; i >= toIndex; i--) + { + // + XOHCL iBar; + result = iBar.Init( + fromBar.symbol, + fromBar.period, + i // + ); + + // + if (!result) + { + continue; + } + + // + isBreaked = + // + IsBullish(forDir) + // + ? + // + iBar.low < upper + // + : + // + iBar.high > lower + // + ; + if (isBreaked) + { + break; + } + } + + // + result = !isBreaked; + + // + return result; +} + +/** + * Validate Specified Order Block ... + * + * @param forDir: ENUM_X_DIRECTION member ... + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + * + * @return ( bool ) + */ +bool IsValid( + XCOrderBlock *orderBlock, + ENUM_X_DIRECTION forDir, + string symbol, + ENUM_TIMEFRAMES period // +) +{ + // + bool result = false; + + // + result = + // + IsValid(symbol) && + IsValid(period) && + orderBlock != NULL && + HasDirection(forDir) && + orderBlock.IsValid() + // + ; + if (!result) + { + return result; + } + + // + XOHCL toBar; + XOHCL fromBar; + XOHCL breakerBar; + result = HasBreakerBar( + toBar, + fromBar, + breakerBar, + forDir, + symbol, + period, + (XCZone *)orderBlock // + ); + if (!result) + { + return result; + } + + // + // Validate Zone Touch ... + result = IsValid( + toBar, + fromBar, + breakerBar, + forDir, + (XCZone *)orderBlock // + ); + + // + return result; +} + +/** + * Get Oldest Zone ... + * + * @return ( int ) + */ +int GetOldest( + XCZone *&source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XCZone *oldest = NULL; + for (int i = 0; i < count; i++) + { + // + XCZone *iZone = source[i]; + + // + bool canSet = + oldest == NULL || + (oldest != NULL && + oldest.From() > iZone.From()); + if (canSet) + { + // + result = i; + oldest = iZone; + } + } + + // + return result; +} + +/** + * Get Youngest Zone ... + * + * @return ( int ) + */ +int GetYoungest( + XCZone *&source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XCZone *youngest = NULL; + for (int i = 0; i < count; i++) + { + // + XCZone *iZone = source[i]; + + // + bool canSet = + youngest == NULL || + (youngest != NULL && + youngest.From() < iZone.From()); + if (canSet) + { + // + result = i; + youngest = iZone; + } + } + + // + return result; +} + +template +bool ToZone( + T *&source[], + XCZone *&dest[] // +) +{ + // + bool result = false; + + // + Clean(dest); + + // + int count = ArraySize(source); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T *item = source[i]; + + // + if (item != NULL) + { + // + Add( + (XCZone *)item, + dest // + ); + } + } + + // + int destCount = ArraySize(dest); + result = IsValidSize(destCount); + + // + return result; +} + +// +typedef void (*TOnPOIEvent)(ENUM_XPOI_EVENTS event, + XCBasePOI *param // +); + +// \ No newline at end of file diff --git a/BKPS/14031106/Libraries/x-saherelm.x-trade.lib.mq5 b/BKPS/14031106/Libraries/x-saherelm.x-trade.lib.mq5 new file mode 100644 index 0000000..e3bd0fe --- /dev/null +++ b/BKPS/14031106/Libraries/x-saherelm.x-trade.lib.mq5 @@ -0,0 +1,6032 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XTradeLib +// Description: All models related to Trade ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" +#include + +// +// Definitions ... + +// +// a List of Used Tokens ... + +// +// Common ... +string XIDToken = "ID"; +string XTicketToken = "TK"; +string XModeToken = "MD"; +string XTypeToken = "TY"; +string XPeriodToken = "PR"; +string XProviderToken = "PRV"; +string XProfitToken = "PF"; + +// +string XTPToken = "TP"; +string XSLToken = "SL"; +string XTimeToken = "TM"; +string XEntryToken = "EN"; +string XVolumeToken = "VL"; +string XSymbolToken = "SMBL"; + +// +string XSupportToken = "SP"; +string XEQMSupportToken = "EQM"; +string XEQPToken = "EQP"; + +// +string XSLTrailToken = "SLT"; + +// +string XActionToken = "A"; + +// +string XDirectionalToken = "D"; +string XINDirectionalToken = "IND"; + +// +string XRecoveryToken = "XRCV"; + +// +// Available Order Modes ... +enum ENUM_X_ORDER_MODES +{ + X_ORDER_MODE_NOTHING, // Nothing + X_ORDER_MODE_MARKET, // Market Order + X_ORDER_MODE_STOP, // Pending Stop Order + X_ORDER_MODE_LIMIT, // Pending Limit Order + X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order +}; + +// +string ToString(ENUM_X_ORDER_MODES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_ORDER_MODE_MARKET: + result = "Market"; + break; + + // + case X_ORDER_MODE_LIMIT: + result = "Limit"; + break; + + // + case X_ORDER_MODE_STOP: + result = "Stop"; + break; + + // + case X_ORDER_MODE_STOP_LIMIT: + result = "StopLimit"; + break; + } + + // + return result; +} + +// +// Select Positions Type ... +enum ENUM_X_POSITION_SELECT_METHODS +{ + X_POSITION_SELECT_NONE, // None + X_POSITION_SELECT_MAX, // Max + X_POSITION_SELECT_MIN, // Min + X_POSITION_SELECT_BOTH, // Min and Max + X_POSITION_SELECT_ALL, // All +}; + +// +// Signal Execution Result ... +// note that some of them must be handles in +// EA's ... +enum ENUM_X_SIGNAL_EXECUTION_RESULT +{ + // + X_SIGNAL_EXECUTION_UNKNOWN, // Unknown + X_SIGNAL_EXECUTION_SUCCEED, // Succed + X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed + X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type + X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade + X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error + X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR, // Prev Profit Error + X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached + X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED, // Same Positions Delay Not Passed + X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params +}; + +// +// Available Guard Action ... +enum ENUM_X_GUARD_ACTIONS +{ + X_GUARD_ACTION_NOTHING, // Nothing + X_GUARD_ACTION_HEDGE, // Hedge + X_GUARD_PARTIAL_CLOSE, // Partial Close + X_GUARD_ACTION_TRAIL_STOP, // Trail StopLoss + X_GUARD_ACTION_FORCE_CLOSE, // Force Close + X_GUARD_ACTION_ADD_SUPPORT_SIGNAL, // Add Support Signal + X_GUARD_ACTION_CANCEL_PENDING_ORDERS, // Cancel Pending Orders +}; + +// +enum ENUM_X_POSITION_TYPES +{ + X_POSITION_TYPE_NONE = 0, + X_POSITION_TYPE_ALL = 1, + X_POSITION_TYPE_LONG = 2, + X_POSITION_TYPE_SHORT = 3, +}; + +// +string ToString(ENUM_X_POSITION_TYPES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_POSITION_TYPE_ALL: + result = "All"; + break; + + // + case X_POSITION_TYPE_NONE: + result = "NONE"; + break; + + // + case X_POSITION_TYPE_SHORT: + result = "Short"; + break; + + // + case X_POSITION_TYPE_LONG: + result = "Long"; + break; + } + + // + return result; +} + +// +bool IsLong(ENUM_X_POSITION_TYPES value) +{ + return value == X_POSITION_TYPE_LONG; +} + +// +bool ToPositionType( + ENUM_POSITION_TYPE &dest, + ENUM_X_POSITION_TYPES source // +) +{ + // + bool result = false; + + // + result = source == X_POSITION_TYPE_LONG || + source == X_POSITION_TYPE_SHORT; + if (!result) + { + return result; + } + + // + dest = + source == X_POSITION_TYPE_LONG + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + return result; +} + +// +ENUM_X_POSITION_TYPES ToPositionType(ENUM_POSITION_TYPE value) +{ + return IsLong(value) + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; +} + +// +ENUM_X_POSITION_TYPES GetOppositPositionType(ENUM_POSITION_TYPE type) +{ + // + ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE; + + // + bool isLong = IsLong(type); + bool isShort = IsShort(type); + + // + result = + // + isLong + ? X_POSITION_TYPE_SHORT + : isShort + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_NONE + // + ; + + // + return result; +} + +// +ENUM_X_DIRECTION ToDirection(ENUM_POSITION_TYPE value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + result = IsLong(value) + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +ENUM_X_DIRECTION ToDirection(ENUM_X_POSITION_TYPES value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + result = value == X_POSITION_TYPE_ALL + ? X_DIRECTION_ALL + : value == X_POSITION_TYPE_LONG + ? X_DIRECTION_BULLISH + : value == X_POSITION_TYPE_SHORT + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + + // + return result; +} + +// +// Structs ... + +// +// Model an Open Position ... +struct XPosition +{ + // + // Props ... + + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Sifnal Provider ... + string provider; + + // + // Position Comment ... + string comment; + + // + // Constructor ... + XPosition() + { + Clean(); + } + + // + // Initializers ... + + bool ByIndex(int index) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + ulong mTicket = mPositionInfo.Ticket(); + + // + result = ByTicket(mTicket); + + // + return result; + } + + bool ByTicket(ulong mTicket) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByTicket(mTicket); + if (!result) + { + return result; + } + + // + swap = mPositionInfo.Swap(); + magic = mPositionInfo.Magic(); + openAt = mPositionInfo.Time(); + sl = mPositionInfo.StopLoss(); + ticket = mPositionInfo.Ticket(); + symbol = mPositionInfo.Symbol(); + tp = mPositionInfo.TakeProfit(); + profit = mPositionInfo.Profit(); + volume = mPositionInfo.Volume(); + comment = mPositionInfo.Comment(); + entry = mPositionInfo.PriceOpen(); + type = mPositionInfo.PositionType(); + price = mPositionInfo.PriceCurrent(); + commission = mPositionInfo.Commission(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + magic = 0; + ticket = 0; + tp = 0; + sl = 0; + swap = 0; + entry = 0; + price = 0; + profit = 0; + volume = 0; + openAt = 0; + commission = 0; + + // + type = NULL; + period = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) + // + ; + + // + return result; + } + + // + // Retrieve Entry Price ... + double GetEntry() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetEntry( + symbol, + type + // + ); + + // + return result; + } + + // + // Retrieve Exit ... + double GetExit() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetExit( + symbol, + type + // + ); + + // + return result; + } + + // + // Get Spread by Point ... + double GetSpread() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = PriceToPoint(GetSpread(symbol)); + + // + return result; + } + + // + double GetPointsValue() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetPoints(symbol); + + // + return result; + } + + // + double GetProfitInPoint() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); // Tick size + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // Tick value + double pointSize = SymbolInfoDouble(symbol, SYMBOL_POINT); // Point size + double pointValue = tickValue * pointSize / tickSize; // Point value + + // + result = profit / (volume * tickValue); + + // + return result; + } + + // + // Find Risk ... + double GetRisk() + { + // + double result = 0; + + // + if (!IsValid()) + { + return 0; + } + + // + result = MathAbs(entry - sl); + + // + return result; + } + + // + // Find Reward ... + double GetReward() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathAbs(tp - entry); + + // + return result; + } + + // + double GetRewardInPoint() + { + // + double result = 0; + + // + result = GetReward() / GetPoints(); + + // + return result; + } + + // + // Find Risk Reward Ratio ... + double GetRiskRewardRatio() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetReward() / GetRisk(); + + // + return result; + } + + // + // Calculate TP Levels ... + int CalculateTPLevels(double &tps[]) + { + + // + int result = 0; + + // + Clean(tps); + + // + bool isValid = IsValid(); + if (!isValid) + { + return result; + } + + // + double risk = GetRisk(); + int r2r = (int)GetRiskRewardRatio(); + bool isLong = IsLong(type); + for (int i = 0; i < r2r; i++) + { + // + double iValue = + isLong + ? entry + risk + (i * risk) + : entry - risk - (i * risk); + // + Add( + iValue, + tps // + ); + } + + // + result = ArraySize(tps); + + // + return result; + } + + // + // Calculate Reached TP Levels ... + void CalculateReahedTP( + double &reachedLevel, + double &reachedPrice // + ) + { + // + reachedLevel = -1; + reachedPrice = 0; + double tps[]; + bool isLong = IsLong(type); + double exitPrice = GetExit(); + int tpLevels = CalculateTPLevels(tps); + if (!IsValidSize(tpLevels) || exitPrice <= 0) + { + return; + } + + // + for (int i = 0; i < tpLevels - 1; i++) + { + // + double cTP = tps[i]; + double nTP = tps[i + 1]; + + // + bool isReached = + isLong + ? exitPrice > cTP && + exitPrice < nTP + : exitPrice < cTP && + exitPrice > nTP; + if (isReached) + { + // + reachedLevel = i + 1; + reachedPrice = cTP; + } + } + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XPosition &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XPosition &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell) + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Signal ... +struct XSignal +{ + // + // Props ... + + // + ulong positionId; // if Executed this filled ... + + // + datetime time; // Issue Time ... + + // + double tp; // Take Profit ... + double sl; // Stop Loss ... + double entry; // Exntry or Execution Price ... + double volume; // Position Volume ... + + // + string symbol; // Trading Symbol ... + string comment; // Comment ... + string provider; // Signaller ... + + // + ENUM_TIMEFRAMES period; // Trading TimeFrame ... + ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ... + ENUM_X_ORDER_MODES mode; // Execution Mode ... + + // + XSignal supports[]; // a Collecion of Support Signals ... + + // + int pushers; // Signal Pushers ... + string conditions; // Signal Conditions ... + + // + // Additional ... + + // + // TP ... + double fullTPLevel; // Full TP ... + double partialCloseMultiplier; // Amount of Partial Close ... + double partialCloseOnTPLevel; // Do Partial Close on TP Level ... + + // + // RF ... + double tpLevelForBreakEven; // TP Level for Break Even ... + bool riskFreeOnBreakEven; // Risk Free Signal On Break Even ... + + // + // Traget ... + double target; // Force Risk Free On Target ... + + // + // SL Trail ... + bool trailSL; // Do SL Trail ... + double trailSLStartOnReachTPLevel; // Start SL Trail After Reached TP Level ... + + // + // Constructor ... + XSignal() + { + Clean(); + } + + // + bool Prepare( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell) + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + bool result = false; + + // + result = + // + IsValid(mMode) && + IsValid(mSymbol) && + IsValid(mPeriod) && + NotEmpty(mEntry) && + NotEmpty(mVolume) && + IsValid(mProvider) + // + ; + if (!result) + { + return result; + } + + // + if (mTP < 0) + { + mTP = 0; + } + + // + if (mSL < 0) + { + mSL = 0; + } + + // + type = mType; + mode = mMode; + symbol = mSymbol; + period = mPeriod; + provider = mProvider; + + // + // Normalization Values ... + sl = NormalizePrice(mSL, mSymbol); + tp = NormalizePrice(mTP, mSymbol); + mEntry = NormalizePrice(mEntry, mSymbol); + mVolume = NormalizeVolume(mVolume, mSymbol); + + // + entry = mEntry; + volume = mVolume; + + // + result = Normalize(); + + // + return result; + } + + // + bool PrepareComplex( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell) + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + // + // TP ... + double mFullTPLevel = 0, // Full TP Level + double mPartialCloseOnTPLevel = 0, // Partial Close On TP Level + double mPartialCloseMultiplier = 0, // Partial Close Multiplier + // + // RF ... + bool mRiskFreeOnBreakEven = false, // Risk Free Signal On Break Even ... + double mTpLevelForBreakEven = 0, // TP Level for Break Even ... + // + // SL Trail ... + bool mTrailSL = false, // Trail SL + double mTrailSLStartOnReachTPLevel = 0 // Trail SL Starts after Reached TP Level + ) + { + // + bool result = false; + + // + // Validate Args ... + result = + // + // Common ... + mSL > 0 && + mEntry > 0 && + mVolume > 0 && + IsValid(mSymbol) && + IsValid(mPeriod) && + IsValid(mProvider) && + mMode != X_ORDER_MODE_NOTHING + // + && + // + // TP ... + mFullTPLevel > 0 + // + ; + if (!result) + { + return result; + } + + // + // Prepare Regular Signal Values ... + double _risk = MathAbs(mEntry - mSL); + double _reward = _risk * mFullTPLevel; + + // + bool isLong = IsLong(mType); + + // + sl = mSL; + type = mType; + mode = mMode; + entry = mEntry; + symbol = mSymbol; + period = mPeriod; + volume = mVolume; + provider = mProvider; + fullTPLevel = mFullTPLevel; + tp = isLong + ? mEntry + _reward + : mEntry - _reward; + + // + result = Normalize(); + if (!result) + { + return result; + } + + // + // Calculate Other Conditions ... + + // + bool canPartialClose = + // + mPartialCloseOnTPLevel > 0 && + mPartialCloseMultiplier > 0 && + mPartialCloseOnTPLevel < mFullTPLevel + // + ; + if (canPartialClose) + { + // + partialCloseOnTPLevel = mPartialCloseOnTPLevel; + partialCloseMultiplier = mPartialCloseMultiplier; + } + + // + bool canRFOnBEP = + // + mRiskFreeOnBreakEven && + mTpLevelForBreakEven > 0 + // + ; + if (canRFOnBEP) + { + // + riskFreeOnBreakEven = mRiskFreeOnBreakEven; + tpLevelForBreakEven = mTpLevelForBreakEven; + } + + // + bool canTrailSL = + // + mTrailSL && + mTrailSLStartOnReachTPLevel > 0 && + mTrailSLStartOnReachTPLevel < mFullTPLevel + // + ; + if (canTrailSL) + { + // + trailSL = mTrailSL; + trailSLStartOnReachTPLevel = mTrailSLStartOnReachTPLevel; + } + + // + result = IsValid(); + + // + return result; + } + + // + bool PrepareLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + mMode, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + mMode, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Market Mode ... + + // + bool PrepareMarketLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareLong( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareMarketShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareShort( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Stop Mode ... + + // + bool PrepareStopLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareLong( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareStopShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareShort( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Limit Mode ... + + // + bool PrepareLimitLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareLong( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + bool PrepareLimitShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double mSL = 0, // Stop Loss + double mTP = 0 // Take Profit + ) + { + // + return PrepareShort( + mSymbol, + mProvider, + mPeriod, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + mSL, + mTP + // + ); + } + + // + // Generate Opposit Direction ... + bool GenerateOpposit( + XSignal &mSignal // Oppsoit Signal + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + ENUM_POSITION_TYPE mType = GetOpposit(this.type); + double mEntry = GetExit(this.symbol, mType); + + // + bool isLong = IsLong(mType); + + // + // Calculate Risk Reward Ratio ... + double risk = GetRisk(); + double reward = GetReward(); + + // + double mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + double mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + result = mSignal.Prepare( + this.symbol, + this.provider, + this.period, + mType, + this.mode, + mEntry, + this.volume, + mSL, + mTP // + ); + + // + return result; + } + + // + // Prepare Opposit Signal based On a Position ... + bool PrepareOpposit( + XPosition &source // Source Data + ) + { + // + bool result = false; + + // + ENUM_POSITION_TYPE mType = GetOpposit(source.type); + double mEntry = GetEntry(source.symbol, mType); + + // + bool isLong = IsLong(mType); + + // + double risk = source.GetRisk(); + double reward = source.GetReward(); + + // + double mSL = isLong + ? mEntry - risk + : mEntry + risk; + + // + double mTP = isLong + ? mEntry + reward + : mEntry - reward; + + // + return Prepare( + source.symbol, + source.provider, + source.period, + mType, + X_ORDER_MODE_MARKET, + mEntry, + source.volume, + mSL, + mTP // + ); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + entry = 0; + volume = 0; + pushers = 0; + positionId = 0; + + // + time = NULL; + type = NULL; + mode = NULL; + symbol = NULL; + period = NULL; + comment = NULL; + provider = NULL; + conditions = NULL; + + // + target = 0; + + // + trailSL = false; + riskFreeOnBreakEven = false; + + // + fullTPLevel = 0; + tpLevelForBreakEven = 0; + partialCloseOnTPLevel = 0; + partialCloseMultiplier = 0; + trailSLStartOnReachTPLevel = 0; + + // + Clean(supports); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(period) && + IsValid(symbol) && + NotEmpty(volume) && + NotEmpty(entry) + // + ; + + // + if (!result) + { + return result; + } + + // + return result; + } + + // + // DO All Calculations and Normalizations ... + bool Normalize() + { + // + bool result = false; + + // + // Normalizations ... + symbol = NormalizeSymbol(symbol); + period = NormalizePeriod(period); + + // + time = NormalizeTime(time); + + // + sl = NormalizePrice(sl, symbol); + tp = NormalizePrice(tp, symbol); + entry = NormalizePrice(entry, symbol); + volume = NormalizeVolume(volume, symbol); + + // + result = IsValid(); + + // + return result; + } + + // + // Check Signal Executed or not ... + bool IsExecuted() + { + // + bool result = false; + + // + result = + // + IsValid() && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Generate Comment for Signal ... + string GenerateComment() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (IsValid(provider)) + { + // + // Generate Provider Tag ... + result += GenerateProviderTag(provider); + } + + // + if (IsValid(period)) + { + // + // Generate Period Tag ... + result += GeneratePeriodTag(period); + } + + // + return result; + } + + // + int GetAge() + { + // + return GetAge( + this, + this.period // + ); + } + + // + // Find Risk ... + double GetRisk() + { + // + double result = 0; + + // + if (!IsValid()) + { + return 0; + } + + // + result = MathAbs(entry - sl); + + // + return result; + } + + // + // Find Reward ... + double GetReward() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathAbs(tp - entry); + + // + return result; + } + + // + // Find Risk Reward Ratio ... + double GetRiskRewardRatio() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetReward() / GetRisk(); + + // + return result; + } + + // + // Check Can Partial Close on Specified TP Level ... + bool CanPartialClose() + { + // + bool result = false; + + // + result = + IsValid() && + fullTPLevel > 0 && + partialCloseOnTPLevel > 0 && + partialCloseMultiplier > 0 && + partialCloseOnTPLevel < fullTPLevel; + + // + return result; + } + + // + // Check Can Risk Free On Break Even Point ... + bool CanRiskFreeOnBreakEvenPoint() + { + // + bool result = false; + + // + result = + IsValid() && + riskFreeOnBreakEven && + tpLevelForBreakEven > 0; + + // + return result; + } + + // + // Check Can Trail SL ... + bool CanTrailSL() + { + // + bool result = false; + + // + result = + IsValid() && + trailSL && + fullTPLevel > 0 && + trailSLStartOnReachTPLevel > 0 && + trailSLStartOnReachTPLevel < fullTPLevel; + + // + return result; + } + + // + string GetTag() + { + // + string result = NULL; + + // + result = "XSignal_" + + symbol + "_" + + ToString(period) + "_" + + ToString(type) + "_" + + ToString(sl) + "_" + + ToString(tp) + "_" + + ToString(entry); + + // + return result; + } + + // + // Retrieve String Representation of Signal ... + string ToString() + { + // + string result = NULL; + + // + result = + // + ToString("Symbol", symbol) + + ToString("Period", period) + + ToString("Provider", provider) + + ToString("Type", type) + + ToString("Mode", mode) + + ToString("Volume", volume) + + ToString("Entry", entry) + + ToString("TP", tp) + + ToString("SL", sl) + + ToString("Time", time) + + ToString("Comment", comment) + + // + "" + // + ; + + // + return result; + } +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long positionId; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string symbol; + + // + // Signal Provider ... + string provider; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOrder() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static COrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Retrieve Specific History Order ... + bool HistoryByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static CHistoryOrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + tp = 0; + sl = 0; + magic = 0; + ticket = 0; + positionId = 0; + openPrice = 0; + currentPrice = 0; + initialVolume = 0; + currentVolume = 0; + stopLimitPrice = 0; + + // + setupAt = NULL; + expiredAt = NULL; + executedAt = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + state = NULL; + period = NULL; + filling = NULL; + lifetime = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XOrder &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + state == value.state && + magic == value.magic && + ticket == value.ticket && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XOrder &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell) + ENUM_ORDER_STATE mState = NULL, // Order State + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // State Filter ... + IsStateFilterPassed( + mState, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + string provider; + + // + ENUM_TIMEFRAMES period; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; + + // + // Constructor ... + XDeal() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Deal Index + ) + { + // + bool result = false; + + // + int dealsCount = HistoryDealsTotal(); + result = dealsCount > 0; + if (!result) + { + return result; + } + + // + static CDealInfo mDealInfo; + + // + result = mDealInfo.SelectByIndex(index); + if (!result) + { + // + return result; + } + + // + // Reading Order Info ... + swap = mDealInfo.Swap(); + magic = mDealInfo.Magic(); + order = mDealInfo.Order(); + ticket = mDealInfo.Ticket(); + time = mDealInfo.Time(); + price = mDealInfo.Price(); + symbol = mDealInfo.Symbol(); + profit = mDealInfo.Profit(); + volume = mDealInfo.Volume(); + comment = mDealInfo.Comment(); + positionId = mDealInfo.PositionId(); + entry = mDealInfo.Entry(); + commission = mDealInfo.Commission(); + type = mDealInfo.DealType(); + reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + magic = 0; + positionId = 0; + ticket = 0; + order = 0; + time = 0; + price = 0; + profit = 0; + swap = 0; + commission = 0; + volume = 0; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + entry = NULL; + period = NULL; + reason = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XDeal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + reason == value.reason && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XDeal &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_DEAL_TYPE mType = NULL, // Deal Type + ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry + ENUM_DEAL_REASON mReason = NULL, // Deal Reason + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Entry Filter ... + IsEntryFilterPassed( + mEntry, + this + // + ) + // + && + // + // Reason Filter ... + IsReasonFilterPassed( + mReason, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; + + // + // Constructor ... + XOnTradeHandlerState() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + hasNewDeal = false; + hasNewOrder = false; + hasNewPosition = false; + hasNewHistoryOrder = false; + + // + newDeals = 0; + newOrders = 0; + newPositions = 0; + newHistoryOrders = 0; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ( + // + hasNewDeal + ? newDeals > 0 + : true + // + ) + // + && + // + ( + // + hasNewOrder + ? newOrders > 0 + : true + // + ) + // + && + // + ( + // + hasNewPosition + ? newPositions > 0 + : true + // + ) + // + && + // + ( + // + hasNewHistoryOrder + ? newHistoryOrders > 0 + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// Model Guard Info ... +struct XGuard +{ + // + string symbol; // Trading Symbol ... + string provider; // Signal Provider ... + ENUM_TIMEFRAMES period; // Trading Timeframe ... + ENUM_X_POSITION_TYPES type; // Position Type ... + ENUM_X_GUARD_ACTIONS action; // Which Action to Do ... + + // + double dblPayLoad; + string strPayload; + + // + // Constructor ... + XGuard() + { + Clean(); + } + + // + // Initialize ... + + // + // Global Initializer ... + bool Init( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Timeframe ... + ENUM_X_GUARD_ACTIONS mAction, // Which Action to Do ... + ENUM_X_POSITION_TYPES mType = NULL, // Position Type ... + string mProvider = NULL, // Signal Provider ... + double mDblPayLoad = NULL, + string mStrPayload = NULL // + ) + { + // + type = mType; + symbol = mSymbol; + period = mPeriod; + action = mAction; + provider = mProvider; + dblPayLoad = mDblPayLoad; + strPayload = mStrPayload; + + // + bool result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + provider = NULL; + period = NULL; + action = X_GUARD_ACTION_NOTHING; + + // + strPayload = NULL; + dblPayLoad = EMPTY_VALUE; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + action != X_GUARD_ACTION_NOTHING + // + ; + + // + return result; + } +}; + +// +// Model a Position with all of it's Supports ... +struct XPositionPack +{ + // + ulong ticket; // Main Position's Ticket + + // + XPosition position; // Main Position (if Exists) + + // + int supportOrdersCount; // Supported Orders (Untriggered) + int supportPositionsCount; // Supported Positions + + // + XOrder supportOrders[]; // Supported Orders (Untriggered) + XPosition supportPositions[]; // Supported Positions + + // + // Constructor ... + XPositionPack() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + + // + position.Clean(); + + // + supportOrdersCount = 0; + supportPositionsCount = 0; + + // + Clean(supportOrders); + Clean(supportPositions); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + NotEmpty(ticket) && + ( + // + supportOrdersCount > 0 + ? ArraySize(supportOrders) == supportOrdersCount + : true + // + ) + // + && + // + ( + // + supportPositionsCount > 0 + ? ArraySize(supportPositions) == supportPositionsCount + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// Check Position SL Trails Structure ... +struct XTrail +{ + // + ulong ticket; // Position Ticket ... + ENUM_POSITION_TYPE type; // Type ... + datetime time; // Trail Time ... + double before; // SL Value Before Trailing ... + double after; // SL Value After Trailing ... + int level; // Number of Trails SL ... + double profit; // Profit in SL Time ... + + // + // Constructor ... + XTrail() + { + Clean(); + } + + // + // Tools ... + + // + bool Init( + ulong mTicket, // Ticket + ENUM_POSITION_TYPE mType, // Type + double mProfit, // Profit + double mBefore, // Before + double mAfter // After + ) + { + // + Clean(); + + // + type = mType; + after = mAfter; + ticket = mTicket; + before = mBefore; + profit = mProfit; + + // + level++; + + // + time = TimeCurrent(); + + // + return IsValid(); + } + + // + bool Update( + double mSl, // new SL ... + double mProfit // Profit + ) + { + // + bool result = false; + + // + time = TimeCurrent(); + + // + double cAfter = after; + after = mSl; + before = cAfter; + profit = mProfit; + + // + level++; + + // + result = IsValid(); + + // + return result; + } + + // + string GenerateTag() + { + // + string result = NULL; + + // + string ticketLevelStr = ToString(ticket) + "," + ToString(level); + + // + result = Surround( + XSLTrailToken, + ticketLevelStr // + ); + + // + return result; + } + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + time = 0; + before = 0; + after = 0; + level = 0; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ticket > 0 && + time > 0 && + level > 0 + // + ; + + // + return result; + } +}; + +// +struct XSymbolPositions +{ + // + string symbol; + + // + double profit; + double volume; + + // + double longsProfit; + double longSupportsProfit; + + // + double shortsProfit; + double shortSupportsProfit; + + // + double longsVolume; + double longSupportsVolume; + + // + double shortsVolume; + double shortSupportsVolume; + + // + double requiredProfitForHedge; + + // + XPosition longs[]; + XPosition shorts[]; + XPosition supports[]; + XPosition positions[]; + XPosition longSupports[]; + XPosition shortSupports[]; + + // + bool forceHedge; + + // + XSymbolPositions() + { + Clean(); + } + + // + bool Update( + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // + ) + { + // + bool result = false; + + // + bool hasChild = HasChild(); + if (!hasChild) + { + return result; + } + + // + XPosition _supports[]; + XPosition _positions[]; + + // + XPosition _tmp[]; + + // + Copy( + positions, + _tmp // + ); + + // + Clean(positions); + + // + int tmpsCount = ArraySize(_tmp); + for (int i = 0; i < tmpsCount; i++) + { + // + XPosition iPosition = _tmp[i]; + + // + bool isSupport = IsSupport(iPosition.comment); + if (!isSupport) + { + // + AddRef( + iPosition, + _positions // + ); + } + else + { + // + AddRef( + iPosition, + _supports // + ); + } + } + + // + Clean(_tmp); + + // + Copy( + _positions, + positions // + ); + Clean(_positions); + + // + // Extract Types ... + ExtractPositions( + positions, + longs, + shorts // + ); + + // + Copy( + _supports, + supports // + ); + Clean(_supports); + + // + // Extract Types ... + ExtractPositions( + supports, + longSupports, + shortSupports // + ); + + // + int numOfLongs = 0; + int numOfShorts = 0; + CountPositions( + positions, + numOfLongs, + longsProfit, + longsVolume, + numOfShorts, + shortsProfit, + shortsVolume // + ); + + // + numOfLongs = 0; + numOfShorts = 0; + CountPositions( + supports, + numOfLongs, + longSupportsProfit, + longSupportsVolume, + numOfShorts, + shortSupportsProfit, + shortSupportsVolume // + ); + + // + XPosition _allPositions[]; + Copy( + positions, + _allPositions, + false // + ); + Copy( + supports, + _allPositions, + false // + ); + + // + profit = longsProfit + shortsProfit + longSupportsProfit + shortSupportsProfit; + volume = longsVolume + shortsVolume + longSupportsVolume + shortSupportsVolume; + requiredProfitForHedge = SpecifiedCalculateRequiredProfitForHedge( + _allPositions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + + // + Clean(_allPositions); + + // + result = true; + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + forceHedge = false; + + // + profit = 0; + longsProfit = 0; + shortsProfit = 0; + + // + volume = 0; + longsVolume = 0; + shortsVolume = 0; + + // + requiredProfitForHedge = 0; + + // + Clean(longs); + Clean(shorts); + Clean(positions); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(symbol); + + // + return result; + } + + // + // Has Child ... + bool HasChild() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int count = Count(); + result = IsValidSize(count); + + // + return result; + } + + // + // Count ... + int Count() + { + return ArraySize(positions); + } + + // + int CountSupports() + { + return ArraySize(supports); + } + + // + int CountLongs() + { + return ArraySize(longs); + } + + // + int CountShorts() + { + return ArraySize(shorts); + } + + // + int CountLongSupports() + { + return ArraySize(longSupports); + } + + // + int CountShortSupports() + { + return ArraySize(shortSupports); + } + + // + int GetOldest( + XPosition &_oldest, // + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = GetOldest( + _oldest, + longs // + ); + } + else + { + // + result = GetOldest( + _oldest, + shorts // + ); + } + + // + return result; + } + + // + int GetYoungest( + XPosition &_youngest, // + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = GetYoungest( + _youngest, + longs // + ); + } + else + { + // + result = GetYoungest( + _youngest, + shorts // + ); + } + + // + return result; + } + + // + int GetMaxInProfit( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMaxProfitIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMaxProfitIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // + int GetMinInProfit( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMinProfitIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMinProfitIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // + int GetMaxInDrawdown( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMaxInDrawdownIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMaxInDrawdownIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // + int GetMinInDrawdown( + XPosition &_position, + ENUM_POSITION_TYPE _type // + ) + { + // + int result = -1; + + // + bool isLong = IsLong(_type); + + // + int count = + isLong + ? CountLongs() + : CountShorts(); + if (!IsValidSize(count)) + { + return result; + } + + // + if (isLong) + { + // + result = FindMinInDrawdownIndex( + longs // + ); + + // + if (IsValidIndex(result)) + { + _position = longs[result]; + } + } + else + { + // + result = FindMinInDrawdownIndex( + shorts // + ); + + // + if (IsValidIndex(result)) + { + _position = shorts[result]; + } + } + + // + return result; + } + + // +}; + +// +struct XSymbolLastPosition +{ + // + string symbol; + string provider; + datetime time; + + // + XSymbolLastPosition() + { + Clean(); + } + + // + // Tools ... + + void Clean() + { + // + time = NULL; + symbol = NULL; + provider = NULL; + } +}; + +// +// an Structure for Holding Positions Data ... +struct XTradeData +{ + // + datetime time; // Issue Time (Open Position) + string symbol; // Trading Symbol + double entry; // Entry Price + double volume; // Volume + string provider; // Signaller + ENUM_TIMEFRAMES period; // Trading Timeframe + ENUM_X_POSITION_TYPES type; // Position Type + + // + ulong ticket; // Position Ticket + double swap; // Swap + double profit; // Profit on Close + double commission; // Commission + double maxDrawdown; // Max Position Drawdown + string message; // Close Reason + datetime endTime; // End Time + + // + XSignal signal; // Signal Object + int pushers; // Signal Pushers + string conditions; // Signal Conditions + + // + // Constructor ... + void XTradeInfo() + { + Clean(); + } + + // + // Filling Trade Handler ... + bool Fill(XSignal &_signal) + { + // + bool result = false; + + // + Clean(); + + // + // Check Signal Validation ... + result = _signal.IsValid(); + if (!result) + { + return result; + } + + // + signal = _signal; + time = _signal.time; + entry = _signal.entry; + symbol = _signal.symbol; + volume = _signal.volume; + period = _signal.period; + pushers = _signal.pushers; + provider = _signal.provider; + conditions = _signal.conditions; + type = ToPositionType(_signal.type); + + // + if (_signal.IsExecuted()) + { + ticket = _signal.positionId; + } + + // + return result; + } + + // + // Filling Trade Handler ... + bool Fill(XPosition &_position) + { + // + bool result = false; + + // + Clean(); + + // + // Check Signal Validation ... + result = _position.IsValid(); + if (!result) + { + return result; + } + + // + time = _position.openAt; + symbol = _position.symbol; + entry = _position.entry; + volume = _position.volume; + provider = _position.provider; + period = _position.period; + type = ToPositionType(_position.type); + + // + ticket = _position.ticket; + + // + return result; + } + + // + // Update Data ... + bool Update(XPosition &_position) + { + // + bool result = false; + + // + result = _position.IsValid(); + if (!result) + { + return result; + } + + // + profit = _position.profit; + swap = _position.swap; + + // + if (profit < 0 && + (maxDrawdown == 0 || + MathAbs(profit) > MathAbs(maxDrawdown))) + { + maxDrawdown = profit; + } + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + time = NULL; + type = NULL; + symbol = NULL; + period = NULL; + endTime = NULL; + message = NULL; + provider = NULL; + + // + swap = 0; + entry = 0; + ticket = 0; + profit = 0; + volume = 0; + commission = 0; + maxDrawdown = 0; + + // + signal.Clean(); + + // + ResetTrail(); + ResetRecovery(); + } + + // + // Validation ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ticket > 0 && + IsValid(time) && + IsValid(symbol) && + IsValid(period) + // + ; + + // + return result; + } + + // + // Retrieve Trade Data Age ... + int GetAge() + { + // + int result = -1; + + // + if (!IsValid(symbol) || + !IsValid(time) || + !IsValid(endTime) || + !IsValid(period)) + { + return result; + } + + // + int startIndex = iBarShift( + symbol, + period, + time, + false // + ); + + // + int endIndex = iBarShift( + symbol, + period, + endTime, + false // + ); + + // + result = MathAbs(startIndex - endIndex); + + // + return result; + } + + // + // Check Own of Trade Data ... + // based on Ticket ... + bool IsOwn( + ulong _ticket // + ) + { + // + bool result = false; + + // + result = _ticket == ticket; + + // + return result; + } + + // + // Check Own of Trade Data ... + // based on Symbol/Provider and Period ... + bool IsOwn( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + IsValid(_provider) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE && + // + type == _type && + period == _period && + symbol == _symbol && + provider == _provider + // + ; + + // + return result; + } + + // + // Data Collector ... + + // + // Get Data File Name ... + string GetFileName() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + symbol + "\\" + + ToString(type) + "\\" + + (profit >= 0 ? "Profit" : "Loss") + "\\" + + ToString(ticket) + "_" + + ToString(period) + "_" + + ToFormatString(time) + // + ; + + // + return result; + } + + // + // Get Signal File Name ... + string GetSignalFileName() + { + // + string result = NULL; + + // + result = + // + symbol + "\\" + + ToString(type) + "\\" + + provider + "_" + + ToFormatString(time) + // + ; + + // + return result; + } + + // + // Convert(s) To String Representation(s) ... + string ToString( + bool onlySignals = false // + ) + { + // + string result = NULL; + + // + int age = GetAge(); + + // + result = + // + (onlySignals + ? "" + : ToString("Ticket", ticket)) + + ToString("Symbol", symbol) + + ToString("Period", period) + + ToString("Entry", entry) + + ToString("Provider", provider) + + ToString("Type", ToString(type)) + + ToString("Time", time) + + // + // Attach Trade Info ... + (onlySignals + ? "" + : + // + "-------------" + "\n" + + ToString("Volume", volume) + + ToString("Profit", profit) + + ToString("Commission", commission) + + ToString("Swap", swap) + + ToString("Max Drawdown", maxDrawdown) + + ToString("End Time", endTime) + + ToString("Age", age) + + ToString("Message", message) + + "" + // + ) + + // + // Attach Conditions to Signals ... + (!onlySignals + ? "" + : + // + "-------------" + "\n" + + ToString("Pushers", pushers) + + "Conditions:" + "\n" + + "-------------" + "\n" + + conditions + + "" + // + ) + + // + "" + // + ; + + // + return result; + } + + // + // There are some Controlling Situations for each Trade + // which implemented here ... + + // + // Trailing Stop .... + + // + bool allowTrailStop; // Specified Position Can Trail Stop or not + bool ignoreTPOnTrail; // Ignore TP when SL Trailed + bool trailBasedOnProfit; // Do Trail Based on Profit Points + int trailLevel; // Last Trail Level + double trailStartInPoint; // Trail Starts When Profits Growing in Point + double trailStepInPoint; // Profit Must Grows Point to do Trailling + + // + // Reset all Trailing Configurations .... + void ResetTrail() + { + // + trailLevel = 0; + trailStepInPoint = 0; + trailStartInPoint = 0; + allowTrailStop = false; + ignoreTPOnTrail = false; + trailBasedOnProfit = false; + } + + // + // Recovery ... + + // + bool allowRecover; // Allow Recover Specified Position + double recoveryTPPoint; // Recovery TP Point + double recoverySLPoint; // Recovery SL Point + int maxAllowedRecover; // Max Allowed Recovery + int recoveryLevel; // Number of Recovery Signals + double recoveryVolumeMultiplier; // Recovery Volume Multiplier + double recoveryVolume; // Next Recovery Positioin Volume + ENUM_X_POSITION_TYPES recoveryLookingType; // Looking for Next Recovery Type + + // + void ResetRecovery() + { + // + allowRecover = false; + recoveryLevel = 0; + recoveryVolume = 0; + recoveryTPPoint = 0; + recoverySLPoint = 0; + recoveryVolumeMultiplier = 0; + recoveryLookingType = X_POSITION_TYPE_NONE; + } + + // +}; + +// +// TypeDefs ... + +// +typedef void (*TOnSignal)(XSignal &signal); + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +typedef void (*TOnForceClose)( + const ulong ticket, + const XPosition &position, + const string comment // +); + +// +typedef void (*TOnPartialClose)( + const ulong ticket, + const double profit, + const string comment // +); + +// +typedef void (*TOnModify)( + const ulong ticket, + const double profit, + const string comment // +); + +// +// Classes ... + +// +// Tools ... + +// +bool IsValid(ENUM_X_ORDER_MODES value) +{ + return value != X_ORDER_MODE_NOTHING; +} + +// +// Ages ... + +// +// Retrieve a Position Age ... +int GetAge( + XSignal &signal, // Selected Signal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + signal.symbol, + period, + signal.time); + + // + return result; +} + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.symbol, + period, + order.setupAt); + + // + return result; +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +int FindMaxProfitIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double max = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit <= 0) + { + continue; + } + + // + if (max == 0 || + max < iPosition.profit) + { + // + result = i; + max = iPosition.profit; + } + } + + // + return result; +} + +// +int FindMinProfitIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double min = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit <= 0) + { + continue; + } + + // + if (min == 0 || + min > iPosition.profit) + { + // + result = i; + min = iPosition.profit; + } + } + + // + return result; +} + +// +int ExtractInProfitPositions( + XPosition &positions[], // Position Collection + XPosition &inProfits[] // Result +) +{ + // + int result = 0; + + // + Clean(inProfits); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit > 0) + { + // + AddRef( + iPosition, + inProfits // + ); + } + } + + // + result = ArraySize(inProfits); + + // + return result; +} + +// +int FindMaxInDrawdownIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double max = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit >= 0) + { + continue; + } + + // + if (max == 0 || + MathAbs(max) < MathAbs(iPosition.profit)) + { + // + result = i; + max = iPosition.profit; + } + } + + // + return result; +} + +// +int FindMinInDrawdownIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double min = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit >= 0) + { + continue; + } + + // + if (min == 0 || + min > iPosition.profit) + { + // + result = i; + min = iPosition.profit; + } + } + + // + return result; +} + +// +int ExtractInDrawdownPositions( + XPosition &positions[], // Position Collection + XPosition &inDradowns[] // Result +) +{ + // + int result = 0; + + // + Clean(inDradowns); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit < 0) + { + // + AddRef( + iPosition, + inDradowns // + ); + } + } + + // + result = ArraySize(inDradowns); + + // + return result; +} + +// +// Check Filters ... + +// +// Magic Filter ... +template +bool IsMagicFilterPassed( + ulong magic, + bool filterByMagic, + T &item + // +) +{ + // + return !filterByMagic + ? true + : !NotEmpty(magic) + ? false + : magic == item.magic; +} + +// +// Symbol Filter ... +template +bool IsSymbolFilterPassed( + string symbol, + T &item + // +) +{ + // + return !IsValid(symbol) + ? true + : symbol == item.symbol; +} + +// +// Provider Filter ... +template +bool IsProviderFilterPassed( + string provider, + T &item + // +) +{ + // + return !IsValid(provider) + ? true + : provider == item.provider; +} + +// +// Period Filter ... +template +bool IsPeriodFilterPassed( + ENUM_TIMEFRAMES period, + T &item + // +) +{ + // + return !IsValid(period) + ? true + : period == item.period; +} + +// +// Type Filter ... +template +bool IsTypeFilterPassed( + ENUM_POSITION_TYPE type, + T &item + // +) +{ + // + bool result = type == item.type; + + // + return result; +} +template +bool IsTypeFilterPassed( + ENUM_X_POSITION_TYPES type, + T &item + // +) +{ + // + bool result = type == NULL || type == X_POSITION_TYPE_ALL + ? true + : ((type == X_POSITION_TYPE_LONG && ((int)item.type == (int)POSITION_TYPE_BUY || (int)item.type == (int)ORDER_TYPE_BUY)) || + (type == X_POSITION_TYPE_SHORT && ((int)item.type == (int)POSITION_TYPE_SELL || (int)item.type == (int)ORDER_TYPE_SELL))); + + // + return result; +} +template +bool IsTypeFilterPassed( + ENUM_ORDER_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_DEAL_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} + +// +// Mode Filter ... +template +bool IsModeFilterPassed( + ENUM_X_ORDER_MODES mode, + T &item + // +) +{ + // + return mode == NULL + ? true + : mode == item.mode; +} + +// +// Entry Filter ... +template +bool IsEntryFilterPassed( + ENUM_DEAL_ENTRY entry, + T &item + // +) +{ + // + return entry == NULL + ? true + : entry == item.entry; +} + +// +// Reason Filter ... +template +bool IsReasonFilterPassed( + ENUM_DEAL_REASON reason, + T &item + // +) +{ + // + return reason == NULL + ? true + : reason == item.reason; +} + +// +// State Filter ... +template +bool IsStateFilterPassed( + ENUM_ORDER_STATE state, + T &item + // +) +{ + // + return state == NULL + ? true + : state == item.state; +} + +// + +// +// Find Specific Item Index inside a Collection ... +template +int FindIndex( + T &item, // Item to Find + const T &items[] // Items for Search +) +{ + // + int result = -1; + + // + // Check Item Validation ... + if (!item.IsValid()) + { + return result; + } + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + // Validate Item ... + if (!iItem.IsValid()) + { + continue; + } + + // + bool isSame = item.IsSameAs(iItem); + if (isSame && result <= -1) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +// +// Calculate Positions Profit Summary ... +double SpecifiedCalculatePositionsProfit( + XPosition &positions[] // Source +) +{ + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result += iPosition.profit; + } + + // + return result; +} + +// +// Calculate Required Profit for Hedging ... +double SpecifiedCalculateRequiredProfitForHedge( + XPosition &positions[], // Source + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0; + if (!isHedgingEnable) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0) + { + // + result += + ((iPosition.volume / mMinProfitPerVolumeFactor) * + mMinProfitPerTrade) + + (-1 * iPosition.swap); + } + } + + // + return result; +} + +// +bool SpecifiedIsPositionsReadyForHedge( + XPosition &positions[], // Source + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + double profit = SpecifiedCalculatePositionsProfit(positions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + positions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + + // + bool result = requiredProfit > 0 + ? profit >= requiredProfit + : profit > requiredProfit; + + // + return result; +} + +// +int FindCoverageDrawdownPosition( + XPosition &position, // In Drawdown Position + XPosition &inProfits[], // In Profit Positions + XPosition &coverage[], // Coverage Positons + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + int result = 0; + + // + Clean(coverage); + + // + if (!position.IsValid() || position.profit >= 0) + { + return result; + } + + // + int inProfitsCount = ArraySize(inProfits); + if (!IsValidSize(inProfitsCount)) + { + return result; + } + + // + // Copy in Profits to TMP ... + XPosition tmp[]; + Copy( + inProfits, + tmp // + ); + + // + bool isCoverPassed = false; + while (!isCoverPassed || ArraySize(tmp) > 0) + { + // + XPosition max; + int idx = FindMaxProfitIndex(tmp); + if (idx >= 0) + { + // + if (tmp[idx].profit > 0) + { + AddRef( + tmp[idx], + coverage // + ); + + // + ArrayRemove( + tmp, + idx, + 1 // + ); + } + } + + // + // Check Cover Passed ... + XPosition tmpPositions[]; + Copy( + coverage, + tmpPositions // + ); + AddRef( + position, + tmpPositions // + ); + + // + double profits = SpecifiedCalculatePositionsProfit(tmpPositions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + tmpPositions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + isCoverPassed = profits >= requiredProfit; + if (isCoverPassed) + { + break; + } + + // + if (!isCoverPassed && ArraySize(tmp) == 0) + { + break; + } + } + + // + result = ArraySize(coverage); + + // + return result; +} + +// +// Extract a Collection of Positions SL ... +int ExtractSLs( + XPosition &positions[], + double &sls[] // +) +{ + // + int result = 0; + + // + Clean(sls); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.sl > 0) + { + // + Add( + iPosition.sl, + sls // + ); + } + } + + // + result = ArraySize(sls); + + // + return result; +} + +// +// Extract a Colletion of Positions TP ... +int ExtractTPs( + XPosition &positions[], + double &tps[] // +) +{ + // + int result = 0; + + // + Clean(tps); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.tp > 0) + { + // + Add( + iPosition.tp, + tps // + ); + } + } + + // + result = ArraySize(tps); + + // + return result; +} + +// +// Retrieve String Representation ... +string ToString(ENUM_X_SIGNAL_EXECUTION_RESULT value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_SIGNAL_EXECUTION_UNKNOWN: + result = "Unknown"; + break; + + // + case X_SIGNAL_EXECUTION_SUCCEED: + result = "Succed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_SPREAD: + result = "Spread more than Max Allowed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED: + result = "not Allowed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_NO_EQUITY: + result = "No Equity for Trade"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR: + result = "Price Error"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR: + result = "Previous Position Profit not Passed for Accept Next"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_MAX_REACHED: + result = "Max Allowed Positions Reached"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED: + result = "Min Delay Between to Signal not Passed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS: + result = "Invalid Params"; + break; + } + + // + return result; +} + +// +// Converts Position Type to Order Type ... +ENUM_ORDER_TYPE ToOrderType(ENUM_POSITION_TYPE value) +{ + // + bool isLong = IsLong(value); + + // + ENUM_ORDER_TYPE result = + isLong + ? ORDER_TYPE_BUY + : ORDER_TYPE_SELL; + + // + return result; +} +ENUM_ORDER_TYPE ToOrderType(ENUM_X_POSITION_TYPES value) +{ + // + ENUM_POSITION_TYPE mType = + value == X_POSITION_TYPE_SHORT + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + + // + bool isLong = IsLong(mType); + + // + ENUM_ORDER_TYPE result = + isLong + ? ORDER_TYPE_BUY + : ORDER_TYPE_SELL; + + // + return result; +} + +// +// Tagging ... + +// +// Generate Specified Tag for Using in Comments ... +string GeneratePeriodTag(ENUM_TIMEFRAMES period) +{ + // + string strPeriod = ToString(period); + return Surround( + XPeriodToken, + strPeriod + // + ); +} + +// +// Extract Period from a Tagged string ... +ENUM_TIMEFRAMES ExtractPeriod(string value) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + string pStr = ParseStringSurrounded( + value, + XPeriodToken + // + ); + if (!IsValid(pStr)) + { + return result; + } + + // + result = ToPeriod(pStr); + + // + return result; +} + +// Generate Specified Tag for Using in Comments ... +string GenerateProviderTag(string provider) +{ + // + return Surround( + XProviderToken, + provider + // + ); +} + +// +// Extract Provider from a Tagged string ... +string ExtractProvider(string value) +{ + // + return ParseStringSurrounded( + value, + XProviderToken + // + ); +} + +// +// Generate Support Comment Tag ... +string GenerateSupportTag(ulong ticket) +{ + // + return Surround( + XSupportToken, + ticket + // + ); +} + +// +// Extract Support Positions from a Tagged string ... +ulong ExtractSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XSupportToken + // + ); +} + +// +// Extract Support ... +template +int ExtractSupports( + T &source[], + T &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + ulong isSupport = ExtractSupportedTicket(iSource.comment) > 0; + ulong iEQMSupport = ExtractEQMSupportedTicket(iSource.comment) > 0; + if (isSupport || iEQMSupport) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Generate EQM Support Comment Tag ... +string GenerateEQMSupportTag(ulong ticket) +{ + // + return Surround( + XEQMSupportToken, + ticket + // + ); +} + +// +// Extract EQM Support Positions from a Tagged string ... +ulong ExtractEQMSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XEQMSupportToken + // + ); +} + +// +bool IsSupport(string value) +{ + // + bool result = false; + + // + bool isSupport = ExtractSupportedTicket(value) > 0; + bool isEQMSupport = ExtractEQMSupportedTicket(value) > 0; + + // + result = + // + isSupport + // + || + // + isEQMSupport + // + ; + + // + return result; +} + +// +ulong ExtractParentTicket(string value) +{ + // + ulong result = 0; + + // + if (!IsSupport(value)) + { + return result; + } + + // + result = ExtractSupportedTicket(value); + if (result > 0) + { + return result; + } + + // + result = ExtractEQMSupportedTicket(value); + + // + return result; +} + +// +// XRecovery ... + +// +string GenerateRecoveryTag(ulong ticket) +{ + // + return Surround( + XRecoveryToken, + ticket // + ); +} + +// +ulong ExtractRecoveredTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XRecoveryToken // + ); +} + +// +// Extract Recoveries ... +template +int ExtractRecoveries( + T &source[], + T &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + ulong isRecovery = ExtractRecoveredTicket(iSource.comment) > 0; + if (isRecovery) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Extract Specified Position's Recoveries ... +int ExtractRecoveries( + ulong ticket, + XPosition &source[], + XPosition &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + XPosition iSource = source[i]; + + // + ulong parentTicket = ExtractRecoveredTicket(iSource.comment); + bool isRecovery = parentTicket > 0; + if (isRecovery && parentTicket == ticket) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// SL Trails ... + +// +// Extract SL Trail Level ... +int ExtractSLTrailLevel(string comment) +{ + // + int result = 0; + + // + if (!IsValid(comment)) + { + return result; + } + + // + result = ParseIntSurrounded( + comment, + XSLTrailToken + // + ); + + // + return result; +} + +// +// Generate SL Trail Comment Tag ... +string GenerateSLTrailTag(int level) +{ + // + string result = NULL; + + // + if (level <= 0) + { + return result; + } + + // + result = Surround( + XSLTrailToken, + level + // + ); + + // + return result; +} + +// +// Prepare SL Trail Comment ... +string PrepareSLTrailTag( + const string comment // Original Position Comment ... +) +{ + // + string result = NULL; + + // + int level = 0; + result = comment; + + // + // Check Comment Contains SL Trailing or not ... + int lastTrailLevel = ExtractSLTrailLevel(comment); + if (lastTrailLevel <= 0) + { + level++; + } + else + { + // + level = lastTrailLevel + 1; + string lastLevelStr = GenerateSLTrailTag(lastTrailLevel); + StringReplace( + result, + lastLevelStr, + "" + // + ); + } + + // + // Generate level Comment ... + string levelStr = GenerateSLTrailTag(level); + result += levelStr; + + // + return result; +} + +// +// Count Positions from a Collection ... +void CountPositions( + const XPosition &positions[], + int &longs, + double &longProfits, + double &longVolumes, // + // + int &shorts, + double &shortProfits, + double &shortVolumes // +) +{ + // + longs = 0; + longProfits = 0; + longVolumes = 0; + + // + shorts = 0; + shortProfits = 0; + shortVolumes = 0; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isLong = IsLong(iPosition.type); + if (isLong) + { + // + longs++; + longProfits += iPosition.profit; + longVolumes += iPosition.volume; + } + else + { + // + shorts++; + shortProfits += iPosition.profit; + shortVolumes += iPosition.volume; + } + } +} + +// +// Extract Positions based On Type ... +void ExtractPositions( + XPosition &positions[], + XPosition &longs[], + XPosition &shorts[] // +) +{ + // + int count = ArraySize(positions); + if (!IsValidSize(count)) + { + return; + } + + // + Clean(longs); + Clean(shorts); + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isLong = IsLong(iPosition.type); + if (isLong) + { + AddRef( + iPosition, + longs // + ); + } + else + { + AddRef( + iPosition, + shorts // + ); + } + } +} + +// +int FindSymbolIndex( + string mSymbol, + XSymbolPositions &mItems[] // +) +{ + // + int result = -1; + + // + if (!IsValid(mSymbol)) + { + return result; + } + + // + int count = ArraySize(mItems); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XSymbolPositions iItem = mItems[i]; + + // + if (iItem.symbol == mSymbol) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +int ExtractSymbolPositions( + XPosition &positions[], + XSymbolPositions &items[], // Holds Result + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + int result = 0; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + Clean(items); + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (!iPosition.IsValid()) + { + continue; + } + + // + int itemIDX = FindSymbolIndex( + iPosition.symbol, + items // + ); + if (!IsValidIndex(itemIDX)) + { + // + // Add New One ... + XSymbolPositions item; + item.symbol = iPosition.symbol; + + // + AddRef( + item, + items // + ); + itemIDX = FindSymbolIndex(iPosition.symbol, items); + } + + // + AddRef( + iPosition, + items[itemIDX].positions // + ); + } + + // + result = ArraySize(items); + if (IsValidSize(result)) + { + // + for (int i = 0; i < result; i++) + { + // + items[i].Update( + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + } + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031106/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 new file mode 100644 index 0000000..528cc7f --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 @@ -0,0 +1,1075 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XSCX121SMCBaseStrategy +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../../Classes/x-saherelm.x-alert.class.mq5" +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.class.mq5" +#include "../../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-121.smc.cobjects.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Helper(s) ... + +// +// XStrategy Class Implementation(s) ... +class XCX121SMCBaseStrategy : public XCBaseAlert +{ + // + // Public ... + public: + // + + // + // Constructor(s) ... + XCX121SMCBaseStrategy( + // + // Base ... + string _symbol, // Trading Symbol + ENUM_TIMEFRAMES _period // Trading TimeFrame + ) + { + // + mSymbol = _symbol; + mPeriod = _period; + + // + Init(); + } + + // + // Deconstructor ... + ~XCX121SMCBaseStrategy() + { + DeInit(); + } + + // + // Getter / Setter (s) ... + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve TimeFrame ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Retrieve POI Drawer Instance Pointer ... + **/ + XCPOIDrawer *GetDrawer() + { + return mPOIDrawer; + } + + /** + * Check Strategy is Disabled or not ... + * + * @return ( bool ) + */ + bool IsDisabled() + { + return mForceDisabled; + } + + /** + * Get Chart Id ... + * + * @return ( long ) + */ + long ChartIdentification() + { + return mChartID; + } + + /** + * Set Chart Id ... + * + * @param value: Long ... + */ + void ChartIdentification(long value) + { + // + if (value < 0) + { + value = 0; + } + + // + mChartID = value; + if (mPOIDrawer != NULL) + { + mPOIDrawer.ChartIdentification(value); + } + } + + /** + * Get Sub Window Id ... + * + * @return ( int ) + */ + int SubWindowIdentification() + { + return mSubWindow; + } + + /** + * Set Sub Window Id ... + * + * @param value: Integer ... + */ + void SubWindowIdentification(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSubWindow = value; + if (mPOIDrawer != NULL) + { + mPOIDrawer.SubWindowIdentification(value); + } + } + + /** + * Get Signal Volume ... + * + * @return ( double ) + */ + double Volume() + { + return mVolume; + } + + /** + * Set Signal Volume ... + * + * @param value: Double ... + */ + void Volume(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mVolume = value; + } + + /** + * Get Risk/Reward Ratio ... + * + * @return ( double ) + */ + double R2R() + { + return mR2R; + } + + /** + * Set Risk/Reward Ratio ... + * + * @param value: Double ... + */ + void R2R(double value) + { + // + if (value < 0) + { + value = 1.5; + } + + // + mR2R = value; + } + + /** + * Get Max Allowed Spread ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread ... + * + * @param value: Double ... + */ + void MaxAllowedSpread(double value) + { + mMaxAllowedSpread = value; + } + + /** + * Get Min Required Ticks Verification for Spread Pass ... + * + * @return ( int ) + */ + int MinRequiredTicksForSpreadPass() + { + return mMinRequiredTicksForSpreadPass; + } + + /** + * Set Min Required Ticks Verification for Spread Pass ... + * + * @param value: Integer ... + */ + void MinRequiredTicksForSpreadPass(int value) + { + // + if (value < 100) + { + value = 100; + } + + // + mMinRequiredTicksForSpreadPass = value; + } + + /** + * Get Max Allowed Save Ticks ... + * + * @return ( int ) + */ + int MaxAllowedSaveTicks() + { + return mMaxAllowedSaveTicks; + } + + /** + * Set Max Allowed Save Ticks ... + * + * @param value: Integer ... + */ + void MaxAllowedSaveTicks(int value) + { + // + if (value < 150) + { + value = 150; + } + + // + mMaxAllowedSaveTicks = value; + } + + /** + * Get Long Signalling State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Long Signalling State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + mAllowLong = value; + } + + /** + * Get Short Signalling State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Short Signalling State ... + * + * @param value: Argument 1 + */ + void AllowShort(bool value) + { + mAllowShort = value; + } + + // + // Actions ... + + /** + * Disable Strategy ... + */ + void Disable() + { + mForceDisabled = true; + } + + /** + * Enable Strategy ... + */ + void Enable() + { + mForceDisabled = false; + } + + /** + * Register Signal Event Handler ... + * + * @param handler: an Instance of TOnXSignal ... + */ + void AddXSignalEventHandler(TOnX121SMCSignal handler) + { + // + Add( + handler, + mSignalEventHandlers // + ); + } + + // + // Virtual Actions ... + + /** + * Destroy All Class Implementations ... + */ + virtual void Destroy() + { + } + + /** + * Handle Tick Processing ... + * + * @param positions: XPosition instance Collection ... + */ + virtual void HandleTick() + { + // + // Check State ... + if (IsDisabled()) + { + return; + } + + // + // Check Signalling State ... + if (!AllowLong() && !AllowShort()) + { + return; + } + + // + // Check Bar Tracker State ... + if (!mBarTracker.CanProcessBar()) + { + return; + } + + // + // Retrieve Current Tick and Check it's Time + // by Last Issued Tick ... + MqlTick cTick; + bool hasTick = GetTick( + mSymbol, + cTick // + ); + bool isSameAsLast = cTick.time == mLastTick.time; + if (isSameAsLast) + { + return; + } + + // + // Update Last Issued Tick ... + mLastTick = cTick; + SaveTickData(); + + // + // Check Current Processing Tick has Signal or not ... + XSignal signal; + X121SMCStrategyConditions conditions; + bool hasSignal = HasSignal( + signal, + conditions // + ); + if (!hasSignal) + { + return; + } + + // + // Waits Until Next Candle if Current Tick has Signal ... + mBarTracker.Waits(); + + // + // Notify Signal Event Handlers ... + NotifyOnSignalEventHandlers( + signal, + conditions // + ); + } + + /** + * Check for any Guards ... + * + * @param guards: X121SMCGuard instance Collection ... + * @param positions: XPosition instance Collection ... + * + * @return ( virtual bool ) + */ + virtual bool HandleGuard( + X121SMCGuard &guards[], + XPosition &positions[] // + ) + { + // + bool result = false; + + // + // Check State ... + if (IsDisabled()) + { + return result; + } + + // + // Check Signalling State ... + if (!AllowLong() && !AllowShort()) + { + return result; + } + + // + // Check Bar Tracker State ... + if (!mGuardBarTracker.CanProcessBar()) + { + return result; + } + + // + // Check For Guards ... + result = CheckGuard( + guards, + positions // + ); + + // + // Waits Until Next Candle if Current Tick has Guard ... + mGuardBarTracker.Waits(); + + // + ArrayFree(positions); + + // + return result; + } + + /** + * Check For Signal ... + * + * @param signal: XSignal instance ... + * @param conditions: X121SMCStrategyConditions instance ... + * + * @return ( virtual bool ) + */ + virtual bool HasSignal( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + signal.Clean(); + conditions.Clean(); + + // + return result; + } + + /** + * Check for any Guard Actions ... + * + * @param guards: X121SMCGuard instance Collection ... + * + * @return ( virtual bool ) + */ + virtual bool CheckGuard( + X121SMCGuard &guards[], + const XPosition &positions[] // Positions ... + ) + { + // + bool result = false; + + // + return result; + } + + /** + * Detect SL Candidates based on Strategy and Conditions ... + * + * @param result: Double array reference ... + * @param entry: Double, Position Entry Price ... + * @param conditions: X121SMCStrategyConditions instance, Provides Configurations ... + * @param type: ENUM_X_POSITION_TYPES member, Specified Position Type ... + */ + virtual void DetectSLCandidates( + double &result[], + double entry, + X121SMCStrategyConditions &conditions, + ENUM_X_POSITION_TYPES type // + ) + { + } + + /** + * Customize Strategy Identifier ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + return X121SMCStrategyToken; + } + + // + // Protected ... + protected: + // + + // + // Props ... + + // + XCPOIDrawer *mPOIDrawer; // POI Drawer Class ... + CArrayObj mDrawnObjects; + + // + XTick mTicks[]; // Hold Ticks Data ... + MqlTick mLastTick; // Last Issued Tick ... + + // + XBarTracker mBarTracker; // Strategy Bar Tracker ... + XBarTracker mGuardBarTracker; // Strategy Guard Bar Tracker ... + XCBarAnalyser *mBarAnalyser; // Bar Analyser Instance + + // + // Actions ... + + /** + * Check Spread Passed for Positions... + * + * @return ( bool ) + */ + bool IsSpreadPass() + { + // + bool result = false; + + // + double pointValue = GetPoints(mSymbol); + double maxAllowedSpread = MaxAllowedSpread(); + int minRequiredTicksVerification = MinRequiredTicksForSpreadPass(); + if (maxAllowedSpread > 0) + { + maxAllowedSpread *= pointValue; + } + else + { + maxAllowedSpread = 0; + } + + // + result = maxAllowedSpread <= 0 + ? true + : minRequiredTicksVerification > 0; + if (!result) + { + return result; + } + + // + int ticksCount = ArraySize(mTicks); + result = ticksCount >= minRequiredTicksVerification; + if (!result) + { + return result; + } + + // + if (maxAllowedSpread > 0) + { + // + int end = -1; + int start = -1; + result = CalculateTicksParams( + start, + end, + minRequiredTicksVerification // + ); + if (!result) + { + return result; + } + + // + for (int i = start; i < end; i++) + { + // + XTick iTick = mTicks[i]; + + // + result = iTick.spread <= maxAllowedSpread; + if (!result) + { + break; + } + } + } + + // + return result; + } + + /** + * Prepare and Normalize Signal for Execution in Strategy ... + * + * @param signal: XSignal instance ... + * + * @return ( bool ) + */ + bool PrepareSignal(XSignal &signal) + { + // + bool result = false; + + // + // Check Strategy Is Enables ... + result = !IsDisabled(); + if (!result) + { + return result; + } + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + bool isLong = IsLong(signal.type); + + // + // TODO: Implement Signal Preparation Mechanism here ... + + // + return result; + } + + // + + /** + * Notified Signal Event Handler(s) ... + * + * @param signal: XSignal instance ... + * @param conditions: XStrategyConditions instance ... + */ + void NotifyOnSignalEventHandlers( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + if (!signal.IsValid() || !conditions.IsValid()) + { + return; + } + + // + int count = ArraySize(mSignalEventHandlers); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mSignalEventHandlers[i]( + signal, + conditions // + ); + } + } + + // + // Draw Functions ... + + /** + * Clear all Drawn Objects ... + */ + void ClearDraws() + { + mDrawnObjects.Clear(); + } + + /** + * Remove Specified Drawn Object ... + * + * @param name: Object name ... + */ + void RemoveObject(string name) + { + // + if (!IsValid(name)) + { + return; + } + + // + int count = mDrawnObjects.Total(); + if (!IsValidSize(count)) + { + return; + } + + // + int idx = -1; + for (int i = 0; i < count; i++) + { + // + string iName = ((CChartObject *)mDrawnObjects.At(i)).Name(); + string iObjName = NULL; + if (!IsValid(iName)) + { + iObjName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName(); + } + + // + if ((IsValid(iName) && + iName == name) || + (IsValid(iObjName) && + iObjName == name)) + { + // + idx = i; + break; + } + } + + // + if (IsValidIndex(idx)) + { + mDrawnObjects.Delete(idx); + } + } + + /** + * Add Specified Object to Drawn Objects if not Exists ... + */ + void AddObjectIfNotExists(XCBaseObject *object) + { + // + string name = object.ObjName(); + + // + bool canAdd = true; + int count = mDrawnObjects.Total(); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + string iName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName(); + + // + if (name == iName) + { + // + canAdd = false; + break; + } + } + } + + // + if (canAdd) + { + mDrawnObjects.Add(object); + } + } + + /** + * Add Specified Objects to Drawn Objects if not Exists ... + */ + void AddObjectsIfNotExists(XCBaseObject *&objects[]) + { + // + int count = ArraySize(objects); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + AddObjectIfNotExists(objects[i]); + } + + // + ArrayFree(objects); + } + + // + // Private ... + private: + // + // Props ... + + // + string mSymbol; // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ... + bool mForceDisabled; // Force Disabled ... + bool mAllowLong; // Allow Long Signals + bool mAllowShort; // Allow Short Signals + double mR2R; // Risk/Rewar Ratio ... + double mVolume; // Static Volume Per Trades ... + + // + double mMaxAllowedSpread; // Max Allowed Spread ... + int mMinRequiredTicksForSpreadPass; // Min Required Ticks Verification for Spread Pass ... + int mMaxAllowedSaveTicks; // Max Allowed Save Ticks ... + + // + long mChartID; // Chart ID ... + int mSubWindow; // Sub Window ID ... + + // + // On X121 Signal Recieved Event Handler(s) ... + TOnX121SMCSignal mSignalEventHandlers[]; + + // + // Actions ... + + /** + * Install all Helpers and Prepare all Configurations for required Indicators ... + */ + void Init() + { + // + mForceDisabled = false; + + // + R2R(1); + Volume(0.01); + MaxAllowedSaveTicks(150); + MinRequiredTicksForSpreadPass(100); + + // + ChartIdentification(0); + SubWindowIdentification(0); + + // + // Configure POI Drawer if Required ... + mPOIDrawer = new XCPOIDrawer(); + mPOIDrawer.ChartIdentification(0); + mPOIDrawer.SubWindowIdentification(0); + + // + mPOIDrawer.DemandZoneFill(false); + mPOIDrawer.SupplyZoneFill(false); + mPOIDrawer.BullishFVGFill(false); + mPOIDrawer.BearishFVGFill(false); + mPOIDrawer.SupportZoneFill(false); + mPOIDrawer.ResistanceZoneFill(false); + mPOIDrawer.BullishOrderBlockFill(false); + mPOIDrawer.BearishOrderBlockFill(false); + + // + string symbol = Symbol(); + ENUM_TIMEFRAMES period = Period(); + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + symbol, + period // + ); + + // + // Initialize Guard Bar Tracker ... + mGuardBarTracker.Init( + symbol, + period // + ); + + // + mBarAnalyser = new XCBarAnalyser(); + + // + } + + /** + * De Initialize all Tools ... + */ + void DeInit() + { + // + delete mPOIDrawer; + delete mBarAnalyser; + + // + ArrayFree(mTicks); + ArrayFree(mSignalEventHandlers); + + // + Destroy(); + } + + /** + * Reste Bar Tracker ... + */ + void ResetBarTracker() + { + mBarTracker.Clean(); + } + + /** + * Add new Tick Data to Collection ... + */ + void SaveTickData() + { + // + XTick tick; + bool isInited = tick.Init(mSymbol); + if (!isInited) + { + return; + } + + // + int beforeCount = ArraySize(mTicks); + + // + AddRef( + tick, + mTicks // + ); + + // + int afterCount = ArraySize(mTicks); + + // + bool isAdded = afterCount == beforeCount + 1; + if (isAdded) + { + // + // Cleaning Up Unused Items ... + int maxAllowed = MaxAllowedSaveTicks(); + CleanupArray( + mTicks, + maxAllowed // + ); + } + } + + /** + * Calculate Ticks Param for Looping through Last n items ... + * + * @param start: Integer Reference to Start ... + * @param end: Integer Reference to End ... + * @param numOfLastTicks: Integer Max Number of Required N Last Ticks ... + */ + bool CalculateTicksParams( + int &start, + int &end, + int numOfLastTicks = 5 // + ) + { + // + bool result = 0; + + // + start = -1; + end = -1; + + // + int count = ArraySize(mTicks); + + // + start = count - numOfLastTicks; + if (start < 0) + { + start = 0; + } + + // + end = start + numOfLastTicks; + if (end > count) + { + end = count; + } + + // + result = IsValidIndex(start) && + IsValidIndex(end); + + // + return result; + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 new file mode 100644 index 0000000..3f37d87 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.cobjects.class.mq5 @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XChartObjects +// Description: provides all require Chart Objects ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../../Classes/x-saherelm.x-cobject.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +enum ENUM_X121SMC_CHARTOBJECTS +{ + X_121_NONE_OBJ +}; + +// +// Implementations ... diff --git a/BKPS/14031106/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 new file mode 100644 index 0000000..47d16e0 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5 @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121Panel +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-app-dialog.class.mq5" + +// +// Implementation ... + +// +class X121CAppDialog : public XCAppDialog +{ + // + public: + // + // Constructor(s) ... + void X121CAppDialog() + { + } + + // + // Deconstructor ... + void ~X121CAppDialog() + { + } + + // + void Configure() + { + // + // Configure Dialog ... + BackgroundColor(clrBlack); + } + + // + protected: + // + + // + private: + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 new file mode 100644 index 0000000..e6e98d9 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 @@ -0,0 +1,779 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121SMCCycleHelper +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +// +// Implementations ... + +enum ENUM_X_CYCLES +{ + X_CYCLE_NONE, + X_CYCLE_TRIGGER, + X_CYCLE_DECISION, + X_CYCLE_ANALYSE, + X_CYCLE_VERIFICATION, + X_CYCLE_CONSOLIDATION, + X_CYCLE_VISION, +}; + +string ToString(ENUM_X_CYCLES value) +{ + // + string result = EnumToString(value); + + // + StringReplace(result, "X_CYCLE_", ""); + + // + return result; +} + +enum ENUM_X_CYCLE_EVENTS +{ + SAR_CHANGE_DETECTED, + NEW_PEAK_DETECTED, + NEW_VALE_DETECTED, + PIVOT_POINT_DETECTED, + VWAP_ORDER_CHANGE_ETECTED, + VWAP_STATE_CHANGE_DETCTED, + CONSOLIDATION_BREAKED_DETECTED, + PEAK_PIVOT_STARTED, + PEAK_PIVOT_ENDED, + VALE_PIVOT_STARTED, + VALE_PIVOT_ENDED, +}; + +class XC121SMCCycleHelper : public XCBase +{ + // + public: + // + // Props ... + + // + // X121 ... + XCX121Helper *mX121Helper; + + // + // POI Detector ... + XCPOIDrawer *mPOIDrawer; + XCPOIDetector *mPOIDetector; + + // + // Bar Analyser + XCBarAnalyser *mBarAnalyser; + + // + // Constructor(s) ... + XC121SMCCycleHelper() + { + Default(); + } + + // + // Deconstructor ... + ~XC121SMCCycleHelper() + { + DeInit(); + } + + // + // Getter/Setter(s) ... + + // + // Actions ... + + /** + * Initialize ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + * @param x121Inputs: X121Inputs instance ... + * + * @return ( bool ) + */ + bool Init( + string symbol, + ENUM_TIMEFRAMES period, + X121Inputs &x121Inputs, + int requiredPOIS = 50 // + ) + { + // + bool result = false; + + // + if (requiredPOIS < 10) + { + requiredPOIS = 10; + } + + // + result = IsValid(symbol) && + IsValid(period); + if (!result) + { + return result; + } + + // + // X121 ... + mX121Helper = new XCX121Helper(); + result = mX121Helper.Init( + symbol, + period, + x121Inputs // + ); + if (!result) + { + return result; + } + + // + mPOIDetector = new XCPOIDetector( + symbol, + period // + ); + mPOIDetector.MaxNumberOfRequiredPOIs(requiredPOIS); + mPOIDetector.Init(); + + // + // Initialize Bar Analyser Class Instance ... + mBarAnalyser = new XCBarAnalyser(); + + // + // Initial and Configure POI Drawer if Required ... + mPOIDrawer = new XCPOIDrawer(); + mPOIDrawer.ChartIdentification(0); + mPOIDrawer.SubWindowIdentification(0); + + // + mPOIDrawer.DemandZoneFill(false); + mPOIDrawer.SupplyZoneFill(false); + mPOIDrawer.BullishFVGFill(false); + mPOIDrawer.BearishFVGFill(false); + mPOIDrawer.SupportZoneFill(false); + mPOIDrawer.ResistanceZoneFill(false); + mPOIDrawer.BullishOrderBlockFill(false); + mPOIDrawer.BearishOrderBlockFill(false); + + // + // Set Chart Style ... + ApplyChartStyle(); + + // + return result; + } + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + // + string result = NULL; + + // + result = mX121Helper.GetSymbol(); + + // + return result; + } + + /** + * Retrieve TimeFrame (Period) ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + // + ENUM_TIMEFRAMES result = NULL; + + // + result = mX121Helper.GetPeriod(); + + // + return result; + } + + /** + * Get Specified Bar ... + * + * @param source: XOHCL instance, Source Bar ... + * @param bar: XOHCL instance, Dest Bar ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &source, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = + IsValid(symbol) && + IsValid(period) && + source.IsValid(); + if (!result) + { + return result; + } + + // + int index = iBarShift( + symbol, + period, + source.time // + ); + result = bar.Init( + symbol, + period, + index // + ); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + return result; + } + + /** + * Retrieve Specified Bar ... + * + * @param bar: XOHCL instance ... + * @param index: Integer ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &bar, + int index = 0 // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + if (index < 0) + { + index = 0; + } + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + /** + * Retrieve Specified Bar ... + * + * @param bar: XOHCL instance ... + * @param time: Datetime ... + * + * @return ( bool ) + */ + bool GetBar( + XOHCL &bar, + datetime time = NULL // + ) + { + // + bool result = false; + + // + int index = GetBarIndex(time); + result = GetBar(bar, + index // + ); + + // + return result; + } + + /** + * Retrieve Specified Time Bar Index ... + * + * @param time: DateTime ... + * + * @return ( int ) + */ + int GetBarIndex(datetime time = NULL) + { + // + int result = -1; + + // + time = NormalizeTime(time); + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + result = iBarShift( + symbol, + period, + time // + ); + + // + return result; + } + + /** + * Detect Market Structure Method 2 ... + * + * @param model: XMarketStructure instance Reference ... + * + * @return ( bool ) + */ + bool DetectMarketStructure( + ENUM_X_DIRECTION &dir, + int pivotsCount = 3 // + ) + { + // + bool result = false; + + // + int barIndex = 0; + + // + if (pivotsCount < 3) + { + pivotsCount = 3; + } + + // + dir = X_DIRECTION_NONE; + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + int hpIndex = -1; + int hpIndexes[]; + double hpValues[]; + + // + int lvIndex = -1; + int lvIndexes[]; + double lvValues[]; + + // + for (int i = 0; i < pivotsCount; i++) + { + // + hpIndex = barIndex; + lvIndex = barIndex; + + // + double lastHP = 0; + double lastLV = 0; + + // + int hpCount = ArraySize(hpIndexes); + int lvCount = ArraySize(lvIndexes); + + // + if (IsValidSize(hpCount)) + { + // + lastHP = hpValues[hpCount - 1]; + hpIndex = hpIndexes[hpCount - 1]; + } + + // + if (IsValidSize(lvCount)) + { + // + lastLV = lvValues[lvCount - 1]; + lvIndex = lvIndexes[lvCount - 1]; + } + + // + if (lastHP == 0) + { + // + lastHP = mX121Helper + .xpvHelper + .GetPeak(hpIndex); + } + + // + if (lastLV == 0) + { + // + lastLV = mX121Helper + .xpvHelper + .GetVale(lvIndex); + } + + // + int highestPeakIndex = -1; + double highesrPeak = + mX121Helper + .xpvHelper + .GetHigherPeak( + highestPeakIndex, + lastHP, + hpIndex // + ); + if (IsValidIndex(highestPeakIndex)) + { + // + Add( + highestPeakIndex, + hpIndexes // + ); + + // + Add( + highesrPeak, + hpValues // + ); + } + + // + int lowestValeIndex = -1; + double lowestVale = + mX121Helper + .xpvHelper + .GetLowerVale( + lowestValeIndex, + lastLV, + lvIndex // + ); + if (IsValidIndex(lowestValeIndex)) + { + // + Add( + lowestValeIndex, + lvIndexes // + ); + + // + Add( + lowestVale, + lvValues // + ); + } + + // + bool canBreak = ArraySize(hpIndexes) >= pivotsCount || + ArraySize(lvIndexes) >= pivotsCount; + if (canBreak) + { + break; + } + } + + // + ArrayReverse(hpValues); + ArrayReverse(hpIndexes); + int countHPs = ArraySize(hpIndexes); + + // + ArrayReverse(lvValues); + ArrayReverse(lvIndexes); + int countLVs = ArraySize(lvIndexes); + + // + bool isValidHPs = countHPs >= pivotsCount; + bool isValidLVs = countLVs >= pivotsCount; + + // + result = isValidHPs || + isValidLVs; + if (!result) + { + return result; + } + + // + if (isValidHPs && isValidLVs) + { + // + hpIndex = hpIndexes[countHPs - 1]; + lvIndex = lvIndexes[countLVs - 1]; + } + + // + dir = + !isValidHPs && isValidLVs + ? X_DIRECTION_BULLISH + : !isValidLVs && isValidHPs + ? X_DIRECTION_BEARISH + : hpIndex < lvIndex + ? X_DIRECTION_BEARISH + : lvIndex < hpIndex + ? X_DIRECTION_BULLISH + : X_DIRECTION_ALL; + + // + return result; + } + + /** + * Detect Order Blocks ... + * + * @return ( int ) + */ + bool DetectOrderBlocks( + XCOrderBlock *&bullishOrderBlocks[], + XCOrderBlock *&bearishOrderBlocks[] // + ) + { + // + bool result = false; + + // + Clean(bullishOrderBlocks); + Clean(bearishOrderBlocks); + + // + XPOIState state; + mPOIDetector.GetState(state); + bool isValid = state.IsValid() && + state.HasChild(); + if (!isValid) + { + return result; + } + + // + int bullOBsCount = DetectDirectionOrderBlocks( + X_DIRECTION_BULLISH, + state, + bullishOrderBlocks // + ); + + // + int bearOBsCount = DetectDirectionOrderBlocks( + X_DIRECTION_BEARISH, + state, + bearishOrderBlocks // + ); + + // + result = IsValidSize(bullOBsCount + + bearOBsCount); + + // + return result; + } + + /** + * Retrieve Cycle Conditions ... + * + * @param events: ENUM_X_CYCLE_EVENTS member, Array ... + * @param conditions: X121SMCCycleConditions instance ... + * @param barIndex: Integer ... + * @param loopback: Integer ... + * + * @return ( bool ) + */ + bool GetConditions( + ENUM_X_CYCLE_EVENTS &events[], + ENUM_XPOI_EVENTS &poiEvents[], + X121SMCCycleConditions &conditions, + int barIndex = 0, + int loopback = 7 // + ) + { + // + bool result = false; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (loopback < 5) + { + loopback = 5; + } + + // + Clean(events); + Clean(poiEvents); + conditions.Clean(); + + // + result = mX121Helper.GetConditions( + conditions.x121Conditions, + barIndex, + loopback // + ); + if (!result) + { + // + conditions.Clean(); + return result; + } + + // + mPOIDetector.Update(poiEvents); + mPOIDetector.GetState(conditions.state); + + // + conditions.symbol = conditions.x121Conditions.symbol; + conditions.period = conditions.x121Conditions.period; + conditions.time = TimeCurrent(); + + // + result = conditions.IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Virtuals ... + + /** + * Set Default Properties Values ... + */ + virtual void Default() + { + } + + // + protected: + // + + // + private: + // + // Props ... + + // + // Actions ... + + /** + * Release All Resources ... + */ + void DeInit() + { + // + delete mX121Helper; + delete mPOIDetector; + delete mBarAnalyser; + } + + /** + * Apply Chart Style ... + */ + void ApplyChartStyle() + { + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + + // + ENUM_CHART_MODE mMode = CHART_CANDLES; // chart's mMode + bool mShowBidLine = true; // show bid line + bool mShowAskLine = true; // show ask line + bool mShowGrid = false; // show grids on chart + bool mShowVolumes = false; // show volumes + bool mShowTradeLevels = true; // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true; // chart autoscroll + bool mQuickNavigation = true; // chart quick navigation state + color mForeGroundColor = clrWhite; // chart's foreground color + color mBackGroundColor = clrBlack; // chart's background color + color mUpColor = clrGreen; // Up Color + color mDownColor = clrRed; // Down Color + color mBullishColor = clrGreen; // Bullish color + color mBearishColor = clrRed; // Bearish color + color mGridColor = clrGray; // grid color + color mBidLineColor = clrGray; // bid line color + color mAskLineColor = clrRed; // ask line color + color mLineColor = clrLime; // line mMode and doji candlestick color + color mStopColor = clrGold; // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen; // volumes color + + // + ChartSetInteger(chartId, CHART_MODE, mMode); + ChartSetInteger(chartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(chartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(chartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(chartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(chartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(chartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(chartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(chartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(chartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(chartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(chartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(chartId, CHART_COLOR_VOLUME, mVolumesColor); + } + + // +}; diff --git a/BKPS/14031106/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 new file mode 100644 index 0000000..7dfb754 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 @@ -0,0 +1,4336 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCX121SMCTradeHandler +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../../Classes/x-saherelm.x-alert.class.mq5" +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../../Classes/x-saherelm.x-trade.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... + +// +// Model a Trade Data ... +struct X121SMCTradeData +{ + // + double ask; // Ask Price on Start Time + double bid; // bid Price on Start Time + ulong ticket; // Position Ticket + double swap; // Swap + double profit; // Profit on Close + XSignal signal; // Signal Object + string message; // Message + datetime endTime; // End Time + datetime startTime; // Start Time + double commission; // Commission + string conditions; // Signal Conditions + double maxDrawdown; // Max Position Drawdown + bool isTargeted; // Check Targetted Before Or Not + + // + // Constructor ... + X121SMCTradeData() + { + Clean(); + } + + /** + * Initialize Item ... + * + * @param _signal: XSignal instance Reference, Provides Source For Initializaion ... + * + * @return ( bool ) + */ + bool Init(XSignal &_signal) + { + // + bool result = false; + + // + Clean(); + + // + result = _signal.IsValid(); + if (!result) + { + return result; + } + + // + signal = _signal; + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + /** + * Cleaning Up Model ... + */ + void Clean() + { + // + ask = 0; + bid = 0; + swap = 0; + profit = 0; + ticket = 0; + commission = 0; + maxDrawdown = 0; + + // + endTime = NULL; + message = NULL; + startTime = NULL; + conditions = NULL; + + // + isTargeted = false; + + // + signal.Clean(); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + signal.IsValid() + // + ; + + // + return result; + } + + /** + * Calculate Model Age ... + * + * @return ( int ) + */ + int GetAge() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + int startIndex = iBarShift( + GetSymbol(), + GetPeriod(), + startTime, + false // + ); + + // + datetime mEndTime = IsValid(endTime) + ? endTime + : TimeCurrent(); + int endIndex = iBarShift( + GetSymbol(), + GetPeriod(), + mEndTime, + false // + ); + + // + result = MathAbs(startIndex - endIndex); + + // + return result; + } + + // + // Owner Functions ... + + /** + * Check a Ticket is Own to Model or not ... + * + * @param _ticket: ULONG, Position Ticket ... + * + * @return ( bool ) + */ + bool IsOwn( + ulong _ticket // + ) + { + // + bool result = false; + + // + result = IsValid() && + _ticket == ticket; + + // + return result; + } + + /** + * Check Specified Conditions is Own to Model or not ... + * + * @param _symbol: String, Specified Symbol ... + * @param _provider: String, Specified Provider ... + * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... + * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... + * + * @return ( bool ) + */ + bool IsOwnSignalTime( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type, + datetime _time // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_time) && + Time() == _time && + IsValid(_symbol) && + IsValid(_period) && + XType() == _type && + IsValid(_provider) && + GetPeriod() == _period && + GetSymbol() == _symbol && + Provider() == _provider && + XType() != X_POSITION_TYPE_ALL && + XType() != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + /** + * Check Specified Conditions is Own to Model or not ... + * + * @param _symbol: String, Specified Symbol ... + * @param _provider: String, Specified Provider ... + * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... + * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... + * + * @return ( bool ) + */ + bool IsOwnStartTime( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type, + datetime _time // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_time) && + IsValid(_symbol) && + IsValid(_period) && + XType() == _type && + IsValid(startTime) && + startTime == _time && + IsValid(_provider) && + GetPeriod() == _period && + GetSymbol() == _symbol && + Provider() == _provider && + XType() != X_POSITION_TYPE_ALL && + XType() != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + /** + * Check Specified Signal is Own to Model or not ... + * + * @param _signal: XSignal instance Reference ... + * + * @return ( bool ) + */ + bool IsOwn(XSignal &_signal) + { + // + bool result = false; + + // + result = + // + IsValid() && + _signal.IsValid() && + IsOwnSignalTime( + _signal.symbol, + _signal.provider, + _signal.period, + ToPositionType(_signal.type), + _signal.time) + // + ; + + // + return result; + } + + /** + * Check Specified Position is Own to Model or not ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool IsOwn(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwnStartTime( + _position.symbol, + _position.provider, + _position.period, + ToPositionType(_position.type), + _position.openAt) + // + ; + + // + return result; + } + + /** + * Check Specified Position is Own to Model or not ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool IsOwnPosition(XPosition &_position) + { + // + bool result = false; + + // + double tp = TP(); + double sl = SL(); + double entry = Entry(); + double volume = Volume(); + string symbol = GetSymbol(); + string provider = Provider(); + ENUM_POSITION_TYPE type = Type(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + double pVolume = _position.volume; + double pSL = NormalizePrice(_position.sl, _position.symbol); + double pTP = NormalizePrice(_position.tp, _position.symbol); + double pEntry = NormalizePrice(_position.entry, _position.symbol); + + // + result = + // + IsValid() && + (sl == pSL || + tp == pTP) && + entry == pEntry && + pVolume == volume && + _position.IsValid() && + type == _position.type && + symbol == _position.symbol && + period == _position.period && + provider == _position.provider + // + ; + + // + if (!result) + { + // + result = + // + IsValid() && + _position.IsValid() && + _position.ticket == signal.positionId; + } + + // + return result; + } + + /** + * Update Model Data by Providing Specified Signal ... + * + * @param _signal: XSignal instance Reference ... + * + * @return ( bool ) + */ + bool Update(XSignal &_signal) + { + // + bool result = false; + + // + result = + // + IsValid() && + _signal.IsValid() && + IsOwn(_signal) + // + ; + if (!result) + { + return result; + } + + // + signal = _signal; + + // + return result; + } + + /** + * Update Model Data by Providing Specified Position ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool Update(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwn(_position) + // + ; + if (!result) + { + return result; + } + + // + swap = _position.swap; + ticket = _position.ticket; + profit = _position.profit; + message = _position.comment; + startTime = _position.openAt; + + // + // Set Once ... + if (commission == 0 && + _position.commission != 0) + { + commission = _position.commission; + } + + // + // Set Once ... + if (ask == 0) + { + ask = GetAsk(_position.symbol); + } + + // + // Set Once ... + if (bid == 0) + { + bid = GetBid(_position.symbol); + } + + // + if (profit < 0 && profit < maxDrawdown) + { + maxDrawdown = profit; + } + + // + return result; + } + + /** + * Update Model Data by Providing Specified Position ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool UpdatePosition(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwnPosition(_position) + // + ; + if (!result) + { + return result; + } + + // + swap = _position.swap; + ticket = _position.ticket; + profit = _position.profit; + message = _position.comment; + startTime = _position.openAt; + + // + // Set Once ... + if (commission == 0 && + _position.commission != 0) + { + commission = _position.commission; + } + + // + // Set Once ... + if (ask == 0) + { + ask = GetAsk(_position.symbol); + } + + // + // Set Once ... + if (bid == 0) + { + bid = GetBid(_position.symbol); + } + + // + if (profit < 0 && profit < maxDrawdown) + { + maxDrawdown = profit; + } + + // + return result; + } + + // + // Tools Extensions ... + + /** + * Get Model Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return signal.symbol; + } + + /** + * Get Model Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return signal.period; + } + + /** + * Get Model Provider ... + * + * @return ( string ) + */ + string Provider() + { + return signal.provider; + } + + /** + * Get Model Entry ... + * + * @return ( double ) + */ + double Entry() + { + return signal.entry; + } + + /** + * Get Model Stop Loss ... + * + * @return ( double ) + */ + double SL() + { + return signal.sl; + } + + /** + * Get Model Take Profit ... + * + * @return ( double ) + */ + double TP() + { + return signal.tp; + } + + /** + * Get Model Target ... + * + * @return ( double ) + */ + double Target() + { + return signal.target; + } + + /** + * Get Position Spread on Open Time ... + * + * @return ( double ) + */ + double Spread() + { + return MathAbs(ask - bid); + } + + /** + * Get Model Volume ... + * + * @return ( double ) + */ + double Volume() + { + return signal.volume; + } + + /** + * Get Model Point Value ... + * + * @return ( double ) + */ + double Points() + { + return GetPoints(GetSymbol()); + } + + /** + * Get Model Type ... + * + * @return ( ENUM_POSITION_TYPE ) + */ + ENUM_POSITION_TYPE Type() + { + return signal.type; + } + + /** + * Get Model Type ... + * + * @return ( ENUM_X_POSITION_TYPES ) + */ + ENUM_X_POSITION_TYPES XType() + { + // + ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsLong(Type()) + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + return result; + } + + /** + * Get Model Signal Mode ... + * + * @return ( ENUM_X_ORDER_MODES ) + */ + ENUM_X_ORDER_MODES Mode() + { + return signal.mode; + } + + /** + * Get Model Signal Time ... + * + * @return ( datetime ) + */ + datetime Time() + { + return signal.time; + } + + // + // Additional Helpers Extensions ... + + /** + * Get Signal Full TP Level ... + * + * @return ( double ) + */ + double FullTPLevel() + { + return signal.fullTPLevel; + } + + /** + * Check Can Partial Close Position or not ... + * + * @return ( bool ) + */ + bool CanPartialClose() + { + return signal.CanPartialClose(); + } + + /** + * Retrieve Partial Close Volume Multiplier ... + * + * @return ( double ) + */ + double PartialCloseMultiplier() + { + return signal.partialCloseMultiplier; + } + + /** + * Get Partial Close On TP Level ... + * + * @return ( double ) + */ + double PartialCloseOnTPLevel() + { + return signal.partialCloseOnTPLevel; + } + + /** + * Check Can Risk Free Position on Break Even Point or not ... + * + * @return ( bool ) + */ + bool CanRiskFreeOnBreakEvenPoint() + { + return signal.CanRiskFreeOnBreakEvenPoint(); + } + + /** + * Get Minimum Required Profit after Break Even Point for Risk Free ... + * + * @return ( double ) + */ + double TPLevelForBreakEven() + { + return signal.tpLevelForBreakEven; + } + + /** + * Calculate Break Even Point ... + * + * @return ( double ) + */ + double CalculateBreakEvenPoint() + { + // + double result = 0; + + // + bool isValid = + // + ask > 0 && + bid > 0 && + IsValid() && + ticket > 0 && + signal.IsValid() + // + ; + if (!isValid) + { + return result; + } + + // + // Calculate Spread ... + double spread = Spread(); + if (spread <= 0) + { + return result; + } + + // + // Calculate BEP ... + result = + // + spread + (-1 * swap) + MathAbs(commission) + // + ; + + // + return result; + } + + /** + * Check Can Trail Position Stop Loss or not ... + * + * @return ( bool ) + */ + bool CanTrailSL() + { + return signal.CanTrailSL(); + } + + /** + * Get Start Position SL Trailling on TP Level ... + * + * @return ( double ) + */ + double TrailSLStartOnReachTPLevel() + { + return signal.trailSLStartOnReachTPLevel; + } + + // + // Data Collector Extensions ... + + /** + * Get Data Collection File Name ... + * + * @return ( string ) + */ + string GetFileName() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetSymbol() + "\\" + + ToString(XType()) + "\\" + + (profit >= 0 ? "Profit" : "Loss") + "\\" + + ToString(ticket) + "_" + + ToString(GetPeriod()) + "_" + + ToFormatString(startTime) + // + ; + + // + return result; + } + + /** + * Get Signal Collectiong File Name ... + * + * @return ( string ) + */ + string GetSignalFileName() + { + // + string result = NULL; + + // + result = + // + GetSymbol() + "\\" + + ToString(XType()) + "\\" + + Provider() + "_" + + ToFormatString(startTime) + // + ; + + // + return result; + } + + /** + * Converts Model to String Representation ... + * + * @param onlySignals: Boolean, Specified Represent Only Signal or not ... + * + * @return ( string ) + */ + string ToString( + bool onlySignals = false // + ) + { + // + string result = NULL; + + // + int age = GetAge(); + + // + result = + // + (onlySignals ? "" : ToString("Ticket", ticket)) + + ToString("Symbol", GetSymbol()) + + ToString("Period", GetPeriod()) + + ToString("Entry", Entry()) + + ToString("Provider", Provider()) + + ToString("Type", ToString(XType())) + + ToString("Time", startTime) + + // + // Attach Trade Info ... + (onlySignals ? "" : + // + "-------------" + "\n" + + ToString("Volume", Volume()) + + ToString("Profit", profit) + + ToString("Commission", commission) + + ToString("Swap", swap) + + ToString("Max Drawdown", maxDrawdown) + + ToString("End Time", endTime) + + ToString("Age", age) + + ToString("Message", message) + + "" + // + ) + + // + // Attach Conditions to Signals ... + (!onlySignals ? "" : + // + "-------------" + "\n" + + ToString("Pushers", signal.pushers) + + "Conditions:" + "\n" + + "-------------" + "\n" + + conditions + + "" + // + ) + + // + "" + // + ; + + // + return result; + } + + // + // End Of X121SMCTradeData Model ... +}; + +// +// Model Specified Symbol's Positions States ... +struct X121SMCSymbolPositionInfo +{ + // + string symbol; + + // + datetime enableAt; + + // + int longSLs; + int longTPs; + + // + int shortSLs; + int shortTPs; + + // + int countedSLs; + + // + // Constructor ... + X121SMCSymbolPositionInfo() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + longSLs = 0; + longTPs = 0; + + // + shortSLs = 0; + shortTPs = 0; + + // + countedSLs = 0; + + // + enableAt = NULL; + } + + /** + * Check is own Symbol Info ... + * + * @param _symbol: String ... + * + * @return ( bool ) + */ + bool IsOwn(string _symbol) + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + _symbol == symbol + // + ; + + // + return result; + } + + /** + * Check Symbol Trading is Enable or not ... + * + * @param time: DateTime ... + * + * @return ( bool ) + */ + bool IsEnable(datetime time = NULL) + { + // + bool result = false; + + // + time = NormalizeTime(time); + + // + bool isEnableAtValid = IsValid(enableAt); + + // + result = + !isEnableAtValid + ? true + : time > enableAt; + if (result && + isEnableAtValid) + { + Reset(); + } + + // + return result; + } + + /** + * Pause Symbol Trading ... + * + * @param seconds: Integer ... + */ + void Pause(int seconds) + { + // + if (seconds <= 0) + { + return; + } + + // + datetime _enableAt = ((datetime)((int)TimeCurrent() + seconds)); + enableAt = _enableAt; + } + + /** + * Handle Stop Loss ... + * + * @param _type: ENUM_POSITION_TYPE member ... + */ + void HandleSL(ENUM_POSITION_TYPE _type) + { + // + bool isLong = IsLong(_type); + if (isLong) + { + longSLs++; + } + else + { + shortSLs++; + } + + // + countedSLs++; + } + + /** + * Handle Take Profit ... + * + * @param _type: ENUM_POSITION_TYPE member ... + */ + void HandleTP(ENUM_POSITION_TYPE _type) + { + // + bool isLong = IsLong(_type); + if (isLong) + { + longTPs++; + } + else + { + shortTPs++; + } + + // + countedSLs--; + if (countedSLs < 0) + { + countedSLs = 0; + } + } + + /** + * Reset Counter ... + */ + void Reset() + { + // + countedSLs = 0; + enableAt = NULL; + } + + // + // End of X121SMCSymbolPositionInfo Model ... +}; + +// +// Implementations ... + +// +// a Class For Read and Write Trade Info Data in Files ... +class X121SMCTradeCollector +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor(s) ... + X121SMCTradeCollector( + string _path = NULL // Base Path + ) + { + // + mAccount = new XCAccount(); + + // + if (IsValid(_path)) + { + mPath = _path; + } + else + { + mPath = "X121SMCTradeData" + "\\" + mAccount.GetCompany(); + } + } + + // + // Deconstructor ... + ~X121SMCTradeCollector() + { + } + + /** + * Check Specified Model is Exists or not ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool IsExists(X121SMCTradeData &item) + { + // + bool result = false; + + // + int mHandler = GetFileHandlerForRead(item); + result = mHandler != INVALID_HANDLE; + FileClose(mHandler); + + // + return result; + } + + /** + * Save Specified Model as Data ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool Save(X121SMCTradeData &item) + { + // + bool result = false; + + // + // Check info is Valid ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + string content = item.ToString(); + content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true); + + // + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + /** + * Save Specified Model as Signal ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool SaveSignal(X121SMCTradeData &item) + { + // + bool result = false; + + // + string content = item.ToString(true); + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetSignalFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + /** + * Save Specified Model Conditions ... + * Conditions only save for Loss Signals ... + * this means the profit must be Lower than Zero ... + * ans also message Contains SL ... + * + * @param item: X121SMCTradeData instance Reference, Provides Source Model ... + * + * @return ( bool ) + */ + bool SaveConditions(X121SMCTradeData &item) + { + // + bool result = false; + + // + // Validate Item ... + result = + // + item.profit < 0 && + Contains("SL", item.message) + // + ; + if (!result) + { + return result; + } + + // + string content = item.signal.conditions; + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetConditionsFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileSeek(mHandler, 0, SEEK_END); + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + + // + string mPath; // Base Path ... + + // + XCAccount *mAccount; + + // + string GetFilePath(X121SMCTradeData &item) + { + // + string fileName = item.GetFileName(); + + // + return GetFilePath(fileName); + } + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetSignalFilePath(X121SMCTradeData &item) + { + // + string fileName = item.GetSignalFileName(); + + // + return GetSignalFilePath(fileName); + } + string GetSignalFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetConditionsFilePath(X121SMCTradeData &item) + { + // + bool isLong = IsLong(item.Type()); + + // + string fileName = + item.GetSymbol() + "\\" + + (isLong ? "Longs" : "Shorts"); + + // + return GetConditionsFilePath(fileName); + } + string GetConditionsFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + int GetFileHandlerForRead(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetFileHandlerForWrite(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetSignalFileHandlerForRead(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetSignalFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetSignalFileHandlerForWrite(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetSignalFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetConditionsFileHandlerForRead(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetConditionsFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetConditionsFileHandlerForWrite(X121SMCTradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetConditionsFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + // End of X121SMCTradeCollector Class ... +}; + +// +// Trade Handler Class ... +// a Class For Handling All Trade Requirements ... +class XC121SMCTradeHandler : public XCBaseAlert +{ + // + // Public ... + public: + // + + // + // Constructor(s) ... + XC121SMCTradeHandler(XCTrade *trader) + { + // + mTrader = trader; + mAdditionalVolume = 0; + mCollector = new X121SMCTradeCollector(); + } + + // + // Deconstructor ... + ~XC121SMCTradeHandler() + { + // + ArrayFree(mData); + ArrayFree(mSymbolInfos); + ArrayFree(mLastExecutedSignals); + + // + delete mDrawer; + + // + delete mTrader; + delete mCollector; + } + + // + // ReadOnly Props ... + + /** + * Get Max Same Time Trades ... + * + * @return ( double ) + */ + double GetMaxSameTimeTrades() + { + return maxSameTimeTrades; + } + + /** + * Get Max Drawdown Happens ... + * + * @return ( double ) + */ + double GetMaxDrawdown() + { + return maxDrawdown; + } + + /** + * Get Currently Drawdown of Account ... + * + * @return ( double ) + */ + double GetCurrentDrawdown() + { + return currentDrawdown; + } + + /** + * Get Account Current Drawdown Percent ... + * + * @return ( double ) + */ + double GetDrawdownPercent() + { + return drawdownPercent; + } + + // + // Properties Getter(s) / Setter(s) ... + + // + // Saving Properties ... + + /** + * Get Save Signals State ... + * + * @return ( bool ) + */ + bool SaveSignals() + { + return mSaveSignals; + } + + /** + * Set Save Signals State ... + * + * @param value: Boolean ... + */ + void SaveSignals(bool value) + { + mSaveSignals = value; + } + + /** + * Get Save Trades State ... + * + * @return ( bool ) + */ + bool SaveTrades() + { + return mSaveTrades; + } + + /** + * Set Save Trades State ... + * + * @param value: Boolean ... + */ + void SaveTrades(bool value) + { + mSaveTrades = value; + } + + /** + * Get Save Conditions State ... + * + * @return ( bool ) + */ + bool SaveConditions() + { + return mSaveConditions; + } + + /** + * Set Save Conditions State ... + * + * @param value: Boolean ... + */ + void SaveConditions(bool value) + { + mSaveConditions = value; + } + + // + // Signalling Props ... + + /** + * Get Allow Long Signals State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Allow Long Signals State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + mAllowLong = value; + } + + /** + * Get Allow Short Signals State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Allow Short Signals State ... + * + * @param value: Boolean ... + */ + void AllowShort(bool value) + { + mAllowShort = value; + } + + /** + * Get Max Allowed Long Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedLongs() + { + return mMaxAllowedLongs; + } + + /** + * Set Max Allowed Long Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedLongs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedLongs = value; + } + + /** + * Get Max Allowed Short Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedShorts() + { + return mMaxAllowedShorts; + } + + /** + * Set Max Allowed Short Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedShorts(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedShorts = value; + } + + /** + * Get Use Max Allowed Signal Types Per Symbol State ... + * + * @return ( bool ) + */ + bool UseMaxAllowedSignalsPerSymbol() + { + return mUseMaxAllowedSignalsPerSymbol; + } + + /** + * Set Use Max Allowed Signal Types Per Symbol State ... + * + * @param value: Boolean ... + */ + void UseMaxAllowedSignalsPerSymbol(bool value) + { + mUseMaxAllowedSignalsPerSymbol = false; + } + + /** + * Get Last Position Profit In Points for Accept new Signal ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double LastPositionProfitForAcceptNextInPoint() + { + return mLastPositionProfitForAcceptNextInPoint; + } + + /** + * Set Last Position Profit In Points for Accept new Signal ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void LastPositionProfitForAcceptNextInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mLastPositionProfitForAcceptNextInPoint = value; + } + + /** + * Get Delay between two Signals in Bars ... + * 0 => Accept All ... + * + * @return ( int ) + */ + int DelaysBetweenTwoSignalsInBar() + { + return mDelaysBetweenTwoSignalsInBar; + } + + /** + * Set Delay between two Signals in Bars ... + * + * @param value: Integer ... + * 0 => Accept All ... + */ + void DelaysBetweenTwoSignalsInBar(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDelaysBetweenTwoSignalsInBar = value; + } + + /** + * Get Max Allowed Spread for Signalling ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread for Signalling ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void MaxAllowedSpread(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSpread = value; + } + + /** + * Get Additional Signal Volume ... + * + * @return ( double ) + */ + double AdditionalVolume() + { + return mAdditionalVolume; + } + + /** + * Set Additional Signal Volume ... + * + * @param value: Double ... + * min = 0.01 + */ + void AdditionalVolume(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 0 && value < 0.01) + { + value = 0.01; + } + + // + mAdditionalVolume = value; + } + + // + // Risk Management Props ... + + /** + * Get Max Allowed Drawdown Percent for Open Trades ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + * + * @return ( double ) + */ + double MaxAllowedDrawdownToOpenTrades() + { + return mMaxAllowedDrawdownToOpenTrades; + } + + /** + * Set Max Allowed Drawdown Percent for Open Trades ... + * + * @param value: Double ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + */ + void MaxAllowedDrawdownToOpenTrades(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 50) + { + value = 50; + } + + // + mMaxAllowedDrawdownToOpenTrades = value; + } + + /** + * Get Max Allowed SL for Pause Signalling Per Symbol ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedSLToPauseSignallingPerSymbol() + { + return mMaxAllowedSLToPauseSignallingPerSymbol; + } + + /** + * Set Max Allowed SL for Pause Signalling Per Symbol ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedSLToPauseSignallingPerSymbol(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSLToPauseSignallingPerSymbol = value; + } + + /** + * Get Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int PauseSignallingAfterReachesMaxAllowedSLInSecconds() + { + return mPauseSignallingAfterReachesMaxAllowedSLInSecconds; + } + + /** + * Set Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void PauseSignallingAfterReachesMaxAllowedSLInSecconds(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPauseSignallingAfterReachesMaxAllowedSLInSecconds = value; + } + + // + // Protection Props ... + + /** + * Get Allow Hedge Positions State ... + * + * @return ( bool ) + */ + bool AllowHedging() + { + return mAllowHedging; + } + + /** + * Set Allow Hedge Positions State ... + * + * @param value: Boolean ... + */ + void AllowHedging(bool value) + { + mAllowHedging = value; + } + + /** + * Get Minimum Open Positions for Hedging ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int MinOpenTradesFroHedging() + { + return mMinOpenTradesFroHedging; + } + + /** + * Set Minimum Open Positions for Hedging ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void MinOpenTradesFroHedging(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinOpenTradesFroHedging = value; + } + + /** + * Get Minimum Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgingMinVolumeStep() + { + return mHedgingMinVolumeStep; + } + + /** + * Set Minimum Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgingMinVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 0 && value < 0.01) + { + value = 0.01; + } + + // + if (value > 0 && value > 0.1) + { + value = 0.1; + } + + // + mHedgingMinVolumeStep = value; + } + + /** + * Get Minimum Required Profit Per Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgeingMinRequiredProfitPerVolumeStep() + { + return mHedgeingMinRequiredProfitPerVolumeStep; + } + + /** + * Set Minimum Required Profit Per Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgeingMinRequiredProfitPerVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mHedgeingMinRequiredProfitPerVolumeStep = value; + } + + /** + * Get POI Drawer instance Pointer ... + */ + XCPOIDrawer *GetDrawer() + { + return mDrawer; + } + + /** + * Get POI Drawer instance Pointer ... + */ + void SetDrawer(XCPOIDrawer *drawer) + { + mDrawer = drawer; + } + + /** + * Check Darwer Exists Before Draw anything ... + * + * @return ( bool ) + */ + bool CanDraw() + { + return mDrawer != NULL; + } + + // + // Actions ... + + // + // Data Collection Actions ... + + /** + * Add Executed Signal Data Model to Trade Datas ... + * + * @param signal: XSignal instance Reference, Issued Signal ... + */ + void Add(XSignal &signal) + { + // + // Check Signal is Valid and also not Exists + // in Datas ... + int idx = -1; + bool hasItem = HasItem( + signal, + idx // + ); + if (hasItem) + { + return; + } + + // + // Initialize Data Item and Add it to Collection of Datas + // if Everythings OK ... + X121SMCTradeData data; + bool isInited = data.Init(signal); + if (isInited) + { + // + Add(data); + SaveSignal(data); + } + } + + /** + * Update a Registered Data Model by Providing Specified Signal ... + * usually used When a signal Modified after Executed for Conditionally Signals ... + * + * @param signal: XSignal instance Reference, Issued Signal ... + */ + void Update(XSignal &signal) + { + // + // Validate Signal ... + if (!signal.IsValid()) + { + return; + } + + // + // Check Signal Registered Before ... + int idx = -1; + bool hasItem = HasItem( + signal, + idx // + ); + bool isUpdated = false; + if (!hasItem) + { + // + // Add New Item if not Exists ... + Add(signal); + isUpdated = true; + } + else + { + // + // Update Data Model in Datas Collection ... + isUpdated = mData[idx].Update(signal); + } + + // + if (isUpdated) + { + SaveSignal(mData[idx]); + } + } + + /** + * Update a Registered Data Model by Providing Specified Position ... + * used for Updating Positions Data or When a Conditional Order Executed as Position ... + * + * @param position: XPosition instance Referece ... + */ + void Update(XPosition &position) + { + // + // Validate Position ... + if (!position.IsValid()) + { + return; + } + + // + // Check Position Registered Before ... + int idx = -1; + bool hasItem = HasItem( + position, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Data Model in Datas Collection ... + mData[idx].Update(position); + } + + /** + * Remove Specified Registered Signal from Data Collection ... + * + * @param signal: XSignal instance Reference ... + */ + void Remove(XSignal &signal) + { + // + // Validate Signal ... + if (!signal.IsValid()) + { + return; + } + + // + // Check Signal is Registered or not ... + int idx = -1; + bool hasItem = HasItem( + signal, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Remove Data From Collection ... + ArrayRemove( + mData, + idx, + 1 // + ); + } + + /** + * Handle Position Execution Finished by Providing a Deal ... + * usually used when a Position TP/SL Triggered ... + * + * @param deal: XDeal instance Reference ... + */ + void Finish(const XDeal &deal) + { + // + // Validate Deal ... + // Check Specified Data Registered or not ... + int idx = -1; + bool hasItem = HasItem( + deal.positionId, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Data Info ... + mData[idx].swap = deal.swap; + mData[idx].endTime = deal.time; + mData[idx].profit = deal.profit; + + // + // Check Deal Reason ... + bool isTP = deal.reason == DEAL_REASON_TP || + (deal.reason == DEAL_REASON_SL && deal.profit > 0); + bool isSL = deal.reason == DEAL_REASON_SL && deal.profit < 0; + + // + // Prepare Specified Message Based on Deal Reason ... + mData[idx].message = + isTP + ? "TP" + : isSL + ? "SL" + : ""; + + // + // Handle Symbol Positions TP or SL Actions ... + if (isTP || isSL) + { + // + // Check Symbol Position Info Model Exists ... + int symbolIDX = -1; + bool hasInfo = HasSymbol( + mData[idx].GetSymbol(), + symbolIDX // + ); + + // + // Try to Update or Add Symbol Position Info ... + X121SMCSymbolPositionInfo info; + if (!hasInfo) + { + // + // Add New One ... + info.symbol = mData[idx].GetSymbol(); + } + else + { + // + // Update Exists ... + info = mSymbolInfos[symbolIDX]; + + // + // Remove Exists ... + ArrayRemove( + mSymbolInfos, + symbolIDX, + 1 // + ); + } + + // + ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type()) + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + // Call Propper TP / SL Handlers on Symbol Position Info Model ... + if (isTP) + { + info.HandleTP(xType); + } + else if (isSL) + { + info.HandleSL(xType); + } + + // + // Add Model to Symbol Positions Collection ... + AddRef( + info, + mSymbolInfos // + ); + + // + // Try to Check Symbol Positions Info Collection for Pause Specified Symbol ... + HandlePauseSymbol(mData[idx].GetSymbol()); + } + + // + // Save Collector Calss Data Model ... + Save(idx); + } + + /** + * Handle Position Execution Finished by Providing some Data ... + * usually used when a Position Force Closed Triggered ... + * + * @param ticket: ULong, Position ticket ... + * @param position: XPosition instance Reference ... + * @param comment: String, Force Closing Comment ... + */ + void Finish( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + // Validate and Check Data Registered or not ... + int idx = -1; + bool hasItem = HasItem( + ticket, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Data Info ... + mData[idx].swap = position.swap; + mData[idx].endTime = TimeCurrent(); + mData[idx].profit = position.profit; + + // + mData[idx].message = comment; + + // + // Handle Force Closes as TP/SL for Updating + // Symbol Info Positions ... + bool handleForceClose = true; + if (handleForceClose) + { + // + // Simulate TP/SL based on Closing Profit ... + bool isTP = position.profit > 0; + bool isSL = position.profit <= 0; + + // + if (isTP || isSL) + { + // + // Check Symbol Position Info Model Exists ... + int symbolIDX = -1; + bool hasInfo = HasSymbol( + mData[idx].GetSymbol(), + symbolIDX // + ); + + // + // Try to Update or Add Symbol Position Info ... + X121SMCSymbolPositionInfo info; + if (!hasInfo) + { + // + // Add New One ... + info.symbol = mData[idx].GetSymbol(); + } + else + { + // + // Update Exists ... + info = mSymbolInfos[symbolIDX]; + + // + // Remove Exists ... + ArrayRemove( + mSymbolInfos, + symbolIDX, + 1 // + ); + } + + // + ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type()) + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + // Call Propper TP / SL Handlers on Symbol Position Info Model ... + if (isTP) + { + info.HandleTP(xType); + } + else if (isSL) + { + info.HandleSL(xType); + } + + // + // Add Model to Symbol Positions Collection ... + AddRef( + info, + mSymbolInfos // + ); + + // + // Try to Check Symbol Positions Info Collection for Pause Specified Symbol ... + HandlePauseSymbol(mData[idx].GetSymbol()); + } + + // + // Save Collector Calss Data Model ... + Save(idx); + } + } + + /** + * Update New Open Positions Data on Collection ... + */ + void HandleNewPosition() + { + // + // Retrieve Last Open Position ... + ulong lastOpenPositionTicket = mTrader.GetLastOpenPositionTicket(); + if (lastOpenPositionTicket == 0) + { + return; + } + + // + XPosition position; + bool hasPosition = mTrader.GetPosition( + lastOpenPositionTicket, + position // + ); + if (!hasPosition) + { + return; + } + + // + // Calculate Position Commission ... + double commission = mTrader.GetPositionCommission(position.ticket); + position.commission = commission; + + // + // Apply Updates on Data Collection ... + int idx = -1; + bool hasItem = HasItemByPosition( + position, + idx // + ); + if (!hasItem) + { + return; + } + + // + mData[idx].UpdatePosition(position); + } + + // + // Symbol Position Info Actions ... + + /** + * Retrieve Specified Symbols Info ... + * + * @param symbol: String ... + * @param info: X121SMCSymbolPositionInfo instance ... + * + * @return ( bool ) + */ + bool GetSymbolInfo( + string symbol, + X121SMCSymbolPositionInfo &info // + ) + { + // + bool result = false; + + // + info.Clean(); + + // + int symbolIDX = -1; + result = HasSymbol( + symbol, + symbolIDX // + ); + if (!result) + { + return result; + } + + // + info = mSymbolInfos[symbolIDX]; + + // + return result; + } + + /** + * Pause Specified Symbol Trading ... + * + * @param symbol: String ... + */ + void HandlePauseSymbol(string symbol) + { + // + if (!IsValid(symbol)) + { + return; + } + + // + int idx = -1; + bool hasItem = HasSymbol( + symbol, + idx // + ); + if (!hasItem) + { + return; + } + + // + int maxAllowedSLToPause = MaxAllowedSLToPauseSignallingPerSymbol(); + int pauseDelay = PauseSignallingAfterReachesMaxAllowedSLInSecconds(); + if (maxAllowedSLToPause <= 0 || pauseDelay <= 0) + { + return; + } + + // + bool canPauseSymbol = + mSymbolInfos[idx].IsEnable() && + mSymbolInfos[idx].countedSLs >= maxAllowedSLToPause; + if (!canPauseSymbol) + { + return; + } + + // + mSymbolInfos[idx].Pause(pauseDelay); + + // + string message = "Pause (" + symbol + ") until: (" + ToString(mSymbolInfos[idx].enableAt) + ") ..."; + Alert(message); + + // + } + + /** + * Reset Specified Symbol Info ... + * + * @param symbol: String ... + */ + void ResetSymbolInfo(string symbol) + { + // + if (!IsValid(symbol)) + { + return; + } + + // + int symbolIDX = -1; + bool hasSymbol = HasSymbol( + symbol, + symbolIDX // + ); + if (!hasSymbol) + { + return; + } + + // + mSymbolInfos[symbolIDX].Reset(); + + // + string message = "Reset " + symbol + ", Pause State ..."; + Alert(message); + } + + /** + * Reset All Paused Symbols ... + */ + void ResumePausedSymbols() + { + // + int count = ArraySize(mSymbolInfos); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mSymbolInfos[i].Reset(); + } + + // + string message = "Force Resume Paused Symbols ..."; + Alert(message); + } + + // + // Signal Execution Actions ... + + /** + * Validate Signal For Execution ... + * + * @param signal: XSignal instance Reference ... + * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... + * + * @return ( bool ) + */ + bool CanExecute( + XSignal &signal, + ENUM_X_SIGNAL_EXECUTION_RESULT &state // Execution State + ) + { + // + bool result = false; + + // + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + int symbolIDX = -1; + bool hasSymbolInfo = HasSymbol( + signal.symbol, + symbolIDX // + ); + + // + // Check rading Not Paused ... + result = + !hasSymbolInfo || + mSymbolInfos[symbolIDX].IsEnable(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + bool isLong = IsLong(signal.type); + + // + // Chekc Signalling Enable or not ... + result = + isLong + ? mAllowLong + : mAllowShort; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + // Check Signal is Support or not ... + bool isSupport = IsSupport(signal.comment); + result = !isSupport; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + ENUM_X_POSITION_TYPES pType = ToPositionType(signal.type); + double requiredProfitForAcceptNext = LastPositionProfitForAcceptNextInPoint(); + + // + // Implement Same Signal Conditions ... + XPosition smaeSymbolPositions[]; + int sameSymbolPositionsCount = mTrader.GetPositions( + smaeSymbolPositions, + signal.symbol, + signal.provider, + signal.period, + pType, + true, // Filter By Magic ... + true // Force Clean ... + ); + XPosition youngestSame; + int youngestSameAge = GetYoungest( + youngestSame, + smaeSymbolPositions // + ); + + // + double youngestSameProfitInPoint = youngestSame.GetProfitInPoint(); + + // + result = + sameSymbolPositionsCount == 0 || + (sameSymbolPositionsCount <= 0 + ? true + : requiredProfitForAcceptNext <= 0 + ? true + : youngestSameAge >= 0 && + youngestSameProfitInPoint >= requiredProfitForAcceptNext); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR; + return result; + } + + // + // Retrieve Longs and Shorts ... + XPosition longs[]; + XPosition shorts[]; + bool useMaxAllowedPositionsPerSymbol = UseMaxAllowedSignalsPerSymbol(); + + // + // Retrieve Positions ... + if (useMaxAllowedPositionsPerSymbol) + { + // + mTrader.GetPositions( + longs, + shorts, + signal.symbol, + signal.provider // + ); + } + else + { + // + mTrader.GetPositions( + longs, + shorts, + NULL, // All Symbols ... + signal.provider // + ); + } + + // + // Counting ... + int longsCount = ArraySize(longs); + int shortsCount = ArraySize(shorts); + + // + int maxAllowedLongs = MaxAllowedLongs(); + int maxAllowedShorts = MaxAllowedShorts(); + + // + // Check Max Allowed Positions ... + if (maxAllowedLongs > 0 || + maxAllowedShorts > 0) + { + // + if (isLong && maxAllowedLongs > 0 && longsCount > 0) + { + result = longsCount < maxAllowedLongs; + } + else if (!isLong && maxAllowedShorts > 0 && shortsCount > 0) + { + result = shortsCount < maxAllowedShorts; + } + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + } + + // + // Check Delays Bar if Provided ... + int delaysBarBetweenTwoSignal = DelaysBetweenTwoSignalsInBar(); + if (delaysBarBetweenTwoSignal > 0) + { + // + // Try To Detect Youngest Position ... + int youngestAge = 0; + XPosition youngestPosition; + + // + // Long Positions when there are Longs ... + if (isLong && longsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + longs // + ); + } + // + // Short Positions when there are Shorts ... + else if (!isLong && shortsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + shorts // + ); + } + + // + // Check Delays When Youngest Position Exists ... + if (youngestAge > 0 && youngestPosition.IsValid()) + { + // + result = youngestAge >= delaysBarBetweenTwoSignal; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; + return result; + } + } + + // + // Check Delays When Youngest Position is not Exists ... + if (!youngestPosition.IsValid()) + { + // + // Try to Detect Last Issued Signal in Model Collections ... + int symbolIDX = FindLastExecutedSignalItem(signal); + if (IsValidIndex(symbolIDX)) + { + // + // Calculate Requirements ... + datetime cTime = TimeCurrent(); + int signalPeriodSeconds = PeriodSeconds(signal.period); + datetime lastExecutedTime = mLastExecutedSignals[symbolIDX].time; + datetime passedTime = ((datetime)lastExecutedTime + + ((delaysBarBetweenTwoSignal * signalPeriodSeconds))); + + // + // Check Conditions ... + result = cTime >= passedTime; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; + return result; + } + } + } + } + + // + // Check Max Drawdown Percent for Open Trades ... + double maxAllowedDrawdownPercent = MaxAllowedDrawdownToOpenTrades(); + if (maxAllowedDrawdownPercent > 0) + { + // + // Calculate and Update Drawdown Percent ... + double cdPercent = CalculateMaxDrawdownPercent(); + + // + result = cdPercent < maxAllowedDrawdownPercent; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; + return result; + } + } + + // + // Check Spread ... + double spread = GetSpread(signal.symbol); + double maxAllowedSpread = MaxAllowedSpread(); + if (maxAllowedSpread > 0) + { + // + result = spread <= maxAllowedSpread; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_SPREAD; + return result; + } + } + + // + return result; + } + + /** + * Execute Specific Signal using Trade Handler ... + * + * @param signal: XSignal instance Reference ... + * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... + * @param ignorePolicies: Boolean ... + * + * @return ( bool ) + */ + bool ExecuteSignal( + XSignal &signal, // Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State + bool ignorePolicies = false // Ignore Execution Policies + ) + { + // + bool result = false; + + // + // Check Signal Validation ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + // Check Policies ... + if (!ignorePolicies) + { + // + // Filter Signals if Necessary ... + result = CanExecute( + signal, + state // + ); + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + + // + return result; + } + } + + // + // Apply Additional Volume to Signal if Provided ... + double additionalVolume = AdditionalVolume(); + if (additionalVolume > 0) + { + signal.volume += mAdditionalVolume; + } + + // + // Execute Signal ... + result = mTrader.ExecuteSignal( + signal, + state // + ); + if (result) + { + // + // Add XTradeHandler Data ... + Add(signal); + if (CanDraw()) + { + // + XCSignalObject *iObj; + mDrawer.DrawSignal(signal, iObj); + } + + // + // Handle Last Executed Signal ... + HandleSignalExecuted(signal); + + // + // Alert Executed Signal ... + string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " Executed Successfully ..."; + Alert(msg); + } + + // + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + } + + // + return result; + } + + /** + * Execute Specific Signal using Trade Handler ... + * + * @param signal: XSignal instance Reference ... + * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... + * @param ignorePolicies: Boolean ... + * + * @return ( bool ) + */ + bool ExecuteSignal( + XSignal &signal, // Signal for Execution + X121SMCStrategyConditions &conditions, // Signal Conditions + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State + bool ignorePolicies = false // Ignore Execution Policies + ) + { + // + bool result = false; + + // + // Check Signal Validation ... + result = signal.IsValid() && + conditions.IsValid(); + if (!result) + { + return result; + } + + // + // Check Policies ... + if (!ignorePolicies) + { + // + // Filter Signals if Necessary ... + result = CanExecute( + signal, + state // + ); + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + + // + return result; + } + } + + // + // Apply Additional Volume to Signal if Provided ... + double additionalVolume = AdditionalVolume(); + if (additionalVolume > 0) + { + signal.volume += mAdditionalVolume; + } + + // + // Execute Signal ... + result = mTrader.ExecuteSignal( + signal, + state // + ); + if (result) + { + // + // Add XTradeHandler Data ... + Add(signal); + if (CanDraw()) + { + // + XCSignalObject *iObj; + mDrawer.DrawSignal(signal, iObj); + } + + // + // Handle Last Executed Signal ... + HandleSignalExecuted(signal); + + // + // Alert Executed Signal ... + string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " Executed Successfully ..."; + Alert(msg); + } + + // + if (!result) + { + // + AlertSignalExecutionFailed( + signal, + state // + ); + } + + // + return result; + } + + /** + * Force Close Specified Positions ... + * + * @param symbol: String ... + * @param provider: String ... + * @param period: ENUM_TIMEFRAMES member ... + * @param type: ENUM_X_POSITION_TYPES member ... + * + * @return ( bool ) + */ + bool ForceClose( + string symbol = NULL, + string provider = NULL, + ENUM_TIMEFRAMES period = NULL, + ENUM_X_POSITION_TYPES type = NULL // + ) + { + // + bool result = false; + + // + XPosition positions[]; + int count = mTrader.GetPositions( + positions, + symbol, + provider, + period, + type // + ); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + datetime cTime = TimeCurrent(); + + // + string comment = "Force Close (" + ToString(count) + ") Positions At: " + ToFormatString(cTime) + "..."; + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + result = IsValidSize(closedPositionsCount); + if (result) + { + // + // Finish Positions and Clear Data ... + for (int i = 0; i < ArraySize(positions); i++) + { + // + XPosition iPosition = positions[i]; + Finish( + iPosition.ticket, + iPosition, + comment // + ); + } + + // + ResetProtections(); + + // + string message = "Force Close (" + ToString(count) + ") Positions At: " + + ToFormatString(cTime) + " Successfully ..."; + Alert(message); + } + + // + return result; + } + + /** + * Force Close Positions ... + * + * @return ( bool ) + */ + bool ForceClose( + XPosition &positions[], + string comment, + string notificationMessage // + ) + { + // + bool result = false; + + // + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + result = IsValidSize(closedPositionsCount); + if (result) + { + // + // Finish Positions and Clear Data ... + for (int i = 0; i < ArraySize(positions); i++) + { + // + XPosition iPosition = positions[i]; + Finish( + iPosition.ticket, + iPosition, + comment // + ); + } + + // + ResetProtections(); + + // + if (IsValid(notificationMessage)) + { + Alert(notificationMessage); + } + } + + // + return result; + + // + return result; + } + + // + // Timing Actions ... + + /** + * Update Currently Open Positions Info on Data Collection ... + */ + void UpdateData() + { + // + // Retrieve Positions ... + XPosition positions[]; + int count = mTrader.GetPositions(positions); + if (!IsValidSize(count)) + { + return; + } + + // + // Loop Through Positions ... + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + // Check Position Registered as Data or not ... + int idx = -1; + bool isExists = HasItem( + iPosition.ticket, + idx // + ); + if (isExists) + { + // + // Update Position Data ... + mData[idx].Update(iPosition); + } + } + } + + /** + * Handle Positiona Protections + */ + void HandleProtection() + { + // + // Implement Protection Senario Here ... + int count = Count(); + if (!IsValidSize(count)) + { + // + currentDrawdown = 0; + return; + } + + // + // Calculate Max Same Time Trades ... + maxSameTimeTrades = + maxSameTimeTrades == 0 || + maxSameTimeTrades < count + ? count + : maxSameTimeTrades; + + // + double bepSummary = 0; + double volumeSummary = 0; + double profitSummary = 0; + XPosition positions[]; + + // + // Loop through Open Positions ... + for (int i = 0; i < count; i++) + { + // + X121SMCTradeData iData = mData[i]; + + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iData.ticket, + iPosition // + ); + if (!hasPosition) + { + continue; + } + AddRef( + iPosition, + positions // + ); + + // + // Calculate Break Even Point ... + double entry = iPosition.entry; + double points = iData.Points(); + double volume = iPosition.volume; + bool isLong = IsLong(iData.Type()); + double spread = GetSpread(iData.GetSymbol()); + double bep = iData.CalculateBreakEvenPoint(); + double exitPrice = GetExit( + iPosition.symbol, + iPosition.type // + ); + + // + double tps[]; + double reachedTPLevel = -1; + double reachedTPPrice = 0; + int tpLevelsCount = iPosition.CalculateTPLevels(tps); + iPosition.CalculateReahedTP( + reachedTPLevel, + reachedTPPrice // + ); + + // + bepSummary += bep; + volumeSummary += volume; + profitSummary += iPosition.profit; + + // + // All Protections Done for InProfit Positions ... + if (iData.profit > 0) + { + // + // Check Break Even ... + bool canRFOnBEP = iData.CanRiskFreeOnBreakEvenPoint(); + if (canRFOnBEP && reachedTPLevel > 0) + { + // + double tpLevel = iData.TPLevelForBreakEven(); + int tpIDX = (int)tpLevel - 1; + double rfTPPrice = tps[tpIDX]; + bool isSLReady = isLong + ? iPosition.sl < rfTPPrice + : iPosition.sl > rfTPPrice; + if (isSLReady && tpLevel == reachedTPLevel - 1) + { + // + double sl = rfTPPrice; + double tp = iPosition.tp; + string comment = "RF on BEP ..."; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + string message = ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " RF On BEP Successfully ..."; + Alert(message); + } + } + } + + // + // Check Partial Close ... + bool canPartialClose = iData.CanPartialClose(); + if (canPartialClose && reachedTPLevel > 0) + { + // + double mainVolume = iData.Volume(); + double currentVolume = iPosition.volume; + double partialCloseOnTP = iData.PartialCloseOnTPLevel(); + double partialCloseVolumeMultiplier = iData.PartialCloseMultiplier(); + double closeVolume = currentVolume * partialCloseVolumeMultiplier; + closeVolume = NormalizeVolume(closeVolume, iPosition.symbol); + canPartialClose = + currentVolume == mainVolume && + reachedTPLevel == partialCloseOnTP; + if (canPartialClose) + { + // + string comment = "PC On TP Level: " + ToString(partialCloseOnTP) + " ..."; + bool isModified = mTrader.ClosePartial( + iData.ticket, + closeVolume, + comment // + ); + if (isModified) + { + // + string message = ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " PC (" + ToString(closeVolume) + ") On TP Level: " + + ToString(partialCloseOnTP) + " Successfully ..."; + Alert(message); + + // + // Finish Position ... + if (closeVolume == mainVolume) + { + // + Finish( + iPosition.ticket, + iPosition, + comment // + ); + + // + break; + } + } + } + } + + // + // Check for SL Trail ... + bool canTrailSL = iData.CanTrailSL(); + if (canTrailSL && reachedTPLevel > 0) + { + // + double startTrailTPLevel = iData.TrailSLStartOnReachTPLevel(); + int tSLTPIndex = (int)reachedTPLevel - 1; + double tSLTPPrice = tps[tSLTPIndex]; + canTrailSL = + reachedTPLevel >= startTrailTPLevel && + (isLong + ? iPosition.sl < tSLTPPrice + : iPosition.sl > tSLTPPrice); + if (canTrailSL) + { + // + string comment = "Trail SL on Reached TP: " + ToString(reachedTPLevel) + " ..."; + double sl = tSLTPPrice; + double tp = iPosition.tp; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + string message = ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " Trailed SL On Reached TP: " + ToString(reachedTPLevel) + + " Successfully ..."; + Alert(message); + } + } + } + + // + // Handle RF On Target ... + double target = iData.Target(); + double targetDelta = isLong + ? target + (15 * points) + : target - (15 * points); + bool canRF = + target > 0 && + !iData.isTargeted && + (isLong ? target > entry + : target < entry) && + (isLong + ? iPosition.sl < target + : iPosition.sl > target) && + (isLong + ? iPosition.price > targetDelta + : iPosition.price < targetDelta); + if (canRF) + { + // + double sl = target; + double tp = iPosition.tp; + string comment = "RF On Target ..."; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + mData[i].isTargeted = true; + + // + string message = ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " RF On Traget: " + ToString(target) + + " Successfully ..."; + Alert(message); + } + } + } + } + + // + // Calculate Max Draw Down ... + maxDrawdown = + profitSummary < 0 && + (maxDrawdown == 0 || + maxDrawdown < profitSummary) + ? profitSummary + : maxDrawdown; + + // + // Calculate Current Drawdown ... + currentDrawdown = + profitSummary < 0 + ? profitSummary + : 0; + + // + // Checking Hedge ... + bool allowHedge = AllowHedging(); + if (allowHedge) + { + // + double minHedgeVolumeStep = HedgingMinVolumeStep(); + int minRequiredPositionsForHedge = MinOpenTradesFroHedging(); + double minRequiredProfitPerVolumeStepForHedge = HedgeingMinRequiredProfitPerVolumeStep(); + + // + double minRequiredAdditionalProfit = + bepSummary + + ((volumeSummary / minHedgeVolumeStep) * minRequiredProfitPerVolumeStepForHedge); + + // + bool canHedge = AllowHedging() && + profitSummary > 0 && + minHedgeVolumeStep > 0 && + minRequiredProfitPerVolumeStepForHedge > 0 && + profitSummary >= minRequiredAdditionalProfit && + (minRequiredPositionsForHedge <= 0 + ? true + : count >= minRequiredPositionsForHedge); + if (canHedge) + { + // + string comment = "Hedge (" + ToString(count) + ") Positions By: " + ToString(profitSummary) + "..."; + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + if (IsValidSize(closedPositionsCount)) + { + // + // Finish Positions and Clear Data ... + for (int i = 0; i < ArraySize(positions); i++) + { + // + XPosition iPosition = positions[i]; + Finish( + iPosition.ticket, + iPosition, + comment // + ); + } + + // + ResetProtections(); + + // + string message = "Hedge (" + ToString(count) + ") Positions By: " + + ToString(profitSummary) + " Successfully ..."; + Alert(message); + } + } + } + } + + // + // Protected ... + protected: + // + XCTrade *mTrader; // Instance of Trader Class + X121SMCTradeCollector *mCollector; // Instance of Trade Collector Class + + // + X121SMCTradeData mData[]; // Hold Trade Data + X121SMCSymbolPositionInfo mSymbolInfos[]; // Symbol Positions Info + XSymbolLastPosition mLastExecutedSignals[]; // Last Executed Signals + + // + void AlertSignalExecutionFailed( + XSignal &signal, + ENUM_X_SIGNAL_EXECUTION_RESULT state // + ) + { + // + // Alert Signal Execution Failed ... + string msg = "Failed To Execute " + + (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " due Reason: " + ToString(state) + " ..."; + Alert(msg); + } + + // + // Private ... + private: + // + // Props ... + + // + // Read Only ... + int maxSameTimeTrades; // Holds Max Same Time Trades + double maxDrawdown; // Max Drawdown + double currentDrawdown; // Current Drawdown + double drawdownPercent; // Drawdown Percent + double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation + + // + bool mSaveSignals; // Save Signals + bool mSaveTrades; // Save Trades + bool mSaveConditions; // Save SL Conditions + + // + // Signalling Props ... + bool mAllowLong; // Allow Long Signals ... + bool mAllowShort; // Allow Short Signals ... + int mMaxAllowedLongs; // Max Allowed Long Signals ... + int mMaxAllowedShorts; // Max Allowed Short Signals ... + bool mUseMaxAllowedSignalsPerSymbol; // Use Max Allowed Signal Types Per Symbol ... + double mLastPositionProfitForAcceptNextInPoint; // Last Position Profit In Points for Accept new Signal ... + int mDelaysBetweenTwoSignalsInBar; // Delay between two Signals in Bars ... + double mMaxAllowedSpread; // Max Allowed Spread for Signalling ... + double mAdditionalVolume; // Volume Additional ... + + // + // Risk Management Props ... + double mMaxAllowedDrawdownToOpenTrades; // Max Allowed Drawdown for Open Trades ... + int mMaxAllowedSLToPauseSignallingPerSymbol; // Max Allowed SL for Pause Signalling Per Symbol ... + int mPauseSignallingAfterReachesMaxAllowedSLInSecconds; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + + // + // Protection Props ... + bool mAllowHedging; // Allow Hedge Positions ... + int mMinOpenTradesFroHedging; // Minimum Open Positions for Hedging ... + double mHedgingMinVolumeStep; // Minimum Volume Step for Hedging ... + double mHedgeingMinRequiredProfitPerVolumeStep; // Minimum Required Profit Per Volume Step for Hedging ... + + // + XCPOIDrawer *mDrawer; + + // + // Common Functions ... + + // + // Count Data ... + int Count() + { + return ArraySize(mData); + } + + // + // Add Item ... + bool Add(X121SMCTradeData &item) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + int index = -1; + if (item.ticket > 0) + { + // + result = !HasItem( + item.ticket, + index // + ); + } + else + { + // + result = !HasItem( + item.signal, + index // + ); + } + if (!result || IsValidIndex(index)) + { + // + result = false; + return result; + } + + // + AddRef( + item, + mData // + ); + + // + return result; + } + + // + // Find Item Index ... + bool HasItem( + ulong ticket, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + result = mData[i].IsOwn(ticket); + if (result) + { + // + index = i; + break; + } + } + + // + return result; + } + + // + bool HasItem( + XSignal &signal, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = signal.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwn(signal); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + bool HasItem( + XPosition &position, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = position.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwn(position); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + bool HasItemByPosition( + XPosition &position, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = position.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwnPosition(position); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Find Specific Symbo Indo Item index ... + * + * @param symbol: String ... + * @param index: Integer ... + * + * @return ( bool ) + */ + bool HasSymbol( + string symbol, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = IsValid(symbol); + if (!result) + { + return result; + } + + // + int count = ArraySize(mSymbolInfos); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mSymbolInfos[i] + .IsOwn(symbol); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + void Save(int index) + { + // + int count = Count(); + if (!IsValidIndex(index) || index > count - 1) + { + return; + } + + // + // Save Trade ... + if (mSaveTrades) + { + mCollector.Save(mData[index]); + } + + // + if (mSaveConditions) + { + mCollector.SaveConditions(mData[index]); + } + + // + // Remove Item From List ... + ArrayRemove( + mData, + index, + 1 // + ); + } + + // + void SaveSignal(X121SMCTradeData &item) + { + // + if (!mSaveSignals) + { + return; + } + + // + // Save Signal ... + mCollector.SaveSignal(item); + } + + // + // Find Last Signal Execution ... + int FindLastExecutedSignalItem(XSignal &signal) + { + // + int result = -1; + + // + if (!signal.IsValid()) + { + return result; + } + + // + int count = ArraySize(mLastExecutedSignals); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XSymbolLastPosition iLast = mLastExecutedSignals[i]; + if (iLast.symbol == signal.symbol && + iLast.provider == signal.provider) + { + // + result = i; + break; + } + } + + // + return result; + } + + // + // Handle Last Signal Execution ... + void HandleSignalExecuted(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + + // + datetime cTime = TimeCurrent(); + int symbolIDX = FindLastExecutedSignalItem(signal); + bool hasItem = IsValidIndex(symbolIDX); + if (hasItem) + { + mLastExecutedSignals[symbolIDX].time = cTime; + } + else + { + // + XSymbolLastPosition item; + + // + item.time = cTime; + item.symbol = signal.symbol; + item.provider = signal.provider; + + // + AddRef( + item, + mLastExecutedSignals // + ); + } + } + + // + double CalculateMaxDrawdownPercent() + { + // + double result = 0; + + // + double mEquity = mTrader.mAccount.GetEquity(); + if (mEquity > currentDrawdown) + { + currentDrawdown = mEquity; + } + + // + if (currentDrawdown >= 0) + { + // + drawdownPercent = 0; + return result; + } + + // + drawdownPercent = (currentDrawdown - mEquity) / + (staticBalanceForCalculateDrawdown > 0 + ? staticBalanceForCalculateDrawdown + : currentDrawdown) * + 100; + drawdownPercent = NormalizeDouble(drawdownPercent, 3); + result = drawdownPercent; + + // + return result; + } + + // + void ResetProtections() + { + // + ResumePausedSymbols(); + Clean(mLastExecutedSignals); + } + + // + // End of XC121SMCTradeHandler Class ... +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/X121SMCEA/Experts/x-121.smc.expert.class.mq5 b/BKPS/14031106/X121SMCEA/Experts/x-121.smc.expert.class.mq5 new file mode 100644 index 0000000..e719bea --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Experts/x-121.smc.expert.class.mq5 @@ -0,0 +1,2501 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XC121SMCExpert +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-expert.class.mq5" +#include "../Classes/x-121.smc.x-tradehandler.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" +#include "../Strategy/x-121.smc.strategy.class.mq5" + +// +// Definitions ... +string XC121SMCExpertToken = "XC121SMCEA"; + +// +// Implementation ... + +class XC121SMCExpert : public XCBaseExpert +{ + // + public: + // + + // + // Signal Event Listener ... + TOnStopLoss OnPositionSLEventListener; + TOnTakeProfit OnPositionTPEventListener; + TOnPartialClose OnPositionPartialCloseEventListener; + TOnModify OnPositionModifiedEventListener; + TOnForceClose OnPositionForceCloseEventListener; + + // + TOnDealsChanged OnDealsChangedEventListener; + TOnOrdersChanged OnOrdersChangedEventListener; + TOnPositionsChanged OnPositionsChangedEventListener; + + // + TOnX121SMCSignal OnSignalEventListener; + + // + // Constructor(s) ... + XC121SMCExpert() + { + } + + // + // Deconstructor(s) ... + ~XC121SMCExpert() + { + ArrayFree(mStrategies); + } + + // + // Getter(s) / Setter(s) ... + + // + // Signalling Props ... + + /** + * Get Allow Long Signals State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Allow Long Signals State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + // + mAllowLong = value; + ReConfigure(); + } + + /** + * Get Allow Short Signals State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Allow Short Signals State ... + * + * @param value: Boolean ... + */ + void AllowShort(bool value) + { + // + mAllowShort = value; + ReConfigure(); + } + + /** + * Get Max Allowed Long Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedLongs() + { + return mMaxAllowedLongs; + } + + /** + * Set Max Allowed Long Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedLongs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedLongs = value; + ReConfigure(); + } + + /** + * Get Max Allowed Short Signals ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedShorts() + { + return mMaxAllowedShorts; + } + + /** + * Set Max Allowed Short Signals ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedShorts(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedShorts = value; + ReConfigure(); + } + + /** + * Get Use Max Allowed Signal Types Per Symbol State ... + * + * @return ( bool ) + */ + bool UseMaxAllowedSignalsPerSymbol() + { + return mUseMaxAllowedSignalsPerSymbol; + } + + /** + * Set Use Max Allowed Signal Types Per Symbol State ... + * + * @param value: Boolean ... + */ + void UseMaxAllowedSignalsPerSymbol(bool value) + { + // + mUseMaxAllowedSignalsPerSymbol = false; + ReConfigure(); + } + + /** + * Get Last Position Profit In Points for Accept new Signal ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double LastPositionProfitForAcceptNextInPoint() + { + return mLastPositionProfitForAcceptNextInPoint; + } + + /** + * Set Last Position Profit In Points for Accept new Signal ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void LastPositionProfitForAcceptNextInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mLastPositionProfitForAcceptNextInPoint = value; + ReConfigure(); + } + + /** + * Get Delay between two Signals in Bars ... + * 0 => Accept All ... + * + * @return ( int ) + */ + int DelaysBetweenTwoSignalsInBar() + { + return mDelaysBetweenTwoSignalsInBar; + } + + /** + * Set Delay between two Signals in Bars ... + * + * @param value: Integer ... + * 0 => Accept All ... + */ + void DelaysBetweenTwoSignalsInBar(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDelaysBetweenTwoSignalsInBar = value; + ReConfigure(); + } + + /** + * Get Max Allowed Spread for Signalling ... + * 0 => Accept All ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread for Signalling ... + * + * @param value: Double ... + * 0 => Accept All ... + */ + void MaxAllowedSpread(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSpread = value; + ReConfigure(); + } + + /** + * Get Minimum Spread Verification for Signalling ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int MinRequiredVerificationForSpreadPass() + { + return mMinRequiredVerificationForSpreadPass; + } + + /** + * Set Minimum Spread Verification for Signalling ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void MinRequiredVerificationForSpreadPass(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinRequiredVerificationForSpreadPass = value; + ReConfigure(); + } + + // + // Trade ... + + /** + * Get Allow Open Trade On Signals State ... + * + * @return ( bool ) + */ + bool AllowTrade() + { + return mAllowTrade; + } + + /** + * Set Allow Open Trade On Signals State ... + * + * @param value: Boolean ... + */ + void AllowTrade(bool value) + { + mAllowTrade = value; + } + + /** + * Get Enable Trade on Signals on Time ... + * + * @return ( string ) + */ + string StartTradeAt() + { + return mStartTradeAt; + } + + /** + * Set Enable Trade on Signals on Time ... + * + * @param value: String ... + */ + void StartTradeAt(string value) + { + mStartTradeAt = value; + } + + /** + * Get Enable Trade on Signals on Time ... + * + * @return ( string ) + */ + string StopTradeAt() + { + return mStopTradeAt; + } + + /** + * Set Enable Trade on Signals on Time ... + * + * @param value: String ... + */ + void StopTradeAt(string value) + { + mStopTradeAt = value; + } + + /** + * Get Enable Close All Trades on Signals on Time ... + * + * @return ( string ) + */ + string CloseAllTradesAt() + { + return mCloseAllTradesAt; + } + + /** + * Set Enable Close All Trades on Signals on Time ... + * + * @param value: String ... + */ + void CloseAllTradesAt(string value) + { + mCloseAllTradesAt = value; + } + + // + // Risk Management Props ... + + /** + * Get Risk to Reward Ratio ... + * + * @return ( double ) + */ + double R2R() + { + return mR2R; + } + + /** + * Set Risk to Reward Ratio ... + * + * @param value: Double ... + */ + void R2R(double value) + { + // + if (value < 1) + { + value = 1; + } + + // + mR2R = value; + ReConfigure(); + } + + /** + * Get Static Volume ... + * + * @return ( double ) + */ + double Volume() + { + return mVolume; + } + + /** + * Set Static Volume ... + * + * @param value: Double ... + */ + void Volume(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mVolume = value; + ReConfigure(); + } + + /** + * Get Static Balance for Calculate Trade Volume ... + * + * @return ( double ) + */ + double StaticBalance() + { + return mStaticBalance; + } + + /** + * Set Static Balance for Calculate Trade Volume ... + * + * @param value: Argument 1 + */ + void StaticBalance(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mStaticBalance = value; + } + + /** + * Get Balance Used In Each Trade ... + * + * @return ( double ) + */ + double BalancePerTrade() + { + return mBalancePerTrade; + } + + /** + * Set Balance Used In Each Trade ... + * + * @param value: Argument 1 + */ + void BalancePerTrade(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mBalancePerTrade = value; + } + + /** + * Get Risk Percent Per Balance in Each Trade ... + * + * @return ( double ) + */ + double RiskPercentPerBalance() + { + return mRiskPercentPerBalance; + } + + /** + * Set Risk Percent Per Balance in Each Trade ... + * + * @param value: Double + */ + void RiskPercentPerBalance(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRiskPercentPerBalance = value; + ReConfigure(); + } + + /** + * Get Dynamic Risk Management State ... + * + * @return ( bool ) + */ + bool DynamicRiskManagement() + { + return mDynamicRiskManagement; + } + + /** + * Set Dynamic Risk Management State ... + * + * @param value: Boolean ... + */ + void DynamicRiskManagement(bool value) + { + // + mDynamicRiskManagement = value; + ReConfigure(); + } + + /** + * Get Use Dynamic Volume State ... + * + * @return ( bool ) + */ + bool UseDynamicVolume() + { + return mUseDynamicVolume; + } + + /** + * Set Use Dynamic Volume State ... + * + * @param value: Boolean ... + */ + void UseDynamicVolume(bool value) + { + // + mUseDynamicVolume = value; + ReConfigure(); + } + + /** + * Get Increase Volume Step ... + * + * @return ( double ) + */ + double DynamicVolumeStep() + { + return mDynamicVolumeStep; + } + + /** + * Set Increase Volume Step ... + * + * @param value: Double ... + */ + void DynamicVolumeStep(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mDynamicVolumeStep = value; + ReConfigure(); + } + + /** + * Get Balance Factor for Generate Dynamic Volume ... + * + * @return ( double ) + */ + double DynamicVolumeBalanceFactor() + { + return mDynamicVolumeBalanceFactor; + } + + /** + * Set Balance Factor for Generate Dynamic Volume ... + * + * @param value: Double ... + */ + void DynamicVolumeBalanceFactor(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDynamicVolumeBalanceFactor = value; + ReConfigure(); + } + + /** + * Get Max Allowed Drawdown Percent for Open Trades ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + * + * @return ( double ) + */ + double MaxAllowedDrawdownToOpenTrades() + { + return mMaxAllowedDrawdownToOpenTrades; + } + + /** + * Set Max Allowed Drawdown Percent for Open Trades ... + * + * @param value: Double ... + * 0 => Ignore ... + * min => 0 ... + * max => 100 ... + */ + void MaxAllowedDrawdownToOpenTrades(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 50) + { + value = 50; + } + + // + mMaxAllowedDrawdownToOpenTrades = value; + ReConfigure(); + } + + /** + * Get Max Allowed SL for Pause Signalling Per Symbol ... + * 0 => Unlimited ... + * + * @return ( int ) + */ + int MaxAllowedSLToPauseSignallingPerSymbol() + { + return mMaxAllowedSLToPauseSignallingPerSymbol; + } + + /** + * Set Max Allowed SL for Pause Signalling Per Symbol ... + * + * @param value: Integer ... + * 0 => Unlimited ... + */ + void MaxAllowedSLToPauseSignallingPerSymbol(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSLToPauseSignallingPerSymbol = value; + ReConfigure(); + } + + /** + * Get Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int PauseSignallingAfterReachesMaxAllowedSLInSecconds() + { + return mPauseSignallingAfterReachesMaxAllowedSLInSecconds; + } + + /** + * Set Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void PauseSignallingAfterReachesMaxAllowedSLInSecconds(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPauseSignallingAfterReachesMaxAllowedSLInSecconds = value; + ReConfigure(); + } + + // + // Protection Props ... + + /** + * Get Allow Hedge Positions State ... + * + * @return ( bool ) + */ + bool AllowHedging() + { + return mAllowHedging; + } + + /** + * Set Allow Hedge Positions State ... + * + * @param value: Boolean ... + */ + void AllowHedging(bool value) + { + // + mAllowHedging = value; + ReConfigure(); + } + + /** + * Get Minimum Open Positions for Hedging ... + * 0 => Ignore ... + * + * @return ( int ) + */ + int MinOpenTradesFroHedging() + { + return mMinOpenTradesFroHedging; + } + + /** + * Set Minimum Open Positions for Hedging ... + * + * @param value: Integer ... + * 0 => Ignore ... + */ + void MinOpenTradesFroHedging(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinOpenTradesFroHedging = value; + ReConfigure(); + } + + /** + * Get Minimum Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgingMinVolumeStep() + { + return mHedgingMinVolumeStep; + } + + /** + * Set Minimum Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgingMinVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + if (value > 0 && value < 0.01) + { + value = 0.01; + } + + // + if (value > 0 && value > 0.1) + { + value = 0.1; + } + + // + mHedgingMinVolumeStep = value; + ReConfigure(); + } + + /** + * Get Minimum Required Profit Per Volume Step for Hedging ... + * 0 => Ignore ... + * + * @return ( double ) + */ + double HedgeingMinRequiredProfitPerVolumeStep() + { + return mHedgeingMinRequiredProfitPerVolumeStep; + } + + /** + * Set Minimum Required Profit Per Volume Step for Hedging ... + * + * @param value: Double ... + * 0 => Ignore ... + */ + void HedgeingMinRequiredProfitPerVolumeStep(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mHedgeingMinRequiredProfitPerVolumeStep = value; + ReConfigure(); + } + + // + // Actions ... + + /** + * Handle OnSignalRecieved Event ... + * + * @param signal: XSignal instance ... + * @param conditions: X121SMCStrategyConditions instance ... + */ + void HandleOnSignalRecieved( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + // Check Signal and Conditions Validations ... + + // + if (!signal.IsValid()) + { + return; + } + + // + if (!conditions.IsValid()) + { + return; + } + + // + bool isLong = IsLong(signal.type); + + // + // Notify When a Raw (Unfiltered) Signal Recieved + // if it's Provided ... + bool mAlertRawSignals = false; + if (mAlertRawSignals) + { + // + string msg = "Raw " + (IsLong(signal.type) ? "Long" : "Short") + + " Signal Recieved: (" + signal.provider + "," + + signal.symbol + "," + + ToString(signal.period) + + ") ..."; + + // + Alert(msg); + } + + // + // Apply Volume On Signal ... + ApplyVolumeOnSignal(signal); + + // + // Chekc Signalling Enable or not ... + bool canContinue = + isLong + ? AllowLong() + : AllowShort(); + if (!canContinue) + { + return; + } + + // + // TODO: Apply Filtering On Signal ... + bool isFiltered = false; + if (isFiltered) + { + // + mTradeHandler.Remove(signal); + return; + } + + // + // Attach Conditions Summary to Signal ... + string conditionsSummary = conditions.GenerateSummary( + false, + false, + true, + false // + ); + + // + // TODO: Retrieve Conditions Summary based on Filter ... + signal.conditions = conditionsSummary; + + // + datetime currentTime = TimeCurrent(); + + // + // Chack Allow Trades ... + bool allowTrade = AllowTrade(); + if (allowTrade) + { + // + string startTime = StartTradeAt(); + string endTime = StopTradeAt(); + bool isTimePassed = IsTimeInRange( + TimeCurrent(), + startTime, + endTime // + ); + + // + if (isTimePassed) + { + // + // Execute Signal Using Trade Handler ... + ENUM_X_SIGNAL_EXECUTION_RESULT state; + bool isExecuted = mTradeHandler.ExecuteSignal( + signal, + conditions, + state, + false // ignore Policies ... + ); + } + } + else + { + // + // Only Alert Signals ... + string msg = (IsLong(signal.type) + ? "Long" + : "Short") + + " Signal Recieved: (" + + signal.provider + "," + + signal.symbol + "," + + ToString(signal.period) + + ") ..."; + + // + Alert(msg); + + // + // Draw Signals and Conditions ... + if (eaDrawer != NULL) + { + // + XCBaseObject *objects[]; + XCSignalObject *signalObject; + bool isCreated = eaDrawer.DrawSignal( + signal, + signalObject // + ); + // DrawX121SMCStrategyConditions( + // conditions, + // objects, + // eaDrawer, + // true, // draw Market Structure ... + // true, // Draw Price Zones ... + // true // Draw Decision Zones ... + // ); + + // + Add( + (XCBaseObject *)signalObject, + objects // + ); + + // + Clean(objects); + } + } + + // + signal.Clean(); + conditions.Clean(); + } + + // + // Override Actions ... + + /** + * Apply Default Configurations ... + */ + void DefaultConfigure() override + { + // + // Commons ... + Slippage(10); + TagPrefix(""); + MagicNumber(1694056); + + // + // Symbol ... + SetSymbol(_Symbol); + SetPeriod(_Period); + MultiSymbol(false); + Symbols("EURUSDb,GBPUSDb,USDJPYb,USDCHFb,DowJones30,XAUUSDb"); + + // + // Signalling ... + Disabled(false); + AllowLong(true); + AllowShort(true); + + // + string tag = GetTag(); + + // + // Alert ... + SetAlertPrefix(tag); + SetAlertLogAlerts(true); + SetAlertPushAlerts(true); + SetAlertMailAlerts(false); + SetAlertEnableAlerts(true); + SetAlertTerminalAlerts(false); + + // + // Reports ... + ReportNewDays(true); + ReportNewWeeks(false); + ReportNewHours(false); + ReportNewMonths(false); + + // + R2R(1); + + // + // Volume Default Configurations ... + Volume(0.01); + UseDynamicVolume(false); + DynamicVolumeStep(0.01); + DynamicVolumeBalanceFactor(200); + + // + RiskPercentPerBalance(0); + DynamicRiskManagement(false); + } + + /** + * Vaslidate Inputs ... + * + * @return ( bool ) + */ + bool ValidateInputs() override + { + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + Slippage() > 0 && + MagicNumber() > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + // Checking Volume ... + bool isVolumeValid = true; + if (UseDynamicVolume()) + { + // + isVolumeValid = + DynamicVolumeStep() > 0 && + DynamicVolumeBalanceFactor() > 0; + if (!isVolumeValid) + { + errMessage += "Dynamic Volume configurations error;" + "\n"; + } + } + isVolumeValid = isVolumeValid && + Volume() > 0; + if (!isVolumeValid) + { + errMessage += "Static Volume configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Volume Coniguration ... + isVolumeValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + errMessage = " Errors: \n" + errMessage; + Alert(errMessage); + } + + // + return result; + } + + // + // Initializers and DeInitializers ... + + /** + * Initial EA Requirements ... + * + * @return ( bool ) + */ + bool InitEA() override + { + // + bool result = false; + + // + // Initialize Indicator Helpers ... + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); // Default Configurations ... + mCTHelper = new XCXCTHelper(); + result = mCTHelper.Init( + GetSymbol(), + GetPeriod(), + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); // Default Configurations ... + mCCHelper = new XCXCCHelper(); + result = mCCHelper.Init( + GetSymbol(), + GetPeriod(), + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Configure Alerts ... + SetAlertPrefix(GetTag()); + SetAlertEnableAlerts(GetAlertEnableAlerts()); + SetAlertLogAlerts(GetAlertLogAlerts()); + SetAlertMailAlerts(GetAlertMailAlerts()); + SetAlertPushAlerts(GetAlertPushAlerts()); + SetAlertTerminalAlerts(GetAlertTerminalAlerts()); + + // + // Create Trader Instance and Configure it ... + mTrader = new XCTrade( + Slippage(), + MagicNumber() // + ); + mTrader.AddOnStopLossEventHandler(OnPositionSLEventListener); + mTrader.AddOnTakeProfitEventHandler(OnPositionTPEventListener); + mTrader.AddOnDealsChangedEventHandler(OnDealsChangedEventListener); + mTrader.AddOnOrdersChangedEventHandler(OnOrdersChangedEventListener); + mTrader.AddOnModifyPositionEventHandler(OnPositionModifiedEventListener); + mTrader.AddOnPositionsChangedEventHandler(OnPositionsChangedEventListener); + mTrader.AddOnForceClosePositionEventHandler(OnPositionForceCloseEventListener); + mTrader.AddOnPartialClosePositionEventHandler(OnPositionPartialCloseEventListener); + + // + // Initialize Trade Handler ... + mTradeHandler = new XC121SMCTradeHandler(mTrader); + mTradeHandler.SaveTrades(false); + mTradeHandler.SaveSignals(false); + mTradeHandler.SaveConditions(false); + + // + ReConfigureTradeHandler(); + + // + // Parsers ... + XSymbolParser _symbolParser; + eaDrawer = NULL; + + // + // Single Symbol ... + if (!MultiSymbol()) + { + // + // Register Strategy ... + + // + // Create Class Instance ... + XCX121SMCBaseStrategy *iX121SMCStrategy; + iX121SMCStrategy = new XCX121SMCStrategy( + _Symbol, + _Period // + ); + + // + if (eaDrawer == NULL) + { + // + eaDrawer = iX121SMCStrategy + .GetDrawer(); + } + + // + iX121SMCStrategy.AddXSignalEventHandler(OnSignalEventListener); + + // + ConfigureStrategy(iX121SMCStrategy); + RegisterStrategy(iX121SMCStrategy); + } + // + // Multi Symbol ... + else + { + // + // Parse Symbols ... + string symbols[]; + int symbolsCount = SplitContent( + symbols, + Symbols() // + ); + result = IsValidSize(symbolsCount); + if (!result) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + // Select Symbol ... + string iSymbol = symbols[i]; + + // + // Register Strategy Based On Symbol ... + + // + // Parse Symbol ... + bool isEURUSD = _symbolParser.IsEURUSD(_Symbol); + bool isGBPUSD = _symbolParser.IsGBPUSD(_Symbol); + bool isEURGBP = _symbolParser.IsEURGBP(_Symbol); + bool isUSDCHF = _symbolParser.IsUSDCHF(_Symbol); + bool isEURCHF = _symbolParser.IsEURCHF(_Symbol); + bool isUSDJPY = _symbolParser.IsUSDJPY(_Symbol); + bool isEURJPY = _symbolParser.IsEURJPY(_Symbol); + bool isUSDCAD = _symbolParser.IsUSDCAD(_Symbol); + bool isEURCAD = _symbolParser.IsEURCAD(_Symbol); + bool isAUDUSD = _symbolParser.IsAUDUSD(_Symbol); + bool isEURAUD = _symbolParser.IsEURAUD(_Symbol); + bool isNZDUSD = _symbolParser.IsNZDUSD(_Symbol); + bool isEURNZD = _symbolParser.IsEURNZD(_Symbol); + + // + // Check Symbol Can Register or not ... + bool canRegisterStrategy = true; + + // + if (canRegisterStrategy) + { + // + // Create Class Instance ... + XCX121SMCBaseStrategy *iX121SMCStrategy; + iX121SMCStrategy = new XCX121SMCStrategy( + iSymbol, + _Period // + ); + + // + if (eaDrawer == NULL) + { + // + eaDrawer = iX121SMCStrategy + .GetDrawer(); + } + + // + iX121SMCStrategy.AddXSignalEventHandler(OnSignalEventListener); + + // + // Register Strategy ... + ConfigureStrategy(iX121SMCStrategy); + RegisterStrategy(iX121SMCStrategy); + } + } + + // + Clean(symbols); + } + + // + if (eaDrawer != NULL) + { + mTradeHandler.SetDrawer(eaDrawer); + } + + // + return result; + } + + /** + * Destroy all Initialized EA Requirements ... + */ + void DestroyEA() override + { + // + delete mCTHelper; + delete mCCHelper; + delete mTradeHandler; + + // + Clean(mStrategies); + } + + /** + * Call all Registered Strategies On Tick ... + */ + void HandleStrategiesOnTick() override + { + // + // Check Force Close ... + string forceCloseTimeStr = CloseAllTradesAt(); + if (IsValid(forceCloseTimeStr)) + { + // + datetime forceCloseTime = ParseDateTimeFromTimeString(forceCloseTimeStr); + bool canForceClose = IsTimeInRange( + TimeCurrent(), + forceCloseTime // + ) && + !mIsForceCloseAtTime; + if (canForceClose) + { + mIsForceCloseAtTime = mTradeHandler.ForceClose(); + } + } + + // + // Update Positions Data ... + mTradeHandler.UpdateData(); + + // + // Protect Positions ... + mTradeHandler.HandleProtection(); + + // + int count = ArraySize(mStrategies); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + // Call Tick Handler Function ... + mStrategies[i].HandleTick(); + } + } + + /** + * Handle Strategies Guards ... + */ + void HandleStrategiesGuard() override + { + // + int count = ArraySize(mStrategies); + if (!IsValidSize(count)) + { + return; + } + + // + XPosition positions[]; + int positionsCount = mTrader.GetPositions( + positions, // Result ... + NULL, // Symbol ... + NULL, // Provider ... + NULL, // Period ... + X_POSITION_TYPE_ALL // All Types ... + ); + if (!IsValidSize(positionsCount)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + // Call Tick Handler Function ... + X121SMCGuard iGuards[]; + bool hasGuards = mStrategies[i].HandleGuard( + iGuards, + positions // + ); + if (hasGuards) + { + HandleGuards(iGuards); + } + } + + // + Clean(positions); + } + + // + // Event Handlers ... + + /** + * Calls When a Deals Changed Triggered ... + * + * @param count: Integer, Number of Changes ... + */ + void HandleOnDealsChanged(int count) override + { + } + + /** + * Calls When a Order Changed Triggered ... + * + * @param count: Integer, Number of Changes ... + */ + void HandleOnOrdersChanged(int count) override + { + } + + /** + * Calls When a Positions Changed Triggered ... + * + * @param count: Integer, Number of Changes ... + */ + void HandleOnPositionsChanged(int count) override + { + // + if (IsValidSize(count)) + { + mTradeHandler.HandleNewPosition(); + } + } + + /** + * Calls When a Position's SL Triggered ... + * + * @param deal: XDeal instance ... + */ + void HandleOnStopLossTriggered(const XDeal &deal) override + { + // + // Finish ... + mTradeHandler.Finish(deal); + + // + HandleReportBalance(); + } + + /** + * Calls When a Position's TP Triggered ... + * + * @param deal: XDeal instance ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) override + { + // + // Finish ... + mTradeHandler.Finish(deal); + + // + bool useDynamicRiskManagement = DynamicRiskManagement(); + if (useDynamicRiskManagement) + { + mTradeHandler.ResetSymbolInfo(deal.symbol); + } + + // + HandleReportBalance(); + } + + /** + * Handle Force Close a Position ... + * + * @param ticket: Position Ticket ... + * @param position: XPosition ... + * @param comment: Closing Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) override + { + // + // Finish ... + mTradeHandler.Finish( + ticket, + position, + comment // + ); + + // + HandleReportBalance(); + } + + /** + * Reset All Paused Symbols on Each New Days ... + */ + void HandleOnNewDay() override + { + // + mIsForceCloseAtTime = false; + mTradeHandler.ResumePausedSymbols(); + } + + /** + * Re Configure Materials on Properties Changed ... + */ + void ReConfigure() override + { + // + ReConfigureTradeHandler(); + ReConfigureAllStrategies(); + } + + /** + * Generate Identifier Tag ... + * + * @return ( string ) + */ + string GetTag() override + { + // + string result = NULL; + + // + string tagPrefix = TagPrefix(); + if (IsValid(tagPrefix)) + { + result = tagPrefix; + } + else + { + result = ""; + } + + // + result = + XC121SMCExpertToken + result; + + // + return result; + } + + // + protected: + // + + // + // Props ... + + // + XC121SMCTradeHandler *mTradeHandler; // Trade Handler ... + XCX121SMCBaseStrategy *mStrategies[]; // Registere Strategies in EA ... + + // + // Actions ... + + /** + * Apply Volume Based On Configurations on Signal ... + * + * @param signal: XSignal instance + */ + void ApplyVolumeOnSignal(XSignal &signal) + { + // + double staticVolume = Volume(); + double fVolume = staticVolume > 0 + ? staticVolume + : 0.01; + + // + double staticBalance = StaticBalance(); + double accountBalance = mTrader.mAccount.GetBalance(); + double balance = staticBalance > 0 + ? staticBalance + : accountBalance; + + // + bool useDynamicVolume = UseDynamicVolume(); + double balancePerTrade = BalancePerTrade(); + double dynamicVolumeStep = DynamicVolumeStep(); + double riskPercentPerBalance = RiskPercentPerBalance(); + bool allowDynamicRiskManagement = DynamicRiskManagement(); + double dynamicVolumeBalanceFactor = DynamicVolumeBalanceFactor(); + + // + // Apply Static Volume ... + bool allowStaticVolume = staticVolume > 0; + + // + // Apply Dynamic Volume ... + bool aloowApplyDynamicVolume = useDynamicVolume && + dynamicVolumeStep && + dynamicVolumeBalanceFactor; + + // + // Apply Risk Per Trade Volume ... + bool allowApplyRiskPerTradeVolume = + !aloowApplyDynamicVolume && + riskPercentPerBalance > 0; + + // + // Apply Balance Per Trade Volume ... + bool allowApplyBalacePerTradeVolume = + !aloowApplyDynamicVolume && + !allowApplyRiskPerTradeVolume && + balancePerTrade > 0; + + // + // First Check Dynamic Volume ... + if (aloowApplyDynamicVolume) + { + // + // Dynamic Volume ... + double dVolume = mTrader.GetDynamicVolume( + signal.symbol, + dynamicVolumeBalanceFactor, + dynamicVolumeStep // + ); + if (dVolume < fVolume) + { + dVolume = fVolume; + } + + // + signal.volume = dVolume; + } + else if (allowApplyRiskPerTradeVolume) + { + // + double riskAmountPerBalance = (riskPercentPerBalance * balance) / 100; + + // + double risk = signal.GetRisk(); + double points = GetPoints(signal.symbol); + double riskInPoints = risk / points; + + // + double volume = mTrader.mAccount.CalculateVolume( + signal.symbol, + riskAmountPerBalance, + riskInPoints // + ); + if (volume <= 0) + { + volume = fVolume; + } + + // + // Check Dynamic Risk Management ... + bool allowDynamicRiskManagement = DynamicRiskManagement(); + if (allowDynamicRiskManagement) + { + // + // Calculate Dynamic Additional Risk Management Volume Multiplier ... + double mAdditionalRiskMultiplier = CalculateAdditionalVolumeMultiplier(signal); + if (mAdditionalRiskMultiplier < 1) + { + mAdditionalRiskMultiplier = 1; + } + + // + volume *= mAdditionalRiskMultiplier; + } + + // + signal.volume = volume; + } + else if (allowApplyBalacePerTradeVolume) + { + // + double risk = signal.GetRisk(); + double points = GetPoints(signal.symbol); + double riskInPoints = risk / points; + + // + double volume = mTrader.mAccount.CalculateVolume( + signal.symbol, + balancePerTrade, + riskInPoints // + ); + if (volume <= 0) + { + volume = fVolume; + } + + // + signal.volume = volume; + } + else if (allowStaticVolume) + { + signal.volume = staticVolume; + } + else + { + signal.volume = fVolume; + } + + // + // Normalize Signal Volume ... + signal.volume = NormalizeVolume( + signal.volume, + signal.symbol // + ); + } + + /** + * Configure Startegy ... + */ + void ConfigureStrategy(XCX121SMCBaseStrategy *&strategy) + { + // + if (strategy == NULL) + { + return; + } + + // + // Configure Alerts ... + strategy.SetAlertPrefix(GetTag()); + strategy.SetAlertLogAlerts(GetAlertLogAlerts()); + strategy.SetAlertMailAlerts(GetAlertMailAlerts()); + strategy.SetAlertPushAlerts(GetAlertPushAlerts()); + strategy.SetAlertEnableAlerts(GetAlertEnableAlerts()); + strategy.SetAlertTerminalAlerts(GetAlertTerminalAlerts()); + + // + // Confiugre Signalling ... + + // + strategy.R2R(R2R()); + strategy.AllowLong(AllowLong()); + strategy.AllowShort(AllowShort()); + strategy.MaxAllowedSpread(20); + strategy.MaxAllowedSaveTicks(150); + strategy.MinRequiredTicksForSpreadPass(100); + + // + if (Disabled()) + { + strategy.Disable(); + } + else + { + strategy.Enable(); + } + + // + } + + /** + * Register an Strategy in EA ... + * + * @param strategy: XCX121SMCBaseStrategy instance ... + */ + void RegisterStrategy(XCX121SMCBaseStrategy *strategy) + { + // + if (strategy == NULL) + { + return; + } + + // + ArrayResize( + mStrategies, + ArraySize(mStrategies) + 1 // + ); + + // + mStrategies[ArraySize(mStrategies) - 1] = strategy; + } + + /** + * Re Configure All Registered Strategies ... + */ + void ReConfigureAllStrategies() + { + // + int count = ArraySize(mStrategies); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + ConfigureStrategy(mStrategies[i]); + } + } + + /** + * Re Configure Trade Handler ... + */ + void ReConfigureTradeHandler() + { + // + if (mTradeHandler == NULL) + { + return; + } + + // + // Configure Alerts ... + mTradeHandler.SetAlertPrefix(GetTag()); + mTradeHandler.SetAlertEnableAlerts(GetAlertEnableAlerts()); + mTradeHandler.SetAlertLogAlerts(GetAlertLogAlerts()); + mTradeHandler.SetAlertMailAlerts(GetAlertMailAlerts()); + mTradeHandler.SetAlertPushAlerts(GetAlertPushAlerts()); + mTradeHandler.SetAlertTerminalAlerts(GetAlertTerminalAlerts()); + + // + mTradeHandler.AllowLong(AllowLong()); + mTradeHandler.AllowShort(AllowShort()); + mTradeHandler.MaxAllowedLongs(MaxAllowedLongs()); + mTradeHandler.MaxAllowedShorts(MaxAllowedShorts()); + mTradeHandler.UseMaxAllowedSignalsPerSymbol(UseMaxAllowedSignalsPerSymbol()); + mTradeHandler.LastPositionProfitForAcceptNextInPoint(LastPositionProfitForAcceptNextInPoint()); + mTradeHandler.DelaysBetweenTwoSignalsInBar(DelaysBetweenTwoSignalsInBar()); + mTradeHandler.MaxAllowedSpread(MaxAllowedSpread()); + mTradeHandler.MaxAllowedDrawdownToOpenTrades(MaxAllowedDrawdownToOpenTrades()); + mTradeHandler.MaxAllowedSLToPauseSignallingPerSymbol(MaxAllowedSLToPauseSignallingPerSymbol()); + mTradeHandler.PauseSignallingAfterReachesMaxAllowedSLInSecconds(PauseSignallingAfterReachesMaxAllowedSLInSecconds()); + mTradeHandler.AllowHedging(AllowHedging()); + mTradeHandler.MinOpenTradesFroHedging(MinOpenTradesFroHedging()); + mTradeHandler.HedgingMinVolumeStep(HedgingMinVolumeStep()); + mTradeHandler.HedgeingMinRequiredProfitPerVolumeStep(HedgeingMinRequiredProfitPerVolumeStep()); + } + + // + private: + // + + // + // Props ... + + // + // Signalling Props ... + bool mAllowLong; // Allow Long Signals ... + bool mAllowShort; // Allow Short Signals ... + int mMaxAllowedLongs; // Max Allowed Long Signals ... + int mMaxAllowedShorts; // Max Allowed Short Signals ... + bool mUseMaxAllowedSignalsPerSymbol; // Use Max Allowed Signal Types Per Symbol ... + double mLastPositionProfitForAcceptNextInPoint; // Last Position Profit In Points for Accept new Signal ... + int mDelaysBetweenTwoSignalsInBar; // Delay between two Signals in Bars ... + double mMaxAllowedSpread; // Max Allowed Spread for Signalling ... + int mMinRequiredVerificationForSpreadPass; // Minimum Spread Verification for Signalling ... + + // + // Trade ... + bool mAllowTrade; // Allow Open Trade On Signals ... + string mStartTradeAt; // Enable Trade on Signals on Time ... + string mStopTradeAt; // Enable Trade on Signals on Time ... + string mCloseAllTradesAt; // Enable Close All Trades on Signals on Time ... + + // + bool mIsForceCloseAtTime; + + // + // Risk Management Props ... + double mR2R; // Signallers Risk to Reward Ratio ... + double mVolume; // Static Volume ... + double mStaticBalance; // Static Balance for Calculate Trade Volume ... + double mBalancePerTrade; // Balance Used in Each Trade ... + double mRiskPercentPerBalance; // Risk Percent Per Balance in Each Trade ... + bool mDynamicRiskManagement; // Dynamic Risk Management ... + bool mUseDynamicVolume; // Use Dynamic Volume ... + double mDynamicVolumeStep; // Increase Volume Step ... + double mDynamicVolumeBalanceFactor; // Balance Factor for Generate Dynamic Volume ... + double mMaxAllowedDrawdownToOpenTrades; // Max Allowed Drawdown for Open Trades ... + int mMaxAllowedSLToPauseSignallingPerSymbol; // Max Allowed SL for Pause Signalling Per Symbol ... + int mPauseSignallingAfterReachesMaxAllowedSLInSecconds; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... + + // + // Protection Props ... + bool mAllowHedging; // Allow Hedge Positions ... + int mMinOpenTradesFroHedging; // Minimum Open Positions for Hedging ... + double mHedgingMinVolumeStep; // Minimum Volume Step for Hedging ... + double mHedgeingMinRequiredProfitPerVolumeStep; // Minimum Required Profit Per Volume Step for Hedging ... + + // + XCPOIDrawer *eaDrawer; // EA Drawer ... + + // + double CalculateAdditionalVolumeMultiplier(XSignal &signal) + { + // + double result = 0; + + // + if (!signal.IsValid()) + { + return result; + } + + // + X121SMCSymbolPositionInfo info; + bool hasInfo = mTradeHandler.GetSymbolInfo( + signal.symbol, + info // + ); + if (!hasInfo) + { + return result; + } + + // + if (info.countedSLs >= 2) + { + result = (info.countedSLs / 2) + 1; + } + + // + return result; + } + + /** + * Handle Guard Actions ... + * + * @param guards: X121SMCGuard instance Collection ... + */ + void HandleGuards(X121SMCGuard &guards[]) + { + // + int count = ArraySize(guards); + if (!IsValidSize(guards)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + X121SMCGuard iGuard = guards[i]; + + // + if (!iGuard.IsValid()) + { + continue; + } + + // + // Here we Have to Handle Guard Actions ... + + // + // Close ... + bool canClose = + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE; + + // + // Close All ... + bool canCloseAll = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_ALL; + + // + // Close Longs ... + bool canCloseLongs = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_LONGS; + + // + // Close Shorts ... + bool canCloseShorts = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_SHORTS; + + // + // Partial Close ... + bool canPartialClose = + NotEmpty(iGuard.ticket) && + iGuard.volumeMultiplier > 0 && + iGuard.action == X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE; + + // + // Trail Stop ... + bool canTrailStop = + iGuard.sl > 0 && + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + // Trail Target ... + bool canTrailTarget = + iGuard.tp > 0 && + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_TARGET; + + // + // Hedge ... + bool canHedge = iGuard.action == X_121_SMC_GUARD_ACTION_HEDGE; + + // + // Check is Guard Valid ... + bool isValidGuardAction = + canHedge || + canClose || + canCloseAll || + canTrailStop || + canCloseLongs || + canTrailTarget || + canCloseShorts || + canPartialClose; + if (!isValidGuardAction) + { + continue; + } + + // + // Now we Sure to Have a Valid Guard ... + // Start to o Guard Actions ... + + // + // Close All ... + if (canCloseAll) + { + // + XPosition positions[]; + int positionsCount = + mTrader + .GetPositions( + positions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + X_POSITION_TYPE_ALL, // All Types ... + true // Filter by Magic ... + ); + if (IsValidSize(positionsCount)) + { + // + string comment = "Guard Close All ..."; + string message = "Guard Close All (" + ToString(positionsCount) + ") Positions Successfully ..."; + int forceClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (forceClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close Longs ... + if (canCloseLongs) + { + // + XPosition longPositions[]; + XPosition shortPositions[]; + mTrader + .GetPositions( + longPositions, // Result ... + shortPositions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + true // Filter by Magic ... + ); + + // + int longPositionsCount = ArraySize(longPositions); + bool hasLongPositions = IsValidSize(longPositionsCount); + + // + int shortPositionsCount = ArraySize(shortPositions); + bool hasShortPositions = IsValidSize(shortPositionsCount); + + // + if (hasLongPositions) + { + // + string comment = "Guard Close Longs ..."; + string message = "Guard Close (" + ToString(longPositionsCount) + ") Long Positions Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + longPositions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close Shorts ... + if (canCloseShorts) + { + // + XPosition longPositions[]; + XPosition shortPositions[]; + mTrader + .GetPositions( + longPositions, // Result ... + shortPositions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + true // Filter by Magic ... + ); + + // + int longPositionsCount = ArraySize(longPositions); + bool hasLongPositions = IsValidSize(longPositionsCount); + + // + int shortPositionsCount = ArraySize(shortPositions); + bool hasShortPositions = IsValidSize(shortPositionsCount); + + // + if (hasShortPositions) + { + // + string comment = "Guard Close Shorts ..."; + string message = "Guard Close (" + ToString(shortPositionsCount) + ") Short Positions Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + shortPositions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close ... + if (canClose) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + if (hasPosition) + { + // + XPosition positions[]; + AddRef( + iPosition, + positions // + ); + + // + string comment = "Guard Close ..."; + string message = "Guard Close " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Partial Close ... + if (canPartialClose) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + if (hasPosition) + { + // + // Normalize Volume Multiplier ... + double vMult = iGuard.volumeMultiplier; + if (vMult > 0.5) + { + vMult = 0.5; + } + if (vMult < 0) + { + vMult = 0.5; + } + + // + // Calculate and Normalize Volume ... + double volume = iPosition.volume * iGuard.volumeMultiplier; + volume = NormalizeVolume( + volume, + iPosition.symbol // + ); + + // + string comment = "Guard Partially Closed: " + ToString(volume) + " ..."; + string message = "Guard Partially Closed " + (isLong ? "Long" : "Short") + ": " + ToString(volume) + " Successfully ..."; + bool isModified = mTrader.ClosePartial( + iPosition.ticket, + volume, + comment // + ); + if (isModified) + { + // + mTradeHandler.Alert(message); + + // + if (volume == iPosition.volume) + { + // + mTradeHandler.Finish( + iPosition.ticket, + iPosition, + comment // + ); + + // + RestEA(120 * 60); + } + } + } + } + + // + // Hedge ... + if (canHedge) + { + // + XPosition positions[]; + int positionsCount = + mTrader + .GetPositions( + positions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + X_POSITION_TYPE_ALL, // All Types ... + true // Filter by Magic ... + ); + if (IsValidSize(positionsCount)) + { + // + int longs = 0; + double longProfits = 0; + double longVolumes = 0; + + // + int shorts = 0; + double shortProfits = 0; + double shortVolumes = 0; + CountPositions( + positions, + longs, + longProfits, + longVolumes, + shorts, + shortProfits, + shortVolumes // + ); + + // + int count = longs + shorts; + double profits = longProfits + shortProfits; + double volumes = longVolumes + shortVolumes; + + // + bool canDoHedge = + count > 0 && + profits > 0 && + volumes > 0; + if (canDoHedge) + { + // + string comment = "Guard Hedge ..."; + string message = "Guard Hedge (" + ToString(count) + ") Positions by: (" + ToString(profits) + ") Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + } + + // + // Trail Stop ... + if (canTrailStop) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + bool canDoTrail = + hasPosition && + iPosition.profit > 0 && + isLong + ? iPosition.price > iGuard.sl && + (iPosition.sl == 0 || + iPosition.sl < iGuard.sl) + : iPosition.price < iGuard.sl && + (iPosition.sl == 0 || + iPosition.sl > iGuard.sl); + if (canDoTrail) + { + // + string comment = "Guard Trail Stop ..."; + string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Stop Successfully ..."; + bool isModified = mTrader.Modify( + iPosition.ticket, + iGuard.sl, + iPosition.tp, + comment // + ); + if (isModified) + { + mTradeHandler.Alert(message); + } + } + } + + // + // Trail Target ... + if (canTrailTarget) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + bool canDoTrail = + hasPosition && + iGuard.tp != iPosition.tp && + isLong + ? iGuard.tp > iPosition.price + : iGuard.tp < iPosition.price; + if (canDoTrail) + { + // + string comment = "Guard Trail Target ..."; + string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Target Successfully ..."; + bool isModified = mTrader.Modify( + iPosition.ticket, + iPosition.sl, + iGuard.tp, + comment // + ); + if (isModified) + { + mTradeHandler.Alert(message); + } + } + } + } + + // + Clean(guards); + ArrayFree(guards); + } + + // + void RestEA(int seconds) + { + // + } + + // +}; + +// \ No newline at end of file diff --git a/BKPS/14031106/X121SMCEA/Libraries/x-121.smc.guard.lib.mq5 b/BKPS/14031106/X121SMCEA/Libraries/x-121.smc.guard.lib.mq5 new file mode 100644 index 0000000..1050ca6 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Libraries/x-121.smc.guard.lib.mq5 @@ -0,0 +1,1608 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: +// Description: provide all Global Guarding functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +XPriceZones x121SMCDecisionPriceZone; +XPriceZones x121SMCAnalysePriceZone; +XPriceZones x121SMCVerificationPriceZone; +XConsolidationZone x121SMCConsolidationZone; +bool DetectX121SMCGuards( + string provider, // Provider ... + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + string symbol = triggerCycleHelper.GetSymbol(); + ENUM_TIMEFRAMES period = triggerCycleHelper.GetPeriod(); + + // + XPosition ownPositions[]; + XPosition ownLongPositions[]; + XPosition ownShortPositions[]; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + bool isOwn = iPosition + .IsFiltersPassed( + symbol, + provider, + NULL, + X_POSITION_TYPE_ALL, + iPosition.magic // + ); + if (isOwn) + { + // + AddRef( + iPosition, + ownPositions // + ); + + // + bool isLong = IsLong(positions[i].type); + if (isLong) + { + // + AddRef( + iPosition, + ownLongPositions // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPositions // + ); + } + } + } + + // + count = ArraySize(ownPositions); + + // + int longsCount = ArraySize(ownLongPositions); + bool hasLongs = IsValidSize(longsCount); + + // + int shortsCount = ArraySize(ownShortPositions); + bool hasShorts = IsValidSize(shortsCount); + + // + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + // Here we Are Sure there is Positions to Guard ... + // based on Current Provider ... + + // + // Detect Required Data for Analyse Market to Guard Positions ... + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Trigger ... + ENUM_X_DIRECTION triggerTrendDir; + bool hasTriggerTrend = + triggerCycleHelper + .DetectMarketStructure( + triggerTrendDir // + ); + bool hasTriggerBullishTrend = + hasTriggerTrend && + IsBullish(triggerTrendDir); + bool hasTriggerBearishTrend = + hasTriggerTrend && + IsBearish(triggerTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Consolidation Zone ... + int consolidationLoopback = 7; + double consolidationZoneLower = 0; + double consolidationZoneUpper = 0; + bool isConsolidationZoneBreaked = false; + bool isConsolidationZoneBreakedUp = false; + bool isConsolidationZoneBreakedDown = false; + bool hasConsolidationZone = x121SMCConsolidationZone.IsValid(); + + // + if (!hasConsolidationZone) + { + // + double upper = 0; + double lower = 0; + hasConsolidationZone = + triggerCycleHelper + .mBarAnalyser + .IsConsolidate( + cBar, + upper, + lower, + consolidationLoopback // + ); + + // + if (hasConsolidationZone) + { + // + hasConsolidationZone = x121SMCConsolidationZone.Init( + cBar.symbol, + cBar.period, + upper, + lower, + consolidationLoopback // + ); + } + } + + // + if (hasConsolidationZone) + { + // + x121SMCConsolidationZone.Update(); + + // + consolidationZoneUpper = x121SMCConsolidationZone.upper; + consolidationZoneLower = x121SMCConsolidationZone.lower; + + // + isConsolidationZoneBreaked = x121SMCConsolidationZone.IsBreaked(); + isConsolidationZoneBreakedUp = + isConsolidationZoneBreaked && + IsBullish(x121SMCConsolidationZone.breakDirection); + isConsolidationZoneBreakedDown = + isConsolidationZoneBreaked && + IsBearish(x121SMCConsolidationZone.breakDirection); + + // + consolidationZoneUpper = triggerXConditions.peaksBuffer[1]; + consolidationZoneLower = triggerXConditions.valesBuffer[1]; + + // + if (isConsolidationZoneBreaked) + { + x121SMCConsolidationZone.Clean(); + } + } + + // + // Detect Price Zones ... + + // + // Decision ... + double decisionPriceZoneUpper = 0; + double decisionPriceZoneLower = 0; + bool isDecisionPriceZoneBearish = false; + bool isDecisionPriceZoneBullish = false; + bool isDecisionPriceZoneValidForPeak = false; + bool isDecisionPriceZoneValidForVale = false; + bool isDecisionPriceZoneLowerRejected = false; + bool isDecisionPriceZoneUpperRejected = false; + bool isDecisionPriceZoneUpperBreakedUp = false; + bool isDecisionPriceZoneLowerBreakedDown = false; + bool hasDecisionPriceZone = x121SMCDecisionPriceZone.IsValid(); + + // + if (!hasDecisionPriceZone) + { + // + hasDecisionPriceZone = CalculatePriceInsideZones( + x121SMCDecisionPriceZone, + decisionState, + cBar // + ); + } + + // + if (hasDecisionPriceZone) + { + // + bool hasBoundary = x121SMCDecisionPriceZone.GetBoundary( + X_DIRECTION_ALL, + decisionPriceZoneUpper, + decisionPriceZoneLower // + ); + + // + isDecisionPriceZoneBearish = x121SMCDecisionPriceZone.IsBearish(); + isDecisionPriceZoneBullish = x121SMCDecisionPriceZone.IsBullish(); + + // + XOHCL iBar; + bool isInited = iBar.Init( + symbol, + decisionXConditions.period, + cIndex // + ); + + // + if (hasBoundary) + { + // + isDecisionPriceZoneValidForPeak = + decisionXConditions.peaksBuffer[1] <= decisionPriceZoneUpper && + decisionXConditions.peaksBuffer[1] >= decisionPriceZoneLower; + + // + isDecisionPriceZoneValidForVale = + decisionXConditions.valesBuffer[1] <= decisionPriceZoneUpper && + decisionXConditions.valesBuffer[1] >= decisionPriceZoneLower; + + // + isDecisionPriceZoneLowerRejected = + isInited && + IsBarReject( + decisionPriceZoneLower, + X_DIRECTION_BULLISH, + iBar // + ); + + // + isDecisionPriceZoneUpperRejected = + isInited && + IsBarReject( + decisionPriceZoneUpper, + X_DIRECTION_BEARISH, + iBar // + ); + + // + isDecisionPriceZoneUpperBreakedUp = + isInited && + IsBarBreak( + decisionPriceZoneUpper, + X_DIRECTION_BULLISH, + iBar // + ); + + // + isDecisionPriceZoneLowerBreakedDown = + isInited && + IsBarBreak( + decisionPriceZoneUpper, + X_DIRECTION_BEARISH, + iBar // + ); + } + + // + // Clear Price Zone ... + bool canReset = + // + (!isInited || + !hasBoundary) + // + || + // + (isInited && + hasBoundary && + (iBar.high < decisionPriceZoneLower || + iBar.low > decisionPriceZoneUpper)) + // + ; + if (canReset) + { + // + x121SMCDecisionPriceZone.Clean(); + + // + decisionPriceZoneUpper = 0; + decisionPriceZoneLower = 0; + isDecisionPriceZoneBearish = false; + isDecisionPriceZoneBullish = false; + isDecisionPriceZoneValidForPeak = false; + isDecisionPriceZoneValidForVale = false; + isDecisionPriceZoneLowerRejected = false; + isDecisionPriceZoneUpperRejected = false; + isDecisionPriceZoneUpperBreakedUp = false; + isDecisionPriceZoneLowerBreakedDown = false; + } + } + + // + // Analyse ... + double analysePriceZoneUpper = 0; + double analysePriceZoneLower = 0; + bool isAnalysePriceZoneBearish = false; + bool isAnalysePriceZoneBullish = false; + bool isAnalysePriceZoneValidForPeak = false; + bool isAnalysePriceZoneValidForVale = false; + bool isAnalysePriceZoneLowerRejected = false; + bool isAnalysePriceZoneUpperRejected = false; + bool isAnalysePriceZoneUpperBreakedUp = false; + bool isAnalysePriceZoneLowerBreakedDown = false; + bool hasAnalysePriceZone = x121SMCAnalysePriceZone.IsValid(); + + // + if (!hasAnalysePriceZone) + { + // + hasAnalysePriceZone = CalculatePriceInsideZones( + x121SMCAnalysePriceZone, + analyseState, + cBar // + ); + } + + // + if (hasAnalysePriceZone) + { + // + bool hasBoundary = x121SMCAnalysePriceZone.GetBoundary( + X_DIRECTION_ALL, + analysePriceZoneUpper, + analysePriceZoneLower // + ); + + // + isAnalysePriceZoneBearish = x121SMCAnalysePriceZone.IsBearish(); + isAnalysePriceZoneBullish = x121SMCAnalysePriceZone.IsBullish(); + + // + XOHCL iBar; + bool isInited = iBar.Init( + symbol, + analyseXConditions.period, + cIndex // + ); + + // + if (hasBoundary) + { + // + isAnalysePriceZoneValidForPeak = + analyseXConditions.peaksBuffer[1] <= analysePriceZoneUpper && + analyseXConditions.peaksBuffer[1] >= analysePriceZoneLower; + + // + isAnalysePriceZoneValidForVale = + analyseXConditions.valesBuffer[1] <= analysePriceZoneUpper && + analyseXConditions.valesBuffer[1] >= analysePriceZoneLower; + + // + isAnalysePriceZoneLowerRejected = + isInited && + IsBarReject( + analysePriceZoneLower, + X_DIRECTION_BULLISH, + iBar // + ); + + // + isAnalysePriceZoneUpperRejected = + isInited && + IsBarReject( + analysePriceZoneUpper, + X_DIRECTION_BEARISH, + iBar // + ); + + // + isAnalysePriceZoneUpperBreakedUp = + isInited && + IsBarBreak( + analysePriceZoneUpper, + X_DIRECTION_BULLISH, + iBar // + ); + + // + isAnalysePriceZoneLowerBreakedDown = + isInited && + IsBarBreak( + analysePriceZoneUpper, + X_DIRECTION_BEARISH, + iBar // + ); + } + + // + // Clear Price Zone ... + bool canReset = + // + (!isInited || + !hasBoundary) + // + || + // + (isInited && + hasBoundary && + (iBar.high < analysePriceZoneLower || + iBar.low > analysePriceZoneUpper)) + // + ; + if (canReset) + { + // + x121SMCAnalysePriceZone.Clean(); + + // + analysePriceZoneUpper = 0; + analysePriceZoneLower = 0; + isAnalysePriceZoneBearish = false; + isAnalysePriceZoneBullish = false; + isAnalysePriceZoneValidForPeak = false; + isAnalysePriceZoneValidForVale = false; + isAnalysePriceZoneLowerRejected = false; + isAnalysePriceZoneUpperRejected = false; + isAnalysePriceZoneUpperBreakedUp = false; + isAnalysePriceZoneLowerBreakedDown = false; + } + } + + // + // Verification ... + double verificationPriceZoneUpper = 0; + double verificationPriceZoneLower = 0; + bool isVerificationPriceZoneBearish = false; + bool isVerificationPriceZoneBullish = false; + bool isVerificationPriceZoneValidForPeak = false; + bool isVerificationPriceZoneValidForVale = false; + bool isVerificationPriceZoneLowerRejected = false; + bool isVerificationPriceZoneUpperRejected = false; + bool isVerificationPriceZoneUpperBreakedUp = false; + bool isVerificationPriceZoneLowerBreakedDown = false; + bool hasVerificationPriceZone = x121SMCVerificationPriceZone.IsValid(); + + // + if (!hasVerificationPriceZone) + { + // + hasVerificationPriceZone = CalculatePriceInsideZones( + x121SMCVerificationPriceZone, + verificationState, + cBar // + ); + } + + // + if (hasVerificationPriceZone) + { + // + bool hasBoundary = x121SMCVerificationPriceZone.GetBoundary( + X_DIRECTION_ALL, + verificationPriceZoneUpper, + verificationPriceZoneLower // + ); + + // + isVerificationPriceZoneBearish = x121SMCVerificationPriceZone.IsBearish(); + isVerificationPriceZoneBullish = x121SMCVerificationPriceZone.IsBullish(); + + // + XOHCL iBar; + bool isInited = iBar.Init( + symbol, + verificationXConditions.period, + cIndex // + ); + + // + if (hasBoundary) + { + // + isVerificationPriceZoneValidForPeak = + verificationXConditions.peaksBuffer[1] <= verificationPriceZoneUpper && + verificationXConditions.peaksBuffer[1] >= verificationPriceZoneLower; + + // + isVerificationPriceZoneValidForVale = + verificationXConditions.valesBuffer[1] <= verificationPriceZoneUpper && + verificationXConditions.valesBuffer[1] >= verificationPriceZoneLower; + + // + isVerificationPriceZoneLowerRejected = + isInited && + IsBarReject( + verificationPriceZoneLower, + X_DIRECTION_BULLISH, + iBar // + ); + + // + isVerificationPriceZoneUpperRejected = + isInited && + IsBarReject( + verificationPriceZoneUpper, + X_DIRECTION_BEARISH, + iBar // + ); + + // + isVerificationPriceZoneUpperBreakedUp = + isInited && + IsBarBreak( + verificationPriceZoneUpper, + X_DIRECTION_BULLISH, + iBar // + ); + + // + isVerificationPriceZoneLowerBreakedDown = + isInited && + IsBarBreak( + verificationPriceZoneUpper, + X_DIRECTION_BEARISH, + iBar // + ); + } + + // + // Clear Price Zone ... + bool canReset = + // + (!isInited || + !hasBoundary) + // + || + // + (isInited && + hasBoundary && + (iBar.high < verificationPriceZoneLower || + iBar.low > verificationPriceZoneUpper)) + // + ; + if (canReset) + { + // + x121SMCVerificationPriceZone.Clean(); + + // + verificationPriceZoneUpper = 0; + verificationPriceZoneLower = 0; + isVerificationPriceZoneBearish = false; + isVerificationPriceZoneBullish = false; + isVerificationPriceZoneValidForPeak = false; + isVerificationPriceZoneValidForVale = false; + isVerificationPriceZoneLowerRejected = false; + isVerificationPriceZoneUpperRejected = false; + isVerificationPriceZoneUpperBreakedUp = false; + isVerificationPriceZoneLowerBreakedDown = false; + } + } + + // + // Here We Have all Requirements for Guarding Positions ... + + // + // Close ... + + // + double tpCloseDiff = (15 * points); + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPositions[i]; + + // + // Position Must be In Profit ... + if (iPosition.profit <= 0) + { + continue; + } + + // + bool isPricePassed = MathAbs(iPosition.tp - iPosition.price) <= tpCloseDiff; + if (!isPricePassed) + { + continue; + } + + // + bool isLong = IsLong(iPosition.type); + + // + bool iHasGuard = + // + isLong + ? // + (hasDecisionPriceZone && + isDecisionPriceZoneBearish && + isDecisionPriceZoneValidForPeak) + // + || + // + (hasAnalysePriceZone && + isAnalysePriceZoneBearish && + isAnalysePriceZoneValidForPeak) + // + || + // + (hasVerificationPriceZone && + isVerificationPriceZoneBearish && + isVerificationPriceZoneValidForPeak) + : // + (hasDecisionPriceZone && + isDecisionPriceZoneBullish && + isDecisionPriceZoneValidForVale) + // + || + // + (hasAnalysePriceZone && + isAnalysePriceZoneBullish && + isAnalysePriceZoneValidForVale) + // + || + // + (hasVerificationPriceZone && + isVerificationPriceZoneBullish && + isVerificationPriceZoneValidForVale) + // + ; + if (iHasGuard) + { + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_CLOSE; + + // + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + + // + if (hasLongs) + { + // + bool hasGuard = hasDecisionBearishTrend; + + // + if (hasGuard) + { + // + for (int i = 0; i < longsCount; i++) + { + // + XPosition iPosition = ownLongPositions[i]; + + // + // Position must be in Draw Down ... + if (iPosition.profit > 0) + { + continue; + } + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_CLOSE; + + // + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + if (hasShorts) + { + // + bool hasGuard = hasDecisionBullishTrend; + + // + if (hasGuard) + { + // + for (int i = 0; i < shortsCount; i++) + { + // + XPosition iPosition = ownShortPositions[i]; + + // + // Position must be in Draw Down ... + if (iPosition.profit > 0) + { + continue; + } + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_CLOSE; + + // + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + // Close All ... + + // + MqlDateTime mDate; + bool hasDate = TimeCurrent(mDate); + if (hasDate) + { + // + ENUM_X_WEEK_DAYS dayOfWeek = GetDayOfWeek(); + + // + bool isWeekend = dayOfWeek == X_WEEK_DAY_FRIDAY; + if (isWeekend && mDate.hour == 23 && mDate.min == 30) + { + // + X121SMCGuard guard; + + // + guard.time = cTime; + guard.symbol = symbol; + guard.provider = provider; + guard.action = X_121_SMC_GUARD_ACTION_CLOSE_ALL; + + // + AddGuard( + guard, + guards // + ); + } + } + + // + // Close Longs ... + if (hasLongs) + { + // + bool hasGuard = + // + hasAnalyseBearishTrend && + hasDecisionBearishTrend + // + ; + + // + if (hasGuard) + { + // + X121SMCGuard guard; + + // + guard.time = cTime; + guard.symbol = symbol; + guard.provider = provider; + guard.action = X_121_SMC_GUARD_ACTION_CLOSE_LONGS; + + // + AddGuard( + guard, + guards // + ); + } + } + + // + // Close Shorts ... + if (hasShorts) + { + // + bool hasGuard = + // + hasAnalyseBullishTrend && + hasDecisionBullishTrend + // + ; + + // + if (hasGuard) + { + // + X121SMCGuard guard; + + // + guard.time = cTime; + guard.symbol = symbol; + guard.provider = provider; + guard.action = X_121_SMC_GUARD_ACTION_CLOSE_SHORTS; + + // + AddGuard( + guard, + guards // + ); + } + } + + // + // Partial Close ... + + // + if (hasLongs) + { + // + bool hasGuard = + // + hasTriggerBearishTrend || + !hasDecisionBullishTrend + // + ; + + // + if (hasGuard) + { + // + for (int i = 0; i < longsCount; i++) + { + // + XPosition iPosition = ownLongPositions[i]; + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE; + + // + iGuard.ticket = iPosition.ticket; + iGuard.volumeMultiplier = 0.5; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + if (hasShorts) + { + // + bool hasGuard = + // + hasTriggerBullishTrend || + !hasDecisionBearishTrend + // + ; + + // + if (hasGuard) + { + // + for (int i = 0; i < shortsCount; i++) + { + // + XPosition iPosition = ownShortPositions[i]; + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE; + + // + iGuard.ticket = iPosition.ticket; + iGuard.volumeMultiplier = 0.5; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + // Trail Stop ... + + // + if (hasLongs) + { + // + bool hasTrendGuard = hasDecisionBearishTrend; + + // + bool hasConsolidationGuard = + (hasConsolidationZone && + isConsolidationZoneBreaked && + isConsolidationZoneBreakedUp); + + // + bool hasDecisionPriceZoneGuard = + (hasDecisionPriceZone && + isDecisionPriceZoneBullish && + isDecisionPriceZoneValidForVale && + isDecisionPriceZoneUpperBreakedUp); + + // + bool hasAnalysePriceZoneGuard = + (hasAnalysePriceZone && + isAnalysePriceZoneBullish && + isAnalysePriceZoneValidForVale && + isAnalysePriceZoneUpperBreakedUp); + + // + bool hasVerificationPriceZoneGuard = + (hasVerificationPriceZone && + isVerificationPriceZoneBullish && + isVerificationPriceZoneValidForVale && + isVerificationPriceZoneUpperBreakedUp); + + // + bool hasGuard = + // + hasTrendGuard || + hasConsolidationGuard || + hasDecisionPriceZoneGuard || + hasAnalysePriceZoneGuard || + hasVerificationPriceZoneGuard + // + ; + + // + double guardStop = + hasConsolidationGuard + ? consolidationZoneLower + : hasDecisionPriceZoneGuard + ? decisionPriceZoneLower + : hasAnalysePriceZoneGuard + ? analysePriceZoneLower + : hasVerificationPriceZoneGuard + ? verificationPriceZoneLower + : 0; + + // + if (hasGuard) + { + // + for (int i = 0; i < longsCount; i++) + { + // + XPosition iPosition = ownLongPositions[i]; + + // + // Position Must Be In Profit ... + if (iPosition.profit <= 0) + { + continue; + } + + // + if (hasTrendGuard) + { + guardStop = decisionXConditions.strBuffer[1] - decisionXConditions.atrBuffer[1]; + } + + // + // Price Must Greater than Zone Lower ... + if (iPosition.price < guardStop) + { + continue; + } + + // + // Position Entry Must Lesser than Zone Lower ... + if (iPosition.entry > guardStop) + { + continue; + } + + // + // Position SL must be Zero or Lesser than Zone Lower ... + if (iPosition.sl != 0 && + iPosition.sl > guardStop) + { + continue; + } + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.sl = guardStop; + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + if (hasShorts) + { + // + bool hasTrendGuard = hasDecisionBullishTrend; + + // + bool hasConsolidationGuard = + (hasConsolidationZone && + isConsolidationZoneBreaked && + isConsolidationZoneBreakedDown); + + // + bool hasDecisionPriceZoneGuard = + (hasDecisionPriceZone && + isDecisionPriceZoneBearish && + isDecisionPriceZoneValidForPeak && + isDecisionPriceZoneLowerBreakedDown); + + // + bool hasAnalysePriceZoneGuard = + (hasAnalysePriceZone && + isAnalysePriceZoneBearish && + isAnalysePriceZoneValidForPeak && + isAnalysePriceZoneLowerBreakedDown); + + // + bool hasVerificationPriceZoneGuard = + (hasVerificationPriceZone && + isVerificationPriceZoneBearish && + isVerificationPriceZoneValidForPeak && + isVerificationPriceZoneLowerBreakedDown); + + // + bool hasGuard = + // + hasTrendGuard || + hasConsolidationGuard || + hasDecisionPriceZoneGuard || + hasAnalysePriceZoneGuard || + hasVerificationPriceZoneGuard + // + ; + + // + double guardStop = + hasConsolidationGuard + ? consolidationZoneUpper + : hasDecisionPriceZoneGuard + ? decisionPriceZoneUpper + : hasAnalysePriceZoneGuard + ? analysePriceZoneUpper + : hasVerificationPriceZoneGuard + ? verificationPriceZoneUpper + : 0; + + // + if (hasGuard) + { + // + for (int i = 0; i < shortsCount; i++) + { + // + XPosition iPosition = ownShortPositions[i]; + + // + // Position Must Be In Profit ... + if (iPosition.profit <= 0) + { + continue; + } + + // + if (hasTrendGuard) + { + guardStop = decisionXConditions.strBuffer[1] + decisionXConditions.atrBuffer[1]; + } + + // + // Price Must Lesser than Zone Upper ... + if (iPosition.price > guardStop) + { + continue; + } + + // + // Position Entry Must Greater than Zone Upper ... + if (iPosition.entry < guardStop) + { + continue; + } + + // + // Position SL must be Zero or Greater than Zone Upper ... + if (iPosition.sl != 0 && + iPosition.sl < guardStop) + { + continue; + } + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.sl = guardStop; + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + // Trail Target ... + + // + if (hasLongs) + { + // + bool hasAnalyseGuard = + // + (hasAnalysePriceZone && + isAnalysePriceZoneValidForPeak && + isAnalysePriceZoneUpperRejected) + // + ; + + // + bool hasVerificationGuard = + // + (hasVerificationPriceZone && + isVerificationPriceZoneValidForPeak && + isVerificationPriceZoneUpperRejected) + // + ; + + // + bool hasGuard = + // + hasAnalyseGuard || + hasVerificationGuard + // + ; + + // + double guardTP = + hasAnalyseGuard + ? analysePriceZoneUpper + : hasVerificationGuard + ? verificationPriceZoneUpper + : 0; + + // + if (hasGuard) + { + // + for (int i = 0; i < longsCount; i++) + { + // + XPosition iPosition = ownLongPositions[i]; + + // + // Position Must Be In Profit ... + if (iPosition.profit <= 0) + { + continue; + } + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_TARGET; + + // + iGuard.tp = guardTP; + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + if (hasShorts) + { + // + bool hasAnalyseGuard = + // + (hasAnalysePriceZone && + isAnalysePriceZoneValidForVale && + isAnalysePriceZoneLowerRejected) + // + ; + + // + bool hasVerificationGuard = + // + (hasVerificationPriceZone && + isVerificationPriceZoneValidForVale && + isVerificationPriceZoneLowerRejected) + // + ; + + // + bool hasGuard = + // + hasAnalyseGuard || + hasVerificationGuard + // + ; + + // + double guardTP = + hasAnalyseGuard + ? analysePriceZoneLower + : hasVerificationGuard + ? verificationPriceZoneLower + : 0; + + // + if (hasGuard) + { + // + for (int i = 0; i < shortsCount; i++) + { + // + XPosition iPosition = ownShortPositions[i]; + + // + // Position Must Be In Profit ... + if (iPosition.profit <= 0) + { + continue; + } + + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = provider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_TARGET; + + // + iGuard.tp = guardTP; + iGuard.ticket = iPosition.ticket; + + // + AddGuard( + iGuard, + guards // + ); + } + } + } + + // + // Hedge ... + // TODO: Implement Hedge ... + + // + // Release Arrays ... + ArrayFree(ownPositions); + ArrayFree(ownLongPositions); + ArrayFree(ownShortPositions); + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; +} diff --git a/BKPS/14031106/X121SMCEA/Libraries/x-121.smc.lib.mq5 b/BKPS/14031106/X121SMCEA/Libraries/x-121.smc.lib.mq5 new file mode 100644 index 0000000..a8be496 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Libraries/x-121.smc.lib.mq5 @@ -0,0 +1,749 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: X121SMCLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.base.class.mq5" +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../../Helpers/x-saherelm.x121.helper.mq5" +#include "../../Libraries/x-saherelm.common.lib.mq5" +#include "../../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... + +// +const string X121SMCStrategyToken = "X121SMC"; + +// +const string X121SMCXToken = "X121X"; +const string X121SMCXOBPVToken = "X121XOBPV"; + +// +// X121 SMC Providers ... +enum ENUM_X_121_SMC_PROVIDERS +{ + // + X_121_SMC_PROVIDER_NONE, + X_121_SMC_PROVIDER_X, + X_121_SMC_PROVIDER_XOBPV, +}; + +// +// Guard Actions ... +enum ENUM_X_121_SMC_GUARD_ACTIONS +{ + X_121_SMC_GUARD_ACTION_NONE, // Nothing to Do + X_121_SMC_GUARD_ACTION_CLOSE, // Close Specified Position + X_121_SMC_GUARD_ACTION_CLOSE_ALL, // Close All Positions + X_121_SMC_GUARD_ACTION_CLOSE_LONGS, // Close All Long Positions + X_121_SMC_GUARD_ACTION_CLOSE_SHORTS, // Close All Short Position + X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE, // Partial Close Specified Position + X_121_SMC_GUARD_ACTION_TRAIL_STOP, // Trail Stop of Specified Position + X_121_SMC_GUARD_ACTION_TRAIL_TARGET, // Trail Target of Specified Position + X_121_SMC_GUARD_ACTION_HEDGE, // Hedge Specified Positions +}; + +// +// Each Market Cycle (Time Frame) Conditions +// Model as this Structure ... +struct X121SMCCycleConditions +{ + // + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + X121Conditions x121Conditions; + + // + XPOIState state; + + // + void X121SMCStrategyConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + symbol = NULL; + period = NULL; + time = NULL; + + // + state.Clean(); + x121Conditions.Clean(); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + // + ; + + // + return result; + } + + // + // Reporter Functions ... + + /** + * Generate Provided Scores ... + * + * @param bullishScore: Integer, reference ... + * @param bearishScore: Integer, referenceF ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + if (!IsValid()) + { + return; + } + + // + double bullScore = 0; + double bearScore = 0; + } + + /** + * Generate Summary ... + * + * @param onlyCommons: Boolean ... + * @param onlyConditions: Boolean ... + * @param includeScores: Boolean ... + * @param ignoreFalseConditions: Boolean ... + * @param separator: String ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores, + true // + ); + + // + string conditionsStr = + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + "----------" + separator + + (onlyConditions + ? "" + : commonStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Get Unique Identifier ... + * + * @param forObject: Boolean ... + * + * @return ( string ) + */ + string GetTag( + bool forObject = false // + ) + { + // + string result = NULL; + + // + string typeName = GetTypeName(this); + + // + if (!forObject) + { + result = typeName; + } + else + { + // + result = typeName + "_" + + symbol + "_" + ToString(period) + "_" + + ToMD5(time); + } + + // + return result; + } + + // +}; + +// +// Model Signalling Conditions ... +struct X121SMCStrategyConditions +{ + // + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + double sl; + double tp; + double target; + string provider; + ENUM_X_DIRECTION signalDir; + + // + X121Conditions conditions; + // XPriceZones priceZones; + // XPriceZones decisionZones; + // XMarketStructure marketStructure; + + // + void X121SMCStrategyConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + symbol = NULL; + period = NULL; + time = NULL; + + // + sl = 0; + tp = 0; + provider = NULL; + signalDir = X_DIRECTION_NONE; + + // + conditions.Clean(); + // priceZones.Clean(); + // decisionZones.Clean(); + // marketStructure.Clean(); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + + // + return result; + } + + /** + * Check Conditions Has Valid Bullish Signal ... + * + * @return ( bool ) + */ + bool HasBullishSignal() + { + // + bool result = false; + + // + result = + (sl > 0 || + tp > 0) && + IsValid() && + HasDirection(signalDir); + if (!result) + { + return result; + } + + // + result = + IsBullish(signalDir); + + // + return result; + } + + /** + * Check Conditions Has Valid Bearish Signal ... + * + * @return ( bool ) + */ + bool HasBearishSignal() + { + // + bool result = false; + + // + result = + (sl > 0 || + tp > 0) && + IsValid() && + HasDirection(signalDir); + if (!result) + { + return result; + } + + // + result = + IsBearish(signalDir); + + // + return result; + } + + // + // Reporter Functions ... + + /** + * Generate Provided Scores ... + * + * @param bullishScore: Integer, reference ... + * @param bearishScore: Integer, referenceF ... + */ + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + if (!IsValid()) + { + return; + } + + // + double bullScore = 0; + double bearScore = 0; + } + + /** + * Generate Summary ... + * + * @param onlyCommons: Boolean ... + * @param onlyConditions: Boolean ... + * @param includeScores: Boolean ... + * @param ignoreFalseConditions: Boolean ... + * @param separator: String ... + * + * @return ( string ) + */ + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores, + true // + ); + + // + string conditionsStr = + // + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + "----------" + separator + + (onlyConditions + ? "" + : commonStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + /** + * Get Unique Identifier ... + * + * @param forObject: Boolean ... + * + * @return ( string ) + */ + string GetTag( + bool forObject = false // + ) + { + // + string result = NULL; + + // + string typeName = GetTypeName(this); + + // + if (!forObject) + { + result = typeName; + } + else + { + // + result = typeName + "_" + + symbol + "_" + ToString(period) + "_" + + ToMD5(time); + } + + // + return result; + } + + // +}; + +// +// Model a Guard Action ... +struct X121SMCGuard +{ + // + // Props ... + ENUM_X_121_SMC_GUARD_ACTIONS action; + datetime time; + + // + string symbol; + string provider; + + // + // Specified Position ... + ulong ticket; + + // + // Partial Close ... + double volumeMultiplier; + + // + // SL Trial ... + double sl; + + // + // TP Trial ... + double tp; + + // + // Constructor ... + X121SMCGuard() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + time = NULL; + action = X_121_SMC_GUARD_ACTION_NONE; + + // + symbol = NULL; + provider = NULL; + + // + ticket = 0; + + // + volumeMultiplier = 0; + + // + sl = 0; + tp = 0; + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(time) && + IsValid(symbol) && + IsValid(provider) && + action != X_121_SMC_GUARD_ACTION_NONE + // + ; + if (!result) + { + return result; + } + + // + // Validate Model Based On Specified Guard Actions ... + + // + return result; + } +}; + +/** + * Add Guard to Collection ... + * + * @param guard: X121SMCGuard instance ... + * @param guards: X121SMCGuard instance Collection ... + * + * @return ( int ) + */ +int AddGuard( + X121SMCGuard &guard, + X121SMCGuard &guards[] // +) +{ + // + int result = 0; + + // + if (!guard.IsValid()) + { + return result; + } + + // + AddRef( + guard, + guards // + ); + + // + result = ArraySize(guards); + + // + return result; +} + +// +// +// + +typedef void (*TOnX121SMCSignal)( + XSignal &signal, + X121SMCStrategyConditions &conditions // +); + +// +// Extentions ... + +/** + * Validate a Signal Provider ... + * + * @param value: ENUM_X_121_SMC_PROVIDERS member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_121_SMC_PROVIDERS value) +{ + // + bool result = false; + + // + result = value != X_121_SMC_PROVIDER_NONE; + + // + return result; +} + +/** + * Converts a Signal Provider to String ... + * + * @param value: ENUM_X_121_SMC_PROVIDERS member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_121_SMC_PROVIDERS value) +{ + // + string result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + switch (value) + { + // + case X_121_SMC_PROVIDER_X: + result = X121SMCXToken; + break; + + // + case X_121_SMC_PROVIDER_XOBPV: + result = X121SMCXOBPVToken; + break; + } + + // + return result; +} + +/** + * Parse Specified String as a Signal Provider ... + * + * @param value: String ... + * + * @return ( ENUM_X_121_SMC_PROVIDERS ) + */ +ENUM_X_121_SMC_PROVIDERS ParseProvider(string value) +{ + // + ENUM_X_121_SMC_PROVIDERS result = X_121_SMC_PROVIDER_NONE; + + // + if (!IsValid(value)) + { + return result; + } + + // + if (Contains(X121SMCXToken, value)) + { + result = X_121_SMC_PROVIDER_X; + } + else if (Contains(X121SMCXOBPVToken, value)) + { + result = X_121_SMC_PROVIDER_XOBPV; + } + + // + return result; +} + +// \ No newline at end of file diff --git a/BKPS/14031106/X121SMCEA/Signals/x-121.smc.x.signal.lib.mq5 b/BKPS/14031106/X121SMCEA/Signals/x-121.smc.x.signal.lib.mq5 new file mode 100644 index 0000000..7bf44dc --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Signals/x-121.smc.x.signal.lib.mq5 @@ -0,0 +1,1724 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: X +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + XCOrderBlock *bullishOBs[]; + XCOrderBlock *bearishOBs[]; + + // + // Constructor ... + X121SMCStrategyXSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + Clean(bullishOBs); + Clean(bearishOBs); + + // + } + + // + int CountBullishOBs() + { + return ArraySize(bullishOBs); + } + + // + bool HasBullishOBs() + { + return IsValidSize(CountBullishOBs()); + } + + // + int CountBearishOBs() + { + return ArraySize(bearishOBs); + } + + // + bool HasBearishOBs() + { + return IsValidSize(CountBearishOBs()); + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXSignalConditions mXConditions; +X121SMCStrategyXSignalConditions mXConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXSignalSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXConditions = triggerConditions.x121Conditions; + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + X121Conditions analyseXConditions = analyseConditions.x121Conditions; + X121Conditions verificationXConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXConditions = consolidationConditions.x121Conditions; + X121Conditions visionXConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // PinBar ... + ENUM_X_DIRECTION cBarPinDir; + bool isCBarPin = decisionCycleHelper + .mBarAnalyser + .IsPinBar( + cBar, + cBarPinDir, + 1 // + ); + bool isCBarBullishPin = + isCBarPin && + IsBullish(cBarPinDir); + bool isCBarBearishPin = + isCBarPin && + IsBearish(cBarPinDir); + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // Pull Back ... + ENUM_X_DIRECTION cBarPullbackDir; + bool isCBarPullbacked = + decisionCycleHelper + .mBarAnalyser + .HasPullBack( + cBarPullbackDir, + cBar // + ); + bool isCBarBullishPullbacked = + isCBarPullbacked && + IsBullish(cBarPullbackDir); + bool isCBarBearishPullbacked = + isCBarPullbacked && + IsBearish(cBarPullbackDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bars Pattern and Power and Pressures ... + + // + bool hasCBarBullishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBullishPattern( + cBar, + 2 // + ); + + // + bool hasCBarBearishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBearishPattern( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPower = + decisionCycleHelper + .mBarAnalyser + .HasBullishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPower = + decisionCycleHelper + .mBarAnalyser + .HasBearishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBullishPressure( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBearishPressure( + cBar, + 2 // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + ( + // + hasCBarBullishPattern && + isCBarHasBullishPower && + isCBarHasBullishPressure + // + ) + // + || + // + ( + // + isCBarBullishPin || + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ) + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + ( + // + hasCBarBearishPattern && + isCBarHasBearishPower && + isCBarHasBearishPressure + // + ) + // + || + // + ( + // + isCBarBearishPin || + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ) + // + ; + + // + // Detect Order Block ... + + // + bool hasBullishOrderBlocks = conditions.HasBullishOBs(); + int bullishOrderBlocksCount = conditions.CountBullishOBs(); + + // + bool hasBearishOrderBlocks = conditions.HasBearishOBs(); + int bearishOrderBlocksCount = conditions.CountBearishOBs(); + + // + bool hasOrderBlocks = hasBullishOrderBlocks && + hasBearishOrderBlocks; + if (!hasOrderBlocks) + { + // + XCOrderBlock *bullishOBs[]; + XCOrderBlock *bearishOBs[]; + bool hasOrderBlocks = visionCycleHelper.DetectOrderBlocks( + bullishOBs, + bearishOBs // + ); + + // + if (!hasBullishOrderBlocks) + { + // + Copy( + bullishOBs, + conditions.bullishOBs // + ); + } + + // + if (!hasBearishOrderBlocks) + { + // + Copy( + bearishOBs, + conditions.bearishOBs // + ); + } + + // + hasBullishOrderBlocks = conditions.HasBullishOBs(); + bullishOrderBlocksCount = conditions.CountBullishOBs(); + + // + hasBearishOrderBlocks = conditions.HasBearishOBs(); + bearishOrderBlocksCount = conditions.CountBearishOBs(); + } + + // + bool hasOldestBullishOB = false; + bool hasYoungestBullishOB = false; + XCOrderBlock *oldestBullishOB = NULL; + XCOrderBlock *youngestBullishOB = NULL; + if (hasBullishOrderBlocks) + { + // + XCZone *zones[]; + bool isConverted = ToZone( + conditions.bullishOBs, + zones // + ); + + // + int oldestIDX = GetOldest(zones); + hasOldestBullishOB = IsValidIndex(oldestIDX); + if (hasOldestBullishOB) + { + oldestBullishOB = conditions.bullishOBs[oldestIDX]; + } + + // + int youngestIDX = GetYoungest(zones); + hasYoungestBullishOB = IsValidIndex(youngestIDX); + if (hasYoungestBullishOB) + { + youngestBullishOB = conditions.bullishOBs[youngestIDX]; + } + } + + // + bool hasOldestBearishOB = false; + bool hasYoungestBearishOB = false; + XCOrderBlock *oldestBearishOB = NULL; + XCOrderBlock *youngestBearishOB = NULL; + if (hasBearishOrderBlocks) + { + // + XCZone *zones[]; + bool isConverted = ToZone( + conditions.bearishOBs, + zones // + ); + + // + int oldestIDX = GetOldest(zones); + hasOldestBearishOB = IsValidIndex(oldestIDX); + if (hasOldestBearishOB) + { + oldestBearishOB = conditions.bearishOBs[oldestIDX]; + } + + // + int youngestIDX = GetYoungest(zones); + hasYoungestBearishOB = IsValidIndex(youngestIDX); + if (hasYoungestBearishOB) + { + youngestBearishOB = conditions.bearishOBs[youngestIDX]; + } + } + + // + bool hasPriceInsideOB = false; + XCOrderBlock *priceInsideOB = NULL; + + // + if (!hasPriceInsideOB && + hasBullishOrderBlocks) + { + // + for (int i = 0; i < bullishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bullishOBs[i]; + + // + bool isInside = IsPriceInsideZone( + decisionXConditions.valesBuffer[1], + (XCZone *)iOb // + ); + if (isInside) + { + // + hasPriceInsideOB = true; + priceInsideOB = iOb; + break; + } + } + } + + // + if (!hasPriceInsideOB && + hasBearishOrderBlocks) + { + // + for (int i = 0; i < bearishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bearishOBs[i]; + + // + bool isInside = IsPriceInsideZone( + decisionXConditions.peaksBuffer[1], + (XCZone *)iOb // + ); + if (isInside) + { + // + hasPriceInsideOB = true; + priceInsideOB = iOb; + break; + } + } + } + + // + XStateZones obState; + bool hasOBState = false; + XOHCL priceInsideOBBreakerBar; + if (hasPriceInsideOB) + { + // + XOHCL toBar; + XOHCL fromBar; + ENUM_X_DIRECTION forDir = + priceInsideOB.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + bool hasBreakerBar = HasBreakerBar( + toBar, + fromBar, + priceInsideOBBreakerBar, + forDir, + priceInsideOB.GetSymbol(), + priceInsideOB.GetPeriod(), + (XCZone *)priceInsideOB // + ); + if (hasBreakerBar) + { + // + CalculateStateZones( + obState, + consolidationState, + priceInsideOB.Upper(), + priceInsideOB.Lower(), + priceInsideOBBreakerBar.time // + ); + } + + // + hasOBState = obState.IsValid(); + } + + // + bool isSameCyclesPeak = + // + triggerXConditions.peaksBuffer[1] == decisionXConditions.peaksBuffer[1] && + decisionXConditions.peaksBuffer[1] == analyseXConditions.peaksBuffer[1] && + analyseXConditions.peaksBuffer[1] == verificationXConditions.peaksBuffer[1] && + verificationXConditions.peaksBuffer[1] == consolidationXConditions.peaksBuffer[1] + // + ; + + // + bool isSameCyclesVale = + // + triggerXConditions.valesBuffer[1] == decisionXConditions.valesBuffer[1] && + decisionXConditions.valesBuffer[1] == analyseXConditions.valesBuffer[1] && + analyseXConditions.valesBuffer[1] == verificationXConditions.valesBuffer[1] && + verificationXConditions.valesBuffer[1] == consolidationXConditions.valesBuffer[1] + // + ; + + // + bool hasSameCyclesPV = + hasOBState && + hasPriceInsideOB && + (isSameCyclesPeak || + isSameCyclesVale); + + // + // DRAW ... + // + + // + XCBaseObject *drawnObjects[]; + + // + if (hasBullishOrderBlocks) + { + // + for (int i = 0; i < bullishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bullishOBs[i]; + + // + XCBullishOrderBlockObject *iObObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateBullishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + if (hasBearishOrderBlocks) + { + // + for (int i = 0; i < bearishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bearishOBs[i]; + + // + XCBearishOrderBlockObject *iObObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateBearishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + // if (hasOldestBullishOB) + // { + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBullishOrderBlock( + // oldestBullishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasYoungestBullishOB) + // { + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBullishOrderBlock( + // youngestBullishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasOldestBearishOB) + // { + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBearishOrderBlock( + // oldestBearishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasYoungestBearishOB) + // { + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBearishOrderBlock( + // youngestBearishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // + if (hasPriceInsideOB) + { + // + bool isBullish = priceInsideOB.IsBullish(); + + // + bool isCreated = false; + XCBaseObject *iObObj = NULL; + if (isBullish) + { + // + XCBullishOrderBlockObject *iObj; + isCreated = visionCycleHelper + .mPOIDrawer + .CreateBullishOrderBlock( + priceInsideOB, + iObj // + ); + + // + if (isCreated) + { + // + iObj.ZoneColor(clrYellow); + iObObj = (XCBaseObject *)iObj; + } + } + else + { + // + XCBearishOrderBlockObject *iObj; + isCreated = visionCycleHelper + .mPOIDrawer + .CreateBearishOrderBlock( + priceInsideOB, + iObj // + ); + + // + if (isCreated) + { + // + iObj.ZoneColor(clrOrangeRed); + iObObj = (XCBaseObject *)iObj; + } + } + + // + if (isCreated) + { + // + Add( + iObObj, + drawnObjects // + ); + } + } + + // + if (hasOBState) + { + // + XCBaseObject *stateObjects[]; + int stateObjectsCount = consolidationCycleHelper + .mPOIDrawer + .DrawStateZones( + obState, + stateObjects // + ); + if (IsValidSize(stateObjectsCount)) + { + // + Copy( + stateObjects, + drawnObjects, + false // + ); + } + } + + // + int drawnCount = ArraySize(drawnObjects); + if (IsValidSize(drawnCount)) + { + } + + // + // + // + + // + // Summarize Conditions ... + + // + bool isCondition1Bullish = + // + hasSameCyclesPV && + isCBarBullishFormed && + priceInsideOB.IsBullish() && + // + (decisionXConditions.isBreakedUpPrevSar || + decisionXConditions.isBreakedUpPrevStr || + decisionXConditions.isVWapMaxBreakedUp || + decisionXConditions.isBreakedUpPrevCheMax || + decisionXConditions.isBreakedUpPrevAtrLower) && + // + (decisionXConditions.isSarSwitchedToBullish || + decisionXConditions.isStrSwitchedToBullish || + decisionXConditions.isCheSwitchedToBullish || + decisionXConditions.isVWapSwitchedToBullishState || + decisionXConditions.isVWapSwitchedToBullishOrdered) + // + ; + + // + bool isCondition1Bearish = + // + hasSameCyclesPV && + isCBarBearishFormed && + priceInsideOB.IsBearish() && + // + (decisionXConditions.isBreakedDownPrevSar || + decisionXConditions.isBreakedDownPrevStr || + decisionXConditions.isVWapMinBreakedDown || + decisionXConditions.isBreakedDownPrevCheMin || + decisionXConditions.isBreakedDownPrevAtrUpper) && + // + (decisionXConditions.isSarSwitchedToBearish || + decisionXConditions.isStrSwitchedToBearish || + decisionXConditions.isCheSwitchedToBearish || + decisionXConditions.isVWapSwitchedToBearishState || + decisionXConditions.isVWapSwitchedToBearishOrdered) + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCondition1Bullish + ? priceInsideOB.Upper() + : priceInsideOB.Lower(); + } + + // + // + // + + // + isBullish = + // + isCondition1Bullish + // + ; + + // + isBearish = + // + isCondition1Bearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXSignalTrigger( + // + X121SMCStrategyXSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXConditions = decisionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = IsBarBreak( + point, + setupDir, + cBar // + ); + + // + // Summary ... + + // + isBullish = + // + isBullish // && + // isPointBreaked && + // isSlopesBullish + // + ; + + // + isBearish = + // + isBearish // && + // isPointBreaked && + // isSlopesBearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + double sls[]; + Add( + conditions.pivot, + sls // + ); + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + iAtr *= 1.5; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + + // + // Filling Conditions Props ... + conditions.sl = sl; + // conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_X); + + // + // result = DetectX121SMCGuards( + // provider, + // guards, + // positions, + // triggerCycleHelper, + // decisionCycleHelper, + // analyseCycleHelper, + // verificationCycleHelper, + // consolidationCycleHelper, + // visionCycleHelper // + // ); + + // + return result; +} + +// +int AddX121SMCXConditionsIfNotExists( + X121SMCStrategyXSignalConditions &item, + X121SMCStrategyXSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXConditions( + X121SMCStrategyXSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + return result; +} + +// diff --git a/BKPS/14031106/X121SMCEA/Signals/x-121.smc.xobpv.signal.lib.mq5 b/BKPS/14031106/X121SMCEA/Signals/x-121.smc.xobpv.signal.lib.mq5 new file mode 100644 index 0000000..9009eb8 --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Signals/x-121.smc.xobpv.signal.lib.mq5 @@ -0,0 +1,1724 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: X +// Description: provide all Signalling functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +// #include "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Definitions ... +struct X121SMCStrategyXOBPVSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + double target; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + + // + XCOrderBlock *bullishOBs[]; + XCOrderBlock *bearishOBs[]; + + // + // Constructor ... + X121SMCStrategyXOBPVSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + target = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + Clean(bullishOBs); + Clean(bearishOBs); + + // + } + + // + int CountBullishOBs() + { + return ArraySize(bullishOBs); + } + + // + bool HasBullishOBs() + { + return IsValidSize(CountBullishOBs()); + } + + // + int CountBearishOBs() + { + return ArraySize(bearishOBs); + } + + // + bool HasBearishOBs() + { + return IsValidSize(CountBearishOBs()); + } + + // +}; + +// +// Signaller Data Sources ... +X121SMCStrategyXOBPVSignalConditions mXOBPVConditions; +X121SMCStrategyXOBPVSignalConditions mXOBPVConditionsCollection[]; + +// +// Extension Functions ... + +// +// Detect Setup Conditions ... +bool DetectX121SMCXOBPVSignalSetup( + string _symbol, + ENUM_TIMEFRAMES _period, + // + X121SMCStrategyXOBPVSignalConditions &conditions, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper + // +) +{ + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + conditions.symbol = symbol; + conditions.period = period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 3; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Trigger ... + ENUM_XPOI_EVENTS triggerPoiEvents[]; + ENUM_X_CYCLE_EVENTS triggerCycleEvents[]; + X121SMCCycleConditions triggerConditions; + result = triggerCycleHelper.GetConditions( + triggerCycleEvents, + triggerPoiEvents, + triggerConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Analyse ... + ENUM_XPOI_EVENTS analysePoiEvents[]; + ENUM_X_CYCLE_EVENTS analyseCycleEvents[]; + X121SMCCycleConditions analyseConditions; + result = analyseCycleHelper.GetConditions( + analyseCycleEvents, + analysePoiEvents, + analyseConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Verification ... + ENUM_XPOI_EVENTS verificationPoiEvents[]; + ENUM_X_CYCLE_EVENTS verificationCycleEvents[]; + X121SMCCycleConditions verificationConditions; + result = verificationCycleHelper.GetConditions( + verificationCycleEvents, + verificationPoiEvents, + verificationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Consolidation ... + ENUM_XPOI_EVENTS consolidationPoiEvents[]; + ENUM_X_CYCLE_EVENTS consolidationCycleEvents[]; + X121SMCCycleConditions consolidationConditions; + result = consolidationCycleHelper.GetConditions( + consolidationCycleEvents, + consolidationPoiEvents, + consolidationConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Vision ... + ENUM_XPOI_EVENTS visionPoiEvents[]; + ENUM_X_CYCLE_EVENTS visionCycleEvents[]; + X121SMCCycleConditions visionConditions; + result = visionCycleHelper.GetConditions( + visionCycleEvents, + visionPoiEvents, + visionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState triggerState = triggerConditions.state; + XPOIState decisionState = decisionConditions.state; + XPOIState analyseState = analyseConditions.state; + XPOIState verificationState = verificationConditions.state; + XPOIState consolidationState = consolidationConditions.state; + XPOIState visionState = visionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions triggerXOBPVConditions = triggerConditions.x121Conditions; + X121Conditions decisionXOBPVConditions = decisionConditions.x121Conditions; + X121Conditions analyseXOBPVConditions = analyseConditions.x121Conditions; + X121Conditions verificationXOBPVConditions = verificationConditions.x121Conditions; + X121Conditions consolidationXOBPVConditions = consolidationConditions.x121Conditions; + X121Conditions visionXOBPVConditions = visionConditions.x121Conditions; + + // + // Setup Conditions ... + + // + // Detect Trend ... + + // + // Consolidation ... + ENUM_X_DIRECTION consolidationTrendDir; + bool hasConsolidationTrend = + consolidationCycleHelper + .DetectMarketStructure( + consolidationTrendDir // + ); + bool hasConsolidationBullishTrend = + hasConsolidationTrend && + IsBullish(consolidationTrendDir); + bool hasConsolidationBearishTrend = + hasConsolidationTrend && + IsBearish(consolidationTrendDir); + + // + // Verification ... + ENUM_X_DIRECTION verificationTrendDir; + bool hasVerificationTrend = + verificationCycleHelper + .DetectMarketStructure( + verificationTrendDir // + ); + bool hasVerificationBullishTrend = + hasVerificationTrend && + IsBullish(verificationTrendDir); + bool hasVerificationBearishTrend = + hasVerificationTrend && + IsBearish(verificationTrendDir); + + // + // Analyse ... + ENUM_X_DIRECTION analyseTrendDir; + bool hasAnalyseTrend = + analyseCycleHelper + .DetectMarketStructure( + analyseTrendDir // + ); + bool hasAnalyseBullishTrend = + hasAnalyseTrend && + IsBullish(analyseTrendDir); + bool hasAnalyseBearishTrend = + hasAnalyseTrend && + IsBearish(analyseTrendDir); + + // + // Decision ... + ENUM_X_DIRECTION decisionTrendDir; + bool hasDecisionTrend = + decisionCycleHelper + .DetectMarketStructure( + decisionTrendDir // + ); + bool hasDecisionBullishTrend = + hasDecisionTrend && + IsBullish(decisionTrendDir); + bool hasDecisionBearishTrend = + hasDecisionTrend && + IsBearish(decisionTrendDir); + + // + // Detect Bar State ... + + // + // PinBar ... + ENUM_X_DIRECTION cBarPinDir; + bool isCBarPin = decisionCycleHelper + .mBarAnalyser + .IsPinBar( + cBar, + cBarPinDir, + 1 // + ); + bool isCBarBullishPin = + isCBarPin && + IsBullish(cBarPinDir); + bool isCBarBearishPin = + isCBarPin && + IsBearish(cBarPinDir); + + // + // Engulf ... + ENUM_X_DIRECTION cBarEngulfDir; + bool isCBarEngulfed = decisionCycleHelper + .mBarAnalyser + .IsEngulfBar( + cBar, + cBarEngulfDir, + 0 // Extended ... + ); + bool isCBarBullishEngulfed = + isCBarEngulfed && + IsBullish(cBarEngulfDir); + bool isCBarBearishEngulfed = + isCBarEngulfed && + IsBearish(cBarEngulfDir); + + // + // Momentum ... + ENUM_X_DIRECTION cBarMomentumDir; + bool isCBarMomentum = decisionCycleHelper + .mBarAnalyser + .IsMomentumBar( + cBar, + cBarMomentumDir, + 0 // Extended ... + ); + bool isCBarBullishMomentum = + isCBarMomentum && + IsBullish(cBarMomentumDir); + bool isCBarBearishMomentum = + isCBarMomentum && + IsBearish(cBarMomentumDir); + + // + // Reject ... + ENUM_X_DIRECTION cBarRejectDir; + bool isCBarRejected = decisionCycleHelper + .mBarAnalyser + .IsRejectionBar( + cBar, + cBarRejectDir, + 0 // Extended ... + ); + bool isCBarBullishRejected = + isCBarRejected && + IsBullish(cBarRejectDir); + bool isCBarBearishRejected = + isCBarRejected && + IsBearish(cBarRejectDir); + + // + // Pull Back ... + ENUM_X_DIRECTION cBarPullbackDir; + bool isCBarPullbacked = + decisionCycleHelper + .mBarAnalyser + .HasPullBack( + cBarPullbackDir, + cBar // + ); + bool isCBarBullishPullbacked = + isCBarPullbacked && + IsBullish(cBarPullbackDir); + bool isCBarBearishPullbacked = + isCBarPullbacked && + IsBearish(cBarPullbackDir); + + // + // HH/LL Break ... + + // + bool isCBarBreaksUpHH = IsBarBreak( + hh, + X_DIRECTION_BULLISH, + cBar // + ); + + // + bool isCBarBreaksDownLL = IsBarBreak( + hh, + X_DIRECTION_BEARISH, + cBar // + ); + + // + // Bars Pattern and Power and Pressures ... + + // + bool hasCBarBullishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBullishPattern( + cBar, + 2 // + ); + + // + bool hasCBarBearishPattern = + decisionCycleHelper + .mBarAnalyser + .HasBearishPattern( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPower = + decisionCycleHelper + .mBarAnalyser + .HasBullishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPower = + decisionCycleHelper + .mBarAnalyser + .HasBearishPower( + cBar, + 2 // + ); + + // + bool isCBarHasBullishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBullishPressure( + cBar, + 2 // + ); + + // + bool isCBarHasBearishPressure = + decisionCycleHelper + .mBarAnalyser + .HasBearishPressure( + cBar, + 2 // + ); + + // + // Bar Checking Summary ... + + // + // Bullish ... + bool isCBarBullishFormed = + // + ( + // + hasCBarBullishPattern && + isCBarHasBullishPower && + isCBarHasBullishPressure + // + ) + // + || + // + ( + // + isCBarBullishPin || + isCBarBreaksUpHH || + isCBarBullishEngulfed || + isCBarBullishMomentum || + isCBarBullishRejected + // + ) + // + ; + + // + // Bearish ... + bool isCBarBearishFormed = + // + ( + // + hasCBarBearishPattern && + isCBarHasBearishPower && + isCBarHasBearishPressure + // + ) + // + || + // + ( + // + isCBarBearishPin || + isCBarBreaksDownLL || + isCBarBearishEngulfed || + isCBarBearishMomentum || + isCBarBearishRejected + // + ) + // + ; + + // + // Detect Order Block ... + + // + bool hasBullishOrderBlocks = conditions.HasBullishOBs(); + int bullishOrderBlocksCount = conditions.CountBullishOBs(); + + // + bool hasBearishOrderBlocks = conditions.HasBearishOBs(); + int bearishOrderBlocksCount = conditions.CountBearishOBs(); + + // + bool hasOrderBlocks = hasBullishOrderBlocks && + hasBearishOrderBlocks; + if (!hasOrderBlocks) + { + // + XCOrderBlock *bullishOBs[]; + XCOrderBlock *bearishOBs[]; + bool hasOrderBlocks = visionCycleHelper.DetectOrderBlocks( + bullishOBs, + bearishOBs // + ); + + // + if (!hasBullishOrderBlocks) + { + // + Copy( + bullishOBs, + conditions.bullishOBs // + ); + } + + // + if (!hasBearishOrderBlocks) + { + // + Copy( + bearishOBs, + conditions.bearishOBs // + ); + } + + // + hasBullishOrderBlocks = conditions.HasBullishOBs(); + bullishOrderBlocksCount = conditions.CountBullishOBs(); + + // + hasBearishOrderBlocks = conditions.HasBearishOBs(); + bearishOrderBlocksCount = conditions.CountBearishOBs(); + } + + // + bool hasOldestBullishOB = false; + bool hasYoungestBullishOB = false; + XCOrderBlock *oldestBullishOB = NULL; + XCOrderBlock *youngestBullishOB = NULL; + if (hasBullishOrderBlocks) + { + // + XCZone *zones[]; + bool isConverted = ToZone( + conditions.bullishOBs, + zones // + ); + + // + int oldestIDX = GetOldest(zones); + hasOldestBullishOB = IsValidIndex(oldestIDX); + if (hasOldestBullishOB) + { + oldestBullishOB = conditions.bullishOBs[oldestIDX]; + } + + // + int youngestIDX = GetYoungest(zones); + hasYoungestBullishOB = IsValidIndex(youngestIDX); + if (hasYoungestBullishOB) + { + youngestBullishOB = conditions.bullishOBs[youngestIDX]; + } + } + + // + bool hasOldestBearishOB = false; + bool hasYoungestBearishOB = false; + XCOrderBlock *oldestBearishOB = NULL; + XCOrderBlock *youngestBearishOB = NULL; + if (hasBearishOrderBlocks) + { + // + XCZone *zones[]; + bool isConverted = ToZone( + conditions.bearishOBs, + zones // + ); + + // + int oldestIDX = GetOldest(zones); + hasOldestBearishOB = IsValidIndex(oldestIDX); + if (hasOldestBearishOB) + { + oldestBearishOB = conditions.bearishOBs[oldestIDX]; + } + + // + int youngestIDX = GetYoungest(zones); + hasYoungestBearishOB = IsValidIndex(youngestIDX); + if (hasYoungestBearishOB) + { + youngestBearishOB = conditions.bearishOBs[youngestIDX]; + } + } + + // + bool hasPriceInsideOB = false; + XCOrderBlock *priceInsideOB = NULL; + + // + if (!hasPriceInsideOB && + hasBullishOrderBlocks) + { + // + for (int i = 0; i < bullishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bullishOBs[i]; + + // + bool isInside = IsPriceInsideZone( + decisionXOBPVConditions.valesBuffer[1], + (XCZone *)iOb // + ); + if (isInside) + { + // + hasPriceInsideOB = true; + priceInsideOB = iOb; + break; + } + } + } + + // + if (!hasPriceInsideOB && + hasBearishOrderBlocks) + { + // + for (int i = 0; i < bearishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bearishOBs[i]; + + // + bool isInside = IsPriceInsideZone( + decisionXOBPVConditions.peaksBuffer[1], + (XCZone *)iOb // + ); + if (isInside) + { + // + hasPriceInsideOB = true; + priceInsideOB = iOb; + break; + } + } + } + + // + XStateZones obState; + bool hasOBState = false; + XOHCL priceInsideOBBreakerBar; + if (hasPriceInsideOB) + { + // + XOHCL toBar; + XOHCL fromBar; + ENUM_X_DIRECTION forDir = + priceInsideOB.IsBullish() + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + bool hasBreakerBar = HasBreakerBar( + toBar, + fromBar, + priceInsideOBBreakerBar, + forDir, + priceInsideOB.GetSymbol(), + priceInsideOB.GetPeriod(), + (XCZone *)priceInsideOB // + ); + if (hasBreakerBar) + { + // + CalculateStateZones( + obState, + consolidationState, + priceInsideOB.Upper(), + priceInsideOB.Lower(), + priceInsideOBBreakerBar.time // + ); + } + + // + hasOBState = obState.IsValid(); + } + + // + bool isSameCyclesPeak = + // + triggerXOBPVConditions.peaksBuffer[1] == decisionXOBPVConditions.peaksBuffer[1] && + decisionXOBPVConditions.peaksBuffer[1] == analyseXOBPVConditions.peaksBuffer[1] && + analyseXOBPVConditions.peaksBuffer[1] == verificationXOBPVConditions.peaksBuffer[1] && + verificationXOBPVConditions.peaksBuffer[1] == consolidationXOBPVConditions.peaksBuffer[1] + // + ; + + // + bool isSameCyclesVale = + // + triggerXOBPVConditions.valesBuffer[1] == decisionXOBPVConditions.valesBuffer[1] && + decisionXOBPVConditions.valesBuffer[1] == analyseXOBPVConditions.valesBuffer[1] && + analyseXOBPVConditions.valesBuffer[1] == verificationXOBPVConditions.valesBuffer[1] && + verificationXOBPVConditions.valesBuffer[1] == consolidationXOBPVConditions.valesBuffer[1] + // + ; + + // + bool hasSameCyclesPV = + hasOBState && + hasPriceInsideOB && + (isSameCyclesPeak || + isSameCyclesVale); + + // + // DRAW ... + // + + // + XCBaseObject *drawnObjects[]; + + // + if (hasBullishOrderBlocks) + { + // + for (int i = 0; i < bullishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bullishOBs[i]; + + // + XCBullishOrderBlockObject *iObObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateBullishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + if (hasBearishOrderBlocks) + { + // + for (int i = 0; i < bearishOrderBlocksCount; i++) + { + // + XCOrderBlock *iOb = conditions.bearishOBs[i]; + + // + XCBearishOrderBlockObject *iObObj; + bool isCreated = visionCycleHelper + .mPOIDrawer + .CreateBearishOrderBlock( + iOb, + iObObj // + ); + if (isCreated) + { + // + Add( + (XCBaseObject *)iObObj, + drawnObjects // + ); + } + } + } + + // + // if (hasOldestBullishOB) + // { + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBullishOrderBlock( + // oldestBullishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasYoungestBullishOB) + // { + // // + // XCBullishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBullishOrderBlock( + // youngestBullishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasOldestBearishOB) + // { + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBearishOrderBlock( + // oldestBearishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // // + // if (hasYoungestBearishOB) + // { + // // + // XCBearishOrderBlockObject *iObj; + // bool isCreated = visionCycleHelper + // .mPOIDrawer + // .CreateBearishOrderBlock( + // youngestBearishOB, + // iObj // + // ); + // if (isCreated) + // { + // } + // } + + // + if (hasPriceInsideOB) + { + // + bool isBullish = priceInsideOB.IsBullish(); + + // + bool isCreated = false; + XCBaseObject *iObObj = NULL; + if (isBullish) + { + // + XCBullishOrderBlockObject *iObj; + isCreated = visionCycleHelper + .mPOIDrawer + .CreateBullishOrderBlock( + priceInsideOB, + iObj // + ); + + // + if (isCreated) + { + // + iObj.ZoneColor(clrYellow); + iObObj = (XCBaseObject *)iObj; + } + } + else + { + // + XCBearishOrderBlockObject *iObj; + isCreated = visionCycleHelper + .mPOIDrawer + .CreateBearishOrderBlock( + priceInsideOB, + iObj // + ); + + // + if (isCreated) + { + // + iObj.ZoneColor(clrOrangeRed); + iObObj = (XCBaseObject *)iObj; + } + } + + // + if (isCreated) + { + // + Add( + iObObj, + drawnObjects // + ); + } + } + + // + if (hasOBState) + { + // + XCBaseObject *stateObjects[]; + int stateObjectsCount = consolidationCycleHelper + .mPOIDrawer + .DrawStateZones( + obState, + stateObjects // + ); + if (IsValidSize(stateObjectsCount)) + { + // + Copy( + stateObjects, + drawnObjects, + false // + ); + } + } + + // + int drawnCount = ArraySize(drawnObjects); + if (IsValidSize(drawnCount)) + { + } + + // + // + // + + // + // Summarize Conditions ... + + // + bool isCondition1Bullish = + // + hasSameCyclesPV && + isCBarBullishFormed && + priceInsideOB.IsBullish() && + // + (decisionXOBPVConditions.isBreakedUpPrevSar || + decisionXOBPVConditions.isBreakedUpPrevStr || + decisionXOBPVConditions.isVWapMaxBreakedUp || + decisionXOBPVConditions.isBreakedUpPrevCheMax || + decisionXOBPVConditions.isBreakedUpPrevAtrLower) && + // + (decisionXOBPVConditions.isSarSwitchedToBullish || + decisionXOBPVConditions.isStrSwitchedToBullish || + decisionXOBPVConditions.isCheSwitchedToBullish || + decisionXOBPVConditions.isVWapSwitchedToBullishState || + decisionXOBPVConditions.isVWapSwitchedToBullishOrdered) + // + ; + + // + bool isCondition1Bearish = + // + hasSameCyclesPV && + isCBarBearishFormed && + priceInsideOB.IsBearish() && + // + (decisionXOBPVConditions.isBreakedDownPrevSar || + decisionXOBPVConditions.isBreakedDownPrevStr || + decisionXOBPVConditions.isVWapMinBreakedDown || + decisionXOBPVConditions.isBreakedDownPrevCheMin || + decisionXOBPVConditions.isBreakedDownPrevAtrUpper) && + // + (decisionXOBPVConditions.isSarSwitchedToBearish || + decisionXOBPVConditions.isStrSwitchedToBearish || + decisionXOBPVConditions.isCheSwitchedToBearish || + decisionXOBPVConditions.isVWapSwitchedToBearishState || + decisionXOBPVConditions.isVWapSwitchedToBearishOrdered) + // + ; + + // + bool hasCondition1 = isCondition1Bullish || + isCondition1Bearish; + if (hasCondition1) + { + // + ENUM_X_DIRECTION pzDir = + isCondition1Bullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + double point = GetEntry( + conditions.symbol, + pzDir // + ); + + // + // Manipulate Conditions Point ... + + // + conditions.point = point; + + // + // Manipulate Conditions Pivot ... + + // + conditions.pivot = + isCondition1Bullish + ? priceInsideOB.Upper() + : priceInsideOB.Lower(); + } + + // + // + // + + // + isBullish = + // + isCondition1Bullish + // + ; + + // + isBearish = + // + isCondition1Bearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; + } + + // + conditions.setupTime = cTime; + conditions.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Cleanup Arrays ... + ArrayFree(triggerPoiEvents); + ArrayFree(triggerCycleEvents); + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + ArrayFree(analysePoiEvents); + ArrayFree(analyseCycleEvents); + ArrayFree(verificationPoiEvents); + ArrayFree(verificationCycleEvents); + ArrayFree(consolidationPoiEvents); + ArrayFree(consolidationCycleEvents); + ArrayFree(visionPoiEvents); + ArrayFree(visionCycleEvents); + + // + return result; +} + +// +// Detect Trigger Conditions ... +bool DetectX121SMCXOBPVSignalTrigger( + // + X121SMCStrategyXOBPVSignalConditions &conditions, + // + string _symbol, + ENUM_TIMEFRAMES _period, + // + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper, + // + int maxAllowedSetupAge = 60 // + // +) +{ + // + bool result = false; + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + string symbol = _symbol; + ENUM_TIMEFRAMES period = _period; + + // + XOHCL zBar; + result = decisionCycleHelper.GetBar( + zBar, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = decisionCycleHelper.GetBar( + cBar, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = decisionCycleHelper.GetBar( + pBar, + pIndex // + ); + if (!result) + { + return result; + } + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + int swingLoopback = 9; + double ll = cBar.FindLowest(swingLoopback, MODE_LOW); + double hh = cBar.FindHighest(swingLoopback, MODE_HIGH); + double llDown = cBar.FindLowesttDown(swingLoopback); + double hhUp = cBar.FindHighestUp(swingLoopback); + + // + // Cycles Conditions ... + + // + // Decision ... + ENUM_XPOI_EVENTS decisionPoiEvents[]; + ENUM_X_CYCLE_EVENTS decisionCycleEvents[]; + X121SMCCycleConditions decisionConditions; + result = decisionCycleHelper.GetConditions( + decisionCycleEvents, + decisionPoiEvents, + decisionConditions, + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + // Cycles POI States ... + XPOIState decisionState = decisionConditions.state; + + // + // Cycle X121Conditions ... + X121Conditions decisionXOBPVConditions = decisionConditions.x121Conditions; + + // + // Trigger Conditions ... + + // + // Slopes ... + + // + bool isRsiSlopeBullish = decisionXOBPVConditions.isRsiSlopeBullish; + bool isStrSlopeBullish = decisionXOBPVConditions.isStrSlopeBullish; + bool isAtrUpperSlopeBullish = decisionXOBPVConditions.isAtrUpperSlopeBullish; + bool isAtrLowerSlopeBullish = decisionXOBPVConditions.isAtrLowerSlopeBullish; + bool isVwapFastSlopeBullish = decisionXOBPVConditions.isVwapFastSlopeBullish; + bool isVwapMidSlopeBullish = decisionXOBPVConditions.isVwapMidSlopeBullish; + bool isVwapSlowSlopeBullish = decisionXOBPVConditions.isVwapSlowSlopeBullish; + + // + bool isRsiSlopeBearish = decisionXOBPVConditions.isRsiSlopeBearish; + bool isStrSlopeBearish = decisionXOBPVConditions.isStrSlopeBearish; + bool isAtrUpperSlopeBearish = decisionXOBPVConditions.isAtrUpperSlopeBearish; + bool isAtrLowerSlopeBearish = decisionXOBPVConditions.isAtrLowerSlopeBearish; + bool isVwapFastSlopeBearish = decisionXOBPVConditions.isVwapFastSlopeBearish; + bool isVwapMidSlopeBearish = decisionXOBPVConditions.isVwapMidSlopeBearish; + bool isVwapSlowSlopeBearish = decisionXOBPVConditions.isVwapSlowSlopeBearish; + + // + bool isSlopesBullish = + isRsiSlopeBullish && + isStrSlopeBullish && + isAtrUpperSlopeBullish && + isAtrLowerSlopeBullish && + isVwapFastSlopeBullish && + isVwapMidSlopeBullish && + isVwapSlowSlopeBullish; + + // + bool isSlopesBearish = + isRsiSlopeBearish && + isStrSlopeBearish && + isAtrUpperSlopeBearish && + isAtrLowerSlopeBearish && + isVwapFastSlopeBearish && + isVwapMidSlopeBearish && + isVwapSlowSlopeBearish; + + // + double point = conditions.point; + bool isPointBreaked = IsBarBreak( + point, + setupDir, + cBar // + ); + + // + // Summary ... + + // + isBullish = + // + isBullish // && + // isPointBreaked && + // isSlopesBullish + // + ; + + // + isBearish = + // + isBearish // && + // isPointBreaked && + // isSlopesBearish + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + // Cleanup Setup Conditions ... + int setupAge = conditions.GetSetupAge(); + if (IsValidSize(setupAge) && + IsValidSize(maxAllowedSetupAge) && + setupAge >= maxAllowedSetupAge) + { + conditions.Clean(); + } + + // + // Cleanup Arrays ... + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + + // + return result; + } + + // + // Detect Nearest Pivot Point ... + + // + double entry = GetEntry( + conditions.symbol, + setupDir // + ); + + // + double sls[]; + Add( + conditions.pivot, + sls // + ); + + // + double iAtr = decisionConditions.x121Conditions.atrBuffer[1]; + iAtr *= 1.5; + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double sl = isBullish + ? slsMin - iAtr + : slsMax + iAtr; + double risk = MathAbs(entry - sl); + + // + // Filling Conditions Props ... + conditions.sl = sl; + // conditions.target = target; + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + // Cleanup Arrays ... + ArrayFree(decisionPoiEvents); + ArrayFree(decisionCycleEvents); + + // + return result; +} + +// +bool DetectX121SMCXOBPVGuards( + X121SMCGuard &guards[], + const XPosition &positions[], + XC121SMCCycleHelper *triggerCycleHelper, + XC121SMCCycleHelper *decisionCycleHelper, + XC121SMCCycleHelper *analyseCycleHelper, + XC121SMCCycleHelper *verificationCycleHelper, + XC121SMCCycleHelper *consolidationCycleHelper, + XC121SMCCycleHelper *visionCycleHelper // +) +{ + // + bool result = false; + + // + string provider = ToString(X_121_SMC_PROVIDER_X); + + // + // result = DetectX121SMCGuards( + // provider, + // guards, + // positions, + // triggerCycleHelper, + // decisionCycleHelper, + // analyseCycleHelper, + // verificationCycleHelper, + // consolidationCycleHelper, + // visionCycleHelper // + // ); + + // + return result; +} + +// +int AddX121SMCXOBPVConditionsIfNotExists( + X121SMCStrategyXOBPVSignalConditions &item, + X121SMCStrategyXOBPVSignalConditions &items[], + int maxAllowed = 10 // +) +{ + // + int result = 0; + + // + bool isSetuped = IsValid(item.setupTime) && + HasDirection(item.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(items); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXOBPVSignalConditions tmpItems[]; + Copy( + items, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(item.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXOBPVSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = item.dir == iItem.dir && + item.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + items, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + item, + items // + ); + + // + // Remove Olds ... + CleanupArray( + items, + maxAllowed // + ); + + // + result = ArraySize(items); + + // + return result; +} + +// +int DrawX121SMCXOBPVConditions( + X121SMCStrategyXOBPVSignalConditions &conditions, + XCBaseObject *&drawnObjects[], + XCPOIDrawer *drawer // +) +{ + // + int result = 0; + + // + Clean(drawnObjects); + + // + if (drawer == NULL) + { + return result; + } + + // + bool isSetuped = conditions.IsSetuped(); + if (!isSetuped) + { + return result; + } + + // + return result; +} + +// diff --git a/BKPS/14031106/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/BKPS/14031106/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 new file mode 100644 index 0000000..b366c7c --- /dev/null +++ b/BKPS/14031106/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 @@ -0,0 +1,1366 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCX121SMCStrategy +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../Classes/x-121.smc.base.strategy.class.mq5" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" + +// +#include "../Signals/x-121.smc.x.signal.lib.mq5" +#include "../Signals/x-121.smc.xobpv.signal.lib.mq5" + +// +// Definitions ... + +// +// XStrategy Class Implementation(s) ... +class XCX121SMCStrategy : public XCX121SMCBaseStrategy +{ + // + // Public ... + public: + // + // Props ... + bool useXSignal; + bool useXOBPVSignal; + + // + // Constructor(s) ... + void XCX121SMCStrategy( + // + // Base ... + string _symbol, // Trading Symbol + ENUM_TIMEFRAMES _period // Trading TimeFrame + ) + : XCX121SMCBaseStrategy(_symbol, _period) + { + InitialHelpers(); + } + + // + // Deconstructur ... + void ~XCX121SMCStrategy() + { + // + Destroy(); + + // + ArrayFree(mXConditionsCollection); + ArrayFree(mXOBPVConditionsCollection); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Max Allowed Required POI(s) to Find ... + * + * @return ( int ) + */ + int MaxAllowedRequiredPOIs() + { + return mMaxAllowedRequiredPOIs; + } + + /** + * Set Max Allowed Required POI(s) to Find ... + * + * @param value: number of Required POIs + */ + void MaxAllowedRequiredPOIs(int value) + { + // + if (value < 10) + { + value = 10; + } + + // + mMaxAllowedRequiredPOIs = value; + } + + // + // Overrides Actions ... + + /** + * Destroy All Class Implementations ... + */ + void Destroy() override + { + // + delete mTriggerCycleHelper; + delete mDecisionCycleHelper; + delete mAnalyseCycleHelper; + delete mVerificationCycleHelper; + delete mConsolidationCycleHelper; + delete mVisionCycleHelper; + } + + /** + * Check Conditions For Signal ... + */ + bool HasSignal( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) override + { + // + bool result = false; + + // + signal.Clean(); + conditions.Clean(); + + // + int pushers = 0; + + // + double sl = 0; + double tp = 0; + double risk = 0; + double entry = 0; + double reward = 0; + double r2r = R2R(); + string provider = ""; + double volume = Volume(); + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + + // + bool hasLong = false; + bool hasShort = false; + + // + double selectedSL = 0; + + // + // Start Calculations ... + + // + // Retrieve Common Data ... + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + datetime cTime = TimeCurrent(); + + // + // Required Value For SL/TP Calculations ... + double points = GetPoints(symbol); + double pip = GetPipPrice(symbol); + double pip2 = 2 * pip; + + // + conditions.time = cTime; + conditions.symbol = symbol; + conditions.period = period; + + // + // Check Spread for Signalling Conditions ... + // TODO: Uncomment this ... + // bool isSpreadPassed = IsSpreadPass(); + // result = isSpreadPassed; + // if (!result) + // { + // // + // conditions.Clean(); + // return result; + // } + + // + // Detect Signal Conditions ... + bool hasSignal = false; + + // + bool hasXSignal = false; + bool hasXOBPVSignal = false; + + // + // X Signal ... + if (useXSignal && !hasSignal) + { + // + hasXSignal = DetectXSignal(conditions); + hasSignal = hasXSignal; + } + + // + // XOBPV Signal ... + if (useXOBPVSignal && !hasSignal) + { + // + hasXOBPVSignal = DetectXOBPVSignal(conditions); + hasSignal = hasXOBPVSignal; + } + + // + result = hasSignal; + if (!result) + { + // + conditions.Clean(); + return result; + } + + // + // Combine all Signals Conditions ... + selectedSL = conditions.sl; + provider = conditions.provider; + + // + hasLong = + // + IsBullish(conditions.signalDir) + // + ; + + // + hasShort = + // + IsBearish(conditions.signalDir) + // + ; + + // + result = hasLong || + hasShort; + + // + // Rmove Signal Condition ... + if (result) + { + // + // TYPE ... + type = + hasLong + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + ENUM_X_POSITION_TYPES xType = + hasLong + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + entry = GetEntry( + conditions.symbol, + type // + ); + + // + double slAddition = 0; + sl = + hasLong + ? selectedSL - slAddition + : selectedSL + slAddition; + + // + // RISK Reward ... + risk = + hasLong + ? entry - sl + : sl - entry; + reward = risk * r2r; + tp = + hasLong + ? entry + reward + : entry - reward; + + // + signal.sl = sl; + signal.tp = tp; + signal.type = type; + signal.mode = mode; + signal.entry = entry; + signal.volume = volume; + signal.symbol = symbol; + signal.period = period; + signal.pushers = pushers; + signal.provider = provider; + signal.time = TimeCurrent(); + signal.target = conditions.target; + + // + bool canReplaceTarget = + signal.target > 0 && + (hasLong + ? signal.target > signal.tp + : signal.target < signal.tp); + if (canReplaceTarget) + { + // + signal.tp = conditions.target; + signal.target = tp; + } + + // + result = PrepareSignal(signal); + + // + if (result) + { + // + // Configure Signal Protector ... + // if (useXSTRPVSignal) + // { + // // + // signal.trailSL = false; + // signal.fullTPLevel = r2r; + // signal.partialCloseOnTPLevel = 2; + // signal.partialCloseMultiplier = 0.5; + // signal.trailSLStartOnReachTPLevel = 2; + // } + + // + // TODO: Remove this ... + // XCSignalObject *iObj; + // mPOIDrawer.DrawSignal(signal, iObj); + // Print(""); + } + + // + hasLong = false; + hasShort = false; + } + + // + return result; + } + + /** + * Check for any Guard Actions ... + */ + bool CheckGuard( + X121SMCGuard &guards[], + const XPosition &positions[] // + ) override + { + // + bool result = false; + + // + Clean(guards); + + // + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + // X Guard Detection ... + if (useXSignal) + { + // + bool hasGuard = DetectX121SMCXGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // + // XPZ Guard Detection ... + if (useXOBPVSignal) + { + // + bool hasGuard = DetectX121SMCXOBPVGuards( + guards, + positions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + } + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + /** + * Customize Strategy Identifier ... + */ + string GetTag() override + { + return X121SMCStrategyToken; + } + + // + // Protected ... + protected: + // + + // + // Props ... + + // + XC121SMCCycleHelper *mTriggerCycleHelper; + XC121SMCCycleHelper *mDecisionCycleHelper; + XC121SMCCycleHelper *mAnalyseCycleHelper; + XC121SMCCycleHelper *mVerificationCycleHelper; + XC121SMCCycleHelper *mConsolidationCycleHelper; + XC121SMCCycleHelper *mVisionCycleHelper; + + // + // Actions ... + + // + // Signalling Functions ... + + // + // X Signal ... + bool DetectXSignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_X; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXConditions.setupTime; + bool isSetuped = mXConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXSignalSetup( + symbol, + period, + mXConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXConditions.dir; + setupTime = mXConditions.setupTime; + + // // + // bool hasPivot = mXConditions.pivotZone.IsValid(); + // if (hasPivot) + // { + // // + // XCBaseObject *drawnObjects[]; + // int drawnCount = DrawX121SMCXConditions( + // mXConditions, + // drawnObjects, + // mPOIDrawer // + // ); + // if (IsValidSize(drawnCount)) + // { + // AddObjectsIfNotExists(drawnObjects); + // } + // } + + // + if (isSetuped) + { + // + int items = AddX121SMCXConditionsIfNotExists( + mXConditions, + mXConditionsCollection // + ); + + // + mXConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXSignalConditions mTmpConditions[]; + Copy( + mXConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXSignalTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + + // + // XOBPV Signal ... + bool DetectXOBPVSignal( + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + XOHCL zBar; + result = zBar.Init( + symbol, + period, + zIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL cBar; + result = cBar.Init( + symbol, + period, + cIndex // + ); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = pBar.Init( + symbol, + period, + pIndex // + ); + if (!result) + { + return result; + } + + // + double cLL = cBar.FindLowest(7, MODE_LOW); + double cHH = cBar.FindHighest(7, MODE_HIGH); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XOBPV; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXOBPVConditions.setupTime; + bool isSetuped = mXOBPVConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXOBPVConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = DetectX121SMCXOBPVSignalSetup( + symbol, + period, + mXOBPVConditions, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + setupDir = mXOBPVConditions.dir; + setupTime = mXOBPVConditions.setupTime; + + // + if (isSetuped) + { + // + int items = AddX121SMCXOBPVConditionsIfNotExists( + mXOBPVConditions, + mXOBPVConditionsCollection // + ); + + // + mXOBPVConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXOBPVConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXOBPVSignalConditions mTmpConditions[]; + Copy( + mXOBPVConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXOBPVSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = DetectX121SMCXOBPVSignalTrigger( + mTmpConditions[i], + symbol, + period, + mTriggerCycleHelper, + mDecisionCycleHelper, + mAnalyseCycleHelper, + mVerificationCycleHelper, + mConsolidationCycleHelper, + mVisionCycleHelper // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXOBPVConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXOBPVConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + conditions.target = mConditions.target; + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + int mMaxAllowedRequiredPOIs; // Max Allowed Required POI(s) to Find ... + + /** + * Initial Required Indicators Helper ... + */ + void InitialHelpers() + { + // + useXSignal = false; + useXOBPVSignal = true; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + if (mMaxAllowedRequiredPOIs <= 0) + { + mMaxAllowedRequiredPOIs = 50; + } + + // + // Short ... + ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES scPeriod = NULL; // Time Period + + // + // Medium ... + ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES mcPeriod = NULL; // Time Period + + // + // Long ... + ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES lcPeriod = NULL; // Time Period + + // + // Hind ... + ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Period + ENUM_TIMEFRAMES hcPeriod = NULL; // Time Period + + // + // XPV ... + X121Inputs x121Inputs; + + // + x121Inputs.Default(); + + // + bool showAll = false; + + // + x121Inputs.showRSI = false; + + // + bool isInited = false; + + // + // XPV ... + + // + x121Inputs.xpvInputs.scMethod = scMethod; + x121Inputs.xpvInputs.scPeriod = scPeriod; + x121Inputs.xpvInputs.mcMethod = mcMethod; + x121Inputs.xpvInputs.mcPeriod = mcPeriod; + x121Inputs.xpvInputs.lcMethod = lcMethod; + x121Inputs.xpvInputs.lcPeriod = lcPeriod; + x121Inputs.xpvInputs.hcMethod = hcMethod; + x121Inputs.xpvInputs.hcPeriod = hcPeriod; + + // + x121Inputs.xpvInputs.showSar = showAll || true; + x121Inputs.xpvInputs.showPeaks = showAll || true; + x121Inputs.xpvInputs.showVales = showAll || true; + + // + // XATR ... + x121Inputs.xatrInputs.showATRUpper = showAll || false; + x121Inputs.xatrInputs.showATRLower = showAll || false; + + // + x121Inputs.xatrInputs.atrMultiplier = 1.5; + x121Inputs.xatrInputs.atrSmoothingMode = X_MA_MODE_EMA; + + // + // XSTR ... + x121Inputs.xstrInputs.showStr = showAll || false; + x121Inputs.xstrInputs.showStrUpper = showAll || false; + x121Inputs.xstrInputs.showStrLower = showAll || false; + + // + // XCHE ... + x121Inputs.xcheInputs.showLE1 = showAll || false; + x121Inputs.xcheInputs.showLE2 = showAll || false; + x121Inputs.xcheInputs.showSE1 = showAll || false; + x121Inputs.xcheInputs.showSE2 = showAll || false; + + // + // XDON ... + x121Inputs.xdonInputs.showOpen = showAll || false; + x121Inputs.xdonInputs.showClose = showAll || false; + x121Inputs.xdonInputs.showLow = showAll || false; + x121Inputs.xdonInputs.showHigh = showAll || false; + + // + // XVWAP ... + x121Inputs.xvwapInputs.showVWapFast = showAll || false; + x121Inputs.xvwapInputs.showVWapMedium = showAll || false; + x121Inputs.xvwapInputs.showVWapSlow = showAll || false; + + // + // Initialize Cycle Helpers ... + + // + int requiredPOIS = MaxAllowedRequiredPOIs(); + + // + // Trigger Cycle ... + mTriggerCycleHelper = new XC121SMCCycleHelper(); + isInited = mTriggerCycleHelper.Init( + symbol, + PERIOD_M1, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrYellowGreen; + color bearishColor = clrChocolate; + + // + // Bars ... + mTriggerCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mTriggerCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mTriggerCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mTriggerCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mTriggerCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mTriggerCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mTriggerCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mTriggerCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mTriggerCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Decision Cycle ... + mDecisionCycleHelper = new XC121SMCCycleHelper(); + isInited = mDecisionCycleHelper.Init( + symbol, + PERIOD_M5, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrDodgerBlue; + color bearishColor = clrSienna; + + // + // Bars ... + mDecisionCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mDecisionCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mDecisionCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mDecisionCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mDecisionCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mDecisionCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mDecisionCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mDecisionCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mDecisionCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Analyse Cycle ... + mAnalyseCycleHelper = new XC121SMCCycleHelper(); + isInited = mAnalyseCycleHelper.Init( + symbol, + PERIOD_M15, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrMediumSeaGreen; + color bearishColor = clrBlueViolet; + + // + // Bars ... + mAnalyseCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mAnalyseCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mAnalyseCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mAnalyseCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mAnalyseCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mAnalyseCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mAnalyseCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mAnalyseCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mAnalyseCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Verification Cycle ... + mVerificationCycleHelper = new XC121SMCCycleHelper(); + isInited = mVerificationCycleHelper.Init( + symbol, + PERIOD_M30, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrOliveDrab; + color bearishColor = clrSteelBlue; + + // + // Bars ... + mVerificationCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mVerificationCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mVerificationCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mVerificationCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mVerificationCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mVerificationCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mVerificationCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mVerificationCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mVerificationCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Consolidation Cycle ... + mConsolidationCycleHelper = new XC121SMCCycleHelper(); + isInited = mConsolidationCycleHelper.Init( + symbol, + PERIOD_H1, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrLime; + color bearishColor = clrRed; + + // + // Bars ... + mConsolidationCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mConsolidationCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mConsolidationCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mConsolidationCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mConsolidationCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mConsolidationCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mConsolidationCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mConsolidationCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mConsolidationCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + + // + // Vision Cycle ... + mVisionCycleHelper = new XC121SMCCycleHelper(); + isInited = mVisionCycleHelper.Init( + symbol, + PERIOD_H4, + x121Inputs, + requiredPOIS // + ); + if (isInited) + { + // + // Configure POI Drawer ... + color bullishColor = clrAqua; + color bearishColor = clrMagenta; + + // + // Bars ... + mVisionCycleHelper.mPOIDrawer.BarBullishColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BarBearishColor(bearishColor); + + // + // Swings ... + mVisionCycleHelper.mPOIDrawer.SwingLowColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.SwingHighColor(bearishColor); + + // + // Momentum ... + mVisionCycleHelper.mPOIDrawer.BullishMomentumBarColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishMomentumBarColor(bearishColor); + + // + // Rejection ... + mVisionCycleHelper.mPOIDrawer.BullishRejectionBarColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishRejectionBarColor(bearishColor); + + // + // Support and Resistance ... + mVisionCycleHelper.mPOIDrawer.SupportZoneColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.ResistanceZoneColor(bearishColor); + + // + // Demand and Supply ... + mVisionCycleHelper.mPOIDrawer.DemandZoneColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.SupplyZoneColor(bearishColor); + + // + // Order Blocks ... + mVisionCycleHelper.mPOIDrawer.BullishOrderBlockColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishOrderBlockColor(bearishColor); + + // + // Fair Value Gaps ... + mVisionCycleHelper.mPOIDrawer.BullishFVGColor(bullishColor); + mVisionCycleHelper.mPOIDrawer.BearishFVGColor(bearishColor); + } + } + + // +}; + +// \ No newline at end of file