1300 lines
36 KiB
Plaintext
1300 lines
36 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 ...
|
|
XCXFIMAHelper *fimaHelper; // XFIMA Helper ...
|
|
|
|
//
|
|
XBoxZone obs[];
|
|
XBoxZone fvgs[];
|
|
XBoxZone supports[];
|
|
XBoxZone resistances[];
|
|
|
|
//
|
|
// Constructor ...
|
|
XCXFIMAPOIDetector(
|
|
XCXFIMAHelper *_fimaHelper //
|
|
) : XCMarketPatternDetector()
|
|
{
|
|
//
|
|
barAnalyser = new XCBarAnalyser();
|
|
fimaHelper = _fimaHelper;
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCXFIMAPOIDetector()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
//
|
|
// Actions and Tools ...
|
|
|
|
//
|
|
// Pivot Analysors ...
|
|
|
|
/**
|
|
* Analyse Market based on Specified Kind of Pivots ...
|
|
*
|
|
* @param analysis: XPivotAnalysis, reference to hold result ...
|
|
* @param barIndex: int, Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
* @param validationLength: int, Specified Pivots Validation Length ignore if <= 0 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AnalysePVPivots(
|
|
XPivotAnalysis &analysis,
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500,
|
|
int validationLength = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
analysis.Clean();
|
|
|
|
//
|
|
// Reading Pivots ...
|
|
XPivot pivots[];
|
|
int count = ExtractPVPivots(
|
|
pivots, // Result ...
|
|
barIndex, // Bar Index ...
|
|
requiredNumberOFPivots, // Required Number of Pivots ...
|
|
maxAllowedLoopbackLength, // Max Allowed Loopback ...
|
|
validationLength // Validation Length ...
|
|
);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
//
|
|
SpecifiedClean(pivots);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = fimaHelper.GetSymbol();
|
|
ENUM_TIMEFRAMES period = fimaHelper.GetPeriod();
|
|
|
|
//
|
|
// Initialize Analysis ...
|
|
result = analysis.Init(
|
|
"XFIMA_XPV",
|
|
symbol,
|
|
period,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
if (!result)
|
|
{
|
|
analysis.Clean();
|
|
}
|
|
SpecifiedClean(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Analyse Market based on Specified Kind of Pivots ...
|
|
*
|
|
* @param analysis: XPivotAnalysis, reference to hold result ...
|
|
* @param barIndex: int, Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
* @param validationLength: int, Specified Pivots Validation Length ignore if <= 0 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AnalyseMAPivots(
|
|
XPivotAnalysis &analysis,
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500,
|
|
int validationLength = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
analysis.Clean();
|
|
|
|
//
|
|
// Reading Pivots ...
|
|
XPivot pivots[];
|
|
int count = ExtractMAPivots(
|
|
pivots, // Result ...
|
|
barIndex, // Bar Index ...
|
|
requiredNumberOFPivots, // Required Number of Pivots ...
|
|
maxAllowedLoopbackLength, // Max Allowed Loopback ...
|
|
validationLength // Validation Length ...
|
|
);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
//
|
|
SpecifiedClean(pivots);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = fimaHelper.GetSymbol();
|
|
ENUM_TIMEFRAMES period = fimaHelper.GetPeriod();
|
|
|
|
//
|
|
// Initialize Analysis ...
|
|
result = analysis.Init(
|
|
"XFIMA_XMA",
|
|
symbol,
|
|
period,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
if (!result)
|
|
{
|
|
analysis.Clean();
|
|
}
|
|
SpecifiedClean(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Analyse Market based on Specified Kind of Pivots ...
|
|
*
|
|
* @param analysis: XPivotAnalysis, reference to hold result ...
|
|
* @param barIndex: int, Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AnalyseSARPivots(
|
|
XPivotAnalysis &analysis,
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
analysis.Clean();
|
|
|
|
//
|
|
// Reading Pivots ...
|
|
XPivot pivots[];
|
|
int count = ExtractSARPivots(
|
|
pivots, // Result ...
|
|
barIndex, // Bar Index ...
|
|
requiredNumberOFPivots, // Required Number of Pivots ...
|
|
maxAllowedLoopbackLength // Max Allowed Loopback ...
|
|
);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
//
|
|
SpecifiedClean(pivots);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = fimaHelper.GetSymbol();
|
|
ENUM_TIMEFRAMES period = fimaHelper.GetPeriod();
|
|
|
|
//
|
|
// Initialize Analysis ...
|
|
result = analysis.Init(
|
|
"XFIMA_XSAR",
|
|
symbol,
|
|
period,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
if (!result)
|
|
{
|
|
analysis.Clean();
|
|
}
|
|
SpecifiedClean(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Analyse Market based on Specified Kind of Pivots ...
|
|
*
|
|
* @param analysis: XPivotAnalysis, reference to hold result ...
|
|
* @param barIndex: int, Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AnalyseZigZagPivots(
|
|
XPivotAnalysis &analysis,
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
analysis.Clean();
|
|
|
|
//
|
|
// Reading Pivots ...
|
|
XPivot pivots[];
|
|
int count = ExtractZigZagPivots(
|
|
pivots, // Result ...
|
|
barIndex, // Bar Index ...
|
|
requiredNumberOFPivots, // Required Number of Pivots ...
|
|
maxAllowedLoopbackLength // Max Allowed Loopback ...
|
|
);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
//
|
|
SpecifiedClean(pivots);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = fimaHelper.GetSymbol();
|
|
ENUM_TIMEFRAMES period = fimaHelper.GetPeriod();
|
|
|
|
//
|
|
// Initialize Analysis ...
|
|
result = analysis.Init(
|
|
"XFIMA_XZG",
|
|
symbol,
|
|
period,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
if (!result)
|
|
{
|
|
analysis.Clean();
|
|
}
|
|
SpecifiedClean(pivots);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Pivot Extractors ...
|
|
|
|
/**
|
|
* Extract Specified Kind of Pivots ...
|
|
*
|
|
* @param pivots: XPivot, refrence Collection to hold Extracted pivots ...
|
|
* @param barIndex: int, Specified Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
* @param validationLength: int, Specified Pivots Validation Length ignore if <= 0 ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int ExtractPVPivots(
|
|
XPivot &pivots[],
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500,
|
|
int validationLength = 0 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
result = fimaHelper.ExtractPVPivots(
|
|
pivots,
|
|
barIndex,
|
|
requiredNumberOFPivots,
|
|
maxAllowedLoopbackLength,
|
|
validationLength //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Extract Specified Kind of Pivots ...
|
|
*
|
|
* @param pivots: XPivot, refrence Collection to hold Extracted pivots ...
|
|
* @param barIndex: int, Specified Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
* @param validationLength: int, Specified Pivots Validation Length ignore if <= 0 ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int ExtractMAPivots(
|
|
XPivot &pivots[],
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500,
|
|
int validationLength = 0 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
result = fimaHelper.ExtractMAPivots(
|
|
pivots,
|
|
barIndex,
|
|
requiredNumberOFPivots,
|
|
maxAllowedLoopbackLength,
|
|
validationLength //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Extract Specified Kind of Pivots ...
|
|
*
|
|
* @param pivots: XPivot, refrence Collection to hold Extracted pivots ...
|
|
* @param barIndex: int, Specified Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int ExtractSARPivots(
|
|
XPivot &pivots[],
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
result = fimaHelper.ExtractSARPivots(
|
|
pivots,
|
|
barIndex,
|
|
requiredNumberOFPivots,
|
|
maxAllowedLoopbackLength //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Extract Specified Kind of Pivots ...
|
|
*
|
|
* @param pivots: XPivot, refrence Collection to hold Extracted pivots ...
|
|
* @param barIndex: int, Specified Bar Index ...
|
|
* @param requiredNumberOFPivots: int, Specified which Number of Pivots must be Extracted ...
|
|
* @param maxAllowedLoopbackLength: int, Specified Maximum Loopback Length for Pivot Extraction ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int ExtractZigZagPivots(
|
|
XPivot &pivots[],
|
|
int barIndex = 0,
|
|
int requiredNumberOFPivots = 50,
|
|
int maxAllowedLoopbackLength = 1500 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
result = fimaHelper.ExtractZigZagPivots(
|
|
pivots,
|
|
barIndex,
|
|
requiredNumberOFPivots,
|
|
maxAllowedLoopbackLength //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Destroy ...
|
|
*/
|
|
void Destroy()
|
|
{
|
|
//
|
|
SpecifiedClean(obs);
|
|
SpecifiedClean(fvgs);
|
|
SpecifiedClean(supports);
|
|
SpecifiedClean(resistances);
|
|
|
|
//
|
|
delete barAnalyser;
|
|
ZeroMemory(barAnalyser);
|
|
}
|
|
|
|
//
|
|
// Testers ...
|
|
|
|
/**
|
|
* Analyse Market based on Specified Bar ...
|
|
*
|
|
* @param forBar: XOHCL, reference Specified Bar for Analyse Market ...
|
|
* @param structure: XFIMAMarketStructure, reference to holds result ...
|
|
* @param config: XFIMAPatternDetectorConfig, reference to Configure Detector ...
|
|
*/
|
|
void AnalyseMarket(
|
|
XOHCL &forBar,
|
|
XFIMAMarketStructure &structure,
|
|
XFIMAPatternDetectorConfig &config //
|
|
)
|
|
{
|
|
//
|
|
// Prepare ...
|
|
structure.Clean();
|
|
|
|
//
|
|
// Validate ...
|
|
if (!forBar.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do Analysis ...
|
|
|
|
//
|
|
structure.bar = forBar;
|
|
|
|
//
|
|
int idx = -1;
|
|
bool has = false;
|
|
int maxAllowedCollecting = 50;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Detecting POI Based on Config ...
|
|
|
|
//
|
|
// Order Block ...
|
|
if (config.detectOB)
|
|
{
|
|
//
|
|
bool isOB = HasOB(
|
|
forBar,
|
|
iDir,
|
|
structure.ob,
|
|
config.obLoopback //
|
|
);
|
|
bool isBullishOB = isOB &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishOB = isOB &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (!isOB)
|
|
{
|
|
structure.ob.Clean();
|
|
}
|
|
|
|
//
|
|
// Detect Touches ...
|
|
if (isOB)
|
|
{
|
|
//
|
|
AddIfNotExists(
|
|
structure.ob,
|
|
obs,
|
|
maxAllowedCollecting //
|
|
);
|
|
|
|
//
|
|
XOHCL pBar;
|
|
bool has = forBar.GetPreviousBar(pBar);
|
|
if (has)
|
|
{
|
|
//
|
|
structure.isOBTouched =
|
|
isBullishOB
|
|
? pBar.low < structure.ob.upper
|
|
: pBar.high > structure.ob.lower;
|
|
}
|
|
|
|
//
|
|
pBar.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fair Value Gap ...
|
|
if (config.detectFVG)
|
|
{
|
|
//
|
|
bool isFVG = HasFVG(
|
|
forBar,
|
|
iDir,
|
|
structure.fvg,
|
|
config.fvgLoopback //
|
|
);
|
|
bool isBullishFVG = isFVG &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishFVG = isFVG &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (!isFVG)
|
|
{
|
|
structure.fvg.Clean();
|
|
}
|
|
|
|
//
|
|
// Detect Touches ...
|
|
if (isFVG)
|
|
{
|
|
//
|
|
AddIfNotExists(
|
|
structure.fvg,
|
|
fvgs,
|
|
maxAllowedCollecting //
|
|
);
|
|
|
|
//
|
|
XOHCL pBar;
|
|
bool has = forBar.GetPreviousBar(pBar);
|
|
if (has)
|
|
{
|
|
//
|
|
structure.isFVGTouched =
|
|
isBullishFVG
|
|
? pBar.low < structure.fvg.upper
|
|
: pBar.high > structure.fvg.lower;
|
|
}
|
|
|
|
//
|
|
pBar.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Momentum Bar ...
|
|
if (config.detectMomentum)
|
|
{
|
|
//
|
|
bool isMomentum = IsMomentumBar(
|
|
forBar,
|
|
iDir,
|
|
config.momentumBarRangeLength,
|
|
config.momentumBarApprovedMultiplier //
|
|
);
|
|
bool isBullishMomentum = isMomentum &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishMomentum = isMomentum &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isMomentum)
|
|
{
|
|
structure.momentumDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Engulfed Bar ...
|
|
if (config.detectEngulfed)
|
|
{
|
|
//
|
|
bool isEngulfed = IsEngulfedBar(
|
|
forBar,
|
|
iDir //
|
|
);
|
|
bool isBullishEngulfed = isEngulfed &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishEngulfed = isEngulfed &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isEngulfed)
|
|
{
|
|
structure.engulfedDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking TruGaped Bar ...
|
|
if (config.detectTrueGaped)
|
|
{
|
|
//
|
|
bool isTrueGaped = IsTrueGapedBar(
|
|
forBar,
|
|
iDir,
|
|
config.truwGapApprovedPointMultiplier //
|
|
);
|
|
bool isBullishTrueGaped = isTrueGaped &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishTrueGaped = isTrueGaped &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isTrueGaped)
|
|
{
|
|
structure.trueGapedDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Pinned Bar ...
|
|
if (config.detectPinned)
|
|
{
|
|
//
|
|
bool isPinned = IsPinnedBar(
|
|
forBar,
|
|
iDir,
|
|
config.pinnedBaarShadowApprovedMultiplier,
|
|
config.pinnedBarMinimumPinBarRangeMultiplier,
|
|
config.pinnedBarForceDirection //
|
|
);
|
|
bool isBullishPinned = isPinned &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishPinned = isPinned &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isPinned)
|
|
{
|
|
structure.pinnedDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Star Pattern ...
|
|
if (config.detectStarPattern)
|
|
{
|
|
//
|
|
bool isStarPattern = IsStartPattern(
|
|
forBar,
|
|
iDir //
|
|
);
|
|
bool isBullishStarPattern = isStarPattern &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishStarPattern = isStarPattern &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isStarPattern)
|
|
{
|
|
structure.starPatternDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Piercing Pattern ...
|
|
if (config.detectPiercingPattern)
|
|
{
|
|
//
|
|
bool isPiercingPattern = IsPiercingPattern(
|
|
forBar,
|
|
iDir //
|
|
);
|
|
bool isBullishPiercingPattern = isPiercingPattern &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishPiercingPattern = isPiercingPattern &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isPiercingPattern)
|
|
{
|
|
structure.piercingPatternDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Rising Pattern ...
|
|
if (config.detectRisingPattern)
|
|
{
|
|
//
|
|
bool isRisingPattern = IsRisingPattern(
|
|
forBar,
|
|
iDir //
|
|
);
|
|
bool isBullishRisingPattern = isRisingPattern &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishRisingPattern = isRisingPattern &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isRisingPattern)
|
|
{
|
|
structure.risingPatternDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking Flag Pattern ...
|
|
if (config.detectFlagPattern)
|
|
{
|
|
//
|
|
XOHCL swingBar;
|
|
bool isFlagPattern = IsFlagPattern(
|
|
forBar,
|
|
iDir,
|
|
swingBar,
|
|
config.flagPatternMinimumPullbackBars //
|
|
);
|
|
bool isBullishFlagPattern = isFlagPattern &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishFlagPattern = isFlagPattern &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isFlagPattern)
|
|
{
|
|
//
|
|
structure.flagSwing = swingBar;
|
|
structure.flagPatternDir = iDir;
|
|
}
|
|
swingBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Detect SignalKey Bar Pattern ...
|
|
if (config.detectSignalKeyBarPattern)
|
|
{
|
|
//
|
|
bool isSignalKeyBar = IsSignalKeyBarPattern(
|
|
forBar,
|
|
iDir,
|
|
config.signalKeyBarShadowApprovedMultiplier,
|
|
config.signalKeyBarMinimumPinBarRangeMultiplier,
|
|
config.signalKeyBarForceDirection //
|
|
);
|
|
bool isBullishSignalKeyBar = isSignalKeyBar &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool isBearishSignalKeyBar = isSignalKeyBar &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (isSignalKeyBar)
|
|
{
|
|
structure.signalKeyBarPatternDir = iDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Detect Swing Trend ...
|
|
if (config.detectSwingTrend)
|
|
{
|
|
//
|
|
XOHCL swings[];
|
|
bool hasSwingTrend = HasSwingTrend(
|
|
forBar,
|
|
iDir,
|
|
swings,
|
|
config.trendingNumberOfSwings,
|
|
config.trendingSwingShoulders //
|
|
);
|
|
bool hasBullishSwingTrend = hasSwingTrend &&
|
|
IsSpecifiedBullish(iDir);
|
|
bool hasBearishSwingTrend = hasSwingTrend &&
|
|
IsSpecifiedBearish(iDir);
|
|
if (hasSwingTrend)
|
|
{
|
|
//
|
|
Copy(
|
|
swings,
|
|
structure.trendSwings //
|
|
);
|
|
structure.trendDir = iDir;
|
|
}
|
|
SpecifiedClean(swings);
|
|
}
|
|
|
|
//
|
|
// Detect Supports ...
|
|
if (config.detectSupport)
|
|
{
|
|
//
|
|
XOHCL support;
|
|
bool hasSupport = HasSupport(
|
|
forBar,
|
|
support,
|
|
config.supportAndResistanceValidationLength,
|
|
config.supportAndResistanceMaxAllowedLoopback //
|
|
);
|
|
if (hasSupport)
|
|
{
|
|
//
|
|
XBoxZone supportBox;
|
|
has = ToSupportBox(support, supportBox);
|
|
|
|
//
|
|
// Validate Zone Strength if Provided ...
|
|
if (config.minAllowdSupportAndResistanceStrength > 0)
|
|
{
|
|
//
|
|
has = has &&
|
|
ValidateStrength(
|
|
supportBox,
|
|
config.minAllowdSupportAndResistanceStrength //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (has)
|
|
{
|
|
//
|
|
AddIfNotExists(
|
|
supportBox,
|
|
supports,
|
|
maxAllowedCollecting //
|
|
);
|
|
|
|
//
|
|
structure.support = supportBox;
|
|
}
|
|
|
|
//
|
|
// Check for Support Touches ...
|
|
XOHCL pBar;
|
|
has = has &&
|
|
forBar.GetPreviousBar(pBar);
|
|
if (has)
|
|
{
|
|
structure.isSupportTouched = pBar.low < supportBox.upper;
|
|
}
|
|
|
|
//
|
|
pBar.Clean();
|
|
supportBox.Clean();
|
|
}
|
|
support.Clean();
|
|
}
|
|
|
|
//
|
|
// Detect Resistance ...
|
|
if (config.detectResistance)
|
|
{
|
|
//
|
|
XOHCL resistance;
|
|
bool hasResistance = HasResistance(
|
|
forBar,
|
|
resistance,
|
|
config.supportAndResistanceValidationLength,
|
|
config.supportAndResistanceMaxAllowedLoopback //
|
|
);
|
|
if (hasResistance)
|
|
{
|
|
//
|
|
XBoxZone resistanceBox;
|
|
has = ToResistanceBox(resistance, resistanceBox);
|
|
|
|
//
|
|
// Validate Zone Strength if Provided ...
|
|
if (config.minAllowdSupportAndResistanceStrength > 0)
|
|
{
|
|
//
|
|
has = has &&
|
|
ValidateStrength(
|
|
resistanceBox,
|
|
config.minAllowdSupportAndResistanceStrength //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (has)
|
|
{
|
|
//
|
|
AddIfNotExists(
|
|
resistanceBox,
|
|
resistances,
|
|
maxAllowedCollecting //
|
|
);
|
|
|
|
//
|
|
structure.resistance = resistanceBox;
|
|
}
|
|
|
|
//
|
|
// Check for Resistance Touches ...
|
|
XOHCL pBar;
|
|
has = has &&
|
|
forBar.GetPreviousBar(pBar);
|
|
if (has)
|
|
{
|
|
structure.isResistanceTouched = pBar.high > resistanceBox.upper;
|
|
}
|
|
|
|
//
|
|
pBar.Clean();
|
|
resistanceBox.Clean();
|
|
}
|
|
resistance.Clean();
|
|
}
|
|
|
|
//
|
|
// Analysers ...
|
|
|
|
//
|
|
// Analyse Based on PV ...
|
|
if (config.analyseFIMAPVPivots)
|
|
{
|
|
//
|
|
XPivotAnalysis analysis;
|
|
has = AnalysePVPivots(
|
|
analysis, // Result ...
|
|
forBar.Index(), // Bar Index ...
|
|
config.numberOfRequiredPivotsForAnalysis, // Required Number of Pivots ...
|
|
config.maxAllowedLoopbackLengthForAnalysis, // Max Allowed Loopback ...
|
|
config.pvPivotsValidationLength // Validation Length ...
|
|
);
|
|
if (has)
|
|
{
|
|
structure.pvAnalysis = analysis;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Analyse Based on MA ...
|
|
if (config.analyseFIMAMAPivots)
|
|
{
|
|
//
|
|
XPivotAnalysis analysis;
|
|
has = AnalyseMAPivots(
|
|
analysis, // Result ...
|
|
forBar.Index(), // Bar Index ...
|
|
config.numberOfRequiredPivotsForAnalysis, // Required Number of Pivots ...
|
|
config.maxAllowedLoopbackLengthForAnalysis, // Max Allowed Loopback ...
|
|
config.pvPivotsValidationLength // Validation Length ...
|
|
);
|
|
if (has)
|
|
{
|
|
structure.maAnalysis = analysis;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Analyse Based on SAR ...
|
|
if (config.analyseFIMASARPivots)
|
|
{
|
|
//
|
|
XPivotAnalysis analysis;
|
|
has = AnalyseSARPivots(
|
|
analysis, // Result ...
|
|
forBar.Index(), // Bar Index ...
|
|
config.numberOfRequiredPivotsForAnalysis, // Required Number of Pivots ...
|
|
config.maxAllowedLoopbackLengthForAnalysis // Max Allowed Loopback ...
|
|
);
|
|
if (has)
|
|
{
|
|
structure.sarAnalysis = analysis;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Analyse Based on ZigZag ...
|
|
if (config.analyseFIMAZigZagPivots)
|
|
{
|
|
//
|
|
XPivotAnalysis analysis;
|
|
has = AnalyseZigZagPivots(
|
|
analysis, // Result ...
|
|
forBar.Index(), // Bar Index ...
|
|
config.numberOfRequiredPivotsForAnalysis, // Required Number of Pivots ...
|
|
config.maxAllowedLoopbackLengthForAnalysis // Max Allowed Loopback ...
|
|
);
|
|
if (has)
|
|
{
|
|
structure.zigzagAnalysis = analysis;
|
|
}
|
|
}
|
|
|
|
//
|
|
// COMPLEX Actions ...
|
|
|
|
//
|
|
// Lockup For Previous Zone ...
|
|
has = structure.isSupportTouched ||
|
|
structure.isResistanceTouched;
|
|
if (has)
|
|
{
|
|
//
|
|
if (structure.isSupportTouched)
|
|
{
|
|
//
|
|
idx = GetYoungestBefore(
|
|
structure.support.from,
|
|
supports //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
structure.prevZone = supports[idx];
|
|
}
|
|
}
|
|
else if (structure.isResistanceTouched)
|
|
{
|
|
//
|
|
idx = GetYoungestBefore(
|
|
structure.resistance.from,
|
|
resistances //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
structure.prevZone = resistances[idx];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Detect Recently Tested Zones ...
|
|
if ((config.detectSupport ||
|
|
config.detectResistance) &&
|
|
config.recentlyTestedZonesMaxLookup > 0)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
int idx = -1;
|
|
bool has = false;
|
|
|
|
//
|
|
int start = forBar.Index() + 1;
|
|
int end = start + config.recentlyTestedZonesMaxLookup;
|
|
for (int i = start; i < end; i++) {
|
|
//
|
|
// Initialize Indexed Bar ...
|
|
has = forBar.BarAt(i, iBar);
|
|
if (!has) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Selecting Support and Resistances ...
|
|
|
|
//
|
|
// Supports ...
|
|
idx = GetYoungestBefore(iBar.time, supports);
|
|
has = IsValidIndex(idx);
|
|
if (has) {
|
|
//
|
|
// Check Testing ...
|
|
has = IsTested(iBar, supports[idx]);
|
|
if (has) {
|
|
//
|
|
AddIfNotExists(
|
|
supports[idx],
|
|
structure.recentlyTestedZones //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resistances ...
|
|
idx = GetYoungestBefore(iBar.time, resistances);
|
|
has = IsValidIndex(idx);
|
|
if (has) {
|
|
//
|
|
// Check Testing ...
|
|
has = IsTested(iBar, resistances[idx]);
|
|
if (has) {
|
|
//
|
|
AddIfNotExists(
|
|
resistances[idx],
|
|
structure.recentlyTestedZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checkup for FakeBreaked Zones ...
|
|
if (config.detectSupport ||
|
|
config.detectResistance)
|
|
{
|
|
//
|
|
// Retrieve Previous Bar ...
|
|
int idx = -1;
|
|
XOHCL pForBar;
|
|
XOHCL breakerBar;
|
|
XBoxZone pSupport;
|
|
XOHCL pBreakerBar;
|
|
XBoxZone pResistance;
|
|
|
|
//
|
|
// Selecting Previously Touched Support / Resistance ...
|
|
has = forBar.GetPreviousBar(pForBar);
|
|
if (has)
|
|
{
|
|
//
|
|
// Detecting Nearest Above Lows Support ...
|
|
idx = GetYoungestAbove(
|
|
pForBar.low,
|
|
supports //
|
|
);
|
|
has = IsValidIndex(idx) &&
|
|
IsBreaked(
|
|
forBar,
|
|
supports[idx] //
|
|
);
|
|
if (has)
|
|
{
|
|
pSupport = supports[idx];
|
|
}
|
|
|
|
//
|
|
// Detecting Nearest Below Highs Resistance ...
|
|
idx = GetYoungestBelow(
|
|
pForBar.high,
|
|
resistances //
|
|
);
|
|
has = IsValidIndex(idx) &&
|
|
IsBreaked(
|
|
forBar,
|
|
resistances[idx] //
|
|
);
|
|
if (has)
|
|
{
|
|
pResistance = resistances[idx];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check at least a zone Exists ...
|
|
// Selecting pTestedZone ...
|
|
has = pSupport.IsValid() ||
|
|
pResistance.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
// Support ...
|
|
has = pSupport.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
structure.isPTest = true;
|
|
structure.pTestedZone = pSupport;
|
|
}
|
|
|
|
//
|
|
// Resistance ...
|
|
has = pResistance.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
structure.isPTest = true;
|
|
structure.pTestedZone = pResistance;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check pTestedZone Existance ...
|
|
has = structure.isPTest &&
|
|
structure.pTestedZone.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
// Get Breaker Bars ...
|
|
XOHCL breakerBars[];
|
|
int breakerBarsCount = GetBreakerBars(
|
|
structure.pTestedZone,
|
|
breakerBars //
|
|
);
|
|
has = IsValidSize(breakerBarsCount);
|
|
if (has)
|
|
{
|
|
//
|
|
idx = GetYoungestBar(breakerBars);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
breakerBar = breakerBars[idx];
|
|
}
|
|
}
|
|
|
|
//
|
|
SpecifiedClean(breakerBars);
|
|
}
|
|
|
|
//
|
|
// Check Zone Breaker Bar Exists ...
|
|
// Validate Zone Fake Breake Langth ...
|
|
has = breakerBar.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
// Validate Breake Length ...
|
|
has = (breakerBar.Index() - pForBar.Index()) <= config.supportAndResistanceBreakeValidationLength;
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
//
|
|
if (!has)
|
|
{
|
|
//
|
|
structure.isPTest = false;
|
|
structure.pTestedZone.Clean();
|
|
}
|
|
pForBar.Clean();
|
|
pSupport.Clean();
|
|
breakerBar.Clean();
|
|
pBreakerBar.Clean();
|
|
pResistance.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Tools / Actions ...
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
// |