Files
MQL5Data/Libraries/x-saherelm.x-ohcl.lib.mq5
2025-10-09 12:34:26 +03:30

3082 lines
54 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Common Library
// --------------------------------------
// Name: XOHCLLib
// Description: provide all commonly used functions ...
//
//
// 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
//
#include "../Libraries/x-saherelm.common.extensions.lib.mq5"
//
// Describe an Specific Candle ...
struct XOHCL
{
//
// Props ...
//
double high;
double open;
double close;
double low;
long volume;
double spread;
//
string symbol;
datetime time;
ENUM_TIMEFRAMES period;
//
// Constructor ...
XOHCL()
{
Clean();
}
//
// Init a Bar ...
// Using Bar Index ...
bool Init(
string mSymbol = NULL, // Trading Symbol
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period
int barIndex = 0 // Bar Index
)
{
//
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
//
symbol = mSymbol;
period = mPeriod;
//
time = iTime(
mSymbol,
mPeriod,
barIndex //
);
//
open = iOpen(
mSymbol,
mPeriod,
barIndex //
);
open = NormalizePrice(open, mSymbol);
//
close = iClose(
mSymbol,
mPeriod,
barIndex //
);
close = NormalizePrice(close, mSymbol);
//
high = iHigh(
mSymbol,
mPeriod,
barIndex //
);
high = NormalizePrice(high, mSymbol);
//
low = iLow(
mSymbol,
mPeriod,
barIndex //
);
low = NormalizePrice(low, mSymbol);
//
spread = iSpread(
mSymbol,
mPeriod,
barIndex //
);
spread = NormalizePrice(spread, mSymbol);
//
volume = iTickVolume(
mSymbol,
mPeriod,
barIndex //
);
//
bool result = IsValid();
//
return result;
}
//
// Init a Bar ...
// Using Bar Time ...
bool Init(
string mSymbol = NULL, // Trading Symbol
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period
datetime mTime = NULL // Bar Time
)
{
//
mTime = NormalizeTime(mTime);
//
int barIndex = iBarShift(
mSymbol,
mPeriod,
mTime,
false //
);
//
bool result = Init(
mSymbol,
mPeriod,
barIndex
//
);
//
return result;
}
//
// Tools ...
//
void Clean()
{
//
low = 0;
high = 0;
open = 0;
close = 0;
spread = 0;
volume = 0;
//
time = NULL;
symbol = NULL;
period = NULL;
//
ZeroMemory(this);
}
//
// Validate Bar ...
bool IsValid()
{
//
bool result = false;
//
result =
//
low > 0 &&
high > 0 &&
open > 0 &&
close > 0 &&
volume > 0
//
// TODO: Fix in Some Cases for Zero Spread ...
// spread > 0 &&
//
;
//
return result;
}
//
int TotalBars()
{
//
int result = 0;
//
result = iBars(
symbol,
period //
);
//
return result;
}
//
// Calculate X_PRICE Specified Type ...
double GetPrice(ENUM_X_PRICE mPType)
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
return GetAppliedPrice(
mPType,
open,
high,
low,
close //
);
}
//
// Retrieve Price base On Series Mode ...
double GetPrice(ENUM_SERIESMODE mMode)
{
//
ENUM_X_PRICE mType = ToXPrice(mMode);
//
return GetPrice(mType);
}
//
// Calculate Applied Price ...
double GetPrice(ENUM_APPLIED_PRICE mPType)
{
//
ENUM_X_PRICE mType = ToXPrice(mPType);
//
return GetPrice(mType);
}
//
// Find Specific Price ...
bool FindHigherPriceBar(
XOHCL &bar,
double price,
ENUM_X_PRICE _type = X_PRICE_HIGH //
)
{
//
bool result = false;
//
result = IsValid();
if (!result)
{
return result;
}
//
int totalBars = TotalBars();
result = IsValidSize(totalBars);
if (!result)
{
return result;
}
//
int start = Index();
int maxAllowedLoopback = totalBars / 5;
for (int i = start; i < maxAllowedLoopback; i++)
{
//
result = bar.Init(
symbol,
period,
i //
);
//
if (!result)
{
break;
}
//
double iPrice = bar.GetPrice(_type);
//
result =
//
iPrice > 0 &&
iPrice > price
//
;
if (result)
{
break;
}
}
//
if (!result)
{
bar.Clean();
}
//
return result;
}
//
// Find Specific Price ...
bool FindLowerPriceBar(
XOHCL &bar,
double price,
ENUM_X_PRICE _type = X_PRICE_HIGH //
)
{
//
bool result = false;
//
result = IsValid();
if (!result)
{
return result;
}
//
int totalBars = TotalBars();
result = IsValidSize(totalBars);
if (!result)
{
return result;
}
//
int start = Index();
int maxAllowedLoopback = totalBars / 5;
for (int i = start; i < maxAllowedLoopback; i++)
{
//
result = bar.Init(
symbol,
period,
i //
);
//
if (!result)
{
break;
}
//
double iPrice = bar.GetPrice(_type);
//
result =
//
iPrice > 0 &&
iPrice < price
//
;
if (result)
{
break;
}
}
//
if (!result)
{
bar.Clean();
}
//
return result;
}
//
// Calculate up Price ...
double GetUp()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = MathMax(open, close);
//
return result;
}
//
// Calculate Down Price ...
double GetDown()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = MathMin(open, close);
//
return result;
}
//
// Calculate Bar Body ...
double GetBody()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = GetUp() - GetDown();
//
return result;
}
//
// Calculate Bar Range ...
double GetRange()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = high - low;
//
return result;
}
//
// Calculate Bar Shadows ...
double GetShadows()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = GetRange() - GetBody();
//
return result;
}
//
// Calculate Bar High Shadow ...
double GetHighShadow()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result =
//
high - GetUp()
//
;
//
return result;
}
//
// Calculate Bar Low Shadow ...
double GetLowShadow()
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result =
//
GetDown() - low;
//
;
//
return result;
}
//
// Check Bar is Bullish ...
bool IsBullish()
{
//
bool result = false;
//
if (!IsValid())
{
return result;
}
//
result = open < close;
//
return result;
}
//
// Check Bar is Bearish ...
bool IsBearish()
{
//
bool result = false;
//
if (!IsValid())
{
return result;
}
//
result = open > close;
//
return result;
}
//
// Get Direction of Bar ...
ENUM_X_DIRECTION GetDirection()
{
//
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
//
bool isBullish = IsBullish();
bool isBearish = IsBearish();
//
result =
isBullish && isBearish
? X_DIRECTION_ALL
: !isBullish && !isBearish
? X_DIRECTION_NONE
: isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
return result;
}
//
// Find Next Bar Time ...
datetime NextAt()
{
//
datetime result = NULL;
//
if (!IsValid())
{
return result;
}
//
int prSeconds = PeriodSeconds(period);
//
result = time + prSeconds;
//
return result;
}
//
// Find Prev Bar Time ...
datetime BeforeOn()
{
//
datetime result = NULL;
//
if (!IsValid())
{
return result;
}
//
int prSeconds = PeriodSeconds(period);
//
result = time - prSeconds;
//
return result;
}
//
// Calculate Last Bar Open Time in Smaller Period ...
datetime GetLastBarTimeOfPeriod(
ENUM_TIMEFRAMES smallerPeriod //
)
{
//
datetime result = NULL;
//
if (!IsValid())
{
return result;
}
//
int sourceSeconds = PeriodSeconds(period);
int destSeconds = PeriodSeconds(smallerPeriod);
if (destSeconds >= sourceSeconds)
{
//
result = time;
return result;
}
//
result = (datetime)((((int)time) + sourceSeconds) - destSeconds);
//
return result;
}
//
// Calculate Close Time ...
datetime GetCloseTime()
{
//
datetime result = NULL;
//
if (!IsValid())
{
return result;
}
//
int seconds = PeriodSeconds(period);
//
result = (datetime)(((int)time) + seconds);
//
return result;
}
//
bool BarAt(
int index,
XOHCL &bar //
)
{
//
bool result = false;
//
bar.Clean();
//
result = IsValid();
if (!result)
{
return result;
}
//
if (index < 0)
{
index = 0;
}
//
result = bar.Init(
symbol,
period,
index //
);
//
return result;
}
//
bool BarAt(
datetime _time,
XOHCL &bar //
)
{
//
bool result = false;
//
bar.Clean();
//
result = IsValid();
if (!result)
{
return result;
}
//
_time = NormalizeTime(_time);
//
result = bar.Init(
symbol,
period,
_time //
);
//
return result;
}
//
bool BarIn(
ENUM_TIMEFRAMES _period,
XOHCL &bar //
)
{
//
bool result = false;
//
bar.Clean();
//
result = IsValid() &&
IsSpecifiedValid(_period);
if (!result)
{
return result;
}
//
int index = Index(_period);
result = bar.Init(
symbol,
_period,
index //
);
//
return result;
}
//
// Find Current Bar Index on Chart ...
int Index()
{
//
int result = -1;
//
if (!IsValid())
{
return result;
}
//
result = iBarShift(
symbol,
period,
time
//
);
//
return result;
}
//
int Index(datetime value)
{
//
int result = -1;
//
value = NormalizeTime(value);
//
result = IsValid();
if (!result)
{
return result;
}
//
result = iBarShift(
symbol,
period,
value //
);
//
return result;
}
//
int Index(ENUM_TIMEFRAMES value)
{
//
int result = -1;
//
result = IsValid() &&
IsSpecifiedValid(value);
if (!result)
{
return result;
}
//
result = iBarShift(
symbol,
value,
time //
);
//
return result;
}
//
bool GetNextBar(XOHCL &bar)
{
//
bool result = false;
//
result = IsValid();
if (!result)
{
return result;
}
//
int idx = Index();
result = idx > 0;
if (!result)
{
return result;
}
//
result = bar.Init(
this.symbol,
this.period,
idx - 1 //
);
//
if (!result)
{
bar.Clean();
}
//
return result;
}
//
bool GetPreviousBar(XOHCL &bar)
{
//
bool result = false;
//
result = IsValid();
if (!result)
{
return result;
}
//
int idx = Index();
//
result = bar.Init(
this.symbol,
this.period,
idx + 1 //
);
//
if (!result)
{
bar.Clean();
}
//
return result;
}
//
bool HasFiboPressure(
ENUM_X_DIRECTION forDir,
ENUM_X_FIBO_LEVELS level = X_FIBO_LEVEL_382 //
)
{
//
bool result = false;
//
result = IsValid() &&
HasDirection(forDir);
if (!result)
{
return result;
}
//
bool isBullish = IsSpecifiedBullish(forDir);
bool isBearish = IsSpecifiedBearish(forDir);
//
double fiboLevelValue = GetFibonacciLevel(
high,
low,
level,
forDir //
);
//
isBullish =
isBullish &&
GetDown() > fiboLevelValue;
isBearish =
isBearish &&
GetUp() < fiboLevelValue;
//
result = isBullish ||
isBearish;
//
return result;
}
//
bool IsRejected(
double price,
ENUM_X_DIRECTION forDir,
bool forceType = false,
bool forcePressure = false //
)
{
//
bool result = false;
//
result = IsValid() &&
price > 0 &&
HasDirection(forDir);
if (!result)
{
return result;
}
//
bool isBullish =
IsSpecifiedBullish(forDir) &&
low < price &&
GetDown() > price;
//
bool isBearish =
IsSpecifiedBearish(forDir) &&
high > price &&
GetUp() < price;
//
if (forceType)
{
//
isBullish =
isBullish &&
IsBullish();
//
isBearish =
isBearish &&
IsBearish();
}
//
if (forcePressure)
{
//
isBullish =
isBullish &&
HasFiboPressure(forDir);
//
isBearish =
isBearish &&
HasFiboPressure(forDir);
}
//
result = isBullish ||
isBearish;
//
return result;
}
//
bool IsBreaked(
double price,
ENUM_X_DIRECTION forDir,
ENUM_X_FIBO_LEVELS fibLevel = X_FIBO_LEVEL_500,
ENUM_X_BOUNDARY_PRICE boundaryType = X_BOUNDARY_PRICE_UP_DOWN //
)
{
//
bool result = false;
//
result = IsValid() &&
price > 0 &&
HasDirection(forDir) &&
IsSpecifiedValid(boundaryType);
if (!result)
{
return result;
}
//
bool isUpDownPriceType = boundaryType == X_BOUNDARY_PRICE_UP_DOWN;
//
bool isBullish =
IsBullish() &&
low < price &&
high > price &&
IsSpecifiedBullish(forDir);
//
bool isBearish =
IsBearish() &&
low < price &&
high > price &&
IsSpecifiedBearish(forDir);
//
result = isBullish ||
isBearish;
if (result)
{
//
// Calculate Range ...
double range =
isUpDownPriceType
? GetBody()
: GetRange();
//
// Apply Edge Range ...
double iReqRange =
(range / 100) * (GetFiboLevelValue(fibLevel) * 100);
//
// Calculate Boundary Price ...
double iBoundary =
isUpDownPriceType
? isBullish
? GetUp()
: GetDown()
: isBullish
? high
: low;
//
// Detect Breaked Value ...
//
double breakedPrice =
isBullish
? (high - price)
: (price - low);
//
result =
breakedPrice >= iReqRange;
}
//
return result;
}
//
// Find Highest Bar Index ...
int FindHighestIndex(
int mLength, // Loopback ...
ENUM_SERIESMODE mMode // Calculation mode
)
{
//
int result = -1;
//
if (!IsValid())
{
return result;
}
//
if (mLength < 2)
{
mLength = 2;
}
//
result = iHighest(
symbol,
period,
mMode,
mLength,
Index());
//
return result;
}
//
// Find Highest ...
double FindHighest(
int mLength, // Loopback ...
ENUM_SERIESMODE mMode // Calculation mode
)
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
int idx = FindHighestIndex(
mLength,
mMode);
if (idx <= -1)
{
return result;
}
//
XOHCL iH;
result = iH.Init(
symbol,
period,
idx
//
);
if (!result)
{
return result;
}
//
result = iH.GetPrice(mMode);
//
return result;
}
/**
* Detect Highest of Specified Price type in Market ...
*
* @param index: souble, reference to hold detected Value Bar index ...
* @param mLength: int, Specified Loopback Length ...
* @param mPriceType: ENUM_X_PRICE, Specified Price type to Detect ...
*
* @return ( double )
*/
double FindHighest(
int &index, // Index ...
int mLength, // Loopback ...
ENUM_X_PRICE mPriceType // Price Type ...
)
{
//
double result = EMPTY_VALUE;
//
// Prepare ...
index = -1;
//
// Normalize ...
mLength = NormalizeInt(mLength, 1);
//
// Validate ...
bool has = IsValid() &&
IsXValid(mPriceType);
if (!has)
{
return result;
}
//
XOHCL iBar;
int start = Index();
int end = start + mLength;
double iValue = EMPTY_VALUE;
for (int i = start; i < end; i++)
{
//
iBar.Clean();
has = BarAt(i, iBar);
if (!has)
{
continue;
}
//
// Calculate Price ...
iValue = iBar.GetPrice(mPriceType);
//
// Compare Price With Prev Detected ...
has = !NotEmptyZero(result)
? true
: iValue > result;
if (has)
{
//
index = i;
result = iValue;
}
}
//
// Cleanup Resources ...
iBar.Clean();
//
return result;
}
//
// Find Highest ...
double FindHighestUp(
int mLength // Loopback ...
)
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = FindHighest(mLength, MODE_OPEN);
result = MathMax(mLength, FindHighest(mLength, MODE_CLOSE));
//
return result;
}
//
// Find Lowest Bar Index ...
int FindLowestIndex(
int mLength, // Loopback ...
ENUM_SERIESMODE mMode // Calculation mode
)
{
//
int result = -1;
//
if (!IsValid())
{
return result;
}
//
if (mLength < 2)
{
mLength = 2;
}
//
result = iLowest(
symbol,
period,
mMode,
mLength,
Index());
//
return result;
}
//
// Find Lowest ...
double FindLowest(
int mLength, // Loopback ...
ENUM_SERIESMODE mMode // Calculation mode
)
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
int idx = FindLowestIndex(
mLength,
mMode);
if (idx <= -1)
{
return result;
}
//
XOHCL iL;
result = iL.Init(
symbol,
period,
idx
//
);
if (!result)
{
return result;
}
//
result = iL.GetPrice(mMode);
//
return result;
}
/**
* Detect Lowest of Specified Price type in Market ...
*
* @param index: souble, reference to hold detected Value Bar index ...
* @param mLength: int, Specified Loopback Length ...
* @param mPriceType: ENUM_X_PRICE, Specified Price type to Detect ...
*
* @return ( double )
*/
double FindLowest(
int &index, // Index ...
int mLength, // Loopback ...
ENUM_X_PRICE mPriceType // Price Type ...
)
{
//
double result = EMPTY_VALUE;
//
// Prepare ...
index = -1;
//
// Normalize ...
mLength = NormalizeInt(mLength, 1);
//
// Validate ...
bool has = IsValid() &&
IsXValid(mPriceType);
if (!has)
{
return result;
}
//
XOHCL iBar;
int start = Index();
int end = start + mLength;
double iValue = EMPTY_VALUE;
for (int i = start; i < end; i++)
{
//
iBar.Clean();
has = BarAt(i, iBar);
if (!has)
{
continue;
}
//
// Calculate Price ...
iValue = iBar.GetPrice(mPriceType);
//
// Compare Price With Prev Detected ...
has = !NotEmptyZero(result)
? true
: iValue < result;
if (has)
{
//
index = i;
result = iValue;
}
}
//
// Cleanup Resources ...
iBar.Clean();
//
return result;
}
//
// Find Lowest ...
double FindLowesttDown(
int mLength // Loopback ...
)
{
//
double result = 0;
//
if (!IsValid())
{
return result;
}
//
result = FindLowest(mLength, MODE_OPEN);
result = MathMax(mLength, FindLowest(mLength, MODE_CLOSE));
//
return result;
}
//
// Swing Detection ...
//
int FindSwing(
ENUM_X_SWING_TYPE type,
int shoulders = 3 //
)
{
//
int result = -1;
//
// Validate ...
bool isValid = IsValid() &&
IsXValid(type);
if (!isValid)
{
return result;
}
//
// Find Next Swing ...
result = FindXSwing(
type,
symbol,
period,
Index(),
shoulders //
);
//
return result;
}
//
int FindNextSwing(
ENUM_X_SWING_TYPE type,
int shoulders = 3 //
)
{
//
int result = -1;
//
// Validate ...
bool isValid = IsValid() &&
IsXValid(type);
if (!isValid)
{
return result;
}
//
// Find Next Swing ...
result = FindXSwing(
type,
symbol,
period,
Index() + 1,
shoulders //
);
//
return result;
}
//
bool FindSwingBar(
ENUM_X_SWING_TYPE type,
XOHCL &swingBar,
int shoulders = 3 //
)
{
//
bool result = false;
//
// Prepare ...
swingBar.Clean();
//
// Validate ...
result = IsValid() &&
IsXValid(type);
if (!result)
{
return result;
}
//
// Find Next Swing ...
int idx = FindXSwing(
type,
symbol,
period,
Index(),
shoulders //
);
result = IsValidIndex(idx);
if (!result)
{
return result;
}
//
result = swingBar.Init(
symbol,
period,
idx //
);
//
return result;
}
//
bool FindNextSwingBar(
ENUM_X_SWING_TYPE type,
XOHCL &swingBar,
int shoulders = 3 //
)
{
//
bool result = false;
//
// Prepare ...
swingBar.Clean();
//
// Validate ...
result = IsValid() &&
IsXValid(type);
if (!result)
{
return result;
}
//
// Find Next Swing ...
int idx = FindXSwing(
type,
symbol,
period,
Index() + 1,
shoulders //
);
result = IsValidIndex(idx);
if (!result)
{
return result;
}
//
result = swingBar.Init(
symbol,
period,
idx //
);
//
return result;
}
//
// Same Checkers ...
//
bool IsSameAs(XOHCL &item)
{
//
bool result = false;
//
result = IsValid() &&
item.IsValid() &&
IsSameTime(item) &&
IsSameMarket(item);
//
return result;
}
//
bool IsSameTime(XOHCL &item)
{
//
bool result = false;
//
result = IsValid() &&
item.IsValid() &&
time == item.time;
//
return result;
}
//
bool IsSameSymbol(XOHCL &item)
{
//
bool result = false;
//
result = IsValid() &&
item.IsValid() &&
symbol == item.symbol;
//
return result;
}
//
bool IsSamePeriod(XOHCL &item)
{
//
bool result = false;
//
result = IsValid() &&
item.IsValid() &&
period == item.period;
//
return result;
}
//
bool IsSameMarket(XOHCL &item)
{
//
bool result = false;
//
result = IsValid() &&
item.IsValid() &&
IsSameSymbol(item) &&
IsSamePeriod(item);
//
return result;
}
//
// Other ...
string GetTag(string prefix = "")
{
//
string result = NULL;
//
result =
(IsSpecifiedValid(prefix)
? prefix + "_"
: "") +
"XOHCL_" + symbol + "_" + ToXString(period) + "_" + ToFormatString(time);
//
return result;
}
//
// Convert to String Representation ...
string ToString()
{
//
string result = "";
//
result = GetTypeName(this) +
"(O(" + ToXString(open) + "),H(" + ToXString(high) + "),C(" + ToXString(close) + "),L(" + ToXString(low) + "))";
//
return result;
}
};
//
// Models ...
//
// Model a Bar Remains Time ...
struct XBarRemainsTime
{
//
int days;
int hours;
int minutes;
int seconds;
//
// Constructor ...
XBarRemainsTime()
{
Clean();
}
//
// Always Calculate Current 0 Bar Timing ...
bool Init(
string mSymbol = NULL, // Trading Symbol
ENUM_TIMEFRAMES mPeriod = NULL // Trading Period
)
{
//
bool result = false;
//
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
//
int minuteSecoonds = 60;
int hourSeconds = minuteSecoonds * 60;
int daySeconds = 24 * hourSeconds;
//
int periodSeconds = PeriodSeconds(
mPeriod);
datetime startTime = GetBarTime(
mSymbol,
mPeriod,
0
//
);
//
int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent();
//
int mWorkingSecondsDiff = secondsDiff;
if (mWorkingSecondsDiff > daySeconds)
{
//
days = mWorkingSecondsDiff / daySeconds;
mWorkingSecondsDiff -= days * daySeconds;
}
if (mWorkingSecondsDiff > hourSeconds)
{
//
hours = mWorkingSecondsDiff / hourSeconds;
mWorkingSecondsDiff -= hours * hourSeconds;
}
if (mWorkingSecondsDiff > minuteSecoonds)
{
//
minutes = mWorkingSecondsDiff / minuteSecoonds;
mWorkingSecondsDiff -= minutes * minuteSecoonds;
}
seconds = mWorkingSecondsDiff;
//
result = true;
//
return result;
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
days = 0;
hours = 0;
minutes = 0;
seconds = 0;
//
ZeroMemory(this);
}
//
// To String Representation ...
string ToString(
string dayId = "d",
string hourId = "h",
string minuteId = "m",
string secondId = "s",
string idSeparator = ": ",
string separator = ", ",
bool ignoreZeroValues = true
//
)
{
//
string result = "";
//
// Days ...
if (!ignoreZeroValues || days > 0)
{
result += dayId + idSeparator + (string)days + separator;
}
//
// Hours ...
if (!ignoreZeroValues || hours > 0)
{
//
string strHour = ToXString(hours);
if (StringLen(strHour) == 1)
{
strHour = "0" + strHour;
}
//
result += hourId + idSeparator + strHour + separator;
}
//
// Minutes ...
if (!ignoreZeroValues || minutes > 0)
{
//
string strMinute = ToXString(minutes);
if (StringLen(strMinute) == 1)
{
strMinute = "0" + strMinute;
}
//
result += minuteId + idSeparator + strMinute + separator;
}
//
// Seconds ...
if (!ignoreZeroValues || seconds > 0)
{
//
string strSec = ToXString(seconds);
if (StringLen(strSec) == 1)
{
strSec = "0" + strSec;
}
//
result += secondId + idSeparator + strSec;
}
//
return result;
}
};
//
// Tracking Times ...
struct XTimeTracker
{
//
// Props ...
int xMonth;
int xDayOfWeek;
int xForWeekDay;
int xDay;
int xHour;
int xMinute;
//
// Constructor ...
XTimeTracker()
{
Clean();
}
//
// Tools ...
//
void Clean()
{
//
xDay = -1;
xHour = -1;
xMonth = -1;
xMinute = -1;
xDayOfWeek = -1;
xForWeekDay = -1;
//
ZeroMemory(this);
}
//
// Detecting New Minute ...
bool IsNewMinute()
{
//
bool result = false;
//
// Retrieve Current Time as Struct ...
MqlDateTime timeStruct = GetCurrentTime();
//
// Check Houre ...
result = timeStruct.min != xMinute;
if (result)
{
xMinute = timeStruct.min;
}
//
return result;
}
//
// Detecting New Houre ...
bool IsNewHour()
{
//
bool result = false;
//
// Retrieve Current Time as Struct ...
MqlDateTime timeStruct = GetCurrentTime();
//
// Check Houre ...
result = timeStruct.hour != xHour;
if (result)
{
xHour = timeStruct.hour;
}
//
return result;
}
//
// Detecting New Day ...
bool IsNewDay()
{
//
bool result = false;
//
// Retrieve Current Time as Struct ...
MqlDateTime timeStruct = GetCurrentTime();
//
// Check Houre ...
result = timeStruct.day_of_year != xDay;
if (result)
{
xDay = timeStruct.day_of_year;
}
//
return result;
}
//
// Detecting New Week ...
bool IsNewWeek()
{
//
bool result = false;
//
// Retrieve Current Time as Struct ...
MqlDateTime timeStruct = GetCurrentTime();
//
// Check Week ...
// Since Week Starts From Monday in Forex World ...
// we Calculate Start of Week by 1-Monday ...
result =
xDayOfWeek == -1 &&
xForWeekDay == -1
? true
: timeStruct.day_of_week == 1 &&
timeStruct.day_of_year > xForWeekDay;
//
xForWeekDay = timeStruct.day_of_year;
xDayOfWeek = timeStruct.day_of_week;
//
return result;
}
//
// Detecting End Of Week ...
bool IsWeekEnd()
{
//
bool result = false;
//
// Retrieve Current Time as Struct ...
MqlDateTime timeStruct = GetCurrentTime();
//
// Check WeekEnd ...
// Since Week Starts From Monday in Forex World ...
// we Calculate End of Week by 5-Friday ...
result =
xDayOfWeek != -1 &&
timeStruct.day_of_week == 5 &&
timeStruct.hour == 23 &&
timeStruct.min == 59 &&
timeStruct.sec == 59;
//
return result;
}
//
// Detecting New Month ...
bool IsNewMonth()
{
//
bool result = false;
//
// Retrieve Current Time as Struct ...
MqlDateTime timeStruct = GetCurrentTime();
//
// Check Houre ...
result = timeStruct.mon != xMonth;
if (result)
{
xMonth = timeStruct.mon;
}
//
return result;
}
};
//
// Tracking Bars on Specified Environment ...
struct XBarTracker
{
//
string symbol; // Tracking Symbol
ENUM_TIMEFRAMES period; // Tracking Time Frame
//
int lastTrackedBar; // Last Tracked Bar ...
//
bool waitsUntilNext; // Waits Until Next Bar ...
//
// Constructor ...
XBarTracker()
{
Clean();
}
//
// Initializer ...
bool Init(
string mSymbol = NULL, // Trading Symbol
ENUM_TIMEFRAMES mPeriod = NULL // Trading Period
)
{
//
bool result = false;
//
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
//
this.symbol = mSymbol;
this.period = mPeriod;
//
this.lastTrackedBar = 0;
//
result = true;
//
return result;
}
//
// Retrieve all Bars ...
int CountBars()
{
//
return iBars(
symbol,
period
//
);
}
//
// Check if it's New Bar ...
bool IsNewBar()
{
//
bool result = false;
//
int currentBars = CountBars();
//
result = currentBars > lastTrackedBar;
if (result)
{
lastTrackedBar = currentBars;
}
//
return result;
}
//
bool CanProcessBar()
{
//
bool _isInTestMode = IsRunningOnTestMode();
//
bool isNewBar = IsNewBar();
//
bool result =
_isInTestMode
? isNewBar
: !waitsUntilNext
? true
: isNewBar;
if (result && waitsUntilNext)
{
waitsUntilNext = false;
}
//
return result;
}
//
void Waits()
{
this.waitsUntilNext = true;
}
//
// Tools ...
void Clean()
{
//
symbol = NormalizeSymbol(NULL);
period = NormalizePeriod(NULL);
//
ZeroMemory(this);
}
//
bool GetBar(
XOHCL &bar,
int index = 0 //
)
{
//
bool result = false;
//
result = bar.Init(
symbol,
period,
index //
);
//
return result;
}
//
bool GetBar(
XOHCL &bar,
datetime time = NULL //
)
{
//
bool result = false;
//
NormalizeTime(time);
//
int barIndex = iBarShift(
symbol,
period,
time,
false //
);
//
result = barIndex >= 0;
if (!result)
{
return result;
}
//
result = bar.Init(
symbol,
period,
barIndex //
);
//
return result;
}
//
int Index(datetime time = NULL)
{
//
int result = 0;
//
NormalizeTime(time);
//
result = iBarShift(
symbol,
period,
time,
false //
);
//
return result;
}
};
//
// Extensions ...
//
// Extract Specific Range of Bars ...
// using Start Bar Index ...
int GetBars(
XOHCL &bars[], // Hold Result
string mSymbol = NULL, // Trading Symbol
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame
int from = 0, // Start Bar Index
int count = 1 // Number of Bars
)
{
//
int result = 0;
//
from = NormalizeInt(from);
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
//
int total = Bars(
mSymbol,
mPeriod //
);
if (from > total - 2)
{
from = total - 2;
}
//
if (count < 0)
{
count = 1;
}
//
int start = from;
int end = start + count;
if (end > total - 1)
{
end = total - 1;
}
//
Clean(bars);
//
for (int i = start; i < end; i++)
{
//
XOHCL iBar;
bool isValid = iBar.Init(
mSymbol,
mPeriod,
i //
);
//
if (isValid)
{
//
AddRef(
iBar,
bars //
);
}
}
//
result = ArraySize(bars);
//
return result;
}
//
// Extract Specific Range of Bars ...
// using Start Bar Time ...
int GetBars(
XOHCL &bars[], // Hold Result
string mSymbol = NULL, // Trading Symbol
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame
datetime from = NULL, // Start Bar Time
int count = 1 // Number of Bars
)
{
//
from = NormalizeTime(from);
mSymbol = NormalizeSymbol(mSymbol);
mPeriod = NormalizePeriod(mPeriod);
//
int barIndex = GetBarIndex(
mSymbol,
mPeriod,
from //
);
//
return GetBars(
bars,
mSymbol,
mPeriod,
barIndex,
count //
);
}
/**
* Remove Specified Item from a Collection ...
*
* @param item: Specified Item ...
* @param source: Specified Collection for Remove item from it ...
*
* @return ( bool )
*/
bool Remove(
XOHCL &item,
XOHCL &source[] //
)
{
//
bool result = false;
//
result =
item.IsValid() &&
HasChild(source);
if (!result)
{
return result;
}
//
int idx = -1;
result = FindIndex(
idx,
item,
source //
);
if (!result)
{
return result;
}
//
result = ArrayRemove(
source,
idx,
1 //
);
//
return result;
}
/**
* Remove Specified items from a Collection ...
*
* @param items: Specified Items to Remove ...
* @param sources: Sepcified Collection for Removing items from it ...
*
* @return ( int )
*/
int Removes(
XOHCL &items[],
XOHCL &sources[] //
)
{
//
int result = 0;
//
bool has = HasChild(items) &&
HasChild(sources);
if (!has)
{
return result;
}
//
int idx = -1;
has = false;
int count = ArraySize(items);
for (int i = 0; i < count; i++)
{
//
// Detect Item Index in Collection ...
has = FindIndex(
idx,
items[i],
sources //
);
if (has)
{
//
// Remove Detected Index from Collection ...
has = ArrayRemove(
sources,
idx,
1 //
);
//
if (has)
{
//
// Count Removed Items ...
result++;
}
}
}
//
return result;
}
/**
* Find Specified Item index in a Collection ...
*
* @param index: int, reference to Hold Index if Exists ...
* @param item: Specified item to Detect ...
* @param source: Collection to Search for item ...
*
* @return ( bool )
*/
bool FindIndex(
int &index,
XOHCL &item,
XOHCL &source[] //
)
{
//
bool result = false;
//
index = -1;
//
int count = ArraySize(source);
result = item.IsValid() &&
IsValidSize(count);
if (!result)
{
return result;
}
//
for (int i = 0; i < count; i++)
{
//
bool isSame = item.IsSameAs(source[i]);
if (isSame)
{
//
index = i;
break;
}
}
//
result = IsValidIndex(index);
//
return result;
}
/**
* Add Specified Item to Specified Collection, if not Exists ...
*
* @param item: Item to Add ...
* @param sources: Collection to Add item ...
* @param maxAllowed: int, Max Allowed Collection Size ...
*
* @return ( bool )
*/
bool AddIfNotExists(
XOHCL &item,
XOHCL &sources[],
int maxAllowed = 0 //
)
{
//
bool result = false;
//
// Validate Args ...
result = item.IsValid();
if (!result)
{
return result;
}
//
// Check Item Exists or not ...
int idx = -1;
bool isExists = FindIndex(
idx,
item,
sources //
);
result = !isExists;
if (!result)
{
return result;
}
//
AddRef(
item,
sources //
);
//
// Handle Cleanup Collection
// if Max Reached ...
if (result &&
maxAllowed > 0)
{
//
CleanupArray(
sources,
maxAllowed //
);
}
//
return result;
}
/**
* Get Oldest Index of Specified Collection ...
*
* @param source: Specified Collection ...
*
* @return ( int )
*/
int GetOldest(
XOHCL &source[] //
)
{
//
int result = -1;
//
int count = ArraySize(source);
if (!IsValidSize(count))
{
return result;
}
//
XOHCL selected;
for (int i = 0; i < count; i++)
{
//
bool canSet =
!selected.IsValid()
? true
: selected.time > source[i].time;
if (canSet)
{
//
result = i;
selected = source[i];
}
}
//
selected.Clean();
//
return result;
}
/**
* Get Youngest Index of Specified Collection ...
*
* @param source: Specified Collection ...
*
* @return ( int )
*/
int GetYoungest(
XOHCL &source[] //
)
{
//
int result = -1;
//
int count = ArraySize(source);
if (!IsValidSize(count))
{
return result;
}
//
XOHCL selected;
for (int i = 0; i < count; i++)
{
//
bool canSet =
!selected.IsValid()
? true
: selected.time < source[i].time;
if (canSet)
{
//
result = i;
selected = source[i];
}
}
//
selected.Clean();
//
return result;
}
/**
* Get Lowest Index of Specified Collection ...
*
* @param source: Specified Collection ...
*
* @return ( int )
*/
int GetLowest(
XOHCL &source[],
ENUM_X_PRICE _priceType = X_PRICE_LOW //
)
{
//
int result = -1;
//
if (!IsXValid(_priceType))
{
_priceType = X_PRICE_LOW;
}
//
int count = ArraySize(source);
if (!IsValidSize(count))
{
return result;
}
//
XOHCL selected;
double iPrice = EMPTY_VALUE;
double selectedPrice = EMPTY_VALUE;
for (int i = 0; i < count; i++)
{
//
iPrice = source[i].GetPrice(_priceType);
selectedPrice = selected.GetPrice(_priceType);
//
bool canSet =
!selected.IsValid()
? true
: selectedPrice > iPrice;
if (canSet)
{
//
result = i;
selected = source[i];
}
}
//
selected.Clean();
//
return result;
}
/**
* Get Highest Index of Specified Collection ...
*
* @param source: Specified Collection ...
* @param _priceType: Specified Price type ...
*
* @return ( int )
*/
int GetHighest(
XOHCL &source[],
ENUM_X_PRICE _priceType = X_PRICE_HIGH //
)
{
//
int result = -1;
//
if (!IsXValid(_priceType))
{
_priceType = X_PRICE_HIGH;
}
//
int count = ArraySize(source);
if (!IsValidSize(count))
{
return result;
}
//
XOHCL selected;
double iPrice = EMPTY_VALUE;
double selectedPrice = EMPTY_VALUE;
for (int i = 0; i < count; i++)
{
//
iPrice = source[i].GetPrice(_priceType);
selectedPrice = selected.GetPrice(_priceType);
//
bool canSet =
!selected.IsValid()
? true
: selectedPrice < iPrice;
if (canSet)
{
//
result = i;
selected = source[i];
}
}
//
selected.Clean();
//
return result;
}
/**
* Get Nearest Directional Bar ...
*
* @param bar: XOHCL, reference to Specified Start Bar ...
* @param directionalBar: XOHCL, reference to hold Detected Bar ...
* @param forDir: ENUM_X_DIRECTION, Specified Which Directional Bar looking for ...
* @param loopback: int, Loopback Length ...
*
* @return ( bool )
*/
bool GetDirectionalBar(
XOHCL &bar,
XOHCL &directionalBar,
ENUM_X_DIRECTION forDir,
int loopback = 1500 //
)
{
//
bool result = false;
//
// Prepare ...
directionalBar.Clean();
//
// Normalize ...
loopback = NormalizeInt(loopback, 1);
//
// Validate ...
result = bar.IsValid() &&
HasDirection(forDir);
if (!result)
{
return result;
}
//
int start = bar.Index() + 1;
int end = start + loopback;
for (int i = start; i < end; i++)
{
//
directionalBar.Clean();
result = bar.BarAt(i, directionalBar);
result = result &&
directionalBar.GetDirection() == forDir;
if (result)
{
break;
}
//
directionalBar.Clean();
}
//
result = directionalBar.IsValid() &&
forDir == directionalBar.GetDirection();
//
// Cleanup Resources ...
if (!result)
{
directionalBar.Clean();
}
//
return result;
}
/**
* Get Nearest Breaker Bar of Specified Bar's Price ...
*
* @param bar: XOHCL, reference to Specified Bar ...
* @param breaker: XOHCL, reference to hold Detected Breaker Bar ...
* @param priceType: ENUM_X_PRICE, which price type of Bar to Check to Break ...
* @param breakType: ENUM_X_PRICE, which price of Breaker Bar must Breke price ...
* @param breakDir: ENUM_X_DIRECTION, Specified Break Direction ...
* @param loopback: int, Max Allowed Loopback to Detect Breaker Bar ...
*
* @return ( bool )
*/
bool GetBreakerBar(
XOHCL &bar,
XOHCL &breaker,
ENUM_X_PRICE priceType,
ENUM_X_PRICE breakType,
ENUM_X_DIRECTION breakDir,
int loopback = 1500 //
)
{
//
// PriceType: which Applied Price of Specified Bar must to Check for Break ...
//
// BreakType: which Applied Price of breakerBar must Break price ...
//
// BreakDir:
// -----------
// Bullish: Price Must Break Applied Price from Down to Top ...
// Bearish: Price must Break Applied Price from Top to Down ...
//
bool result = false;
//
// Prepare ...
breaker.Clean();
//
// Normalize ...
loopback = NormalizeInt(loopback, 1);
//
// Validate ...
result = bar.IsValid() &&
IsXValid(priceType) &&
IsXValid(breakType) &&
HasDirection(breakDir);
if (!result)
{
return result;
}
//
double iPrice = EMPTY_VALUE;
bool isBullish = IsXBullish(breakDir);
double price = bar.GetPrice(priceType);
//
int start = bar.Index();
int end = start + loopback;
for (int i = start; i < end; i++)
{
//
breaker.Clean();
iPrice = EMPTY_VALUE;
//
// Initialize Indexed Bar ...
result = bar.BarAt(i, breaker);
if (!result)
{
breaker.Clean();
break;
}
//
// Check Breake ...
iPrice = breaker.GetPrice(breakType);
result =
isBullish
? iPrice > price
: iPrice < price;
if (result)
{
break;
}
}
//
result = breaker.IsValid();
//
// Cleanup Resources ...
if (!result)
{
breaker.Clean();
}
//
return result;
}
//