Add Support For ZigZag Swing Prediction to TestRegression Expert ...
This commit is contained in:
+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);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Reference in New Issue
Block a user