1069 lines
23 KiB
Plaintext
1069 lines
23 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// ----------------------------------------------
|
|
// Name: XCMarketPatternDetector
|
|
// Description: provides all Alerts requirements ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../Classes/x-saherelm.base.class.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Implementation ...
|
|
class XCMarketPatternDetector : public XCBase
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XCMarketPatternDetector()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCMarketPatternDetector()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Actions / Helpers ...
|
|
|
|
/**
|
|
* Check Specified Bar is Momentum Bar or not ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
* @param requiredBars: int, bar range for approve Momentum ...
|
|
* @param approvedMultiplier: int, a Multipler for approve Momentum ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsMomentumBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int requiredBars = 3,
|
|
int approvedMultiplier = 2 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Normalizing ...
|
|
requiredBars = NormalizeInt(requiredBars, 3, 10);
|
|
approvedMultiplier = NormalizeInt(approvedMultiplier, 2, 5);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Requirements ...
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool has = false;
|
|
double rangeBody = 0;
|
|
int start = bar.Index() + 1;
|
|
int end = start + requiredBars;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
// Initialized Bar ...
|
|
has = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
|
|
//
|
|
// Summarize Body Sizes ...
|
|
if (has)
|
|
{
|
|
rangeBody += iBar.GetBody();
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Calculate Body Approvement ...
|
|
result = bar.GetBody() >= (approvedMultiplier * rangeBody);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Direction ...
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Engulfed Bar or not ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsEngulfedBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Requirements ...
|
|
|
|
//
|
|
XOHCL iBar;
|
|
result = bar.GetPreviousBar(iBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Prev Bar Must Inside Bar ...
|
|
result = bar.GetUp() > iBar.GetUp() &&
|
|
bar.GetDown() < iBar.GetDown();
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
iBar.IsBearish() &&
|
|
bar.IsBullish();
|
|
bool isBearish =
|
|
iBar.IsBullish() &&
|
|
bar.IsBearish();
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is True Gapped Bar or not ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
* @param approvedPointMultiplier: double, Gap Validation Multiplier in Point ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsTrueGapedBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
double approvedPointMultiplier = 1 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Normalizing ...
|
|
approvedPointMultiplier = NormalizeDouble(approvedPointMultiplier, 1, 100);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Requirements ...
|
|
|
|
//
|
|
XOHCL iBar;
|
|
result = bar.GetPreviousBar(iBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
iBar.IsBullish() &&
|
|
bar.IsBullish();
|
|
bool isBearish =
|
|
iBar.IsBearish() &&
|
|
bar.IsBearish();
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double point = GetPoints(bar.symbol);
|
|
double approvedGapSize = approvedPointMultiplier * point;
|
|
|
|
//
|
|
// Check Gap Exists ...
|
|
result =
|
|
isBullish
|
|
? bar.low > iBar.high
|
|
: iBar.low > bar.high;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Gap Size ...
|
|
double gapSize = isBullish
|
|
? bar.low - iBar.high
|
|
: iBar.low - bar.high;
|
|
result = gapSize >= approvedGapSize;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Pinned Bar or not ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
* @param shadowApprovedMultiplier: int, Shadow Size Approve Multiplier ...
|
|
* @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ...
|
|
* @param forceDirection: bool, Apply Force Bar Type ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPinnedBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int shadowApprovedMultiplier = 3,
|
|
double minimumPinBarRangeMultiplier = 4,
|
|
bool forceDirection = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Normalizing ...
|
|
shadowApprovedMultiplier = NormalizeInt(shadowApprovedMultiplier, 2, 5);
|
|
minimumPinBarRangeMultiplier = NormalizeDouble(minimumPinBarRangeMultiplier, 2, 100);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Requirements ...
|
|
double body = bar.GetBody();
|
|
double lowShadow = bar.GetLowShadow();
|
|
double highShadow = bar.GetHighShadow();
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
lowShadow > body &&
|
|
lowShadow > highShadow &&
|
|
lowShadow >= (body * shadowApprovedMultiplier);
|
|
bool isBearish =
|
|
highShadow > body &&
|
|
highShadow > lowShadow &&
|
|
highShadow > (body * shadowApprovedMultiplier);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Checking Force Bar Type ...
|
|
if (forceDirection)
|
|
{
|
|
//
|
|
result =
|
|
isBullish
|
|
? bar.IsBullish()
|
|
: bar.IsBearish();
|
|
}
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Range Validation ...
|
|
double point = GetPoints(bar.symbol);
|
|
double approvedRange = minimumPinBarRangeMultiplier * point;
|
|
result = bar.GetRange() >= approvedRange;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Setting Direction ...
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar has Star Pattern or not ...
|
|
* Morning Star => Bullish
|
|
* Evening Star => Bearish
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsStartPattern(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Requirements ...
|
|
XOHCL pBar, p2Bar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
bar.IsBullish() &&
|
|
p2Bar.IsBearish();
|
|
bool isBearish =
|
|
bar.IsBearish() &&
|
|
p2Bar.IsBullish();
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Checking Gap Exists Between Bars ...
|
|
result =
|
|
isBullish
|
|
? p2Bar.GetDown() > pBar.GetUp() &&
|
|
pBar.GetUp() < bar.GetDown()
|
|
: p2Bar.GetUp() < pBar.GetDown() &&
|
|
pBar.GetDown() > bar.GetUp();
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar Close Validation ...
|
|
double barClosedApprovedPrice = p2Bar.GetDown() + ((p2Bar.GetUp() - p2Bar.GetDown()) / 2);
|
|
result =
|
|
isBullish
|
|
? bar.close > barClosedApprovedPrice
|
|
: bar.close < barClosedApprovedPrice;
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validating PBar Body and Shadow ...
|
|
double body = pBar.GetBody();
|
|
double lowShadow = pBar.GetLowShadow();
|
|
double highShadow = pBar.GetHighShadow();
|
|
result =
|
|
body < bar.GetBody() &&
|
|
body < p2Bar.GetBody() &&
|
|
(isBullish
|
|
? lowShadow > body &&
|
|
lowShadow > highShadow
|
|
: highShadow > body &&
|
|
highShadow > lowShadow);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar has Pirecing Pattern or not ...
|
|
* Piercing => Bullish
|
|
* Dark Cloud Cover => Bearish
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPiercingPattern(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL pBar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
bar.IsBullish() &&
|
|
pBar.IsBearish();
|
|
bool isBearish =
|
|
bar.IsBearish() &&
|
|
pBar.IsBullish();
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar Close ...
|
|
double barCloseApprovedPrice = pBar.GetDown() + ((pBar.GetUp() - pBar.GetDown()) / 2);
|
|
result =
|
|
isBullish
|
|
? bar.close > barCloseApprovedPrice
|
|
: bar.close < barCloseApprovedPrice;
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
pBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar has Rising Pattern or not ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsRisingPattern(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Required Bars ...
|
|
XOHCL iBar;
|
|
XOHCL bars[];
|
|
bool has = false;
|
|
int start = bar.Index();
|
|
int end = start + 5;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
// Initialized Bar ...
|
|
has = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBar,
|
|
bars //
|
|
);
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
result = ArraySize(bars) == 5;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
SpecifiedClean(bars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
bars[0].IsBullish() &&
|
|
bars[4].IsBullish() &&
|
|
bars[1].IsBearish() &&
|
|
bars[2].IsBearish() &&
|
|
bars[3].IsBearish();
|
|
bool isBearish =
|
|
bars[0].IsBearish() &&
|
|
bars[4].IsBearish() &&
|
|
bars[1].IsBullish() &&
|
|
bars[2].IsBullish() &&
|
|
bars[3].IsBullish();
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
SpecifiedClean(bars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Range Validation ...
|
|
double upper = bars[4].GetUp();
|
|
double lower = bars[4].GetDown();
|
|
|
|
//
|
|
double max = MathMax(bars[1].GetUp(), bars[2].GetUp());
|
|
max = MathMax(max, bars[3].GetUp());
|
|
|
|
//
|
|
double min = MathMin(bars[1].GetDown(), bars[2].GetDown());
|
|
min = MathMin(min, bars[3].GetDown());
|
|
|
|
//
|
|
result =
|
|
max < upper &&
|
|
min > lower &&
|
|
(isBullish
|
|
? bars[0].close > bars[4].GetUp()
|
|
: bars[0].close < bars[4].GetDown());
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
SpecifiedClean(bars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
iBar.Clean();
|
|
SpecifiedClean(bars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar has Flag Pattern or not ...
|
|
*
|
|
* @param bar: XOHCL, Specified Bar ...
|
|
* @param dir: ENUM_X_DIRECTION a reference for Direction ...
|
|
* @param swingBar: XOHCL, Detected Swing Bar ...
|
|
* @param minimumPullbackBars: int, Minimum Shoulders of Swing Bar ...
|
|
* @param minimumPullbackBars: int, Minimum Shoulders of Swing Bar ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsFlagPattern(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
XOHCL &swingBar,
|
|
int minimumPullbackBars = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
swingBar.Clean();
|
|
CleanDirection(dir);
|
|
|
|
//
|
|
// Normalizing ...
|
|
minimumPullbackBars = NormalizeInt(minimumPullbackBars, 3, 10);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Previous Bar ...
|
|
XOHCL pBar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Directions ...
|
|
bool isBullish =
|
|
bar.IsBullish() &&
|
|
bar.close > pBar.GetUp();
|
|
bool isBearish =
|
|
bar.IsBearish() &&
|
|
bar.close < pBar.GetDown();
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect Swing Bar ...
|
|
ENUM_X_SWING_TYPE swingType =
|
|
isBullish
|
|
? X_SWING_HIGH
|
|
: X_SWING_LOW;
|
|
result =
|
|
result &&
|
|
IsXValid(swingType) &&
|
|
bar.FindNextSwingBar(
|
|
swingType,
|
|
swingBar,
|
|
minimumPullbackBars //
|
|
) &&
|
|
(isBullish
|
|
? swingBar.IsBullish() &&
|
|
swingBar.high > pBar.high
|
|
: swingBar.IsBearish() &&
|
|
swingBar.low < pBar.low);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
swingBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = bar.GetDirection();
|
|
|
|
//
|
|
// Get Result ...
|
|
result = HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
pBar.Clean();
|
|
if (!result)
|
|
{
|
|
swingBar.Clean();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool HasTrend(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
XOHCL &swings[],
|
|
int numberOfSwings = 3,
|
|
int swingShoulders = 7 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
CleanDirection(dir);
|
|
SpecifiedClean(swings);
|
|
|
|
//
|
|
// Normalizing ...
|
|
numberOfSwings = NormalizeInt(numberOfSwings, 3, 10);
|
|
swingShoulders = NormalizeInt(swingShoulders, 3);
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Trend Direction ...
|
|
XOHCL iSwing;
|
|
int idx = -1;
|
|
bool has = false;
|
|
XOHCL swingLows[];
|
|
XOHCL swingHighs[];
|
|
int lastSwingLowIndex = bar.Index();
|
|
int lastSwingHighIndex = bar.Index();
|
|
while (ArraySize(swingLows) < numberOfSwings || ArraySize(swingHighs) < numberOfSwings)
|
|
{
|
|
//
|
|
bool canLookupSwingLow = ArraySize(swingLows) < numberOfSwings;
|
|
bool canLookupSwingHigh = ArraySize(swingHighs) < numberOfSwings;
|
|
if (!canLookupSwingLow && !canLookupSwingHigh)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Handle Swing Lows ...
|
|
if (canLookupSwingLow)
|
|
{
|
|
//
|
|
iSwing.Clean();
|
|
idx = FindXSwing(
|
|
X_SWING_LOW,
|
|
bar.symbol,
|
|
bar.period,
|
|
lastSwingLowIndex + 1,
|
|
swingShoulders //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
has = iSwing.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
idx //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSwing,
|
|
swingLows //
|
|
);
|
|
|
|
//
|
|
lastSwingLowIndex = idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Swing Highs ...
|
|
if (canLookupSwingHigh)
|
|
{
|
|
//
|
|
iSwing.Clean();
|
|
idx = FindXSwing(
|
|
X_SWING_HIGH,
|
|
bar.symbol,
|
|
bar.period,
|
|
lastSwingHighIndex + 1,
|
|
swingShoulders //
|
|
);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
has = iSwing.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
idx //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSwing,
|
|
swingHighs //
|
|
);
|
|
|
|
//
|
|
lastSwingHighIndex = idx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Trend Based On Swings ...
|
|
|
|
|
|
//
|
|
iSwing.Clean();
|
|
SpecifiedClean(swingLows);
|
|
SpecifiedClean(swingHighs);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
|
|
//
|
|
// Helpers ...
|
|
|
|
/**
|
|
* Clean Specified Referenced Direction ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION
|
|
*/
|
|
void CleanDirection(ENUM_X_DIRECTION &dir)
|
|
{
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
};
|
|
|
|
// |