1718 lines
35 KiB
Plaintext
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);
|
|
}
|
|
};
|
|
|
|
// |