Add Support For ZigZag Swing Prediction to TestRegression Expert ...
This commit is contained in:
@@ -0,0 +1,344 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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 <ChartObjects/ChartObjectsLines.mqh>
|
||||
|
||||
//
|
||||
// Inputs ...
|
||||
input int mLoopbackLength = 200;
|
||||
input ENUM_X_PRICE mPriceType = X_PRICE_HIGH;
|
||||
|
||||
//
|
||||
// Calculation ...
|
||||
input group "Calculation";
|
||||
input int zigzagDepth = 12; // Depth
|
||||
input int zigzagDeviation = 5; // Deviation
|
||||
input int zigzagBackStep = 3; // Back Step
|
||||
|
||||
//
|
||||
// Variables ...
|
||||
|
||||
//
|
||||
int mZigZagHandler = INVALID_HANDLE;
|
||||
|
||||
//
|
||||
// double mSumX = 0;
|
||||
// double mSumY = 0;
|
||||
// double mSumXY = 0;
|
||||
// double mSumX2 = 0;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
//
|
||||
double xData[];
|
||||
double yData[];
|
||||
int xDataCount = CollectData(
|
||||
xData,
|
||||
yData //
|
||||
);
|
||||
|
||||
//
|
||||
// Initialize ZigZag Handler ...
|
||||
mZigZagHandler = iCustom(
|
||||
_Symbol,
|
||||
_Period,
|
||||
"ZigZagColor",
|
||||
zigzagDepth,
|
||||
zigzagDeviation,
|
||||
zigzagBackStep //
|
||||
);
|
||||
if (mZigZagHandler == INVALID_HANDLE)
|
||||
{
|
||||
Print("Error creating ZigZag handle");
|
||||
return (INIT_FAILED);
|
||||
}
|
||||
|
||||
// //
|
||||
// for (int i = 0; i < mLoopbackLength; i++)
|
||||
// {
|
||||
// //
|
||||
// double iY = yData[i];
|
||||
// double iX = xData[i];
|
||||
|
||||
// //
|
||||
// mSumX += iX;
|
||||
// mSumY += iY;
|
||||
// mSumXY += (iX * iY);
|
||||
// mSumX2 += (iX * iX);
|
||||
// }
|
||||
|
||||
// //
|
||||
// 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();
|
||||
bool 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;
|
||||
}
|
||||
|
||||
//
|
||||
+390
-147
@@ -14,15 +14,44 @@
|
||||
|
||||
//
|
||||
// Inputs ...
|
||||
|
||||
//
|
||||
// Calculation ...
|
||||
input int zigzagDepth = 12; // Depth
|
||||
input int zigzagDeviation = 5; // Deviation
|
||||
input int zigzagBackStep = 3; // Back Step
|
||||
|
||||
//
|
||||
input int mLoopbackLength = 200;
|
||||
input ENUM_X_PRICE mPriceType = X_PRICE_HIGH;
|
||||
input int mExtendFutureLength = 100; // Bars to extend trendlines into the future
|
||||
|
||||
//
|
||||
// Variables ...
|
||||
double mSumX = 0;
|
||||
double mSumY = 0;
|
||||
double mSumXY = 0;
|
||||
double mSumX2 = 0;
|
||||
|
||||
//
|
||||
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[];
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert initialization function |
|
||||
@@ -30,28 +59,11 @@ double mSumX2 = 0;
|
||||
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;
|
||||
// Initialize Bar Tracker ...
|
||||
mBarTracker.Init(
|
||||
_Symbol,
|
||||
_Period //
|
||||
);
|
||||
|
||||
//
|
||||
double xData[];
|
||||
@@ -60,71 +72,21 @@ int OnInit()
|
||||
xData,
|
||||
yData //
|
||||
);
|
||||
double _cSlope;
|
||||
double _cIntercept;
|
||||
int calculatedCount = CalculateSlopeandIntercept(
|
||||
_cSlope,
|
||||
_cIntercept,
|
||||
xData,
|
||||
yData //
|
||||
|
||||
//
|
||||
// Initialize ZigZag Handler ...
|
||||
mZigZagHandler = iCustom(
|
||||
_Symbol,
|
||||
_Period,
|
||||
"ZigZag",
|
||||
zigzagDepth,
|
||||
zigzagDeviation,
|
||||
zigzagBackStep //
|
||||
);
|
||||
|
||||
//
|
||||
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)
|
||||
if (mZigZagHandler == INVALID_HANDLE)
|
||||
{
|
||||
//
|
||||
// Styling Trend Line ...
|
||||
}
|
||||
|
||||
//
|
||||
CChartObjectTrend *iCTrend = new CChartObjectTrend();
|
||||
isCreated = iCTrend.Create(
|
||||
ChartID(),
|
||||
cName,
|
||||
0,
|
||||
time1,
|
||||
cPrice1,
|
||||
time2,
|
||||
cPrice2 //
|
||||
);
|
||||
if (isCreated)
|
||||
{
|
||||
//
|
||||
// Styling Trend Line ...
|
||||
Print("Error creating ZigZag handle");
|
||||
return (INIT_FAILED);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -135,14 +97,35 @@ int OnInit()
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
//---
|
||||
//
|
||||
IndicatorRelease(mZigZagHandler);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert tick function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTick()
|
||||
{
|
||||
//---
|
||||
//
|
||||
if (!mBarTracker.IsNewBar())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
int readedZigZagsCount = ReadZigZagValues();
|
||||
if (readedZigZagsCount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ProcessZigZagsPeaksAndVales();
|
||||
CalculateZigZagLinearRegressionParameters();
|
||||
DrawZigZagPredictedTrendLines();
|
||||
|
||||
//
|
||||
// Process ZigZag Values ...
|
||||
Print("");
|
||||
|
||||
//
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
@@ -204,91 +187,351 @@ int CollectData(
|
||||
}
|
||||
|
||||
//
|
||||
int CalculateSlopeandIntercept(
|
||||
double &_slope,
|
||||
double &_intercept,
|
||||
double &xData[],
|
||||
double &yData[] //
|
||||
)
|
||||
int ReadZigZagValues(int barIndex = 0)
|
||||
{
|
||||
//
|
||||
int result = 0;
|
||||
|
||||
//
|
||||
bool has = false;
|
||||
// Normalize ...
|
||||
barIndex = NormalizeInt(barIndex, 0);
|
||||
|
||||
//
|
||||
_slope = 0;
|
||||
_intercept = 0;
|
||||
|
||||
//
|
||||
if (!HasChild(xData) ||
|
||||
!HasChild(yData))
|
||||
// Validate ...
|
||||
if (mZigZagHandler == INVALID_HANDLE)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
double sumX = 0;
|
||||
double sumY = 0;
|
||||
double sumXY = 0;
|
||||
double sumX2 = 0;
|
||||
// Copy ZigZag Values to Buffers ...
|
||||
result = CopyBuffer(mZigZagHandler, MAIN_LINE, 0, mLoopbackLength, mZigZagBuffer);
|
||||
|
||||
//
|
||||
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;
|
||||
// Set ZigZag Buffers as Series ...
|
||||
ArraySetAsSeries(mZigZagBuffer, true);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
double PredictValue(
|
||||
double &_slope,
|
||||
double &_intercept,
|
||||
datetime forTime //
|
||||
)
|
||||
void ProcessZigZagsPeaksAndVales()
|
||||
{
|
||||
//
|
||||
double result = 0;
|
||||
// Here we Parse ZigZag Values to Detect Peak or Vale ...
|
||||
|
||||
//
|
||||
if (!IsSpecifiedValid(forTime))
|
||||
// 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++)
|
||||
{
|
||||
return result;
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
|
||||
//
|
||||
double forX = iBarShift(
|
||||
_Symbol,
|
||||
_Period,
|
||||
forTime //
|
||||
); // (double)TimeToSeconds(forTime);
|
||||
result = (_intercept + _slope * forX);
|
||||
// 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;
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
double iZigZagIDX = -1;
|
||||
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 //
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TODO:
|
||||
// - [] Add Support for Reading Specified Number of Swings instead of Specified Loopback ...
|
||||
}
|
||||
|
||||
//
|
||||
void CalculateZigZagLinearRegressionParameters()
|
||||
{
|
||||
//
|
||||
// Peaks ...
|
||||
CalculateSlopeAndIntercept(
|
||||
mPeakSlope,
|
||||
mPeakIntercept,
|
||||
mZigZagPeakIndexes,
|
||||
mZigZagPeaks //
|
||||
);
|
||||
|
||||
//
|
||||
// Vales ...
|
||||
CalculateSlopeAndIntercept(
|
||||
mValeSlope,
|
||||
mValeIntercept,
|
||||
mZigZagValeIndexes,
|
||||
mZigZagVales //
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void DrawZigZagPredictedTrendLines()
|
||||
{
|
||||
//
|
||||
// This Variables are Same in Peaks and Vales ...
|
||||
|
||||
//
|
||||
// TODO:
|
||||
// - [] Add Support for Extending Lines betwen Oldest and Youngest Pivots ...
|
||||
// - [] Add Support for Styling Lines ...
|
||||
|
||||
//
|
||||
// FromTime ...
|
||||
datetime fromTime = iTime(
|
||||
_Symbol,
|
||||
_Period,
|
||||
mLoopbackLength - 1 //
|
||||
);
|
||||
int fromIDX = iBarShift(
|
||||
_Symbol,
|
||||
_Period,
|
||||
fromTime //
|
||||
);
|
||||
|
||||
//
|
||||
// To Time ...
|
||||
// this time Calculated using From Time and mExtendFutureLength ...
|
||||
datetime toTime = fromTime + (mExtendFutureLength * PeriodSeconds(_Period));
|
||||
int toIDX = iBarShift(
|
||||
_Symbol,
|
||||
_Period,
|
||||
toTime //
|
||||
);
|
||||
|
||||
//
|
||||
// Predict Values ...
|
||||
|
||||
//
|
||||
// Peak ...
|
||||
double mPeakTo = PredictValue(
|
||||
mPeakSlope,
|
||||
mPeakIntercept,
|
||||
toIDX //
|
||||
);
|
||||
double mPeakFrom = PredictValue(
|
||||
mPeakSlope,
|
||||
mPeakIntercept,
|
||||
fromIDX //
|
||||
);
|
||||
|
||||
//
|
||||
// Vale ...
|
||||
double mValeTo = PredictValue(
|
||||
mValeSlope,
|
||||
mValeIntercept,
|
||||
toIDX //
|
||||
);
|
||||
double mValeFrom = PredictValue(
|
||||
mValeSlope,
|
||||
mValeIntercept,
|
||||
fromIDX //
|
||||
);
|
||||
|
||||
//
|
||||
// Draw Predicted Lines ...
|
||||
|
||||
//
|
||||
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,
|
||||
fromTime,
|
||||
mPeakFrom,
|
||||
toTime,
|
||||
mPeakTo //
|
||||
);
|
||||
if (isCreated)
|
||||
{
|
||||
//
|
||||
// Apply Styles ...
|
||||
|
||||
//
|
||||
mUpperTrend.Width(2);
|
||||
mUpperTrend.RayRight(true);
|
||||
mUpperTrend.Color(clrAqua);
|
||||
}
|
||||
|
||||
//
|
||||
// Vale ...
|
||||
|
||||
//
|
||||
// Cleanup Lower Object ...
|
||||
if (mLowerTrend != NULL)
|
||||
{
|
||||
//
|
||||
mLowerTrend.Delete();
|
||||
mLowerTrend.Detach();
|
||||
delete mLowerTrend;
|
||||
ZeroMemory(mLowerTrend);
|
||||
}
|
||||
|
||||
//
|
||||
mLowerTrend = new CChartObjectTrend();
|
||||
isCreated = mLowerTrend.Create(
|
||||
ChartID(),
|
||||
"LowerTrend",
|
||||
0,
|
||||
fromTime,
|
||||
mValeFrom,
|
||||
toTime,
|
||||
mValeTo //
|
||||
);
|
||||
if (isCreated)
|
||||
{
|
||||
//
|
||||
// Apply Styles ...
|
||||
|
||||
//
|
||||
mLowerTrend.Width(2);
|
||||
mLowerTrend.RayRight(true);
|
||||
mLowerTrend.Color(clrMagenta);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Binary file not shown.
@@ -0,0 +1,288 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ZigzagColor.mq5 |
|
||||
//| Copyright 2000-2025, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2000-2025, MetaQuotes Ltd."
|
||||
#property link "https://www.mql5.com"
|
||||
//--- indicator settings
|
||||
#property indicator_chart_window
|
||||
#property indicator_buffers 5
|
||||
#property indicator_plots 1
|
||||
#property indicator_type1 DRAW_COLOR_ZIGZAG
|
||||
#property indicator_width1 3
|
||||
#property indicator_color1 clrAqua, clrMagenta
|
||||
//--- input parameters
|
||||
input int InpDepth =12; // Depth
|
||||
input int InpDeviation=5; // Deviation
|
||||
input int InpBackstep =3; // Back Step
|
||||
//--- indicator buffers
|
||||
double ZigzagPeakBuffer[];
|
||||
double ZigzagBottomBuffer[];
|
||||
double HighMapBuffer[];
|
||||
double LowMapBuffer[];
|
||||
double ColorBuffer[];
|
||||
|
||||
int ExtRecalc=3; // recounting's depth
|
||||
|
||||
enum EnSearchMode
|
||||
{
|
||||
Extremum=0, // searching for the first extremum
|
||||
Peak=1, // searching for the next ZigZag peak
|
||||
Bottom=-1 // searching for the next ZigZag bottom
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnInit()
|
||||
{
|
||||
//--- indicator buffers mapping
|
||||
SetIndexBuffer(0,ZigzagPeakBuffer,INDICATOR_DATA);
|
||||
SetIndexBuffer(1,ZigzagBottomBuffer,INDICATOR_DATA);
|
||||
SetIndexBuffer(2,ColorBuffer,INDICATOR_COLOR_INDEX);
|
||||
SetIndexBuffer(3,HighMapBuffer,INDICATOR_CALCULATIONS);
|
||||
SetIndexBuffer(4,LowMapBuffer,INDICATOR_CALCULATIONS);
|
||||
//--- set accuracy
|
||||
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
|
||||
//--- name for DataWindow and indicator subwindow label
|
||||
string short_name=StringFormat("ZigZagColor(%d,%d,%d)",InpDepth,InpDeviation,InpBackstep);
|
||||
IndicatorSetString(INDICATOR_SHORTNAME,short_name);
|
||||
PlotIndexSetString(0,PLOT_LABEL,short_name);
|
||||
//--- set an empty value
|
||||
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| ZigZag calculation |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnCalculate(const int rates_total,
|
||||
const int prev_calculated,
|
||||
const datetime &time[],
|
||||
const double &open[],
|
||||
const double &high[],
|
||||
const double &low[],
|
||||
const double &close[],
|
||||
const long &tick_volume[],
|
||||
const long &volume[],
|
||||
const int &spread[])
|
||||
{
|
||||
if(rates_total<100)
|
||||
return(0);
|
||||
//---
|
||||
int i,start=0;
|
||||
int extreme_counter=0,extreme_search=Extremum;
|
||||
int shift,back=0,last_high_pos=0,last_low_pos=0;
|
||||
double val=0,res=0;
|
||||
double cur_low=0,cur_high=0,last_high=0,last_low=0;
|
||||
//--- initializing
|
||||
if(prev_calculated==0)
|
||||
{
|
||||
ArrayInitialize(ZigzagPeakBuffer,0.0);
|
||||
ArrayInitialize(ZigzagBottomBuffer,0.0);
|
||||
ArrayInitialize(HighMapBuffer,0.0);
|
||||
ArrayInitialize(LowMapBuffer,0.0);
|
||||
//--- start calculation from bar number InpDepth
|
||||
start=InpDepth-1;
|
||||
}
|
||||
//--- ZigZag was already calculated before
|
||||
if(prev_calculated>0)
|
||||
{
|
||||
i=rates_total-1;
|
||||
//--- searching for the third extremum from the last uncompleted bar
|
||||
while(extreme_counter<ExtRecalc && i>rates_total -100)
|
||||
{
|
||||
res=(ZigzagPeakBuffer[i]+ZigzagBottomBuffer[i]);
|
||||
//---
|
||||
if(res!=0)
|
||||
extreme_counter++;
|
||||
i--;
|
||||
}
|
||||
i++;
|
||||
start=i;
|
||||
//--- what type of exremum we search for
|
||||
if(LowMapBuffer[i]!=0)
|
||||
{
|
||||
cur_low=LowMapBuffer[i];
|
||||
extreme_search=Peak;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_high=HighMapBuffer[i];
|
||||
extreme_search=Bottom;
|
||||
}
|
||||
//--- clear indicator values
|
||||
for(i=start+1; i<rates_total && !IsStopped(); i++)
|
||||
{
|
||||
ZigzagPeakBuffer[i] =0.0;
|
||||
ZigzagBottomBuffer[i]=0.0;
|
||||
LowMapBuffer[i] =0.0;
|
||||
HighMapBuffer[i] =0.0;
|
||||
}
|
||||
}
|
||||
//--- searching for high and low extremes
|
||||
for(shift=start; shift<rates_total && !IsStopped(); shift++)
|
||||
{
|
||||
//--- low
|
||||
val=Lowest(low,InpDepth,shift);
|
||||
if(val==last_low)
|
||||
val=0.0;
|
||||
else
|
||||
{
|
||||
last_low=val;
|
||||
if((low[shift]-val)>(InpDeviation*_Point))
|
||||
val=0.0;
|
||||
else
|
||||
{
|
||||
for(back=InpBackstep; back>=1; back--)
|
||||
{
|
||||
res=LowMapBuffer[shift-back];
|
||||
//---
|
||||
if((res!=0) && (res>val))
|
||||
LowMapBuffer[shift-back]=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(low[shift]==val)
|
||||
LowMapBuffer[shift]=val;
|
||||
else
|
||||
LowMapBuffer[shift]=0.0;
|
||||
//--- high
|
||||
val=Highest(high,InpDepth,shift);
|
||||
if(val==last_high)
|
||||
val=0.0;
|
||||
else
|
||||
{
|
||||
last_high=val;
|
||||
if((val-high[shift])>(InpDeviation*_Point))
|
||||
val=0.0;
|
||||
else
|
||||
{
|
||||
for(back=InpBackstep; back>=1; back--)
|
||||
{
|
||||
res=HighMapBuffer[shift-back];
|
||||
//---
|
||||
if((res!=0) && (res<val))
|
||||
HighMapBuffer[shift-back]=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(high[shift]==val)
|
||||
HighMapBuffer[shift]=val;
|
||||
else
|
||||
HighMapBuffer[shift]=0.0;
|
||||
}
|
||||
//--- set last values
|
||||
if(extreme_search==0) // undefined values
|
||||
{
|
||||
last_low=0;
|
||||
last_high=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_low=cur_low;
|
||||
last_high=cur_high;
|
||||
}
|
||||
//--- final selection of extreme points for ZigZag
|
||||
for(shift=start; shift<rates_total && !IsStopped(); shift++)
|
||||
{
|
||||
res=0.0;
|
||||
switch(extreme_search)
|
||||
{
|
||||
case Extremum:
|
||||
if(last_low==0 && last_high==0)
|
||||
{
|
||||
if(HighMapBuffer[shift]!=0)
|
||||
{
|
||||
last_high=high[shift];
|
||||
last_high_pos=shift;
|
||||
extreme_search=-1;
|
||||
ZigzagPeakBuffer[shift]=last_high;
|
||||
ColorBuffer[shift]=0;
|
||||
res=1;
|
||||
}
|
||||
if(LowMapBuffer[shift]!=0)
|
||||
{
|
||||
last_low=low[shift];
|
||||
last_low_pos=shift;
|
||||
extreme_search=1;
|
||||
ZigzagBottomBuffer[shift]=last_low;
|
||||
ColorBuffer[shift]=1;
|
||||
res=1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Peak:
|
||||
if(LowMapBuffer[shift]!=0.0 && LowMapBuffer[shift]<last_low &&
|
||||
HighMapBuffer[shift]==0.0)
|
||||
{
|
||||
ZigzagBottomBuffer[last_low_pos]=0.0;
|
||||
last_low_pos=shift;
|
||||
last_low=LowMapBuffer[shift];
|
||||
ZigzagBottomBuffer[shift]=last_low;
|
||||
ColorBuffer[shift]=1;
|
||||
res=1;
|
||||
}
|
||||
if(HighMapBuffer[shift]!=0.0 && LowMapBuffer[shift]==0.0)
|
||||
{
|
||||
last_high=HighMapBuffer[shift];
|
||||
last_high_pos=shift;
|
||||
ZigzagPeakBuffer[shift]=last_high;
|
||||
ColorBuffer[shift]=0;
|
||||
extreme_search=Bottom;
|
||||
res=1;
|
||||
}
|
||||
break;
|
||||
case Bottom:
|
||||
if(HighMapBuffer[shift]!=0.0 &&
|
||||
HighMapBuffer[shift]>last_high &&
|
||||
LowMapBuffer[shift]==0.0)
|
||||
{
|
||||
ZigzagPeakBuffer[last_high_pos]=0.0;
|
||||
last_high_pos=shift;
|
||||
last_high=HighMapBuffer[shift];
|
||||
ZigzagPeakBuffer[shift]=last_high;
|
||||
ColorBuffer[shift]=0;
|
||||
}
|
||||
if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0)
|
||||
{
|
||||
last_low=LowMapBuffer[shift];
|
||||
last_low_pos=shift;
|
||||
ZigzagBottomBuffer[shift]=last_low;
|
||||
ColorBuffer[shift]=1;
|
||||
extreme_search=Peak;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return(rates_total);
|
||||
}
|
||||
}
|
||||
|
||||
//--- return value of prev_calculated for next call
|
||||
return(rates_total);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get highest value for range |
|
||||
//+------------------------------------------------------------------+
|
||||
double Highest(const double&array[],int count,int start)
|
||||
{
|
||||
double res=array[start];
|
||||
//---
|
||||
for(int i=start-1; i>start-count && i>=0; i--)
|
||||
if(res<array[i])
|
||||
res=array[i];
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Get lowest value for range |
|
||||
//+------------------------------------------------------------------+
|
||||
double Lowest(const double&array[],int count,int start)
|
||||
{
|
||||
double res=array[start];
|
||||
//---
|
||||
for(int i=start-1; i>start-count && i>=0; i--)
|
||||
if(res>array[i])
|
||||
res=array[i];
|
||||
//---
|
||||
return(res);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -7065,67 +7065,54 @@ bool SetChartVolumesColor(
|
||||
//
|
||||
|
||||
/**
|
||||
* Linear Regression Based Calculate Data ...
|
||||
* int this Senario X Axis is Buffer Index ...
|
||||
* Calculate Slope and Intercept for Linear Regression Predictions ...
|
||||
*
|
||||
* @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 ...
|
||||
* @param _slope: double, refrence to Hold Calculated Slope ...
|
||||
* @param _intercept: double, reference to Hold Calculated Intercept ...
|
||||
* @param xData: double, reference Collection to Provides X-Axis Data for Calculations ...
|
||||
* @param yData: double, reference Collection to Provides Y-Axis Data for Calculations ...
|
||||
*
|
||||
* @return ( bool )
|
||||
* @return ( int )
|
||||
*/
|
||||
bool CalculateLinearRegression(
|
||||
int CalculateSlopeAndIntercept(
|
||||
double &_slope,
|
||||
double &_intercept,
|
||||
double &_source[],
|
||||
int _start = 0,
|
||||
int _count = 0 //
|
||||
double &xData[],
|
||||
double &yData[] //
|
||||
)
|
||||
{
|
||||
//
|
||||
bool result = false;
|
||||
int result = 0;
|
||||
|
||||
//
|
||||
// Prepare ...
|
||||
_slope = EMPTY_VALUE;
|
||||
_intercept = EMPTY_VALUE;
|
||||
bool has = false;
|
||||
|
||||
//
|
||||
// Validate ...
|
||||
int count = ArraySize(_source);
|
||||
result = IsValidSize(count);
|
||||
if (!result)
|
||||
_slope = 0;
|
||||
_intercept = 0;
|
||||
|
||||
//
|
||||
if (!HasChild(xData) ||
|
||||
!HasChild(yData))
|
||||
{
|
||||
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 = 0;
|
||||
double y = 0;
|
||||
int end = MathMin(ArraySize(xData), ArraySize(yData));
|
||||
for (int i = 0; i < end; i++)
|
||||
{
|
||||
//
|
||||
double x = i + 1;
|
||||
double y = _source[i];
|
||||
double x = xData[i];
|
||||
double y = yData[i];
|
||||
|
||||
//
|
||||
sumX += x;
|
||||
@@ -7135,54 +7122,46 @@ bool CalculateLinearRegression(
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate Slope and Intercept ...
|
||||
int n = _count;
|
||||
_slope = ((n * sumXY) - (sumX * sumY)) / ((n * sumX2) - (sumX * sumX));
|
||||
_intercept = ((sumY - _slope) * sumX) / n;
|
||||
int n = end;
|
||||
_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;
|
||||
}
|
||||
result = n;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
double CalculateValueBySlopeIntercept(
|
||||
/**
|
||||
* Predict Value for Specified X ...
|
||||
*
|
||||
* @param _sllope: double, Provided Slope ...
|
||||
* @param _intercept: double, Provided Intercept ...
|
||||
* @param _forX: double, Specified XValue ...
|
||||
*
|
||||
* @return ( double )
|
||||
*/
|
||||
double PredictValue(
|
||||
double _slope,
|
||||
double _intercept,
|
||||
int _index //
|
||||
double _forX //
|
||||
)
|
||||
{
|
||||
//
|
||||
double result = EMPTY_VALUE;
|
||||
|
||||
//
|
||||
// Normalize Index ...
|
||||
_index = NormalizeInt(_index, 1);
|
||||
double result = 0;
|
||||
|
||||
//
|
||||
// Validate ...
|
||||
if (
|
||||
if (!NotEmpty(_forX) ||
|
||||
!NotEmpty(_slope) ||
|
||||
!NotEmpty(_intercept) ||
|
||||
!IsValidIndex(_index))
|
||||
!NotEmpty(_intercept))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
result = (_intercept + _slope * _index);
|
||||
result = (_intercept + (_slope * _forX));
|
||||
|
||||
//
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user