/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Tools Library // -------------------------------------- // Name: XToolsLib // Description: provide all commonly used Tools ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Imports ... #include "../Libraries/x-saherelm.draw.lib.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" // // Definitions ... // // Detect Trends ... struct XTrendDetector { // string symbol; ENUM_TIMEFRAMES period; // double higherHighs[]; datetime higherHighTimes[]; // double higherLows[]; datetime higherLowTimes[]; // double lowerHighs[]; datetime lowerHighTimes[]; // double lowerLows[]; datetime lowerLowTimes[]; // bool isFirstLow; // bool isUpTrend; bool isDownTrend; // int _numberOfPivots; int _pivotShoulders; // // Constructor ... XTrendDetector() { Clean(); } // bool FindTrend( string _symbol, ENUM_TIMEFRAMES _period, int barIndex = 0, int _requiredPivots = 3, int _requiredShoulders = 3 // ) { // bool result = false; // Clean(); // if (barIndex < 0) { barIndex = 0; } // if (_requiredPivots < 3) { _requiredPivots = 3; } // if (_requiredShoulders < 3) { _requiredShoulders = 3; } // result = // IsValid(_symbol) && IsValid(_period) // ; if (!result) { Clean(); return result; } // // Find Swing Lows and Swing Highs ... // int hhIndexes[]; datetime hhTimes[]; double hhs[]; // int llIndexes[]; datetime llTimes[]; double lls[]; // bool isEnough = false; // int lastHHIndex = barIndex; int lastLLIndex = barIndex; while (!isEnough) { // int hhSize = ArraySize(hhs); if (hhSize < _requiredPivots) { // lastHHIndex = FindSwing( _symbol, _period, X_SWING_HIGH, _requiredShoulders, lastHHIndex + 1 // ); if (lastHHIndex >= 0) { // XOHCL hBar; bool isInited = hBar.Init( _symbol, _period, lastHHIndex // ); if (isInited) { // Add( hBar.high, hhs // ); // Add( hBar.time, hhTimes // ); // Add( lastHHIndex, hhIndexes // ); } } } // int llSize = ArraySize(lls); if (llSize < _requiredPivots) { // lastLLIndex = FindSwing( _symbol, _period, X_SWING_LOW, _requiredShoulders, lastLLIndex + 1 // ); if (lastLLIndex >= 0) { // XOHCL lBar; bool isInited = lBar.Init( _symbol, _period, lastLLIndex // ); if (isInited) { // Add( lBar.low, lls // ); // Add( lBar.time, llTimes // ); // Add( lastHHIndex, llIndexes // ); } } } // hhSize = ArraySize(hhs); llSize = ArraySize(lls); isEnough = // hhSize == _requiredPivots && llSize == _requiredPivots // ; } // // Draws ... // for (int i = 0; i < ArraySize(hhs); i++) // { // // // DrawArrow( // ChartID(), // "XTRND_HH" + ToString(i), // 0, // hhTimes[i], // hhs[i], // 234, // ANCHOR_BOTTOM, // clrMagenta, // STYLE_SOLID, // 3 // // ); // // // DrawArrow( // ChartID(), // "XTRND_LL" + ToString(i), // 0, // llTimes[i], // lls[i], // 233, // ANCHOR_TOP, // clrAqua, // STYLE_SOLID, // 3 // // ); // } // isUpTrend = // isFirstLow ? // lls[0] > lls[1] && lls[1] > lls[2] && // hhs[0] > hhs[1] && hhs[1] > hhs[2] // : // hhs[0] > hhs[1] && hhs[1] > hhs[2] && // lls[0] > lls[1] && lls[1] > lls[2] // ; isDownTrend = // isFirstLow ? // lls[0] < lls[1] && lls[1] < lls[2] && // hhs[0] < hhs[1] && hhs[1] < hhs[2] // : // hhs[0] < hhs[1] && hhs[1] < hhs[2] && // lls[0] < lls[1] && lls[1] < lls[2] // ; for (int i = 1; i < _requiredPivots; i++) { // // Lows ... // // Lower Lows ... if (lls[i - 1] < lls[i]) { // Add( lls[i - 1], lowerLows // ); // Add( llTimes[i - 1], lowerLowTimes // ); } else // // Higher Lows ... if (lls[i - 1] > lls[i]) { // Add( lls[i - 1], higherLows // ); // Add( llTimes[i - 1], higherLowTimes // ); } // // Highs ... // // Higher Highs ... if (hhs[i - 1] > hhs[i]) { // Add( hhs[i - 1], higherHighs // ); // Add( hhTimes[i - 1], higherHighTimes // ); } else // // Lower Highs ... if (hhs[i - 1] < hhs[i]) { // Add( hhs[i - 1], lowerHighs // ); // Add( hhTimes[i - 1], lowerHighTimes // ); } } // // Remove Draws ... // RemoveDraws("XTRND"); // result = isUpTrend || isDownTrend; if (!result) { Clean(); } // symbol = _symbol; period = _period; _numberOfPivots = _requiredPivots; _pivotShoulders = _requiredShoulders; // result = IsValid(); if (!result) { Clean(); } // return result; } // bool HasTrend() { // bool result = isUpTrend || isDownTrend; // return result; } // // Tools ... // // Cleanup ... void Clean() { // symbol = NULL; period = NULL; // isUpTrend = false; isFirstLow = false; isDownTrend = false; // _numberOfPivots = 0; _pivotShoulders = 0; // Clean(higherHighs); Clean(higherHighTimes); // Clean(higherLows); Clean(higherLowTimes); // Clean(lowerHighs); Clean(lowerHighTimes); // Clean(lowerLows); Clean(lowerLowTimes); } // // Validate ... bool IsValid() { // bool result = false; // result = // IsValid(symbol) && IsValid(period) // ; // return result; } }; // // a Pivot Point ... struct XPivot { // string symbol; // Trading Symbol ... ENUM_TIMEFRAMES period; // Trading TimeFrame ... // double price; // Price ... datetime time; // Time ... // int breakedAsSupport; // Number of Breaked As Support ... int rejectedAsSupport; // Number of Rejected As Support ... // int breakedAsResistance; // Number of Breaked As Resistance ... int rejectedAsResistance; // Number of Rejected As Resistance ... // bool isSupport; datetime supportTime; // bool isResistance; datetime resistanceTime; // double _threshold; // threshold in Point ... int _lastCalculatedBar; // last calculated bars ... int _loopbackForSupportAndResistance; // Number of LoopBacks for Support or Resistance ... // // Constructor ... XPivot() { Clean(); } // // Find Last Support for Market and // Initialize Pivot Based On it ... bool FindLastSupport( string _symbol, ENUM_TIMEFRAMES _period, int barIndex = 0, int _supResVerificationsStep = 21, double __threshold = 5 // ) { // bool result = false; // Clean(); // if (barIndex < 0) { barIndex = 0; } // if (__threshold < 0) { __threshold = 0; } // if (_supResVerificationsStep < 0) { _supResVerificationsStep = 21; } // result = // IsValid(_symbol) && IsValid(_period) && IsValidSize(_supResVerificationsStep) // ; if (!result) { // Clean(); return result; } // // Find Resistance ... // // Retrieve Current Bar ... XOHCL cBar; result = cBar.Init( _symbol, _period, barIndex // ); if (!result) { // Clean(); return result; } // // Calculate Available Bars ... // int bars = iBars( _symbol, _period // ); int maxAllowedBars = bars - 500; int currentLength = _supResVerificationsStep; // // Find Highest High ... for (int i = barIndex; i < maxAllowedBars; i++) { // // Validate and Regenrate Current Length ... if (i > 1) { // currentLength = _supResVerificationsStep * i; // if (currentLength > maxAllowedBars) { currentLength = maxAllowedBars; } } // // Clean ... Clean(); // int llIndex = cBar.FindLowestIndex( currentLength, MODE_LOW // ); XOHCL llBar; result = llBar.Init( _Symbol, _Period, llIndex // ); if (!result) { continue; } // symbol = _symbol; period = _period; price = llBar.low; // _threshold = __threshold; _loopbackForSupportAndResistance = _supResVerificationsStep; // Calculate( barIndex // ); // result = isSupport; if (result) { // supportTime = llBar.time; break; } } // result = IsValid() && isSupport; if (!result) { Clean(); } // return result; } // // Find Last Resistance for Market and // Initialized Pivot Based On it ... bool FindLastResistance( string _symbol, ENUM_TIMEFRAMES _period, int barIndex = 0, int _supResVerificationsStep = 21, double __threshold = 5 // ) { // bool result = false; // Clean(); // if (barIndex < 0) { barIndex = 0; } // if (__threshold < 0) { __threshold = 0; } // if (_supResVerificationsStep < 0) { _supResVerificationsStep = 21; } // result = // IsValid(_symbol) && IsValid(_period) && IsValidSize(_supResVerificationsStep) // ; if (!result) { // Clean(); return result; } // // Find Resistance ... // // Retrieve Current Bar ... XOHCL cBar; result = cBar.Init( _symbol, _period, barIndex // ); if (!result) { // Clean(); return result; } // // Calculate Available Bars ... // int bars = iBars( _symbol, _period // ); int maxAllowedBars = bars - 500; int currentLength = _supResVerificationsStep; // // Find Highest High ... for (int i = barIndex; i < maxAllowedBars; i++) { // // Validate and Regenrate Current Length ... if (i > 1) { // currentLength = _supResVerificationsStep * i; // if (currentLength > maxAllowedBars) { currentLength = maxAllowedBars; } } // // Clean ... Clean(); // int hhIndex = cBar.FindHighestIndex( currentLength, MODE_HIGH // ); XOHCL hhBar; result = hhBar.Init( _Symbol, _Period, hhIndex // ); if (!result) { continue; } // symbol = _symbol; period = _period; price = hhBar.high; // _threshold = __threshold; _loopbackForSupportAndResistance = _supResVerificationsStep; // Calculate( barIndex // ); // result = isResistance; if (result) { // resistanceTime = hhBar.time; break; } } // result = IsValid() && isResistance; if (!result) { Clean(); } // return result; } // // Check Rejection Based On Pivot Type ... bool IsRejected() { // bool result = false; // result = // IsValid() && ( // isSupport || isResistance // ) // ; if (!result) { return result; } // result = // isSupport ? IsSupportRejected() : IsResistanceRejected() // ; // return result; } // // Check Breake Based On Pivot Type ... bool IsBreaked() { // bool result = false; // result = // IsValid() && ( // isSupport || isResistance // ) // ; if (!result) { return result; } // result = // isSupport ? IsSupportBreaked() : IsResistanceBreaked() // ; // return result; } // // Tools ... // // Check Support Rejected ... bool IsSupportRejected( int barIndex = 0 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // result = isSupport; if (!result) { return result; } // // Initialize Required Bars ... // XOHCL cBar; result = cBar.Init( symbol, period, 1 // ); if (!result) { return result; } // XOHCL pBar; result = pBar.Init( symbol, period, 2 // ); if (!result) { return result; } // double threshold = GetPoints(symbol) * _threshold; // result = // // Check Support Touch or Fake Break ... pBar.low < price && ( // pBar.low < price || pBar.low < price - threshold // ) // && // // Check Rejection ... cBar.low > price && ( // cBar.low > price || cBar.low > price + threshold // ) // && // // Check Rejection Must be Bullish ... cBar.IsBullish() // ; // return result; } // // Check Support Breaked ... bool IsSupportBreaked( int barIndex = 0 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // result = isSupport; if (!result) { return result; } // // Initialize Required Bars ... // XOHCL cBar; result = cBar.Init( symbol, period, barIndex + 1 // ); if (!result) { return result; } // XOHCL pBar; result = pBar.Init( symbol, period, barIndex + 2 // ); if (!result) { return result; } // double threshold = GetPoints(symbol) * _threshold; // result = // // Check Support Breaks ... pBar.close < price && ( // pBar.close < price - threshold || pBar.low < price - threshold // ) // && // // Check 50% ... ( // (price - pBar.close) > (pBar.GetBody() / 100) * 50 || (price - cBar.close) > (cBar.GetBody() / 100) * 50 // ) // && // // Also Next Bar must Closed Below Support ... cBar.high < price && cBar.high < price - threshold // && // cBar.close < price && cBar.close < price - threshold // && // cBar.IsBearish() // ; if (result) { DrawArrow( 0, "PBar", 0, pBar.time, pBar.low, 233, ANCHOR_TOP, clrYellow // ); } // return result; } // // Check Resistance Rejected ... bool IsResistanceRejected( int barIndex = 0 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // result = isResistance; if (!result) { return result; } // // Initialize Required Bars ... // XOHCL cBar; result = cBar.Init( symbol, period, 1 // ); if (!result) { return result; } // XOHCL pBar; result = pBar.Init( symbol, period, 2 // ); if (!result) { return result; } // double threshold = GetPoints(symbol) * _threshold; // result = // // Check Resistance Touch or Fake Break ... pBar.high > price && ( // pBar.high > price || pBar.high > price + threshold // ) // && // // Check Rejection ... cBar.high < price && ( // cBar.high < price || cBar.high < price - threshold // ) // && // // Check Rejection Must be Bearish ... cBar.IsBearish() // ; // return result; } // // Check Resistance Breaked ... bool IsResistanceBreaked( int barIndex = 0 // ) { // bool result = false; // if (barIndex < 0) { barIndex = 0; } // result = isResistance; if (!result) { return result; } // // Initialize Required Bars ... // XOHCL cBar; result = cBar.Init( symbol, period, 1 // ); if (!result) { return result; } // XOHCL pBar; result = pBar.Init( symbol, period, 2 // ); if (!result) { return result; } // double threshold = GetPoints(symbol) * _threshold; // result = // // Check Resistance Breaks ... pBar.close > price && ( // pBar.close > price + threshold || pBar.high > price + threshold // ) // && // // Check 50% ... ( // (pBar.close - price) > (pBar.GetBody() / 100) * 50 || (cBar.close - price) > (cBar.GetBody() / 100) * 50 // ) // && // // Also Next Bar Must Closed Above Resistance ... cBar.low > price && cBar.low > price + threshold // && // cBar.close > price && cBar.close > price + threshold // && // cBar.IsBullish() // ; // return result; } // // Cleanup ... void Clean() { // time = NULL; symbol = NULL; period = NULL; supportTime = NULL; resistanceTime = NULL; // price = 0; // breakedAsSupport = 0; rejectedAsSupport = 0; breakedAsResistance = 0; rejectedAsResistance = 0; // _lastCalculatedBar = -1; // isSupport = false; isResistance = false; // _objName = NULL; } // // Validate Model ... bool IsValid() { // bool result = false; // result = // IsValid(symbol) && IsValid(period) && price > 0 // ; // return result; } // // Calculate Required Data ... void Calculate( int barIndex, int loopback = 288 // ) { // if (isSupport || isResistance) { return; } // int bars = iBars( symbol, period // ); // loopback += barIndex; // // Normalizing Loopback ... if (loopback > bars) { loopback = bars - 2 - _loopbackForSupportAndResistance; } // // Check Previous Calculation ... if (bars == _lastCalculatedBar) { return; } // _lastCalculatedBar = bars; // // First Get Current State of Pivot ... // Means Use Zero Index ... XOHCL pBar; bool isInited = pBar.Init( symbol, period, barIndex + 1 // ); if (!isInited) { return; } // // Retrieve Highest High and Lowest Low of SupRes Loopback ... double hhValue = pBar .FindHighest( _loopbackForSupportAndResistance, MODE_HIGH // ); // double llValue = pBar .FindLowest( _loopbackForSupportAndResistance, MODE_LOW // ); // isSupport = llValue > price; isResistance = hhValue < price; // // Prevent Moving Forward if it isn't Support or Resistance ... if (!isSupport && !isResistance) { return; } // time = TimeCurrent(); // for (int i = 2; i < loopback; i++) { // XOHCL iBar; isInited = iBar.Init( symbol, period, i // ); if (!isInited) { continue; } // XOHCL iPBar; isInited = iPBar.Init( symbol, period, i + 1 // ); if (!isInited) { continue; } // XOHCL iPPBar; isInited = iPPBar.Init( symbol, period, i + 2 // ); if (!isInited) { continue; } // bool isBreaked = false; bool isRejected = false; // if (isSupport) { // // Count Support Rejects // and Support Breaks ... // // Support Rejected ... isRejected = // // Check Support Touch or Fake Break ... iPBar.low < price // && // // Check Rejection ... iBar.low > price // ; if (isRejected) { rejectedAsSupport++; } // // Support Breaked ... isBreaked = // // Check Support Breaks ... iPBar.close < price // && // // Check 50% ... (price - iPBar.close) > (iPBar.GetBody() / 100) * 50 // && // // Also Next Bar must Closed Below Support ... iBar.high < price // && // iBar.close < price // && // iBar.IsBullish() // ; if (isBreaked) { breakedAsSupport++; } } else if (isResistance) { // // Count Resistance Reject // or Resistance Breaks ... // // Resistance Rejected ... isRejected = // // Check Resistance Touch or Fake Break ... iPBar.high > price // && // // Check Rejection ... iBar.high < price // ; if (isRejected) { rejectedAsResistance++; } // // Resistance Breaked ... isBreaked = // // Check Resistance Breaks ... iPBar.close > price // && // // Check 50% ... (iPBar.close - price) > (iPBar.GetBody() / 100) * 50 // && // // Also Next Bar Must Closed Above Resistance ... iBar.low > price // && // iBar.close > price // && // iBar.IsBullish() // ; if (isBreaked) { breakedAsResistance++; } } } } // string GetTag() { return "XPivot"; } // // Draw Functions ... // // Last Draw Object Name ... string _objName; // // Draw ... bool Draw( long _chartId, string _prefix = "", color _color = clrYellow, color _thresholdColor = clrAqua, ENUM_LINE_STYLE _style = STYLE_DOT, bool _ray = true, int _width = 1, int _subWindow = 0, bool forcePrefix = false // ) { // bool result = false; // if (!isSupport && !isResistance) { return result; } // _objName = (IsValid(_prefix) && forcePrefix) ? _prefix : GetTag() + "_" + (IsValid(_prefix) ? _prefix + "_" : "") + ToString(NormalizeDouble(price, 2)); // int timeBarIndex = iBarShift( symbol, period, time, false // ); datetime time1 = // isSupport ? supportTime : resistanceTime // ; // result = DrawTrendLine( _chartId, _objName, _subWindow, time1, price, time, price, _color, _style, _width, false, false, _ray // ); // if (result && _threshold > 0) { // // Calculate Threshodl Value ... double diff = GetPoints(symbol) * _threshold; // // Up Threshold ... result = DrawTrendLine( _chartId, _objName + "_UPTRSH", _subWindow, time1, price + diff, time, price + diff, _thresholdColor, _style, _width, false, false, _ray // ); // if (result) { // // Down Threshold ... result = DrawTrendLine( _chartId, _objName + "_DOWNTRSH", _subWindow, time1, price - diff, time, price - diff, _thresholdColor, _style, _width, false, false, _ray // ); } } // return result; } // // Remove Draw ... void Remove() { // if (!IsValid(_objName)) { return; } // RemoveDraws(_objName); } }; //