/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XC121SMCCycleHelper // Description: provides all based classes for use ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Imports ... #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-poi.class.mq5" #include "../../Helpers/x-saherelm.x121.helper.mq5" #include "../Libraries/x-121.smc.lib.mq5" // // Definitions ... struct XSarChange { // // Props ... ENUM_X_DIRECTION dir; // Sar Changed To Direction ... datetime time; // Sar Changed Time ... double last; // Sar Value Before Change ... double value; // Sar Value After Change ... // // Constructor ... XSarChange() { Clean(); } // // Tools ... /** * Cleanup ... */ void Clean() { // last = 0; value = 0; time = NULL; dir = X_DIRECTION_NONE; } /** * Validation ... * * @return ( bool ) */ bool IsValid() { // bool result = false; // result = last > 0 && value > 0 && IsValid(time) && HasDirection(dir); // return result; } /** * Initialize ... * * @param _last: Last Sar Value ... * @param _current: Current Sar Value ... * * @return ( bool ) */ bool Init( double _last, double _current, datetime _time, ENUM_X_DIRECTION _dir // ) { // bool result = false; // result = _last > 0 && _current > 0 && IsValid(_time) && HasDirection(_dir); if (!result) { return result; } // dir = _dir; last = _last; time = _time; value = _current; // result = IsValid(); // return result; } /** * Check Change is Bullish ... * * @return ( bool ) */ bool IsBullish() { // bool result = false; // result = IsValid() && IsBullish(dir); // return result; } /** * Check Change is Bearish ... * * @return ( bool ) */ bool IsBearishّ() { // bool result = false; // result = IsValid() && IsBearish(dir); // return result; } // }; // // Implementations ... class XC121SMCCycleHelper : public XCBase { // public: // // Props ... // // XPV ... XCXPVHelper *mXPVHelper; XPVPivot pivots[]; XPVPivot orderFlow[]; // // X3MA ... XCX3MAHelper *mX3MAHelper; // // X3VWAP ... XCX3VWAPHelper *mX3VWAPHelper; // // XCHSAR ... XCXCHSARHelper *mXCHSARHelper; XSarChange sarChanges[]; // // X121 ... XCX121Helper *mX121Helper; // // POI Detector ... XCPOIDetector *mPOIDetector; // // Constructor(s) ... XC121SMCCycleHelper() { } // // Deconstructor ... ~XC121SMCCycleHelper() { DeInit(); } // // Getter/Setter(s) ... // // Actions ... /** * Initialize ... * * @param symbol: String ... * @param period: ENUM_TIMEFRAMES member ... * @param xpvInputs: XPVInputs instance ... * @param x3maInputs: X3MAInputs instance ... * @param x3vwapInputs: X3VWAPInputs instance ... * @param xchsarInputs: XCHSARInputs instance ... * * @return ( bool ) */ bool Init( string symbol, ENUM_TIMEFRAMES period, XPVInputs &xpvInputs, X3MAInputs &x3maInputs, X3VWAPInputs &x3vwapInputs, XCHSARInputs &xchsarInputs // ) { // bool result = false; // result = IsValid(symbol) && IsValid(period); if (!result) { return result; } // // XPV ... // result = xpvInputs.IsValid(); if (!result) { return result; } // mXPVHelper = new XCXPVHelper(); result = mXPVHelper.Init( symbol, period, xpvInputs // ); if (!result) { return result; } // // X3MA ... // result = x3maInputs.IsValid(); if (!result) { return result; } // mX3MAHelper = new XCX3MAHelper(); result = mX3MAHelper.Init( symbol, period, x3maInputs // ); if (!result) { return result; } // // X3VWAP ... // result = x3vwapInputs.IsValid(); if (!result) { return result; } // mX3VWAPHelper = new XCX3VWAPHelper(); result = mX3VWAPHelper.Init( symbol, period, x3vwapInputs // ); if (!result) { return result; } // // XCHSAR ... // result = xchsarInputs.IsValid(); if (!result) { return result; } // mXCHSARHelper = new XCXCHSARHelper(); result = mXCHSARHelper.Init( symbol, period, xchsarInputs // ); if (!result) { return result; } // mPOIDetector = new XCPOIDetector( symbol, period // ); mPOIDetector.MaxNumberOfRequiredPOIs(0); mPOIDetector.Init(); // // Initialize Bar Analyser Class Instance ... mBarAnalyser = new XCBarAnalyser(); // // Set Chart Style ... ApplyChartStyle(); // return result; } /** * Get Specified Bar ... * * @param source: XOHCL instance, Source Bar ... * @param bar: XOHCL instance, Dest Bar ... * * @return ( bool ) */ bool GetBar( XOHCL &source, XOHCL &bar // ) { // bool result = false; // bar.Clean(); // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); // result = IsValid(symbol) && IsValid(period) && source.IsValid(); if (!result) { return result; } // int index = iBarShift( symbol, period, source.time // ); result = bar.Init( symbol, period, index // ); if (!result) { // bar.Clean(); return result; } // return result; } /** * Retrieve Specified Bar ... * * @param bar: XOHCL instance ... * @param index: Integer ... * * @return ( bool ) */ bool GetBar( XOHCL &bar, int index = 0 // ) { // bool result = false; // bar.Clean(); // if (index < 0) { index = 0; } // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); // result = bar.Init( symbol, period, index // ); // return result; } /** * Retrieve Specified Bar ... * * @param bar: XOHCL instance ... * @param time: Datetime ... * * @return ( bool ) */ bool GetBar( XOHCL &bar, datetime time = NULL // ) { // bool result = false; // int index = GetBarIndex(time); result = GetBar(bar, index // ); // return result; } /** * Retrieve Specified Time Bar Index ... * * @param time: DateTime ... * * @return ( int ) */ int GetBarIndex(datetime time = NULL) { // int result = -1; // time = NormalizeTime(time); // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); // result = iBarShift( symbol, period, time // ); // return result; } /** * Retrieve Cycle Conditions ... * * @param conditions: X121SMCCycleConditions instance ... * @param barIndex: Integer ... * @param loopback: Integer ... * * @return ( bool ) */ bool GetConditions( X121SMCCycleConditions &conditions, int barIndex = 0, int loopback = 7 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // if (loopback < 5) { loopback = 5; } // conditions.Clean(); // result = mXPVHelper.GetConditions( conditions.xpvConditions, barIndex, loopback // ); if (!result) { // conditions.Clean(); return result; } // result = mX3MAHelper.GetConditions( conditions.x3maConditions, barIndex, loopback // ); if (!result) { // conditions.Clean(); return result; } // result = mX3VWAPHelper.GetConditions( conditions.x3vwapConditions, barIndex, loopback // ); if (!result) { // conditions.Clean(); return result; } // result = mXCHSARHelper.GetConditions( conditions.xchsarConditions, barIndex, loopback // ); if (!result) { // conditions.Clean(); return result; } // conditions.symbol = conditions.xpvConditions.symbol; conditions.period = conditions.xpvConditions.period; conditions.time = TimeCurrent(); // result = conditions.IsValid(); // return result; } // // POI Tools ... /** * Detect Nearest Current SAR Change ... * * @param changeBar: XOHCL instance, Holds Nearest Change Bar ... * @param bar: XOHCL instance, represents Current Bar for Loopback ... * * @return ( bool ) */ bool DetectNearestCSARChange( XOHCL &changeBar, XOHCL &bar // ) { // bool result = false; // changeBar.Clean(); // result = bar.IsValid(); if (!result) { return result; } // XOHCL mBar; result = GetBar( bar, mBar // ); if (!result) { return result; } // int barIndex = mBar.Index(); double sar = mXCHSARHelper.GetC(barIndex); bool isBullish = sar > 0 && sar < mBar.low; bool isBearish = sar > 0 && sar > mBar.high; result = isBullish || isBearish; if (!result) { return result; } // // Loop Back to Find Nearest Sar Change ... bool canContinue = true; while (canContinue) { // barIndex++; // XOHCL iBar; canContinue = iBar.Init( mBar.symbol, mBar.period, barIndex // ); if (!canContinue) { break; } // double iSar = mXCHSARHelper.GetC(barIndex); bool isISarBullish = iSar > 0 && iSar < iBar.low; bool isISarBearish = iSar > 0 && iSar > iBar.high; bool isSarChanged = isBullish ? !isISarBullish : !isISarBearish; // if (isSarChanged) { // result = iBar.GetNextBar(changeBar); canContinue = false; break; } } // result = changeBar.IsValid(); // return result; } /** * Detect Last Decision Bar ( Rejection, Pin, Momentum ) ... * * @param decisionBar: XOHCL instance, Holds Decision Bar ... * @param forDir: ENUM_X_DIRECTION member, Specified Bar Direction ... * @param bar: XOHCL instance, represents Current Bar for Loopback ... * * @return ( bool ) */ bool DetectNearestDecisionBar( XOHCL &decisionBar, ENUM_X_DIRECTION forDir, XOHCL &bar // ) { // bool result = false; // decisionBar.Clean(); // result = bar.IsValid() && forDir != X_DIRECTION_ALL && forDir != X_DIRECTION_NONE; if (!result) { return result; } // XOHCL mBar; result = GetBar( bar, mBar // ); if (!result) { return result; } // int barIndex = mBar.Index(); bool isBullish = IsBullish(forDir); // bool canContinue = true; while (canContinue) { // barIndex++; // XOHCL iBar; canContinue = iBar.Init( mBar.symbol, mBar.period, barIndex // ); if (!canContinue) { break; } // ENUM_X_DIRECTION decisionDir; bool isDecisionBar = mBarAnalyser .IsDecisionBar( iBar, decisionDir // ); if (isDecisionBar) { // if (decisionDir == forDir) { // decisionBar = mBar; canContinue = false; break; } } // canContinue = !decisionBar.IsValid(); } // result = decisionBar .IsValid(); // return result; } // // Parabolic Sar Extensions ... /** * Check Sar Changes and Save it ... * * @param change: XSarChange instance ... * @param time: DateTime ... * * @return ( bool ) */ bool IsSarChanged( XSarChange &change, datetime time = NULL // ) { // bool result = false; // change.Clean(); // XOHCL bar; result = GetBar( bar, time // ); if (!result) { return result; } // XOHCL prevBar; result = bar.GetPreviousBar(prevBar); if (!result) { return result; } // XOHCL prevPrevBar; result = prevBar.GetPreviousBar(prevPrevBar); if (!result) { return result; } // prevPrevBar = prevBar; prevBar = bar; // int index = prevBar.Index(); // double current = mXCHSARHelper.GetC(index); double prev = mXCHSARHelper.GetC(index + 1); // bool isCurrentBullish = current < prevBar.low; bool isPrevBullish = prev < prevPrevBar.low; // bool isCurrentBearish = current > prevBar.high; bool isPrevBearish = prev > prevPrevBar.high; // bool isChangedToBullish = isCurrentBullish && !isPrevBullish; // bool isChangedToBearish = isCurrentBearish && !isPrevBearish; // result = isChangedToBullish || isChangedToBearish; if (!result) { return result; } ENUM_X_DIRECTION dir = isChangedToBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // result = change .Init( prev, current, prevBar.time, dir // ); if (!result) { return result; } // XSarChange lastChange; bool hasLastItem = GetLastItem( lastChange, sarChanges // ); bool canAdd = !hasLastItem ? true : lastChange.time < change.time; if (canAdd) { // AddRef( change, sarChanges // ); } // CleanSarChanges(); // return result; } /** * Cleanup Unused Sar Changes ... */ void CleanSarChanges() { // int required = 10; int count = ArraySize(sarChanges); if (!IsValidSize(count) || count <= required) { return; } // int mustRemove = count - required; ArrayRemove( sarChanges, 0, mustRemove // ); } // // XPV Extensions ... /** * Detect First Pivot ... * * @param pivot: XPVPivot instance ... * @param time: DateTime ... * @param minRepetition: Integer, Minimum Repetition ... * @param maxAllowedLoopbackBars: Integer, Max Allowed LoopBack Bars ... * * @return ( bool ) */ bool DetectLastPivot( XPVPivot &pivot, datetime time = NULL, int minRepetition = 40, int maxAllowedLoopbackBars = 576 // ) { // bool result = false; // pivot.Clean(); // int index = GetBarIndex(time); result = DetectPivot( pivot, index, minRepetition, maxAllowedLoopbackBars // ); // return result; } /** * Detect Pivot ... * * @param pivot: XPVPivot instance ... * @param barIndex: Integer ... * @param minRepetition: Integer, Minimum Repetition ... * @param maxAllowedLoopbackBars: Integer, Max Allowed LoopBack Bars ... * * @return ( bool ) */ bool DetectPivot( XPVPivot &pivot, int barIndex = 0, int minRepetition = 40, int maxAllowedLoopbackBars = 576 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); // int start = barIndex; int end = start + maxAllowedLoopbackBars; // double peak = 0; int peakRepeate = 0; int peakToBarIndex = 0; int peakFromBarIndex = 0; // double vale = 0; int valeRepeate = 0; int valeToBarIndex = 0; int valeFromBarIndex = 0; // bool canLookupPeak = true; bool canLookupVale = true; bool canLookup = true; while (canLookup) { // // Check Peak ... double iPeak = mXPVHelper.GetPeak(barIndex); if (iPeak != peak) { // if (peak != 0 && peakRepeate >= minRepetition) { // XPVPivot iPivot; // iPivot.lower = 0; iPivot.upper = peak; iPivot.symbol = symbol; iPivot.period = period; iPivot.type = XPV_PEAK; iPivot.repetition = peakRepeate; iPivot.to = iTime( symbol, period, peakToBarIndex // ); iPivot.from = iTime( symbol, period, peakFromBarIndex // ); // iPivot.lower = iPivot.CalculateLower(); // bool isValid = iPivot.IsValid(); if (isValid) { // pivot = iPivot; break; } } // peak = iPeak; peakRepeate = 0; peakFromBarIndex = 0; peakToBarIndex = barIndex; } else if (iPeak == peak) { // peakRepeate++; peakFromBarIndex = barIndex; } // // Check Vale ... double iVale = mXPVHelper.GetVale(barIndex); if (iVale != vale) { // if (vale != 0 && valeRepeate >= minRepetition) { // XPVPivot iPivot; // iPivot.upper = 0; iPivot.lower = vale; iPivot.symbol = symbol; iPivot.period = period; iPivot.type = XPV_VALE; iPivot.repetition = valeRepeate; iPivot.to = iTime( symbol, period, valeToBarIndex // ); iPivot.from = iTime( symbol, period, valeFromBarIndex // ); // iPivot.upper = iPivot.CalculateUpper(); // bool isValid = iPivot.IsValid(); if (isValid) { // pivot = iPivot; break; } } // vale = iVale; valeRepeate = 0; valeFromBarIndex = 0; valeToBarIndex = barIndex; } else if (iVale == vale) { // valeRepeate++; valeFromBarIndex = barIndex; } // canLookupPeak = !pivot.IsValid(); canLookupVale = !pivot.IsValid(); canLookup = barIndex < end && (canLookupPeak || canLookupVale); if (canLookup) { barIndex++; } } // result = pivot.IsValid(); if (result) { // XPVPivot last; bool hasLastPivot = GetLastPivot(last); // if (hasLastPivot) { // // Check For Pivot Update ... bool isLastPivotSameAsCurrent = pivot.IsValid() && last.IsValid() && pivot.from == last.from && pivot.type == last.type; if (!isLastPivotSameAsCurrent) { // AddRef( pivot, pivots // ); // CleanPivots(); } else { // // Update Last Pivot ... RemoveLastItem(pivots); // pivot.to = TimeCurrent(); // AddRef( pivot, pivots // ); // CleanPivots(); } } else { // // Add New Pivot ... AddRef( pivot, pivots // ); // CleanPivots(); } } // // DetectOrderFlow(); // return result; } /** * Retriece Last Pivot if Exists ... * * @param pivot: XPVPivot instane ... * * @return ( bool ) */ bool GetLastPivot(XPVPivot &pivot) { // bool result = false; // pivot.Clean(); // int count = ArraySize(pivots); if (!IsValidSize(count)) { return result; } // result = GetLastItem( pivot, pivots // ); // return result; } /** * Detect Order Flow ... * * @param dir: ENUM_X_DIRECTION member, Hold's Order Flow Direction ... * @param minPivots: Integer, minimum Required Pivots for Order Flow ... * * @return ( bool ) */ bool DetectOrderFlow( ENUM_X_DIRECTION &dir, int minPivots = 3 // ) { // bool result = false; // // Normalize Minimum Pivots ... if (minPivots < 2) { minPivots = 2; } // Clean(orderFlow); Copy( pivots, orderFlow // ); // // Sort Pivots ... SortPivots(orderFlow); // // Filter Broken Order Flows ... FilterBrokenPivots(orderFlow); // int count = ArraySize(orderFlow); result = IsValidSize(count) && count >= minPivots; if (!result) { return result; } // // Detect Order Flow Direction ... result = DetectPivotDirection( orderFlow, dir // ); if (!result) { return result; } // return result; } /** * Cleanup Unused Pivots ... */ void CleanPivots() { // int required = 10; int count = ArraySize(pivots); if (!IsValidSize(count) || count <= required) { return; } // int mustRemove = count - required; ArrayRemove( pivots, 0, mustRemove // ); } // // Virtuals ... // protected: // // private: // // Props ... XCBarAnalyser *mBarAnalyser; // // Actions ... /** * Release All Resources ... */ void DeInit() { // delete mXPVHelper; delete mX3MAHelper; delete mX3VWAPHelper; delete mXCHSARHelper; // delete mBarAnalyser; } /** * Apply Chart Style ... */ void ApplyChartStyle() { // // Retrieve Current Chart ID ... long chartId = ChartID(); // ENUM_CHART_MODE mMode = CHART_CANDLES; // chart's mMode bool mShowBidLine = true; // show bid line bool mShowAskLine = true; // show ask line bool mShowGrid = false; // show grids on chart bool mShowVolumes = false; // show volumes bool mShowTradeLevels = true; // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) bool mAutoScroll = true; // chart autoscroll bool mQuickNavigation = true; // chart quick navigation state color mForeGroundColor = clrWhite; // chart's foreground color color mBackGroundColor = clrBlack; // chart's background color color mUpColor = clrGreen; // Up Color color mDownColor = clrRed; // Down Color color mBullishColor = clrGreen; // Bullish color color mBearishColor = clrRed; // Bearish color color mGridColor = clrGray; // grid color color mBidLineColor = clrGray; // bid line color color mAskLineColor = clrRed; // ask line color color mLineColor = clrLime; // line mMode and doji candlestick color color mStopColor = clrGold; // Color of stop order levels (Stop Loss and Take Profit) color mVolumesColor = clrGreen; // volumes color // ChartSetInteger(chartId, CHART_MODE, mMode); ChartSetInteger(chartId, CHART_SHOW_BID_LINE, mShowBidLine); ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, mShowAskLine); ChartSetInteger(chartId, CHART_SHOW_GRID, mShowGrid); ChartSetInteger(chartId, CHART_SHOW_VOLUMES, mShowVolumes); ChartSetInteger(chartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); ChartSetInteger(chartId, CHART_AUTOSCROLL, mAutoScroll); ChartSetInteger(chartId, CHART_QUICK_NAVIGATION, mQuickNavigation); ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, mForeGroundColor); ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, mBackGroundColor); ChartSetInteger(chartId, CHART_COLOR_CHART_UP, mUpColor); ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, mDownColor); ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, mBullishColor); ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); ChartSetInteger(chartId, CHART_COLOR_GRID, mGridColor); ChartSetInteger(chartId, CHART_COLOR_BID, mBidLineColor); ChartSetInteger(chartId, CHART_COLOR_ASK, mAskLineColor); ChartSetInteger(chartId, CHART_COLOR_STOP_LEVEL, mStopColor); ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, mLineColor); ChartSetInteger(chartId, CHART_COLOR_VOLUME, mVolumesColor); } /** * Retrieve Symbol ... * * @return ( string ) */ string GetSymbol() { // string result = NULL; // result = mXPVHelper.GetSymbol(); // return result; } /** * Retrieve TimeFrame (Period) ... * * @return ( ENUM_TIMEFRAMES ) */ ENUM_TIMEFRAMES GetPeriod() { // ENUM_TIMEFRAMES result = NULL; // result = mXPVHelper.GetPeriod(); // return result; } };