/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCXFIMAPoiDetector ... // Description: XFIMA POI Detector 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 XFIMA POI Detector Class" #property strict // // Imports ... #include "../../Classes/x-saherelm.base.class.mq5" #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-market.pattern.class.mq5" #include "../Libraries/x-saherelm.xfima.lib.mq5" // // Definitions ... enum ENUM_XFIMA_PIVOTS { XFIMA_PIVOT_NONE = 0, XFIMA_PIVOT_PV = 1, XFIMA_PIVOT_ATR = 2, XFIMA_PIVOT_ZIGZAG = 3, XFIMA_PIVOT_MA_CROSS = 4, XFIMA_PIVOT_HK_SWITCH = 5, XFIMA_PIVOT_SAR_SWITCH = 6, XFIMA_PIVOT_BOUNDARY_SWITCH = 7, }; bool IsXValid(ENUM_XFIMA_PIVOTS value) { // bool result = false; // result = value != XFIMA_PIVOT_NONE; // return result; } string ToXString(ENUM_XFIMA_PIVOTS value) { // string result = NULL; // if (!IsXValid(value)) { return result; } // switch (value) { // case XFIMA_PIVOT_NONE: result = "NONE"; break; // case XFIMA_PIVOT_PV: result = "XPV"; break; // case XFIMA_PIVOT_ATR: result = "XATR"; break; // case XFIMA_PIVOT_ZIGZAG: result = "XZGP"; break; // case XFIMA_PIVOT_MA_CROSS: result = "XMACRS"; break; // case XFIMA_PIVOT_HK_SWITCH: result = "XHKSWCH"; break; // case XFIMA_PIVOT_SAR_SWITCH: result = "XSARSWCH"; break; // case XFIMA_PIVOT_BOUNDARY_SWITCH: result = "XBNDSWCH"; break; } // return result; } ENUM_XFIMA_PIVOTS ToXFIMAPivots(string value) { // ENUM_XFIMA_PIVOTS result = XFIMA_PIVOT_NONE; // if (!IsXValid(value)) { return result; } // if (value == ToXString(XFIMA_PIVOT_NONE)) { result = XFIMA_PIVOT_NONE; } else if (value == ToXString(XFIMA_PIVOT_PV)) { result = XFIMA_PIVOT_PV; } else if (value == ToXString(XFIMA_PIVOT_ATR)) { result = XFIMA_PIVOT_ATR; } else if (value == ToXString(XFIMA_PIVOT_ZIGZAG)) { result = XFIMA_PIVOT_ZIGZAG; } else if (value == ToXString(XFIMA_PIVOT_MA_CROSS)) { result = XFIMA_PIVOT_MA_CROSS; } else if (value == ToXString(XFIMA_PIVOT_HK_SWITCH)) { result = XFIMA_PIVOT_HK_SWITCH; } else if (value == ToXString(XFIMA_PIVOT_SAR_SWITCH)) { result = XFIMA_PIVOT_SAR_SWITCH; } else if (value == ToXString(XFIMA_PIVOT_BOUNDARY_SWITCH)) { result = XFIMA_PIVOT_BOUNDARY_SWITCH; } // return result; } // // Implementation ... class XCXFIMAPOIDetector : public XCMarketPatternDetector { // // Public ... public: // // Props ... // string symbol; ENUM_TIMEFRAMES period; // XCBarAnalyser *barAnalyser; // Bar Analyser ... XCXFIMAHelper *fimaHelper; // XFIMA Helper ... XCXFIMAHelperParser *fimaParser; // XFIMA Helper Parser ... // // Constructor ... XCXFIMAPOIDetector( XCXFIMAHelper *_fimaHelper, XCXFIMAHelperParser *_fimaParser // ) : XCMarketPatternDetector() { // barAnalyser = new XCBarAnalyser(); fimaHelper = _fimaHelper; fimaParser = _fimaParser; // symbol = fimaHelper.GetSymbol(); period = fimaHelper.GetPeriod(); } // // Deconstructor ... ~XCXFIMAPOIDetector() { Destroy(); } // // Actions and Tools ... // // Detectors ... // // XPV ... /** * Check Conditions to Detecte XPV based Consolidation Zone ... * * @param zone: XBoxZone, reference to holds detected zone ... * @param barIndex: int, Specified Bar Index ... * @param forcePVBreak: bool, force to has PV Side Break ... * @param forceHasSarSwitch: bool, force to has SAR Switche ... * * @return ( bool ) */ bool DetectPVConsolidationZone( XBoxZone &zone, int barIndex = 0, bool forcePVBreak = false, bool forceHasSarSwitch = false // ) { // bool result = false; // // Prepare ... zone.Clean(); // // Normalize ... barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... result = fimaParser.IsValid(); if (!result) { return result; } // // Do ... // bool isPeakSame = fimaParser.IsPeakSame(barIndex); bool isValeSame = fimaParser.IsValeSame(barIndex); result = !(isPeakSame && isValeSame); if (!result) { return result; } // double iPeak = EMPTY_VALUE; double iVale = EMPTY_VALUE; // int idx = barIndex; bool canLookup = true; while (canLookup) { // idx++; isPeakSame = fimaParser.IsPeakSame(idx); isValeSame = fimaParser.IsValeSame(idx); result = isPeakSame && isValeSame; if (!result) { // zone.from = GetBarTime(symbol, period, idx); break; } // if (idx == barIndex + 1) { // zone.to = GetBarTime( symbol, period, idx // ); } // zone.from = GetBarTime( symbol, period, idx // ); // iPeak = fimaHelper.GetPeak(idx); iVale = fimaHelper.GetVale(idx); // zone.lower = !NotEmptyZero(zone.lower) ? iVale : MathMin(zone.lower, iVale); // zone.upper = !NotEmptyZero(zone.upper) ? iPeak : MathMax(zone.upper, iPeak); } // // Validating Zone Params ... result = // IsXValid(zone.to) && IsXValid(zone.from) && zone.from < zone.to && // NotEmptyZero(zone.lower) && NotEmptyZero(zone.upper) && zone.upper > zone.lower // ; // // Prepare Zone ... if (result) { // iPeak = fimaHelper.GetPeak(barIndex); iVale = fimaHelper.GetVale(barIndex); bool isPeakOverLast = fimaParser.IsPeakOverLast(barIndex); bool isValeUnderLast = fimaParser.IsValeUnderLast(barIndex); bool isValeBreak = iVale < zone.lower; bool isPeakBreak = iPeak > zone.upper; bool isPVBreak = isPeakBreak || isValeBreak; // zone.at = GetBarTime(symbol, period, barIndex); zone.symbol = symbol; zone.period = period; zone.dir = (isPeakOverLast && !isValeUnderLast && isPVBreak) ? X_DIRECTION_BULLISH : (isValeUnderLast && !isPeakOverLast && isPVBreak) ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; zone.type = ToXString(X_BAR_PATTERN_CONSOLIDATION); // // Refine Zone Upper and Lower ... if (zone.IsValid()) { // XOHCL iBar; int zoneLoopback = zone.FromIndex() - zone.ToIndex(); result = zone.ToBar(iBar) && IsValidSize(zoneLoopback); if (result) { // double zoneLL = iBar.FindLowest(zoneLoopback, MODE_LOW); double zoneHH = iBar.FindHighest(zoneLoopback, MODE_HIGH); result = NotEmptyZero(zoneLL) && NotEmptyZero(zoneHH); if (result) { // zone.lower = zone.lower == zoneLL ? zone.lower : MathMax(zone.lower, zoneLL); // zone.upper = zone.upper == zoneHH ? zone.upper : MathMin(zone.upper, zoneHH); } } // iBar.Clean(); } // // Validate ... result = zone.IsValid(); } // // Validate Zones From ... if (result) { // int idx = zone.FromIndex(); // iPeak = fimaHelper.GetPeak(idx); iVale = fimaHelper.GetVale(idx); // bool isValeOverLast = fimaParser.IsValeOverLast(idx); bool isPeakUnderLast = fimaParser.IsPeakUnderLast(idx); // result = result && (zone.IsBullish() ? !isPeakUnderLast : zone.IsBearish() ? !isValeOverLast : false); } // // Apply Forces ... // // PV Break ... // Peak or Vale must Breaked at Bar ... if (result && forcePVBreak) { // bool isPVBreaked = (zone.IsBullish() && fimaParser.IsPeakOverLast(barIndex)) || (zone.IsBearish() && fimaParser.IsValeUnderLast(barIndex)); // result = result && isPVBreaked; } // // Other Loop based Forces ... if (result && (forceHasSarSwitch)) { // bool hasSarSwitch = false; // int start = zone.ToIndex(); int end = zone.FromIndex(); for (int i = start; i <= end; i++) { // // Check Sar Switches ... if (forceHasSarSwitch && !hasSarSwitch) { // hasSarSwitch = zone.IsBullish() ? fimaParser.IsSARSwitchedToBullish(i) : fimaParser.IsSARSwitchedToBearish(i); } } // // Validate Forces ... if (forceHasSarSwitch) { // result = result && hasSarSwitch; } } // // Cleanup ... if (!result) { zone.Clean(); } // return result; } /** * Detect XPV Zone ... * * @param zone: XBoxZone, reference to Holds detected Zone ... * @param barIndex: int, Specified Bar Index ... * * @return ( bool ) */ bool DetectXPVZone( XBoxZone &zone, int barIndex = 0 // ) { // bool result = false; // // Prepare ... zone.Clean(); // // Normalize ... barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... result = fimaParser.IsValid(); if (!result) { return result; } // // Do ... // XOHCL bar; result = bar.Init(fimaParser.symbol, fimaParser.period, barIndex); if (!result) { // bar.Clean(); return result; } // // Vale ... bool isValeOverLast = fimaParser.IsValeOverLast(barIndex); bool isValeUnderLast = fimaParser.IsValeUnderLast(barIndex); bool isNewVale = isValeOverLast || isValeUnderLast; // // Peak ... bool isPeakOverLast = fimaParser.IsPeakOverLast(barIndex); bool isPeakUnderLast = fimaParser.IsPeakUnderLast(barIndex); bool isNewPeak = isPeakOverLast || isPeakUnderLast; // // Detect new Peak or Vale ... result = isNewVale || isNewPeak; // // Count Same Peaks and Same Vales from Index of Prev ... int pIDX = barIndex + 1; int samePeaks = fimaParser.CountSamePeaks(pIDX); int sameVales = fimaParser.CountSameVales(pIDX); result = result && IsValidSize(samePeaks) && IsValidSize(sameVales); // // Try to Evaluate Zone ... int peaksStartIndex = pIDX + samePeaks; int valesStartIndex = pIDX + sameVales; int fromIDX = MathMin(peaksStartIndex, valesStartIndex); if (result) { // // Assign Zone Symbol / Period ... zone.symbol = fimaParser.symbol; zone.period = fimaParser.period; // // Calculate Zone Times ... zone.to = GetBarTime( zone.symbol, zone.period, barIndex // ); zone.from = GetBarTime( zone.symbol, zone.period, fromIDX // ); zone.at = zone.to; // // Calculate Upper and Lower ... zone.upper = fimaHelper.GetPeak(fromIDX); zone.lower = fimaHelper.GetVale(fromIDX); // // Validate Zone Upper and Lower ... for (int i = pIDX; i <= fromIDX; i++) { // if (isValeUnderLast) { zone.lower = MathMin(zone.lower, fimaHelper.GetVale(i)); } // if (isPeakOverLast) { zone.upper = MathMax(zone.upper, fimaHelper.GetPeak(i)); } } // // Calculate Zone Direction ... zone.dir = isValeOverLast ? X_DIRECTION_BULLISH : isValeUnderLast ? X_DIRECTION_BEARISH : isPeakOverLast ? X_DIRECTION_BULLISH : isPeakUnderLast ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; // // Refine Zone Upper / Lower based on Direction and Bars ... // // Detect Highest High / Lowest Low ... double ll = bar.FindLowest(fromIDX - barIndex, MODE_LOW); double hh = bar.FindHighest(fromIDX - barIndex, MODE_HIGH); // if (isNewVale) { zone.upper = MathMin(zone.upper, hh); } // if (isNewPeak) { zone.lower = MathMax(zone.lower, ll); } // // Set Zone Type ... zone.type = ToXString(XFIMA_PIVOT_PV); // // Summarize result ... result = zone.IsValid(); } // result = zone.IsValid(); // // Cleanup ... if (!result) { zone.Clean(); } bar.Clean(); // return result; } // // Analysors ... /** * Analyse Market ... * * @param structure: XFIMAMarketStructure, reference to holds Market Strucutre ... * @param config: XFIMAMarketStructureConfig, reference to Provide Structure Analyse Config ... * @param barIndex: int, Specified Bar Index ... * * @return ( bool ) */ bool AnalyseMarket( XFIMAMarketStructure &structure, XFIMAMarketStructureConfig &config, int barIndex = 0 // ) { // bool result = false; // // Prepare ... structure.Clean(); // // Normalize ... barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... result = fimaParser.IsValid(); if (!result) { return result; } // // Do ... int idx = -1; XOHCL tmpBar; datetime fromTime = NULL; XPatternAnalysis tmpBarAnalysis; // // Initialize Indexed Bar ... result = structure.bar.Init(symbol, period, barIndex); // // Analyse Bar Patterns ... if (result) { // result = AnalyseBarPatterns( structure.bar, structure.barAnalysis, config.barsAnalysisConfig // ); } // // Analyse Pivots ... // // XPV ... CollectPVPivots( structure.pvPivots, barIndex, config.requiredPivots, config.loopback // ); // // XMA ... CollectMAPivots( structure.maPivots, barIndex, config.requiredPivots, config.loopback // ); // // XZG ... CollectZGPivots( structure.zgPivots, barIndex, config.requiredPivots, config.loopback // ); // // XHK ... CollectHKPivots( structure.hkPivots, barIndex, config.requiredPivots, config.loopback // ); // // XSAR ... CollectSARPivots( structure.sarPivots, barIndex, config.requiredPivots, config.loopback // ); // // XPV Analysis ... if (result && config.analysePVPivots) { // result = HasChild(structure.pvPivots); // // Check Oldest ... idx = GetOldest(structure.pvPivots); result = IsValidIndex(idx); if (result) { // fromTime = !IsXValid(fromTime) ? structure.pvPivots[idx].time : MathMin(fromTime, structure.pvPivots[idx].time); } // // Initialize Analysis ... if (result) { // result = structure.pvAnalysis.Init( ToXString(XFIMA_PIVOT_PV), symbol, period, structure.pvPivots // ); } } // // XZG Analysis ... if (result && config.analyseZGPivots) { // result = HasChild(structure.zgPivots); // // Check Oldest ... idx = GetOldest(structure.zgPivots); result = IsValidIndex(idx); if (result) { // fromTime = !IsXValid(fromTime) ? structure.zgPivots[idx].time : MathMin(fromTime, structure.zgPivots[idx].time); } // // Initialize Analysis ... if (result) { // result = structure.zgAnalysis.Init( ToXString(XFIMA_PIVOT_ZIGZAG), symbol, period, structure.zgPivots // ); } } // // XHK Analysis ... if (result && config.analyseHKPivots) { // result = HasChild(structure.hkPivots); // // Check Oldest ... idx = GetOldest(structure.hkPivots); result = IsValidIndex(idx); if (result) { // fromTime = !IsXValid(fromTime) ? structure.hkPivots[idx].time : MathMin(fromTime, structure.hkPivots[idx].time); } // // Initialize Analysis ... if (result) { // result = structure.hkAnalysis.Init( ToXString(XFIMA_PIVOT_HK_SWITCH), symbol, period, structure.hkPivots // ); } } // // XMA Analysis ... if (result && config.analyseMAPivots) { result = HasChild(structure.maPivots); // // Check Oldest ... idx = GetOldest(structure.maPivots); result = IsValidIndex(idx); if (result) { // fromTime = !IsXValid(fromTime) ? structure.maPivots[idx].time : MathMin(fromTime, structure.maPivots[idx].time); } // // Initialize Analysis ... if (result) { // result = structure.maAnalysis.Init( ToXString(XFIMA_PIVOT_MA_CROSS), symbol, period, structure.maPivots // ); } } // // XSAR Analysis ... if (result && config.analyseSARPivots) { // result = HasChild(structure.sarPivots); // // Check Oldest ... idx = GetOldest(structure.sarPivots); result = IsValidIndex(idx); if (result) { // fromTime = !IsXValid(fromTime) ? structure.sarPivots[idx].time : MathMin(fromTime, structure.sarPivots[idx].time); } // // Initialize Analysis ... if (result) { // result = structure.sarAnalysis.Init( ToXString(XFIMA_PIVOT_SAR_SWITCH), symbol, period, structure.sarPivots // ); } } // // Order Flow ... if (result && config.detectOrderFlow) { // HasOrderFlow( structure.bar, structure.orderFlowDir, structure.orderFlow, config.orderFlowValidation, config.orderFlowUseOB, config.orderFlowUseFVG, config.orderFlowUseSupportAndResistance, config.barsAnalysisConfig.supportAndResistanceLoopbackLength, config.barsAnalysisConfig.supportAndResistanceValidationLength, config.loopback // ); } // // Analyse Bar Patterns ... if (result && config.analyseBarPatterns) { // // Collect Pivots ... XPivot tmps[]; Copy(structure.pvPivots, tmps, false); Copy(structure.zgPivots, tmps, false); Copy(structure.hkPivots, tmps, false); Copy(structure.maPivots, tmps, false); Copy(structure.sarPivots, tmps, false); // XPivot sames[]; XPivot tmpPivot; int samesCount = 0; while (HasChild(tmps)) { // tmpPivot.Clean(); tmpPivot = tmps[0]; ArrayRemove(tmps, 0, 1); // XClean(sames); samesCount = ExtractSameTimePivots(tmpPivot, sames, tmps); if (HasChild(sames)) { // tmpBar.Clean(); if (sames[0].GetBar(tmpBar)) { // tmpBarAnalysis.Clean(); if (AnalyseBarPatterns(tmpBar, tmpBarAnalysis, config.barsAnalysisConfig)) { // AddRef(tmpBarAnalysis, structure.barsAnalysis); } } // Removes(sames, tmps); } } // // Bars Analysis Exists ... result = HasChild(structure.barsAnalysis); // // Cleanup ... XClean(tmps); XClean(sames); tmpPivot.Clean(); } // // Cleanup ... if (!result) { structure.Clean(); } // return result; } // // Collectors ... /** * Collect ZigZag Pivots ... * * @param pivots: XPivot, reference collection to holds Detected Pivots ... * @param barIndex: int, Specified Start Bar Index ... * @param count: int, Specified number of required Pivots ... * @param loopback: int, Max Allowed Loopback length for Detection ... * * @return ( int ) */ int CollectZGPivots( XPivot &pivots[], int barIndex = 0, int count = 50, int loopback = 500 // ) { // int result = 0; // // Prepare ... XClean(pivots); // // Normalize ... count = NormalizeInt(count, 0); loopback = NormalizeInt(loopback, 50); barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... bool has = fimaParser.IsValid(); if (!has) { return result; } // // Do ... XOHCL bar; XPivot pivot; int start = barIndex; bool isBullish = false; bool isBearish = false; int end = start + loopback; ENUM_X_DIRECTION dir = X_DIRECTION_NONE; for (int i = start; i < end; i++) { // isBullish = fimaParser.IsZGLow(i); isBearish = fimaParser.IsZGHigh(i); // has = isBullish || isBearish; if (has) { // // Specified Direction ... dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // // Initialize Indexed Bar ... // Validate it, and Converts it to Pivot ... bar.Clean(); has = bar.Init(symbol, period, i); has = has && ToPivot( bar, pivot, dir, ToXString(XFIMA_PIVOT_ZIGZAG) // ); if (has) { // // Add Detected Pivot ... AddIfNotExists(pivot, pivots); } // has = count <= 0 ? false : ArraySize(pivots) >= count; if (has) { break; } } // // Cleanup ... bar.Clean(); pivot.Clean(); } // result = ArraySize(pivots); // // Cleanup ... bar.Clean(); pivot.Clean(); // return result; } /** * Collect MA Pivots ... * * @param pivots: XPivot, reference collection to holds Detected Pivots ... * @param barIndex: int, Specified Start Bar Index ... * @param count: int, Specified number of required Pivots ... * @param loopback: int, Max Allowed Loopback length for Detection ... * * @return ( int ) */ int CollectMAPivots( XPivot &pivots[], int barIndex = 0, int count = 50, int loopback = 500 // ) { // int result = 0; // // Prepare ... XClean(pivots); // // Normalize ... count = NormalizeInt(count, 0); loopback = NormalizeInt(loopback, 50); barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... bool has = fimaParser.IsValid(); if (!has) { return result; } // // Do ... XOHCL bar; XPivot pivot; int start = barIndex; bool isBullish = false; bool isBearish = false; int end = start + loopback; ENUM_X_DIRECTION dir = X_DIRECTION_NONE; for (int i = start; i < end; i++) { // isBullish = fimaParser.IsMAFastCrossedOverSlow(i); isBearish = fimaParser.IsMAFastCrossedUnderSlow(i); // has = isBullish || isBearish; if (has) { // // Specified Direction ... dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // // Initialize Indexed Bar ... // Validate it, and Converts it to Pivot ... bar.Clean(); has = bar.Init(symbol, period, i); has = has && ToPivot( bar, pivot, dir, ToXString(XFIMA_PIVOT_MA_CROSS) // ); if (has) { // // Replace MA Values ... pivot.value = isBullish ? fimaHelper.GetMASlow(barIndex) : fimaHelper.GetMAFast(barIndex); // // Add Detected Pivot ... AddIfNotExists(pivot, pivots); } // has = count <= 0 ? false : ArraySize(pivots) >= count; if (has) { break; } } // // Cleanup ... bar.Clean(); pivot.Clean(); } // result = ArraySize(pivots); // // Cleanup ... bar.Clean(); pivot.Clean(); // return result; } /** * Collect HK Pivots ... * * @param pivots: XPivot, reference collection to holds Detected Pivots ... * @param barIndex: int, Specified Start Bar Index ... * @param count: int, Specified number of required Pivots ... * @param loopback: int, Max Allowed Loopback length for Detection ... * * @return ( int ) */ int CollectHKPivots( XPivot &pivots[], int barIndex = 0, int count = 50, int loopback = 500 // ) { // int result = 0; // // Prepare ... XClean(pivots); // // Normalize ... count = NormalizeInt(count, 0); loopback = NormalizeInt(loopback, 50); barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... bool has = fimaParser.IsValid(); if (!has) { return result; } // // Do ... XOHCL bar; XPivot pivot; int start = barIndex; bool isBullish = false; bool isBearish = false; int end = start + loopback; ENUM_X_DIRECTION dir = X_DIRECTION_NONE; for (int i = start; i < end; i++) { // isBullish = fimaParser.IsHKSwitchedToBullish(i); isBearish = fimaParser.IsHKSwitchedToBearish(i); // has = isBullish || isBearish; if (has) { // // Specified Direction ... dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // // Initialize Indexed Bar ... // Validate it, and Converts it to Pivot ... bar.Clean(); has = bar.Init(symbol, period, i); has = has && ToPivot( bar, pivot, dir, ToXString(XFIMA_PIVOT_HK_SWITCH) // ); if (has) { // // Replace Value ... pivot.value = isBullish ? fimaHelper.GetHKLow(i) : fimaHelper.GetHKHigh(i); // // Add Detected Pivot ... AddIfNotExists(pivot, pivots); } // has = count <= 0 ? false : ArraySize(pivots) >= count; if (has) { break; } } // // Cleanup ... bar.Clean(); pivot.Clean(); } // result = ArraySize(pivots); // // Cleanup ... bar.Clean(); pivot.Clean(); // return result; } /** * Collect PV Pivots ... * * @param pivots: XPivot, reference collection to holds Detected Pivots ... * @param barIndex: int, Specified Start Bar Index ... * @param count: int, Specified number of required Pivots ... * @param loopback: int, Max Allowed Loopback length for Detection ... * * @return ( int ) */ int CollectPVPivots( XPivot &pivots[], int barIndex = 0, int count = 50, int loopback = 500 // ) { // int result = 0; // // Prepare ... XClean(pivots); // // Normalize ... count = NormalizeInt(count, 0); loopback = NormalizeInt(loopback, 50); barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... bool has = fimaParser.IsValid(); if (!has) { return result; } // // Do ... XOHCL bar; XPivot pivot; int start = barIndex; bool isBullish = false; bool isBearish = false; int end = start + loopback; ENUM_X_DIRECTION dir = X_DIRECTION_NONE; for (int i = start; i < end; i++) { // isBullish = fimaParser.IsPeakOverLast(i); isBearish = fimaParser.IsValeUnderLast(i); // has = isBullish || isBearish; if (has) { // // Specified Direction ... dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // // Initialize Indexed Bar ... // Validate it, and Converts it to Pivot ... bar.Clean(); has = bar.Init(symbol, period, i); has = has && ToPivot( bar, pivot, dir, ToXString(XFIMA_PIVOT_PV) // ); if (has) { // // Replace Value ... pivot.value = isBullish ? fimaHelper.GetHKLow(i) : fimaHelper.GetHKHigh(i); // // Add Detected Pivot ... AddIfNotExists(pivot, pivots); } // has = count <= 0 ? false : ArraySize(pivots) >= count; if (has) { break; } } // // Cleanup ... bar.Clean(); pivot.Clean(); } // result = ArraySize(pivots); // // Cleanup ... bar.Clean(); pivot.Clean(); // return result; } /** * Collect SAR Pivots ... * * @param pivots: XPivot, reference collection to holds Detected Pivots ... * @param barIndex: int, Specified Start Bar Index ... * @param count: int, Specified number of required Pivots ... * @param loopback: int, Max Allowed Loopback length for Detection ... * * @return ( int ) */ int CollectSARPivots( XPivot &pivots[], int barIndex = 0, int count = 50, int loopback = 500 // ) { // int result = 0; // // Prepare ... XClean(pivots); // // Normalize ... count = NormalizeInt(count, 0); loopback = NormalizeInt(loopback, 50); barIndex = fimaParser.NormalizeBarIndex(barIndex); // // Validate ... bool has = fimaParser.IsValid(); if (!has) { return result; } // // Do ... XOHCL bar; XPivot pivot; int start = barIndex; bool isBullish = false; bool isBearish = false; int end = start + loopback; ENUM_X_DIRECTION dir = X_DIRECTION_NONE; for (int i = start; i < end; i++) { // isBullish = fimaParser.IsSARSwitchedToBullish(i); isBearish = fimaParser.IsSARSwitchedToBearish(i); // has = isBullish || isBearish; if (has) { // // Specified Direction ... dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // // Initialize Indexed Bar ... // Validate it, and Converts it to Pivot ... bar.Clean(); has = bar.Init(symbol, period, i); has = has && ToPivot( bar, pivot, dir, ToXString(XFIMA_PIVOT_SAR_SWITCH) // ); if (has) { // // Add Detected Pivot ... AddIfNotExists(pivot, pivots); } // has = count <= 0 ? false : ArraySize(pivots) >= count; if (has) { break; } } // // Cleanup ... bar.Clean(); pivot.Clean(); } // result = ArraySize(pivots); // // Cleanup ... bar.Clean(); pivot.Clean(); // return result; } /** * Collect Specified ZOnes Boundary Min / Max Values ... * * @param uppers: XPivot, collection reference to holds Peaks of Zone's Boundary ... * @param lowers: XPivot, collection reference to holds Vales of Zone's Boundary ... * @param zone: XBoxZone, reference to Provide Specified Zone for Boundary Detection ... * * @return ( int ) */ int CollectZonesBoundary( XPivot &uppers[], XPivot &lowers[], XBoxZone &zone // ) { // int result = 0; // // Prepare ... XClean(uppers); XClean(lowers); // // Validate ... bool has = zone.IsValid() && fimaParser.IsValid(); if (!has) { return result; } // double iUpper; double iLower; datetime iTime; XPivot upperPivot; XPivot lowerPivot; int start = zone.ToIndex(); int end = zone.FromIndex(); for (int i = start; i <= end; i++) { // iUpper = fimaParser.GetBoundaryMax(i); iLower = fimaParser.GetBoundaryMin(i); iTime = GetBarTime(zone.symbol, zone.period, i); // has = IsXValid(iTime) && NotEmptyZero(iUpper) && NotEmptyZero(iLower); if (has) { // // Upper Pivot ... upperPivot.Clean(); has = upperPivot.Init( iUpper, iTime, zone.symbol, zone.dir, zone.period, X_PIVOT_TYPE_PEAK // ); if (has) { upperPivot.prefix = "XBNDUP"; } // // Lower Pivot ... lowerPivot.Clean(); has = lowerPivot.Init( iLower, iTime, zone.symbol, zone.dir, zone.period, X_PIVOT_TYPE_VALE // ); if (has) { lowerPivot.prefix = "XBNDLO"; } // has = upperPivot.IsValid() && lowerPivot.IsValid(); if (has) { // AddRef(upperPivot, uppers); AddRef(lowerPivot, lowers); } } } // result = MathMin(ArraySize(uppers), ArraySize(lowers)); // // Cleanup ... upperPivot.Clean(); lowerPivot.Clean(); // return result; } /** * Check Zone Has Boundary Trend or not ... * * @param zone: XBoxZOne, reference to Specified Zone for Checking Trend ... * @param trend: XTrend, reference to holds Detected Trend Result ... * @param basedOnToTime: bool, if set true, do based on to and it's prev bar ... * * @return ( bool ) */ bool HasBoundaryTrend( XBoxZone &zone, XTrend &trend, bool basedOnToTime = false // ) { // bool result = false; // // Prepare ... trend.Clean(); // // Validate ... result = zone.IsValid() && fimaParser.IsValid(); if (!result) { return result; } // // Do ... // int toIDX = zone.ToIndex(); int fromIDX = basedOnToTime ? toIDX + 1 : zone.FromIndex(); datetime fromTime = GetBarTime(zone.symbol, zone.period, fromIDX); // double toMin = fimaParser.GetBoundaryMin(toIDX); double toMax = fimaParser.GetBoundaryMax(toIDX); // double fromMin = fimaParser.GetBoundaryMin(fromIDX); double fromMax = fimaParser.GetBoundaryMax(fromIDX); // bool isMinBullish = fromMin < toMin; bool isMaxBullish = fromMax < toMax; bool isBullish = isMinBullish && isMaxBullish; // bool isMinBearish = fromMin > toMin; bool isMaxBearish = fromMax > toMax; bool isBearish = isMinBearish && isMaxBearish; // result = isBullish || isBearish; if (result) { // result = trend.Init( zone.symbol, zone.period, TimeCurrent(), isBullish ? fromMin : fromMax, fromTime, isBullish ? toMin : toMax, zone.to // ); } // // Validate Result ... result = trend.IsValid() && trend.HasTrend(); if (!result) { trend.Clean(); } // return result; } /** * Get Cycle Based PV Zone ... * * @param bar: XOHCL, reference to Specified Zone ... * @param zone: XBoxZone, reference to holds PV Zone ... * * @return ( bool ) */ bool GetSCZone( XOHCL &bar, XBoxZone &zone // ) { // bool result = false; // // Prepare ... zone.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // int barIndex = bar.Index(); // double upper = fimaHelper.GetSHH(barIndex); double lower = fimaHelper.GetSLL(barIndex); double pHH = fimaHelper.GetSHH(barIndex + 1); double pLL = fimaHelper.GetSLL(barIndex + 1); int sameLLs = fimaParser.CountSCSameLLs(barIndex); int sameHHs = fimaParser.CountSCSameHHs(barIndex); int fromIDX = barIndex + MathMax(sameLLs, sameHHs); // zone.to = bar.time; zone.at = bar.time; zone.upper = upper; zone.lower = lower; zone.symbol = bar.symbol; zone.period = bar.period; zone.dir = (upper > pHH || lower > pLL) ? X_DIRECTION_BULLISH : (upper < pHH || lower < pLL) ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; zone.type = ToXString(XFIMA_PIVOT_PV) + "_SC"; zone.from = GetBarTime(bar.symbol, bar.period, fromIDX); // result = zone.IsValid(); if (!result) { zone.Clean(); } // return result; } /** * Get Cycle Based PV Zone ... * * @param bar: XOHCL, reference to Specified Zone ... * @param zone: XBoxZone, reference to holds PV Zone ... * * @return ( bool ) */ bool GetMCZone( XOHCL &bar, XBoxZone &zone // ) { // bool result = false; // // Prepare ... zone.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // int barIndex = bar.Index(); // double upper = fimaHelper.GetMHH(barIndex); double lower = fimaHelper.GetMLL(barIndex); double pHH = fimaHelper.GetMHH(barIndex + 1); double pLL = fimaHelper.GetMLL(barIndex + 1); int sameLLs = fimaParser.CountMCSameLLs(barIndex); int sameHHs = fimaParser.CountMCSameHHs(barIndex); int fromIDX = barIndex + MathMax(sameLLs, sameHHs); // zone.to = bar.time; zone.at = bar.time; zone.upper = upper; zone.lower = lower; zone.symbol = bar.symbol; zone.period = bar.period; zone.dir = (upper > pHH || lower > pLL) ? X_DIRECTION_BULLISH : (upper < pHH || lower < pLL) ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; zone.type = ToXString(XFIMA_PIVOT_PV) + "_MC"; zone.from = GetBarTime(bar.symbol, bar.period, fromIDX); // result = zone.IsValid(); if (!result) { zone.Clean(); } // return result; } /** * Get Cycle Based PV Zone ... * * @param bar: XOHCL, reference to Specified Zone ... * @param zone: XBoxZone, reference to holds PV Zone ... * * @return ( bool ) */ bool GetLCZone( XOHCL &bar, XBoxZone &zone // ) { // bool result = false; // // Prepare ... zone.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // int barIndex = bar.Index(); // double upper = fimaHelper.GetLHH(barIndex); double lower = fimaHelper.GetLLL(barIndex); double pHH = fimaHelper.GetLHH(barIndex + 1); double pLL = fimaHelper.GetLLL(barIndex + 1); int sameLLs = fimaParser.CountLCSameLLs(barIndex); int sameHHs = fimaParser.CountLCSameHHs(barIndex); int fromIDX = barIndex + MathMax(sameLLs, sameHHs); // zone.to = bar.time; zone.at = bar.time; zone.upper = upper; zone.lower = lower; zone.symbol = bar.symbol; zone.period = bar.period; zone.dir = (upper > pHH || lower > pLL) ? X_DIRECTION_BULLISH : (upper < pHH || lower < pLL) ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; zone.type = ToXString(XFIMA_PIVOT_PV) + "_LC"; zone.from = GetBarTime(bar.symbol, bar.period, fromIDX); // result = zone.IsValid(); if (!result) { zone.Clean(); } // return result; } /** * Get Cycle Based PV Zone ... * * @param bar: XOHCL, reference to Specified Zone ... * @param zone: XBoxZone, reference to holds PV Zone ... * * @return ( bool ) */ bool GetHCZone( XOHCL &bar, XBoxZone &zone // ) { // bool result = false; // // Prepare ... zone.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // int barIndex = bar.Index(); // double upper = fimaHelper.GetHHH(barIndex); double lower = fimaHelper.GetHLL(barIndex); double pHH = fimaHelper.GetHHH(barIndex + 1); double pLL = fimaHelper.GetHLL(barIndex + 1); int sameLLs = fimaParser.CountHCSameLLs(barIndex); int sameHHs = fimaParser.CountHCSameHHs(barIndex); int fromIDX = barIndex + MathMax(sameLLs, sameHHs); // zone.to = bar.time; zone.at = bar.time; zone.upper = upper; zone.lower = lower; zone.symbol = bar.symbol; zone.period = bar.period; zone.dir = (upper > pHH || lower > pLL) ? X_DIRECTION_BULLISH : (upper < pHH || lower < pLL) ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; zone.type = ToXString(XFIMA_PIVOT_PV) + "_HC"; zone.from = GetBarTime(bar.symbol, bar.period, fromIDX); // result = zone.IsValid(); if (!result) { zone.Clean(); } // return result; } /** * Check Specified Bar is Rejected Specified XFIMA Values or not ... * * @param bar: XOHCL, reference to Specified Bar ... * @param rejecteds: double, collection reference to holds Rejected Values ... * @param forDir: ENUM_X_DIRECTION, Specified required Rejection Direction ... * @param bullishRejectUpperPriceType: ENUM_X_PRICE, Specified Bullish Rejection Upper Price Type ... * @param bullishRejectLowerPriceType: ENUM_X_PRICE, Specified Bullish Rejection Lower Price Type ... * @param bearishRejectUpperPriceType: ENUM_X_PRICE, Specified Bearish Rejection Upper Price Type ... * @param bearishRejectLowerPriceType: ENUM_X_PRICE, Specified Bearish Rejection Lower Price Type ... * @param ignoreBoundary: bool, ignoring XFIMA Max and Min Values Rejections ... * * @return ( int ) */ int IsRejectXFIMA( XOHCL &bar, double &rejecteds[], ENUM_X_DIRECTION forDir, ENUM_X_PRICE bullishRejectUpperPriceType = X_PRICE_DOWN, ENUM_X_PRICE bullishRejectLowerPriceType = X_PRICE_LOW, ENUM_X_PRICE bearishRejectUpperPriceType = X_PRICE_HIGH, ENUM_X_PRICE bearishRejectLowerPriceType = X_PRICE_UP, bool ignoreBoundary = true // ) { // int result = 0; // // Prepare ... XClean(rejecteds); // // Validate ... bool has = bar.IsValid() && fimaParser.IsValid() && HasDirection(forDir) && IsXValid(bullishRejectLowerPriceType) && IsXValid(bullishRejectUpperPriceType) && IsXValid(bearishRejectUpperPriceType) && IsXValid(bearishRejectLowerPriceType); if (!has) { return result; } // int pBarIndex = bar.Index() + 1; bool isBullish = IsXBullish(forDir); // // Reading Values ... double values[]; int count = fimaParser.ReadXFIMAValues(values, pBarIndex); has = HasChild(values); // // Detect Rejected Prices ... if (has) { // double min = GetMin(values); double max = GetMax(values); // for (int i = 0; i < count; i++) { // // Detect Rejection ... has = isBullish ? (bar.GetPrice(bullishRejectLowerPriceType) < values[i] && bar.GetPrice(bullishRejectUpperPriceType) > values[i]) : (bar.GetPrice(bearishRejectUpperPriceType) > values[i] && bar.GetPrice(bearishRejectLowerPriceType) < values[i]); if (has) { // // Validate Rejection ... if (ignoreBoundary) { // has = has && (values[i] != min && values[i] != max); } // // Add Result ... if (has) { Add(values[i], rejecteds); } } } } // result = ArraySize(rejecteds); // return result; } // // Others ... /** * Destroy ... */ void Destroy() { // delete barAnalyser; ZeroMemory(barAnalyser); // ZeroMemory(fimaHelper); ZeroMemory(fimaParser); } // // Testers ... // // Protected ... protected: // // Props ... // // Private ... private: // // }; //