Files
MQL5Data/XFIMAEA/Classes/x-saherelm.xfima.x-poi.detector.class.mq5
T
2025-11-01 08:40:19 +03:30

2231 lines
55 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"
//
// Definitions ...
enum ENUM_XFIMA_PIVOTS
{
XFIMA_PIVOT_NONE = 0,
XFIMA_PIVOT_PV = 1,
XFIMA_PIVOT_ATR = 2,
XFIMA_PIVOT_ZIGZAG = 3,
XFIMA_PIVOT_MA_CROSS = 4,
XFIMA_PIVOT_HK_SWITCH = 5,
XFIMA_PIVOT_SAR_SWITCH = 6,
XFIMA_PIVOT_BOUNDARY_SWITCH = 7,
};
bool IsXValid(ENUM_XFIMA_PIVOTS value)
{
//
bool result = false;
//
result = value != XFIMA_PIVOT_NONE;
//
return result;
}
string ToXString(ENUM_XFIMA_PIVOTS value)
{
//
string result = NULL;
//
if (!IsXValid(value))
{
return result;
}
//
switch (value)
{
//
case XFIMA_PIVOT_NONE:
result = "NONE";
break;
//
case XFIMA_PIVOT_PV:
result = "XPV";
break;
//
case XFIMA_PIVOT_ATR:
result = "XATR";
break;
//
case XFIMA_PIVOT_ZIGZAG:
result = "XZGP";
break;
//
case XFIMA_PIVOT_MA_CROSS:
result = "XMACRS";
break;
//
case XFIMA_PIVOT_HK_SWITCH:
result = "XHKSWCH";
break;
//
case XFIMA_PIVOT_SAR_SWITCH:
result = "XSARSWCH";
break;
//
case XFIMA_PIVOT_BOUNDARY_SWITCH:
result = "XBNDSWCH";
break;
}
//
return result;
}
ENUM_XFIMA_PIVOTS ToXFIMAPivots(string value)
{
//
ENUM_XFIMA_PIVOTS result = XFIMA_PIVOT_NONE;
//
if (!IsXValid(value))
{
return result;
}
//
if (value == ToXString(XFIMA_PIVOT_NONE))
{
result = XFIMA_PIVOT_NONE;
}
else if (value == ToXString(XFIMA_PIVOT_PV))
{
result = XFIMA_PIVOT_PV;
}
else if (value == ToXString(XFIMA_PIVOT_ATR))
{
result = XFIMA_PIVOT_ATR;
}
else if (value == ToXString(XFIMA_PIVOT_ZIGZAG))
{
result = XFIMA_PIVOT_ZIGZAG;
}
else if (value == ToXString(XFIMA_PIVOT_MA_CROSS))
{
result = XFIMA_PIVOT_MA_CROSS;
}
else if (value == ToXString(XFIMA_PIVOT_HK_SWITCH))
{
result = XFIMA_PIVOT_HK_SWITCH;
}
else if (value == ToXString(XFIMA_PIVOT_SAR_SWITCH))
{
result = XFIMA_PIVOT_SAR_SWITCH;
}
else if (value == ToXString(XFIMA_PIVOT_BOUNDARY_SWITCH))
{
result = XFIMA_PIVOT_BOUNDARY_SWITCH;
}
//
return result;
}
//
// Implementation ...
class XCXFIMAPOIDetector : public XCMarketPatternDetector
{
//
// Public ...
public:
//
// Props ...
//
string symbol;
ENUM_TIMEFRAMES period;
//
XCBarAnalyser *barAnalyser; // Bar Analyser ...
XCXFIMAHelper *fimaHelper; // XFIMA Helper ...
XCXFIMAHelperParser *fimaParser; // XFIMA Helper Parser ...
//
// Constructor ...
XCXFIMAPOIDetector(
XCXFIMAHelper *_fimaHelper,
XCXFIMAHelperParser *_fimaParser //
) : XCMarketPatternDetector()
{
//
barAnalyser = new XCBarAnalyser();
fimaHelper = _fimaHelper;
fimaParser = _fimaParser;
//
symbol = fimaHelper.GetSymbol();
period = fimaHelper.GetPeriod();
}
//
// Deconstructor ...
~XCXFIMAPOIDetector()
{
Destroy();
}
//
// Actions and Tools ...
//
// Detectors ...
//
// XPV ...
/**
* Check Conditions to Detecte XPV based Consolidation Zone ...
*
* @param zone: XBoxZone, reference to holds detected zone ...
* @param barIndex: int, Specified Bar Index ...
* @param forcePVBreak: bool, force to has PV Side Break ...
* @param forceHasSarSwitch: bool, force to has SAR Switche ...
*
* @return ( bool )
*/
bool DetectPVConsolidationZone(
XBoxZone &zone,
int barIndex = 0,
bool forcePVBreak = false,
bool forceHasSarSwitch = false //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
//
// Normalize ...
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
result = fimaParser.IsValid();
if (!result)
{
return result;
}
//
// Do ...
//
bool isPeakSame = fimaParser.IsPeakSame(barIndex);
bool isValeSame = fimaParser.IsValeSame(barIndex);
result = !(isPeakSame &&
isValeSame);
if (!result)
{
return result;
}
//
double iPeak = EMPTY_VALUE;
double iVale = EMPTY_VALUE;
//
int idx = barIndex;
bool canLookup = true;
while (canLookup)
{
//
idx++;
isPeakSame = fimaParser.IsPeakSame(idx);
isValeSame = fimaParser.IsValeSame(idx);
result = isPeakSame &&
isValeSame;
if (!result)
{
//
zone.from = GetBarTime(symbol, period, idx);
break;
}
//
if (idx == barIndex + 1)
{
//
zone.to = GetBarTime(
symbol,
period,
idx //
);
}
//
zone.from = GetBarTime(
symbol,
period,
idx //
);
//
iPeak = fimaHelper.GetPeak(idx);
iVale = fimaHelper.GetVale(idx);
//
zone.lower =
!NotEmptyZero(zone.lower)
? iVale
: MathMin(zone.lower, iVale);
//
zone.upper =
!NotEmptyZero(zone.upper)
? iPeak
: MathMax(zone.upper, iPeak);
}
//
// Validating Zone Params ...
result =
//
IsXValid(zone.to) &&
IsXValid(zone.from) &&
zone.from < zone.to &&
//
NotEmptyZero(zone.lower) &&
NotEmptyZero(zone.upper) &&
zone.upper > zone.lower
//
;
//
// Prepare Zone ...
if (result)
{
//
iPeak = fimaHelper.GetPeak(barIndex);
iVale = fimaHelper.GetVale(barIndex);
bool isPeakOverLast = fimaParser.IsPeakOverLast(barIndex);
bool isValeUnderLast = fimaParser.IsValeUnderLast(barIndex);
bool isValeBreak = iVale < zone.lower;
bool isPeakBreak = iPeak > zone.upper;
bool isPVBreak = isPeakBreak ||
isValeBreak;
//
zone.at = GetBarTime(symbol, period, barIndex);
zone.symbol = symbol;
zone.period = period;
zone.dir = (isPeakOverLast && !isValeUnderLast && isPVBreak)
? X_DIRECTION_BULLISH
: (isValeUnderLast && !isPeakOverLast && isPVBreak)
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
zone.type = ToXString(X_BAR_PATTERN_CONSOLIDATION);
//
// Refine Zone Upper and Lower ...
if (zone.IsValid())
{
//
XOHCL iBar;
int zoneLoopback = zone.FromIndex() - zone.ToIndex();
result = zone.ToBar(iBar) &&
IsValidSize(zoneLoopback);
if (result)
{
//
double zoneLL = iBar.FindLowest(zoneLoopback, MODE_LOW);
double zoneHH = iBar.FindHighest(zoneLoopback, MODE_HIGH);
result = NotEmptyZero(zoneLL) &&
NotEmptyZero(zoneHH);
if (result)
{
//
zone.lower = zone.lower == zoneLL
? zone.lower
: MathMax(zone.lower, zoneLL);
//
zone.upper = zone.upper == zoneHH
? zone.upper
: MathMin(zone.upper, zoneHH);
}
}
//
iBar.Clean();
}
//
// Validate ...
result = zone.IsValid();
}
//
// Validate Zones From ...
if (result)
{
//
int idx = zone.FromIndex();
//
iPeak = fimaHelper.GetPeak(idx);
iVale = fimaHelper.GetVale(idx);
//
bool isValeOverLast = fimaParser.IsValeOverLast(idx);
bool isPeakUnderLast = fimaParser.IsPeakUnderLast(idx);
//
result =
result &&
(zone.IsBullish()
? !isPeakUnderLast
: zone.IsBearish()
? !isValeOverLast
: false);
}
//
// Apply Forces ...
//
// PV Break ...
// Peak or Vale must Breaked at Bar ...
if (result && forcePVBreak)
{
//
bool isPVBreaked =
(zone.IsBullish() && fimaParser.IsPeakOverLast(barIndex)) ||
(zone.IsBearish() && fimaParser.IsValeUnderLast(barIndex));
//
result = result &&
isPVBreaked;
}
//
// Other Loop based Forces ...
if (result && (forceHasSarSwitch))
{
//
bool hasSarSwitch = false;
//
int start = zone.ToIndex();
int end = zone.FromIndex();
for (int i = start; i <= end; i++)
{
//
// Check Sar Switches ...
if (forceHasSarSwitch && !hasSarSwitch)
{
//
hasSarSwitch =
zone.IsBullish()
? fimaParser.IsSARSwitchedToBullish(i)
: fimaParser.IsSARSwitchedToBearish(i);
}
}
//
// Validate Forces ...
if (forceHasSarSwitch)
{
//
result =
result &&
hasSarSwitch;
}
}
//
// Cleanup ...
if (!result)
{
zone.Clean();
}
//
return result;
}
/**
* Detect XPV Zone ...
*
* @param zone: XBoxZone, reference to Holds detected Zone ...
* @param barIndex: int, Specified Bar Index ...
*
* @return ( bool )
*/
bool DetectXPVZone(
XBoxZone &zone,
int barIndex = 0 //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
//
// Normalize ...
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
result = fimaParser.IsValid();
if (!result)
{
return result;
}
//
// Do ...
//
XOHCL bar;
result = bar.Init(fimaParser.symbol, fimaParser.period, barIndex);
if (!result)
{
//
bar.Clean();
return result;
}
//
// Vale ...
bool isValeOverLast = fimaParser.IsValeOverLast(barIndex);
bool isValeUnderLast = fimaParser.IsValeUnderLast(barIndex);
bool isNewVale = isValeOverLast || isValeUnderLast;
//
// Peak ...
bool isPeakOverLast = fimaParser.IsPeakOverLast(barIndex);
bool isPeakUnderLast = fimaParser.IsPeakUnderLast(barIndex);
bool isNewPeak = isPeakOverLast || isPeakUnderLast;
//
// Detect new Peak or Vale ...
result = isNewVale || isNewPeak;
//
// Count Same Peaks and Same Vales from Index of Prev ...
int pIDX = barIndex + 1;
int samePeaks = fimaParser.CountSamePeaks(pIDX);
int sameVales = fimaParser.CountSameVales(pIDX);
result =
result &&
IsValidSize(samePeaks) &&
IsValidSize(sameVales);
//
// Try to Evaluate Zone ...
int peaksStartIndex = pIDX + samePeaks;
int valesStartIndex = pIDX + sameVales;
int fromIDX = MathMin(peaksStartIndex, valesStartIndex);
if (result)
{
//
// Assign Zone Symbol / Period ...
zone.symbol = fimaParser.symbol;
zone.period = fimaParser.period;
//
// Calculate Zone Times ...
zone.to = GetBarTime(
zone.symbol,
zone.period,
barIndex //
);
zone.from = GetBarTime(
zone.symbol,
zone.period,
fromIDX //
);
zone.at = zone.to;
//
// Calculate Upper and Lower ...
zone.upper = fimaHelper.GetPeak(fromIDX);
zone.lower = fimaHelper.GetVale(fromIDX);
//
// Validate Zone Upper and Lower ...
for (int i = pIDX; i <= fromIDX; i++)
{
//
if (isValeUnderLast)
{
zone.lower = MathMin(zone.lower, fimaHelper.GetVale(i));
}
//
if (isPeakOverLast)
{
zone.upper = MathMax(zone.upper, fimaHelper.GetPeak(i));
}
}
//
// Calculate Zone Direction ...
zone.dir =
isValeOverLast
? X_DIRECTION_BULLISH
: isValeUnderLast
? X_DIRECTION_BEARISH
: isPeakOverLast
? X_DIRECTION_BULLISH
: isPeakUnderLast
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
//
// Refine Zone Upper / Lower based on Direction and Bars ...
//
// Detect Highest High / Lowest Low ...
double ll = bar.FindLowest(fromIDX - barIndex, MODE_LOW);
double hh = bar.FindHighest(fromIDX - barIndex, MODE_HIGH);
//
if (isNewVale)
{
zone.upper = MathMin(zone.upper, hh);
}
//
if (isNewPeak)
{
zone.lower = MathMax(zone.lower, ll);
}
//
// Set Zone Type ...
zone.type = ToXString(XFIMA_PIVOT_PV);
//
// Summarize result ...
result = zone.IsValid();
}
//
result = zone.IsValid();
//
// Cleanup ...
if (!result)
{
zone.Clean();
}
bar.Clean();
//
return result;
}
//
// Analysors ...
/**
* Analyse Market ...
*
* @param structure: XFIMAMarketStructure, reference to holds Market Strucutre ...
* @param config: XFIMAMarketStructureConfig, reference to Provide Structure Analyse Config ...
* @param barIndex: int, Specified Bar Index ...
*
* @return ( bool )
*/
bool AnalyseMarket(
XFIMAMarketStructure &structure,
XFIMAMarketStructureConfig &config,
int barIndex = 0 //
)
{
//
bool result = false;
//
// Prepare ...
structure.Clean();
//
// Normalize ...
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
result = fimaParser.IsValid();
if (!result)
{
return result;
}
//
// Do ...
int idx = -1;
XOHCL tmpBar;
datetime fromTime = NULL;
XPatternAnalysis tmpBarAnalysis;
//
// Initialize Indexed Bar ...
result = structure.bar.Init(symbol, period, barIndex);
//
// Analyse Bar Patterns ...
if (result)
{
//
result = AnalyseBarPatterns(
structure.bar,
structure.barAnalysis,
config.barsAnalysisConfig //
);
}
//
// Analyse Pivots ...
//
// XPV ...
CollectPVPivots(
structure.pvPivots,
barIndex,
config.requiredPivots,
config.loopback //
);
//
// XMA ...
CollectMAPivots(
structure.maPivots,
barIndex,
config.requiredPivots,
config.loopback //
);
//
// XZG ...
CollectZGPivots(
structure.zgPivots,
barIndex,
config.requiredPivots,
config.loopback //
);
//
// XHK ...
CollectHKPivots(
structure.hkPivots,
barIndex,
config.requiredPivots,
config.loopback //
);
//
// XSAR ...
CollectSARPivots(
structure.sarPivots,
barIndex,
config.requiredPivots,
config.loopback //
);
//
// XPV Analysis ...
if (result && config.analysePVPivots)
{
//
result = HasChild(structure.pvPivots);
//
// Check Oldest ...
idx = GetOldest(structure.pvPivots);
result = IsValidIndex(idx);
if (result)
{
//
fromTime =
!IsXValid(fromTime)
? structure.pvPivots[idx].time
: MathMin(fromTime, structure.pvPivots[idx].time);
}
//
// Initialize Analysis ...
if (result)
{
//
result = structure.pvAnalysis.Init(
ToXString(XFIMA_PIVOT_PV),
symbol,
period,
structure.pvPivots //
);
}
}
//
// XZG Analysis ...
if (result && config.analyseZGPivots)
{
//
result = HasChild(structure.zgPivots);
//
// Check Oldest ...
idx = GetOldest(structure.zgPivots);
result = IsValidIndex(idx);
if (result)
{
//
fromTime =
!IsXValid(fromTime)
? structure.zgPivots[idx].time
: MathMin(fromTime, structure.zgPivots[idx].time);
}
//
// Initialize Analysis ...
if (result)
{
//
result = structure.zgAnalysis.Init(
ToXString(XFIMA_PIVOT_ZIGZAG),
symbol,
period,
structure.zgPivots //
);
}
}
//
// XHK Analysis ...
if (result && config.analyseHKPivots)
{
//
result = HasChild(structure.hkPivots);
//
// Check Oldest ...
idx = GetOldest(structure.hkPivots);
result = IsValidIndex(idx);
if (result)
{
//
fromTime =
!IsXValid(fromTime)
? structure.hkPivots[idx].time
: MathMin(fromTime, structure.hkPivots[idx].time);
}
//
// Initialize Analysis ...
if (result)
{
//
result = structure.hkAnalysis.Init(
ToXString(XFIMA_PIVOT_HK_SWITCH),
symbol,
period,
structure.hkPivots //
);
}
}
//
// XMA Analysis ...
if (result && config.analyseMAPivots)
{
result = HasChild(structure.maPivots);
//
// Check Oldest ...
idx = GetOldest(structure.maPivots);
result = IsValidIndex(idx);
if (result)
{
//
fromTime =
!IsXValid(fromTime)
? structure.maPivots[idx].time
: MathMin(fromTime, structure.maPivots[idx].time);
}
//
// Initialize Analysis ...
if (result)
{
//
result = structure.maAnalysis.Init(
ToXString(XFIMA_PIVOT_MA_CROSS),
symbol,
period,
structure.maPivots //
);
}
}
//
// XSAR Analysis ...
if (result && config.analyseSARPivots)
{
//
result = HasChild(structure.sarPivots);
//
// Check Oldest ...
idx = GetOldest(structure.sarPivots);
result = IsValidIndex(idx);
if (result)
{
//
fromTime =
!IsXValid(fromTime)
? structure.sarPivots[idx].time
: MathMin(fromTime, structure.sarPivots[idx].time);
}
//
// Initialize Analysis ...
if (result)
{
//
result = structure.sarAnalysis.Init(
ToXString(XFIMA_PIVOT_SAR_SWITCH),
symbol,
period,
structure.sarPivots //
);
}
}
//
// Order Flow ...
if (result && config.detectOrderFlow)
{
//
HasOrderFlow(
structure.bar,
structure.orderFlowDir,
structure.orderFlow,
config.orderFlowValidation,
config.orderFlowUseOB,
config.orderFlowUseFVG,
config.orderFlowUseSupportAndResistance,
config.barsAnalysisConfig.supportAndResistanceLoopbackLength,
config.barsAnalysisConfig.supportAndResistanceValidationLength,
config.loopback //
);
}
//
// Analyse Bar Patterns ...
if (result && config.analyseBarPatterns)
{
//
// Collect Pivots ...
XPivot tmps[];
Copy(structure.pvPivots, tmps, false);
Copy(structure.zgPivots, tmps, false);
Copy(structure.hkPivots, tmps, false);
Copy(structure.maPivots, tmps, false);
Copy(structure.sarPivots, tmps, false);
//
XPivot sames[];
XPivot tmpPivot;
int samesCount = 0;
while (HasChild(tmps))
{
//
tmpPivot.Clean();
tmpPivot = tmps[0];
ArrayRemove(tmps, 0, 1);
//
XClean(sames);
samesCount = ExtractSameTimePivots(tmpPivot, sames, tmps);
if (HasChild(sames))
{
//
tmpBar.Clean();
if (sames[0].GetBar(tmpBar))
{
//
tmpBarAnalysis.Clean();
if (AnalyseBarPatterns(tmpBar, tmpBarAnalysis, config.barsAnalysisConfig))
{
//
AddRef(tmpBarAnalysis, structure.barsAnalysis);
}
}
//
Removes(sames, tmps);
}
}
//
// Bars Analysis Exists ...
result = HasChild(structure.barsAnalysis);
//
// Cleanup ...
XClean(tmps);
XClean(sames);
tmpPivot.Clean();
}
//
// Cleanup ...
if (!result)
{
structure.Clean();
}
//
return result;
}
//
// Collectors ...
/**
* Collect ZigZag Pivots ...
*
* @param pivots: XPivot, reference collection to holds Detected Pivots ...
* @param barIndex: int, Specified Start Bar Index ...
* @param count: int, Specified number of required Pivots ...
* @param loopback: int, Max Allowed Loopback length for Detection ...
*
* @return ( int )
*/
int CollectZGPivots(
XPivot &pivots[],
int barIndex = 0,
int count = 50,
int loopback = 500 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(pivots);
//
// Normalize ...
count = NormalizeInt(count, 0);
loopback = NormalizeInt(loopback, 50);
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
bool has = fimaParser.IsValid();
if (!has)
{
return result;
}
//
// Do ...
XOHCL bar;
XPivot pivot;
int start = barIndex;
bool isBullish = false;
bool isBearish = false;
int end = start + loopback;
ENUM_X_DIRECTION dir = X_DIRECTION_NONE;
for (int i = start; i < end; i++)
{
//
isBullish = fimaParser.IsZGLow(i);
isBearish = fimaParser.IsZGHigh(i);
//
has = isBullish || isBearish;
if (has)
{
//
// Specified Direction ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Initialize Indexed Bar ...
// Validate it, and Converts it to Pivot ...
bar.Clean();
has = bar.Init(symbol, period, i);
has = has &&
ToPivot(
bar,
pivot,
dir,
ToXString(XFIMA_PIVOT_ZIGZAG) //
);
if (has)
{
//
// Add Detected Pivot ...
AddIfNotExists(pivot, pivots);
}
//
has = count <= 0
? false
: ArraySize(pivots) >= count;
if (has)
{
break;
}
}
//
// Cleanup ...
bar.Clean();
pivot.Clean();
}
//
result = ArraySize(pivots);
//
// Cleanup ...
bar.Clean();
pivot.Clean();
//
return result;
}
/**
* Collect MA Pivots ...
*
* @param pivots: XPivot, reference collection to holds Detected Pivots ...
* @param barIndex: int, Specified Start Bar Index ...
* @param count: int, Specified number of required Pivots ...
* @param loopback: int, Max Allowed Loopback length for Detection ...
*
* @return ( int )
*/
int CollectMAPivots(
XPivot &pivots[],
int barIndex = 0,
int count = 50,
int loopback = 500 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(pivots);
//
// Normalize ...
count = NormalizeInt(count, 0);
loopback = NormalizeInt(loopback, 50);
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
bool has = fimaParser.IsValid();
if (!has)
{
return result;
}
//
// Do ...
XOHCL bar;
XPivot pivot;
int start = barIndex;
bool isBullish = false;
bool isBearish = false;
int end = start + loopback;
ENUM_X_DIRECTION dir = X_DIRECTION_NONE;
for (int i = start; i < end; i++)
{
//
isBullish = fimaParser.IsMAFastCrossedOverSlow(i);
isBearish = fimaParser.IsMAFastCrossedUnderSlow(i);
//
has = isBullish || isBearish;
if (has)
{
//
// Specified Direction ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Initialize Indexed Bar ...
// Validate it, and Converts it to Pivot ...
bar.Clean();
has = bar.Init(symbol, period, i);
has = has &&
ToPivot(
bar,
pivot,
dir,
ToXString(XFIMA_PIVOT_MA_CROSS) //
);
if (has)
{
//
// Replace MA Values ...
pivot.value =
isBullish
? fimaHelper.GetMASlow(barIndex)
: fimaHelper.GetMAFast(barIndex);
//
// Add Detected Pivot ...
AddIfNotExists(pivot, pivots);
}
//
has = count <= 0
? false
: ArraySize(pivots) >= count;
if (has)
{
break;
}
}
//
// Cleanup ...
bar.Clean();
pivot.Clean();
}
//
result = ArraySize(pivots);
//
// Cleanup ...
bar.Clean();
pivot.Clean();
//
return result;
}
/**
* Collect HK Pivots ...
*
* @param pivots: XPivot, reference collection to holds Detected Pivots ...
* @param barIndex: int, Specified Start Bar Index ...
* @param count: int, Specified number of required Pivots ...
* @param loopback: int, Max Allowed Loopback length for Detection ...
*
* @return ( int )
*/
int CollectHKPivots(
XPivot &pivots[],
int barIndex = 0,
int count = 50,
int loopback = 500 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(pivots);
//
// Normalize ...
count = NormalizeInt(count, 0);
loopback = NormalizeInt(loopback, 50);
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
bool has = fimaParser.IsValid();
if (!has)
{
return result;
}
//
// Do ...
XOHCL bar;
XPivot pivot;
int start = barIndex;
bool isBullish = false;
bool isBearish = false;
int end = start + loopback;
ENUM_X_DIRECTION dir = X_DIRECTION_NONE;
for (int i = start; i < end; i++)
{
//
isBullish = fimaParser.IsHKSwitchedToBullish(i);
isBearish = fimaParser.IsHKSwitchedToBearish(i);
//
has = isBullish || isBearish;
if (has)
{
//
// Specified Direction ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Initialize Indexed Bar ...
// Validate it, and Converts it to Pivot ...
bar.Clean();
has = bar.Init(symbol, period, i);
has = has &&
ToPivot(
bar,
pivot,
dir,
ToXString(XFIMA_PIVOT_HK_SWITCH) //
);
if (has)
{
//
// Replace Value ...
pivot.value =
isBullish
? fimaHelper.GetHKLow(i)
: fimaHelper.GetHKHigh(i);
//
// Add Detected Pivot ...
AddIfNotExists(pivot, pivots);
}
//
has = count <= 0
? false
: ArraySize(pivots) >= count;
if (has)
{
break;
}
}
//
// Cleanup ...
bar.Clean();
pivot.Clean();
}
//
result = ArraySize(pivots);
//
// Cleanup ...
bar.Clean();
pivot.Clean();
//
return result;
}
/**
* Collect PV Pivots ...
*
* @param pivots: XPivot, reference collection to holds Detected Pivots ...
* @param barIndex: int, Specified Start Bar Index ...
* @param count: int, Specified number of required Pivots ...
* @param loopback: int, Max Allowed Loopback length for Detection ...
*
* @return ( int )
*/
int CollectPVPivots(
XPivot &pivots[],
int barIndex = 0,
int count = 50,
int loopback = 500 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(pivots);
//
// Normalize ...
count = NormalizeInt(count, 0);
loopback = NormalizeInt(loopback, 50);
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
bool has = fimaParser.IsValid();
if (!has)
{
return result;
}
//
// Do ...
XOHCL bar;
XPivot pivot;
int start = barIndex;
bool isBullish = false;
bool isBearish = false;
int end = start + loopback;
ENUM_X_DIRECTION dir = X_DIRECTION_NONE;
for (int i = start; i < end; i++)
{
//
isBullish = fimaParser.IsPeakOverLast(i);
isBearish = fimaParser.IsValeUnderLast(i);
//
has = isBullish || isBearish;
if (has)
{
//
// Specified Direction ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Initialize Indexed Bar ...
// Validate it, and Converts it to Pivot ...
bar.Clean();
has = bar.Init(symbol, period, i);
has = has &&
ToPivot(
bar,
pivot,
dir,
ToXString(XFIMA_PIVOT_PV) //
);
if (has)
{
//
// Replace Value ...
pivot.value =
isBullish
? fimaHelper.GetHKLow(i)
: fimaHelper.GetHKHigh(i);
//
// Add Detected Pivot ...
AddIfNotExists(pivot, pivots);
}
//
has = count <= 0
? false
: ArraySize(pivots) >= count;
if (has)
{
break;
}
}
//
// Cleanup ...
bar.Clean();
pivot.Clean();
}
//
result = ArraySize(pivots);
//
// Cleanup ...
bar.Clean();
pivot.Clean();
//
return result;
}
/**
* Collect SAR Pivots ...
*
* @param pivots: XPivot, reference collection to holds Detected Pivots ...
* @param barIndex: int, Specified Start Bar Index ...
* @param count: int, Specified number of required Pivots ...
* @param loopback: int, Max Allowed Loopback length for Detection ...
*
* @return ( int )
*/
int CollectSARPivots(
XPivot &pivots[],
int barIndex = 0,
int count = 50,
int loopback = 500 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(pivots);
//
// Normalize ...
count = NormalizeInt(count, 0);
loopback = NormalizeInt(loopback, 50);
barIndex = fimaParser.NormalizeBarIndex(barIndex);
//
// Validate ...
bool has = fimaParser.IsValid();
if (!has)
{
return result;
}
//
// Do ...
XOHCL bar;
XPivot pivot;
int start = barIndex;
bool isBullish = false;
bool isBearish = false;
int end = start + loopback;
ENUM_X_DIRECTION dir = X_DIRECTION_NONE;
for (int i = start; i < end; i++)
{
//
isBullish = fimaParser.IsSARSwitchedToBullish(i);
isBearish = fimaParser.IsSARSwitchedToBearish(i);
//
has = isBullish || isBearish;
if (has)
{
//
// Specified Direction ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Initialize Indexed Bar ...
// Validate it, and Converts it to Pivot ...
bar.Clean();
has = bar.Init(symbol, period, i);
has = has &&
ToPivot(
bar,
pivot,
dir,
ToXString(XFIMA_PIVOT_SAR_SWITCH) //
);
if (has)
{
//
// Add Detected Pivot ...
AddIfNotExists(pivot, pivots);
}
//
has = count <= 0
? false
: ArraySize(pivots) >= count;
if (has)
{
break;
}
}
//
// Cleanup ...
bar.Clean();
pivot.Clean();
}
//
result = ArraySize(pivots);
//
// Cleanup ...
bar.Clean();
pivot.Clean();
//
return result;
}
/**
* Collect Specified ZOnes Boundary Min / Max Values ...
*
* @param uppers: XPivot, collection reference to holds Peaks of Zone's Boundary ...
* @param lowers: XPivot, collection reference to holds Vales of Zone's Boundary ...
* @param zone: XBoxZone, reference to Provide Specified Zone for Boundary Detection ...
*
* @return ( int )
*/
int CollectZonesBoundary(
XPivot &uppers[],
XPivot &lowers[],
XBoxZone &zone //
)
{
//
int result = 0;
//
// Prepare ...
XClean(uppers);
XClean(lowers);
//
// Validate ...
bool has = zone.IsValid() &&
fimaParser.IsValid();
if (!has)
{
return result;
}
//
double iUpper;
double iLower;
datetime iTime;
XPivot upperPivot;
XPivot lowerPivot;
int start = zone.ToIndex();
int end = zone.FromIndex();
for (int i = start; i <= end; i++)
{
//
iUpper = fimaParser.GetBoundaryMax(i);
iLower = fimaParser.GetBoundaryMin(i);
iTime = GetBarTime(zone.symbol, zone.period, i);
//
has =
IsXValid(iTime) &&
NotEmptyZero(iUpper) &&
NotEmptyZero(iLower);
if (has)
{
//
// Upper Pivot ...
upperPivot.Clean();
has = upperPivot.Init(
iUpper,
iTime,
zone.symbol,
zone.dir,
zone.period,
X_PIVOT_TYPE_PEAK //
);
if (has)
{
upperPivot.prefix = "XBNDUP";
}
//
// Lower Pivot ...
lowerPivot.Clean();
has = lowerPivot.Init(
iLower,
iTime,
zone.symbol,
zone.dir,
zone.period,
X_PIVOT_TYPE_VALE //
);
if (has)
{
lowerPivot.prefix = "XBNDLO";
}
//
has = upperPivot.IsValid() &&
lowerPivot.IsValid();
if (has)
{
//
AddRef(upperPivot, uppers);
AddRef(lowerPivot, lowers);
}
}
}
//
result = MathMin(ArraySize(uppers), ArraySize(lowers));
//
// Cleanup ...
upperPivot.Clean();
lowerPivot.Clean();
//
return result;
}
/**
* Check Zone Has Boundary Trend or not ...
*
* @param zone: XBoxZOne, reference to Specified Zone for Checking Trend ...
* @param trend: XTrend, reference to holds Detected Trend Result ...
* @param basedOnToTime: bool, if set true, do based on to and it's prev bar ...
*
* @return ( bool )
*/
bool HasBoundaryTrend(
XBoxZone &zone,
XTrend &trend,
bool basedOnToTime = false //
)
{
//
bool result = false;
//
// Prepare ...
trend.Clean();
//
// Validate ...
result =
zone.IsValid() &&
fimaParser.IsValid();
if (!result)
{
return result;
}
//
// Do ...
//
int toIDX = zone.ToIndex();
int fromIDX =
basedOnToTime
? toIDX + 1
: zone.FromIndex();
datetime fromTime = GetBarTime(zone.symbol, zone.period, fromIDX);
//
double toMin = fimaParser.GetBoundaryMin(toIDX);
double toMax = fimaParser.GetBoundaryMax(toIDX);
//
double fromMin = fimaParser.GetBoundaryMin(fromIDX);
double fromMax = fimaParser.GetBoundaryMax(fromIDX);
//
bool isMinBullish = fromMin < toMin;
bool isMaxBullish = fromMax < toMax;
bool isBullish = isMinBullish && isMaxBullish;
//
bool isMinBearish = fromMin > toMin;
bool isMaxBearish = fromMax > toMax;
bool isBearish = isMinBearish && isMaxBearish;
//
result = isBullish || isBearish;
if (result)
{
//
result = trend.Init(
zone.symbol,
zone.period,
TimeCurrent(),
isBullish
? fromMin
: fromMax,
fromTime,
isBullish
? toMin
: toMax,
zone.to //
);
}
//
// Validate Result ...
result = trend.IsValid() &&
trend.HasTrend();
if (!result)
{
trend.Clean();
}
//
return result;
}
/**
* Get Cycle Based PV Zone ...
*
* @param bar: XOHCL, reference to Specified Zone ...
* @param zone: XBoxZone, reference to holds PV Zone ...
*
* @return ( bool )
*/
bool GetSCZone(
XOHCL &bar,
XBoxZone &zone //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
int barIndex = bar.Index();
//
double upper = fimaHelper.GetSHH(barIndex);
double lower = fimaHelper.GetSLL(barIndex);
double pHH = fimaHelper.GetSHH(barIndex + 1);
double pLL = fimaHelper.GetSLL(barIndex + 1);
int sameLLs = fimaParser.CountSCSameLLs(barIndex);
int sameHHs = fimaParser.CountSCSameHHs(barIndex);
int fromIDX = barIndex + MathMax(sameLLs, sameHHs);
//
zone.to = bar.time;
zone.at = bar.time;
zone.upper = upper;
zone.lower = lower;
zone.symbol = bar.symbol;
zone.period = bar.period;
zone.dir =
(upper > pHH ||
lower > pLL)
? X_DIRECTION_BULLISH
: (upper < pHH ||
lower < pLL)
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
zone.type = ToXString(XFIMA_PIVOT_PV) + "_SC";
zone.from = GetBarTime(bar.symbol, bar.period, fromIDX);
//
result = zone.IsValid();
if (!result)
{
zone.Clean();
}
//
return result;
}
/**
* Get Cycle Based PV Zone ...
*
* @param bar: XOHCL, reference to Specified Zone ...
* @param zone: XBoxZone, reference to holds PV Zone ...
*
* @return ( bool )
*/
bool GetMCZone(
XOHCL &bar,
XBoxZone &zone //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
int barIndex = bar.Index();
//
double upper = fimaHelper.GetMHH(barIndex);
double lower = fimaHelper.GetMLL(barIndex);
double pHH = fimaHelper.GetMHH(barIndex + 1);
double pLL = fimaHelper.GetMLL(barIndex + 1);
int sameLLs = fimaParser.CountMCSameLLs(barIndex);
int sameHHs = fimaParser.CountMCSameHHs(barIndex);
int fromIDX = barIndex + MathMax(sameLLs, sameHHs);
//
zone.to = bar.time;
zone.at = bar.time;
zone.upper = upper;
zone.lower = lower;
zone.symbol = bar.symbol;
zone.period = bar.period;
zone.dir =
(upper > pHH ||
lower > pLL)
? X_DIRECTION_BULLISH
: (upper < pHH ||
lower < pLL)
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
zone.type = ToXString(XFIMA_PIVOT_PV) + "_MC";
zone.from = GetBarTime(bar.symbol, bar.period, fromIDX);
//
result = zone.IsValid();
if (!result)
{
zone.Clean();
}
//
return result;
}
/**
* Get Cycle Based PV Zone ...
*
* @param bar: XOHCL, reference to Specified Zone ...
* @param zone: XBoxZone, reference to holds PV Zone ...
*
* @return ( bool )
*/
bool GetLCZone(
XOHCL &bar,
XBoxZone &zone //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
int barIndex = bar.Index();
//
double upper = fimaHelper.GetLHH(barIndex);
double lower = fimaHelper.GetLLL(barIndex);
double pHH = fimaHelper.GetLHH(barIndex + 1);
double pLL = fimaHelper.GetLLL(barIndex + 1);
int sameLLs = fimaParser.CountLCSameLLs(barIndex);
int sameHHs = fimaParser.CountLCSameHHs(barIndex);
int fromIDX = barIndex + MathMax(sameLLs, sameHHs);
//
zone.to = bar.time;
zone.at = bar.time;
zone.upper = upper;
zone.lower = lower;
zone.symbol = bar.symbol;
zone.period = bar.period;
zone.dir =
(upper > pHH ||
lower > pLL)
? X_DIRECTION_BULLISH
: (upper < pHH ||
lower < pLL)
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
zone.type = ToXString(XFIMA_PIVOT_PV) + "_LC";
zone.from = GetBarTime(bar.symbol, bar.period, fromIDX);
//
result = zone.IsValid();
if (!result)
{
zone.Clean();
}
//
return result;
}
/**
* Get Cycle Based PV Zone ...
*
* @param bar: XOHCL, reference to Specified Zone ...
* @param zone: XBoxZone, reference to holds PV Zone ...
*
* @return ( bool )
*/
bool GetHCZone(
XOHCL &bar,
XBoxZone &zone //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
int barIndex = bar.Index();
//
double upper = fimaHelper.GetHHH(barIndex);
double lower = fimaHelper.GetHLL(barIndex);
double pHH = fimaHelper.GetHHH(barIndex + 1);
double pLL = fimaHelper.GetHLL(barIndex + 1);
int sameLLs = fimaParser.CountHCSameLLs(barIndex);
int sameHHs = fimaParser.CountHCSameHHs(barIndex);
int fromIDX = barIndex + MathMax(sameLLs, sameHHs);
//
zone.to = bar.time;
zone.at = bar.time;
zone.upper = upper;
zone.lower = lower;
zone.symbol = bar.symbol;
zone.period = bar.period;
zone.dir =
(upper > pHH ||
lower > pLL)
? X_DIRECTION_BULLISH
: (upper < pHH ||
lower < pLL)
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
zone.type = ToXString(XFIMA_PIVOT_PV) + "_HC";
zone.from = GetBarTime(bar.symbol, bar.period, fromIDX);
//
result = zone.IsValid();
if (!result)
{
zone.Clean();
}
//
return result;
}
/**
* Check Specified Bar is Rejected Specified XFIMA Values or not ...
*
* @param bar: XOHCL, reference to Specified Bar ...
* @param rejecteds: double, collection reference to holds Rejected Values ...
* @param forDir: ENUM_X_DIRECTION, Specified required Rejection Direction ...
* @param bullishRejectUpperPriceType: ENUM_X_PRICE, Specified Bullish Rejection Upper Price Type ...
* @param bullishRejectLowerPriceType: ENUM_X_PRICE, Specified Bullish Rejection Lower Price Type ...
* @param bearishRejectUpperPriceType: ENUM_X_PRICE, Specified Bearish Rejection Upper Price Type ...
* @param bearishRejectLowerPriceType: ENUM_X_PRICE, Specified Bearish Rejection Lower Price Type ...
* @param ignoreBoundary: bool, ignoring XFIMA Max and Min Values Rejections ...
*
* @return ( int )
*/
int IsRejectXFIMA(
XOHCL &bar,
double &rejecteds[],
ENUM_X_DIRECTION forDir,
ENUM_X_PRICE bullishRejectUpperPriceType = X_PRICE_DOWN,
ENUM_X_PRICE bullishRejectLowerPriceType = X_PRICE_LOW,
ENUM_X_PRICE bearishRejectUpperPriceType = X_PRICE_HIGH,
ENUM_X_PRICE bearishRejectLowerPriceType = X_PRICE_UP,
bool ignoreBoundary = true //
)
{
//
int result = 0;
//
// Prepare ...
XClean(rejecteds);
//
// Validate ...
bool has =
bar.IsValid() &&
fimaParser.IsValid() &&
HasDirection(forDir) &&
IsXValid(bullishRejectLowerPriceType) &&
IsXValid(bullishRejectUpperPriceType) &&
IsXValid(bearishRejectUpperPriceType) &&
IsXValid(bearishRejectLowerPriceType);
if (!has)
{
return result;
}
//
int pBarIndex = bar.Index() + 1;
bool isBullish = IsXBullish(forDir);
//
// Reading Values ...
double values[];
int count = fimaParser.ReadXFIMAValues(values, pBarIndex);
has = HasChild(values);
//
// Detect Rejected Prices ...
if (has)
{
//
double min = GetMin(values);
double max = GetMax(values);
//
for (int i = 0; i < count; i++)
{
//
// Detect Rejection ...
has =
isBullish
? (bar.GetPrice(bullishRejectLowerPriceType) < values[i] &&
bar.GetPrice(bullishRejectUpperPriceType) > values[i])
: (bar.GetPrice(bearishRejectUpperPriceType) > values[i] &&
bar.GetPrice(bearishRejectLowerPriceType) < values[i]);
if (has)
{
//
// Validate Rejection ...
if (ignoreBoundary)
{
//
has =
has &&
(values[i] != min &&
values[i] != max);
}
//
// Add Result ...
if (has)
{
Add(values[i], rejecteds);
}
}
}
}
//
result = ArraySize(rejecteds);
//
return result;
}
//
// Others ...
/**
* Destroy ...
*/
void Destroy()
{
//
delete barAnalyser;
ZeroMemory(barAnalyser);
//
ZeroMemory(fimaHelper);
ZeroMemory(fimaParser);
}
//
// Testers ...
//
// Protected ...
protected:
//
// Props ...
//
// Private ...
private:
//
//
};
//