Files
MQL5Data/Classes/x-saherelm.x-bar.analyser.class.mq5
T
2025-03-14 17:44:33 +03:30

843 lines
17 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 ...
//
#define X_PERCENTAGE_GOLDEN_MULTIPLIER 100000
//
// Implementations ...
class XCBarAnalyser : public XCBase
{
//
public:
//
//
// Constructor(s) ...
void XCBarAnalyser()
{
}
//
// Deconstructor ...
void ~XCBarAnalyser()
{
}
//
// Getter(s) / Setter(s) ...
//
// Providers ...
/**
* 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;
}
/**
* Fill Prices ...
*
* @param prices: double collection
* @param bar: XOHCL instance reference, Provides Start ...
* @param loopback: int, Specified How Many Bars Process ...
* @param type: ENUM_X_PRICE member, Specified Price Type ...
*
* @return ( bool )
*/
bool FillPrice(
double &prices[],
XOHCL &bar,
int loopback = 14,
ENUM_X_PRICE type = X_PRICE_CLOSE //
)
{
//
bool result = false;
//
Clean(prices);
//
loopback = NormalizeInt(loopback, 1);
//
result = IsValid(type) &&
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;
}
//
for (int i = index; i < count; i++)
{
//
XOHCL iBar;
bool isInited = iBar.Init(
symbol,
period,
i //
);
if (!isInited)
{
//
iBar.Clean();
continue;
}
//
double iPrice = iBar.GetPrice(type);
//
isInited = NotEmptyZero(iPrice);
if (isInited)
{
//
Add(
iPrice,
prices //
);
}
//
iBar.Clean();
}
//
result = ArraySize(prices) == count;
if (!result)
{
Clean(prices);
}
//
ArrayReverse(prices);
//
return result;
}
/**
* Calculate Price Range ...
*
* @param ranges: double Collection, Calculated Ranges ...
* @param bar: XOHCL instance Reference, Start Bar ...
* @param forceBody: bool, Force to Calculate Range using Body ...
* @param loopback: int, loopback period for Range Calculated ...
*
* @return ( int )
*/
int GetPriceRange(
double &ranges[],
XOHCL &bar,
bool forceBody = false,
int loopback = 14 //
)
{
//
int result = 0;
//
Clean(ranges);
//
loopback = NormalizeInt(loopback, 1);
//
if (!bar.IsValid())
{
return result;
}
//
bool has = false;
//
// Select Uppers Prices ...
double uppers[];
int uppersCount = 0;
if (forceBody)
{
//
has = FillPrice(
uppers,
bar,
loopback,
X_PRICE_UP //
);
}
else
{
//
has = FillPrice(
uppers,
bar,
loopback,
X_PRICE_HIGH //
);
}
if (has)
{
uppersCount = ArraySize(uppers);
}
//
// Select Lower Prices ...
double lowers[];
int lowersCount = 0;
if (forceBody)
{
//
has = FillPrice(
lowers,
bar,
loopback,
X_PRICE_DOWN //
);
}
else
{
//
has = FillPrice(
lowers,
bar,
loopback,
X_PRICE_LOW //
);
}
if (has)
{
lowersCount = ArraySize(lowers);
}
//
// Validate Filled Prices ...
has =
IsValidSize(uppersCount) &&
IsValidSize(lowersCount) &&
uppersCount == lowersCount;
if (!has)
{
//
Clean(uppers);
Clean(lowers);
//
return result;
}
//
for (int i = 0; i < uppersCount; i++)
{
//
double iValue = uppers[i] - lowers[i];
//
Add(
iValue,
ranges //
);
}
//
result = ArraySize(ranges);
ArrayReverse(ranges);
//
// Cleanup Resources ...
//
Clean(uppers);
Clean(lowers);
//
return result;
}
/**
* Calculate Price Change Percent ...
*
* @param bar: XOHCL instance Reference, Start Bar ...
* @param type: ENUM_X_PRICE member, Specified Price Type ...
* @param loopback: int, loopback period for Range Calculated ...
*
* @return ( double )
*/
double GetPriceChangeRate(
XOHCL &bar,
ENUM_X_PRICE type = X_PRICE_CLOSE,
int loopback = 14 //
)
{
//
double result = 0;
//
bool has = false;
//
loopback = NormalizeInt(loopback, 1);
//
has =
IsValid(type) &&
bar.IsValid();
if (!has)
{
return result;
}
//
XOHCL oldBar;
has = oldBar.Init(
bar.symbol,
bar.period,
bar.Index() + loopback //
);
if (!has)
{
//
oldBar.Clean();
//
return result;
}
double newPrice = bar.GetPrice(type);
double oldPrice = oldBar.GetPrice(type);
//
result = ((newPrice - oldPrice) / oldPrice) / 100;
//
oldBar.Clean();
//
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() + 1;
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 if (isBearish)
{
//
sameBearishBarsFounded++;
canContinueForBullish = false;
}
else
{
//
sameBullishBarsFounded = 0;
sameBearishBarsFounded = 0;
canContinueForBullish = false;
canContinueForBearish = 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;
}
//
index--;
//
dir =
hasBullishSameBars
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
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 forDir,
ENUM_X_FIBO_LEVELS level //
)
{
//
bool result = false;
//
result = bar.IsValid() &&
HasDirection(forDir);
if (!result)
{
return result;
}
//
bool isBullish = IsBullish(forDir);
bool isBearish = IsBearish(forDir);
//
double fiboLevelValue = GetFibonacciLevel(
bar.high,
bar.low,
level,
forDir //
);
//
bool isBullishPressured =
isBullish &&
bar.GetDown() > fiboLevelValue;
bool isBearishPressured =
isBearish &&
bar.GetUp() < fiboLevelValue;
//
result = isBullishPressured ||
isBearishPressured;
//
return result;
}
//
// Actions ...
bool IsSpike(
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 //
)
{
//
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();
if (!result)
{
return result;
}
//
double ranges[];
int rangesCount = GetPriceRange(
ranges,
bar,
forcBodyInRange,
loopback //
);
result = IsValidSize(rangesCount);
if (!result)
{
//
Clean(ranges);
//
return result;
}
//
double rangeMax = GetMax(ranges);
double rangeMin = GetMin(ranges);
double rangeAverage = GetAverage(ranges);
double priceChangePercent = GetPriceChangeRate(
bar,
type,
loopback //
);
//
static double maxPriceChange = 0;
static double minPriceChange = 0;
if (maxPriceChange == 0 || maxPriceChange < priceChangePercent)
{
maxPriceChange = priceChangePercent;
}
if (minPriceChange == 0 || minPriceChange > priceChangePercent)
{
minPriceChange = priceChangePercent;
}
//
bool isBullish =
//
priceChangePercent > 0 &&
priceChangePercent >= minPriceChangePercent
//
;
//
bool isBearish =
//
priceChangePercent < 0 &&
MathAbs(priceChangePercent) >= minPriceChangePercent
//
;
//
result = isBullish ||
isBearish;
if (result)
{
//
dir = isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
}
//
// Cleanup Resources ...
//
Clean(ranges);
//
return result;
}
//
protected:
//
//
private:
//
//
// Props ...
//
// Actions ...
//
};
//