Files
xMQL5/BKPS/14041018/Documents/BKP/ZigZagLinearRegression/TestRegresser.mq5
T
2026-01-08 11:39:42 +03:30

1108 lines
22 KiB
Plaintext

//+------------------------------------------------------------------+
//| 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 <ChartObjects/ChartObjectsLines.mqh>
//
// 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 &times[] //
)
{
//
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 &times[] //
)
{
//
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;
}
//