2195 lines
44 KiB
Plaintext
2195 lines
44 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// --------------------------------------
|
|
// Name: XPOI
|
|
// Description: Bar Analysing ...
|
|
//
|
|
// 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"
|
|
#include "../Libraries/x-saherelm.x-poi.lib.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Implementations ...
|
|
class XCBarAnalyser : public XCBase
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
void XCBarAnalyser()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCBarAnalyser()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Providers ...
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
/**
|
|
* Calculate Loopback Data for Specific Bar ...
|
|
*
|
|
* @param index: Integer, Bar Current Index ...
|
|
* @param start: Integer, Start of Loopback ...
|
|
* @param end: Integer, End of Loopback ...
|
|
* @param count: Integer, Number of Calculating Bars ...
|
|
* @param bar: XOHCL instance, Specified Bar ...
|
|
* @param loopback: Integer, Loopback Length ...
|
|
* @return ( bool )
|
|
*/
|
|
bool CalculateLoopBackData(
|
|
int &index,
|
|
int &start,
|
|
int &end,
|
|
int &count,
|
|
XOHCL &bar,
|
|
int loopback = 1 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (loopback < 1)
|
|
{
|
|
loopback = 1;
|
|
}
|
|
|
|
//
|
|
index = -1;
|
|
start = -1;
|
|
end = -1;
|
|
count = -1;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
index = bar.Index();
|
|
start = index + 1;
|
|
end = start + loopback;
|
|
count = end - start;
|
|
result = count >= 1;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Loopback HH & LL Data ...
|
|
*
|
|
* @param hhIDX: Integer, HH Index ...
|
|
* @param hh: Double, HH Value ...
|
|
* @param llIDX: Integer, LL Index ...
|
|
* @param ll: Double, LL Value ...
|
|
* @param bar: XOHCL instance ...
|
|
* @param loopback: Integer, Loopback Length ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CalculateLoopbackHLData(
|
|
int &hhIDX,
|
|
double &hh,
|
|
int &llIDX,
|
|
double &ll,
|
|
XOHCL &bar,
|
|
int loopback //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (loopback < 1)
|
|
{
|
|
loopback = 1;
|
|
}
|
|
|
|
//
|
|
int index = -1;
|
|
int start = -1;
|
|
int end = -1;
|
|
int count = -1;
|
|
result = CalculateLoopBackData(
|
|
index,
|
|
start,
|
|
end,
|
|
count,
|
|
bar,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
hhIDX = iHighest(
|
|
bar.symbol,
|
|
bar.period,
|
|
MODE_HIGH,
|
|
count,
|
|
start //
|
|
);
|
|
result = IsValidIndex(hhIDX);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
llIDX = iLowest(
|
|
bar.symbol,
|
|
bar.period,
|
|
MODE_LOW,
|
|
count,
|
|
start //
|
|
);
|
|
result = IsValidIndex(llIDX);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
hh = iHigh(
|
|
bar.symbol,
|
|
bar.period,
|
|
hhIDX //
|
|
);
|
|
ll = iLow(
|
|
bar.symbol,
|
|
bar.period,
|
|
llIDX //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Bar Range ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetBarRangePercent(XOHCL &bar)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
result = bar.GetRange() / 100;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Same Bars ...
|
|
*
|
|
* @param bar: XOHCL instance, Start Bar ...
|
|
* @param dir: ENUM_X_DIRECTION member, Holds Result Direction ...
|
|
* @param index: Integer, Holds Result Index ...
|
|
* @param sameBars: Iteger, Required Same Bar ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSameBars(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int &index,
|
|
int sameBars = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (sameBars < 1)
|
|
{
|
|
sameBars = 1;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
index = bar.Index();
|
|
bool canContinue = true;
|
|
int sameBullishBarsFounded = 0;
|
|
int sameBearishBarsFounded = 0;
|
|
bool canContinueForBullish = true;
|
|
bool canContinueForBearish = true;
|
|
while (canContinue)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
result = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
index //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isBullish = iBar.IsBullish();
|
|
bool isBearish = iBar.IsBearish();
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (isBullish)
|
|
{
|
|
//
|
|
sameBullishBarsFounded++;
|
|
canContinueForBearish = false;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
sameBearishBarsFounded++;
|
|
canContinueForBullish = false;
|
|
}
|
|
|
|
//
|
|
result = canContinueForBullish ||
|
|
canContinueForBearish;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
canContinueForBullish =
|
|
canContinueForBullish &&
|
|
sameBullishBarsFounded > 0;
|
|
|
|
//
|
|
canContinueForBearish =
|
|
canContinueForBearish &&
|
|
sameBearishBarsFounded > 0;
|
|
|
|
//
|
|
canContinue =
|
|
canContinueForBullish ||
|
|
canContinueForBearish;
|
|
if (canContinue)
|
|
{
|
|
index++;
|
|
}
|
|
}
|
|
|
|
//
|
|
bool hasBullishSameBars =
|
|
sameBullishBarsFounded >= sameBars;
|
|
|
|
//
|
|
bool hasBearishSameBars =
|
|
sameBearishBarsFounded >= sameBars;
|
|
|
|
//
|
|
result = hasBullishSameBars ||
|
|
hasBearishSameBars;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir =
|
|
hasBullishSameBars
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Price Consolidation ...
|
|
*
|
|
* @param bar: XOHCL instance Reference, Start Bar ...
|
|
* @param loopback: Integer, Consolidation Range Finder ...
|
|
* @param upper: Double Reference ...
|
|
* @param lower: Double Reference ...
|
|
* @param upperAppliedTo: ENUM_APPLIED_PRICE member, Upper Price ...
|
|
* @param lowerAppliedTo: ENUM_APPLIED_PRICE member, Lower Price ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsConsolidate(
|
|
XOHCL &bar,
|
|
double &upper,
|
|
double &lower,
|
|
int loopback = 30,
|
|
ENUM_APPLIED_PRICE upperAppliedTo = PRICE_HIGH,
|
|
ENUM_APPLIED_PRICE lowerAppliedTo = PRICE_LOW //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
|
|
//
|
|
if (loopback < 7)
|
|
{
|
|
loopback = 7;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int consolidationRange = 30;
|
|
double points = GetPoints(bar.symbol);
|
|
int index = bar.Index();
|
|
|
|
//
|
|
double upperPrice[];
|
|
int upperPriceCount = FillPrice(
|
|
upperPrice,
|
|
upperAppliedTo,
|
|
bar.symbol,
|
|
bar.period,
|
|
index,
|
|
loopback //
|
|
);
|
|
|
|
//
|
|
double lowerPrice[];
|
|
int lowerPriceCount = FillPrice(
|
|
lowerPrice,
|
|
lowerAppliedTo,
|
|
bar.symbol,
|
|
bar.period,
|
|
index,
|
|
loopback //
|
|
);
|
|
|
|
//
|
|
result = upperPriceCount == lowerPriceCount &&
|
|
lowerPriceCount == loopback;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
upper = upperPrice[ArrayMaximum(upperPrice)];
|
|
lower = lowerPrice[ArrayMinimum(lowerPrice)];
|
|
|
|
//
|
|
double range = upper - lower;
|
|
result = range <= consolidationRange * points;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bar Has Bullish Trend or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param forceAll: Boolean ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasBullishTrend(
|
|
XOHCL &bar,
|
|
bool forceAll = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL tmpHSW[];
|
|
XOHCL tmpLSW[];
|
|
|
|
//
|
|
bool trend1 = bar.HasBullishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
true //
|
|
);
|
|
|
|
//
|
|
bool trend2 = bar.HasBullishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
false //
|
|
);
|
|
|
|
//
|
|
if (!forceAll)
|
|
{
|
|
//
|
|
result = trend1;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
trend1 ||
|
|
trend2;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bar Has Bearish Trend or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param forceAll: Boolean ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasBearishTrend(
|
|
XOHCL &bar,
|
|
bool forceAll = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL tmpHSW[];
|
|
XOHCL tmpLSW[];
|
|
|
|
//
|
|
bool trend1 = bar.HasBearishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
true //
|
|
);
|
|
|
|
//
|
|
bool trend2 = bar.HasBearishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
false //
|
|
);
|
|
|
|
//
|
|
if (!forceAll)
|
|
{
|
|
//
|
|
result = trend1;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
trend1 ||
|
|
trend2;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar Has Bullish Pattern or not ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Bar ...
|
|
* @param loopback: Integer, Loopback Length for Patterns ...
|
|
* @param verifications: Integer, Number of Given Verifications ...
|
|
* @param checkHammer: Boolean, Specified Check Hammer Pattern ...
|
|
* @param checkMorningStar: Boolean, Specified Check Morning Star Pattern ...
|
|
* @param checkBullishMarubozu: Boolean, Specified Check Marubozu Pattern ...
|
|
* @param checkBullishEngulfing: Boolean, Specified Check Engulfing Pattern ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasBullishPattern(
|
|
XOHCL &bar,
|
|
int loopback = 0,
|
|
int verifications = 1,
|
|
bool checkHammer = true,
|
|
bool checkMorningStar = true,
|
|
bool checkBullishMarubozu = true,
|
|
bool checkBullishEngulfing = true //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (verifications <= 0)
|
|
{
|
|
verifications = 1;
|
|
}
|
|
|
|
//
|
|
int founded = 0;
|
|
|
|
//
|
|
int idx = bar.Index();
|
|
for (int i = idx; i <= idx + loopback; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
result = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isHammer =
|
|
!checkHammer
|
|
? false
|
|
: iBar.IsHammer();
|
|
if (isHammer)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
bool isMorningStar =
|
|
!checkMorningStar
|
|
? false
|
|
: iBar.IsMorningStar();
|
|
if (isMorningStar)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
bool isBullishMarubozu =
|
|
!checkBullishMarubozu
|
|
? false
|
|
: iBar.IsBullishMarubozu();
|
|
if (isBullishMarubozu)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
bool isBullishEngulfing =
|
|
!checkBullishEngulfing
|
|
? false
|
|
: iBar.IsBullishEngulfing();
|
|
if (isBullishEngulfing)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
result =
|
|
result &&
|
|
founded >= verifications;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar Has Bearish Pattern or not ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Bar ...
|
|
* @param loopback: Integer, Loopback Length for Patterns ...
|
|
* @param verifications: Integer, Number of Given Verifications ...
|
|
* @param checkShootingStar: Boolean, Specified Check Shooting Star Pattern ...
|
|
* @param checkEveningStar: Boolean, Specified Check Evening Star Pattern ...
|
|
* @param checkBearishMarubozu: Boolean, Specified Check Marubozu Pattern ...
|
|
* @param checkBearishEngulfing: Boolean, Specified Check Engulfing Pattern ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasBearishPattern(
|
|
XOHCL &bar,
|
|
int loopback = 0,
|
|
int verifications = 1,
|
|
bool checkShootingStar = true,
|
|
bool checkEveningStar = true,
|
|
bool checkBearishMarubozu = true,
|
|
bool checkBearishEngulfing = true //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (verifications <= 0)
|
|
{
|
|
verifications = 1;
|
|
}
|
|
|
|
//
|
|
int founded = 0;
|
|
|
|
//
|
|
int idx = bar.Index();
|
|
for (int i = idx - 1; i <= idx + loopback; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
result = iBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isShootingStar =
|
|
!checkShootingStar
|
|
? false
|
|
: iBar.IsShootingStar();
|
|
if (isShootingStar)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
bool isEveningStar =
|
|
!checkEveningStar
|
|
? false
|
|
: iBar.IsEveningStar();
|
|
if (isEveningStar)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
bool isBearishMarubozu =
|
|
!checkBearishMarubozu
|
|
? false
|
|
: iBar.IsBearishMarubozu();
|
|
if (isBearishMarubozu)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
bool isBearishEngulfing =
|
|
!checkBearishEngulfing
|
|
? false
|
|
: iBar.IsBearishEngulfing();
|
|
if (isBearishEngulfing)
|
|
{
|
|
founded++;
|
|
}
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
result =
|
|
result &&
|
|
founded >= verifications;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Commons ...
|
|
|
|
/**
|
|
* Check Specified Bar's Range is Extended or not ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Bar ...
|
|
* @param loopback: Integer, Loopback Length ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasExtendedRange(
|
|
XOHCL &bar,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (loopback < 3)
|
|
{
|
|
loopback = 3;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = bar.Index();
|
|
int start = index + 1;
|
|
int end = start + loopback;
|
|
int count = end - start;
|
|
result = count >= 1;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double sum = 0;
|
|
XOHCL iBar = bar;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
bool isRetrieved = iBar.GetPreviousBar(iBar);
|
|
if (!isRetrieved)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
sum += iBar.GetRange();
|
|
}
|
|
|
|
//
|
|
result = sum > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double avg = sum / count;
|
|
|
|
//
|
|
result = bar.GetRange() >= avg;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar's Body is Extended or not ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Bar ...
|
|
* @param loopback: Integer, Loopback Length ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasExtendedBody(
|
|
XOHCL &bar,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (loopback < 3)
|
|
{
|
|
loopback = 3;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = bar.Index();
|
|
int start = index + 1;
|
|
int end = start + loopback;
|
|
int count = end - start;
|
|
result = count >= 1;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double sum = 0;
|
|
XOHCL iBar = bar;
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
bool isRetrieved = iBar.GetPreviousBar(iBar);
|
|
if (!isRetrieved)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
sum += iBar.GetBody();
|
|
}
|
|
|
|
//
|
|
result = sum > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double avg = sum / count;
|
|
|
|
//
|
|
result = bar.GetBody() >= avg;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar's Body and Range is Extended or not ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Bar ...
|
|
* @param loopback: Integer, Loopback Length ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsExtended(
|
|
XOHCL &bar,
|
|
int loopback = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool hasExtendedBody = HasExtendedBody(bar, loopback);
|
|
bool hasExtendedRange = HasExtendedRange(bar, loopback);
|
|
result = hasExtendedBody &&
|
|
hasExtendedRange;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Swing High or not ...
|
|
*
|
|
* @param bar: XOHCL instnce ...
|
|
* @param range: Integer, Specified Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSwingHigh(
|
|
XOHCL &bar,
|
|
int range = 2 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (range < 1)
|
|
{
|
|
range = 1;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = bar.Index();
|
|
result = range > 0 &&
|
|
index >= range;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = bar.symbol;
|
|
ENUM_TIMEFRAMES period = bar.period;
|
|
|
|
//
|
|
for (int i = 1; i <= range; i++)
|
|
{
|
|
//
|
|
// Prev Bar ...
|
|
XOHCL iPrevBar;
|
|
result = iPrevBar.Init(
|
|
symbol,
|
|
period,
|
|
index + i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Next Bar ...
|
|
XOHCL iNextBar;
|
|
result = iNextBar.Init(
|
|
symbol,
|
|
period,
|
|
index - i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = bar.high >= iPrevBar.high &&
|
|
bar.high >= iNextBar.high;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Swing Low or not ...
|
|
*
|
|
* @param bar: XOHCL instnce ...
|
|
* @param range: Integer, Specified Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSwingLow(
|
|
XOHCL &bar,
|
|
int range = 2 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (range < 1)
|
|
{
|
|
range = 1;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = bar.Index();
|
|
result = range > 0 &&
|
|
index >= range;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = bar.symbol;
|
|
ENUM_TIMEFRAMES period = bar.period;
|
|
|
|
//
|
|
for (int i = 1; i <= range; i++)
|
|
{
|
|
//
|
|
// Prev Bar ...
|
|
XOHCL iPrevBar;
|
|
result = iPrevBar.Init(
|
|
symbol,
|
|
period,
|
|
index + i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Next Bar ...
|
|
XOHCL iNextBar;
|
|
result = iNextBar.Init(
|
|
symbol,
|
|
period,
|
|
index - i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = bar.low <= iPrevBar.low &&
|
|
bar.low <= iNextBar.low;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is Momentum Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
* @param extend: Integer ...
|
|
* @param bodyPercent: Double ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsMomentumBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int extend = 1,
|
|
double bodyPercent = 70 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (extend < 0)
|
|
{
|
|
extend = 0;
|
|
}
|
|
|
|
//
|
|
if (bodyPercent < 50)
|
|
{
|
|
bodyPercent = 50;
|
|
}
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
bar.Index() > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (extend > 0)
|
|
{
|
|
//
|
|
result = IsExtended(
|
|
bar,
|
|
extend //
|
|
);
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
double body = bar.GetBody();
|
|
double rp = GetBarRangePercent(bar);
|
|
|
|
//
|
|
result = body >= rp * bodyPercent;
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
bar.IsBullish()
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is Rejection Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
* @param extend: Integer ...
|
|
* @param shadowPercent: Double ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsRejectionBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int extend = 1,
|
|
double shadowPercent = 60 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (extend < 0)
|
|
{
|
|
extend = 0;
|
|
}
|
|
|
|
//
|
|
if (shadowPercent < 50)
|
|
{
|
|
shadowPercent = 50;
|
|
}
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
bar.Index() > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (extend > 0)
|
|
{
|
|
//
|
|
result = IsExtended(
|
|
bar,
|
|
extend //
|
|
);
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
double body = bar.GetBody();
|
|
double range = bar.GetRange();
|
|
double shadows = bar.GetShadows();
|
|
double lowShadow = bar.GetLowShadow();
|
|
double highShadow = bar.GetHighShadow();
|
|
double rp = GetBarRangePercent(bar);
|
|
|
|
//
|
|
result = shadows >= rp * shadowPercent;
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
lowShadow > highShadow
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Engulfing Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
* @param extend: Integer ...
|
|
* @param bodyPercent: Double ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsEngulfBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int extend = 1,
|
|
double bodyPercent = 60 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (extend < 0)
|
|
{
|
|
extend = 0;
|
|
}
|
|
|
|
//
|
|
if (bodyPercent < 50)
|
|
{
|
|
bodyPercent = 50;
|
|
}
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
bar.Index() > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Previous Bar ...
|
|
XOHCL pBar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (extend > 0)
|
|
{
|
|
//
|
|
result = IsExtended(
|
|
pBar,
|
|
extend //
|
|
);
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Engulfig ...
|
|
result =
|
|
bar.GetUp() > pBar.GetUp() &&
|
|
bar.GetDown() < pBar.GetDown();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Engulfing Direction ...
|
|
bool isBullishEngulfed =
|
|
pBar.IsBearish() &&
|
|
bar.IsBullish();
|
|
bool isBearishEngulfed =
|
|
pBar.IsBullish() &&
|
|
bar.IsBearish();
|
|
|
|
//
|
|
result = isBullishEngulfed ||
|
|
isBearishEngulfed;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = isBullishEngulfed
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Bar is Pin Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
* @param extend: Integer ...
|
|
* @param shadowPercent: Double ...
|
|
* @param bodyPercent: Double ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPinBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int extend = 1,
|
|
double shadowPercent = 65,
|
|
double bodyPercent = 25 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
bar.Index() > 0 &&
|
|
bodyPercent > 0 &&
|
|
shadowPercent > 0 &&
|
|
bodyPercent < shadowPercent;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Chack Range Extends ...
|
|
if (extend > 0)
|
|
{
|
|
//
|
|
result = HasExtendedRange(
|
|
bar,
|
|
extend //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Body ...
|
|
double rangePercent = GetBarRangePercent(bar);
|
|
|
|
//
|
|
double body = bar.GetBody();
|
|
double highShadow = bar.GetHighShadow();
|
|
double lowShadow = bar.GetLowShadow();
|
|
|
|
//
|
|
// Check Body ...
|
|
result = body / rangePercent >= bodyPercent;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isPassedHighShadow =
|
|
highShadow / rangePercent >= shadowPercent;
|
|
bool isPassedLowShadow =
|
|
lowShadow / rangePercent >= shadowPercent;
|
|
result =
|
|
isPassedLowShadow ||
|
|
isPassedHighShadow;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = isPassedLowShadow
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Decision Bar (Pin, Momentum or Rejection) ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
* @param extend: Integer ...
|
|
* @param shadowForPinAndRejectionBarPercent: Double ...
|
|
* @param bodyForPinBarPercent: Double ...
|
|
* @param bodyForEngulfBarPercent: Double ...
|
|
* @param bodyForMomentumBarPercent: Double ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsDecisionBar(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int extend = 1,
|
|
double shadowForPinAndRejectionBarPercent = 65,
|
|
double bodyForPinBarPercent = 25,
|
|
double bodyForEngulfBarPercent = 65,
|
|
double bodyForMomentumBarPercent = 70 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
bar.Index() > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Pin Bar ...
|
|
ENUM_X_DIRECTION pinDir;
|
|
bool isPiBar = IsPinBar(
|
|
bar,
|
|
pinDir,
|
|
extend,
|
|
shadowForPinAndRejectionBarPercent,
|
|
bodyForPinBarPercent //
|
|
);
|
|
|
|
//
|
|
// Engulfing Bar ...
|
|
ENUM_X_DIRECTION engulfDir;
|
|
bool isEngulfBar = IsEngulfBar(
|
|
bar,
|
|
engulfDir,
|
|
extend,
|
|
bodyForEngulfBarPercent //
|
|
);
|
|
|
|
//
|
|
// Momentum Bar ...
|
|
ENUM_X_DIRECTION momentumDir;
|
|
bool isMomentumBar = IsMomentumBar(
|
|
bar,
|
|
momentumDir,
|
|
extend,
|
|
bodyForMomentumBarPercent //
|
|
);
|
|
|
|
//
|
|
// Rejection Bar ...
|
|
ENUM_X_DIRECTION rejectionDir;
|
|
bool isRejectionBar = IsRejectionBar(
|
|
bar,
|
|
rejectionDir,
|
|
extend,
|
|
shadowForPinAndRejectionBarPercent //
|
|
);
|
|
|
|
//
|
|
result = isPiBar ||
|
|
isEngulfBar ||
|
|
isMomentumBar ||
|
|
isRejectionBar;
|
|
if (result)
|
|
{
|
|
//
|
|
if (isPiBar)
|
|
{
|
|
dir = pinDir;
|
|
}
|
|
else if (isEngulfBar)
|
|
{
|
|
dir = engulfDir;
|
|
}
|
|
else if (isMomentumBar)
|
|
{
|
|
dir = momentumDir;
|
|
}
|
|
else
|
|
{
|
|
dir = rejectionDir;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsBullish(dir) ||
|
|
IsBearish(dir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Fibonacci Level 382 Pressure ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasFiboPressure(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double bearishFib382 = GetFibonacciLevel(
|
|
bar.high,
|
|
bar.low,
|
|
0.382,
|
|
1 //
|
|
);
|
|
double bullishFib382 = GetFibonacciLevel(
|
|
bar.high,
|
|
bar.low,
|
|
0.382,
|
|
-1 //
|
|
);
|
|
|
|
//
|
|
bool isBullish = bar.GetDown() > bearishFib382;
|
|
bool isBearish = bar.GetUp() < bullishFib382;
|
|
|
|
//
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Support and Resistance Zones ...
|
|
|
|
/**
|
|
* Check a Bar is Support Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param range: Integer, Specified Verifiation Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSupport(
|
|
XOHCL &bar,
|
|
int range = 21 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (range < 2)
|
|
{
|
|
range = 2;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = bar.Index();
|
|
result = range > 0 &&
|
|
index >= range;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = bar.symbol;
|
|
ENUM_TIMEFRAMES period = bar.period;
|
|
|
|
//
|
|
for (int i = 1; i <= range; i++)
|
|
{
|
|
//
|
|
int prevIDX = index + i;
|
|
int nextIDX = index - 1;
|
|
|
|
//
|
|
// Prev Bar ...
|
|
XOHCL iPrevBar;
|
|
result = iPrevBar.Init(
|
|
symbol,
|
|
period,
|
|
prevIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Next Bar ...
|
|
XOHCL iNextBar;
|
|
result = iNextBar.Init(
|
|
symbol,
|
|
period,
|
|
nextIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = bar.low <= iPrevBar.low &&
|
|
bar.low <= iNextBar.low;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Bar is Resistance Bar or not ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param range: Integer, Specified Verifiation Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsResistance(
|
|
XOHCL &bar,
|
|
int range = 21 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (range < 2)
|
|
{
|
|
range = 2;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = bar.Index();
|
|
result = range > 0 &&
|
|
index >= range;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = bar.symbol;
|
|
ENUM_TIMEFRAMES period = bar.period;
|
|
|
|
//
|
|
for (int i = 1; i <= range; i++)
|
|
{
|
|
//
|
|
int prevIDX = index + i;
|
|
int nextIDX = index - 1;
|
|
|
|
//
|
|
// Prev Bar ...
|
|
XOHCL iPrevBar;
|
|
result = iPrevBar.Init(
|
|
symbol,
|
|
period,
|
|
prevIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Next Bar ...
|
|
XOHCL iNextBar;
|
|
result = iNextBar.Init(
|
|
symbol,
|
|
period,
|
|
nextIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = bar.high >= iPrevBar.high &&
|
|
bar.high >= iNextBar.high;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Order Blocks ...
|
|
|
|
/**
|
|
* Detect an Order Block Based on Given Bar ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Start Bar ...
|
|
* @param ob: XOHCL instance, Fill it if Order Block Found ...
|
|
* @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ...
|
|
* @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasOrderBlock(
|
|
XOHCL &bar,
|
|
XOHCL &ob,
|
|
ENUM_X_DIRECTION &dir,
|
|
int sameBars = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ob.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (sameBars < 1)
|
|
{
|
|
sameBars = 1;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = 0;
|
|
result = HasSameBars(
|
|
bar,
|
|
dir,
|
|
index,
|
|
sameBars //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int obIndex = index;
|
|
result = ob.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
obIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Fair Value Gaps ...
|
|
|
|
/**
|
|
* Detect a Fair Value Gap Based on Given Bar ...
|
|
*
|
|
* @param bar: XOHCL instance, Specified Start Bar ...
|
|
* @param dir: ENUM_X_DIRECTION member, Specified Founded Order Block Direction ...
|
|
* @param sameBars: Integer, Specified Min Same Bars for Detecting Order Block ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasFairValueGap(
|
|
XOHCL &bar,
|
|
XOHCL &prevBar,
|
|
XOHCL &nextBar,
|
|
ENUM_X_DIRECTION &dir,
|
|
int sameBars = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
prevBar.Clean();
|
|
nextBar.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (sameBars < 1)
|
|
{
|
|
sameBars = 1;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = 0;
|
|
result = HasSameBars(
|
|
bar,
|
|
dir,
|
|
index,
|
|
sameBars //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(dir);
|
|
|
|
//
|
|
int to = bar.Index() + 1;
|
|
int from = index + 1;
|
|
for (int i = from; i > to; i--)
|
|
{
|
|
//
|
|
result = prevBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = nextBar.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
i - 2 //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = isBullish
|
|
? prevBar.high < nextBar.low
|
|
: prevBar.low > nextBar.high;
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
//
|
|
prevBar.Clean();
|
|
nextBar.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Bar CHOCH ...
|
|
|
|
/**
|
|
* Check Specified Bar Has PullBack or not ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION member, Specified Direction ...
|
|
* @param bar: XOHCL instance, Speciied Bar ...
|
|
* @param loopback: Integer, loopback Length ...
|
|
* @param forceBody: Boolean, Specified Choch Happens only by Bar's Body ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasPullBack(
|
|
ENUM_X_DIRECTION &dir,
|
|
XOHCL &bar,
|
|
int loopback = 3,
|
|
bool forceBody = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (loopback < 1)
|
|
{
|
|
loopback = 1;
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string symbol = bar.symbol;
|
|
ENUM_TIMEFRAMES period = bar.period;
|
|
|
|
//
|
|
// Calculate Loopback Data ...
|
|
int index = -1;
|
|
int start = -1;
|
|
int end = -1;
|
|
int count = -1;
|
|
result = CalculateLoopBackData(
|
|
index,
|
|
start,
|
|
end,
|
|
count,
|
|
bar,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Loopback HH and LL Data ...
|
|
int hhIDX = -1;
|
|
double hh = -1;
|
|
int llIDX = -1;
|
|
double ll = -1;
|
|
result = CalculateLoopbackHLData(
|
|
hhIDX,
|
|
hh,
|
|
llIDX,
|
|
ll,
|
|
bar,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullishDirection =
|
|
bar.high > hh &&
|
|
bar.low > ll;
|
|
bool isBearishDirection =
|
|
bar.high < hh &&
|
|
bar.low < ll;
|
|
result = isBullishDirection ||
|
|
isBearishDirection;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (forceBody)
|
|
{
|
|
//
|
|
isBullishDirection =
|
|
bar.GetUp() > hh &&
|
|
bar.GetDown() > ll;
|
|
isBearishDirection =
|
|
bar.GetUp() < hh &&
|
|
bar.GetDown() < ll;
|
|
result = isBullishDirection ||
|
|
isBearishDirection;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Bar's Direction in related to CHOCH Direction ...
|
|
result =
|
|
isBullishDirection
|
|
? bar.IsBullish()
|
|
: bar.IsBearish();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Set Direction ...
|
|
dir =
|
|
isBullishDirection
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
// Check Loopback End Bar ...
|
|
XOHCL endBar;
|
|
result = endBar.Init(
|
|
symbol,
|
|
period,
|
|
end - 1 //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// End Bar Must be InDirect by Specified Bar ...
|
|
result =
|
|
isBullishDirection
|
|
? endBar.IsBearish()
|
|
: endBar.IsBullish();
|
|
|
|
//
|
|
// Check Loopback for Directional Bars ...
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
//
|
|
};
|
|
|
|
// |