//+------------------------------------------------------------------+ //| TestRegresser.mq5 | //| SaherElm IT Center | //| https://www.saherelm.ir | //+------------------------------------------------------------------+ #property copyright "SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" // // Imports ... #include "../Classes/x-saherelm.x-cobject.class.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" #include // // Inputs ... // // Calculation ... input int zigzagDepth = 12; // Depth input int zigzagDeviation = 5; // Deviation input int zigzagBackStep = 3; // Back Step input int mLoopbackLength = 200; // Loopback Length for Calculation input int mRequiredPivots = 50; // Required Peaks for Calculation (0 > use loopback ) // // Variables ... // double mZigZagBuffer[]; // ZigZag Values Buffer ... XBarTracker mBarTracker; // Bar Tracker ... bool mZigZagPivotIsPeaks[]; // Check ZigZag Pivot Peak or Vale ... double mZigZagPivotPrices[]; // ZigZag Pivot Prices ... double mZigZagPivotIndexes[]; // ZigZag Pivot Indexes ... datetime mZigZagPivotTimes[]; // ZigZag Pivot Times ... CChartObjectTrend *mUpperTrend; // Trend Line Upper ... CChartObjectTrend *mLowerTrend; // Trend Line Lower ... int mZigZagHandler = INVALID_HANDLE; // ZigZag Indicator Handler ... // double mPeakSlope; double mPeakIntercept; double mZigZagPeaks[]; double mZigZagPeakIndexes[]; datetime mZigZagPeakTimes[]; // double mValeSlope; double mValeIntercept; double mZigZagVales[]; double mZigZagValeIndexes[]; datetime mZigZagValeTimes[]; // datetime mToTime; datetime mFromTime; // // Predictions ... // double mPeakTo; double mValeTo; double mPeakFrom; double mValeFrom; // ENUM_X_DIRECTION mUpperTrendDir; ENUM_X_DIRECTION mLowerTrendDir; // // Support and Resistances ... // XBoxZone mSupportBox; double mMinorSupport; double mMajorSupport; XCBoxObject *mSupportObj; // XBoxZone mResistanceBox; double mMinorResistance; double mMajorResistance; XCBoxObject *mResistanceObj; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // // Initialize Bar Tracker ... mBarTracker.Init( _Symbol, _Period // ); // // Initialize ZigZag Handler ... mZigZagHandler = iCustom( _Symbol, _Period, "ZigZag", zigzagDepth, zigzagDeviation, zigzagBackStep // ); if (mZigZagHandler == INVALID_HANDLE) { Print("Error creating ZigZag handle"); return (INIT_FAILED); } // return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // IndicatorRelease(mZigZagHandler); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // if (!mBarTracker.IsNewBar()) { return; } // int readedZigZagsCount = 0; bool readZigZagsBasedOnPivots = mRequiredPivots > 0; // // Reading ZigZag Values Based on Loopback Length ... if (!readZigZagsBasedOnPivots) { readedZigZagsCount = ReadZigZagValues(); } // // Reading ZigZag Pivots based on required Pivots ... else { // readedZigZagsCount = ReadingZigZagPivots( 0, // BarIndex ... mRequiredPivots, // Required Pivots ... 1500 // Max Allowed Loopback Length ... ); } // // Validate Reading Succeed ... if (readedZigZagsCount <= 0) { return; } // // Try to Detect ZigZag Peaks and Vales ... ProcessZigZagsPeaksAndVales(); // // Try to Calculate ZigZag Supports and Resistances ... ProcessZigZagsSupportsAnsResistances(); // // Try to Calculate Peaks and Vales Linear Regression Based // Slope and Intercept (s) and also Detect From and To Times then // Predict Peaks and Vales Values for them then ... // Prepare Support and Resistance Boxes based on Calculated Support // and Resistances ... if (!CalculateZigZagLinearRegressionParameters()) { return; } // // Draw Peaks and Vales Based Trend Lines ... DrawAnalysis(); // // Process ZigZag Values ... Print(""); // } //+------------------------------------------------------------------+ // int ReadZigZagValues(int barIndex = 0) { // int result = 0; // // Normalize ... barIndex = NormalizeInt(barIndex, 0); // // Validate ... if (mZigZagHandler == INVALID_HANDLE) { return result; } // // Copy ZigZag Values to Buffers ... result = CopyBuffer(mZigZagHandler, MAIN_LINE, 0, mLoopbackLength, mZigZagBuffer); // // Set ZigZag Buffers as Series ... ArraySetAsSeries(mZigZagBuffer, true); // if (result <= 0) { return result; } // // Filling ZigZag Pivots ... // // Clean Buffers ... SpecifiedClean(mZigZagPivotTimes); SpecifiedClean(mZigZagPivotPrices); SpecifiedClean(mZigZagPivotIsPeaks); SpecifiedClean(mZigZagPivotIndexes); // // Looping Through ZigZag Buffers ... XOHCL iBar; bool has = false; double iZigZag = 0; bool isIZigZagPeak = false; int count = ArraySize(mZigZagBuffer); for (int i = 0; i < count; i++) { // // Reading ZigZag Value ... iZigZag = mZigZagBuffer[i]; // // Validate ZigZag Values ... if (!NotEmptyZero(iZigZag)) { continue; } // // Check ZigZag Value Is Peak or Vale ... // // Initialize iBar ... has = iBar.Init( _Symbol, _Period, i // ); // // Validate Bar and also Exclude Most Recent Swing ... if (!has || iBar.Index() == 0) { // iBar.Clean(); continue; } // isIZigZagPeak = iZigZag == iBar.high; // // Filling Buffers ... Add( iBar.time, mZigZagPivotTimes // ); Add( iZigZag, mZigZagPivotPrices // ); Add( isIZigZagPeak, mZigZagPivotIsPeaks // ); Add( (double)iBar.Index(), mZigZagPivotIndexes // ); // // Cleanup Resources ... iBar.Clean(); } // return result; } // int ReadingZigZagPivots( int barIndex = 0, int requiredPivots = 15, int maxAllowedLoopback = 1500 // ) { // int result = 0; // // Cleanup Resources ... SpecifiedClean(mZigZagPivotTimes); SpecifiedClean(mZigZagPivotPrices); SpecifiedClean(mZigZagPivotIsPeaks); SpecifiedClean(mZigZagPivotIndexes); // // Normalize ... barIndex = NormalizeInt(barIndex, 0); requiredPivots = NormalizeInt(requiredPivots, 2); maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 100); // XOHCL iBar; bool has = false; double iZigZag = 0; bool isPeak = false; int idx = barIndex - 1; double tmpZigZagBuffer[]; int maxAllowed = barIndex + maxAllowedLoopback; while (idx < maxAllowed && ArraySize(mZigZagPivotPrices) < requiredPivots) { // idx++; // // Initializing Bar ... has = iBar.Init( _Symbol, _Period, idx // ); if (!has) { continue; } // // Reading ZigZag Value ... if (CopyBuffer(mZigZagHandler, MAIN_LINE, idx, 1, tmpZigZagBuffer) < 1) { // iBar.Clean(); continue; } // // Read ZigZag Value and Validate it ... iZigZag = tmpZigZagBuffer[0]; has = NotEmptyZero(iZigZag); if (!has) { // iBar.Clean(); SpecifiedClean(tmpZigZagBuffer); // continue; } // isPeak = iZigZag == iBar.high; // // Validate ZigZag Value for Ignore Zero ... if (iBar.Index() == barIndex) { // iBar.Clean(); SpecifiedClean(tmpZigZagBuffer); // continue; } // // Filling Pivots ... // Add( iZigZag, mZigZagPivotPrices // ); // Add( isPeak, mZigZagPivotIsPeaks // ); // Add( iBar.time, mZigZagPivotTimes // ); // Add( (double)iBar.Index(), mZigZagPivotIndexes // ); // // Cleanup Resources ... iBar.Clean(); SpecifiedClean(tmpZigZagBuffer); // // Check Can Break Loop ... has = idx >= maxAllowed || ArraySize(mZigZagPivotPrices) == requiredPivots; if (has) { break; } } // // Cleanup Resources ... SpecifiedClean(tmpZigZagBuffer); // result = ArraySize(mZigZagPivotPrices); // return result; } // void ProcessZigZagsPeaksAndVales() { // // Here we Parse ZigZag Values to Detect Peak or Vale ... // int count = 0; bool has = false; // // Extract mZigZag Peaks and Vales ... SpecifiedClean(mZigZagPeaks); SpecifiedClean(mZigZagVales); SpecifiedClean(mZigZagPeakTimes); SpecifiedClean(mZigZagValeTimes); SpecifiedClean(mZigZagPeakIndexes); SpecifiedClean(mZigZagValeIndexes); count = ArraySize(mZigZagPivotPrices); has = IsValidSize(count); if (!has) { return; } // double iZigZag = 0; double iZigZagIDX = -1; bool isIZigZagPeak = false; datetime iZigZagTime = NULL; for (int i = 0; i < count; i++) { // // Reading Required Values ... iZigZag = mZigZagPivotPrices[i]; iZigZagTime = mZigZagPivotTimes[i]; iZigZagIDX = mZigZagPivotIndexes[i]; isIZigZagPeak = mZigZagPivotIsPeaks[i]; // if (isIZigZagPeak) { // Add( iZigZag, mZigZagPeaks // ); // Add( iZigZagTime, mZigZagPeakTimes // ); // Add( iZigZagIDX, mZigZagPeakIndexes // ); } else { // Add( iZigZag, mZigZagVales // ); // Add( iZigZagTime, mZigZagValeTimes // ); // Add( iZigZagIDX, mZigZagValeIndexes // ); } } } // void ProcessZigZagsSupportsAnsResistances() { // int count = 0; bool has = false; double iValue = EMPTY_VALUE; double tmpValue = EMPTY_VALUE; // // Support ... // Supports Calculated based on Vales ... // tmpValue = EMPTY_VALUE; mMinorSupport = EMPTY_VALUE; mMajorSupport = EMPTY_VALUE; count = ArraySize(mZigZagVales); has = IsValidSize(count); if (has) { // for (int i = 0; i < count; i++) { // // Reading Indexed Value ... iValue = mZigZagVales[i]; // // Check Can Change Major Support ... has = !NotEmpty(mMajorSupport) || mMajorSupport > iValue; if (has) { // tmpValue = mMajorSupport; mMajorSupport = iValue; } else { // // Check Minor Support ... has = !NotEmpty(tmpValue) || tmpValue > iValue; if (has) { tmpValue = iValue; } } } // has = NotEmpty(tmpValue); if (has) { mMinorSupport = tmpValue; } } // // Resistance ... // Resistances Calculated based on Peaks ... // tmpValue = EMPTY_VALUE; mMinorResistance = EMPTY_VALUE; mMajorResistance = EMPTY_VALUE; count = ArraySize(mZigZagPeaks); has = IsValidSize(count); if (has) { // for (int i = 0; i < count; i++) { // // Reading Indexed Value ... iValue = mZigZagPeaks[i]; // // Check Can Change Major Resistance ... has = !NotEmpty(mMajorResistance) || mMajorResistance < iValue; if (has) { // tmpValue = mMajorResistance; mMajorResistance = iValue; } elsetmp { // // Check Minor Resistance ... has = !NotEmpty(tmpValue) || tmpValue < iValue; if (has) { tmpValue = iValue; } } } // has = NotEmpty(tmpValue); if (has) { mMinorResistance = tmpValue; } } } // bool CalculateZigZagLinearRegressionParameters() { // bool result = false; mUpperTrendDir = X_DIRECTION_NONE; mLowerTrendDir = X_DIRECTION_NONE; // // Peaks ... CalculateSlopeAndIntercept( mPeakSlope, mPeakIntercept, mZigZagPeakIndexes, mZigZagPeaks // ); // // Vales ... CalculateSlopeAndIntercept( mValeSlope, mValeIntercept, mZigZagValeIndexes, mZigZagVales // ); // result = (NotEmpty(mPeakSlope) && NotEmpty(mPeakIntercept)) || (NotEmpty(mValeSlope) && NotEmpty(mValeIntercept)); if (!result) { return result; } // // Detect Oldest and Youngest Time of Pivots ... // int idx = -1; bool has = false; // // Oldest ... has = FindOldestIndex( idx, mZigZagPivotTimes // ); if (has) { mFromTime = mZigZagPivotTimes[idx]; } // // Youngest ... has = FindYoungesttIndex( idx, mZigZagPivotTimes // ); if (has) { mToTime = mZigZagPivotTimes[idx]; } // // Validate Extracted Times ... result = IsSpecifiedValid(mToTime) && IsSpecifiedValid(mFromTime); if (!result) { return result; } // // Detect Extracted Times Bar Indexes ... // int mToIDX = iBarShift( _Symbol, _Period, mToTime // ); int mFromIDX = iBarShift( _Symbol, _Period, mFromTime // ); // // Validate Detected Bar Indexes ... result = IsValidIndex(mToIDX) && IsValidIndex(mFromIDX); if (!result) { return result; } // // Calculate Predictions ... // // Peak ... mPeakTo = PredictValue( mPeakSlope, mPeakIntercept, mToIDX // ); mPeakFrom = PredictValue( mPeakSlope, mPeakIntercept, mFromIDX // ); // // Vale ... mValeTo = PredictValue( mValeSlope, mValeIntercept, mToIDX // ); mValeFrom = PredictValue( mValeSlope, mValeIntercept, mFromIDX // ); // mUpperTrendDir = mPeakFrom < mPeakTo ? X_DIRECTION_BULLISH : mPeakFrom > mPeakTo ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; mLowerTrendDir = mValeFrom < mValeTo ? X_DIRECTION_BULLISH : mValeFrom > mValeTo ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; // // Prepare Support and Resistance Boxes ... // // Support ... // mSupportBox.Clean(); has = NotEmptyZero(mMinorSupport) && NotEmptyZero(mMajorSupport); if (has) { // mSupportBox.to = mToTime; mSupportBox.from = mFromTime; mSupportBox.symbol = _Symbol; mSupportBox.period = _Period; mSupportBox.type = "Support"; mSupportBox.upper = mMinorSupport; mSupportBox.lower = mMajorSupport; mSupportBox.dir = X_DIRECTION_BULLISH; } // // Resistance ... // mResistanceBox.Clean(); has = NotEmptyZero(mMinorResistance) && NotEmptyZero(mMajorResistance); if (has) { // mResistanceBox.to = mToTime; mResistanceBox.from = mFromTime; mResistanceBox.symbol = _Symbol; mResistanceBox.period = _Period; mResistanceBox.type = "Resistance"; mResistanceBox.upper = mMajorResistance; mResistanceBox.lower = mMinorResistance; mResistanceBox.dir = X_DIRECTION_BEARISH; } // result = mSupportBox.IsValid() || mResistanceBox.IsValid(); // return result; } // void DrawAnalysis() { // bool isCreated = false; // // Peak ... // // Cleanup Upper Object ... if (mUpperTrend != NULL) { // mUpperTrend.Delete(); mUpperTrend.Detach(); delete mUpperTrend; ZeroMemory(mUpperTrend); } // mUpperTrend = new CChartObjectTrend(); isCreated = mUpperTrend.Create( ChartID(), "UpperTrend", 0, mFromTime, mPeakFrom, mToTime, mPeakTo // ); if (isCreated) { // // Apply Styles ... // color upperColor = IsSpecifiedBullish(mUpperTrendDir) ? clrAqua : IsSpecifiedBearish(mUpperTrendDir) ? clrMagenta : clrGray; // Neutural ... // mUpperTrend.Width(2); mUpperTrend.RayRight(true); mUpperTrend.Color(upperColor); } // // Vale ... // // Cleanup Lower Object ... if (mLowerTrend != NULL) { // mLowerTrend.Delete(); mLowerTrend.Detach(); delete mLowerTrend; ZeroMemory(mLowerTrend); } // mLowerTrend = new CChartObjectTrend(); isCreated = mLowerTrend.Create( ChartID(), "LowerTrend", 0, mFromTime, mValeFrom, mToTime, mValeTo // ); if (isCreated) { // // Apply Styles ... // color lowerColor = IsSpecifiedBullish(mLowerTrendDir) ? clrAqua : IsSpecifiedBearish(mLowerTrendDir) ? clrMagenta : clrGray; // Neutural ... // mLowerTrend.Width(2); mLowerTrend.RayRight(true); mLowerTrend.Color(lowerColor); } // // Support ... // // Cleanup Support Object ... if (mSupportObj != NULL) { // mSupportObj.Delete(); mSupportObj.Detach(); delete mSupportObj; ZeroMemory(mSupportObj); } // isCreated = mSupportBox.IsValid(); if (isCreated) { // datetime to = TimeCurrent(); mSupportObj = new XCBoxObject(); isCreated = mSupportObj.Create( ChartID(), 0, "Support", mSupportBox.upper, mSupportBox.lower, mSupportBox.from, to // ); if (isCreated) { // // Apply Style ... mSupportObj.BoxWidth(2); mSupportObj.BoxColor(clrAqua); } } // // Resistance ... // // Cleanup Resistance Object ... if (mResistanceObj != NULL) { // mResistanceObj.Delete(); mResistanceObj.Detach(); delete mResistanceObj; ZeroMemory(mResistanceObj); } // isCreated = mResistanceBox.IsValid(); if (isCreated) { // datetime to = TimeCurrent(); mResistanceObj = new XCBoxObject(); isCreated = mResistanceObj.Create( ChartID(), 0, "Resistance", mResistanceBox.upper, mResistanceBox.lower, mResistanceBox.from, to // ); if (isCreated) { // // Apply Style ... mResistanceObj.BoxWidth(2); mResistanceObj.BoxColor(clrMagenta); } } } // int FindOldestIndex( int &index, datetime ×[] // ) { // bool result = false; // // Prepare ... index = -1; // // Validate ... if (!HasChild(times)) { return result; } // bool has = false; datetime tmpTime = NULL; for (int i = 0; i < ArraySize(times); i++) { // has = !IsSpecifiedValid(tmpTime) ? true : tmpTime > times[i]; if (has) { // index = i; tmpTime = times[i]; } } // // Validate result ... result = IsValidIndex(index) && IsSpecifiedValid(tmpTime); // return result; } // int FindYoungesttIndex( int &index, datetime ×[] // ) { // bool result = false; // // Prepare ... index = -1; // // Validate ... if (!HasChild(times)) { return result; } // bool has = false; datetime tmpTime = NULL; for (int i = 0; i < ArraySize(times); i++) { // has = !IsSpecifiedValid(tmpTime) ? true : tmpTime < times[i]; if (has) { // index = i; tmpTime = times[i]; } } // // Validate result ... result = IsValidIndex(index) && IsSpecifiedValid(tmpTime); // return result; } //