456 lines
10 KiB
Plaintext
456 lines
10 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class
|
|
// -------------------------------------------------
|
|
// Name: XCXFIMAPoiDetector ...
|
|
// Description: XFIMA POI Detector Class ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property description "SaherElm XFIMA POI Detector Class"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../../Classes/x-saherelm.base.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-market.pattern.class.mq5"
|
|
#include "../Libraries/x-saherelm.xfima.lib.mq5"
|
|
|
|
//
|
|
// Implementation ...
|
|
class XCXFIMAPOIDetector : public XCMarketPatternDetector
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
XCBarAnalyser *barAnalyser; // Bar Analyser ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XCXFIMAPOIDetector()
|
|
{
|
|
//
|
|
barAnalyser = new XCBarAnalyser();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCXFIMAPOIDetector()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
//
|
|
// Actions and Tools ...
|
|
|
|
/**
|
|
* Get Specified Number of Recent ZigZag Points ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar for Start ...
|
|
* @param fimaHelper: XCXFIMAHelper, instance of XFIMA Helper ...
|
|
* @param zigzagPoints: XZigZagPoint, Array of Founded Points ...
|
|
* @param numberOfRequiredPivots: int, Specified Number of required ZigZag Points ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int GetZigZagPivot(
|
|
XOHCL &bar,
|
|
XCXFIMAHelper *&fimaHelper,
|
|
XZigZagPivot &zigzagPivots[],
|
|
int numberOfRequiredPivots = 5 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// Normalize ...
|
|
SpecifiedClean(zigzagPivots);
|
|
numberOfRequiredPivots = NormalizeInt(numberOfRequiredPivots, 3);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid() &&
|
|
bar.symbol == fimaHelper.GetSymbol() &&
|
|
bar.period == fimaHelper.GetPeriod();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Update Fima Helper ...
|
|
int index = bar.Index();
|
|
fimaHelper.Update(index);
|
|
|
|
//
|
|
// Start Reading ZigZag Values ...
|
|
double iZG = 0;
|
|
double iPZG = 0;
|
|
int iZGIdx = -1;
|
|
int iPZGIdx = -1;
|
|
bool has = false;
|
|
int start = index;
|
|
XZigZagPivot iZGPoint;
|
|
datetime iZGTime = NULL;
|
|
datetime iPZGTime = NULL;
|
|
int lastZGDetected = start;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
ENUM_X_ZIGZAG_POINT_TYPE iType = X_ZIGZAG_PIVOT_TYPE_NONE;
|
|
while (ArraySize(zigzagPivots) < numberOfRequiredPivots)
|
|
{
|
|
//
|
|
// Reading Last two ZigZag Value ...
|
|
|
|
//
|
|
// Detect Last ZG Value ...
|
|
has = GetZigZagValue(lastZGDetected, iZG, iZGIdx, iZGTime, fimaHelper);
|
|
if (!has)
|
|
{
|
|
//
|
|
iZG = 0;
|
|
iPZG = 0;
|
|
iZGIdx = -1;
|
|
iPZGIdx = -1;
|
|
iZGTime = NULL;
|
|
iPZGTime = NULL;
|
|
iZGPoint.Clean();
|
|
iDir = X_DIRECTION_NONE;
|
|
iType = X_ZIGZAG_PIVOT_TYPE_NONE;
|
|
|
|
//
|
|
start++;
|
|
lastZGDetected++;
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Detect Previous ZG Value ...
|
|
has = GetZigZagValue(lastZGDetected + 1, iPZG, iPZGIdx, iPZGTime, fimaHelper);
|
|
if (!has)
|
|
{
|
|
//
|
|
iZG = 0;
|
|
iPZG = 0;
|
|
iZGIdx = -1;
|
|
iPZGIdx = -1;
|
|
iZGTime = NULL;
|
|
iPZGTime = NULL;
|
|
iZGPoint.Clean();
|
|
iDir = X_DIRECTION_NONE;
|
|
iType = X_ZIGZAG_PIVOT_TYPE_NONE;
|
|
|
|
//
|
|
start++;
|
|
lastZGDetected++;
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Direction ...
|
|
iDir =
|
|
(iZG > iPZG)
|
|
? X_DIRECTION_BULLISH
|
|
: (iZG < iPZG)
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Check Point Type ...
|
|
iType =
|
|
IsSpecifiedBullish(iDir)
|
|
? X_ZIGZAG_PIVOT_TYPE_PEAK
|
|
: IsSpecifiedBearish(iDir)
|
|
? X_ZIGZAG_PIVOT_TYPE_VALE
|
|
: X_ZIGZAG_PIVOT_TYPE_NONE;
|
|
has =
|
|
IsXValid(iType) &&
|
|
HasDirection(iDir);
|
|
if (!has)
|
|
{
|
|
//
|
|
iZG = 0;
|
|
iPZG = 0;
|
|
iZGIdx = -1;
|
|
iPZGIdx = -1;
|
|
iZGTime = NULL;
|
|
iPZGTime = NULL;
|
|
iZGPoint.Clean();
|
|
iDir = X_DIRECTION_NONE;
|
|
iType = X_ZIGZAG_PIVOT_TYPE_NONE;
|
|
|
|
//
|
|
start++;
|
|
lastZGDetected++;
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Initialize ZigZag Point ...
|
|
has = iZGPoint.Init(
|
|
iZG,
|
|
iZGTime,
|
|
bar.symbol,
|
|
iDir,
|
|
bar.period,
|
|
iType //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
iZGPoint.AddIfNotExists(zigzagPivots);
|
|
lastZGDetected = iZGIdx + 1;
|
|
}
|
|
|
|
//
|
|
// Reset Resources ...
|
|
iZG = 0;
|
|
iPZG = 0;
|
|
iZGIdx = -1;
|
|
iPZGIdx = -1;
|
|
iZGTime = NULL;
|
|
iPZGTime = NULL;
|
|
iZGPoint.Clean();
|
|
iDir = X_DIRECTION_NONE;
|
|
iType = X_ZIGZAG_PIVOT_TYPE_NONE;
|
|
|
|
//
|
|
start++;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(zigzagPivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool AnalyseMarketUsingZigZag(
|
|
XOHCL &bar,
|
|
ENUM_TIMEFRAMES forPeriod,
|
|
XCXFIMAHelper *&fimaHelper,
|
|
XZigZagAnalysis &analysis,
|
|
int numberOfRequiredPivots = 20 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
analysis.Clean();
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize ...
|
|
numberOfRequiredPivots = NormalizeInt(numberOfRequiredPivots, 5);
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = bar.period;
|
|
}
|
|
|
|
//
|
|
// Reading XZigZag Points ...
|
|
XOHCL iPeriodBar;
|
|
result = iPeriodBar.Init(
|
|
bar.symbol,
|
|
forPeriod,
|
|
bar.Index() //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
iPeriodBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Required Pivots ...
|
|
XZigZagPivot pivots[];
|
|
int pivotsCount = GetZigZagPivot(
|
|
iPeriodBar,
|
|
fimaHelper,
|
|
pivots,
|
|
numberOfRequiredPivots //
|
|
);
|
|
result = IsValidSize(pivotsCount);
|
|
if (!result)
|
|
{
|
|
//
|
|
analysis.Clean();
|
|
iPeriodBar.Clean();
|
|
SpecifiedClean(pivots);
|
|
}
|
|
|
|
//
|
|
// Initialize Analysis Model ...
|
|
result = analysis.Analyse(
|
|
bar,
|
|
pivots //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
analysis.Clean();
|
|
iPeriodBar.Clean();
|
|
SpecifiedClean(pivots);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Destroy ...
|
|
*/
|
|
void Destroy()
|
|
{
|
|
//
|
|
delete barAnalyser;
|
|
ZeroMemory(barAnalyser);
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Tools / Actions ...
|
|
|
|
/**
|
|
* Read Specified Value of ZigZag ...
|
|
*
|
|
* @param fromBarIndex: int, Specified Start Bar Index ...
|
|
* @param value: double, reference to Hold ZigZag Value ...
|
|
* @param index: int, reference to Hold ZigZag Value's Bar Index ...
|
|
* @param time: datetime, reference to Hold ZigZag Value's Time ...
|
|
* @param maxAllowedLoopback: int, Maximum Allowe Loopback to Detect Specified Point ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetZigZagValue(
|
|
int fromBarIndex,
|
|
double &value,
|
|
int &index,
|
|
datetime &time,
|
|
XCXFIMAHelper *&fimaHelper,
|
|
int maxAllowedLoopback = 100 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
fromBarIndex = NormalizeInt(fromBarIndex, 0);
|
|
maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 10, 100);
|
|
|
|
//
|
|
// Prepare ...
|
|
value = 0;
|
|
index = -1;
|
|
time = NULL;
|
|
|
|
//
|
|
// Validate ...
|
|
result = fimaHelper != NULL;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int start = fromBarIndex;
|
|
int end = start + maxAllowedLoopback;
|
|
while (start < end)
|
|
{
|
|
//
|
|
fimaHelper.Update(start);
|
|
|
|
//
|
|
value = fimaHelper.GetZigZag(start);
|
|
result = value > 0 && value != EMPTY_VALUE;
|
|
if (result)
|
|
{
|
|
//
|
|
time = GetBarTime(
|
|
fimaHelper.GetSymbol(),
|
|
fimaHelper.GetPeriod(),
|
|
start //
|
|
);
|
|
|
|
//
|
|
index = start;
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
value = 0;
|
|
index = -1;
|
|
time = NULL;
|
|
|
|
//
|
|
start++;
|
|
}
|
|
|
|
//
|
|
result =
|
|
value > 0 &&
|
|
IsValidIndex(index) &&
|
|
value != EMPTY_VALUE &&
|
|
IsSpecifiedValid(time);
|
|
if (!result)
|
|
{
|
|
//
|
|
value = 0;
|
|
index = -1;
|
|
time = NULL;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
// |