1484 lines
31 KiB
Plaintext
1484 lines
31 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// --------------------------------------
|
|
// Name: XC121SMCCycleHelper
|
|
// Description: provides all based classes for use ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-poi.class.mq5"
|
|
#include "../../Helpers/x-saherelm.x121.helper.mq5"
|
|
#include "../Libraries/x-121.smc.lib.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
struct XSarChange
|
|
{
|
|
//
|
|
// Props ...
|
|
ENUM_X_DIRECTION dir; // Sar Changed To Direction ...
|
|
datetime time; // Sar Changed Time ...
|
|
double last; // Sar Value Before Change ...
|
|
double value; // Sar Value After Change ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XSarChange()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
last = 0;
|
|
value = 0;
|
|
time = NULL;
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
/**
|
|
* Validation ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
last > 0 &&
|
|
value > 0 &&
|
|
IsValid(time) &&
|
|
HasDirection(dir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Initialize ...
|
|
*
|
|
* @param _last: Last Sar Value ...
|
|
* @param _current: Current Sar Value ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
double _last,
|
|
double _current,
|
|
datetime _time,
|
|
ENUM_X_DIRECTION _dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
_last > 0 &&
|
|
_current > 0 &&
|
|
IsValid(_time) &&
|
|
HasDirection(_dir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = _dir;
|
|
last = _last;
|
|
time = _time;
|
|
value = _current;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Change is Bullish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsValid() &&
|
|
IsBullish(dir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Change is Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearishّ()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsValid() &&
|
|
IsBearish(dir);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Implementations ...
|
|
|
|
class XC121SMCCycleHelper : public XCBase
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// XPV ...
|
|
XCXPVHelper *mXPVHelper;
|
|
XPVPivot pivots[];
|
|
XPVPivot orderFlow[];
|
|
|
|
//
|
|
// X3MA ...
|
|
XCX3MAHelper *mX3MAHelper;
|
|
|
|
//
|
|
// X3VWAP ...
|
|
XCX3VWAPHelper *mX3VWAPHelper;
|
|
|
|
//
|
|
// XCHSAR ...
|
|
XCXCHSARHelper *mXCHSARHelper;
|
|
XSarChange sarChanges[];
|
|
|
|
//
|
|
// X121 ...
|
|
XCX121Helper *mX121Helper;
|
|
|
|
//
|
|
// POI Detector ...
|
|
XCPOIDetector *mPOIDetector;
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
XC121SMCCycleHelper()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XC121SMCCycleHelper()
|
|
{
|
|
DeInit();
|
|
}
|
|
|
|
//
|
|
// Getter/Setter(s) ...
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
/**
|
|
* Initialize ...
|
|
*
|
|
* @param symbol: String ...
|
|
* @param period: ENUM_TIMEFRAMES member ...
|
|
* @param xpvInputs: XPVInputs instance ...
|
|
* @param x3maInputs: X3MAInputs instance ...
|
|
* @param x3vwapInputs: X3VWAPInputs instance ...
|
|
* @param xchsarInputs: XCHSARInputs instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
string symbol,
|
|
ENUM_TIMEFRAMES period,
|
|
XPVInputs &xpvInputs,
|
|
X3MAInputs &x3maInputs,
|
|
X3VWAPInputs &x3vwapInputs,
|
|
XCHSARInputs &xchsarInputs //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid(symbol) &&
|
|
IsValid(period);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// XPV ...
|
|
|
|
//
|
|
result = xpvInputs.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mXPVHelper = new XCXPVHelper();
|
|
result = mXPVHelper.Init(
|
|
symbol,
|
|
period,
|
|
xpvInputs //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// X3MA ...
|
|
|
|
//
|
|
result = x3maInputs.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mX3MAHelper = new XCX3MAHelper();
|
|
result = mX3MAHelper.Init(
|
|
symbol,
|
|
period,
|
|
x3maInputs //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// X3VWAP ...
|
|
|
|
//
|
|
result = x3vwapInputs.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mX3VWAPHelper = new XCX3VWAPHelper();
|
|
result = mX3VWAPHelper.Init(
|
|
symbol,
|
|
period,
|
|
x3vwapInputs //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// XCHSAR ...
|
|
|
|
//
|
|
result = xchsarInputs.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mXCHSARHelper = new XCXCHSARHelper();
|
|
result = mXCHSARHelper.Init(
|
|
symbol,
|
|
period,
|
|
xchsarInputs //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mPOIDetector = new XCPOIDetector(
|
|
symbol,
|
|
period //
|
|
);
|
|
mPOIDetector.MaxNumberOfRequiredPOIs(0);
|
|
mPOIDetector.Init();
|
|
|
|
//
|
|
// Initialize Bar Analyser Class Instance ...
|
|
mBarAnalyser = new XCBarAnalyser();
|
|
|
|
//
|
|
// Set Chart Style ...
|
|
ApplyChartStyle();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Specified Bar ...
|
|
*
|
|
* @param source: XOHCL instance, Source Bar ...
|
|
* @param bar: XOHCL instance, Dest Bar ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetBar(
|
|
XOHCL &source,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
string symbol = GetSymbol();
|
|
ENUM_TIMEFRAMES period = GetPeriod();
|
|
|
|
//
|
|
result =
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
source.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = iBarShift(
|
|
symbol,
|
|
period,
|
|
source.time //
|
|
);
|
|
result = bar.Init(
|
|
symbol,
|
|
period,
|
|
index //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
bar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Specified Bar ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param index: Integer ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetBar(
|
|
XOHCL &bar,
|
|
int index = 0 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
|
|
//
|
|
string symbol = GetSymbol();
|
|
ENUM_TIMEFRAMES period = GetPeriod();
|
|
|
|
//
|
|
result = bar.Init(
|
|
symbol,
|
|
period,
|
|
index //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Specified Bar ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param time: Datetime ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetBar(
|
|
XOHCL &bar,
|
|
datetime time = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int index = GetBarIndex(time);
|
|
result = GetBar(bar,
|
|
index //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Specified Time Bar Index ...
|
|
*
|
|
* @param time: DateTime ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int GetBarIndex(datetime time = NULL)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
string symbol = GetSymbol();
|
|
ENUM_TIMEFRAMES period = GetPeriod();
|
|
|
|
//
|
|
result = iBarShift(
|
|
symbol,
|
|
period,
|
|
time //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Cycle Conditions ...
|
|
*
|
|
* @param conditions: X121SMCCycleConditions instance ...
|
|
* @param barIndex: Integer ...
|
|
* @param loopback: Integer ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetConditions(
|
|
X121SMCCycleConditions &conditions,
|
|
int barIndex = 0,
|
|
int loopback = 7 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (loopback < 5)
|
|
{
|
|
loopback = 5;
|
|
}
|
|
|
|
//
|
|
conditions.Clean();
|
|
|
|
//
|
|
result = mXPVHelper.GetConditions(
|
|
conditions.xpvConditions,
|
|
barIndex,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
conditions.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mX3MAHelper.GetConditions(
|
|
conditions.x3maConditions,
|
|
barIndex,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
conditions.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mX3VWAPHelper.GetConditions(
|
|
conditions.x3vwapConditions,
|
|
barIndex,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
conditions.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mXCHSARHelper.GetConditions(
|
|
conditions.xchsarConditions,
|
|
barIndex,
|
|
loopback //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
conditions.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
conditions.symbol = conditions.xpvConditions.symbol;
|
|
conditions.period = conditions.xpvConditions.period;
|
|
conditions.time = TimeCurrent();
|
|
|
|
//
|
|
result = conditions.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// POI Tools ...
|
|
|
|
/**
|
|
* Detect Nearest Current SAR Change ...
|
|
*
|
|
* @param changeBar: XOHCL instance, Holds Nearest Change Bar ...
|
|
* @param bar: XOHCL instance, represents Current Bar for Loopback ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectNearestCSARChange(
|
|
XOHCL &changeBar,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
changeBar.Clean();
|
|
|
|
//
|
|
result =
|
|
bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL mBar;
|
|
result = GetBar(
|
|
bar,
|
|
mBar //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int barIndex = mBar.Index();
|
|
double sar = mXCHSARHelper.GetC(barIndex);
|
|
bool isBullish = sar > 0 &&
|
|
sar < mBar.low;
|
|
bool isBearish = sar > 0 &&
|
|
sar > mBar.high;
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Back to Find Nearest Sar Change ...
|
|
bool canContinue = true;
|
|
while (canContinue)
|
|
{
|
|
//
|
|
barIndex++;
|
|
|
|
//
|
|
XOHCL iBar;
|
|
canContinue = iBar.Init(
|
|
mBar.symbol,
|
|
mBar.period,
|
|
barIndex //
|
|
);
|
|
if (!canContinue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
double iSar = mXCHSARHelper.GetC(barIndex);
|
|
bool isISarBullish =
|
|
iSar > 0 &&
|
|
iSar < iBar.low;
|
|
bool isISarBearish =
|
|
iSar > 0 &&
|
|
iSar > iBar.high;
|
|
bool isSarChanged =
|
|
isBullish
|
|
? !isISarBullish
|
|
: !isISarBearish;
|
|
|
|
//
|
|
if (isSarChanged)
|
|
{
|
|
//
|
|
result = iBar.GetNextBar(changeBar);
|
|
canContinue = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = changeBar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Last Decision Bar ( Rejection, Pin, Momentum ) ...
|
|
*
|
|
* @param decisionBar: XOHCL instance, Holds Decision Bar ...
|
|
* @param forDir: ENUM_X_DIRECTION member, Specified Bar Direction ...
|
|
* @param bar: XOHCL instance, represents Current Bar for Loopback ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectNearestDecisionBar(
|
|
XOHCL &decisionBar,
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
decisionBar.Clean();
|
|
|
|
//
|
|
result =
|
|
bar.IsValid() &&
|
|
forDir != X_DIRECTION_ALL &&
|
|
forDir != X_DIRECTION_NONE;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL mBar;
|
|
result = GetBar(
|
|
bar,
|
|
mBar //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int barIndex = mBar.Index();
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
bool canContinue = true;
|
|
while (canContinue)
|
|
{
|
|
//
|
|
barIndex++;
|
|
|
|
//
|
|
XOHCL iBar;
|
|
canContinue = iBar.Init(
|
|
mBar.symbol,
|
|
mBar.period,
|
|
barIndex //
|
|
);
|
|
if (!canContinue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION decisionDir;
|
|
bool isDecisionBar = mBarAnalyser
|
|
.IsDecisionBar(
|
|
iBar,
|
|
decisionDir //
|
|
);
|
|
if (isDecisionBar)
|
|
{
|
|
//
|
|
if (decisionDir == forDir)
|
|
{
|
|
//
|
|
decisionBar = mBar;
|
|
canContinue = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
canContinue = !decisionBar.IsValid();
|
|
}
|
|
|
|
//
|
|
result = decisionBar
|
|
.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Parabolic Sar Extensions ...
|
|
|
|
/**
|
|
* Check Sar Changes and Save it ...
|
|
*
|
|
* @param change: XSarChange instance ...
|
|
* @param time: DateTime ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSarChanged(
|
|
XSarChange &change,
|
|
datetime time = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
change.Clean();
|
|
|
|
//
|
|
XOHCL bar;
|
|
result = GetBar(
|
|
bar,
|
|
time //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL prevBar;
|
|
result = bar.GetPreviousBar(prevBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL prevPrevBar;
|
|
result = prevBar.GetPreviousBar(prevPrevBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
prevPrevBar = prevBar;
|
|
prevBar = bar;
|
|
|
|
//
|
|
int index = prevBar.Index();
|
|
|
|
//
|
|
double current = mXCHSARHelper.GetC(index);
|
|
double prev = mXCHSARHelper.GetC(index + 1);
|
|
|
|
//
|
|
bool isCurrentBullish =
|
|
current < prevBar.low;
|
|
bool isPrevBullish =
|
|
prev < prevPrevBar.low;
|
|
|
|
//
|
|
bool isCurrentBearish =
|
|
current > prevBar.high;
|
|
bool isPrevBearish =
|
|
prev > prevPrevBar.high;
|
|
|
|
//
|
|
bool isChangedToBullish =
|
|
isCurrentBullish &&
|
|
!isPrevBullish;
|
|
|
|
//
|
|
bool isChangedToBearish =
|
|
isCurrentBearish &&
|
|
!isPrevBearish;
|
|
|
|
//
|
|
result = isChangedToBullish ||
|
|
isChangedToBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
ENUM_X_DIRECTION dir =
|
|
isChangedToBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
result = change
|
|
.Init(
|
|
prev,
|
|
current,
|
|
prevBar.time,
|
|
dir //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XSarChange lastChange;
|
|
bool hasLastItem = GetLastItem(
|
|
lastChange,
|
|
sarChanges //
|
|
);
|
|
bool canAdd = !hasLastItem
|
|
? true
|
|
: lastChange.time < change.time;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
AddRef(
|
|
change,
|
|
sarChanges //
|
|
);
|
|
}
|
|
|
|
//
|
|
CleanSarChanges();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Cleanup Unused Sar Changes ...
|
|
*/
|
|
void CleanSarChanges()
|
|
{
|
|
//
|
|
int required = 10;
|
|
int count = ArraySize(sarChanges);
|
|
if (!IsValidSize(count) || count <= required)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int mustRemove = count - required;
|
|
ArrayRemove(
|
|
sarChanges,
|
|
0,
|
|
mustRemove //
|
|
);
|
|
}
|
|
|
|
//
|
|
// XPV Extensions ...
|
|
|
|
/**
|
|
* Detect First Pivot ...
|
|
*
|
|
* @param pivot: XPVPivot instance ...
|
|
* @param time: DateTime ...
|
|
* @param minRepetition: Integer, Minimum Repetition ...
|
|
* @param maxAllowedLoopbackBars: Integer, Max Allowed LoopBack Bars ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectLastPivot(
|
|
XPVPivot &pivot,
|
|
datetime time = NULL,
|
|
int minRepetition = 40,
|
|
int maxAllowedLoopbackBars = 576 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
pivot.Clean();
|
|
|
|
//
|
|
int index = GetBarIndex(time);
|
|
result = DetectPivot(
|
|
pivot,
|
|
index,
|
|
minRepetition,
|
|
maxAllowedLoopbackBars //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Pivot ...
|
|
*
|
|
* @param pivot: XPVPivot instance ...
|
|
* @param barIndex: Integer ...
|
|
* @param minRepetition: Integer, Minimum Repetition ...
|
|
* @param maxAllowedLoopbackBars: Integer, Max Allowed LoopBack Bars ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectPivot(
|
|
XPVPivot &pivot,
|
|
int barIndex = 0,
|
|
int minRepetition = 40,
|
|
int maxAllowedLoopbackBars = 576 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
string symbol = GetSymbol();
|
|
ENUM_TIMEFRAMES period = GetPeriod();
|
|
|
|
//
|
|
int start = barIndex;
|
|
int end = start + maxAllowedLoopbackBars;
|
|
|
|
//
|
|
double peak = 0;
|
|
int peakRepeate = 0;
|
|
int peakToBarIndex = 0;
|
|
int peakFromBarIndex = 0;
|
|
|
|
//
|
|
double vale = 0;
|
|
int valeRepeate = 0;
|
|
int valeToBarIndex = 0;
|
|
int valeFromBarIndex = 0;
|
|
|
|
//
|
|
bool canLookupPeak = true;
|
|
bool canLookupVale = true;
|
|
bool canLookup = true;
|
|
while (canLookup)
|
|
{
|
|
//
|
|
// Check Peak ...
|
|
double iPeak = mXPVHelper.GetPeak(barIndex);
|
|
if (iPeak != peak)
|
|
{
|
|
//
|
|
if (peak != 0 &&
|
|
peakRepeate >= minRepetition)
|
|
{
|
|
//
|
|
XPVPivot iPivot;
|
|
|
|
//
|
|
iPivot.lower = 0;
|
|
iPivot.upper = peak;
|
|
iPivot.symbol = symbol;
|
|
iPivot.period = period;
|
|
iPivot.type = XPV_PEAK;
|
|
iPivot.repetition = peakRepeate;
|
|
iPivot.to = iTime(
|
|
symbol,
|
|
period,
|
|
peakToBarIndex //
|
|
);
|
|
iPivot.from = iTime(
|
|
symbol,
|
|
period,
|
|
peakFromBarIndex //
|
|
);
|
|
|
|
//
|
|
iPivot.lower = iPivot.CalculateLower();
|
|
|
|
//
|
|
bool isValid = iPivot.IsValid();
|
|
if (isValid)
|
|
{
|
|
//
|
|
pivot = iPivot;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
peak = iPeak;
|
|
peakRepeate = 0;
|
|
peakFromBarIndex = 0;
|
|
peakToBarIndex = barIndex;
|
|
}
|
|
else if (iPeak == peak)
|
|
{
|
|
//
|
|
peakRepeate++;
|
|
peakFromBarIndex = barIndex;
|
|
}
|
|
|
|
//
|
|
// Check Vale ...
|
|
double iVale = mXPVHelper.GetVale(barIndex);
|
|
if (iVale != vale)
|
|
{
|
|
//
|
|
if (vale != 0 &&
|
|
valeRepeate >= minRepetition)
|
|
{
|
|
//
|
|
XPVPivot iPivot;
|
|
|
|
//
|
|
iPivot.upper = 0;
|
|
iPivot.lower = vale;
|
|
iPivot.symbol = symbol;
|
|
iPivot.period = period;
|
|
iPivot.type = XPV_VALE;
|
|
iPivot.repetition = valeRepeate;
|
|
iPivot.to = iTime(
|
|
symbol,
|
|
period,
|
|
valeToBarIndex //
|
|
);
|
|
iPivot.from = iTime(
|
|
symbol,
|
|
period,
|
|
valeFromBarIndex //
|
|
);
|
|
|
|
//
|
|
iPivot.upper = iPivot.CalculateUpper();
|
|
|
|
//
|
|
bool isValid = iPivot.IsValid();
|
|
if (isValid)
|
|
{
|
|
//
|
|
pivot = iPivot;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
vale = iVale;
|
|
valeRepeate = 0;
|
|
valeFromBarIndex = 0;
|
|
valeToBarIndex = barIndex;
|
|
}
|
|
else if (iVale == vale)
|
|
{
|
|
//
|
|
valeRepeate++;
|
|
valeFromBarIndex = barIndex;
|
|
}
|
|
|
|
//
|
|
canLookupPeak = !pivot.IsValid();
|
|
canLookupVale = !pivot.IsValid();
|
|
canLookup = barIndex < end &&
|
|
(canLookupPeak ||
|
|
canLookupVale);
|
|
if (canLookup)
|
|
{
|
|
barIndex++;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = pivot.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
XPVPivot last;
|
|
bool hasLastPivot = GetLastPivot(last);
|
|
|
|
//
|
|
if (hasLastPivot)
|
|
{
|
|
//
|
|
// Check For Pivot Update ...
|
|
bool isLastPivotSameAsCurrent =
|
|
pivot.IsValid() &&
|
|
last.IsValid() &&
|
|
pivot.from == last.from &&
|
|
pivot.type == last.type;
|
|
if (!isLastPivotSameAsCurrent)
|
|
{
|
|
//
|
|
AddRef(
|
|
pivot,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
CleanPivots();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update Last Pivot ...
|
|
RemoveLastItem(pivots);
|
|
|
|
//
|
|
pivot.to = TimeCurrent();
|
|
|
|
//
|
|
AddRef(
|
|
pivot,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
CleanPivots();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add New Pivot ...
|
|
AddRef(
|
|
pivot,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
CleanPivots();
|
|
}
|
|
}
|
|
|
|
//
|
|
// DetectOrderFlow();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retriece Last Pivot if Exists ...
|
|
*
|
|
* @param pivot: XPVPivot instane ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetLastPivot(XPVPivot &pivot)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
pivot.Clean();
|
|
|
|
//
|
|
int count = ArraySize(pivots);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetLastItem(
|
|
pivot,
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Order Flow ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION member, Hold's Order Flow Direction ...
|
|
* @param minPivots: Integer, minimum Required Pivots for Order Flow ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectOrderFlow(
|
|
ENUM_X_DIRECTION &dir,
|
|
int minPivots = 3 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Minimum Pivots ...
|
|
if (minPivots < 2)
|
|
{
|
|
minPivots = 2;
|
|
}
|
|
|
|
//
|
|
Clean(orderFlow);
|
|
Copy(
|
|
pivots,
|
|
orderFlow //
|
|
);
|
|
|
|
//
|
|
// Sort Pivots ...
|
|
SortPivots(orderFlow);
|
|
|
|
//
|
|
// Filter Broken Order Flows ...
|
|
FilterBrokenPivots(orderFlow);
|
|
|
|
//
|
|
int count = ArraySize(orderFlow);
|
|
result = IsValidSize(count) &&
|
|
count >= minPivots;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect Order Flow Direction ...
|
|
result = DetectPivotDirection(
|
|
orderFlow,
|
|
dir //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Cleanup Unused Pivots ...
|
|
*/
|
|
void CleanPivots()
|
|
{
|
|
//
|
|
int required = 10;
|
|
int count = ArraySize(pivots);
|
|
if (!IsValidSize(count) || count <= required)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int mustRemove = count - required;
|
|
ArrayRemove(
|
|
pivots,
|
|
0,
|
|
mustRemove //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Virtuals ...
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
// Props ...
|
|
XCBarAnalyser *mBarAnalyser;
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
/**
|
|
* Release All Resources ...
|
|
*/
|
|
void DeInit()
|
|
{
|
|
//
|
|
delete mXPVHelper;
|
|
delete mX3MAHelper;
|
|
delete mX3VWAPHelper;
|
|
delete mXCHSARHelper;
|
|
|
|
//
|
|
delete mBarAnalyser;
|
|
}
|
|
|
|
/**
|
|
* Apply Chart Style ...
|
|
*/
|
|
void ApplyChartStyle()
|
|
{
|
|
//
|
|
// Retrieve Current Chart ID ...
|
|
long chartId = ChartID();
|
|
|
|
//
|
|
ENUM_CHART_MODE mMode = CHART_CANDLES; // chart's mMode
|
|
bool mShowBidLine = true; // show bid line
|
|
bool mShowAskLine = true; // show ask line
|
|
bool mShowGrid = false; // show grids on chart
|
|
bool mShowVolumes = false; // show volumes
|
|
bool mShowTradeLevels = true; // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders)
|
|
bool mAutoScroll = true; // chart autoscroll
|
|
bool mQuickNavigation = true; // chart quick navigation state
|
|
color mForeGroundColor = clrWhite; // chart's foreground color
|
|
color mBackGroundColor = clrBlack; // chart's background color
|
|
color mUpColor = clrGreen; // Up Color
|
|
color mDownColor = clrRed; // Down Color
|
|
color mBullishColor = clrGreen; // Bullish color
|
|
color mBearishColor = clrRed; // Bearish color
|
|
color mGridColor = clrGray; // grid color
|
|
color mBidLineColor = clrGray; // bid line color
|
|
color mAskLineColor = clrRed; // ask line color
|
|
color mLineColor = clrLime; // line mMode and doji candlestick color
|
|
color mStopColor = clrGold; // Color of stop order levels (Stop Loss and Take Profit)
|
|
color mVolumesColor = clrGreen; // volumes color
|
|
|
|
//
|
|
ChartSetInteger(chartId, CHART_MODE, mMode);
|
|
ChartSetInteger(chartId, CHART_SHOW_BID_LINE, mShowBidLine);
|
|
ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, mShowAskLine);
|
|
ChartSetInteger(chartId, CHART_SHOW_GRID, mShowGrid);
|
|
ChartSetInteger(chartId, CHART_SHOW_VOLUMES, mShowVolumes);
|
|
ChartSetInteger(chartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels);
|
|
ChartSetInteger(chartId, CHART_AUTOSCROLL, mAutoScroll);
|
|
ChartSetInteger(chartId, CHART_QUICK_NAVIGATION, mQuickNavigation);
|
|
ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, mForeGroundColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, mBackGroundColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_CHART_UP, mUpColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, mDownColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, mBullishColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, mBearishColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_GRID, mGridColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_BID, mBidLineColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_ASK, mAskLineColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_STOP_LEVEL, mStopColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, mLineColor);
|
|
ChartSetInteger(chartId, CHART_COLOR_VOLUME, mVolumesColor);
|
|
}
|
|
|
|
/**
|
|
* Retrieve Symbol ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetSymbol()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result = mXPVHelper.GetSymbol();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve TimeFrame (Period) ...
|
|
*
|
|
* @return ( ENUM_TIMEFRAMES )
|
|
*/
|
|
ENUM_TIMEFRAMES GetPeriod()
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
result = mXPVHelper.GetPeriod();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|