This commit is contained in:
2025-06-02 03:41:33 +03:30
parent aca304dc6f
commit 2f0efd0285
3 changed files with 883 additions and 76 deletions
+488 -73
View File
@@ -110,6 +110,12 @@ class XCXCATBEASignaller : XCBase
//
// Props ...
//
// Signalling Methods ...
bool allowSignallingBasedOnConditions; // Signalling and Entry based on Market Conditions ...
bool allowSignallingBasedOnTriggerBlocks; // Signalling Based on Trigger Block Detection ...
bool allowSignallingBasedOnTriggerBlocksInsideOther; // Signalling based on Trigger Blocks inside other Trigger Blocks ...
//
bool allowDraws; // Allow Draws or not ...
bool allowGuards; // Allow Guards or not ...
@@ -126,7 +132,12 @@ class XCXCATBEASignaller : XCBase
XTriggerBlockValidationRules validations; // Trigger Block Validations ...
//
XBoxZone unavailableZones[]; // Un Available Zones ...
XBoxZone cPeak; // Current Peak ...
XBoxZone cVale; // Current Vale ...
XBoxZone unavailableZones[]; // Un Available Zones ...
XTriggerBlock cTriggerBlock; // Currently Selected Trigger Block ...
XTriggerBlock triggerBlocks[]; // Founded Trigger Blocks ...
XTriggerBlock cInsideTriggerBlock; // a TriggerBlock which Currently Selected Trigger Block is Inside it ...
//
XCATBEAStrategyConditions mConditions;
@@ -195,6 +206,8 @@ class XCXCATBEASignaller : XCBase
int count = 0;
bool has = false;
int barIndex = 0;
cTriggerBlock.Clean();
cInsideTriggerBlock.Clean();
//
// Check Guards ...
@@ -320,6 +333,42 @@ class XCXCATBEASignaller : XCBase
drawer.Draw(bar.time);
}
//
// Detect Trigger Blocks and Collect them ...
XTriggerBlock iTriggerBlock;
X121XCatbConditions iConditions;
has = DetectTriggerBlock(
helper,
barAnalyser,
iTriggerBlock,
iConditions,
validations,
filters,
barIndex,
10 // Loopback ...
);
if (has)
{
//
// Add Trigger Block to Collection if not Exists ...
AddIfNotExists(
iTriggerBlock,
triggerBlocks //
);
}
iConditions.Clean();
iTriggerBlock.Clean();
//
// Draw Trigger Blocks ...
if (allowDraws)
{
//
// Handle To Updating ...
// datetime cTime = TimeCurrent();
// DrawTriggerBlocks(cTime);
}
//
// Here we Check Active Session ...
// and Prevent Moving forward if there is not
@@ -372,93 +421,274 @@ class XCXCATBEASignaller : XCBase
helper.Update(barIndex);
//
// Trigger Block Detection ...
result = DetectTriggerBlock(
helper,
barAnalyser,
mConditions.triggerBlock,
mConditions.conditions,
validations,
filters,
barIndex,
10 // Loopback ...
);
if (result)
// Detect Signal Setup Based on Market Conditions ...
if (!result &&
allowSignallingBasedOnConditions)
{
//
// Prepare Condition ...
//
// Prepare Signal ...
mConditions.dir =
mConditions
.triggerBlock
.GetDirection();
mConditions.symbol = symbol;
mConditions.period = period;
mConditions.provider = provider;
mConditions.reward = riskToRewardRatio;
mConditions.time = mConditions.conditions.bars[0].time;
mConditions.setupTime = mConditions.conditions.bars[0].time;
//
// Prepare Target ...
double targets[];
for (int i = 1; i <= riskToRewardRatio; i++)
{
//
Add(
(double)i,
targets //
);
}
//
// Calculate SL Additions ...
double iATR = 0;
if (barIndex > 0 &&
barIndex < ArraySize(helper.atrBuffer))
{
iATR = helper.atrBuffer[barIndex];
}
double slAdditional = slATRMultiplier * iATR;
//
// Preparing Signal ...
result = ToSignal(
mConditions.triggerBlock.trigger,
mConditions.triggerBlock.signal,
targets,
slAdditional //
// Detect Signalling Zone ...
result = DetectSignalZone(
helper,
barAnalyser,
mConditions.conditions,
mConditions.pivotZone,
barIndex,
10 // Loopback ...
);
if (result)
{
//
mConditions.triggerBlock.signal.provider = provider;
mConditions.sl = mConditions.triggerBlock.signal.sl;
mConditions.tp = mConditions.triggerBlock.signal.tp;
mConditions.pivot = mConditions.triggerBlock.signal.sl;
mConditions.entry = mConditions.triggerBlock.signal.entry;
mConditions.point = mConditions.triggerBlock.signal.entry;
mConditions.type = ToPositionType(mConditions.triggerBlock.signal.type);
// Filling Conditions of Strategy ...
}
}
//
// Detect Signal Setup Based on Trigger Block Detection ...
if (!result &&
allowSignallingBasedOnTriggerBlocks)
{
//
// Detect Trigger Block ...
result = DetectTriggerBlock(
helper,
barAnalyser,
mConditions.triggerBlock,
mConditions.conditions,
validations,
filters,
barIndex,
10 // Loopback ...
);
if (result)
{
//
// Use Trigger Block ...
UseTriggerBlock(mConditions.triggerBlock);
//
// Draw Trigger Block ...
if (allowDraws)
// Prepare Condition ...
//
// Prepare Signal ...
mConditions.dir =
mConditions
.triggerBlock
.GetDirection();
mConditions.symbol = symbol;
mConditions.period = period;
mConditions.provider = provider;
mConditions.reward = riskToRewardRatio;
mConditions.time = mConditions.conditions.bars[0].time;
mConditions.setupTime = mConditions.conditions.bars[0].time;
//
// Prepare Target ...
double targets[];
for (int i = 1; i <= riskToRewardRatio; i++)
{
//
DrawTriggerBlock(
mConditions.triggerBlock,
drawer.drawer,
mObjects,
NULL, // To ...
false // Draw Signal ...
Add(
(double)i,
targets //
);
}
//
// Calculate SL Additions ...
double iATR = 0;
if (barIndex > 0 &&
barIndex < ArraySize(helper.atrBuffer))
{
iATR = helper.atrBuffer[barIndex];
}
double slAdditional = slATRMultiplier * iATR;
//
// Preparing Signal ...
result = ToSignal(
mConditions.triggerBlock.trigger,
mConditions.triggerBlock.signal,
targets,
slAdditional //
);
if (result)
{
//
mConditions.triggerBlock.signal.provider = provider;
mConditions.sl = mConditions.triggerBlock.signal.sl;
mConditions.tp = mConditions.triggerBlock.signal.tp;
mConditions.pivot = mConditions.triggerBlock.signal.sl;
mConditions.entry = mConditions.triggerBlock.signal.entry;
mConditions.point = mConditions.triggerBlock.signal.entry;
mConditions.type = ToPositionType(mConditions.triggerBlock.signal.type);
//
// Draw Trigger Block ...
if (allowDraws)
{
//
DrawTriggerBlock(
mConditions.triggerBlock,
drawer.drawer,
mObjects,
NULL, // To ...
false // Draw Signal ...
);
}
}
}
}
//
// Detect Signal Setup Based On Trigger Blocks Second Entry ...
if (!result &&
allowSignallingBasedOnTriggerBlocksInsideOther)
{
//
// First We Hvae to Select Peak and Vale ...
//
// Check Peak and Vale Exists ...
int peakIDX = GetYoungest(detector.peakPivots);
int valeIDX = GetYoungest(detector.valePivots);
result = IsValidIndex(peakIDX) &&
IsValidIndex(valeIDX);
if (result)
{
//
cPeak = detector.peakPivots[peakIDX];
cVale = detector.valePivots[valeIDX];
//
// Trigger Block Detection ...
result = HasChild(triggerBlocks) &&
ArraySize(triggerBlocks) > 1;
if (result)
{
//
// Check Newest Trigger Block ...
int newestIDX = GetYoungest(triggerBlocks);
result = IsValidIndex(newestIDX);
if (result)
{
//
cTriggerBlock = triggerBlocks[newestIDX];
//
// Check Trigger Block is New ...
int toIDX = cTriggerBlock.ToIndex() == 0;
bool isNewest = toIDX == 0;
if (isNewest)
{
//
// Now we have to Check Newest Trigger Block Place ...
int insideTBIDX = DetectInsideTriggerBlock(
cTriggerBlock,
cInsideTriggerBlock,
triggerBlocks //
);
//
// Check InsideTB is Exists and Valid ...
result =
cInsideTriggerBlock.IsValid() &&
IsValidIndex(insideTBIDX);
if (result)
{
//
// Remove Peak from Detector Collections ...
// and Make it unavailable ...
ArrayRemove(
detector.peakPivots,
peakIDX,
1 //
);
AddRef(
cPeak,
unavailableZones //
);
//
// Remove Vale from Detector Collections ...
// and Make it unavailable ...
ArrayRemove(
detector.peakPivots,
peakIDX,
1 //
);
AddRef(
cVale,
unavailableZones //
);
//
// Remove Selected Trigger Block ...
// and Make it unavailable ...
RemoveTriggerBlock(
cTriggerBlock,
triggerBlocks //
);
UseTriggerBlock(cTriggerBlock);
//
// Remove Selected Inside Trigger Block ...
// and Make it unavailable ...
RemoveTriggerBlock(
cInsideTriggerBlock,
triggerBlocks //
);
UseTriggerBlock(cInsideTriggerBlock);
//
CleanupArray(
unavailableZones,
maxAllowedCollection //
);
//
// Draw Trigger Blocks if Allowed ...
if (allowDraws)
{
//
//
// Draw Blocks ...
datetime cTime = TimeCurrent();
//
// mObjects.Clear();
//
// Detected Block ...
DrawTriggerBlock(
cTriggerBlock,
drawer.drawer,
mObjects,
cTime,
false // Draw Signal ...
);
//
// Inside Block ...
DrawTriggerBlock(
cInsideTriggerBlock,
drawer.drawer,
mObjects,
cTime,
false // Draw Signal ...
);
}
//
Print("Salam ...");
}
}
}
}
}
}
//
// Check a Signal Setup Exists or not ...
result = mConditions.IsValid() &&
mConditions.IsSetuped();
@@ -617,6 +847,14 @@ class XCXCATBEASignaller : XCBase
*/
void Init(XCATBEASignallerInputs &inputs)
{
//
maxAllowedCollection = 50;
//
allowSignallingBasedOnConditions = false;
allowSignallingBasedOnTriggerBlocks = true;
allowSignallingBasedOnTriggerBlocksInsideOther = false;
//
bool has = inputs.IsValid();
if (!has)
@@ -714,12 +952,16 @@ class XCXCATBEASignaller : XCBase
* @return ( int )
*/
int AddConditionsIfNotExists(
int maxAllowed = 10 //
int maxAllowed = 50 //
)
{
//
int result = 0;
//
// Normalize Args ...
maxAllowed = maxAllowedCollection;
//
bool isSetuped = IsValid(mConditions.setupTime) &&
HasDirection(mConditions.dir);
@@ -788,6 +1030,178 @@ class XCXCATBEASignaller : XCBase
return result;
}
/**
* Add TriggerBlock if not Exists
* inside a Collection ...
*/
int AddIfNotExists(
XTriggerBlock &tb,
XTriggerBlock &tbs[],
int maxAllowed = 50 //
)
{
//
int result = 0;
//
// Normalize Args ...
maxAllowed = maxAllowedCollection;
//
// First Validate ...
if (!tb.IsValid())
{
return result;
}
//
// Check Exists ...
// and prevent moving forward if exists ...
int idx = -1;
bool isExists = FindTriggerBlockIndex(
idx,
tb,
tbs //
);
result = !isExists;
if (!result)
{
return result;
}
//
// Add if not Exists ...
AddRef(
tb,
tbs //
);
//
// Cleanup ...
CleanupArray(
tbs,
maxAllowed //
);
//
result = ArraySize(tbs);
//
return result;
}
/**
* Use Specified Trigger Block and Make it Un Available ...
*
* @param tb: XTriggerBlock instance reference, Specified Used Trigger Block ...
*/
void UseTriggerBlock(XTriggerBlock &tb)
{
//
bool has = tb.IsValid();
if (!has)
{
return;
}
//
// Trigger Box ...
has = tb.trigger.IsValid();
if (has)
{
//
AddRef(
tb.trigger,
unavailableZones //
);
}
//
// Order Block Box ...
has = tb.ob.IsValid();
if (has)
{
//
AddRef(
tb.ob,
unavailableZones //
);
}
//
// Fair Value Gap ...
has = tb.fvg.IsValid();
if (has)
{
//
AddRef(
tb.fvg,
unavailableZones //
);
}
//
// Following Liquidity ...
has = tb.fLiquidity.IsValid();
if (has)
{
//
AddRef(
tb.fLiquidity,
unavailableZones //
);
}
//
// Reversal Liquidity ...
has = tb.rLiquidity.IsValid();
if (has)
{
//
AddRef(
tb.rLiquidity,
unavailableZones //
);
}
//
// Cleaning Up ...
CleanupArray(
unavailableZones,
maxAllowedCollection //
);
}
/**
* Draw Exists Trigger Blocks ...
*/
void DrawTriggerBlocks(datetime to = NULL)
{
//
// Check Has Child of trigger Blocks ...
bool has = HasChild(triggerBlocks);
if (!has)
{
return;
}
//
// Loop through Blocks ...
int count = ArraySize(triggerBlocks);
for (int i = 0; i < count; i++)
{
//
// Draw Indexed Trigger Block ...
DrawTriggerBlock(
triggerBlocks[i],
drawer.drawer,
mObjects,
to,
false //
);
}
}
//
// Private ...
private:
@@ -797,6 +1211,7 @@ class XCXCATBEASignaller : XCBase
string provider;
CArrayObj *mObjects;
ENUM_TIMEFRAMES period;
int maxAllowedCollection; // Max Allowed Collection Items ...
//
// Initialize and Configure POI Detector and Drawer ...
+340
View File
@@ -303,6 +303,346 @@ struct XTriggerBlockFilters
//
// Extensions ...
/**
* Get Newest Trigger Block Index inside a Collection ...
*
* @return ( int )
*/
int GetYoungest(XTriggerBlock &tbs[])
{
//
int result = -1;
//
// Checking Collection Has Childs ...
if (!HasChild(tbs))
{
return result;
}
//
datetime selected = NULL;
int count = ArraySize(tbs);
for (int i = 0; i < count; i++)
{
//
bool canSelect =
!IsValid(selected)
? true
: tbs[i].trigger.from > selected;
if (canSelect)
{
//
result = i;
selected = tbs[i].trigger.from;
}
}
//
return result;
}
/**
* Get Oldest Trigger Block Index inside a Collection ...
*
* @return ( int )
*/
int GetOldest(XTriggerBlock &tbs[])
{
//
int result = -1;
//
// Checking Collection Has Childs ...
if (!HasChild(tbs))
{
return result;
}
//
datetime selected = NULL;
int count = ArraySize(tbs);
for (int i = 0; i < count; i++)
{
//
bool canSelect =
!IsValid(selected)
? true
: tbs[i].trigger.from < selected;
if (canSelect)
{
//
result = i;
selected = tbs[i].trigger.from;
}
}
//
return result;
}
/**
* Get Highest Trigger Block Index inside a Collection ...
*
* @return ( int )
*/
int GetHighest(XTriggerBlock &tbs[])
{
//
int result = -1;
//
// Checking Collection Has Childs ...
if (!HasChild(tbs))
{
return result;
}
//
double selected = 0;
int count = ArraySize(tbs);
for (int i = 0; i < count; i++)
{
//
bool canSelect =
selected <= 0
? true
: tbs[i].trigger.lower > selected;
if (canSelect)
{
//
result = i;
selected = tbs[i].trigger.lower;
}
}
//
return result;
}
/**
* Get Lowest Trigger Block Index inside a Collection ...
*
* @return ( int )
*/
int GetLowest(XTriggerBlock &tbs[])
{
//
int result = -1;
//
// Checking Collection Has Childs ...
if (!HasChild(tbs))
{
return result;
}
//
double selected = 0;
int count = ArraySize(tbs);
for (int i = 0; i < count; i++)
{
//
bool canSelect =
selected <= 0
? true
: tbs[i].trigger.upper < selected;
if (canSelect)
{
//
result = i;
selected = tbs[i].trigger.upper;
}
}
//
return result;
}
/**
* Find Trigger Block Index inside a Colletion ...
*/
bool FindTriggerBlockIndex(
int &index,
XTriggerBlock &tb,
XTriggerBlock &tbs[] //
)
{
//
bool result = false;
//
index = -1;
//
result = tb.IsValid();
if (!result)
{
return result;
}
//
bool isExists = false;
bool has = HasChild(tbs);
if (has)
{
//
int count = ArraySize(tbs);
for (int i = 0; i < count; i++)
{
//
isExists = tb.trigger.IsSameAs(tbs[i].trigger);
if (isExists)
{
//
index = i;
break;
}
}
}
//
result =
isExists &&
IsValidIndex(index);
//
return result;
}
/**
* Remove Specified Trigger Block from a Collection, if Exists ...
*
* @param tb: XTriggerBlock instance reference, Specified Trigger Block for Checking ...
* @param tbs: XTriggerBlock instance reference Array, Collection of Trigger Blocks ...
*
* @return ( bool )
*/
bool RemoveTriggerBlock(
XTriggerBlock &tb,
XTriggerBlock &tbs[] //
)
{
//
bool result = false;
//
// Validate Args ...
result = tb.IsValid() &&
HasChild(tbs);
if (!result)
{
return result;
}
//
int idx = -1;
result = FindTriggerBlockIndex(
idx,
tb,
tbs //
);
if (!result)
{
return result;
}
//
result = ArrayRemove(
tbs,
idx,
1 //
);
//
return result;
}
/**
* Detect a TriggerBlock which Specified TriggerBlock is Inside of it ...
*
* @param tb: XTriggerBlock instance reference, Specified Trigger Block for Checking ...
* @param insideTB: XTriggerBlock instance reference, Holds founded inside Trigger Block ...
* @param tbs: XTriggerBlock instance collection, Specified Collection for Checking ...
* @param minimumLengthBetweenTBs: int, Minimum Bars between two Trigger Blocks ...
*
* @return ( int ) founded Inside TriggerBlock index ...
*/
int DetectInsideTriggerBlock(
XTriggerBlock &tb,
XTriggerBlock &insideTB,
XTriggerBlock &tbs[],
int minimumLengthBetweenTBs = 5 //
)
{
//
int result = -1;
//
// Normalize Args ...
minimumLengthBetweenTBs = NormalizeInt(minimumLengthBetweenTBs, 3);
//
// Check Collection has Childs ...
bool has = HasChild(tbs);
if (!has)
{
return result;
}
//
insideTB.Clean();
bool isBullish = tb.IsBullish();
bool isBearish = tb.IsBearish();
//
int count = ArraySize(tbs);
for (int i = 0; i < count; i++)
{
//
// Check Trigger Block Conditions ...
bool isInside =
//
// Check Not Same ...
!tb.trigger.IsSameAs(tbs[i].trigger) &&
//
// Check Direction ...
tb.trigger.dir == tbs[i].trigger.dir &&
//
// Check Length of TBS ...
(minimumLengthBetweenTBs <= 0
? true
: tb.trigger.FromIndex() + minimumLengthBetweenTBs <= tbs[i].trigger.FromIndex()) &&
//
// Check Inside it ...
(isBullish
? (tb.trigger.lower < tbs[i].trigger.upper &&
tb.trigger.lower > tbs[i].trigger.lower &&
tb.trigger.lower < tbs[i].trigger.GetMid())
: (tb.trigger.upper > tbs[i].trigger.lower &&
tb.trigger.upper < tbs[i].trigger.upper &&
tb.trigger.upper > tbs[i].trigger.GetMid())) &&
//
// Check Last ...
(!insideTB.IsValid()
? true
: isBullish
? insideTB.trigger.upper > tbs[i].trigger.upper
: insideTB.trigger.lower < tbs[i].trigger.lower)
//
;
if (isInside)
{
//
result = i;
insideTB = tbs[i];
}
}
//
return result;
}
/**
* Detect Trigger Block ...
*
+55 -3
View File
@@ -275,12 +275,64 @@ struct XCATBEAStrategyConditions
//
};
//
bool DetectSignalZone()
/**
* Detect Signal Zone based on Market Conditions ...
*
* @param helper: XCX121XCatbHelper instance pointer ...
* @param barAnalyser: XCBarAnalyser instance pointer ...
* @param conditions: X121XCatbConditions instance reference, hold signalling Conditions ...
* @param signalZone: XBoxZone instance reference, hold Signal Zone ...
* @param barIndex: int, Bar Index ...
* @param loopback: int, Loopback for Market Conditions ...
*
* @return ( bool )
*/
bool DetectSignalZone(
XCX121XCatbHelper *helper,
XCBarAnalyser *barAnalyser,
X121XCatbConditions &conditions,
XBoxZone &signalZone,
int barIndex = 0,
int loopback = 10 //
)
{
//
bool result = false;
//
// Normalize Args ...
signalZone.Clean();
conditions.Clean();
loopback = NormalizeInt(loopback, 0);
barIndex = NormalizeInt(barIndex, 0);
//
// Validate Args ...
result =
helper != NULL &&
barAnalyser != NULL;
if (!result)
{
return result;
}
//
// Validate Result ...
result = signalZone.IsValid();
//
// Cleanup Resources ...
//
if (!result)
{
//
signalZone.Clean();
conditions.Clean();
}
//
return result;
}
}
//