Add Support For ZigZag Swing Prediction to TestRegression Expert ...

This commit is contained in:
2025-09-22 13:35:43 +03:30
parent 7a4f1aa48b
commit 0a102fb01b
5 changed files with 1064 additions and 210 deletions
+390 -147
View File
@@ -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);
}
}
//