1710 lines
36 KiB
Plaintext
1710 lines
36 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class
|
|
// -------------------------------------------------
|
|
// Name: XCX121XKIPoiDetector ...
|
|
// Description: X121XKI POI Detector Class ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property description "SaherElm X121XKI POI Detector Class"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../../Classes/x-saherelm.base.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-market.pattern.class.mq5"
|
|
#include "../../Helpers/x-saherelm.x121.xki.helper.mq5"
|
|
#include "../Classes/x-saherelm.x121.xki.parser.class.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Implementation ...
|
|
class XCX121XKIPOIDetector : public XCMarketPatternDetector
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
XCBarAnalyser *barAnalyser; // Bar Analyser ...
|
|
XCX121XKIHelper *kiHelper; // X121XKI Helper ...
|
|
XCX121XKIHelperParser *kiParser; // X121XKI Helper Parser ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XCX121XKIPOIDetector(
|
|
XCX121XKIHelper *_kiHelper,
|
|
XCX121XKIHelperParser *_kiParser //
|
|
) : XCMarketPatternDetector()
|
|
{
|
|
//
|
|
barAnalyser = new XCBarAnalyser();
|
|
kiHelper = _kiHelper;
|
|
kiParser = _kiParser;
|
|
|
|
//
|
|
symbol = kiHelper.GetSymbol();
|
|
period = kiHelper.GetPeriod();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCX121XKIPOIDetector()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
//
|
|
// Actions and Tools ...
|
|
|
|
// #region POI Detectors ...
|
|
bool NearestKIFastBullish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKIFastBullish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKIFastBearish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKIFastBearish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKIFastSwitchedToBullish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKIFastSwitchedToBullish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKIFastSwitchedToBearish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKIFastSwitchedToBearish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKISlowBullish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKISlowBullish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKISlowBearish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKISlowBearish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKISlowSwitchedToBullish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKISlowSwitchedToBullish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool NearestKISlowSwitchedToBearish(
|
|
int &index,
|
|
int barIndex = 0,
|
|
int loopback = 50 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Loop Back ...
|
|
bool isPassed = false;
|
|
for (int i = barIndex; i < barIndex + loopback; i++)
|
|
{
|
|
//
|
|
isPassed = kiParser.IsKISlowSwitchedToBearish(i);
|
|
if (isPassed)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
// #endregion
|
|
|
|
// #region Detectors ...
|
|
bool IsPOI(
|
|
ENUM_X_DIRECTION &forDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
forDir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
bool isBullish = IsBullishPOI(barIndex);
|
|
bool isBearish = IsBearishPOI(barIndex);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(forDir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBullishPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendBullish(barIndex) &&
|
|
kiParser.IsRSIBullish(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsPinnedBar(bar, dir) &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBearishPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendBearish(barIndex) &&
|
|
kiParser.IsRSIBearish(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsPinnedBar(bar, dir) &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBreakoutPOI(
|
|
ENUM_X_DIRECTION &forDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
forDir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
bool isBullish = IsBullishBreakoutPOI(barIndex);
|
|
bool isBearish = IsBearishBreakoutPOI(barIndex);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(forDir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBullishBreakoutPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsBullishBreakout(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsMomentumBar(bar, dir) &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBearishBreakoutPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsBearishBreakout(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsMomentumBar(bar, dir) &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsReversalPOI(
|
|
ENUM_X_DIRECTION &forDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
forDir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
bool isBullish = IsBullishReversalPOI(barIndex);
|
|
bool isBearish = IsBearishReversalPOI(barIndex);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(forDir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBullishReversalPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsBullishReversal(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsStarPattern(bar, dir) &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBearishReversalPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsBearishReversal(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsStarPattern(bar, dir) &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsContinuationPOI(
|
|
ENUM_X_DIRECTION &forDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
forDir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
bool isBullish = IsBullishContinuationPOI(barIndex);
|
|
bool isBearish = IsBearishContinuationPOI(barIndex);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(forDir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBullishContinuationPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendStrongBullish(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL swingBar;
|
|
result = result &&
|
|
IsFlagPattern(bar, dir, swingBar) &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
swingBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBearishContinuationPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendStrongBearish(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL swingBar;
|
|
result = result &&
|
|
IsFlagPattern(bar, dir, swingBar) &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
swingBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsExhaustionPOI(
|
|
ENUM_X_DIRECTION &forDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
forDir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
bool isBullish = IsBullishExhaustionPOI(barIndex);
|
|
bool isBearish = IsBearishExhaustionPOI(barIndex);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(forDir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBullishExhaustionPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendStrongBullish(barIndex) &&
|
|
kiParser.IsRSIOverbought(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsPiercingPattern(bar, dir) &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBearishExhaustionPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendStrongBearish(barIndex) &&
|
|
kiParser.IsRSIOversold(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsPiercingPattern(bar, dir) &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsTrendExhaustedPOI(
|
|
ENUM_X_DIRECTION &forDir,
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize ...
|
|
forDir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
bool isBullish = IsBullishTrendExhaustedPOI(barIndex);
|
|
bool isBearish = IsBearishTrendExhaustedPOI(barIndex);
|
|
result = isBullish || isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(forDir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBullishTrendExhaustedPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendStrongBullish(barIndex) &&
|
|
kiParser.IsVolatilityLow(barIndex) &&
|
|
kiParser.IsRSIOverbought(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsPiercingPattern(bar, dir) &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool IsBearishTrendExhaustedPOI(int barIndex = 0)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
result = kiParser.IsTrendStrongBearish(barIndex) &&
|
|
kiParser.IsVolatilityLow(barIndex) &&
|
|
kiParser.IsRSIOversold(barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add candlestick confirmation ...
|
|
XOHCL bar;
|
|
ENUM_X_DIRECTION dir;
|
|
result = result &&
|
|
bar.Init(symbol, period, barIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = result &&
|
|
IsPiercingPattern(bar, dir) &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
// #endregion
|
|
|
|
// #region XDetectors ...
|
|
bool IsKISignal(
|
|
ENUM_X_DIRECTION &dir, //
|
|
int barIndex = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
// Retrieve KI State ...
|
|
bool isBullish = kiParser.IsKIFastSwitchedToBullish(barIndex + 1) &&
|
|
kiParser.IsKIFastBullish(barIndex) &&
|
|
kiParser.IsKISlowBullish(barIndex);
|
|
bool isBearish = kiParser.IsKIFastSwitchedToBearish(barIndex + 1) &&
|
|
kiParser.IsKIFastBearish(barIndex) &&
|
|
kiParser.IsKISlowBearish(barIndex);
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: isBearish
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
result = HasDirection(dir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = bar.Init(symbol, period, barIndex + 1);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Bar Direction Same as Dir ...
|
|
|
|
//
|
|
// Price Place Check ...
|
|
double kiFast = kiHelper.GetKIFast(barIndex + 1);
|
|
double kiSlow = kiHelper.GetKISlow(barIndex + 1);
|
|
isBullish =
|
|
isBullish &&
|
|
bar.close > kiFast &&
|
|
kiFast > kiSlow &&
|
|
(kiParser.IsKIFastOverLast(barIndex + 1) ||
|
|
kiParser.IsKISlowOverLast(barIndex + 1));
|
|
isBearish =
|
|
isBearish &&
|
|
bar.close < kiFast &&
|
|
kiFast < kiSlow &&
|
|
(kiParser.IsKIFastUnderLast(barIndex + 1) ||
|
|
kiParser.IsKISlowUnderLast(barIndex + 1));
|
|
|
|
//
|
|
result =
|
|
result &&
|
|
(isBullish ||
|
|
isBearish);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
// #endregion
|
|
|
|
// #region Zone Detectors ...
|
|
int DetectSupports(
|
|
XBoxZone &zones[],
|
|
int barIndex,
|
|
int loopback = 50,
|
|
bool forceValidation = true,
|
|
int validationLength = 7,
|
|
string forSymbol = NULL,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XClean(zones);
|
|
|
|
//
|
|
// Normalize ...
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsXValid(forSymbol))
|
|
{
|
|
forSymbol = symbol;
|
|
}
|
|
|
|
//
|
|
if (!IsXValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
if (loopback < 2)
|
|
{
|
|
loopback = 2;
|
|
}
|
|
|
|
//
|
|
if (validationLength < 2)
|
|
{
|
|
validationLength = 2;
|
|
}
|
|
|
|
//
|
|
// Preparing Loops ...
|
|
XOHCL tmpBar;
|
|
bool has = false;
|
|
double upper = 0;
|
|
double lower = 0;
|
|
XBoxZone tmpZone;
|
|
string type = NULL;
|
|
double tmpValue = 0;
|
|
datetime from = NULL;
|
|
int start = barIndex;
|
|
int end = barIndex + loopback;
|
|
datetime to = GetBarTime(forSymbol, forPeriod, barIndex);
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
// Initialize Bar ...
|
|
if (tmpBar.Init(forSymbol, forPeriod, i))
|
|
{
|
|
//
|
|
// Check Has Shadow ...
|
|
has = tmpBar.GetHighShadow() > 0 ||
|
|
tmpBar.GetLowShadow() > 0;
|
|
if (has)
|
|
{
|
|
//
|
|
// Check Support or Resistance ...
|
|
|
|
//
|
|
// Support ...
|
|
tmpValue = tmpBar.FindLowest(validationLength, MODE_LOW);
|
|
has = NotEmptyZero(tmpValue) &&
|
|
tmpValue == tmpBar.low;
|
|
if (has)
|
|
{
|
|
//
|
|
tmpZone.Clean();
|
|
lower = tmpValue;
|
|
from = tmpBar.time;
|
|
upper = tmpBar.GetDown();
|
|
type = ToXString(X_BAR_PATTERN_SUPPORT);
|
|
has = tmpZone.Init(
|
|
forSymbol,
|
|
forPeriod,
|
|
upper,
|
|
lower,
|
|
from,
|
|
to,
|
|
X_DIRECTION_BULLISH,
|
|
type //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
tmpZone,
|
|
zones //
|
|
);
|
|
|
|
//
|
|
tmpZone.Clean();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
if (HasChild(zones) && forceValidation)
|
|
{
|
|
ValidateZones(zones, barIndex);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(zones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
int DetectResistances(
|
|
XBoxZone &zones[],
|
|
int barIndex,
|
|
int loopback = 50,
|
|
bool forceValidation = true,
|
|
int validationLength = 7,
|
|
string forSymbol = NULL,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XClean(zones);
|
|
|
|
//
|
|
// Normalize ...
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsXValid(forSymbol))
|
|
{
|
|
forSymbol = symbol;
|
|
}
|
|
|
|
//
|
|
if (!IsXValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
if (loopback < 2)
|
|
{
|
|
loopback = 2;
|
|
}
|
|
|
|
//
|
|
if (validationLength < 2)
|
|
{
|
|
validationLength = 2;
|
|
}
|
|
|
|
//
|
|
// Preparing Loops ...
|
|
XOHCL tmpBar;
|
|
bool has = false;
|
|
double upper = 0;
|
|
double lower = 0;
|
|
XBoxZone tmpZone;
|
|
string type = NULL;
|
|
double tmpValue = 0;
|
|
datetime from = NULL;
|
|
int start = barIndex;
|
|
int end = barIndex + loopback;
|
|
datetime to = GetBarTime(forSymbol, forPeriod, barIndex);
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
// Initialize Bar ...
|
|
if (tmpBar.Init(forSymbol, forPeriod, i))
|
|
{
|
|
//
|
|
// Check Has Shadow ...
|
|
has = tmpBar.GetHighShadow() > 0 ||
|
|
tmpBar.GetLowShadow() > 0;
|
|
if (has)
|
|
{
|
|
//
|
|
// Check Support or Resistance ...
|
|
|
|
//
|
|
// Resistance ...
|
|
tmpValue = tmpBar.FindHighest(validationLength, MODE_HIGH);
|
|
has = NotEmptyZero(tmpValue) &&
|
|
tmpValue == tmpBar.high;
|
|
if (has)
|
|
{
|
|
//
|
|
tmpZone.Clean();
|
|
upper = tmpValue;
|
|
from = tmpBar.time;
|
|
lower = tmpBar.GetUp();
|
|
type = ToXString(X_BAR_PATTERN_RESISTANCE);
|
|
has = tmpZone.Init(
|
|
forSymbol,
|
|
forPeriod,
|
|
upper,
|
|
lower,
|
|
from,
|
|
to,
|
|
X_DIRECTION_BEARISH,
|
|
type //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(
|
|
tmpZone,
|
|
zones //
|
|
);
|
|
|
|
//
|
|
tmpZone.Clean();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
if (HasChild(zones) && forceValidation)
|
|
{
|
|
ValidateZones(zones, barIndex);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(zones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
void ValidateZones(
|
|
XBoxZone &zones[],
|
|
int barIndex = 0,
|
|
ENUM_X_BOUNDARY_PRICE forPriceType = X_BOUNDARY_PRICE_UP_DOWN //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
|
|
//
|
|
has = HasChild(zones) &&
|
|
IsXValid(forPriceType);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XOHCL tmpBar;
|
|
XBoxZone tmp;
|
|
XBoxZone tmps[];
|
|
double tmpValue = 0;
|
|
for (int i = 0; i < ArraySize(zones); i++)
|
|
{
|
|
//
|
|
tmp = zones[i];
|
|
|
|
//
|
|
// Validate Zone ...
|
|
has = false;
|
|
for (int j = barIndex; j < tmp.FromIndex(); j++)
|
|
{
|
|
//
|
|
// Initial Bar ...
|
|
if (tmpBar.Init(tmp.symbol, tmp.period, j))
|
|
{
|
|
//
|
|
tmpValue = forPriceType == X_BOUNDARY_PRICE_UP_DOWN
|
|
? tmp.IsBullish()
|
|
? tmpBar.GetDown()
|
|
: tmpBar.GetUp()
|
|
: forPriceType == X_BOUNDARY_PRICE_HIGH_LOW
|
|
? tmp.IsBullish()
|
|
? tmpBar.low
|
|
: tmpBar.high
|
|
: EMPTY_VALUE;
|
|
if (NotEmptyZero(tmpValue))
|
|
{
|
|
//
|
|
// Check Break ...
|
|
has = tmp.IsBullish()
|
|
? tmpValue < tmp.lower
|
|
: tmpValue > tmp.upper;
|
|
|
|
//
|
|
// If Breakes ...
|
|
if (has)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpBar.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Not Breaked ...
|
|
if (!has)
|
|
{
|
|
//
|
|
AddIfNotExists(
|
|
tmp,
|
|
tmps //
|
|
);
|
|
}
|
|
|
|
//
|
|
tmp.Clean();
|
|
}
|
|
|
|
//
|
|
// Update Zones ...
|
|
XClean(zones);
|
|
Copy(
|
|
tmps,
|
|
zones //
|
|
);
|
|
XClean(tmps);
|
|
}
|
|
|
|
void GetCurrentStructure(
|
|
XBoxZone &supports[],
|
|
XBoxZone &resistances[],
|
|
XBoxZone &minorSupport,
|
|
XBoxZone &majorSupport,
|
|
XBoxZone &minorResistance,
|
|
XBoxZone &majorResistance,
|
|
int barIndex = 0,
|
|
string forSymbol = NULL,
|
|
ENUM_TIMEFRAMES forPeriod = NULL,
|
|
int loopback = 50,
|
|
int minorValidation = 7,
|
|
int majorValidation = 14 //
|
|
)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
XClean(supports);
|
|
XClean(resistances);
|
|
minorSupport.Clean();
|
|
majorSupport.Clean();
|
|
minorResistance.Clean();
|
|
majorResistance.Clean();
|
|
|
|
//
|
|
// Normalize ...
|
|
barIndex = kiParser.NormalizeBarIndex(barIndex);
|
|
if (!IsXValid(forSymbol))
|
|
{
|
|
forSymbol = symbol;
|
|
}
|
|
if (!IsXValid(forPeriod))
|
|
{
|
|
forPeriod = period;
|
|
}
|
|
|
|
//
|
|
int tmpIDX = -1;
|
|
int supportsCount = 0;
|
|
XBoxZone tmpSupports[];
|
|
int resistancesCount = 0;
|
|
XBoxZone tmpResistances[];
|
|
|
|
//
|
|
// Detect Minors ...
|
|
|
|
//
|
|
supportsCount = DetectSupports(
|
|
tmpSupports,
|
|
barIndex,
|
|
loopback,
|
|
true, // Force Validation ...
|
|
minorValidation,
|
|
forSymbol,
|
|
forPeriod //
|
|
);
|
|
if (IsValidSize(supportsCount))
|
|
{
|
|
//
|
|
FillNotExists(
|
|
supports,
|
|
tmpSupports //
|
|
);
|
|
|
|
//
|
|
tmpIDX = GetYoungest(tmpSupports);
|
|
if (IsValidIndex(tmpIDX))
|
|
{
|
|
minorSupport = tmpSupports[tmpIDX];
|
|
}
|
|
}
|
|
|
|
//
|
|
resistancesCount = DetectResistances(
|
|
tmpResistances,
|
|
barIndex,
|
|
loopback,
|
|
true, // Force Validation ...
|
|
minorValidation,
|
|
forSymbol,
|
|
forPeriod //
|
|
);
|
|
if (IsValidSize(resistancesCount))
|
|
{
|
|
//
|
|
FillNotExists(
|
|
resistances,
|
|
tmpResistances //
|
|
);
|
|
|
|
//
|
|
tmpIDX = GetYoungest(tmpResistances);
|
|
if (IsValidIndex(tmpIDX))
|
|
{
|
|
minorResistance = tmpResistances[tmpIDX];
|
|
}
|
|
}
|
|
|
|
//
|
|
XClean(tmpSupports);
|
|
XClean(tmpResistances);
|
|
|
|
//
|
|
// Detect Majors ...
|
|
|
|
//
|
|
supportsCount = DetectSupports(
|
|
tmpSupports,
|
|
barIndex,
|
|
loopback,
|
|
true, // Force Validation ...
|
|
majorValidation,
|
|
forSymbol,
|
|
forPeriod //
|
|
);
|
|
if (IsValidSize(supportsCount))
|
|
{
|
|
//
|
|
FillNotExists(
|
|
supports,
|
|
tmpSupports //
|
|
);
|
|
|
|
//
|
|
tmpIDX = GetLowest(tmpSupports);
|
|
if (IsValidIndex(tmpIDX))
|
|
{
|
|
majorSupport = tmpSupports[tmpIDX];
|
|
}
|
|
}
|
|
|
|
//
|
|
resistancesCount = DetectResistances(
|
|
tmpResistances,
|
|
barIndex,
|
|
loopback,
|
|
true, // Force Validation ...
|
|
majorValidation,
|
|
forSymbol,
|
|
forPeriod //
|
|
);
|
|
if (IsValidSize(resistancesCount))
|
|
{
|
|
//
|
|
FillNotExists(
|
|
resistances,
|
|
tmpResistances //
|
|
);
|
|
|
|
//
|
|
tmpIDX = GetHighest(tmpResistances);
|
|
if (IsValidIndex(tmpIDX))
|
|
{
|
|
majorResistance = tmpResistances[tmpIDX];
|
|
}
|
|
}
|
|
|
|
//
|
|
XClean(tmpSupports);
|
|
XClean(tmpResistances);
|
|
}
|
|
// #endregion
|
|
|
|
//
|
|
// Others ...
|
|
|
|
/**
|
|
* Destroy ...
|
|
*/
|
|
void Destroy()
|
|
{
|
|
//
|
|
delete barAnalyser;
|
|
ZeroMemory(barAnalyser);
|
|
|
|
//
|
|
ZeroMemory(kiHelper);
|
|
ZeroMemory(kiParser);
|
|
}
|
|
|
|
//
|
|
// Testers ...
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
// |