This commit is contained in:
2024-12-03 01:03:32 +03:30
parent de90f2d5fb
commit 29c9df62c5
7 changed files with 6420 additions and 332 deletions
@@ -26,6 +26,140 @@
//
// 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 ...
@@ -40,6 +174,8 @@ class XC121SMCCycleHelper : public XCBase
//
// XPV ...
XCXPVHelper *mXPVHelper;
XPVPivot pivots[];
XPVPivot orderFlow[];
//
// X3MA ...
@@ -52,6 +188,7 @@ class XC121SMCCycleHelper : public XCBase
//
// XCHSAR ...
XCXCHSARHelper *mXCHSARHelper;
XSarChange sarChanges[];
//
// POI Detector ...
@@ -271,6 +408,102 @@ class XC121SMCCycleHelper : public XCBase
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 ...
*
@@ -569,6 +802,557 @@ class XC121SMCCycleHelper : public XCBase
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();
}
}
//
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 ...