last works on implementing Candlestick Patterns on Bar Analyser Class ...

This commit is contained in:
2025-03-15 04:13:08 +03:30
parent a05b8f464d
commit 3b31c36541
4 changed files with 979 additions and 86 deletions
+557 -33
View File
@@ -26,9 +26,6 @@
//
// Definitions ...
//
#define X_PERCENTAGE_GOLDEN_MULTIPLIER 100000
//
// Implementations ...
class XCBarAnalyser : public XCBase
@@ -423,7 +420,7 @@ class XCBarAnalyser : public XCBase
for (int i = 0; i < uppersCount; i++)
{
//
double iValue = uppers[i] - lowers[i];
double iValue = lowers[i] + (uppers[i] - lowers[i]);
//
Add(
@@ -707,45 +704,48 @@ class XCBarAnalyser : public XCBase
return result;
}
//
// Actions ...
bool IsSpike(
/**
* Detect Big Price Change Happens or not ...
*
* @param bar: XOHCL instance reference, Start Bar ...
* @param dir: ENUM_X_DIRECTION member, Event Direction ...
* @param type: ENUM_X_PRICE member, Price Type ...
* @param forcBodyInRange: bool, Use Body in Range Detection ...
* @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ...
*
* @return ( bool )
*/
bool IsBigChange(
XOHCL &bar,
XOHCL &fromBar,
XOHCL &toBar,
ENUM_X_DIRECTION &dir,
double minPriceChangePercent = 1.5,
ENUM_X_PRICE type = X_PRICE_CLOSE,
bool forcBodyInRange = true,
double rangeExtendMultiplier = 2,
int loopback = 14 //
double rangeExtendMultiplier = 1.0 //
)
{
//
bool result = false;
//
toBar.Clean();
fromBar.Clean();
dir = X_DIRECTION_NONE;
loopback = NormalizeInt(loopback, 1);
rangeExtendMultiplier = NormalizeDouble(rangeExtendMultiplier, 1);
minPriceChangePercent = NormalizeDouble(minPriceChangePercent, 1.5);
//
int periodSeconds = PeriodSeconds(bar.period);
double divider = X_PERCENTAGE_GOLDEN_MULTIPLIER;
double periodMult = (periodSeconds / PeriodSeconds(PERIOD_M5)) * 0.2;
minPriceChangePercent /= (divider / periodMult);
//
result = bar.IsValid();
result =
bar.IsValid() &&
IsValid(type);
if (!result)
{
return result;
}
//
double minPriceChangePercent = 0;
int loopback = GetPeriodSharpData(
minPriceChangePercent,
bar.period //
);
//
double ranges[];
int rangesCount = GetPriceRange(
@@ -765,6 +765,7 @@ class XCBarAnalyser : public XCBase
}
//
// Calculate Ranges ...
double rangeMax = GetMax(ranges);
double rangeMin = GetMin(ranges);
double rangeAverage = GetAverage(ranges);
@@ -775,29 +776,54 @@ class XCBarAnalyser : public XCBase
);
//
static double maxPriceChange = 0;
static double minPriceChange = 0;
if (maxPriceChange == 0 || maxPriceChange < priceChangePercent)
// Calculate HH and LL ...
double hh = 0;
double ll = 0;
int hhIDX = -1;
int llIDX = -1;
result = CalculateLoopbackHLData(
hhIDX,
hh,
llIDX,
ll,
bar,
loopback //
);
result =
result &&
ll > 0 &&
hh > ll &&
IsValidIndex(llIDX) &&
IsValidIndex(hhIDX);
if (!result)
{
maxPriceChange = priceChangePercent;
}
if (minPriceChange == 0 || minPriceChange > priceChangePercent)
{
minPriceChange = priceChangePercent;
return result;
}
//
int hhDiff = (hhIDX - bar.Index());
int llDiff = (llIDX - bar.Index());
//
bool isBullish =
//
hhDiff <= 1 &&
llIDX > hhIDX &&
bar.close >= hh &&
priceChangePercent > 0 &&
priceChangePercent >= minPriceChangePercent
priceChangePercent >= minPriceChangePercent &&
bar.high > (rangeAverage * rangeExtendMultiplier)
//
;
//
bool isBearish =
//
llDiff <= 1 &&
hhIDX > llIDX &&
bar.close <= ll &&
priceChangePercent < 0 &&
bar.low < (rangeAverage * rangeExtendMultiplier) &&
MathAbs(priceChangePercent) >= minPriceChangePercent
//
;
@@ -823,6 +849,504 @@ class XCBarAnalyser : public XCBase
return result;
}
//
// Actions ...
/**
* Detect Spike ...
*
* @param bar: XOHCL instance reference, Start Bar ...
* @param dir: ENUM_X_DIRECTION member, Event Direction ...
* @param type: ENUM_X_PRICE member, Price Type ...
* @param forcBodyInRange: bool, Use Body in Range Detection ...
* @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ...
* @param sameBars: int, Specified How Many Same Bars Required for an Spike ...
*
* @return ( bool )
*/
bool IsSpike(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
ENUM_X_PRICE type = X_PRICE_CLOSE,
bool forcBodyInRange = true,
double rangeExtendMultiplier = 1.0,
int sameBars = 3 //
)
{
//
bool result = false;
//
dir = X_DIRECTION_NONE;
sameBars = NormalizeInt(sameBars, 2);
//
result = IsValid(type) &&
bar.IsValid();
if (!result)
{
return result;
}
//
// First We Have to Has a Big Change ...
result = IsBigChange(
bar,
dir,
type,
forcBodyInRange,
rangeExtendMultiplier //
);
if (!result)
{
return result;
}
//
// Check Has Same Bars ...
int sameBarsIndex = -1;
ENUM_X_DIRECTION sameBarsDir;
result = HasSameBars(
bar,
sameBarsDir,
sameBarsIndex,
sameBars //
);
if (!result)
{
return result;
}
//
// Check Same Bars Direction sames To Price Change ...
result = sameBarsDir == dir;
if (!result)
{
return result;
}
//
return result;
}
//
// Candlestick ...
/**
* Check Specified Bar is Doji Pattern or not ...
*
* @param bar: XOHCL instance reference, Specified Bar to Check ...
* @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ...
* @param shadowMultiplier: double, Specified Shadow Multiplier ...
*
* @return ( bool )
*/
bool IsDoji(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
double shadowMultiplier = 1.5 //
)
{
//
bool result = false;
//
dir = X_DIRECTION_NONE;
shadowMultiplier = NormalizeDouble(shadowMultiplier, 1.5, 3);
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
double body = bar.GetBody();
double range = bar.GetRange();
//
result =
body > 0 &&
range > 0
? (body / range < 0.1)
: false;
if (result)
{
//
dir =
bar.GetLowShadow() >= (bar.GetHighShadow() * shadowMultiplier)
? X_DIRECTION_BULLISH
: bar.GetHighShadow() >= (bar.GetLowShadow() * shadowMultiplier)
? X_DIRECTION_BEARISH
: X_DIRECTION_NONE;
//
result = HasDirection(dir);
}
//
return result;
}
/**
* Check Specified Bar is Hammer Pattern or not ...
*
* @param bar: XOHCL instance reference, Specified Bar to Check ...
* @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ...
* @param bodyMultiplier: double, Specified Body Multiplier ...
*
* @return ( bool )
*/
bool IsHammer(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
double bodyMultiplier = 2.0 //
)
{
//
bool result = false;
//
dir = X_DIRECTION_NONE;
bodyMultiplier = NormalizeDouble(bodyMultiplier, 1.5, 3);
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
double body = bar.GetBody();
double lShadow = bar.GetLowShadow();
double hShadow = bar.GetHighShadow();
//
bool isBullish =
hShadow < body &&
lShadow > (bodyMultiplier * body);
//
bool isBearish =
lShadow < body &&
hShadow > (bodyMultiplier * body);
//
result = isBullish ||
isBearish;
if (result)
{
//
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
return result;
}
/**
* Check Specified Bar is Engulfed Prev Bar or not ...
*
* @param bar: XOHCL instance reference, Specified Bar to Check ...
* @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ...
*
* @return ( bool )
*/
bool IsEngulfed(
XOHCL &bar,
ENUM_X_DIRECTION &dir //
)
{
//
bool result = false;
//
dir = X_DIRECTION_NONE;
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
XOHCL pBar;
result = bar.GetPreviousBar(pBar);
if (!result)
{
//
pBar.Clean();
return result;
}
//
result = bar.GetBody() > pBar.GetBody();
if (!result)
{
//
pBar.Clean();
return result;
}
//
bool isBullish =
bar.IsBullish() &&
pBar.IsBearish() &&
bar.GetDown() <= pBar.GetDown() &&
bar.GetUp() > pBar.GetUp();
//
bool isBearish =
bar.IsBearish() &&
pBar.IsBullish() &&
bar.GetUp() >= pBar.GetUp() &&
bar.GetDown() < pBar.GetDown();
//
result = isBullish ||
isBearish;
if (result)
{
//
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
// Cleanup Resources ...
//
pBar.Clean();
//
return result;
}
/**
* Check Specified Bar is Momentum Bar or not ...
*
* @param bar: XOHCL instance reference, Specified Bar to Check ...
* @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ...
* @param loopback: int, Specified Loopback ...
* @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ...
*
* @return ( bool )
*/
bool IsMomentum(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
int loopback = 2,
double rangeExtendMultiplier = 1.5 //
)
{
//
bool result = false;
//
dir = X_DIRECTION_NONE;
loopback = NormalizeInt(loopback, 1);
rangeExtendMultiplier = NormalizeDouble(rangeExtendMultiplier, 1);
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Bar Must Engulfed ...
result = IsEngulfed(
bar,
dir //
);
if (!result)
{
return result;
}
//
// Calculate HH and LL ...
double hh = 0;
double ll = 0;
int hhIDX = -1;
int llIDX = -1;
result = CalculateLoopbackHLData(
hhIDX,
hh,
llIDX,
ll,
bar,
loopback //
);
result =
result &&
ll > 0 &&
hh > ll &&
IsValidIndex(llIDX) &&
IsValidIndex(hhIDX);
if (!result)
{
return result;
}
//
bool isBullish =
bar.low > ll &&
IsBullish(dir) &&
bar.close >= hh;
//
bool isBearish =
bar.high < hh &&
IsBearish(dir) &&
bar.close <= ll;
//
result = isBullish ||
isBearish;
if (result)
{
//
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
// Cleanup Resources ...
//
return result;
}
/**
* Check Specified Bar is Pullback or not ...
*
* @param bar: XOHCL instance reference, Specified Bar to Check ...
* @param dir: ENUM_X_DIRECTION member, Specified Doji Direction ...
* @param loopback: int, Specified Loopback ...
* @param forceBody: bool, Force Using Body ...
*
* @return ( bool )
*/
bool IsPullback(
XOHCL &bar,
ENUM_X_DIRECTION &dir,
int loopback = 3,
bool forceBody = false //
)
{
//
bool result = false;
//
dir = X_DIRECTION_NONE;
loopback = NormalizeInt(loopback, 3);
//
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Bar Must Engulfed ...
result = IsEngulfed(
bar,
dir //
);
if (!result)
{
return result;
}
//
// Calculate HH and LL ...
double hh = 0;
double ll = 0;
int hhIDX = -1;
int llIDX = -1;
result = CalculateLoopbackHLData(
hhIDX,
hh,
llIDX,
ll,
bar,
loopback //
);
result =
result &&
ll > 0 &&
hh > ll &&
IsValidIndex(llIDX) &&
IsValidIndex(hhIDX);
if (!result)
{
return result;
}
//
bool isBullish =
bar.high > hh &&
bar.low > ll;
//
bool isBearish =
bar.high < hh &&
bar.low < ll;
//
result = isBullish ||
isBearish;
if (result)
{
//
if (forceBody)
{
//
isBullish =
isBullish &&
bar.GetUp() > hh &&
bar.GetDown() > ll &&
llIDX == bar.Index() + 1;
//
isBearish =
isBearish &&
bar.GetUp() < hh &&
bar.GetDown() < ll &&
hhIDX == bar.Index() + 1;
//
result = isBullish ||
isBearish;
}
//
if (result)
{
//
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
}
//
return result;
}
//
protected:
//
-46
View File
@@ -2988,52 +2988,6 @@
//
// Decisions ...
//
bool IsBullishDecision(
XOHCL &bar,
double percent = 70 // Percent of Body
)
{
//
bool result = false;
//
result =
//
bar.IsValid() &&
bar.Index() > 0 &&
bar.IsBullish() &&
(bar.GetRange() * percent) / 100 <= bar.GetBody()
//
;
//
return result;
}
//
bool IsBearishDecision(
XOHCL &bar,
double percent = 70 // Percent of Body
)
{
//
bool result = false;
//
result =
//
bar.IsValid() &&
bar.Index() > 0 &&
bar.IsBearish() &&
(bar.GetRange() * percent) / 100 <= bar.GetBody()
//
;
//
return result;
}
//
// Candlestic Patterns ...
+114 -7
View File
@@ -24,6 +24,7 @@
//
// XCPOIDetector *mPOIDetector;
XBarTracker mBarTracker;
XCBarAnalyser *mBarAnalyser;
//
@@ -47,6 +48,12 @@ int OnInit()
//
mBarAnalyser = new XCBarAnalyser();
//
mBarTracker.Init(
_Symbol,
_Period //
);
//
return (INIT_SUCCEEDED);
}
@@ -89,6 +96,12 @@ void DetectBarAnalyser()
return;
}
//
if (!mBarTracker.IsNewBar())
{
return;
}
//
XOHCL zBar;
bool isInited = zBar.Init(
@@ -96,21 +109,115 @@ void DetectBarAnalyser()
_Period,
0 //
);
if (!isInited)
{
//
zBar.Clean();
return;
}
//
XOHCL toBar;
XOHCL fromBar;
XOHCL cBar;
isInited = zBar.GetPreviousBar(cBar);
if (!isInited)
{
//
zBar.Clean();
cBar.Clean();
return;
}
//
// Check Big Change in Price ...
ENUM_X_DIRECTION dir;
bool isBigChange = mBarAnalyser.IsBigChange(
zBar, // Bar ...
dir, // Change Direction ...
X_PRICE_CLOSE, // Price Change Type ...
true, // Force Use Body for Range Calculation ...
1.0 // Range Extend Multiplier ...
);
if (isBigChange)
{
// Print("Big Price Change Detected: ", ToString(dir));
}
//
// Check Big Change in Price ...
bool isSpike = mBarAnalyser.IsSpike(
zBar,
fromBar,
toBar,
dir //
zBar, // Bar ...
dir, // Change Direction ...
X_PRICE_CLOSE, // Price Change Type ...
true, // Force Use Body for Range Calculation ...
1.0, // Range Extend Multiplier ...
3 // Same Bars ...
);
if (isSpike)
{
Print("Spike Detected ...");
// Print("Spike Detected: ", ToString(dir));
}
//
// Check Doji Pattern ...
bool isDoji = mBarAnalyser.IsDoji(
cBar,
dir //
);
if (isDoji)
{
Print(ToString(dir), " Doji Detected ...");
}
//
// Check Hammer Pattern ...
bool isHammer = mBarAnalyser.IsHammer(
cBar,
dir //
);
if (isHammer)
{
Print(ToString(dir), " Hammer Detected ...");
}
//
// Check Engulf Pattern ...
bool isEngulfed = mBarAnalyser.IsEngulfed(
cBar,
dir //
);
if (isEngulfed)
{
Print(ToString(dir), " Engulfed Detected ...");
}
//
// Check Momentum Pattern ...
bool isMomentum = mBarAnalyser.IsMomentum(
cBar,
dir //
);
if (isMomentum)
{
Print(ToString(dir), " Momentum Detected ...");
}
//
// Check Pullback Pattern ...
bool isPullback = mBarAnalyser.IsPullback(
cBar,
dir //
);
if (isMomentum)
{
Print(ToString(dir), " Pullback Detected ...");
}
//
// Cleanup Resources ...
//
zBar.Clean();
cBar.Clean();
}
/**
@@ -3425,6 +3425,183 @@ int GetCycleLengthOn(
return result;
}
/**
* Retrieve Sharp Change Info for Specified Period ...
*
* @param priceChange: double, required Price Change ...
* @param mPeriod: ENUM_TIMEFRAMES member, Specified Period ...
*
* @return ( int )
*/
int GetPeriodSharpData(
double &priceChange,
ENUM_TIMEFRAMES mPeriod = NULL //
)
{
//
int result = 0;
//
priceChange = 0.0;
//
mPeriod = NormalizePeriod(mPeriod);
//
switch (mPeriod)
{
//
case PERIOD_M1:
//
priceChange = 0.000008;
result = 14;
break;
//
case PERIOD_M2:
//
priceChange = 0.000008;
result = 14;
break;
//
case PERIOD_M3:
//
priceChange = 0.00001;
result = 14;
break;
//
case PERIOD_M4:
//
priceChange = 0.000011;
result = 14;
break;
//
case PERIOD_M5:
//
priceChange = 0.000015;
result = 14;
break;
//
case PERIOD_M6:
//
priceChange = 0.000015;
result = 14;
break;
//
case PERIOD_M10:
//
priceChange = 0.000015;
result = 12;
break;
//
case PERIOD_M12:
//
priceChange = 0.000015;
result = 11;
break;
//
case PERIOD_M15:
//
priceChange = 0.000015;
result = 9;
break;
//
case PERIOD_M20:
//
priceChange = 0.000015;
result = 9;
break;
//
case PERIOD_M30:
//
priceChange = 0.000017;
result = 7;
break;
//
case PERIOD_H1:
//
priceChange = 0.000019;
result = 5;
break;
//
case PERIOD_H2:
//
priceChange = 0.000019;
result = 5;
break;
//
case PERIOD_H3:
//
priceChange = 0.000019;
result = 5;
break;
//
case PERIOD_H4:
//
priceChange = 0.000022;
result = 5;
break;
//
case PERIOD_H6:
//
priceChange = 0.000022;
result = 5;
break;
//
case PERIOD_H8:
//
priceChange = 0.000025;
result = 5;
break;
//
case PERIOD_H12:
//
priceChange = 0.000027;
result = 5;
break;
//
case PERIOD_D1:
//
priceChange = 0.000027;
result = 3;
break;
//
case PERIOD_W1:
//
priceChange = 0.00003;
result = 3;
break;
//
case PERIOD_MN1:
//
priceChange = 0.00003;
result = 3;
break;
}
//
return result;
}
//
// END Cycles ...
//
@@ -5873,6 +6050,137 @@ double GetAppliedPrice(
return result;
}
/**
* Calculate Applied Price ...
*
* @param mSymbol: string, Specified Symbol ...
* @param mPeriod: ENUM_TIMEFRAMES member, Specified PEriod ...
* @param barIndex: int, Specified Bar Index ...
* @param mType: ENUM_X_PRICE member, Specified Price Type ...
*
* @return ( double )
*/
double GetAppliedPrice(
string mSymbol = NULL, // Symbol
ENUM_TIMEFRAMES mPeriod = NULL, // Period
int barIndex = 0, // Bar Index
ENUM_X_PRICE mType = X_PRICE_CLOSE // Type of Price Selection,
)
{
//
double result = 0;
//
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
barIndex = NormalizeInt(barIndex, 0);
//
bool has = IsValid(mType);
if (!has)
{
return result;
}
//
double open = iOpen(
mSymbol,
mPeriod,
barIndex //
);
//
double high = iHigh(
mSymbol,
mPeriod,
barIndex //
);
//
double low = iLow(
mSymbol,
mPeriod,
barIndex //
);
//
double close = iClose(
mSymbol,
mPeriod,
barIndex //
);
//
// Retrieve Applied Price ...
result = GetAppliedPrice(
mType,
open,
high,
low,
close //
);
//
return result;
}
/**
* Calculate Applied Price ...
*
* @param mSymbol: string, Specified Symbol ...
* @param mPeriod: ENUM_TIMEFRAMES member, Specified PEriod ...
* @param time: int, Specified Bar Time ...
* @param mType: ENUM_X_PRICE member, Specified Price Type ...
*
* @return ( double )
*/
double GetAppliedPrice(
string mSymbol = NULL, // Symbol
ENUM_TIMEFRAMES mPeriod = NULL, // Period
datetime mTime = NULL, // Bar Time
ENUM_X_PRICE mType = X_PRICE_CLOSE // Type of Price Selection,
)
{
//
double result = 0;
//
mTime = NormalizeTime(mTime);
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
//
bool has = IsValid(mType);
if (!has)
{
return result;
}
//
int barIndex = GetBarIndex(
mSymbol,
mPeriod,
mTime //
);
has = IsValidIndex(barIndex);
if (!has)
{
return result;
}
//
// Retrieve Applied Price ...
result = GetAppliedPrice(
mSymbol,
mPeriod,
barIndex,
mType //
);
//
return result;
}
//
// END Price ...
//