1459 lines
35 KiB
Plaintext
1459 lines
35 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_ZIGZAG = 2,
|
|
XFIMA_PIVOT_MA_CROSS = 3,
|
|
XFIMA_PIVOT_HK_SWITCH = 4,
|
|
XFIMA_PIVOT_SAR_SWITCH = 5,
|
|
XFIMA_PIVOT_BOUNDARY_SWITCH = 6,
|
|
};
|
|
|
|
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_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_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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Others ...
|
|
|
|
/**
|
|
* Destroy ...
|
|
*/
|
|
void Destroy()
|
|
{
|
|
//
|
|
delete barAnalyser;
|
|
ZeroMemory(barAnalyser);
|
|
|
|
//
|
|
ZeroMemory(fimaHelper);
|
|
ZeroMemory(fimaParser);
|
|
}
|
|
|
|
//
|
|
// Testers ...
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
// |