Files
MQL5Data/Libraries/x-saherelm.tools.mq5
T
2024-07-12 23:58:17 +03:30

1718 lines
35 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Tools Library
// --------------------------------------
// Name: XToolsLib
// Description: provide all commonly used Tools ...
//
//
// 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 "../Libraries/x-saherelm.draw.lib.mq5"
#include "../Libraries/x-saherelm.common.lib.mq5"
//
// Definitions ...
//
// Detect Trends ...
struct XTrendDetector
{
//
string symbol;
ENUM_TIMEFRAMES period;
//
double higherHighs[];
datetime higherHighTimes[];
//
double higherLows[];
datetime higherLowTimes[];
//
double lowerHighs[];
datetime lowerHighTimes[];
//
double lowerLows[];
datetime lowerLowTimes[];
//
bool isFirstLow;
//
bool isUpTrend;
bool isDownTrend;
//
int _numberOfPivots;
int _pivotShoulders;
//
// Constructor ...
XTrendDetector()
{
Clean();
}
//
bool FindTrend(
string _symbol,
ENUM_TIMEFRAMES _period,
int barIndex = 0,
int _requiredPivots = 3,
int _requiredShoulders = 3 //
)
{
//
bool result = false;
//
Clean();
//
if (barIndex < 0)
{
barIndex = 0;
}
//
if (_requiredPivots < 3)
{
_requiredPivots = 3;
}
//
if (_requiredShoulders < 3)
{
_requiredShoulders = 3;
}
//
result =
//
IsValid(_symbol) &&
IsValid(_period)
//
;
if (!result)
{
Clean();
return result;
}
//
// Find Swing Lows and Swing Highs ...
//
int hhIndexes[];
datetime hhTimes[];
double hhs[];
//
int llIndexes[];
datetime llTimes[];
double lls[];
//
bool isEnough = false;
//
int lastHHIndex = barIndex;
int lastLLIndex = barIndex;
while (!isEnough)
{
//
int hhSize = ArraySize(hhs);
if (hhSize < _requiredPivots)
{
//
lastHHIndex = FindSwing(
_symbol,
_period,
X_SWING_HIGH,
_requiredShoulders,
lastHHIndex + 1 //
);
if (lastHHIndex >= 0)
{
//
XOHCL hBar;
bool isInited = hBar.Init(
_symbol,
_period,
lastHHIndex //
);
if (isInited)
{
//
Add(
hBar.high,
hhs //
);
//
Add(
hBar.time,
hhTimes //
);
//
Add(
lastHHIndex,
hhIndexes //
);
}
}
}
//
int llSize = ArraySize(lls);
if (llSize < _requiredPivots)
{
//
lastLLIndex = FindSwing(
_symbol,
_period,
X_SWING_LOW,
_requiredShoulders,
lastLLIndex + 1 //
);
if (lastLLIndex >= 0)
{
//
XOHCL lBar;
bool isInited = lBar.Init(
_symbol,
_period,
lastLLIndex //
);
if (isInited)
{
//
Add(
lBar.low,
lls //
);
//
Add(
lBar.time,
llTimes //
);
//
Add(
lastHHIndex,
llIndexes //
);
}
}
}
//
hhSize = ArraySize(hhs);
llSize = ArraySize(lls);
isEnough =
//
hhSize == _requiredPivots &&
llSize == _requiredPivots
//
;
}
//
// Draws ...
// for (int i = 0; i < ArraySize(hhs); i++)
// {
// //
// DrawArrow(
// ChartID(),
// "XTRND_HH" + ToString(i),
// 0,
// hhTimes[i],
// hhs[i],
// 234,
// ANCHOR_BOTTOM,
// clrMagenta,
// STYLE_SOLID,
// 3 //
// );
// //
// DrawArrow(
// ChartID(),
// "XTRND_LL" + ToString(i),
// 0,
// llTimes[i],
// lls[i],
// 233,
// ANCHOR_TOP,
// clrAqua,
// STYLE_SOLID,
// 3 //
// );
// }
//
isUpTrend =
//
isFirstLow
?
//
lls[0] > lls[1] &&
lls[1] > lls[2] &&
//
hhs[0] > hhs[1] &&
hhs[1] > hhs[2]
//
:
//
hhs[0] > hhs[1] &&
hhs[1] > hhs[2] &&
//
lls[0] > lls[1] &&
lls[1] > lls[2]
//
;
isDownTrend =
//
isFirstLow
?
//
lls[0] < lls[1] &&
lls[1] < lls[2] &&
//
hhs[0] < hhs[1] &&
hhs[1] < hhs[2]
//
:
//
hhs[0] < hhs[1] &&
hhs[1] < hhs[2] &&
//
lls[0] < lls[1] &&
lls[1] < lls[2]
//
;
for (int i = 1; i < _requiredPivots; i++)
{
//
// Lows ...
//
// Lower Lows ...
if (lls[i - 1] < lls[i])
{
//
Add(
lls[i - 1],
lowerLows //
);
//
Add(
llTimes[i - 1],
lowerLowTimes //
);
}
else
//
// Higher Lows ...
if (lls[i - 1] > lls[i])
{
//
Add(
lls[i - 1],
higherLows //
);
//
Add(
llTimes[i - 1],
higherLowTimes //
);
}
//
// Highs ...
//
// Higher Highs ...
if (hhs[i - 1] > hhs[i])
{
//
Add(
hhs[i - 1],
higherHighs //
);
//
Add(
hhTimes[i - 1],
higherHighTimes //
);
}
else
//
// Lower Highs ...
if (hhs[i - 1] < hhs[i])
{
//
Add(
hhs[i - 1],
lowerHighs //
);
//
Add(
hhTimes[i - 1],
lowerHighTimes //
);
}
}
//
// Remove Draws ...
// RemoveDraws("XTRND");
//
result = isUpTrend || isDownTrend;
if (!result)
{
Clean();
}
//
symbol = _symbol;
period = _period;
_numberOfPivots = _requiredPivots;
_pivotShoulders = _requiredShoulders;
//
result = IsValid();
if (!result)
{
Clean();
}
//
return result;
}
//
bool HasTrend()
{
//
bool result = isUpTrend || isDownTrend;
//
return result;
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
symbol = NULL;
period = NULL;
//
isUpTrend = false;
isFirstLow = false;
isDownTrend = false;
//
_numberOfPivots = 0;
_pivotShoulders = 0;
//
Clean(higherHighs);
Clean(higherHighTimes);
//
Clean(higherLows);
Clean(higherLowTimes);
//
Clean(lowerHighs);
Clean(lowerHighTimes);
//
Clean(lowerLows);
Clean(lowerLowTimes);
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result =
//
IsValid(symbol) &&
IsValid(period)
//
;
//
return result;
}
};
//
// a Pivot Point ...
struct XPivot
{
//
string symbol; // Trading Symbol ...
ENUM_TIMEFRAMES period; // Trading TimeFrame ...
//
double price; // Price ...
datetime time; // Time ...
//
int breakedAsSupport; // Number of Breaked As Support ...
int rejectedAsSupport; // Number of Rejected As Support ...
//
int breakedAsResistance; // Number of Breaked As Resistance ...
int rejectedAsResistance; // Number of Rejected As Resistance ...
//
bool isSupport;
int supportLength;
datetime supportTime;
//
bool isResistance;
int resistanceLength;
datetime resistanceTime;
//
double _threshold; // threshold in Point ...
int _lastCalculatedBar; // last calculated bars ...
int _loopbackForSupportAndResistance; // Number of LoopBacks for Support or Resistance ...
//
// Constructor ...
XPivot()
{
Clean();
}
//
// Find Last Support for Market and
// Initialize Pivot Based On it ...
bool FindLastSupport(
string _symbol,
ENUM_TIMEFRAMES _period,
int barIndex = 0,
int _supResVerificationsStep = 21,
double __threshold = 5 //
)
{
//
bool result = false;
//
Clean();
//
if (barIndex < 0)
{
barIndex = 0;
}
//
if (__threshold < 0)
{
__threshold = 0;
}
//
if (_supResVerificationsStep < 0)
{
_supResVerificationsStep = 21;
}
//
result =
//
IsValid(_symbol) &&
IsValid(_period) &&
IsValidSize(_supResVerificationsStep)
//
;
if (!result)
{
//
Clean();
return result;
}
//
// Find Resistance ...
//
// Retrieve Current Bar ...
XOHCL cBar;
result = cBar.Init(
_symbol,
_period,
barIndex //
);
if (!result)
{
//
Clean();
return result;
}
//
// Calculate Available Bars ...
//
int bars = iBars(
_symbol,
_period //
);
int maxAllowedBars = bars / 10;
int currentLength = _supResVerificationsStep;
//
// Find Highest High ...
for (int i = barIndex; i < maxAllowedBars; i++)
{
//
// Validate and Regenrate Current Length ...
if (i > 1)
{
//
currentLength = _supResVerificationsStep * i;
//
if (currentLength > maxAllowedBars)
{
currentLength = maxAllowedBars;
}
}
//
// Clean ...
Clean();
//
int llIndex = cBar.FindLowestIndex(
currentLength,
MODE_LOW //
);
XOHCL llBar;
result = llBar.Init(
_Symbol,
_Period,
llIndex //
);
if (!result)
{
continue;
}
//
symbol = _symbol;
period = _period;
price = llBar.low;
//
_threshold = __threshold;
_loopbackForSupportAndResistance = _supResVerificationsStep;
//
Calculate(
barIndex //
);
//
result = isSupport;
if (result)
{
//
supportTime = llBar.time;
supportLength = currentLength;
break;
}
}
//
result = IsValid() && isSupport;
if (!result)
{
Clean();
}
//
return result;
}
//
// Find Last Resistance for Market and
// Initialized Pivot Based On it ...
bool FindLastResistance(
string _symbol,
ENUM_TIMEFRAMES _period,
int barIndex = 0,
int _supResVerificationsStep = 21,
double __threshold = 5 //
)
{
//
bool result = false;
//
Clean();
//
if (barIndex < 0)
{
barIndex = 0;
}
//
if (__threshold < 0)
{
__threshold = 0;
}
//
if (_supResVerificationsStep < 0)
{
_supResVerificationsStep = 21;
}
//
result =
//
IsValid(_symbol) &&
IsValid(_period) &&
IsValidSize(_supResVerificationsStep)
//
;
if (!result)
{
//
Clean();
return result;
}
//
// Find Resistance ...
//
// Retrieve Current Bar ...
XOHCL cBar;
result = cBar.Init(
_symbol,
_period,
barIndex //
);
if (!result)
{
//
Clean();
return result;
}
//
// Calculate Available Bars ...
//
int bars = iBars(
_symbol,
_period //
);
int maxAllowedBars = bars / 10;
int currentLength = _supResVerificationsStep;
//
// Find Highest High ...
for (int i = barIndex; i < maxAllowedBars; i++)
{
//
// Validate and Regenrate Current Length ...
if (i > 1)
{
//
currentLength = _supResVerificationsStep * i;
//
if (currentLength > maxAllowedBars)
{
currentLength = maxAllowedBars;
}
}
//
// Clean ...
Clean();
//
int hhIndex = cBar.FindHighestIndex(
currentLength,
MODE_HIGH //
);
XOHCL hhBar;
result = hhBar.Init(
_Symbol,
_Period,
hhIndex //
);
if (!result)
{
continue;
}
//
symbol = _symbol;
period = _period;
price = hhBar.high;
//
_threshold = __threshold;
_loopbackForSupportAndResistance = _supResVerificationsStep;
//
Calculate(
barIndex //
);
//
result = isResistance;
if (result)
{
//
resistanceTime = hhBar.time;
resistanceLength = currentLength;
break;
}
}
//
result = IsValid() && isResistance;
if (!result)
{
Clean();
}
//
return result;
}
//
// Check Rejection Based On Pivot Type ...
bool IsRejected()
{
//
bool result = false;
//
result =
//
IsValid() &&
(
//
isSupport ||
isResistance
//
)
//
;
if (!result)
{
return result;
}
//
result =
//
isSupport
? IsSupportRejected()
: IsResistanceRejected()
//
;
//
return result;
}
//
// Check Breake Based On Pivot Type ...
bool IsBreaked()
{
//
bool result = false;
//
result =
//
IsValid() &&
(
//
isSupport ||
isResistance
//
)
//
;
if (!result)
{
return result;
}
//
result =
//
isSupport
? IsSupportBreaked()
: IsResistanceBreaked()
//
;
//
return result;
}
//
// Tools ...
//
// Check Support Rejected ...
bool IsSupportRejected(
int barIndex = 0 //
)
{
//
bool result = false;
//
if (barIndex < 0)
{
barIndex = 0;
}
//
result = isSupport;
if (!result)
{
return result;
}
//
// Initialize Required Bars ...
//
XOHCL cBar;
result = cBar.Init(
symbol,
period,
1 //
);
if (!result)
{
return result;
}
//
XOHCL pBar;
result = pBar.Init(
symbol,
period,
2 //
);
if (!result)
{
return result;
}
//
double threshold = GetPoints(symbol) * _threshold;
//
result =
//
// Check Support Touch or Fake Break ...
pBar.low < price &&
(
//
pBar.low < price ||
pBar.low < price - threshold
//
)
//
&&
//
// Check Rejection ...
cBar.low > price &&
(
//
cBar.low > price ||
cBar.low > price + threshold
//
)
//
&&
//
// Check Rejection Must be Bullish ...
cBar.IsBullish()
//
;
//
return result;
}
//
// Check Support Breaked ...
bool IsSupportBreaked(
int barIndex = 0 //
)
{
//
bool result = false;
//
if (barIndex < 0)
{
barIndex = 0;
}
//
result = isSupport;
if (!result)
{
return result;
}
//
// Initialize Required Bars ...
//
XOHCL cBar;
result = cBar.Init(
symbol,
period,
barIndex + 1 //
);
if (!result)
{
return result;
}
//
XOHCL pBar;
result = pBar.Init(
symbol,
period,
barIndex + 2 //
);
if (!result)
{
return result;
}
//
double threshold = GetPoints(symbol) * _threshold;
//
result =
//
// Check Support Breaks ...
pBar.close < price &&
(
//
pBar.close < price - threshold ||
pBar.low < price - threshold
//
)
//
&&
//
// Check 50% ...
(
//
(price - pBar.close) > (pBar.GetBody() / 100) * 50 ||
(price - cBar.close) > (cBar.GetBody() / 100) * 50
//
)
//
&&
//
// Also Next Bar must Closed Below Support ...
cBar.high < price &&
cBar.high < price - threshold
//
&&
//
cBar.close < price &&
cBar.close < price - threshold
//
&&
//
cBar.IsBearish()
//
;
if (result)
{
// DrawArrow(
// 0,
// "PBar",
// 0,
// pBar.time,
// pBar.low,
// 233,
// ANCHOR_TOP,
// clrYellow //
// );
}
//
return result;
}
//
// Check Resistance Rejected ...
bool IsResistanceRejected(
int barIndex = 0 //
)
{
//
bool result = false;
//
if (barIndex < 0)
{
barIndex = 0;
}
//
result = isResistance;
if (!result)
{
return result;
}
//
// Initialize Required Bars ...
//
XOHCL cBar;
result = cBar.Init(
symbol,
period,
1 //
);
if (!result)
{
return result;
}
//
XOHCL pBar;
result = pBar.Init(
symbol,
period,
2 //
);
if (!result)
{
return result;
}
//
double threshold = GetPoints(symbol) * _threshold;
//
result =
//
// Check Resistance Touch or Fake Break ...
pBar.high > price &&
(
//
pBar.high > price ||
pBar.high > price + threshold
//
)
//
&&
//
// Check Rejection ...
cBar.high < price &&
(
//
cBar.high < price ||
cBar.high < price - threshold
//
)
//
&&
//
// Check Rejection Must be Bearish ...
cBar.IsBearish()
//
;
//
return result;
}
//
// Check Resistance Breaked ...
bool IsResistanceBreaked(
int barIndex = 0 //
)
{
//
bool result = false;
//
if (barIndex < 0)
{
barIndex = 0;
}
//
result = isResistance;
if (!result)
{
return result;
}
//
// Initialize Required Bars ...
//
XOHCL cBar;
result = cBar.Init(
symbol,
period,
1 //
);
if (!result)
{
return result;
}
//
XOHCL pBar;
result = pBar.Init(
symbol,
period,
2 //
);
if (!result)
{
return result;
}
//
double threshold = GetPoints(symbol) * _threshold;
//
result =
//
// Check Resistance Breaks ...
pBar.close > price &&
(
//
pBar.close > price + threshold ||
pBar.high > price + threshold
//
)
//
&&
//
// Check 50% ...
(
//
(pBar.close - price) > (pBar.GetBody() / 100) * 50 ||
(cBar.close - price) > (cBar.GetBody() / 100) * 50
//
)
//
&&
//
// Also Next Bar Must Closed Above Resistance ...
cBar.low > price &&
cBar.low > price + threshold
//
&&
//
cBar.close > price &&
cBar.close > price + threshold
//
&&
//
cBar.IsBullish()
//
;
//
return result;
}
//
// Cleanup ...
void Clean()
{
//
time = NULL;
symbol = NULL;
period = NULL;
supportTime = NULL;
resistanceTime = NULL;
//
price = 0;
//
supportLength = 0;
resistanceLength = 0;
breakedAsSupport = 0;
rejectedAsSupport = 0;
breakedAsResistance = 0;
rejectedAsResistance = 0;
//
_lastCalculatedBar = -1;
//
isSupport = false;
isResistance = false;
//
_objName = NULL;
}
//
// Validate Model ...
bool IsValid()
{
//
bool result = false;
//
result =
//
IsValid(symbol) &&
IsValid(period) &&
price > 0
//
;
//
return result;
}
//
// Calculate Required Data ...
void Calculate(
int barIndex,
int loopback = 288 //
)
{
//
if (isSupport || isResistance)
{
return;
}
//
int bars = iBars(
symbol,
period //
);
//
loopback += barIndex;
//
// Normalizing Loopback ...
if (loopback > bars)
{
loopback = bars - 2 - _loopbackForSupportAndResistance;
}
//
// Check Previous Calculation ...
if (bars == _lastCalculatedBar)
{
return;
}
//
_lastCalculatedBar = bars;
//
// First Get Current State of Pivot ...
// Means Use Zero Index ...
XOHCL pBar;
bool isInited = pBar.Init(
symbol,
period,
barIndex + 1 //
);
if (!isInited)
{
return;
}
//
// Retrieve Highest High and Lowest Low of SupRes Loopback ...
double hhValue = pBar
.FindHighest(
_loopbackForSupportAndResistance,
MODE_HIGH //
);
//
double llValue = pBar
.FindLowest(
_loopbackForSupportAndResistance,
MODE_LOW //
);
//
isSupport = llValue > price;
isResistance = hhValue < price;
//
// Prevent Moving Forward if it isn't Support or Resistance ...
if (!isSupport && !isResistance)
{
return;
}
//
time = TimeCurrent();
//
for (int i = 2; i < loopback; i++)
{
//
XOHCL iBar;
isInited = iBar.Init(
symbol,
period,
i //
);
if (!isInited)
{
continue;
}
//
XOHCL iPBar;
isInited = iPBar.Init(
symbol,
period,
i + 1 //
);
if (!isInited)
{
continue;
}
//
XOHCL iPPBar;
isInited = iPPBar.Init(
symbol,
period,
i + 2 //
);
if (!isInited)
{
continue;
}
//
bool isBreaked = false;
bool isRejected = false;
//
if (isSupport)
{
//
// Count Support Rejects
// and Support Breaks ...
//
// Support Rejected ...
isRejected =
//
// Check Support Touch or Fake Break ...
iPBar.low < price
//
&&
//
// Check Rejection ...
iBar.low > price
//
;
if (isRejected)
{
rejectedAsSupport++;
}
//
// Support Breaked ...
isBreaked =
//
// Check Support Breaks ...
iPBar.close < price
//
&&
//
// Check 50% ...
(price - iPBar.close) > (iPBar.GetBody() / 100) * 50
//
&&
//
// Also Next Bar must Closed Below Support ...
iBar.high < price
//
&&
//
iBar.close < price
//
&&
//
iBar.IsBullish()
//
;
if (isBreaked)
{
breakedAsSupport++;
}
}
else if (isResistance)
{
//
// Count Resistance Reject
// or Resistance Breaks ...
//
// Resistance Rejected ...
isRejected =
//
// Check Resistance Touch or Fake Break ...
iPBar.high > price
//
&&
//
// Check Rejection ...
iBar.high < price
//
;
if (isRejected)
{
rejectedAsResistance++;
}
//
// Resistance Breaked ...
isBreaked =
//
// Check Resistance Breaks ...
iPBar.close > price
//
&&
//
// Check 50% ...
(iPBar.close - price) > (iPBar.GetBody() / 100) * 50
//
&&
//
// Also Next Bar Must Closed Above Resistance ...
iBar.low > price
//
&&
//
iBar.close > price
//
&&
//
iBar.IsBullish()
//
;
if (isBreaked)
{
breakedAsResistance++;
}
}
}
}
//
string GetTag()
{
return "XPivot";
}
//
// Draw Functions ...
//
// Last Draw Object Name ...
string _objName;
//
// Draw ...
bool Draw(
long _chartId,
string _prefix = "",
color _color = clrYellow,
color _thresholdColor = clrAqua,
ENUM_LINE_STYLE _style = STYLE_DOT,
bool _ray = true,
int _width = 1,
int _subWindow = 0,
bool forcePrefix = false //
)
{
//
bool result = false;
//
if (!isSupport && !isResistance)
{
return result;
}
//
_objName = (IsValid(_prefix) && forcePrefix)
? _prefix
: GetTag() + "_" + (IsValid(_prefix) ? _prefix + "_" : "") + ToString(NormalizeDouble(price, 2));
//
int timeBarIndex = iBarShift(
symbol,
period,
time,
false //
);
datetime time1 =
//
isSupport
? supportTime
: resistanceTime
//
;
//
result = DrawTrendLine(
_chartId,
_objName,
_subWindow,
time1,
price,
time,
price,
_color,
_style,
_width,
false,
false,
_ray //
);
//
if (result && _threshold > 0)
{
//
// Calculate Threshodl Value ...
double diff = GetPoints(symbol) * _threshold;
//
// Up Threshold ...
result = DrawTrendLine(
_chartId,
_objName + "_UPTRSH",
_subWindow,
time1,
price + diff,
time,
price + diff,
_thresholdColor,
_style,
_width,
false,
false,
_ray //
);
//
if (result)
{
//
// Down Threshold ...
result = DrawTrendLine(
_chartId,
_objName + "_DOWNTRSH",
_subWindow,
time1,
price - diff,
time,
price - diff,
_thresholdColor,
_style,
_width,
false,
false,
_ray //
);
}
}
//
return result;
}
//
// Remove Draw ...
void Remove()
{
//
if (!IsValid(_objName))
{
return;
}
//
RemoveDraws(_objName);
}
};
//