diff --git a/Experts/xcatb.test.ea.mq5 b/Experts/xcatb.test.ea.mq5 index 4cfea122..cefd7d17 100644 --- a/Experts/xcatb.test.ea.mq5 +++ b/Experts/xcatb.test.ea.mq5 @@ -26,6 +26,7 @@ #include "../Classes/x-saherelm.x-trade.class.mq5" #include "../Classes/x-saherelm.x-volume.class.mq5" #include "../Helpers/x-saherelm.x121.xcatb.helper.mq5" +#include "../XCATBEA/Classes/xcatbea.signaller.class.mq5" #include "../XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5" #include "../XCATBEA/Libraries/xcatbea.signaller.lib.mq5" diff --git a/Helpers/x-saherelm.x121.xcatb.helper.mq5 b/Helpers/x-saherelm.x121.xcatb.helper.mq5 index a0ba5a2a..100b596b 100644 --- a/Helpers/x-saherelm.x121.xcatb.helper.mq5 +++ b/Helpers/x-saherelm.x121.xcatb.helper.mq5 @@ -33,7 +33,7 @@ enum ENUM_X121_XCATB_BUFFERS { X121_XCATB_SAR_LINE = 0, - X121_XCATB_SAR_STATE_LINE = 28, + X121_XCATB_SAR_STATE_LINE = 30, X121_XCATB_PEAK_LINE = 2, X121_XCATB_VALE_LINE = 3, X121_XCATB_PEAK_GOLDEN_LINE = 4, @@ -41,7 +41,7 @@ enum ENUM_X121_XCATB_BUFFERS X121_XCATB_ATR_BAND_UPPER_LINE = 6, X121_XCATB_ATR_BAND_LOWER_LINE = 7, X121_XCATB_TREND_LINE = 8, - X121_XCATB_TREND_STATE_LINE = 29, + X121_XCATB_TREND_STATE_LINE = 31, X121_XCATB_SBAR_O_LINE = 10, X121_XCATB_SBAR_H_LINE = 11, X121_XCATB_SBAR_L_LINE = 12, @@ -58,23 +58,25 @@ enum ENUM_X121_XCATB_BUFFERS X121_XCATB_L_LL_LINE = 25, X121_XCATB_H_HH_LINE = 26, X121_XCATB_H_LL_LINE = 27, - X121_XCATB_RSI_LINE = 30, - X121_XCATB_ADX_LINE = 31, - X121_XCATB_ADXP_LINE = 32, - X121_XCATB_ADXN_LINE = 33, - X121_XCATB_DELTA_LINE = 34, - X121_XCATB_DELTA_SIGNAL_LINE = 35, - X121_XCATB_VOLUME_BULLISH_LINE = 36, - X121_XCATB_VOLUME_BEARISH_LINE = 37, - X121_XCATB_VOLUME_VOLUME_BULLISH_SIGNAL_LINE = 38, - X121_XCATB_VOLUME_VOLUME_BEARISH_SIGNAL_LINE = 39, - X121_XCATB_ATR_LINE = 40, - X121_XCATB_ATR_BAND_RAW_UPPER_LINE = 41, - X121_XCATB_ATR_BAND_RAW_LOWER_LINE = 42, - X121_XCATB_HK_BAR_O_LINE = 43, - X121_XCATB_HK_BAR_H_LINE = 44, - X121_XCATB_HK_BAR_L_LINE = 45, - X121_XCATB_HK_BAR_C_LINE = 46, + X121_XCATB_KI_LINE = 28, + X121_XCATB_KI_STATE_LINE = 50, + X121_XCATB_RSI_LINE = 32, + X121_XCATB_ADX_LINE = 33, + X121_XCATB_ADXP_LINE = 34, + X121_XCATB_ADXN_LINE = 35, + X121_XCATB_DELTA_LINE = 36, + X121_XCATB_DELTA_SIGNAL_LINE = 37, + X121_XCATB_VOLUME_BULLISH_LINE = 38, + X121_XCATB_VOLUME_BEARISH_LINE = 39, + X121_XCATB_VOLUME_VOLUME_BULLISH_SIGNAL_LINE = 40, + X121_XCATB_VOLUME_VOLUME_BEARISH_SIGNAL_LINE = 41, + X121_XCATB_ATR_LINE = 42, + X121_XCATB_ATR_BAND_RAW_UPPER_LINE = 43, + X121_XCATB_ATR_BAND_RAW_LOWER_LINE = 44, + X121_XCATB_HK_BAR_O_LINE = 45, + X121_XCATB_HK_BAR_H_LINE = 46, + X121_XCATB_HK_BAR_L_LINE = 47, + X121_XCATB_HK_BAR_C_LINE = 48, }; // @@ -99,6 +101,7 @@ struct X121XCatbInputs // // Presentation ... bool showBars; // Show Bars + bool showKI; // Show KI bool showPV; // Show PV bool showPVGolden; // Show PV Golden bool showSar; // Show Sar @@ -144,6 +147,7 @@ struct X121XCatbInputs // // Presentation ... showBars = false; // Show Bars + showKI = false; // Show KI showPV = false; // Show PV showPVGolden = false; // Show PV Golden showSar = false; // Show Sar @@ -183,6 +187,7 @@ struct X121XCatbInputs // // Presentation ... showBars = true; // Show Bars + showKI = false; // Show KI showPV = false; // Show PV showPVGolden = false; // Show PV Golden showSar = false; // Show Sar @@ -205,6 +210,7 @@ struct X121XCatbInputs void Hide() { // + showKI = false; showPV = false; showSar = false; showTrend = false; @@ -273,6 +279,7 @@ struct X121XCatbConditions // // Buffers ... + double kiBuffer[]; double sarBuffer[]; double atrBuffer[]; double rsiBuffer[]; @@ -295,6 +302,7 @@ struct X121XCatbConditions double hkOpenBuffer[]; double hkHighBuffer[]; double hkCloseBuffer[]; + double kiStateBuffer[]; double sarStateBuffer[]; double atrUpperBuffer[]; double atrLowerBuffer[]; @@ -341,6 +349,20 @@ struct X121XCatbConditions bool isSarSwitchedToBullish; bool isSarSwitchedToBearish; + // + // KI ... + + // + bool isKIBullish; + bool isKIBearish; + + // + bool isKISameAsLast; + + // + bool isKISwitchedToBullish; + bool isKISwitchedToBearish; + // // ADX ... @@ -494,6 +516,7 @@ struct X121XCatbConditions // Clean(bars); + Clean(kiBuffer); Clean(sarBuffer); Clean(atrBuffer); Clean(rsiBuffer); @@ -516,6 +539,7 @@ struct X121XCatbConditions Clean(hkOpenBuffer); Clean(hkHighBuffer); Clean(hkCloseBuffer); + Clean(kiStateBuffer); Clean(sarStateBuffer); Clean(atrUpperBuffer); Clean(atrLowerBuffer); @@ -534,6 +558,7 @@ struct X121XCatbConditions // ArraySetAsSeries(bars, true); + ArraySetAsSeries(kiBuffer, true); ArraySetAsSeries(sarBuffer, true); ArraySetAsSeries(atrBuffer, true); ArraySetAsSeries(rsiBuffer, true); @@ -556,6 +581,7 @@ struct X121XCatbConditions ArraySetAsSeries(hkOpenBuffer, true); ArraySetAsSeries(hkHighBuffer, true); ArraySetAsSeries(hkCloseBuffer, true); + ArraySetAsSeries(kiStateBuffer, true); ArraySetAsSeries(sarStateBuffer, true); ArraySetAsSeries(atrUpperBuffer, true); ArraySetAsSeries(atrLowerBuffer, true); @@ -605,6 +631,20 @@ struct X121XCatbConditions isSarSwitchedToBullish = false; isSarSwitchedToBearish = false; + // + // KI ... + + // + isKIBullish = false; + isKIBearish = false; + + // + isKISameAsLast = false; + + // + isKISwitchedToBullish = false; + isKISwitchedToBearish = false; + // // ADX ... @@ -799,6 +839,29 @@ struct X121XCatbConditions bearishScore += score; } + // + // KI ... + + // + if (isKIBullish) + { + bullishScore += score; + } + if (isKISwitchedToBullish) + { + bullishScore += score; + } + + // + if (isKIBearish) + { + bearishScore += score; + } + if (isKISwitchedToBearish) + { + bearishScore += score; + } + // // ADX ... @@ -1121,6 +1184,15 @@ struct X121XCatbConditions ToString("isClosedUnderATRLower", isClosedUnderATRLower, ignoreFalseConditions, separator) + // "-----------------------" + separator + + "KI: " + separator + + "-----------------------" + separator + + ToString("isKIBullish", isKIBullish, ignoreFalseConditions, separator) + + ToString("isKIBearish", isKIBearish, ignoreFalseConditions, separator) + + ToString("isKISameAsLast", isKISameAsLast, ignoreFalseConditions, separator) + + ToString("isKISwitchedToBullish", isKISwitchedToBullish, ignoreFalseConditions, separator) + + ToString("isKISwitchedToBearish", isKISwitchedToBearish, ignoreFalseConditions, separator) + + // + "-----------------------" + separator + "SAR: " + separator + "-----------------------" + separator + ToString("isSarBullish", isSarBullish, ignoreFalseConditions, separator) + @@ -1264,6 +1336,7 @@ class XCX121XCatbHelper : public XCBaseHelper // // Buffers ... + double kiBuffer[]; double sarBuffer[]; double atrBuffer[]; double rsiBuffer[]; @@ -1286,6 +1359,7 @@ class XCX121XCatbHelper : public XCBaseHelper double hkOpenBuffer[]; double hkHighBuffer[]; double hkCloseBuffer[]; + double kiStateBuffer[]; double sarStateBuffer[]; double atrUpperBuffer[]; double atrLowerBuffer[]; @@ -1412,6 +1486,7 @@ class XCX121XCatbHelper : public XCBaseHelper } // + ArraySetAsSeries(kiBuffer, true); ArraySetAsSeries(sarBuffer, true); ArraySetAsSeries(atrBuffer, true); ArraySetAsSeries(rsiBuffer, true); @@ -1434,6 +1509,7 @@ class XCX121XCatbHelper : public XCBaseHelper ArraySetAsSeries(hkOpenBuffer, true); ArraySetAsSeries(hkHighBuffer, true); ArraySetAsSeries(hkCloseBuffer, true); + ArraySetAsSeries(kiStateBuffer, true); ArraySetAsSeries(sarStateBuffer, true); ArraySetAsSeries(atrUpperBuffer, true); ArraySetAsSeries(atrLowerBuffer, true); @@ -1470,6 +1546,7 @@ class XCX121XCatbHelper : public XCBaseHelper mInputs.appliedCycle, "", // Presentation ... mInputs.showBars, + mInputs.showKI, mInputs.showPV, mInputs.showPVGolden, mInputs.showSar, @@ -1963,6 +2040,113 @@ class XCX121XCatbHelper : public XCBaseHelper // // Readers ... + // + // Readers ... + + // + // SAR ... + + // + double GetKI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(barIndex); + + // + int count = ArraySize(kiBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return kiBuffer[barIndex]; + } + + // + int CopyKI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(start); + + // + // Copy Items ... + return Copy( + 0, + count, + kiBuffer, + buffer, + forceClean + // + ); + } + + // + // KI State ... + + // + double GetKIState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(barIndex); + + // + int count = ArraySize(kiStateBuffer); + if (barIndex >= count) + { + barIndex = count - 1; + } + + // + return kiStateBuffer[barIndex]; + } + + // + int CopyKIState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(start); + + // + // Copy Items ... + return Copy( + 0, + count, + kiStateBuffer, + buffer, + forceClean + // + ); + } + // // SAR ... @@ -3996,6 +4180,19 @@ class XCX121XCatbHelper : public XCBaseHelper // // Buffers ... + CopyKI( + zIndex, + loopback, + conditions.kiBuffer // + ); + + // + CopyKIState( + zIndex, + loopback, + conditions.kiStateBuffer // + ); + CopySar( zIndex, loopback, @@ -4281,6 +4478,23 @@ class XCX121XCatbHelper : public XCBaseHelper double p2ATRLower = conditions.atrLowerBuffer[p2IDX]; double p3ATRLower = conditions.atrLowerBuffer[p3IDX]; + // + // KI ... + + // + double zKI = conditions.kiBuffer[zIDX]; + double cKI = conditions.kiBuffer[cIDX]; + double pKI = conditions.kiBuffer[pIDX]; + double p2KI = conditions.kiBuffer[p2IDX]; + double p3KI = conditions.kiBuffer[p3IDX]; + + // + double zKIState = conditions.kiStateBuffer[zIDX]; + double cKIState = conditions.kiStateBuffer[cIDX]; + double pKIState = conditions.kiStateBuffer[pIDX]; + double p2KIState = conditions.kiStateBuffer[p2IDX]; + double p3KIState = conditions.kiStateBuffer[p3IDX]; + // // SAR ... @@ -4471,6 +4685,26 @@ class XCX121XCatbHelper : public XCBaseHelper bool isClosedUnderATRLower = conditions.bars[cIDX].close < cATRLower; + // + // KI ... + + // + bool isKIBullish = cKIState > 0; + bool isKIBearish = cKIState < 0; + + // + bool isKISameAsLast = cKI == pKI; + + // + bool isKISwitchedToBullish = + cKIState > 0 && + pKIState <= 0; + + // + bool isKISwitchedToBearish = + cKIState < 0 && + pKIState >= 0; + // // SAR ... @@ -4747,6 +4981,8 @@ class XCX121XCatbHelper : public XCBaseHelper conditions.rsiOSLevel = _rsiOSLevel; conditions.isDeltaDown = isDeltaDown; conditions.isTrendDown = isTrendDown; + conditions.isKIBullish = isKIBullish; + conditions.isKIBearish = isKIBearish; conditions.adxThreshold = _adxThreshold; conditions.isSarBullish = isSarBullish; conditions.isSarBearish = isSarBearish; @@ -4756,6 +4992,7 @@ class XCX121XCatbHelper : public XCBaseHelper conditions.isRSIBearish = isRSIBearish; conditions.isSBarBullish = isSBarBullish; conditions.isSBarBearish = isSBarBearish; + conditions.isKISameAsLast = isKISameAsLast; conditions.isDeltaBullish = isDeltaBullish; conditions.isDeltaBearish = isDeltaBearish; conditions.isTrendBullish = isTrendBullish; @@ -4781,6 +5018,8 @@ class XCX121XCatbHelper : public XCBaseHelper conditions.isRSICrossedUnderOS = isRSICrossedUnderOS; conditions.isADXUnderThreshold = isADXUnderThreshold; conditions.isClosedOverATRUpper = isClosedOverATRUpper; + conditions.isKISwitchedToBullish = isKISwitchedToBullish; + conditions.isKISwitchedToBearish = isKISwitchedToBearish; conditions.isClosedUnderATRLower = isClosedUnderATRLower; conditions.isSarSwitchedToBullish = isSarSwitchedToBullish; conditions.isSarSwitchedToBearish = isSarSwitchedToBearish; @@ -4836,6 +5075,24 @@ class XCX121XCatbHelper : public XCBaseHelper barIndex = 0; } + // + CopyBuffer( + mHandler, + X121_XCATB_KI_LINE, + barIndex, + maxRequiredBars, + kiBuffer // + ); + + // + CopyBuffer( + mHandler, + X121_XCATB_KI_STATE_LINE, + barIndex, + maxRequiredBars, + kiStateBuffer // + ); + // CopyBuffer( mHandler, @@ -5175,6 +5432,18 @@ class XCX121XCatbHelper : public XCBaseHelper int maxAllowed = 100 // ) { + // + CleanupArray( + kiBuffer, + maxAllowed // + ); + + // + CleanupArray( + kiStateBuffer, + maxAllowed // + ); + // CleanupArray( sarBuffer, diff --git a/Indicators/x-saherelm.x121.xcatb.mq5 b/Indicators/x-saherelm.x121.xcatb.mq5 index 39459a71..86607b9f 100644 --- a/Indicators/x-saherelm.x121.xcatb.mq5 +++ b/Indicators/x-saherelm.x121.xcatb.mq5 @@ -80,6 +80,7 @@ input ENUM_X_MARKET_CYCLES appliedCycle = X_MARKET_CYCLE_HIND; // Applied Cycle // Presentation ... input group "Presentation"; input bool showBars = true; // Show Bars +input bool showKI = false; // Show KI input bool showPV = false; // Show PV input bool showPVGolden = false; // Show PV Golden input bool showSar = false; // Show Sar @@ -98,6 +99,7 @@ double sarMax = 0.2; // Maximum double rsiOBLevel = 70.0; // RSI OB Level double rsiOSLevel = 30.0; // RSI OS Level double adxThreshold = 25.0; // ADX Threshold +int kiLength = 144; // KI Length int sarArrowCode = 159; // Parabolic Sar Arrow Code int peakArrowCode = 159; // Peaks Arrow Code int valeArrowCode = 159; // Vales Arrow Code @@ -144,8 +146,8 @@ ENUM_X_MA_METHOD volumeSignalMethod = X_MA_MODE_EMA; // Volume Signalling Method // Color: 4 // Bar: 8 // Data Buffer: 19 -#property indicator_buffers 49 -#property indicator_plots 18 +#property indicator_buffers 52 +#property indicator_plots 19 // // Plot Buffers ... @@ -447,11 +449,30 @@ double hLLBuffer[]; #property indicator_style18 STYLE_DOT #property indicator_width18 1 +// +// KI ... + +// +#define kiBufferIndex 28 +#define kiBufferPlotIndex 18 +double kiBuffer[]; + +// +#define kiColorBufferIndex 29 +double kiColorBuffer[]; + +// +#property indicator_label19 "KI" +#property indicator_type19 DRAW_COLOR_LINE +#property indicator_color19 CLR_NONE, clrGreen, clrRed, clrGray +#property indicator_style19 STYLE_DASHDOTDOT +#property indicator_width19 2 + // // Data Buffers ... // -#define mLastBufferIndex 27 +#define mLastBufferIndex 29 // // SAR ... @@ -553,6 +574,13 @@ double lowHKBuffer[]; #define closeHKBufferIndex mLastBufferIndex + 19 double closeHKBuffer[]; +// +// KI ... + +// +#define kiStateBufferIndex mLastBufferIndex + 20 +double kiStateBuffer[]; + // // Variables, Properties and etc ... @@ -1288,6 +1316,21 @@ void DefineBuffers() PlotIndexSetInteger(hLLBufferPlotIndex, PLOT_DRAW_TYPE, hDrawType); PlotIndexSetDouble(hLLBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + // + // KI ... + + // + ArraySetAsSeries(kiBuffer, true); + SetIndexBuffer(kiBufferIndex, kiBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(kiBufferPlotIndex, PLOT_SHOW_DATA, showKI); + PlotIndexSetDouble(kiBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + ArraySetAsSeries(kiColorBuffer, true); + SetIndexBuffer(kiColorBufferIndex, kiColorBuffer, INDICATOR_COLOR_INDEX); + // // Data Buffers ... @@ -1374,6 +1417,13 @@ void DefineBuffers() ArraySetAsSeries(closeHKBuffer, true); SetIndexBuffer(closeHKBufferIndex, closeHKBuffer, INDICATOR_CALCULATIONS); + // + // KI ... + + // + ArraySetAsSeries(kiStateBuffer, true); + SetIndexBuffer(kiStateBufferIndex, kiStateBuffer, INDICATOR_DATA); + // } @@ -1684,6 +1734,7 @@ void CalculateBuffers( void FillBuffersZero(int barIndex) { // + kiColorBuffer[barIndex] = hideColorIDX; sarColorBuffer[barIndex] = hideColorIDX; trendColorBuffer[barIndex] = hideColorIDX; @@ -1741,6 +1792,19 @@ void CalculateValues( tickVolume // ); + // + // KI ... + CalculateKI( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + // // PV ... CalculatePV( @@ -1895,6 +1959,90 @@ void CalculateCycleRanges( ); } +// +void CalculateKI( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + barIndex // + ); + + // + double iClose = close[barIndex]; + + // + // Calculate KI / Color ... + double lastKI = + isFirstBar + ? emptyValue + : kiBuffer[lastBarIndex]; + double iKI = lastKI; + if (isInited) + { + // + double iLLKI = iBar.FindLowest(kiLength, MODE_LOW); + double iHHKI = iBar.FindHighest(kiLength, MODE_HIGH); + + // + iKI = (iHHKI + iLLKI) / 2; + if (iLLKI == 0 || iHHKI == 0) + { + iKI = lastKI; + } + } + else + { + iKI = lastKI; + } + kiBuffer[barIndex] = iKI; + + // + double iKIState = neuturalState; + double iKIColor = neuturalColorIDX; + if (iClose > iKI) + { + // + iKIState = bullishState; + iKIColor = + !showKI + ? hideColorIDX + : bullishColorIDX; + } + else if (iClose < iKI) + { + // + iKIState = bearishState; + iKIColor = + !showKI + ? hideColorIDX + : bearishColorIDX; + } + kiStateBuffer[barIndex] = iKIState; + kiColorBuffer[barIndex] = iKIColor; + + // + iBar.Clean(); +} + // void CalculatePV( int barIndex, diff --git a/XCATBEA/Classes/xcatbea.signaller.class.mq5 b/XCATBEA/Classes/xcatbea.signaller.class.mq5 index 41bf4214..e1d0a303 100644 --- a/XCATBEA/Classes/xcatbea.signaller.class.mq5 +++ b/XCATBEA/Classes/xcatbea.signaller.class.mq5 @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////// // -// SaherElm IT Center MQL5 Indicator +// SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCXCATBEASignaller ... // Description: Class for XCATBEA Signaller ... @@ -17,16 +17,22 @@ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" -#property description "SaherElm Class for XCATBEA Signaller" +#property description "SaherElm XCXCATBEASignaller Class" #property strict // // Imports ... +#include "../../Classes/x-saherelm.x-alert.class.mq5" +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5"; +#include "../Classes/xcatbea.x-poi.detector.class.mq5"; +#include "../Classes/xcatbea.x-poi.drawer.class.mq5"; #include "../Libraries/xcatbea.lib.mq5"; #include "../Libraries/xcatbea.signaller.lib.mq5"; +#include "../Libraries/xcatbea.x-poi.extensions.lib.mq5"; // // Definitions ... -class XCXCATBEASignaller : XCBase +class XCXCATBEASignaller : XCBaseAlert { }; \ No newline at end of file diff --git a/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 b/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 new file mode 100644 index 00000000..691a4008 --- /dev/null +++ b/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 @@ -0,0 +1,1646 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXCAYBEAPOIDetector ... +// Description: Class for XCATBEA POI Detector ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Class for XCATBEA POI Detector" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" + +// +// Definitions ... + +// +enum ENUM_XCATB_PIVOTS +{ + XCA_NONE, // None + XCA_PEAK, // Peak + XCA_VALE, // Vale +}; + +// +bool IsValid(ENUM_XCATB_PIVOTS value) +{ + // + bool result = false; + + // + result = value != XCA_NONE; + + // + return result; +} + +// +string ToString(ENUM_XCATB_PIVOTS value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + +// +ENUM_X_DIRECTION GetDirection(ENUM_XCATB_PIVOTS value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + switch (value) + { + // + case XCA_VALE: + result = X_DIRECTION_BULLISH; + break; + + // + case XCA_PEAK: + result = X_DIRECTION_BEARISH; + break; + } + + // + return result; +} + +// +string GetBoxType(ENUM_XCATB_PIVOTS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case XCA_VALE: + case XCA_PEAK: + result = ToString(value); + break; + } + + // + return result; +} + +// +ENUM_XCATB_PIVOTS GetPivotType(XBoxZone &value) +{ + // + ENUM_XCATB_PIVOTS result = XCA_NONE; + + // + bool has = value.IsValid(); + if (!has) + { + return result; + } + + // + bool isPeak = value.type == GetBoxType(XCA_PEAK) && + value.dir == GetDirection(XCA_PEAK); + bool isVale = value.type == GetBoxType(XCA_VALE) && + value.dir == GetDirection(XCA_VALE); + + // + if (isPeak) + { + result = XCA_PEAK; + } + else if (isVale) + { + result = XCA_VALE; + } + + // + return result; +} + +// +struct XCATBPivot +{ + // + // Props ... + datetime to; + double value; + string symbol; + datetime from; + double reserve; + ENUM_XCATB_PIVOTS type; + ENUM_TIMEFRAMES period; + + // + double values[]; + + // + // Constructor ... + XCATBPivot() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + value = 0; + to = NULL; + reserve = 0; + from = NULL; + symbol = NULL; + period = NULL; + type = XCA_NONE; + + // + Clean(values); + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + from < to && + value != 0 && + IsValid(to) && + IsValid(from) && + IsValid(type) && + IsValid(symbol) && + IsValid(period); + + // + return result; + } + + /** + * Check a Model is Same as this or not ... + * + * @param pivot: XCATBPivot ... + * + * @return ( bool ) + */ + bool IsSameAs(XCATBPivot &pivot) + { + // + bool result = false; + + // + result = + IsValid() && + pivot.IsValid(); + if (!result) + { + return result; + } + + // + result = + to == pivot.to && + from == pivot.from && + type == pivot.type && + value == pivot.value && + symbol == pivot.symbol && + period == pivot.period; + + // + return result; + } + + /** + * Retrieve To Index ... + * + * @param forPeriod: ENUM_TIMEFRAMES, Specified Period ... + * + * @return ( int ) + */ + int ToIndex( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = GetBarIndex( + symbol, + forPeriod, + to // + ); + + // + return result; + } + + /** + * Retrieve From Index ... + * + * @param forPeriod: ENUM_TIMEFRAMES, Specified Period ... + * + * @return ( int ) + */ + int FromIndex( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + result = GetBarIndex( + symbol, + forPeriod, + from // + ); + + // + return result; + } + + /** + * Retrieve Age of Pivot ... + * + * @param forPeriod: ENUM_TIMEFRAMES, Specified Period ... + * + * @return ( int ) + */ + int GetAge( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + if (!IsValid(forPeriod)) + { + forPeriod = period; + } + + // + int toIDX = ToIndex(forPeriod); + int fromIDX = FromIndex(forPeriod); + + // + result = fromIDX - toIDX; + + // + return result; + } + + /** + * Converts Pivot to Box ... + * + * @param box: XBoxZone instance reference ... + * + * @return ( bool ) + */ + bool AsBox( + XBoxZone &box // + ) + { + // + bool result = false; + + // + box.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION iDir = GetDirection(type); + + // + result = HasDirection(iDir); + if (!result) + { + return result; + } + + // + bool isBullish = + IsBullish(iDir) && + value < reserve; + + // + bool isBearish = + IsBearish(iDir) && + value > reserve; + + // + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + box.to = to; + box.dir = iDir; + box.from = from; + box.symbol = symbol; + box.period = period; + + // + string typeStr = GetBoxType(type); + box.type = typeStr; + + // + box.upper = + isBullish + ? reserve + : value; + box.lower = + isBullish + ? value + : reserve; + + // + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + return result; + } + + // +}; + +// +// Implementations ... +class XCXCATBEAPOIDetector : public XCBase +{ + // + // Public ... + public: + // + // Props ... + int maxAllowedPivots; // Max Allowed Holding Pibots ... + int pivotVerifications; // Pivots Verifications ... + int pivotDetectionLoopbac; // Pivots Detection Loopback ... + + // + // Breaked Pivots ... + XBoxZone invalidPivots[]; + + // + // Constructors ... + XCXCATBEAPOIDetector( + XCX121XCatbHelper *_helper // + ) + { + // + helper = _helper; + barAnalyser = new XCBarAnalyser(); + + // + Default(); + } + + // + // De Constructors ... + ~XCXCATBEAPOIDetector() + { + // + CleanPivots(); + + // + ZeroMemory(helper); + + // + delete barAnalyser; + ZeroMemory(barAnalyser); + } + + // + // Properties ... + + // + // Tools ... + + // + virtual void Default() + { + // + // COMMON ... + + // + maxAllowedPivots = 50; + pivotVerifications = 5; + pivotDetectionLoopbac = 100; + + // + // PV ... + + // + maxAllowedPVLifetime = 0; + selectRejectedPVPivots = false; + selectEngulfedPVPivots = false; + + // + detectPeakPivots = false; + detectValePivots = false; + } + + // + void Detect( + int barIndex = 0 // + ) + { + } + + // + void Validate( + XBoxZone &unavailables[], + int barIndex = 0 // + ) + { + } + + // + // Pivots ... + + // + // INVALID Pivots ... + + // + bool HasInvalidPivots() + { + return HasChild(invalidPivots); + } + + // + int CountInvalidPivots() + { + return ArraySize(invalidPivots); + } + + // + // PV ... + + // + int maxAllowedPVLifetime; // Max Allowed PV Life ... + bool selectRejectedPVPivots; // Select Rejected PV Pivots ... + bool selectEngulfedPVPivots; // Select Engulfed PV Pivots ... + + // + bool DetectPeakAndValePivot( + int barIndex, + ENUM_X_DIRECTION forDir, + XOHCL &zBar, + XOHCL &cBar, + XOHCL &pBar, + XOHCL &p2Bar, + XCX121XCatbHelper &conditions // + ) + { + // + bool result = false; + + // + // Checking Direction ... + result = HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool forBullish = IsBullish(forDir); + bool forBearish = IsBearish(forDir); + + // + // Check Allowed ... + result = + forBullish + ? detectValePivots + : detectPeakPivots; + if (!result) + { + return result; + } + + // + // Validate Args ... + result = + // + barIndex >= 0 && + zBar.IsValid() && + cBar.IsValid() && + pBar.IsValid() && + p2Bar.IsValid() + // + ; + if (!result) + { + return result; + } + + // + // Define Requirements ... + + // + int zIDX = 0; + int cIDX = zIDX + 1; + int pIDX = cIDX + 1; + int p2IDX = pIDX + 1; + + // + datetime cTime = zBar.time; + string symbol = zBar.symbol; + ENUM_TIMEFRAMES period = zBar.period; + double points = GetPoints(symbol); + + // + // Reading Conditional Values ... + + // + // PEAK ... + double zPeak = conditions.peakBuffer[zIDX]; + double cPeak = conditions.peakBuffer[cIDX]; + double pPeak = conditions.peakBuffer[pIDX]; + double p2Peak = conditions.peakBuffer[p2IDX]; + + // + // PEAK Golden ... + double zPeakGolden = conditions.peakGoldenBuffer[zIDX]; + double cPeakGolden = conditions.peakGoldenBuffer[cIDX]; + double pPeakGolden = conditions.peakGoldenBuffer[pIDX]; + double p2PeakGolden = conditions.peakGoldenBuffer[p2IDX]; + + // + // VALE ... + double zVale = conditions.valeBuffer[zIDX]; + double cVale = conditions.valeBuffer[cIDX]; + double pVale = conditions.valeBuffer[pIDX]; + double p2Vale = conditions.valeBuffer[p2IDX]; + + // + // VALE Golden ... + double zValeGolden = conditions.valeGoldenBuffer[zIDX]; + double cValeGolden = conditions.valeGoldenBuffer[cIDX]; + double pValeGolden = conditions.valeGoldenBuffer[pIDX]; + double p2ValeGolden = conditions.valeGoldenBuffer[p2IDX]; + + // + // Detecting Bar Conditions ... + + // + ENUM_X_DIRECTION cBarDir; + + // + // Rejected ... + bool isCBarRejected = barAnalyser + .IsRejected( + cBar, + cBarDir, + false, // Force Type ... + false // Force Fibo Pressure ... + ); + + // + bool isCBarBullishRejected = + forBullish && + isCBarRejected && + IsBullish(cBarDir); + bool isCBarBearishRejected = + forBearish && + isCBarRejected && + IsBearish(cBarDir); + + // + bool isPBarRejected = barAnalyser + .IsRejected( + pBar, + cBarDir, + false, // Force Type ... + false // Force Fibo Pressure ... + ); + bool isPBarBullishRejected = + forBullish && + isPBarRejected && + IsBullish(cBarDir); + bool isPBarBearishRejected = + forBearish && + isPBarRejected && + IsBearish(cBarDir); + + // + bool isBarBullishRejected = + forBullish && + (isCBarBullishRejected || + isPBarBullishRejected); + + // + bool isBarBearishRejected = + forBearish && + (isCBarBearishRejected || + isPBarBearishRejected); + + // + // Engulfed ... + bool isCBarEngulfed = barAnalyser + .IsEngulfed( + cBar, + cBarDir // + ); + bool isCBarBullishEngulfed = + forBullish && + isCBarEngulfed && + IsBullish(cBarDir); + bool isCBarBearishEngulfed = + forBearish && + isCBarEngulfed && + IsBearish(cBarDir); + + // + bool isPBarEngulfed = barAnalyser + .IsEngulfed( + pBar, + cBarDir // + ); + bool isPBarBullishEngulfed = + forBullish && + isPBarEngulfed && + IsBullish(cBarDir); + bool isPBarBearishEngulfed = + forBearish && + isPBarEngulfed && + IsBearish(cBarDir); + + // + bool isBarBullishEngulfed = + forBullish && + (isCBarBullishEngulfed || + isPBarBullishEngulfed); + + // + bool isBarBearishEngulfed = + forBearish && + (isCBarBearishEngulfed || + isPBarBearishEngulfed); + + // + // Prepare Conditinal Conditions ... + + // + // PEAK ... + + // + bool isPeakSameLast = cPeak == pPeak; + bool isPeakSameLastPrev = pPeak == p2Peak; + + // + bool isPeakSwitchedToSameLast = isPeakSameLast && + !isPeakSameLastPrev; + bool isPeakFinishedFromSameLast = !isPeakSameLast && + isPeakSameLastPrev; + + // + // VALE ... + + // + bool isValeSameLast = cVale == pVale; + bool isValeSameLastPrev = pVale == p2Vale; + + // + bool isValeSwitchedToSameLast = isValeSameLast && + !isValeSameLastPrev; + bool isValeFinishedFromSameLast = !isValeSameLast && + isValeSameLastPrev; + + // + // Summarizing Conditions ... + + // + result = false; + + // + bool hasStartCondition = + // + forBullish + ? isValeFinishedFromSameLast + : isPeakFinishedFromSameLast + // + ; + + // + bool hasContinuationCondition = + // + forBullish + ? isValeSameLast + : isPeakSameLast + // + ; + + // + bool hasEndCondition = + // + forBullish + ? isValeSwitchedToSameLast + : isPeakSwitchedToSameLast + // + ; + + // + // Apply Validations ... + if (hasEndCondition) + { + // + bool hasSelectionType = selectRejectedPVPivots || + selectEngulfedPVPivots; + + // + bool isPVRejected = + forBullish + ? (isBarBullishRejected && + selectRejectedPVPivots) + : (isBarBearishRejected && + selectRejectedPVPivots); + + // + bool isPVEngulfed = + forBullish + ? (isBarBullishEngulfed && + selectEngulfedPVPivots) + : (isBarBearishEngulfed && + selectEngulfedPVPivots); + + // + bool isBarPassed = + !hasSelectionType + ? true + : isPVRejected || + isPVEngulfed; + + // + hasEndCondition = + isBarPassed && + hasEndCondition; + if (!hasEndCondition) + { + // + // VALE ... + if (forBullish) + { + valePivot.Clean(); + } + + // + // PEAK ... + if (forBearish) + { + peakPivot.Clean(); + } + } + } + + // + // + // + + // + // ReInstance Pivot ... + if (hasStartCondition) + { + // + // VALE ... + if (forBullish) + { + // + valePivot.Clean(); + + // + valePivot.type = XCA_VALE; + valePivot.symbol = symbol; + valePivot.period = period; + + // + valePivot.to = pBar.time; + valePivot.from = pBar.time; + valePivot.value = pVale; + valePivot.reserve = pValeGolden; + } + + // + // PEAK ... + if (forBearish) + { + // + peakPivot.Clean(); + + // + peakPivot.type = XCA_PEAK; + peakPivot.symbol = symbol; + peakPivot.period = period; + + // + peakPivot.to = pBar.time; + peakPivot.from = pBar.time; + peakPivot.value = pPeak; + peakPivot.reserve = pPeakGolden; + } + } + + // + // Calculate and Fill Pivot Requirements ... + if (hasContinuationCondition) + { + // + // VALE ... + if (forBullish) + { + // + valePivot.from = pBar.time; + + // + valePivot.reserve = + valePivot.reserve == 0 + ? pValeGolden + : MathMin(valePivot.reserve, pValeGolden); + } + + // + // PEAK ... + if (forBearish) + { + // + peakPivot.from = pBar.time; + + // + peakPivot.reserve = + peakPivot.reserve == 0 + ? pPeakGolden + : MathMax(peakPivot.reserve, pPeakGolden); + } + } + + // + // End up Pivot and Store it ... + if (hasEndCondition) + { + // + // VALE ... + if (forBullish) + { + // + result = + valePivot.IsValid() && + valePivot.GetAge() >= pivotVerifications; + if (result) + { + // + XBoxZone iBox; + result = valePivot.AsBox(iBox); + if (result) + { + // + newValePivotDetected = AddBox( + iBox, + valePivots // + ); + } + + // + iBox.Clean(); + } + + // + valePivot.Clean(); + } + + // + // PEAK ... + if (forBearish) + { + // + result = + peakPivot.IsValid() && + peakPivot.GetAge() >= pivotVerifications; + if (result) + { + // + XBoxZone iBox; + result = peakPivot.AsBox(iBox); + if (result) + { + // + newPeakPivotDetected = AddBox( + iBox, + peakPivots // + ); + } + + // + iBox.Clean(); + } + + // + peakPivot.Clean(); + } + } + + // + return result; + } + + // + void ValidatePeakValePivots( + XBoxZone &unavailables[], + int barIndex = 0 // + ) + { + // + bool has = false; + + // + bool applyLifetimeValidating = maxAllowedPVLifetime > 0; + + // + // PEAK ... + has = HasPeakPivots(); + if (has) + { + // + ApplyValidationOnBoxes( + peakPivots, + unavailables, + barIndex // + ); + + // + if (applyLifetimeValidating) + { + // + ApplyLifeTimeValidationOnBoxes( + peakPivots, + maxAllowedPVLifetime, + barIndex // + ); + } + } + + // + // VALE ... + has = HasValePivots(); + if (has) + { + // + ApplyValidationOnBoxes( + valePivots, + unavailables, + barIndex // + ); + + // + if (applyLifetimeValidating) + { + // + ApplyLifeTimeValidationOnBoxes( + valePivots, + maxAllowedPVLifetime, + barIndex // + ); + } + } + } + + // + // PEAK ... + + // + XCATBPivot peakPivot; + bool detectPeakPivots; + XBoxZone peakPivots[]; + bool newPeakPivotDetected; + + // + bool HasPeakPivots() + { + return HasChild(peakPivots); + } + + // + int CountPeakPivots() + { + return ArraySize(peakPivots); + } + + // + // VALE ... + + // + XCATBPivot valePivot; + bool detectValePivots; + XBoxZone valePivots[]; + bool newValePivotDetected; + + // + bool HasValePivots() + { + return HasChild(valePivots); + } + + // + int CountValePivots() + { + return ArraySize(valePivots); + } + + // + // Protected ... + protected: + // + // Props ... + + // + bool AddBox( + XBoxZone &box, + XBoxZone &boxes[] // + ) + { + // + bool result = false; + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + int idx = -1; + bool isExists = FindBoxIndex( + idx, + box, + boxes // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + int before = ArraySize(boxes); + + // + AddRef( + box, + boxes // + ); + + // + int after = ArraySize(boxes); + + // + result = after > before; + + // + return result; + } + + // + bool ValidateBox( + XBoxZone &box, + XBoxZone &unavailables[], + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize Bar Index ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Ceck Input Box is Valid ... + result = box.IsValid(); + if (!result) + { + return result; + } + + // + // Check Input Box is Available ... + bool canCheckUnAvailableBoxes = HasChild(unavailables); + if (canCheckUnAvailableBoxes) + { + // + int idx = -1; + bool isUnAvailable = FindBoxIndex( + idx, + box, + unavailables // + ); + result = !isUnAvailable; + if (!result) + { + return result; + } + } + + // + // Check Input Box is Breaked or not ... + + // + // Check Bar Index must after Box To Index ... + int toIDX = box.ToIndex(); + int fromIDX = box.FromIndex(); + result = toIDX > barIndex && + fromIDX > barIndex && + fromIDX > toIDX; + if (!result) + { + return result; + } + + // + // Detect Box Applied Boundary Price ... + // For Checking Break of Box ... + bool isBullish = box.IsBullish(); + double boundary = + isBullish + ? box.lower + : box.upper; + + // + // for validating Box Break we have to wait At Least 3 Bars Close + // out of Box Boundary ... + int barsLength = 3; + + // + // Calculate Start Checking Bar Index ... + int startCheckBreaktionBarIndex = toIDX - barsLength; + bool isBarIndexValid = startCheckBreaktionBarIndex > 0 && + barIndex < startCheckBreaktionBarIndex; + result = isBarIndexValid; + if (!result) + { + // + // Assume Box is Valid if Bar Index not Valid for Checking ... + result = true; + return result; + } + + // + // Try to Check Box Validation if Everything is OK ... + XOHCL cBar; + XOHCL pBar; + XOHCL p2Bar; + bool isValid = false; + bool isBreaked = false; + for (int i = barIndex; i < startCheckBreaktionBarIndex; i++) + { + // + // Initialize Bars ... + isValid = cBar.Init( + box.symbol, + box.period, + i + 1 // + ); + isValid = + result && + cBar.GetPreviousBar(pBar); + isValid = + result && + pBar.GetPreviousBar(p2Bar); + if (!isValid) + { + // + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + + // + result = false; + + // + break; + } + + // + // Preparing Conditions ... + + // + bool isBullishBreaked = + isBullish && + cBar.close < boundary && + pBar.close < boundary && + p2Bar.close < boundary; + + // + bool isBearishBreaked = + !isBullish && + cBar.close > boundary && + pBar.close > boundary && + p2Bar.close > boundary; + + // + // Calculate Result ... + isBreaked = isBullishBreaked || + isBearishBreaked; + if (isBreaked) + { + // + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + + // + result = false; + + // + break; + } + + // + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + } + + // + result = isValid && + !isBreaked; + if (!result) + { + // + int idx = -1; + bool isExists = FindBoxIndex( + idx, + box, + invalidPivots // + ); + if (!isExists) + { + // + AddRef( + box, + invalidPivots // + ); + } + } + + // + // Cleanup Resource ... + + // + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + void CleanPivots() + { + // + Clean(invalidPivots); + + // + peakPivot.Clean(); + valePivot.Clean(); + + // + Clean(peakPivots); + Clean(valePivots); + } + + // + void SortPivots() + { + // + bool has = false; + + // + // Invalid Pivots ... + has = HasInvalidPivots(); + if (has) + { + ApplySortOnBoxes(invalidPivots); + } + + // + // PV ... + + // + // PEAK ... + has = HasPeakPivots(); + if (has) + { + ApplySortOnBoxes(peakPivots); + } + + // + // VALE ... + has = HasValePivots(); + if (has) + { + ApplySortOnBoxes(valePivots); + } + } + + // + void ApplySortOnBoxes( + XBoxZone &items[] // + ) + { + // + int idx = -1; + bool has = false; + + // + has = HasChild(items); + if (!has) + { + return; + } + + // + XBoxZone tmp[]; + Copy( + items, + tmp // + ); + Clean(items); + + // + while (HasChild(tmp)) + { + // + idx = GetOldest(tmp); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XBoxZone iBox = tmp[idx]; + ArrayRemove( + tmp, + idx, + 1 // + ); + + // + AddRef( + iBox, + items // + ); + } + + // + CleanupArray( + items, + maxAllowedPivots // + ); + + // + Clean(tmp); + } + + // + void ApplyValidationOnBoxes( + XBoxZone &items[], + XBoxZone &unavailables[], + int barIndex = 0 // + ) + { + // + bool has = false; + + // + has = HasChild(items); + if (!has) + { + return; + } + + // + XBoxZone tmp[]; + Copy( + items, + tmp // + ); + Clean(items); + while (HasChild(tmp)) + { + // + XBoxZone iBox = tmp[0]; + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + has = ValidateBox( + iBox, + unavailables, + barIndex // + ); + if (has) + { + // + AddRef( + iBox, + items // + ); + } + + // + iBox.Clean(); + // + } + + // + Clean(tmp); + } + + // + void ApplyLifeTimeValidationOnBoxes( + XBoxZone &items[], + int maxAllowedAge = 0, + int barIndex = 0 // + ) + { + // + bool has = false; + + // + barIndex = NormalizeInt(barIndex, 0); + + // + has = + maxAllowedAge > 0 && + HasChild(items); + if (!has) + { + return; + } + + // + datetime cTime = GetBarTime( + helper.GetSymbol(), + helper.GetPeriod(), + barIndex // + ); + + // + XBoxZone tmp[]; + Copy( + items, + tmp // + ); + Clean(items); + + // + while (HasChild(tmp)) + { + // + XBoxZone iBox = tmp[0]; + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + datetime defTo = iBox.to; + iBox.to = cTime; + + // + int iAge = iBox.GetAge(); + has = iAge <= maxAllowedAge; + iBox.to = defTo; + if (has) + { + // + AddRef( + iBox, + items // + ); + } + else + { + // + int idx = -1; + bool isExists = FindBoxIndex( + idx, + iBox, + invalidPivots // + ); + if (!isExists) + { + // + AddRef( + iBox, + invalidPivots // + ); + } + } + + // + iBox.Clean(); + } + + // + Clean(tmp); + } + + // + // Prrivate ... + private: + // + // Props ... + + // + XCX121XCatbHelper *helper; + XCBarAnalyser *barAnalyser; + + // +}; + +// \ No newline at end of file diff --git a/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 b/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 new file mode 100644 index 00000000..c548f343 --- /dev/null +++ b/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 @@ -0,0 +1,604 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXCATBEAPOIDrawer ... +// Description: XCATBEA POI Drawer Class +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XCATBEA POI Drawer Class" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Classes/xcatbea.x-poi.detector.class.mq5" + +// +// Definitions ... +struct XCAPivotStyle +{ + // + // Properties ... + int width; + color clr; + ENUM_LINE_STYLE style; + + // + // Constructor ... + XCAPivotStyle() + { + Default(); + } + + // + // Tools ... + + // + // Cleanup Model ... + void Clean() + { + // + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + ZeroMemory(this); + } + + // + // Default Props ... + void Default() + { + // + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + } +}; + +// +// Implementations ... +class XCXCATBEAPOIDrawer : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCPOIDrawer *drawer; + + // + // Drawers ... + bool drawPeakPivots; + bool drawValePivots; + + // + // Styling ... + + // + XCAPivotStyle defaultBullishStyle; + XCAPivotStyle defaultBearishStyle; + + // + XCAPivotStyle peakPivotStyle; + XCAPivotStyle valePivotStyle; + + // + // Constructors ... + XCXCATBEAPOIDrawer( + XCXCATBEAPOIDetector *_detector // + ) + { + // + detector = _detector; + drawer = new XCPOIDrawer(); + + // + Default(); + } + + // + // De Constructors ... + ~XCXCATBEAPOIDrawer() + { + // + Clear(); + + // + delete drawer; + ZeroMemory(drawer); + + // + ZeroMemory(detector); + } + + // + // Properties ... + + // + // Tools ... + + // + virtual void Default() + { + // + // Drawing ... + drawPeakPivots = false; + drawValePivots = false; + + // + // Styling ... + + // + // Bullish ... + defaultBullishStyle.width = 1; + defaultBullishStyle.clr = clrLime; + defaultBullishStyle.style = STYLE_SOLID; + + // + // Bearish ... + defaultBearishStyle.width = 1; + defaultBearishStyle.clr = clrRed; + defaultBearishStyle.style = STYLE_SOLID; + + // + // Pivots ... + + // + // PV ... + peakPivotStyle = defaultBearishStyle; + valePivotStyle = defaultBullishStyle; + } + + // + void Draw(datetime to = NULL) + { + // + // PV ... + DrawPeakPivots(to); + DrawValePivots(to); + } + + // + void DrawPivot( + XBoxZone &pivot, + datetime to = NULL // + ) + { + // + DrawBox( + pivot, + to, + false, + false // + ); + } + + // + void DrawBox( + XBoxZone &box, + datetime to = NULL, + bool drawMiddle = false, + bool ignoreType = false // + ) + { + // + bool has = box.IsValid(); + if (!has) + { + return; + } + + // + bool canUpdateTo = IsValid(to); + if (canUpdateTo) + { + box.to = to; + } + + // + // Draw Box as POI ... + if (!ignoreType) + { + // + // Detect Pivot Type ... + ENUM_XCATB_PIVOTS iType = GetPivotType(box); + has = IsValid(iType); + if (!has) + { + return; + } + + // + switch (iType) + { + // + case XCA_PEAK: + // + DrawPeakPivot( + box, + to // + ); + break; + + // + case XCA_VALE: + // + DrawValePivot( + box, + to // + ); + break; + } + } + // + // Draw Regular Box ... + else + { + // + // Select Styling Config ... + XCAPivotStyle style; + + // + if (box.IsBullish()) + { + style = defaultBullishStyle; + } + else + { + style = defaultBearishStyle; + } + + // + // Draw Box itself ... + XCBoxObject *iBoxObj; + has = drawer.DrawBox( + box, + iBoxObj // + ); + if (has) + { + // + // Style Object ... + ApplyPivotStyle( + iBoxObj, + style // + ); + + // + // Store Object ... + mObjects.Add(iBoxObj); + } + + // + // Draw Box Middle Range ... + if (drawMiddle) + { + // + double middle = box.GetMid(); + string middleName = box.GetMiddleTag(); + + // + CChartObjectTrend *iMidObj; + iMidObj = new CChartObjectTrend(); + has = iMidObj.Create( + drawer.ChartIdentification(), + middleName, + drawer.SubWindowIdentification(), + box.from, + middle, + box.to, + middle // + ); + if (has) + { + // + // Styling Object ... + iMidObj.Color(style.clr); + iMidObj.Width(style.width); + iMidObj.Style(style.style); + + // + // Store Object ... + mObjects.Add(iMidObj); + } + } + + // + style.Clean(); + } + } + + // + void DrawBoxes( + XBoxZone &boxes[], + datetime to = NULL, + bool drawMiddle = false, + bool ignoreType = false // + ) + { + // + bool has = HasChild(boxes); + if (!has) + { + return; + } + + // + int count = ArraySize(boxes); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = boxes[i]; + + // + // Detect Pivot Type ... + DrawBox( + iBox, + to, + drawMiddle, + ignoreType // + ); + + // + iBox.Clean(); + } + } + + // + void Clear() + { + // + // Cleanup Models ... + defaultBullishStyle.Clean(); + defaultBearishStyle.Clean(); + + // + // Cleanup Styles ... + peakPivotStyle.Clean(); + valePivotStyle.Clean(); + + // + // Cleanup Pivot Objects Holder ... + mObjects.Clear(); + mPeakPivotObjects.Clear(); + mValePivotObjects.Clear(); + } + + // + // Collection Drawers ... + + // + void DrawPeakPivots(datetime to = NULL) + { + // + bool has = drawPeakPivots; + if (!has) + { + return; + } + + // + has = detector.HasPeakPivots(); + if (!has) + { + return; + } + + // + int count = detector.CountPeakPivots(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = detector.peakPivots[i]; + + // + DrawPeakPivot( + iBox, + to // + ); + + // + iBox.Clean(); + } + } + + // + void DrawValePivots(datetime to = NULL) + { + // + bool has = drawValePivots; + if (!has) + { + return; + } + + // + has = detector.HasValePivots(); + if (!has) + { + return; + } + + // + int count = detector.CountValePivots(); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = detector.valePivots[i]; + + // + DrawValePivot( + iBox, + to // + ); + + // + iBox.Clean(); + } + } + + // + // One Item Drawers ... + + // + void DrawPeakPivot( + XBoxZone &item, + datetime to = NULL // + ) + { + // + bool has = drawPeakPivots; + if (!has) + { + return; + } + + // + has = item.IsValid() && + item.type == GetBoxType(XCA_PEAK) && + item.dir == GetDirection(XCA_PEAK); + if (!has) + { + return; + } + + // + bool canUpdateTo = IsValid(to); + if (canUpdateTo) + { + item.to = to; + } + + // + XCBoxObject *iObj; + has = drawer.DrawBox( + item, + iObj // + ); + if (has) + { + // + // Style Object ... + ApplyPivotStyle( + iObj, + peakPivotStyle // + ); + + // + // Store Object ... + mPeakPivotObjects.Add(iObj); + } + + // + ZeroMemory(iObj); + } + + // + void DrawValePivot( + XBoxZone &item, + datetime to = NULL // + ) + { + // + bool has = drawValePivots; + if (!has) + { + return; + } + + // + has = item.IsValid() && + item.type == GetBoxType(XCA_VALE) && + item.dir == GetDirection(XCA_VALE); + if (!has) + { + return; + } + + // + bool canUpdateTo = IsValid(to); + if (canUpdateTo) + { + item.to = to; + } + + // + XCBoxObject *iObj; + has = drawer.DrawBox( + item, + iObj // + ); + if (has) + { + // + // Style Object ... + ApplyPivotStyle( + iObj, + valePivotStyle // + ); + + // + // Store Object ... + mValePivotObjects.Add(iObj); + } + + // + ZeroMemory(iObj); + } + + // + // Protected ... + protected: + // + // Props ... + + // + void ApplyPivotStyle( + XCBoxObject *&object, + XCAPivotStyle &style // + ) + { + // + if (object == NULL) + { + return; + } + + // + object.BoxColor(style.clr); + object.BoxWidth(style.width); + object.BoxStyle(style.style); + } + + // + // Prrivate ... + private: + // + // Props ... + XCXCATBEAPOIDetector *detector; + + // + CArrayObj mObjects; + + // + CArrayObj mPeakPivotObjects; + CArrayObj mValePivotObjects; + + // +}; + +// \ No newline at end of file diff --git a/XCATBEA/Libraries/xcatbea.x-poi.extensions.lib.mq5 b/XCATBEA/Libraries/xcatbea.x-poi.extensions.lib.mq5 new file mode 100644 index 00000000..4e63cbfe --- /dev/null +++ b/XCATBEA/Libraries/xcatbea.x-poi.extensions.lib.mq5 @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Library +// ------------------------------------------------- +// Name: XCATBEAPOIExtension Lib +// Description: Library for Adding Extensions on +// XCATBEA POI(s) ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Extensions Library for XCATBEA POI(s)" +#property strict + +// +// Imports ... +#include "../Classes/xcatbea.x-poi.detector.class.mq5"; + +// +// Extensions ... + +// +int ExtractPivots( + XBoxZone &extracted[], + ENUM_XCATB_PIVOTS type, + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + Clean(extracted); + + // + bool has = + IsValid(type) && + HasChild(source); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + ENUM_XCATB_PIVOTS iType = GetPivotType(iBox); + + // + has = iType == type; + if (has) + { + // + AddRef( + iBox, + extracted // + ); + } + + // + iBox.Clean(); + } + + // + result = ArraySize(extracted); + + // + return result; +}