diff --git a/Documents/BKP/xfima.poi.analysis.tmp.code.mq5 b/Documents/BKP/xfima.poi.analysis.tmp.code.mq5 index cff0f141..09b58b22 100644 --- a/Documents/BKP/xfima.poi.analysis.tmp.code.mq5 +++ b/Documents/BKP/xfima.poi.analysis.tmp.code.mq5 @@ -1,186 +1,641 @@ - // // - // // Detect At lease Two PEAK and Two Vale ... - // XZigZagPoint tmpPoints[]; - // Copy( - // points, - // tmpPoints // - // ); +// // +// // Detect At lease Two PEAK and Two Vale ... +// XZigZagPoint tmpPoints[]; +// Copy( +// points, +// tmpPoints // +// ); - // // - // // Detect Highs ... +// // +// // Detect Highs ... - // // - // // Highest High ... +// // +// // Highest High ... - // // - // XZigZagPoint iZGPeak1; - // XZigZagPoint iZGPeak2; +// // +// XZigZagPoint iZGPeak1; +// XZigZagPoint iZGPeak2; - // // - // // First ... - // int idx = GetHighest( - // tmpPoints, - // X_ZIGZAG_POINT_TYPE_PEAK // - // ); - // result = IsValidIndex(idx); - // if (!result) - // { - // // - // Clean(); - // iZGPeak1.Clean(); - // iZGPeak2.Clean(); - // SpecifiedClean(tmpPoints); +// // +// // First ... +// int idx = GetHighest( +// tmpPoints, +// X_ZIGZAG_POINT_TYPE_PEAK // +// ); +// result = IsValidIndex(idx); +// if (!result) +// { +// // +// Clean(); +// iZGPeak1.Clean(); +// iZGPeak2.Clean(); +// SpecifiedClean(tmpPoints); - // // - // return result; - // } - // iZGPeak1 = tmpPoints[idx]; - // ArrayRemove( - // tmpPoints, - // idx, - // 1 // - // ); +// // +// return result; +// } +// iZGPeak1 = tmpPoints[idx]; +// ArrayRemove( +// tmpPoints, +// idx, +// 1 // +// ); - // // - // // Second ... - // idx = GetHighest( - // tmpPoints, - // X_ZIGZAG_POINT_TYPE_PEAK // - // ); - // result = IsValidIndex(idx); - // if (!result) - // { - // // - // Clean(); - // iZGPeak1.Clean(); - // iZGPeak2.Clean(); - // SpecifiedClean(tmpPoints); +// // +// // Second ... +// idx = GetHighest( +// tmpPoints, +// X_ZIGZAG_POINT_TYPE_PEAK // +// ); +// result = IsValidIndex(idx); +// if (!result) +// { +// // +// Clean(); +// iZGPeak1.Clean(); +// iZGPeak2.Clean(); +// SpecifiedClean(tmpPoints); - // // - // return result; - // } - // iZGPeak2 = tmpPoints[idx]; - // ArrayRemove( - // tmpPoints, - // idx, - // 1 // - // ); +// // +// return result; +// } +// iZGPeak2 = tmpPoints[idx]; +// ArrayRemove( +// tmpPoints, +// idx, +// 1 // +// ); - // // - // // Detect Lows ... +// // +// // Detect Lows ... - // // - // XZigZagPoint iZGVale1; - // XZigZagPoint iZGVale2; +// // +// XZigZagPoint iZGVale1; +// XZigZagPoint iZGVale2; - // // - // // First ... - // idx = GetLowest( - // tmpPoints, - // X_ZIGZAG_POINT_TYPE_VALE // - // ); - // result = IsValidIndex(idx); - // if (!result) - // { - // // - // Clean(); - // iZGPeak1.Clean(); - // iZGPeak2.Clean(); - // iZGVale1.Clean(); - // iZGVale2.Clean(); - // SpecifiedClean(tmpPoints); +// // +// // First ... +// idx = GetLowest( +// tmpPoints, +// X_ZIGZAG_POINT_TYPE_VALE // +// ); +// result = IsValidIndex(idx); +// if (!result) +// { +// // +// Clean(); +// iZGPeak1.Clean(); +// iZGPeak2.Clean(); +// iZGVale1.Clean(); +// iZGVale2.Clean(); +// SpecifiedClean(tmpPoints); - // // - // return result; - // } - // iZGVale1 = tmpPoints[idx]; - // ArrayRemove( - // tmpPoints, - // idx, - // 1 // - // ); +// // +// return result; +// } +// iZGVale1 = tmpPoints[idx]; +// ArrayRemove( +// tmpPoints, +// idx, +// 1 // +// ); - // // - // // Second ... - // idx = GetLowest( - // tmpPoints, - // X_ZIGZAG_POINT_TYPE_VALE // - // ); - // result = IsValidIndex(idx); - // if (!result) - // { - // // - // Clean(); - // iZGPeak1.Clean(); - // iZGPeak2.Clean(); - // iZGVale1.Clean(); - // iZGVale2.Clean(); - // SpecifiedClean(tmpPoints); +// // +// // Second ... +// idx = GetLowest( +// tmpPoints, +// X_ZIGZAG_POINT_TYPE_VALE // +// ); +// result = IsValidIndex(idx); +// if (!result) +// { +// // +// Clean(); +// iZGPeak1.Clean(); +// iZGPeak2.Clean(); +// iZGVale1.Clean(); +// iZGVale2.Clean(); +// SpecifiedClean(tmpPoints); - // // - // return result; - // } - // iZGVale2 = tmpPoints[idx]; - // ArrayRemove( - // tmpPoints, - // idx, - // 1 // - // ); +// // +// return result; +// } +// iZGVale2 = tmpPoints[idx]; +// ArrayRemove( +// tmpPoints, +// idx, +// 1 // +// ); - // // - // // Check Directions ... - // bool isBullish = - // // - // (iZGPeak1.time > iZGPeak2.time && - // iZGVale1.time < iZGVale2.time) - // // - // ; - // bool isBearish = - // // - // (iZGPeak1.time < iZGPeak2.time && - // iZGVale1.time > iZGVale2.time) - // // - // ; - // result = - // (isBullish && !isBearish) || - // (isBearish && !isBullish); - // if (!result) - // { - // // - // Clean(); - // iZGPeak1.Clean(); - // iZGPeak2.Clean(); - // iZGVale1.Clean(); - // iZGVale2.Clean(); - // SpecifiedClean(tmpPoints); +// // +// // Check Directions ... +// bool isBullish = +// // +// (iZGPeak1.time > iZGPeak2.time && +// iZGVale1.time < iZGVale2.time) +// // +// ; +// bool isBearish = +// // +// (iZGPeak1.time < iZGPeak2.time && +// iZGVale1.time > iZGVale2.time) +// // +// ; +// result = +// (isBullish && !isBearish) || +// (isBearish && !isBullish); +// if (!result) +// { +// // +// Clean(); +// iZGPeak1.Clean(); +// iZGPeak2.Clean(); +// iZGVale1.Clean(); +// iZGVale2.Clean(); +// SpecifiedClean(tmpPoints); - // // - // return result; - // } +// // +// return result; +// } - // // - // // Setting Direction ... - // dir = - // isBullish - // ? X_DIRECTION_BULLISH - // : isBearish - // ? X_DIRECTION_BEARISH - // : X_DIRECTION_NONE; +// // +// // Setting Direction ... +// dir = +// isBullish +// ? X_DIRECTION_BULLISH +// : isBearish +// ? X_DIRECTION_BEARISH +// : X_DIRECTION_NONE; - // // - // // Setting Points ... - // Copy( - // points, - // pivots // - // ); +// // +// // Setting Points ... +// Copy( +// points, +// pivots // +// ); +// +// Cleanup Resources ... +// iZGPeak1.Clean(); +// iZGPeak2.Clean(); +// iZGVale1.Clean(); +// iZGVale2.Clean(); +// SpecifiedClean(tmpPoints); +/** + * Analyse Market Structure ... + * + * @param bar: XOHCL, Specified Bar ... + * @param _pivots: XZigZagPivot, Specified ZigZag Points Collection ... + * + * @return ( bool ) + */ +bool Analyse( + XOHCL &bar, + XZigZagPivot &_pivots[] // +) +{ + // + bool result = false; - + // + // Validate ... + result = bar.IsValid() && + HasChild(_pivots) && + bar.symbol == _pivots[0].symbol; + if (!result) + { // - // Cleanup Resources ... - // iZGPeak1.Clean(); - // iZGPeak2.Clean(); - // iZGVale1.Clean(); - // iZGVale2.Clean(); - // SpecifiedClean(tmpPoints); + Clean(); + return result; + } + + // + // AssignSymbol and Period ... + time = bar.time; + symbol = bar.symbol; + period = bar.period; + Copy(_pivots, pivots); + + // + // Calculate Peaks and Vales Regressions ... + + // + // Peaks Processing ... + double mPeak = 0; + double bPeak = 0; + result = ValidateZigZagPivots( + mPeak, + bPeak, + _pivots, + X_ZIGZAG_PIVOT_TYPE_PEAK // + ); + + // + // Vales Processing ... + double mVale = 0; + double bVale = 0; + result = + result && + ValidateZigZagPivots( + mVale, + bVale, + _pivots, + X_ZIGZAG_PIVOT_TYPE_VALE // + ); + if (!result) + { + // + Clean(); + // SpecifiedClean(recentPeaks); + // SpecifiedClean(recentVales); + + // + return result; + } + + // // + // // Extracting Pivots ... + // int numberOfPivots = 2; + + // // + // // Reading Recent Peaks ... + // XZigZagPivot recentPeaks[]; + // int recentPeaksCount = GetRecent( + // _pivots, + // recentPeaks, + // numberOfPivots, + // X_ZIGZAG_PIVOT_TYPE_PEAK // + // ); + + // // + // // Reading Recent Vales ... + // XZigZagPivot recentVales[]; + // int recentValesCount = GetRecent( + // _pivots, + // recentVales, + // numberOfPivots, + // X_ZIGZAG_PIVOT_TYPE_VALE // + // ); + + // // + // // Validate Pivots ... + // result = + // recentPeaksCount >= numberOfPivots && + // recentValesCount >= numberOfPivots; + // if (!result) + // { + // // + // Clean(); + // SpecifiedClean(recentPeaks); + // SpecifiedClean(recentVales); + + // // + // return result; + // } + + // // + // // Detect Direction ... + + // // + // int zIdx = 0; + // int pIdx = numberOfPivots - 1; + + // // + // bool isBullish = + // recentPeaks[zIdx].value > recentPeaks[pIdx].value && + // recentVales[zIdx].value > recentVales[pIdx].value; + + // // + // bool isBearish = + // recentPeaks[zIdx].value < recentPeaks[pIdx].value && + // recentVales[zIdx].value < recentVales[pIdx].value; + + // // + // result = isBullish || isBearish; + // if (!result) + // { + // // + // Clean(); + // SpecifiedClean(recentPeaks); + // SpecifiedClean(recentVales); + + // // + // return result; + // } + + // // + // dir = + // isBullish + // ? X_DIRECTION_BULLISH + // : X_DIRECTION_BEARISH; + + // + // Calculate Support and Resistance ... + + // + // Validate ... + result = IsValid(); + if (!result) + { + Clean(); + } + + // + // SpecifiedClean(recentPeaks); + // SpecifiedClean(recentVales); + + // + return result; +} + +bool ValidateZigZagPivots( + double &_pivot, + double &_processed, + XZigZagPivot &_pivots[], + ENUM_X_ZIGZAG_POINT_TYPE _type // +) +{ + // + bool result = false; + + // + // Prepare ... + _pivot = 0; + _processed = 0; + + // + // Validate ... + result = HasChild(_pivots); + if (!result) + { + return result; + } + + // + // Define Required Variables for Calculations ... + double sumT = 0; + double sumP = 0; + double sumTP = 0; + double sumT2 = 0; + bool has = false; + int typeCount = 0; + + // + // Loop Through Pivots to Calculate Specified + // Type Pivots Summaries ... + int count = ArraySize(_pivots); + for (int i = 0; i < count; i++) + { + // + // Check Type Passed ... + has = + !IsXValid(_type) + ? true + : _type == _pivots[i].type; + if (!has) + { + continue; + } + + // + typeCount++; + double iP = _pivots[i].value; + double iT = (double)_pivots[i].time; + + // + sumT += iT; + sumP += iP; + sumTP += iT * iP; + sumT2 += iT * iP; + } + + // + // Calculate Process Values ... + double denominator = typeCount * sumT2 - sumT * sumT; + if (denominator != 0) + { + // + _pivot = (typeCount * sumTP - sumT * sumP) / denominator; + _processed = (sumP - _pivot * sumT) / typeCount; + } + else + { + _processed = sumP / typeCount; + } + + // + // Validating Result ... + result = _pivot > 0 && + _processed > 0; + + // + return result; +} + +/** + * Analyse Market Structure ... + * + * @param bar: XOHCL, Specified Bar ... + * @param _pivots: XZigZagPivot, Specified ZigZag Points Collection ... + * + * @return ( bool ) + */ +bool Analyse( + XOHCL &bar, + XZigZagPivot &_pivots[] // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + HasChild(_pivots) && + bar.symbol == _pivots[0].symbol; + if (!result) + { + // + Clean(); + return result; + } + + // + // Assign Requirements ... + + // + time = bar.time; + symbol = bar.symbol; + period = bar.period; + Copy(_pivots, pivots); + + // + int oldestPeakIdx = GetOldest(pivots, X_ZIGZAG_PIVOT_TYPE_PEAK); + int oldestValeIdx = GetOldest(pivots, X_ZIGZAG_PIVOT_TYPE_VALE); + int youngestPeakIdx = GetYoungest(pivots, X_ZIGZAG_PIVOT_TYPE_PEAK); + int youngestValeIdx = GetYoungest(pivots, X_ZIGZAG_PIVOT_TYPE_VALE); + + // + // Calculate Peaks and Vales Regressions ... + + // + // Peaks Processing ... + double mPeak = 0; + double bPeak = 0; + bool hasPeak = ValidateZigZagPivots( + mPeak, + bPeak, + pivots, + X_ZIGZAG_PIVOT_TYPE_PEAK // + ); + + // + // Vales Processing ... + double mVale = 0; + double bVale = 0; + bool hasVale = ValidateZigZagPivots( + mVale, + bVale, + pivots, + X_ZIGZAG_PIVOT_TYPE_VALE // + ); + + // + // Validate Calculated requirements ... + result = + (hasPeak || hasVale) && + (IsValidIndex(oldestPeakIdx) && + IsValidIndex(oldestValeIdx) && + IsValidIndex(youngestPeakIdx) && + IsValidIndex(youngestValeIdx)); + if (!result) + { + // + Clean(); + return result; + } + + // + // Calculating Values ... + + // + peakToTime = pivots[youngestPeakIdx].time; + peakFromTime = pivots[oldestPeakIdx].time; + + // + valeToTime = pivots[youngestValeIdx].time; + valeFromTime = pivots[oldestValeIdx].time; + + // + // Check Different Senarios ... + // 1-Valid Peak and Valid Vale Exists ... + if (hasPeak && hasVale) + { + // + // When Slopes Have same Sign, Use Average Slope for Parallel Lines ... + if (mPeak * mVale > 0) + { + // + // Calculating Parallel Slopes ... + double slopeParallel = (mPeak + mVale) / 2; + double bParallelPeak = pivots[youngestPeakIdx].value - slopeParallel * (double)peakToTime; + double bParallelVale = pivots[youngestValeIdx].value - slopeParallel * (double)valeToTime; + + // + // Peak ... + peakTo = slopeParallel * (double)peakToTime + bParallelPeak; + peakFrom = slopeParallel * (double)peakFromTime + bParallelPeak; + + // + // Vale ... + valeTo = slopeParallel * (double)valeToTime + bParallelVale; + valeFrom = slopeParallel * (double)valeFromTime + bParallelVale; + } + else + // + // separate trendlines if slopes differ ... + { + // + // Peak ... + peakTo = mPeak * (double)peakToTime + bPeak; + peakFrom = mPeak * (double)peakFromTime + bPeak; + + // + // Vale ... + valeTo = mVale * (double)valeToTime + bVale; + valeFrom = mVale * (double)valeFromTime + bVale; + } + } + else + // + // Only one of them Exists ... + { + // + // Valid Peak ... + if (hasPeak) + { + // + // Peak ... + peakTo = mPeak * (double)peakToTime + bPeak; + peakFrom = mPeak * (double)peakFromTime + bPeak; + } + + // + // Valid Vale ... + if (hasVale) + { + // + // Vale ... + valeTo = mVale * (double)valeToTime + bVale; + valeFrom = mVale * (double)valeFromTime + bVale; + } + } + + // + // Detecting Direction ... + + // + bool isBullish = + valeTo > valeFrom || + (valeTo > valeFrom && + peakTo > peakFrom); + + // + bool isBearish = + peakTo < peakFrom || + (peakTo < peakFrom && + valeTo < valeFrom); + + // + // Validate When Only One Direction Exists ... + result = + (isBullish && !isBearish) || + (isBearish && !isBullish); + if (!result) + { + // + Clean(); + return result; + } + + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Calculate Support and Resistance ... + + // + // Validate ... + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; +} diff --git a/Experts/TestRegresser.mq5 b/Experts/TestRegresser.mq5 new file mode 100644 index 00000000..af399abe --- /dev/null +++ b/Experts/TestRegresser.mq5 @@ -0,0 +1,294 @@ +//+------------------------------------------------------------------+ +//| 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 "../Libraries/x-saherelm.common.lib.mq5" +#include + +// +// Inputs ... +input int mLoopbackLength = 200; +input ENUM_X_PRICE mPriceType = X_PRICE_HIGH; + +// +// Variables ... +double mSumX = 0; +double mSumY = 0; +double mSumXY = 0; +double mSumX2 = 0; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // + for (int i = 0; i < mLoopbackLength; i++) + { + // + double iY = GetAppliedPrice( + _Symbol, + _Period, + i, + mPriceType // + ); + double iX = i + 1; + + // + mSumX += iX; + mSumY += iY; + mSumXY += (iX * iY); + mSumX2 += (iX * iX); + } + + // + int n = mLoopbackLength; + double slope = (n * mSumXY - mSumX * mSumY) / (n * mSumX2 - mSumX * mSumX); + double intercept = (mSumY - slope * mSumX) / n; + + // + double xData[]; + double yData[]; + int xDataCount = CollectData( + xData, + yData // + ); + double _cSlope; + double _cIntercept; + int calculatedCount = CalculateSlopeandIntercept( + _cSlope, + _cIntercept, + xData, + yData // + ); + + // + datetime time1 = iTime(_Symbol, _Period, mLoopbackLength); + datetime time2 = iTime(_Symbol, _Period, 0); + + // + double price1 = (intercept + slope * mLoopbackLength); + double price2 = (intercept + slope); + + // + double cPrice1 = PredictValue( + _cSlope, + _cIntercept, + time1 // + ); + double cPrice2 = PredictValue( + _cSlope, + _cIntercept, + time2 // + ); + + // + string name = "TrendLine"; + string cName = "cTrendLine"; + + // + CChartObjectTrend *iTrend = new CChartObjectTrend(); + bool isCreated = iTrend.Create( + ChartID(), + name, + 0, + time1, + price1, + time2, + price2 // + ); + if (isCreated) + { + // + // Styling Trend Line ... + } + + // + CChartObjectTrend *iCTrend = new CChartObjectTrend(); + isCreated = iCTrend.Create( + ChartID(), + cName, + 0, + time1, + cPrice1, + time2, + cPrice2 // + ); + if (isCreated) + { + // + // Styling Trend Line ... + } + + // + return (INIT_SUCCEEDED); +} +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + //--- +} +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + //--- +} +//+------------------------------------------------------------------+ + +// +int CollectData( + double &xData[], + double &yData[], + int barIndex = 0 // +) +{ + // + int result = false; + + // + SpecifiedClean(xData); + SpecifiedClean(yData); + + // + barIndex = NormalizeInt(barIndex, 0); + + // + int start = barIndex; + int end = start + mLoopbackLength; + for (int i = start; i < end; i++) + { + // + double iY = GetAppliedPrice( + _Symbol, + _Period, + i // + ); + + // + datetime iTime = iTime( + _Symbol, + _Period, + i // + ); + double iX = i + 1; // (double)TimeToSeconds(iTime); + + // + Add( + iX, + xData // + ); + + // + Add( + iY, + yData // + ); + } + + // + result = ArraySize(xData); + + // + return result; +} + +// +int CalculateSlopeandIntercept( + double &_slope, + double &_intercept, + double &xData[], + double &yData[] // +) +{ + // + int result = 0; + + // + bool has = false; + + // + _slope = 0; + _intercept = 0; + + // + if (!HasChild(xData) || + !HasChild(yData)) + { + return result; + } + + // + double sumX = 0; + double sumY = 0; + double sumXY = 0; + double sumX2 = 0; + + // + double x = 0; + double y = 0; + int end = MathMin(ArraySize(xData), ArraySize(yData)); + for (int i = 0; i < end; i++) + { + // + double x = xData[i]; + double y = yData[i]; + + // + sumX += x; + sumY += y; + sumXY += x * y; + sumX2 += x * x; + } + + // + int n = end; + _slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX); + _intercept = (sumY - _slope * sumX) / n; + + // + result = n; + + // + return result; +} + +// +double PredictValue( + double &_slope, + double &_intercept, + datetime forTime // +) +{ + // + double result = 0; + + // + if (!IsSpecifiedValid(forTime)) + { + return result; + } + + // + double forX = iBarShift( + _Symbol, + _Period, + forTime // + ); // (double)TimeToSeconds(forTime); + result = (_intercept + _slope * forX); + + // + return result; +} + +// \ No newline at end of file diff --git a/Experts/x-saherelm.xfima.backtester.ea.mq5 b/Experts/x-saherelm.xfima.backtester.ea.mq5 index 6bb562d5..1eb521d1 100644 --- a/Experts/x-saherelm.xfima.backtester.ea.mq5 +++ b/Experts/x-saherelm.xfima.backtester.ea.mq5 @@ -1147,34 +1147,175 @@ void DetectPatterns() { // // ZIGZAG Pattern ... - if (detectZIGZAGPatterns) + // if (detectZIGZAGPatterns) + // { + // // + // // Detect Market Analysis ... + // XZigZagAnalysis zAnalysis; + // has = fima2Signaller.fimaPOIDetector.AnalyseMarketUsingZigZag( + // cBar, + // cBar.period, + // fima2Signaller.fimaHelper, + // zAnalysis, + // 15 // + // ); + // if (has) + // { + // // + // Print(ShortName + zAnalysis.GetMessage()); + + // // + // XCZigZagAnalysisObject *iObj; + // has = fima2Signaller.fimaPOIDrawer.DrawZigZagMarketAnalysisByPV( + // iObj, + // zAnalysis // + // ); + // if (has) + // { + // draws.Add(iObj); + // } + // } + // } + + // + // Reading Pivots ... + double iLows[]; + double iHighs[]; + double lowTo = 0; + double highTo = 0; + double lowFrom = 0; + double highFrom = 0; + datetime lowToTime = NULL; + datetime highToTime = NULL; + datetime lowFromTime = NULL; + datetime highFromTime = NULL; + double lowsSlope = EMPTY_VALUE; + double highsSlope = EMPTY_VALUE; + double lowsIntercept = EMPTY_VALUE; + double highsIntercept = EMPTY_VALUE; + + // + int iLoopbackLength = 50; + for (int i = 0; i < iLoopbackLength; i++) { // - // Detect Market Analysis ... - XZigZagAnalysis zAnalysis; - has = fima2Signaller.fimaPOIDetector.AnalyseMarketUsingZigZag( - cBar, - cBar.period, - fima2Signaller.fimaHelper, - zAnalysis, - 15 // - ); - if (has) - { - // - Print(ShortName + zAnalysis.GetMessage()); + double iLowPrice = iLow(_Symbol, _Period, i); + double iHighPrice = iHigh(_Symbol, _Period, i); - // - XCZigZagAnalysisObject *iObj; - has = fima2Signaller.fimaPOIDrawer.DrawZigZagMarketAnalysis( - iObj, - zAnalysis // - ); - if (has) - { - draws.Add(iObj); - } - } + // + Add( + iLowPrice, + iLows // + ); + Add( + iHighPrice, + iHighs // + ); + } + has = CalculateLinearRegression( + lowsSlope, + lowsIntercept, + iLows, + 0, + 0 // + ); + if (has) + { + // + lowToTime = GetBarTime( + _Symbol, + _Period, + 0 // + ); + lowTo = CalculateValueBySlopeIntercept( + lowsSlope, + lowsIntercept, + 0 // + ); + + // + lowFromTime = GetBarTime( + _Symbol, + _Period, + iLoopbackLength // + ); + lowFrom = CalculateValueBySlopeIntercept( + lowsSlope, + lowsIntercept, + iLoopbackLength // + ); + } + + // + has = CalculateLinearRegression( + highsSlope, + highsIntercept, + iHighs, + 0, + 0 // + ); + if (has) + { + // + highToTime = GetBarTime( + _Symbol, + _Period, + 0 // + ); + highTo = CalculateValueBySlopeIntercept( + highsSlope, + highsIntercept, + 0 // + ); + + // + highFromTime = GetBarTime( + _Symbol, + _Period, + iLoopbackLength // + ); + highFrom = CalculateValueBySlopeIntercept( + highsSlope, + highsIntercept, + iLoopbackLength // + ); + } + + // + // Try to Draw ... + + // + // Low ... + CChartObjectTrend *iLowTrend; + has = fima2Signaller.fimaPOIDrawer.DrawTrendLine( + lowFrom, + lowFromTime, + lowTo, + lowToTime, + iLowTrend, + "LOW_TREMD", + true // Ray Right ... + ); + if (has) + { + draws.Add(iLowTrend); + } + + // + // High ... + CChartObjectTrend *iHighTrend; + has = fima2Signaller.fimaPOIDrawer.DrawTrendLine( + highFrom, + highFromTime, + highTo, + highToTime, + iHighTrend, + "HIGH_TREMD", + true // Ray Right ... + ); + if (has) + { + draws.Add(iHighTrend); } } diff --git a/Libraries/x-saherelm.common.extensions.lib.mq5 b/Libraries/x-saherelm.common.extensions.lib.mq5 index ac070026..afca0c1c 100644 --- a/Libraries/x-saherelm.common.extensions.lib.mq5 +++ b/Libraries/x-saherelm.common.extensions.lib.mq5 @@ -6641,22 +6641,22 @@ int GetPriceBoundary( /** * Get Applied Price Buffer ... - * + * * @param mType: ENUM_X_PRICE, Specified Price Type ... * @param dest: double, Holds Destination Prices ... * @param mOpen: double collection, Open Prices ... * @param mHigh: double collection, High Prices ... * @param mLow: double collection, Low Prices ... * @param mClose: double collection, Close Prices ... - * + * * @return ( int ) */ int GetAppliedPrice( ENUM_X_PRICE mType, double &dest[], - const double &mOpen[], // Open Prices - const double &mHigh[], // High Preices - const double &mLow[], // Low Prices + const double &mOpen[], // Open Prices + const double &mHigh[], // High Preices + const double &mLow[], // Low Prices const double &mClose[] // Close Prices ) { @@ -7061,3 +7061,135 @@ bool SetChartVolumesColor( // // +// START Linear Regression ... +// + +/** + * Linear Regression Based Calculate Data ... + * int this Senario X Axis is Buffer Index ... + * + * @param _slope: double, refrence for Calculated Slope ... + * @param _intercept: double, reference for Calculated Intercept ... + * @param _source: double, Y Axis Valus Collection ... + * @param _start: int, start Index ... + * @param _count: int, number of Calculations ... + * + * @return ( bool ) + */ +bool CalculateLinearRegression( + double &_slope, + double &_intercept, + double &_source[], + int _start = 0, + int _count = 0 // +) +{ + // + bool result = false; + + // + // Prepare ... + _slope = EMPTY_VALUE; + _intercept = EMPTY_VALUE; + + // + // Validate ... + int count = ArraySize(_source); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + // Normalize ... + _start = NormalizeInt(_start, 0, count - 1); + if (_count == 0 || _count + _start >= count) + { + // + // Get Whole Array ... + _count = count - 1 - _start; + } + int _end = _start + _count; + + // + // Define Requirements ... + double sumX = 0; + double sumY = 0; + double sumXY = 0; + double sumX2 = 0; + + // + // Looping Through Source Buffer to Cellect Data ... + for (int i = _start; i < _end; i++) + { + // + double x = i + 1; + double y = _source[i]; + + // + sumX += x; + sumY += y; + sumXY += x * y; + sumX2 += x * x; + } + + // + // Calculate Slope and Intercept ... + int n = _count; + _slope = ((n * sumXY) - (sumX * sumY)) / ((n * sumX2) - (sumX * sumX)); + _intercept = ((sumY - _slope) * sumX) / n; + + // + result = sumX > 0 && + sumY > 0 && + sumXY > 0 && + sumX2 > 0 && + NotEmpty(_slope) && + NotEmpty(_intercept); + if (!result) + { + // + _slope = EMPTY_VALUE; + _intercept = EMPTY_VALUE; + } + + // + return result; +} + +double CalculateValueBySlopeIntercept( + double _slope, + double _intercept, + int _index // +) +{ + // + double result = EMPTY_VALUE; + + // + // Normalize Index ... + _index = NormalizeInt(_index, 1); + + // + // Validate ... + if ( + !NotEmpty(_slope) || + !NotEmpty(_intercept) || + !IsValidIndex(_index)) + { + return result; + } + + // + result = (_intercept + _slope * _index); + + // + return result; +} + +// +// END Linear Regression ... +// + +// diff --git a/XFIMAEA/Classes/x-saherelm.xfima.x-poi.drawer.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.x-poi.drawer.class.mq5 index 6e8f2518..63c4eb91 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.x-poi.drawer.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.x-poi.drawer.class.mq5 @@ -44,7 +44,7 @@ class XCXFIMAPOIDrawer : public XCPOIDrawer * * @return ( bool ) */ - bool DrawZigZagMarketAnalysis( + bool DrawZigZagMarketAnalysisByPV( XCZigZagAnalysisObject *&object, XZigZagAnalysis &model, bool rayRight = false, @@ -69,7 +69,78 @@ class XCXFIMAPOIDrawer : public XCPOIDrawer // object = new XCZigZagAnalysisObject(); - result = object.Create( + result = object.CreateByPV( + ChartIdentification(), + SubWindowIdentification(), + model // + ); + if (result) + { + // + // Apply Style ... + bool isBullish = model.IsBullish(); + + // + XPOIStyle style; + if (isBullish) + { + style = defaultBullishStyle; + } + else + { + style = defaultBearishStyle; + } + + // + ApplyZigZagMarketAnalysisStyle( + object, + style, + true, // Ray Right ... + false // Ray Left ... + ); + } + + // + return result; + } + + /** + * Draw Specified XZigZagMarketStyle on Chart ... + * + * @param object: XCZigZagAnalysisObject, pointer reference to Drawn Object ... + * @param model: XZigZagAnalysis, reference to Model ... + * @param numberOfPivots: int, required number of pivots for Draw Trends ... + * @param rayRight: bool, Ray To Right ... + * @param rayLeft: bool, Ray To Left ... + * + * @return ( bool ) + */ + bool DrawZigZagMarketAnalysisByRecent( + XCZigZagAnalysisObject *&object, + XZigZagAnalysis &model, + bool rayRight = false, + bool rayLeft = false, + int numberOfPivots = 2 // + ) + { + // + bool result = false; + + // + // Prepare ... + object = NULL; + + // + // Validate ... + result = model.IsValid(); + if (!result) + { + return result; + } + + // + object = new XCZigZagAnalysisObject(); + result = object.CreateByRecent( ChartIdentification(), SubWindowIdentification(), model, @@ -96,8 +167,8 @@ class XCXFIMAPOIDrawer : public XCPOIDrawer ApplyZigZagMarketAnalysisStyle( object, style, - false, // Ray Right ... - true // Ray Left ... + true, // Ray Right ... + false // Ray Left ... ); } diff --git a/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 b/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 index f50f084b..87c6ba2d 100644 --- a/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 +++ b/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 @@ -570,7 +570,20 @@ struct XZigZagAnalysis XZigZagPivot pivots[]; // ZigZag Pivots ... // - ENUM_X_DIRECTION dir; // Direction ... + // Calculated Values ... + double peakTo; // Recent Peak .. + double valeTo; // Recent Vale ... + double peakFrom; // Previous Peak ... + double valeFrom; // Previous Vale ... + double peakSlope; // Calculated Slope for Peak ... + double valeSlope; // Calculated Slope for Vale ... + datetime peakToTime; // Recent Peak Time ... + datetime valeToTime; // Recent Vale Time ... + double peakIntercept; // Calculated Intercept for Peak ... + double valeIntercept; // Calculated Intercept for Vale ... + ENUM_X_DIRECTION dir; // Direction ... + datetime peakFromTime; // Previous Peak Time ... + datetime valeFromTime; // Previous Vale Time ... // // Constructor ... @@ -611,78 +624,191 @@ struct XZigZagAnalysis } // - // AssignSymbol and Period ... + // Assign Requirements ... + + // time = bar.time; symbol = bar.symbol; period = bar.period; + Copy(_pivots, pivots); // - // Extracting Pivots ... - int numberOfPivots = 2; + int oldestPeakIdx = GetOldest(pivots, X_ZIGZAG_PIVOT_TYPE_PEAK); + int oldestValeIdx = GetOldest(pivots, X_ZIGZAG_PIVOT_TYPE_VALE); + int youngestPeakIdx = GetYoungest(pivots, X_ZIGZAG_PIVOT_TYPE_PEAK); + int youngestValeIdx = GetYoungest(pivots, X_ZIGZAG_PIVOT_TYPE_VALE); // - // Reading Recent Peaks ... - XZigZagPivot recentPeaks[]; - int recentPeaksCount = GetRecent( - _pivots, - recentPeaks, - numberOfPivots, - X_ZIGZAG_PIVOT_TYPE_PEAK // - ); + // Calculate Peaks and Vales Regressions ... // - // Reading Recent Vales ... - XZigZagPivot recentVales[]; - int recentValesCount = GetRecent( - _pivots, - recentVales, - numberOfPivots, - X_ZIGZAG_PIVOT_TYPE_VALE // - ); + // Peak Time ... + peakToTime = pivots[youngestPeakIdx].time; + peakFromTime = pivots[oldestPeakIdx].time; // - // Validate Pivots ... + // Vale Time ... + valeToTime = pivots[youngestValeIdx].time; + valeFromTime = pivots[oldestValeIdx].time; + + // + // Validating Calculated Peaks and Vales Times ... result = - recentPeaksCount >= numberOfPivots && - recentValesCount >= numberOfPivots; + (IsSpecifiedValid(valeToTime) && + IsSpecifiedValid(valeFromTime)) || + (IsSpecifiedValid(peakToTime) && + IsSpecifiedValid(peakFromTime)); if (!result) { // Clean(); - SpecifiedClean(recentPeaks); - SpecifiedClean(recentVales); - - // return result; } // - // Detect Direction ... + // Calculate Slope and Intercepts ... // - int zIdx = 0; - int pIdx = numberOfPivots - 1; - - // - bool isBullish = - recentPeaks[zIdx].value > recentPeaks[pIdx].value && - recentVales[zIdx].value > recentVales[pIdx].value; - - // - bool isBearish = - recentPeaks[zIdx].value < recentPeaks[pIdx].value && - recentVales[zIdx].value < recentVales[pIdx].value; - - // - result = isBullish || isBearish; + // Peaks ... + result = CalculateZigZagLinearRegression( + peakSlope, + peakIntercept, + pivots, + X_ZIGZAG_PIVOT_TYPE_PEAK // + ); if (!result) { // Clean(); - SpecifiedClean(recentPeaks); - SpecifiedClean(recentVales); + return result; + } + // + // Vales ... + result = CalculateZigZagLinearRegression( + valeSlope, + valeIntercept, + pivots, + X_ZIGZAG_PIVOT_TYPE_VALE // + ); + if (!result) + { // + Clean(); + return result; + } + + // + // Calculate Peaks and Vales ... + + // + // Peaks ... + + // + int iPeakToIDX = GetBarIndex( + symbol, + period, + peakToTime // + ); + if (IsValidIndex(iPeakToIDX)) + { + // + peakTo = CalculateValueBySlopeIntercept( + peakSlope, + peakIntercept, + iPeakToIDX // + ); + } + + // + int iPeakFromIDX = GetBarIndex( + symbol, + period, + peakFromTime // + ); + if (IsValidIndex(iPeakFromIDX)) + { + // + peakFrom = CalculateValueBySlopeIntercept( + peakSlope, + peakIntercept, + iPeakFromIDX // + ); + } + + // + // Vales ... + + // + int iValeToIDX = GetBarIndex( + symbol, + period, + valeToTime // + ); + if (IsValidIndex(iValeToIDX)) + { + // + valeTo = CalculateValueBySlopeIntercept( + valeSlope, + valeIntercept, + iValeToIDX // + ); + } + + // + int iValeFromIDX = GetBarIndex( + symbol, + period, + valeFromTime // + ); + if (IsValidIndex(iValeFromIDX)) + { + // + valeFrom = CalculateValueBySlopeIntercept( + valeSlope, + valeIntercept, + iValeFromIDX // + ); + } + + // + // Validating Calculated Peaks and Vales ... + result = + (NotEmpty(valeTo) && + NotEmpty(valeFrom) > 0) || + (NotEmpty(peakTo) > 0 && + NotEmpty(peakFrom) > 0); + if (!result) + { + // + Clean(); + return result; + } + + // + // Detecting Direction ... + + // + bool isBullish = + valeTo > valeFrom || + (valeTo > valeFrom && + peakTo > peakFrom); + + // + bool isBearish = + peakTo < peakFrom || + (peakTo < peakFrom && + valeTo < valeFrom); + + // + // Validate When Only One Direction Exists ... + result = + (isBullish && !isBearish) || + (isBearish && !isBullish); + if (!result) + { + // + Clean(); return result; } @@ -692,9 +818,6 @@ struct XZigZagAnalysis ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; - // - Copy(_pivots, pivots); - // // Calculate Support and Resistance ... @@ -706,10 +829,6 @@ struct XZigZagAnalysis Clean(); } - // - SpecifiedClean(recentPeaks); - SpecifiedClean(recentVales); - // return result; } @@ -729,6 +848,16 @@ struct XZigZagAnalysis dir = X_DIRECTION_NONE; SpecifiedClean(pivots); + // + peakTo = 0; + valeTo = 0; + peakFrom = 0; + valeFrom = 0; + peakToTime = NULL; + valeToTime = NULL; + peakFromTime = NULL; + valeFromTime = NULL; + // ZeroMemory(this); } @@ -752,6 +881,30 @@ struct XZigZagAnalysis IsSpecifiedValid(symbol) && IsSpecifiedValid(period) // + && + // + ( + // + // Validate Peak ... + (peakTo > 0 && + peakFrom > 0 && + peakSlope != EMPTY_VALUE && + peakIntercept != EMPTY_VALUE && + IsSpecifiedValid(peakToTime) && + IsSpecifiedValid(peakFromTime)) + // + || + // + // Validate Vale ... + (valeTo > 0 && + valeFrom > 0 && + valeSlope != EMPTY_VALUE && + valeIntercept != EMPTY_VALUE && + IsSpecifiedValid(valeToTime) && + IsSpecifiedValid(valeFromTime)) + // + ) + // ; // @@ -1337,7 +1490,7 @@ class XCZigZagAnalysisObject : public XCBaseObject * * @return ( bool ) */ - bool Create( + bool CreateByRecent( long chart_id, int window, XZigZagAnalysis &model, @@ -1392,10 +1545,10 @@ class XCZigZagAnalysisObject : public XCBaseObject chart_id, upperName, window, - rPeaks[0].time, - rPeaks[0].value, rPeaks[numberOfPivots - 1].time, - rPeaks[numberOfPivots - 1].value // + rPeaks[numberOfPivots - 1].value, + rPeaks[0].time, + rPeaks[0].value // ); if (!result) { @@ -1408,10 +1561,93 @@ class XCZigZagAnalysisObject : public XCBaseObject chart_id, lowerName, window, - rVales[0].time, - rVales[0].value, rVales[numberOfPivots - 1].time, - rVales[numberOfPivots - 1].value // + rVales[numberOfPivots - 1].value, + rVales[0].time, + rVales[0].value // + ); + if (!result) + { + // + mUpper.Detach(); + mUpper.Delete(); + + // + return result; + } + + // + // Setting Object Name ... + if (result) + { + ObjName(objID); + } + + // + return result; + } + + /** + * Create Object ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param model: XZigZagAnalysis, reference model ... + * + * @return ( bool ) + */ + bool CreateByPV( + long chart_id, + int window, + XZigZagAnalysis &model // + ) + { + // + bool result = false; + + // + // Validate ... + result = model.IsValid(); + if (!result) + { + return result; + } + + // + // Generate Object ID ... + string objID = model.GetObjectID(); + string upperName = "Upper_" + objID; + string lowerName = "Lower_" + objID; + + // + // Extract Recent Pivots ... + + // + // Creating Upper ... + result = mUpper.Create( + chart_id, + upperName, + window, + model.peakFromTime, + model.peakFrom, + model.peakToTime, + model.peakTo // + ); + if (!result) + { + return result; + } + + // + // Create Lower ... + result = mLower.Create( + chart_id, + lowerName, + window, + model.valeFromTime, + model.valeFrom, + model.valeToTime, + model.valeTo // ); if (!result) { @@ -1974,4 +2210,105 @@ int GetRecent( return result; } +bool CalculateZigZagLinearRegression( + double &_slope, + double &_intercept, + XZigZagPivot &_pivots[], + ENUM_X_ZIGZAG_POINT_TYPE _type // +) +{ + // + bool result = false; + + // + // Prepare ... + _slope = EMPTY_VALUE; + _intercept = EMPTY_VALUE; + + // + // Validate ... + result = + IsXValid(_type) && + HasChild(_pivots); + if (!result) + { + return result; + } + + // + // Extracted Type Specific Valus ... + double values[]; + XZigZagPivot tmp[]; + XZigZagPivot iPivot; + Copy( + _pivots, + tmp // + ); + int count = ArraySize(tmp); + while (HasChild(tmp)) + { + // + // Get Model ... + iPivot = tmp[0]; + + // + // Remove Model ... + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + // Validate Type ... + result = _type == iPivot.type; + if (result) + { + // + // Add Value if Type Passed ... + Add( + iPivot.value, + values // + ); + } + + // + iPivot.Clean(); + } + + // + // Validation Valus ... + result = HasChild(values); + if (result) + { + // + // Calculate Slope / Intercept ... + result = CalculateLinearRegression( + _slope, + _intercept, + values // + ); + } + + // + // Validate Result ... + result = + _slope != EMPTY_VALUE && + _intercept != EMPTY_VALUE; + if (!result) + { + // + _slope = EMPTY_VALUE; + _intercept = EMPTY_VALUE; + } + + // + // Cleanup Resources ... + iPivot.Clean(); + SpecifiedClean(tmp); + SpecifiedClean(values); + + // + return result; +} // \ No newline at end of file