This commit is contained in:
2025-05-28 18:34:30 +03:30
parent 72e8b34da5
commit f958dddec1
4 changed files with 350 additions and 67 deletions
+323 -7
View File
@@ -21,9 +21,9 @@
//
// Imports ...
#include "../Libraries/xcatbea.lib.mq5"
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5"
#include "../Libraries/xcatbea.lib.mq5"
//
// Definiions ...
@@ -145,12 +145,13 @@ struct XTriggerBlockValidationRules
bool forceOBBarType; // Force Order Block to Has InDirectional Bars ...
int minRequiredOBBar; // Min Required OB Bar ...
bool forceFVGBarType; // Force Fair Value Gaps Bars Type ...
int liquidityLoopback; // Liquidity Detection Loopback ...
double maxAllowedRange; // Max Allowed Order Block Range ...
double minAllowedRange; // Min Allowed Order Block Range ...
bool forceHasFLiquidity; // Force Order Block To Has Reversal Liquidity ...
bool forceHasRLiquidity; // Force Order Block to Has Following Liquidity ...
int liquidityLoopback; // Liquidity Detection Loopback ...
bool validateGapSequence; // Validate Fair Value Gaps Bar Sequences ...
int minAllowedBlockLength; // Min Allowed Block Length ...
bool validateBlockEdgeBreakout; // Validate Order Block Edge Breakeout ...
//
@@ -175,6 +176,7 @@ struct XTriggerBlockValidationRules
forceHasSwing = false;
forceOBBarType = false;
forceFVGBarType = false;
minAllowedBlockLength = 0;
forceHasFLiquidity = false;
forceHasRLiquidity = false;
validateGapSequence = false;
@@ -203,7 +205,11 @@ struct XTriggerBlockFilters
bool filterBasedOnHKSignalBar; // Filter Based On HK Signal Bar ...
//
int bosLoopback; // PV Based Filtering BOS Lookup ...
int bosLoopback; // PV Based Filtering BOS Lookup ...
bool forceSarSwitched; // SAR Switched on Sides for Filtering ...
bool forceSarOnBothSide; // SAR Check on Both Sides for Filtering ...
bool forceSarHasBreakout; // SAR Must Has Reversal Direction in Trigger Block ...
bool forceSarHasReversalSide; // SAR Must Has Reversal Direction in Trigger Block ...
//
// Constructor(s) ...
@@ -233,6 +239,10 @@ struct XTriggerBlockFilters
//
bosLoopback = 0;
forceSarSwitched = false;
forceSarOnBothSide = false;
forceSarHasBreakout = false;
forceSarHasReversalSide = false;
//
ZeroMemory(this);
@@ -409,6 +419,7 @@ bool DetectTriggerBlock1(
// validations.liquidityLoopback = 144;
// validations.forceHasFLiquidity = true;
// validations.forceHasRLiquidity = true;
// validations.minAllowedBlockLength = 7;
//
// Apply Validations ...
@@ -434,8 +445,13 @@ bool DetectTriggerBlock1(
//
// TODO: Remove this ...
filters.bosLoopback = 30;
filters.filterBasedOnPV = true;
// filters.bosLoopback = 0;
// filters.filterBasedOnPV = true;
// filters.filterBasedOnSar = false;
// filters.forceSarSwitched = false;
// filters.forceSarOnBothSide = true;
// filters.forceSarHasBreakout = true;
// filters.forceSarHasReversalSide = false;
//
// Apply Filtering ...
@@ -937,6 +953,75 @@ bool ValidateTriggerBlock(
iBar.Clean();
}
//
// Validating Block Length Based on Direction ...
if (result &&
validations.minAllowedBlockLength)
{
//
count = 0;
fromIDX = triggerBlock.FromIndex();
int sIDX = fromIDX;
has = true;
while (has)
{
//
// Initialize iBar ...
has = iBar.Init(
conditions.symbol,
conditions.period,
sIDX //
);
//
has =
has &&
(isBullish
? iBar.low > triggerBlock.trigger.lower
: iBar.high < triggerBlock.trigger.upper);
//
if (!has)
{
break;
}
//
sIDX++;
count++;
iBar.Clean();
}
//
result =
iBar.IsValid() &&
count >= validations.minAllowedBlockLength;
if (result)
{
//
// Update Trigger Block ...
bool usaMinAllowedForBlockLength = false;
if (usaMinAllowedForBlockLength)
{
fromIDX = fromIDX + validations.minAllowedBlockLength;
}
else
{
fromIDX = sIDX - 1;
}
//
triggerBlock.trigger.from = GetBarTime(
conditions.symbol,
conditions.period,
fromIDX //
);
}
//
iBar.Clean();
}
//
if (!result)
{
@@ -1057,12 +1142,20 @@ bool FilterTriggerBlock(
// For PV Filtering ...
//
// Detect Bos ...
// Detect BOS ...
//
// When Loopback for BOS has Specified Value ...
// we Lookup for BOS on Specific Period ...
if (filters.bosLoopback > 0)
{
//
has = true;
int fBOSIDX = -1;
int rBOSIDX = -1;
bool isBOS = false;
bool isFBOS = false;
bool isRBOS = false;
bool isPeakOverLast = false;
bool isValeUnderLast = false;
toIDX = triggerBlock.ob.ToIndex();
@@ -1088,6 +1181,26 @@ bool FilterTriggerBlock(
iVale > 0 &&
iVale < iPVale;
//
isFBOS =
isBullish
? isPeakOverLast
: isValeUnderLast;
if (isFBOS)
{
fBOSIDX = sIDX;
}
//
isRBOS =
isBullish
? isValeUnderLast
: isPeakOverLast;
if (isRBOS)
{
rBOSIDX = sIDX;
}
//
isBOS =
(isBullish &&
@@ -1106,7 +1219,210 @@ bool FilterTriggerBlock(
}
//
result = isBOS;
isFBOS = IsValidIndex(fBOSIDX);
isRBOS = IsValidIndex(rBOSIDX);
//
result = isBOS &&
isFBOS &&
!isRBOS;
}
//
// When Loopback for BOS has not Specified Value ...
// we Lookup for BOS on GAP End Bar ...
if (filters.bosLoopback <= 0)
{
//
toIDX = triggerBlock.ToIndex();
//
// Initialize iBar ...
result = iBar.Init(
conditions.symbol,
conditions.period,
toIDX //
);
result =
result &&
(isBullish ? iBar.high > helper.GetPeak(toIDX + 1)
: iBar.low < helper.GetVale(toIDX + 1));
}
}
//
// Filter Based on SAR ...
if (result &&
filters.filterBasedOnSar)
{
//
toIDX = triggerBlock.ToIndex();
fromIDX = triggerBlock.FromIndex();
//
double iSarState = helper.GetSarState(toIDX);
double iPSarState = helper.GetSarState(toIDX + 1);
//
double iFSarState = helper.GetSarState(fromIDX);
double iPFSarState = helper.GetSarState(fromIDX + 1);
//
bool isSarBullish =
iSarState > 0;
//
bool isSarBearish =
iSarState < 0;
//
bool isFSarBullish =
iFSarState > 0;
//
bool isFSarBearish =
iFSarState < 0;
//
bool isSarSwitchedToBullish =
iSarState > 0 &&
iPSarState <= 0;
//
bool isSarSwitchedToBearish =
iSarState < 0 &&
iPSarState >= 0;
//
bool isFSarSwitchedToBullish =
iFSarState > 0 &&
iPFSarState <= 0;
//
bool isFSarSwitchedToBearish =
iFSarState < 0 &&
iPFSarState >= 0;
//
// Creating Filters ...
//
bool isToFilterPassed =
!filters.forceSarSwitched
? (isBullish
? isSarBullish
: isSarBearish)
: (isBullish
? isSarSwitchedToBullish
: isSarSwitchedToBearish);
//
bool isFromFilterPassed =
!filters.forceSarSwitched
? (isBullish
? isFSarBullish
: isFSarBearish)
: (isBullish
? isFSarSwitchedToBullish
: isFSarSwitchedToBearish);
//
result =
!filters.forceSarOnBothSide
? isToFilterPassed
: isToFilterPassed &&
isFromFilterPassed;
//
// Check Sar Has Reversal Direction inside Trigger Block ...
if (result &&
filters.forceSarHasReversalSide)
{
//
toIDX = triggerBlock.ToIndex();
fromIDX = triggerBlock.FromIndex();
for (int i = toIDX; i < fromIDX; i++)
{
//
double iSarState = helper.GetSarState(i);
//
has =
isBullish
? iSarState > 0
: iSarState < 0;
if (has)
{
break;
}
}
//
result = has;
}
//
// Force Sar Breakouts ...
// in this Senario Sar must in following Direction and
// there is not any Switches ...
// but must breakout Bar the last in Reversal Direction
// of Sar ...
if (result &&
filters.forceSarHasBreakout)
{
//
bool isSarBullishStart =
//
(
//
// Current SAR is Directional ...
conditions.isSarBullish &&
//
// Previous InDirectional Sar Exists ...
helper.lastSarBearish.IsValid() &&
//
// Current Close is Over previous Sar ...
conditions.bars[cIDX].close > helper.lastSarBearish.after &&
//
// Before Close is not Over previous Sar ...
conditions.bars[pIDX].close <= helper.lastSarBearish.after
//
)
//
;
//
bool isSarBearishStart =
//
(
//
// Current SAR is Directional ...
conditions.isSarBearish &&
//
// Previous InDirectional Sar Exists ...
helper.lastSarBullish.IsValid() &&
//
// Current Close is Under previous ...
conditions.bars[cIDX].close < helper.lastSarBullish.after &&
//
// Before Close is not Under previous ...
conditions.bars[pIDX].close >= helper.lastSarBullish.after
//
)
//
;
//
result =
isBullish
? isSarBullishStart
: isSarBearishStart;
}
//
if (result)
{
Print("Filter Passed ...");
}
}