/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCXFIMASignaller ... // Description: XFIMA Signaller 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 Signaller Class" #property strict // // Imports ... #include "../../Classes/x-saherelm.x-signaller.class.mq5" #include "../../Helpers/x-saherelm.xfima.helper.mq5" #include "../Classes/x-saherelm.xfima.parser.class.mq5" #include "../Classes/x-saherelm.xfima.x-poi.detector.class.mq5" #include "../Classes/x-saherelm.xfima.x-poi.drawer.class.mq5" // // Implementation ... // // Base XFIMA base Signaller ... class XCXFIMABaseSignaller : public XCBaseSignaller { // // Public ... public: // // Props ... // CArrayObj drawnObjects; // Drawing Objects Holder ... XFIMAInputs fimaInputs; // XFIMA Inputs ... XCXFIMAHelper *fimaHelper; // XFIMA Indicator Helper ... XCXFIMAPOIDrawer *poiDrawer; // XFIMA POI Drawer ... XCXFIMAHelperParser *fimaParser; // XFIMA Helper Parser ... XCXFIMAPOIDetector *poiDetector; // XFIMA POI Detector ... XFIMAMarketStructureConfig structureConfig; // XFIMA Market Structure Detector Config ... XFIMAMarketStructureDrawerConfig structureDrawConfig; // XFIMA Market Structure Draw Config ... // // Constructor ... XCXFIMABaseSignaller( string _name, // Name ... string _symbol, // Symbol ... ENUM_TIMEFRAMES _period, // Period ... XFIMAInputs &_fimaInputs, // XFIMAInputs ... bool _processAllTicks = false, // Process All Ticks ... double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... double _defaultSignalVolume = 0.01 // Default Signal Volume ... ) : XCBaseSignaller(_name, _symbol, _period, _processAllTicks, _defaultSignalR2R, _defaultSignalRiskInPoint, _defaultSignalVolume // ) { // // Instantiating XFIMA Indicator Helper Class ... if (_fimaInputs.IsValid()) { // fimaHelper = new XCXFIMAHelper(); bool isInited = fimaHelper.Init( _symbol, _period, _fimaInputs // ); if (isInited) { fimaInputs = _fimaInputs; } else { // delete fimaHelper; ZeroMemory(fimaHelper); } } // // Instantiate XFIMA Helper Parser ... fimaParser = new XCXFIMAHelperParser(fimaHelper); // poiDrawer = new XCXFIMAPOIDrawer(); poiDetector = new XCXFIMAPOIDetector(fimaHelper, fimaParser); // // Configure ... structureConfig.Default(); structureDrawConfig.Default(); } // // Deconstructor ... ~XCXFIMABaseSignaller() { Destroy(); } // // Overrides ... // // Actions ... /** * Destroy ... */ void Destroy() { // BeforeDestroy(); // fimaInputs.Clean(); // delete fimaHelper; ZeroMemory(fimaHelper); // delete poiDrawer; ZeroMemory(poiDrawer); // delete poiDetector; ZeroMemory(poiDetector); // structureConfig.Clean(); structureDrawConfig.Clean(); } // // Virtuals ... /** * Before Destroy ... */ void virtual BeforeDestroy() { } /** * Processing Tick ... * * @param barIndex: int, Specified Bar Index ... */ virtual void ProcessTick(int barIndex = 0) { } /** * Processing New Bar ... * * @param barIndex: int, Specified Bar Index ... */ virtual void ProcessNewBar(int barIndex = 0) { } /** * Check Guards Based on MarketConditions ... * * @param guards: XGuard, reference collection to holds result ... * @param positions: XPosition, reference collection to provides positions ... * @param barIndex: int * * @return ( int ) */ int virtual CheckForGuard( XGuard &guards[], XPosition &positions[], int barIndex = 0 // ) { // int result = 0; // SpecifiedClean(guards); // result = ArraySize(guards); // return result; } /** * Check Additional Validations on Childs Instances ... * * @return ( bool virtual ) */ bool virtual CheckAdditionslSignallerValidations() { // bool result = false; // // Validate Fima Helper Requirements ... result = fimaInputs.IsValid() && fimaHelper != NULL && poiDetector != NULL; if (!result) { return result; } // return result; } /** * Normalizing Signal by Signaller Custom Props ... * * @param signal: XSignal ... */ void virtual NormalizeSignal(XSignal &signal) { } // // Protected ... protected: // // // Protected Actions ... // // Private ... private: // }; // // XFIMA Strategy 2 Signaller Class ... class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller { // // Public ... public: // // Props ... // // Constructor ... XCXFIMAStrategy1Signaller( string _symbol, // Symbol ... ENUM_TIMEFRAMES _period, // Period ... XFIMAInputs &_fimaInputs, // XFIMAInputs ... bool _processAllTicks = false, // Process All Ticks ... double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... double _defaultSignalVolume = 0.01 // Default Signal Volume ... ) : XCXFIMABaseSignaller("XFIMA1", _symbol, _period, _fimaInputs, _processAllTicks, _defaultSignalR2R, _defaultSignalRiskInPoint, _defaultSignalVolume // ) { // // Configure ... drawZones = false; drawIZones = false; drawTrends = false; drawSCTrend = false; drawMCTrend = false; drawLCTrend = false; drawHCTrend = false; drawSupport = false; drawISupport = false; drawOrderFlow = false; drawResistance = false; drawIResistance = false; // manageZones = true; manageIZones = true; manageTrends = false; manageOrderFlow = true; // structureConfig.Default(); structureDrawConfig.Default(); } // // Deconstructor ... ~XCXFIMAStrategy1Signaller() { // Destroy(); } // // Overrides ... /** * Processing Tick ... * * @param barIndex: int, Specified Bar Index ... */ virtual void ProcessTick(int barIndex = 0) { } /** * Processing New Bar ... * * @param barIndex: int, Specified Bar Index ... */ virtual void ProcessNewBar(int barIndex = 0) { // // Normalize ... barIndex = NormalizeInt(barIndex, 0); // XOHCL iBar; XBoxZone iZone; XSignal iSignal; bool has = false; XTarget iTargets[]; bool isBullish = false; bool isBearish = false; ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; // // Initialize Bar as CBar ... has = iBar.Init( symbol, period, barIndex // ); if (!has) { // iBar.Clean(); return; } // // Manage ... Manage(iBar); // // Strategy X ... has = HasSignal( iBar, iZone, iTargets, iDir // ); // // Handle Resting Signals ... has = HasDirection(iDir) && iZone.IsValid(); // // Prepare Signal ... if (has) { // isBullish = IsXBullish(iDir); isBearish = IsXBearish(iDir); // // Provided SL ... double points = GetPoints(symbol); double spread = GetSpread(symbol); double entry = GetEntry(symbol, iDir); // // Calculate SL Addition ... double slAddition = slAdditionDistance <= 0 ? 0 : slAdditionDistance * points; // // Calculate SL Price ... double sl = isBullish ? iZone.lower - slAddition : iZone.upper + slAddition; // // Prepare Signal ... has = PrepareSignal( iSignal, iDir, iTargets, 0, // Use Default R2R ... sl, // Provided Price for SL ... 0 // Specified Risk in Point .... ); } // // Notify On Signal Event ... if (has) { NotifySignalEventListeners(iSignal); } // // Cleanup ... iBar.Clean(); iZone.Clean(); iSignal.Clean(); XClean(iTargets); } /** * Check Guards Based on MarketConditions ... * * @param guards: XGuard, reference collection to holds result ... * @param positions: XPosition, reference collection to provides positions ... * @param barIndex: int * * @return ( int ) */ int virtual CheckForGuard( XGuard &guards[], XPosition &positions[], int barIndex = 0 // ) { // int result = 0; // XClean(guards); return result; // int positionsCount = ArraySize(positions); if (!IsValidSize(positionsCount)) { return result; } // // Requirements ... XGuard iGuard; bool has = false; int samePeaks = 0; int sameVales = 0; double iValue = 0; double points10 = 0; double points50 = 0; double points100 = 0; int samePVValidation = 5; bool isPeakOverLast = false; bool isValeUnderLast = false; // for (int i = 0; i < positionsCount; i++) { // points10 = 10 * positions[i].GetPointsValue(); points50 = 50 * positions[i].GetPointsValue(); points100 = 100 * positions[i].GetPointsValue(); // // Near to TP Guard ... has = positions[i].profit > 0; if (has) { // // Has Same Peaks or Vales ... samePeaks = fimaParser.CountSamePeaks(barIndex); sameVales = fimaParser.CountSameVales(barIndex); isPeakOverLast = (fimaParser.IsPeakOverLast(barIndex) || fimaParser.IsPeakOverLast(barIndex + 1)); isValeUnderLast = (fimaParser.IsValeUnderLast(barIndex) || fimaParser.IsValeUnderLast(barIndex + 1)); has = (positions[i].IsBullish() ? ( isPeakOverLast && sameVales >= samePVValidation && fimaHelper.GetVale(barIndex) > positions[i].sl) : positions[i].IsBearish() ? ( isValeUnderLast && samePeaks >= samePVValidation && fimaHelper.GetPeak(barIndex) < positions[i].sl) : false); if (has) { // iGuard.Clean(); iGuard.time = TimeCurrent(); iGuard.symbol = positions[i].symbol; iGuard.period = positions[i].period; iGuard.ticket = positions[i].ticket; iGuard.provider = positions[i].provider; iGuard.sl = positions[i].IsBullish() ? fimaHelper.GetVale(barIndex) - points10 : fimaHelper.GetPeak(barIndex) + points10; iGuard.action = X_GUARD_ACTION_TRAIL_STOP; // has = iGuard.IsValid(); if (has) { AddRef(iGuard, guards); // // Remove TP if in Profit SL ... iValue = (positions[i].IsBullish() ? positions[i].entry + points10 : positions[i].entry - points10); has = (positions[i].IsBullish() && HasResistance()) ? (iGuard.sl >= iValue && positions[i].tp < resistance.lower) : (positions[i].IsBearish() && HasSupport()) ? (iGuard.sl <= iValue && positions[i].tp > support.upper) : false; if (has) { // iGuard.Clean(); iGuard.force = false; iGuard.tp = positions[i].IsBullish() ? resistance.lower : support.upper; iGuard.time = TimeCurrent(); iGuard.symbol = positions[i].symbol; iGuard.period = positions[i].period; iGuard.ticket = positions[i].ticket; iGuard.provider = positions[i].provider; iGuard.action = X_GUARD_ACTION_TRAIL_TARGET; // has = iGuard.IsValid(); if (has) { AddRef(iGuard, guards); } } } } } } // result = ArraySize(guards); // // Cleanup ... iGuard.Clean(); // return result; } // // Protected ... protected: // // void Manage(XOHCL &bar) { // bool has = bar.IsValid(); if (!has) { return; } // XOHCL pBar; XOHCL p2Bar; XOHCL p3Bar; has = bar.GetPreviousBar(pBar); has = has && pBar.GetPreviousBar(p2Bar); has = has && p2Bar.GetPreviousBar(p3Bar); if (!has) { // pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); } // ManageTrends(bar); ManageZones(p2Bar); ManageIZones(p2Bar); ManageOrderFlow(p3Bar); // // Cleanup ... pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); } // // Private ... private: // // Props ... // // Order Flow ... // bool drawOrderFlow; XBoxZone orderFlow[]; bool manageOrderFlow; ENUM_X_DIRECTION orderFlowDir; // bool HasOrderFlow() { // return HasChild(orderFlow) && HasDirection(orderFlowDir); } // bool HasBullishOrderFlow() { return HasOrderFlow() && IsXBullish(orderFlowDir); } // bool HasBearishOrderFlow() { return HasOrderFlow() && IsXBearish(orderFlowDir); } // bool GetOrderFlowBoundary( double &upper, double &lower // ) { // bool result = false; // // Prepare ... upper = EMPTY_VALUE; lower = EMPTY_VALUE; // // Validate ... result = HasOrderFlow(); if (!result) { return result; } // int idx = -1; // // Upper ... idx = GetHighest(orderFlow); if (IsValidIndex(idx)) { upper = orderFlow[idx].upper; } // // Lower ... idx = GetLowest(orderFlow); if (IsValidIndex(idx)) { lower = orderFlow[idx].lower; } // result = NotEmptyZero(upper) && NotEmptyZero(lower) && upper > lower; // // Cleanup ... if (!result) { // upper = EMPTY_VALUE; lower = EMPTY_VALUE; } // return result; } // bool ValidateOrderFlow(XOHCL &bar) { // bool result = false; // // Validate ... result = bar.IsValid() && HasOrderFlow(); if (!result) { return result; } // double upper = EMPTY_VALUE; double lower = EMPTY_VALUE; result = GetOrderFlowBoundary(upper, lower); result = result && HasBullishOrderFlow() ? bar.low > lower : bar.high < upper; // return result; } // void DrawOrderFlow() { // if (!drawOrderFlow || !HasOrderFlow()) { return; } // poiDrawer.DrawZones(orderFlow, structureDrawConfig.drawConfig); } // void ManageOrderFlow(XOHCL &bar) { // // Validate Exists ... if (HasOrderFlow()) { // if (!ValidateOrderFlow(bar)) { // // Invalidate OrderFlow ... XClean(orderFlow); orderFlowDir = X_DIRECTION_NONE; } } // // Detect New ... if (!HasOrderFlow()) { // XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig; // patternConfig.Default(); // patternConfig.supportAndResistanceLoopbackLength = 21; // patternConfig.supportAndResistanceValidationLength = 7; // poiDetector.HasOrderFlow( bar, orderFlowDir, orderFlow, structureConfig.orderFlowValidation, structureConfig.orderFlowUseOB, structureConfig.orderFlowUseFVG, structureConfig.orderFlowUseSupportAndResistance, patternConfig.supportAndResistanceLoopbackLength, patternConfig.supportAndResistanceValidationLength, structureConfig.loopback // ); } // // Update Exists ... if (HasOrderFlow()) { // // Update to Times ... UpdateToTime(orderFlow, TimeCurrent()); // DrawOrderFlow(); } } // // Zone ... // XBoxZone support; XBoxZone resistance; bool drawZones; bool drawSupport; bool manageZones; bool drawResistance; // bool HasZones() { return HasSupport() || HasResistance(); } // bool HasSupport() { return support.IsValid(); } // bool HasResistance() { return resistance.IsValid(); } // bool ValidateZones(XOHCL &bar) { // bool result = false; // // Validate ... result = bar.IsValid() && HasZones(); if (!result) { return result; } // // Support ... bool hasSupport = HasSupport(); if (hasSupport) { // result = bar.close > support.lower && !IsBreaked(support, X_PRICE_CLOSE); if (!result) { // iResistance = support; iResistance.breakAt = NULL; iResistance.dir = X_DIRECTION_BEARISH; iResistance.to = bar.time + (PeriodSeconds(bar.period)); iResistance.from = bar.time - (PeriodSeconds(bar.period)); // support.breakAt = bar.time; support.Clean(); } } // // Resistance ... bool hasResistance = HasResistance(); if (hasResistance) { // result = bar.close < resistance.upper && !IsBreaked(resistance, X_PRICE_CLOSE); if (!result) { // iSupport = resistance; iSupport.breakAt = NULL; iSupport.dir = X_DIRECTION_BULLISH; iSupport.to = bar.time + (PeriodSeconds(bar.period)); iSupport.from = bar.time - (PeriodSeconds(bar.period)); // resistance.breakAt = bar.time; resistance.Clean(); } } // result = (hasSupport && !HasSupport()) || (hasResistance && !HasResistance()); // return result; } // void DrawZones() { // if (!drawZones || !HasZones()) { return; } // if (drawSupport && HasSupport()) { poiDrawer.DrawZone(support, structureDrawConfig.drawConfig); } // if (drawResistance && HasResistance()) { poiDrawer.DrawZone(resistance, structureDrawConfig.drawConfig); } } // void ManageZones(XOHCL &bar) { // // Validate Exists ... if (HasZones()) { // if (!ValidateZones(bar)) { // // Invalidate Zones ... // // Support ... if (IsXValid(support.breakAt)) { // iResistance = support; iResistance.breakAt = NULL; iResistance.dir = X_DIRECTION_BEARISH; iResistance.to = bar.time + (PeriodSeconds(bar.period)); iResistance.from = bar.time - (PeriodSeconds(bar.period)); // support.Clean(); } // // Resistance ... if (IsXValid(resistance.breakAt)) { // iSupport = resistance; iSupport.breakAt = NULL; iSupport.dir = X_DIRECTION_BULLISH; iSupport.to = bar.time + (PeriodSeconds(bar.period)); iSupport.from = bar.time - (PeriodSeconds(bar.period)); // resistance.Clean(); } } } // // Detect New ... XOHCL tmpBar; bool has = false; // // Detect Support ... if (!HasSupport()) { // has = poiDetector.HasSupport( bar, tmpBar, structureConfig.barsAnalysisConfig.supportAndResistanceValidationLength, structureConfig.barsAnalysisConfig.supportAndResistanceLoopbackLength // ); if (has) { // has = ToSupportBox(tmpBar, support, bar.time); has = has && !IsBreaked(support, X_PRICE_CLOSE); if (!has) { // if (support.IsValid()) { // iResistance = support; iResistance.breakAt = NULL; iResistance.dir = X_DIRECTION_BEARISH; iResistance.to = bar.time + (PeriodSeconds(bar.period)); iResistance.from = bar.time - (PeriodSeconds(bar.period)); } // support.Clean(); } } } // // Detect Resistance ... if (!HasResistance()) { // has = poiDetector.HasResistance( bar, tmpBar, structureConfig.barsAnalysisConfig.supportAndResistanceValidationLength, structureConfig.barsAnalysisConfig.supportAndResistanceLoopbackLength // ); if (has) { // has = ToResistanceBox(tmpBar, resistance, bar.time); has = has && !IsBreaked(resistance, X_PRICE_CLOSE); if (!has) { // if (resistance.IsValid()) { // iSupport = resistance; iSupport.breakAt = NULL; iSupport.dir = X_DIRECTION_BULLISH; iSupport.to = bar.time + (PeriodSeconds(bar.period)); iSupport.from = bar.time - (PeriodSeconds(bar.period)); } // resistance.Clean(); } } } // // Update Exists ... if (HasZones()) { // if (HasSupport()) { // support.to = bar.time; support.type = "XFIMASup"; } // if (HasResistance()) { // resistance.to = bar.time; resistance.type = "XFIMARes"; } // DrawZones(); } // // Cleanup ... tmpBar.Clean(); } // XBoxZone iSupport; XBoxZone iResistance; bool drawIZones; bool drawISupport; bool manageIZones; bool drawIResistance; // bool HasIZones() { // return HasISupport() || HasIResistance(); } // bool HasISupport() { return iSupport.IsValid(); } // bool HasIResistance() { return iResistance.IsValid(); } // void DrawIZones() { // if (!drawIZones || !HasIZones()) { return; } // if (drawISupport && HasISupport()) { poiDrawer.DrawZone(iSupport, structureDrawConfig.drawConfig); } // if (drawIResistance && HasIResistance()) { poiDrawer.DrawZone(iResistance, structureDrawConfig.drawConfig); } } // bool ValidateIZones(XOHCL &bar) { // bool result = false; // // Validate ... result = bar.IsValid() && HasIZones(); if (!result) { return result; } // // // Support ... bool hasSupport = HasISupport(); if (hasSupport) { // result = bar.close > iSupport.lower && !IsBreaked(iSupport, X_PRICE_CLOSE); if (!result) { // iSupport.breakAt = bar.time; iSupport.Clean(); } } // // Resistance ... bool hasResistance = HasIResistance(); if (hasResistance) { // result = bar.close < iResistance.upper && !IsBreaked(iResistance, X_PRICE_CLOSE); if (!result) { // iResistance.breakAt = bar.time; iResistance.Clean(); } } // result = (hasSupport && !HasISupport()) || (hasResistance && !HasIResistance()); // return result; } // void ManageIZones(XOHCL &bar) { // // Validate Exists ... if (HasIZones()) { // if (!ValidateIZones(bar)) { // // Invalidate Zones ... // // Support ... if (IsXValid(iSupport.breakAt)) { iSupport.Clean(); } // // Resistance ... if (IsXValid(iResistance.breakAt)) { iResistance.Clean(); } } } // // Update Exists ... if (HasIZones()) { // if (HasISupport()) { // iSupport.to = bar.time; iSupport.type = "XFIMAISup"; } // if (HasIResistance()) { // iResistance.to = bar.time; iResistance.type = "XFIMAIRes"; } // DrawIZones(); } } // // Trends ... // XTrend scTrend; XTrend mcTrend; XTrend lcTrend; XTrend hcTrend; // bool drawTrends; bool drawSCTrend; bool drawMCTrend; bool drawLCTrend; bool drawHCTrend; bool manageTrends; // bool HasTrend() { // bool result = HasSCTrend() || HasMCTrend() || HasLCTrend() || HasHCTrend(); // return result; } // bool HasSCTrend() { return scTrend.IsValid() && scTrend.HasTrend(); } // bool HasMCTrend() { return mcTrend.IsValid() && mcTrend.HasTrend(); } // bool HasLCTrend() { return lcTrend.IsValid() && lcTrend.HasTrend(); } // bool HasHCTrend() { return hcTrend.IsValid() && hcTrend.HasTrend(); } // void DrawTrends() { // if (!drawTrends || !HasTrend()) { return; } // // SC ... if (drawSCTrend && HasSCTrend()) { poiDrawer.DrawTrendLine(scTrend, structureDrawConfig.drawConfig); } // // MC ... if (drawMCTrend && HasMCTrend()) { poiDrawer.DrawTrendLine(mcTrend, structureDrawConfig.drawConfig); } // // LC ... if (drawLCTrend && HasLCTrend()) { poiDrawer.DrawTrendLine(lcTrend, structureDrawConfig.drawConfig); } // // HC ... if (drawHCTrend && HasHCTrend()) { poiDrawer.DrawTrendLine(hcTrend, structureDrawConfig.drawConfig); } } // void ManageTrends(XOHCL &bar) { // // Validate ... bool has = bar.IsValid(); if (!has) { return; } // XTrend tmpTrend; // // SC ... tmpTrend.Clean(); has = fimaParser.HasSCTrend(tmpTrend, bar.Index()); if (has) { scTrend = tmpTrend; } // // MC ... tmpTrend.Clean(); has = fimaParser.HasMCTrend(tmpTrend, bar.Index()); if (has) { mcTrend = tmpTrend; } // // LC ... tmpTrend.Clean(); has = fimaParser.HasLCTrend(tmpTrend, bar.Index()); if (has) { lcTrend = tmpTrend; } // // HC ... tmpTrend.Clean(); has = fimaParser.HasHCTrend(tmpTrend, bar.Index()); if (has) { hcTrend = tmpTrend; } // DrawTrends(); // // Cleanup ... tmpTrend.Clean(); } // // Implementing Strategies ... /** * Check Bar Has Signal Based on Strategy X ... * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... * @param targets: XTarget, reference to detected Signal's Targets collections ... * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... * * @return ( bool ) */ bool HasSignal( XOHCL &bar, XBoxZone &zone, XTarget &targets[], ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Configuration Flags ... // // Signaller Flags ... bool useSignaller1 = true; bool useSignaller2 = false; bool useSignaller3 = false; bool useSignaller4 = false; // XBoxZone tmpZone; string provider = NULL; ENUM_X_DIRECTION tmpDir; // bool signaller1HasSignal = false; bool signaller2HasSignal = false; bool signaller3HasSignal = false; bool signaller4HasSignal = false; // // Validator Flags ... bool validateByOrderFlow = false; // // Target Flags ... bool hasPartialCloseOnTp1 = false; // bool doRFOnEntryOnTP1 = false; // // Draw Flags ... bool draw = true; bool drawZone = true; bool drawMarketStructurePivots = false; bool drawMarketStructureAnalysis = false; bool drawMarketStructureOrderFlow = false; XPOIDrawConfig iDrawConfig; // drawZones = false; drawIZones = false; drawTrends = false; drawSCTrend = false; drawMCTrend = false; drawLCTrend = false; drawHCTrend = false; drawSupport = false; drawISupport = false; drawOrderFlow = false; drawResistance = false; drawIResistance = false; // // Signal Checking ... // // Analyse Market Strucutre ... XFIMAMarketStructure marketStructure; // // Signal Detection Flags ... // // Signaller 1 ... if (useSignaller1) { // signaller1HasSignal = Strategy1HasSignal( bar, tmpZone, targets, tmpDir // ); // if (signaller1HasSignal) { // provider += "1"; // if (!zone.IsValid()) { // dir = tmpDir; zone = tmpZone; } } // tmpZone.Clean(); tmpDir = X_DIRECTION_NONE; } // // Signaller 2 ... if (useSignaller2) { // signaller2HasSignal = Strategy2HasSignal( bar, tmpZone, targets, tmpDir // ); // if (signaller2HasSignal) { // provider += "2"; // if (!zone.IsValid()) { // dir = tmpDir; zone = tmpZone; } } // tmpZone.Clean(); tmpDir = X_DIRECTION_NONE; } // // Signaller 3 ... if (useSignaller3) { // signaller3HasSignal = Strategy3HasSignal( bar, tmpZone, targets, tmpDir // ); // if (signaller3HasSignal) { // provider += "3"; // if (!zone.IsValid()) { // dir = tmpDir; zone = tmpZone; } } // tmpZone.Clean(); tmpDir = X_DIRECTION_NONE; } // // Signaller 4 ... if (useSignaller4) { // signaller4HasSignal = Strategy4HasSignal( bar, tmpZone, targets, tmpDir // ); // if (signaller4HasSignal) { // provider += "4"; // if (!zone.IsValid()) { // dir = tmpDir; zone = tmpZone; } } // tmpZone.Clean(); tmpDir = X_DIRECTION_NONE; } // // Summarize Signallers Result ... result = signaller1HasSignal || signaller2HasSignal || signaller3HasSignal || signaller4HasSignal; // // Signal Validating ... // // Validate Signals by Order Flow ... if (result && validateByOrderFlow) { // // Analyse Market Structure if Required ... if (!marketStructure.IsValid()) { // poiDetector.AnalyseMarket( marketStructure, structureConfig, bar.Index() // ); } // bool isBullish = IsXBullish(dir) && marketStructure.HasBullishOrderFlow(); // bool isBearish = IsXBearish(dir) && marketStructure.HasBearishOrderFlow(); // // Summarizing result ... result = isBullish || isBearish; } // // Targets, Restrictions and Risk Management ... if (result) { // // Requirements ... XTarget iTarget; // // Checking Direction of Signal ... bool isBullish = IsXBullish(dir); bool isBearish = IsXBearish(dir); // // Provided SL ... double points = GetPoints(symbol); double spread = GetSpread(symbol); double entry = GetEntry(symbol, dir); // // Calculate SL Addition ... double slAddition = slAdditionDistance <= 0 ? 0 : slAdditionDistance * points; // // Calculate SL Price ... double sl = isBullish ? zone.lower - slAddition : zone.upper + slAddition; // // Calculate Risk ... double risk = MathAbs(entry - sl); // // Calculate Reward ... double reward = defaultSignalR2R * risk; // // Calculate TP1 ... double tp1 = isBullish ? entry + risk : entry - risk; double tp2 = isBullish ? entry + (2 * risk) : entry - (2 * risk); // // Calculate TP ... double tp = isBullish ? entry + reward : entry - reward; // // Check Max Allowed Risk ... bool hasTooMuchRisk = maxAllowedRiskDistance <= 0 ? false : risk >= (maxAllowedRiskDistance * points); if (hasTooMuchRisk) { // // Clean Signal if Too much Risk ... zone.Clean(); dir = X_DIRECTION_NONE; } // // Common Targets ... // // Partial Close on TP 1 ... if (hasPartialCloseOnTp1) { // iTarget.Clean(); iTarget.target = tp1; iTarget.actingDistance = 5; iTarget.volumeMultiplier = 0.8; iTarget.doRFOnEntry = doRFOnEntryOnTP1; // AddRef(iTarget, targets); } // // Custom Signaller Targets ... // // Restrictions Handling ... if (risk > 0 && HasRestrictions()) { // // Reset Restricitons if necessary ... ResetRestrictions(); // // Handle Custom Restrictions Senario ... } // // Ignore Targets ... if (ignoreTargets) { XClean(targets); } // // Summarize Result ... result = zone.IsValid() && HasDirection(dir); // // Cleanup ... iTarget.Clean(); } // // Draws ... if (result && draw) { // // Prepare Draw Config ... iDrawConfig = structureDrawConfig.drawConfig; iDrawConfig.zonesWidth = 3; iDrawConfig.zonesStyle = STYLE_DASH; iDrawConfig.bullishColor = clrYellow; iDrawConfig.bearishColor = clrDarkOrange; // // Draw Zone ... if (drawZone) { poiDrawer.DrawZone(zone, iDrawConfig); } // // Draw Market Structure ... // // Analyse Market Structure if Required ... if (!marketStructure.IsValid()) { // poiDetector.AnalyseMarket( marketStructure, structureConfig, bar.Index() // ); } if (marketStructure.IsValid()) { // // Order Flow ... if (drawMarketStructureOrderFlow && marketStructure.HasOrderFlow()) { poiDrawer.DrawZones(marketStructure.orderFlow, iDrawConfig); } // // Pivots ... if (drawMarketStructurePivots) { // XPivot pivots[]; int pivotsCount = marketStructure.CollectPivots( pivots, true // Contains Patterns ... ); if (IsValidSize(pivotsCount)) { poiDrawer.DrawPivots(pivots, iDrawConfig); } // XClean(pivots); } // // Analysis ... if (drawMarketStructureAnalysis) { // } } // // Other Drawing Materials ... Print("Signaller Providers: ", provider); } // // Cleanup ... if (!result) { // zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; } // // Cleanup ... tmpZone.Clean(); iDrawConfig.Clean(); marketStructure.Clean(); // return result; } // // Custom Signal Strategies ... /** * Check Bar Has Signal Based on Strategy 3 ... * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... * @param targets: XTarget, reference to detected Signal's Targets collections ... * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... * * @return ( bool ) */ bool Strategy1HasSignal( XOHCL &bar, XBoxZone &zone, XTarget &targets[], ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Define Requirements ... // XOHCL pBar; XOHCL p2Bar; XOHCL p3Bar; XOHCL tmpBar; XPivot tmpPivot; XBoxZone atrBox; XBoxZone zones[]; XBoxZone tmpZone; XBoxZone scPVZone; XBoxZone mcPVZone; XBoxZone lcPVZone; XBoxZone hcPVZone; XBoxZone tmpZones[]; XBoxZone pinBarZone; XBoxZone supports[]; XBoxZone resistances[]; XBoxZone affectedZone; XTrend pinBarZoneTrend; bool isBullish = false; bool isBearish = false; ENUM_X_DIRECTION tmpDir; XPatternAnalysis pBarPatterns; XPatternAnalysis p2BarPatterns; XPatternAnalysis p3BarPatterns; XPatternAnalysisConfig iPatternsConfig; // // Reading Bars ... result = bar.GetPreviousBar(pBar); result = result && pBar.GetPreviousBar(p2Bar); result = result && p2Bar.GetPreviousBar(p3Bar); if (!result) { // pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); // return result; } // // Reading Bar Patterns ... iPatternsConfig.Default(); iPatternsConfig.FullPattern(); result = result && poiDetector.AnalyseBarPatterns( pBar, pBarPatterns, iPatternsConfig // ); result = result && poiDetector.AnalyseBarPatterns( p2Bar, p2BarPatterns, iPatternsConfig // ); result = result && poiDetector.AnalyseBarPatterns( p3Bar, p3BarPatterns, iPatternsConfig // ); if (!result) { // pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); pBarPatterns.Clean(); p2BarPatterns.Clean(); p3BarPatterns.Clean(); iPatternsConfig.Clean(); // return result; } // // Detect Directional Candlestic Patterns ... // // Bullish ... bool isPBarHasBullishPatterns = (bar.close > pBar.low || bar.open > pBar.low) && ( // pBarPatterns.IsPinned(X_DIRECTION_BULLISH) || pBarPatterns.IsEngulfed(X_DIRECTION_BULLISH) || pBarPatterns.IsMomentum(X_DIRECTION_BULLISH) || pBarPatterns.IsPiercing(X_DIRECTION_BULLISH) || pBarPatterns.IsSignalKey(X_DIRECTION_BULLISH) // ); bool isP2BarHasBullishPatterns = (bar.close > p2Bar.low || bar.open > p2Bar.low) && ( // p2BarPatterns.IsPinned(X_DIRECTION_BULLISH) || p2BarPatterns.IsEngulfed(X_DIRECTION_BULLISH) || p2BarPatterns.IsMomentum(X_DIRECTION_BULLISH) || p2BarPatterns.IsPiercing(X_DIRECTION_BULLISH) || p2BarPatterns.IsSignalKey(X_DIRECTION_BULLISH) // ); bool isP3BarHasBullishPatterns = (bar.close > p3Bar.low || bar.open > p3Bar.low) && ( // p3BarPatterns.IsPinned(X_DIRECTION_BULLISH) || p3BarPatterns.IsEngulfed(X_DIRECTION_BULLISH) || p3BarPatterns.IsMomentum(X_DIRECTION_BULLISH) || p3BarPatterns.IsPiercing(X_DIRECTION_BULLISH) || p3BarPatterns.IsSignalKey(X_DIRECTION_BULLISH) // ); // // Bearish ... bool isPBarHasBearishPatterns = (bar.close < pBar.high || bar.open < pBar.high) && ( // pBarPatterns.IsPinned(X_DIRECTION_BEARISH) || pBarPatterns.IsEngulfed(X_DIRECTION_BEARISH) || pBarPatterns.IsMomentum(X_DIRECTION_BEARISH) || pBarPatterns.IsPiercing(X_DIRECTION_BEARISH) || pBarPatterns.IsSignalKey(X_DIRECTION_BEARISH) // ); bool isP2BarHasBearishPatterns = (bar.close < p2Bar.high || bar.open < p2Bar.high) && ( // p2BarPatterns.IsPinned(X_DIRECTION_BEARISH) || p2BarPatterns.IsEngulfed(X_DIRECTION_BEARISH) || p2BarPatterns.IsMomentum(X_DIRECTION_BEARISH) || p2BarPatterns.IsPiercing(X_DIRECTION_BEARISH) || p2BarPatterns.IsSignalKey(X_DIRECTION_BEARISH) // ); bool isP3BarHasBearishPatterns = (bar.close < p3Bar.high || bar.open < p3Bar.high) && ( // p3BarPatterns.IsPinned(X_DIRECTION_BEARISH) || p3BarPatterns.IsEngulfed(X_DIRECTION_BEARISH) || p3BarPatterns.IsMomentum(X_DIRECTION_BEARISH) || p3BarPatterns.IsPiercing(X_DIRECTION_BEARISH) || p3BarPatterns.IsSignalKey(X_DIRECTION_BEARISH) // ); // // Checking Support and Resistances ... // // Support ... bool hasSupport = pBarPatterns.IsSupport(); if (hasSupport) { // hasSupport = pBarPatterns.GetSupport(tmpBar, tmpPivot, tmpZone); if (hasSupport) { AddIfNotExists(tmpZone, supports); } } hasSupport = p2BarPatterns.IsSupport(); if (hasSupport) { // hasSupport = p2BarPatterns.GetSupport(tmpBar, tmpPivot, tmpZone); if (hasSupport) { AddIfNotExists(tmpZone, supports); } } hasSupport = p3BarPatterns.IsSupport(); if (hasSupport) { // hasSupport = p3BarPatterns.GetSupport(tmpBar, tmpPivot, tmpZone); if (hasSupport) { AddIfNotExists(tmpZone, supports); } } // // Resistance ... bool hasResistance = pBarPatterns.IsResistance(); if (hasResistance) { // hasResistance = pBarPatterns.GetResistance(tmpBar, tmpPivot, tmpZone); if (hasResistance) { AddIfNotExists(tmpZone, resistances); } } hasResistance = p2BarPatterns.IsResistance(); if (hasResistance) { // hasResistance = p2BarPatterns.GetResistance(tmpBar, tmpPivot, tmpZone); if (hasResistance) { AddIfNotExists(tmpZone, resistances); } } hasResistance = p3BarPatterns.IsResistance(); if (hasResistance) { // hasResistance = p3BarPatterns.GetResistance(tmpBar, tmpPivot, tmpZone); if (hasResistance) { AddIfNotExists(tmpZone, resistances); } } // // Collecting Zones ... // int collectedZonesCount = poiDetector.DetectZones( bar, zones, true, // Validated Zones ... false, // Remove Used Zones ... false, // Contains Order Blocks ... true, // Contains Fair Value Gaps ... true, // Contains Supports ... true, // Contains Resistances ... X_DIRECTION_NONE, // For Dir (Contains All Direction Zones) ... X_SORT_BY_DATE, // Sort By ... X_DIRECTION_BEARISH, // Sort Dir ... 3, // Zones Loopback ... 3, // Zones Validation Length ... 0, // Count (All Zones) ... 100 // Loop back for Detection ... ); bool hasCollectedZones = IsValidSize(collectedZonesCount) && collectedZonesCount > 1; int affectedZonesCount = 0; bool hasAffectedZone = false; int collectedZonesBullishCount = 0; int collectedZonesBearishCount = 0; bool hasBullishAffectedZone = false; bool hasBearishAffectedZone = false; bool hasBullishCollectedZones = false; bool hasBearishCollectedZones = false; if (hasCollectedZones) { // // Bullish ... XClean(tmpZones); collectedZonesBullishCount = ExtractByDirection(tmpZones, zones, X_DIRECTION_BULLISH); hasBullishCollectedZones = IsValidSize(collectedZonesBullishCount); // // Bearish ... XClean(tmpZones); collectedZonesBearishCount = ExtractByDirection(tmpZones, zones, X_DIRECTION_BEARISH); hasBearishCollectedZones = IsValidSize(collectedZonesBearishCount); // // Extract Affected Zones ... XClean(tmpZones); int affectedZonesCount = ExtractAffectedZones(p2Bar, zones, tmpZones); int idx = GetYoungest(tmpZones); if (IsValidIndex(idx)) { affectedZone = tmpZones[idx]; } hasAffectedZone = affectedZone.IsValid(); hasBullishAffectedZone = hasAffectedZone && affectedZone.IsBullish(); hasBearishAffectedZone = hasAffectedZone && affectedZone.IsBearish(); } // // Reading Cycle PVS ... bool hasSCPV = poiDetector.GetSCZone(pBar, scPVZone); bool hasMCPV = poiDetector.GetMCZone(pBar, mcPVZone); bool hasLCPV = poiDetector.GetLCZone(pBar, lcPVZone); bool hasHCPV = poiDetector.GetHCZone(pBar, hcPVZone); bool isCyclePVBullish = hasMCPV && mcPVZone.IsBullish() && hasLCPV && lcPVZone.IsBullish() && hasHCPV && hcPVZone.IsBullish(); bool isCyclePVBearish = hasMCPV && mcPVZone.IsBearish() && hasLCPV && lcPVZone.IsBearish() && hasHCPV && hcPVZone.IsBearish(); // // Validating Market Direction ... // by Checking HC and LC States ... // bool isLCBullish = fimaParser.IsLCMABullish(pBar.Index()); bool isHCBullish = fimaParser.IsHCMABullish(pBar.Index()); bool isLCHigherLow = (fimaParser.IsLCHigherLow(pBar.Index()) || fimaParser.IsLCHigherLow(p2Bar.Index()) || fimaParser.IsLCHigherLow(p3Bar.Index())); bool isCyclesBullish = isLCBullish && isHCBullish && isLCHigherLow; // bool isLCBearish = fimaParser.IsLCMABearish(pBar.Index()); bool isHCBearish = fimaParser.IsHCMABearish(pBar.Index()); bool isLCLowerHigh = (fimaParser.IsLCLowerHigh(pBar.Index()) || fimaParser.IsLCLowerHigh(p2Bar.Index()) || fimaParser.IsLCLowerHigh(p3Bar.Index())); bool isCyclesBearish = isLCBearish && isHCBearish && isLCLowerHigh; // // Looking For a Pin Bar in P2Bar ... bool isP2BarIsPinBar = poiDetector.IsPinnedBar( p2Bar, tmpDir, 4, // Shadow Multiplier ... 4, // Minimum Range Multiplier ... true // Force Pin Bar Direction ... ); if (isP2BarIsPinBar) { // isP2BarIsPinBar = ToBox( p2Bar, pinBarZone, tmpDir, X_BAR_PATTERN_PINNED // ); if (isP2BarIsPinBar) { // pinBarZone.to = bar.time; isP2BarIsPinBar = poiDetector.HasBoundaryTrend( pinBarZone, pinBarZoneTrend, false // ); isP2BarIsPinBar = isP2BarIsPinBar && tmpDir == pinBarZoneTrend.dir; } } bool isP2BarPinnedBullish = isP2BarIsPinBar && IsXBullish(tmpDir); bool isP2BarPinnedBearish = isP2BarIsPinBar && IsXBearish(tmpDir); // // Checking ATR Box ... bool hasATRBox = fimaParser.GetATRBox( atrBox, bar.Index() // ); bool hasATRBoxBullish = hasATRBox && atrBox.IsBullish(); bool hasATRBoxBearish = hasATRBox && atrBox.IsBearish(); // // Checking Double Patterns ... ENUM_X_DIRECTION iDBDir; XPatternAnalysis iPatterns; XPatternAnalysis iPPatterns; ENUM_X_BAR_PATTERN doublePatterns[]; GetCandlestickPatterns(doublePatterns); bool hasDoublePatterns = poiDetector.HasDoublePatterns( pBar, iDBDir, iPatterns, iPPatterns, doublePatterns, iPatternsConfig, 5 // ); bool hasBullishDoublePatterns = hasDoublePatterns && IsXBullish(iDBDir); bool hasBearishDoublePatterns = hasDoublePatterns && IsXBearish(iDBDir); // isBullish = // hasSupport && hasResistance && isCyclesBullish && hasATRBoxBullish && isCyclePVBullish && isP2BarPinnedBullish && hasBullishAffectedZone && isPBarHasBullishPatterns && hasBullishCollectedZones && isP2BarHasBullishPatterns && collectedZonesBullishCount > collectedZonesBearishCount && true // ; // isBearish = // hasSupport && hasResistance && isCyclesBearish && hasATRBoxBearish && isCyclePVBearish && isP2BarPinnedBearish && hasBearishAffectedZone && isPBarHasBearishPatterns && hasBearishCollectedZones && isP2BarHasBearishPatterns && collectedZonesBearishCount > collectedZonesBullishCount && true // ; // // Validate ... result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // result = HasDirection(dir); } // // Prepare Zone ... if (result) { // zone.Clean(); zone = pinBarZone; // result = zone.IsValid(); } // // Draws ... if (result) { // XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; XPatternAnalysisDrawConfig iPatternsConfig = structureDrawConfig.barAnalysisDrawConfig; iConfig.trendRayLeft = false; iConfig.trendRayRight = false; // // poiDrawer.DrawZone(scPVZone, iConfig); // poiDrawer.DrawZone(mcPVZone, iConfig); // poiDrawer.DrawZone(lcPVZone, iConfig); // poiDrawer.DrawZone(hcPVZone, iConfig); // poiDrawer.DrawPatternAnalysis(pBarPatterns, iPatternsConfig); poiDrawer.DrawPatternAnalysis(p2BarPatterns, iPatternsConfig); poiDrawer.DrawPatternAnalysis(p3BarPatterns, iPatternsConfig); // poiDrawer.DrawZone(pinBarZone, iConfig); poiDrawer.DrawZone(affectedZone, iConfig); poiDrawer.DrawTrendLine(pinBarZoneTrend, iConfig); // // poiDrawer.DrawZones(zones, iConfig); poiDrawer.DrawZones(supports, iConfig); poiDrawer.DrawZones(resistances, iConfig); // if (hasATRBox) { poiDrawer.DrawZone(atrBox, iConfig); } // if (hasDoublePatterns) { // poiDrawer.DrawPatternAnalysis(iPatterns, iPatternsConfig); poiDrawer.DrawPatternAnalysis(iPPatterns, iPatternsConfig); } // iConfig.Clean(); iPatternsConfig.Clean(); // DebugBreak(); // // // result = false; // isBullish = false; // isBearish = false; // zone.Clean(); } // // Prepare Targets ... if (result) { } // // Cleanup ... if (!result) { // zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; } pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); XClean(zones); tmpBar.Clean(); tmpZone.Clean(); XClean(supports); XClean(tmpZones); scPVZone.Clean(); mcPVZone.Clean(); lcPVZone.Clean(); hcPVZone.Clean(); tmpPivot.Clean(); pinBarZone.Clean(); XClean(resistances); affectedZone.Clean(); pBarPatterns.Clean(); p2BarPatterns.Clean(); p3BarPatterns.Clean(); pinBarZoneTrend.Clean(); iPatternsConfig.Clean(); // return result; } /** * Check Bar Has Signal Based on Strategy 2 ... * * Strategy 2: * =========== * - Works Based On PBar Patterns Focused on PinBar ... * - Looking for a Bar Directional Pattern Happens ... * - Validate Fast Ma Over/Under Slow ... * - Validate P2Peak/Vale doesnt Under or Over Last (InDirectional) ... * - Validate P2Bar Has Directional Market Strucuture Zone (OB, FVG, Support/Resistance) ... * * Manipulations: * ================ * there are Some Flags properties to Change Validations in Strategy ... * we can use them for Testing Purposes ... * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... * @param targets: XTarget, reference to detected Signal's Targets collections ... * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... * * @return ( bool ) */ bool Strategy2HasSignal( XOHCL &bar, XBoxZone &zone, XTarget &targets[], ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Define Requirements ... // XOHCL pBar; XOHCL p2Bar; XOHCL p3Bar; bool isBullish = false; bool isBearish = false; // // Read PBar ... result = bar.GetPreviousBar(pBar); result = result && pBar.GetPreviousBar(p2Bar); result = result && p2Bar.GetPreviousBar(p3Bar); if (!result) { // pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); // return result; } // // Reading pBar Patterns ... XPatternAnalysis pBarPatterns; poiDetector.AnalyseBarPatterns( pBar, pBarPatterns, structureConfig.barsAnalysisConfig // ); bool hasSupport = pBarPatterns.IsSupport(); bool hasResistance = pBarPatterns.IsResistance(); // // Check Boundary Trend ... XTrend boundaryTrend; bool hasBoundaryTrend = fimaParser.HasBoundaryTrend(boundaryTrend, pBar.Index()); bool hasBoundaryBullishTrend = hasBoundaryTrend && boundaryTrend.IsBullish(); bool hasBoundaryBearishTrend = hasBoundaryTrend && boundaryTrend.IsBearish(); // // Check Bar Patterns ... // // Bars Sequences ... bool hasBullishSequence = p3Bar.IsBearish() && pBar.IsBullish(); bool hasBearishSequence = p3Bar.IsBullish() && pBar.IsBearish(); // // Bullish ... bool isPBarHasBullishPatterns = (bar.close > pBar.low || bar.open > pBar.low) && ( // pBarPatterns.IsPinned(X_DIRECTION_BULLISH) || pBarPatterns.IsEngulfed(X_DIRECTION_BULLISH) || pBarPatterns.IsMomentum(X_DIRECTION_BULLISH) || pBarPatterns.IsPiercing(X_DIRECTION_BULLISH) || pBarPatterns.IsSignalKey(X_DIRECTION_BULLISH) // ); // // Bearish ... bool isPBarHasBearishPatterns = (bar.close < pBar.high || bar.open < pBar.high) && ( // pBarPatterns.IsPinned(X_DIRECTION_BEARISH) || pBarPatterns.IsEngulfed(X_DIRECTION_BEARISH) || pBarPatterns.IsMomentum(X_DIRECTION_BEARISH) || pBarPatterns.IsPiercing(X_DIRECTION_BEARISH) || pBarPatterns.IsSignalKey(X_DIRECTION_BEARISH) // ); // double peak = fimaHelper.GetPeak(bar.Index()); double vale = fimaHelper.GetVale(bar.Index()); double pPeak = fimaHelper.GetPeak(pBar.Index()); double pVale = fimaHelper.GetVale(pBar.Index()); double p2Peak = fimaHelper.GetPeak(p2Bar.Index()); double p2Vale = fimaHelper.GetVale(p2Bar.Index()); bool isPPeakOverLast = fimaParser.IsPeakOverLast(pBar.Index()); bool isPValeUnderLast = fimaParser.IsValeUnderLast(pBar.Index()); bool isP2PeakOverLast = fimaParser.IsPeakOverLast(p2Bar.Index()); bool isP2ValeUnderLast = fimaParser.IsValeUnderLast(p2Bar.Index()); bool isPeakOverLast = isPPeakOverLast || isP2PeakOverLast; bool isValeUnderLast = isPValeUnderLast || isP2ValeUnderLast; bool isP2ValeOverLast = pVale > p2Vale; bool isP2PeakUnderLast = pPeak < p2Peak; // // Check PBar Close Over Under Fast Ma ... bool isPBarCloseOverFast = pBar.close > fimaHelper.GetMAFast(pBar.Index()); bool isPBarCloseUnderFast = pBar.close < fimaHelper.GetMAFast(pBar.Index()); bool isFastOverLast = fimaHelper.GetMAFast(pBar.Index()) > fimaHelper.GetMAFast(p2Bar.Index()); bool isFastUnderLast = fimaHelper.GetMAFast(pBar.Index()) < fimaHelper.GetMAFast(p2Bar.Index()); // // Force P2Bar is Pin Bar ... ENUM_X_DIRECTION p2Dir; bool isP2BarPinned = poiDetector.IsPinnedBar( p2Bar, p2Dir // ); bool isP2BarBullishPinned = isP2BarPinned && IsXBullish(p2Dir); bool isP2BarBearishPinned = isP2BarPinned && IsXBearish(p2Dir); // // Check Based On LC and HC MA State ... // bool isLCMABullish = fimaParser.IsLCMABullish(pBar.Index()); bool isHCMABullish = fimaParser.IsHCMABullish(pBar.Index()); bool isCycleMABullish = isLCMABullish && isHCMABullish; // bool isLCMABearish = fimaParser.IsLCMABearish(pBar.Index()); bool isHCMABearish = fimaParser.IsHCMABearish(pBar.Index()); bool isCycleMABearish = isLCMABearish && isHCMABearish; // // Do ... // isBullish = // hasSupport && isFastOverLast && isValeUnderLast && isCycleMABullish && hasBullishSequence && !isP2PeakUnderLast && isPBarCloseOverFast && isP2BarBullishPinned && hasBoundaryBullishTrend && isPBarHasBullishPatterns // ; // isBearish = // hasResistance && isPeakOverLast && isFastUnderLast && isCycleMABearish && !isP2ValeOverLast && hasBearishSequence && isPBarCloseUnderFast && isP2BarBearishPinned && hasBoundaryBearishTrend && isPBarHasBearishPatterns // ; // // Validate ... result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // result = HasDirection(dir); } // // Prepare Zone ... if (result) { // zone.Clean(); result = ToBox( p2Bar, zone, dir, X_BAR_PATTERN_PINNED // ); // // Draws ... if (result) { // // XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; // iConfig.trendRayLeft = false; // iConfig.trendRayRight = false; // poiDrawer.DrawTrendLine(boundaryTrend, iConfig); // poiDrawer.DrawZone(zone, structureDrawConfig.drawConfig); // iConfig.Clean(); // // DebugBreak(); } // result = zone.IsValid(); } // // Prepare Targets ... if (result) { } // // Cleanup ... if (!result) { // zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; } pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); pBarPatterns.Clean(); boundaryTrend.Clean(); // return result; } /** * Check Bar Has Signal Based on Strategy 3 ... * * Strategy 3: * =========== * - Works Based On Breaked Support or Resistances ... * - Looking for a Support or Resistance to Breaked ... * - Validate Breaker Bar to Change Peak or Vale ... * - Validate Bar Opposit Side of Breaker Bar's Shadow ... * - Validate by Checking Market Strucutre to Has Directional Zone * (Support for Resistance Break / Resistance for Support Break) ... * - Validate Breaker Bar to Has Directional FVG ... * * Manipulations: * ================ * there are Some Flags properties to Change Validations in Strategy ... * we can use them for Testing Purposes ... * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... * @param targets: XTarget, reference to detected Signal's Targets collections ... * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... * * @return ( bool ) */ bool Strategy3HasSignal( XOHCL &bar, XBoxZone &zone, XTarget &targets[], ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Validation Flags ... // bool validateByPVChanges = true; bool validateByGapExists = true; bool validateByBarShadows = true; bool validateHasDirectionalZone = true; // // Define Requirements ... // XOHCL pBar; XOHCL p2Bar; XOHCL p3Bar; bool isBullish = false; bool isBearish = false; // // Read PBar ... result = bar.GetPreviousBar(pBar); result = result && pBar.GetPreviousBar(p2Bar); result = result && p2Bar.GetPreviousBar(p3Bar); if (!result) { // pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); // return result; } // // Do ... // // Retrieve pBar Patterns ... XBoxZone _fvg; XBoxZone _support; XBoxZone _resistance; XPatternAnalysis pBarPatterns; XPatternAnalysis p2BarPatterns; XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig; // poiDetector.AnalyseBarPatterns( pBar, pBarPatterns, patternConfig // ); poiDetector.AnalyseBarPatterns( p2Bar, p2BarPatterns, patternConfig // ); // // Price Must Break Support or Resistance ... // // Extract Support and Resistance ... bool hasSupport = p2BarPatterns.IsSupport(); bool hasResistance = p2BarPatterns.IsResistance(); if (hasSupport) { // XOHCL tmpBar; XPivot tmpPivot; hasSupport = p2BarPatterns.GetSupport(tmpBar, tmpPivot, _support); tmpBar.Clean(); tmpPivot.Clean(); } if (hasResistance) { // XOHCL tmpBar; XPivot tmpPivot; hasResistance = p2BarPatterns.GetResistance(tmpBar, tmpPivot, _resistance); tmpBar.Clean(); tmpPivot.Clean(); } // bool hasBreakedSupport = hasSupport && pBar.close < _support.lower && p2Bar.close > _support.lower; bool hasBreakedResistance = hasResistance && pBar.close > _resistance.upper && p2Bar.close < _resistance.upper; // isBullish = hasBreakedResistance; isBearish = hasBreakedSupport; // result = isBullish || isBearish; // // Validate By PV Changed ... // Breaker Bar must Change Peak or Value ... if (result && validateByPVChanges) { // bool isPeakOverLast = fimaParser.IsPeakOverLast(pBar.Index()); bool isValeUnderLast = fimaParser.IsValeUnderLast(pBar.Index()); // isBullish = isBullish && isPeakOverLast; // isBearish = isBearish && isValeUnderLast; // // Summarize Result ... result = isBullish || isBearish; } // // Validate by Bar Shadows ... // Breakre Bar Side Shadow must not Reached ... if (result && validateByBarShadows) { // isBullish = isBullish && pBar.low > p2Bar.low; // isBearish = isBearish && pBar.high < p2Bar.high; // // Summarize Result ... result = isBullish || isBearish; } // // Validate Has Directional Zone ... if (result && validateHasDirectionalZone) { // isBullish = isBullish && hasSupport; // isBearish = isBearish && hasResistance; // // Summarize Result ... result = isBullish || isBearish; } // // Validate By Gap Exists ... if (result && validateByGapExists) { // ENUM_X_DIRECTION tmpDir; bool hasFVG = poiDetector.HasFVG( pBar, tmpDir, _fvg // ); // isBullish = isBullish && hasFVG && IsXBullish(tmpDir); // isBearish = isBearish && hasFVG && IsXBearish(tmpDir); // // Summarize Result ... result = isBullish || isBearish; } // // Prepare Direction and Zone ... if (result) { // if (isBullish) { // zone = _resistance; zone.dir = Opposit(_resistance.dir); dir = zone.dir; zone.upper = MathMax(zone.upper, _fvg.upper); zone.lower = MathMin(zone.lower, _fvg.lower); } // if (isBearish) { // zone = _support; zone.dir = Opposit(_support.dir); dir = zone.dir; zone.upper = MathMax(zone.upper, _fvg.upper); zone.lower = MathMin(zone.lower, _fvg.lower); } // // Zone Validation Base ... result = zone.IsValid(); if (result) { // // Validate By Trend of Zone ... XTrend zoneTrend; XTrend zoneToTrend; // // Detecting Trends ... result = poiDetector.HasBoundaryTrend(zone, zoneTrend, false); result = result && poiDetector.HasBoundaryTrend(zone, zoneToTrend, true); // // Validate Trend ... result = result && zone.dir == zoneTrend.dir && zone.dir == zoneToTrend.dir; // // Draw ... if (result) { // // // XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; // iConfig.trendRayLeft = false; // iConfig.trendRayRight = false; // // // poiDrawer.DrawTrendLine(zoneTrend, iConfig); // poiDrawer.DrawTrendLine(zoneToTrend, iConfig); // // // iConfig.Clean(); } // // Cleanup ... zoneTrend.Clean(); zoneToTrend.Clean(); // // Reset Flags ... if (!result) { // zone.Clean(); isBullish = false; isBearish = false; } } // result = zone.IsValid(); } // if (result) { // if (_support.IsValid()) { poiDrawer.DrawZone(_support, structureDrawConfig.drawConfig); } // if (_resistance.IsValid()) { poiDrawer.DrawZone(_resistance, structureDrawConfig.drawConfig); } // if (pBarPatterns.IsValid()) { poiDrawer.DrawPatternAnalysis(pBarPatterns, structureDrawConfig.barAnalysisDrawConfig); } } // // Cleanup ... if (!result) { // zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; } pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); pBarPatterns.Clean(); p2BarPatterns.Clean(); patternConfig.Clean(); // return result; } /** * Check Bar Has Signal Based on Strategy 4 ... * * Strategy 4: * =========== * - Works Based on Order Flow ... * - Looking for new and Fresh Order Flow ... * - Validate Bar is Inside Order Flow ... * - Validate Bar has Proper Pattern ... * - Validate Bar Based on ATR Band in two Step: * - Step 1: Bars is Inside ATR Band (Middle) ... * - Step 2: Trigger Bars Close Price based on ATR Band ... * - Validate Order Flow based on Market Structure Zone ... * - Validate Trigger Bar based on InDirectional Market Structure Zones ... * * Manipulations: * ================ * there are Some Flags properties to Change Validations in Strategy ... * we can use them for Testing Purposes ... * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... * @param targets: XTarget, reference to detected Signal's Targets collections ... * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... * * @return ( bool ) */ bool Strategy4HasSignal( XOHCL &bar, XBoxZone &zone, XTarget &targets[], ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Validation Flags ... bool validateBarInsideZone = true; bool validateByBarPatterns = true; bool validateByXFIMABoundary = true; bool validateByBarInsideATRBand = true; bool validateByBarBasedOnATRBand = true; bool validateByXFIMABoundaryTrend = true; bool validateMarketStructureHasDirectionalZone = true; bool validateMarketStructureDirectionalZoneInsideOrderFlow = true; bool validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP = true; // // Define Requirements ... // XOHCL pBar; XOHCL p2Bar; XOHCL p3Bar; bool isBullish = false; bool isBearish = false; // // Read PBar ... result = bar.GetPreviousBar(pBar); result = result && pBar.GetPreviousBar(p2Bar); result = result && p2Bar.GetPreviousBar(p3Bar); if (!result) { // pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); // return result; } // // Do ... // // Retrieve pBar Patterns ... XPatternAnalysis pBarPatterns; XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig; // poiDetector.AnalyseBarPatterns( pBar, pBarPatterns, patternConfig // ); // // Detecting OrderFlow ... XBoxZone oFlow[]; bool hasOrderFlow = poiDetector.HasOrderFlow( p3Bar, dir, oFlow, structureConfig.orderFlowValidation, structureConfig.orderFlowUseOB, structureConfig.orderFlowUseFVG, structureConfig.orderFlowUseSupportAndResistance, patternConfig.supportAndResistanceLoopbackLength, patternConfig.supportAndResistanceValidationLength, structureConfig.loopback // ); // XTrend boundaryTrend; XTrend boundaryZoneTrend; // double atrBandUpper = EMPTY_VALUE; double atrBandLower = EMPTY_VALUE; double atrBandMiddle = EMPTY_VALUE; // isBullish = hasOrderFlow && IsXBullish(dir); // isBearish = hasOrderFlow && IsXBearish(dir); // // Summarize Result ... result = isBullish || isBearish; // // Force Price of p2Bar is Inside Order Flow ... if (result && validateBarInsideZone) { // double orderFlowUpper = 0; double orderFlowLower = 0; // int idx = -1; idx = GetHighest(oFlow); if (IsValidIndex(idx)) { orderFlowUpper = oFlow[idx].upper; } idx = GetLowest(oFlow); if (IsValidIndex(idx)) { orderFlowLower = oFlow[idx].lower; } // result = NotEmptyZero(orderFlowUpper) && NotEmptyZero(orderFlowLower) && orderFlowUpper > orderFlowLower && (isBullish ? p2Bar.low < orderFlowUpper : p2Bar.high > orderFlowLower); // // Reset Flags ... if (!result) { // isBullish = false; isBearish = false; } } // // Force PBar Has Pattern ... if (result && validateByBarPatterns) { // // Analyse Bar Patterns ... result = pBarPatterns.IsValid(); // // Bullish ... bool isPBarHasBullishPatterns = result && // (bar.close > pBar.low || // bar.open > pBar.low) && ( // pBarPatterns.IsPinned(X_DIRECTION_BULLISH) || pBarPatterns.IsEngulfed(X_DIRECTION_BULLISH) || pBarPatterns.IsMomentum(X_DIRECTION_BULLISH) || pBarPatterns.IsPiercing(X_DIRECTION_BULLISH) || pBarPatterns.IsSignalKey(X_DIRECTION_BULLISH) // ); // // Bearish ... bool isPBarHasBearishPatterns = result && // (bar.close < pBar.high || // bar.open < pBar.high) && ( // pBarPatterns.IsPinned(X_DIRECTION_BEARISH) || pBarPatterns.IsEngulfed(X_DIRECTION_BEARISH) || pBarPatterns.IsMomentum(X_DIRECTION_BEARISH) || pBarPatterns.IsPiercing(X_DIRECTION_BEARISH) || pBarPatterns.IsSignalKey(X_DIRECTION_BEARISH) // ); // isBullish = isBullish && isPBarHasBullishPatterns && !isPBarHasBearishPatterns; // isBearish = isBearish && isPBarHasBearishPatterns && !isPBarHasBullishPatterns; // // Summarize Result ... result = isBullish || isBearish; // // Reset Flags ... if (!result) { // isBullish = false; isBearish = false; } } // // Force P2Bar Place Checking based on ATR Band ... if (result && validateByBarInsideATRBand) { // atrBandUpper = fimaHelper.GetATRBandUpper(p2Bar.Index()); atrBandLower = fimaHelper.GetATRBandLower(p2Bar.Index()); // atrBandMiddle = atrBandLower + ((atrBandUpper - atrBandLower) / 2); // isBullish = isBullish && NotEmptyZero(atrBandMiddle) && p2Bar.low < atrBandMiddle; // isBearish = isBearish && NotEmptyZero(atrBandMiddle) && p2Bar.high > atrBandMiddle; // // Summarize Result ... result = isBullish || isBearish; // // Reset Flags ... if (!result) { // isBullish = false; isBearish = false; } } // // Force PBar Place Checking based on ATR Band ... if (result && validateByBarBasedOnATRBand) { // atrBandUpper = fimaHelper.GetATRBandUpper(pBar.Index()); atrBandLower = fimaHelper.GetATRBandLower(pBar.Index()); // result = NotEmptyZero(atrBandUpper) && NotEmptyZero(atrBandLower) && (isBullish ? pBar.close > atrBandLower : pBar.close < atrBandUpper); // // Reset Flags ... if (!result) { // isBullish = false; isBearish = false; } } // // for Bullish has Support ... // for Bearish has Resistance ... if (result && validateMarketStructureHasDirectionalZone) { // XOHCL tmpBar; XPivot tmpPivot; XBoxZone _support; XBoxZone _resistance; // // Check Market Strucutre Has Support / Resistance ... bool hasSupport = pBarPatterns.IsSupport(); bool hasResistance = pBarPatterns.IsResistance(); // // Retrieve Support / Resistance Zone ... if (hasSupport) { pBarPatterns.GetSupport(tmpBar, tmpPivot, _support); } if (hasResistance) { pBarPatterns.GetResistance(tmpBar, tmpPivot, _resistance); } // // Validate Support and Resistance by Order Flow ... // // Converts Order Flow to Zone ... XBoxZone ofZone; bool hasOFBox = ToBox(ofZone, oFlow); // // Check Market Strucutre Support and Resistance Validation ... if (validateMarketStructureDirectionalZoneInsideOrderFlow) { // hasSupport = hasOFBox && hasSupport && ofZone.lower < _support.lower && ofZone.upper > _support.upper; // hasResistance = hasOFBox && hasResistance && ofZone.lower < _resistance.lower && ofZone.upper > _resistance.upper; } // // Validate Directional Support or Resistance Exists ... // isBullish = isBullish && hasSupport; // isBearish = isBearish && hasResistance; // // Cleanup ... ofZone.Clean(); tmpBar.Clean(); _support.Clean(); tmpPivot.Clean(); _resistance.Clean(); // // Summarize Result ... result = isBullish || isBearish; } // // Validate Makret Structure Has Not Indirectional Zone ... if (result && validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP) { // XOHCL tmpBar; XPivot tmpPivot; XBoxZone _support; XBoxZone _resistance; // // Check Market Strucutre Has Support / Resistance ... bool hasSupport = pBarPatterns.IsSupport(); bool hasResistance = pBarPatterns.IsResistance(); // // Retrieve Support / Resistance Zone ... if (hasSupport) { pBarPatterns.GetSupport(tmpBar, tmpPivot, _support); } if (hasResistance) { pBarPatterns.GetResistance(tmpBar, tmpPivot, _resistance); } // // Converts Order Flow to Zone ... XBoxZone ofZone; bool hasOFBox = ToBox(ofZone, oFlow); // bool hasIndirectionalZone = (isBullish && hasResistance) || (isBearish && hasSupport); if (hasIndirectionalZone) { // // Here we Have to Validate Zone Place ... // double point = GetPoints(bar.symbol); double entry = GetEntry(bar.symbol, dir); double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0; double risk = MathAbs(entry - (isBullish ? oFlow[0].lower : oFlow[0].upper)) + (slAddition * point); double reward = (defaultSignalR2R * risk); double tp = isBullish ? entry + reward : entry - reward; // // Bullish ... if (isBullish && hasResistance) { hasResistance = _resistance.lower <= tp; } // // Bearish ... if (isBearish && hasSupport) { hasSupport = _support.upper >= tp; } } // isBullish = isBullish && !hasResistance; // isBearish = isBearish && !hasSupport; // // Cleanup ... ofZone.Clean(); tmpBar.Clean(); _support.Clean(); tmpPivot.Clean(); _resistance.Clean(); // // Summarize Result ... result = isBullish || isBearish; } // // Validate ... result = isBullish || isBearish; if (result) { // dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // result = HasDirection(dir); } // // Prepare Zone and do Zone Based Validations ... if (result) { // zone.Clean(); result = ToBox( p2Bar, zone, dir, X_BAR_PATTERN_PINNED // ); // // Refine Zone ... zone.to = bar.time; zone.upper = MathMax(zone.upper, atrBandMiddle); zone.lower = MathMin(zone.lower, atrBandMiddle); // // Validate by XFIMA Boundary ... if (result && validateByXFIMABoundary) { // // Try to Retrieve Boundary To Trend ... result = poiDetector.HasBoundaryTrend( zone, boundaryTrend, true // ); // // Try to Retrieve Boundary Zone Trend ... result = result && poiDetector.HasBoundaryTrend( zone, boundaryZoneTrend, false // ); // // Check and Validate Trend Direction ... result = result && zone.dir == boundaryTrend.dir && zone.dir == boundaryZoneTrend.dir; // // Reset Flags ... if (!result) { // zone.Clean(); result = false; isBullish = false; isBearish = false; } } // // Manage Stops ... if (result) { // // Since Stop Management Changes Zones Edge(s) ... // we do it here for Refining Zone ... } // result = zone.IsValid(); } // // Prepare Targets ... if (result) { // XTarget iTarget; // // Calculate Requirements ... double point = GetPoints(bar.symbol); double entry = GetEntry(bar.symbol, dir); double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0; double risk = MathAbs(entry - (isBullish ? zone.lower : zone.upper)) + (slAddition * point); double reward = (defaultSignalR2R * risk); double tp = isBullish ? entry + reward : entry - reward; // // High Risk Target is Used to Protect In Profit Positiions // from Reversal Patterns ... double highRiskR2r = (defaultSignalR2R / 5) * 4; double highRiskReward = highRiskR2r * risk; double highRiskTP = isBullish ? entry + highRiskReward : entry - highRiskReward; iTarget.Clean(); iTarget.actingDistance = 5; iTarget.doRFOnEntry = true; iTarget.target = highRiskTP; iTarget.volumeMultiplier = 0.8; // AddRef(iTarget, targets); // // Cleanup ... iTarget.Clean(); } // // Cleanup ... if (!result) { // zone.Clean(); XClean(targets); dir = X_DIRECTION_NONE; } pBar.Clean(); p2Bar.Clean(); p3Bar.Clean(); XClean(oFlow); pBarPatterns.Clean(); boundaryTrend.Clean(); patternConfig.Clean(); boundaryZoneTrend.Clean(); // return result; } // }; //