This commit is contained in:
2025-06-02 08:46:42 +03:30
parent b660b12322
commit d01e1036ce
5 changed files with 854 additions and 121 deletions
@@ -1624,6 +1624,49 @@ bool HasInsideBox(
return result;
}
/**
* Remove Specified Box from Collection ...
*/
bool RemoveBox(
XBoxZone &box,
XBoxZone &boxes[] //
)
{
//
bool result = false;
//
result =
box.IsValid() &&
HasChild(boxes);
if (!result)
{
return result;
}
//
int idx = -1;
result = FindBoxIndex(
idx,
box,
boxes //
);
if (!result)
{
return result;
}
//
result = ArrayRemove(
boxes,
idx,
1 //
);
//
return result;
}
/**
* Converts to XBoxZone ...
*
+9 -10
View File
@@ -1052,26 +1052,25 @@ class XCXCATBEAExpert : public XCBase
XCATBEAStrategyConditions iConditions = conditions[i];
//
// Prepare Signal Based on Conditions ...
// Define Signal Structure ...
XSignal iSignal;
//
// Check if a Trigger Block Attached and Has Signal ...
// use it ...
// Check Conditions is Valid Triggered Conditions ...
has =
iConditions.IsValid() &&
iConditions.IsSetuped() &&
iConditions.CanTrigger() &&
iConditions.triggerBlock.IsValid() &&
iConditions.triggerBlock.signal.IsValid();
iConditions.CanTrigger();
if (has)
{
iSignal = iConditions.triggerBlock.signal;
//
// Preparing Signal ...
has = ToSignal(
iSignal,
iConditions //
);
}
//
// if we Have any other Signalling senarios we can Handle them here ...
//
// Validate Signal ...
has = iSignal.IsValid();
+659 -108
View File
@@ -137,6 +137,8 @@ class XCXCATBEASignaller : XCBase
XBoxZone unavailableZones[]; // Un Available Zones ...
XTriggerBlock cTriggerBlock; // Currently Selected Trigger Block ...
XTriggerBlock triggerBlocks[]; // Founded Trigger Blocks ...
bool waitsUntilPeakInvalidate; // Waits Until Peak Invalidate ...
bool waitsUntilValeInvalidate; // Waits Until Vale Invalidate ...
XTriggerBlock cInsideTriggerBlock; // a TriggerBlock which Currently Selected Trigger Block is Inside it ...
//
@@ -330,20 +332,22 @@ class XCXCATBEASignaller : XCBase
// Draw POI(s) ...
if (allowDraws)
{
drawer.Draw(bar.time);
// drawer.Draw(bar.time);
}
//
// Detect Trigger Blocks and Collect them ...
XTriggerBlock iTriggerBlock;
X121XCatbConditions iConditions;
XTriggerBlockFilters iFilters;
XTriggerBlockValidationRules iValidations;
has = DetectTriggerBlock(
helper,
barAnalyser,
iTriggerBlock,
iConditions,
validations,
filters,
iValidations,
iFilters,
barIndex,
10 // Loopback ...
);
@@ -420,6 +424,174 @@ class XCXCATBEASignaller : XCBase
// Update All Required Buffers ...
helper.Update(barIndex);
//
datetime cTime = TimeCurrent();
//
// cPeak and cVale ...
// these Helpes Us to Detect Price Levels ...
//
// Draw Peak and Vale if Exists ...
//
// Peak ...
if (cPeak.IsValid())
{
//
cPeak.to = cTime;
drawer.DrawBox(cPeak);
}
//
// Vale ...
if (cVale.IsValid())
{
//
cVale.to = cTime;
drawer.DrawBox(cVale);
}
//
// Try to Validate cPeak an cVale if Exists ...
XOHCL zBar;
XOHCL cBar;
bool isInited = zBar.Init(
symbol,
period,
barIndex //
);
isInited = zBar.GetPreviousBar(cBar);
isInited = helper.GetConditions(
mConditions.conditions,
barIndex,
10 //
);
if (isInited)
{
//
// Validate cPeak and cVale if Exists ...
//
// cPeak ...
if (cPeak.IsValid())
{
//
isInited = cBar.high < cPeak.lower;
if (!isInited)
{
//
cPeak.Clean();
cVale.Clean();
//
waitsUntilPeakInvalidate = false;
waitsUntilValeInvalidate = false;
}
}
//
// cVale ...
if (cVale.IsValid())
{
//
isInited = cBar.low > cVale.upper;
if (!isInited)
{
//
cPeak.Clean();
cVale.Clean();
//
waitsUntilPeakInvalidate = false;
waitsUntilValeInvalidate = false;
}
}
//
// Try To Detect Peak and Vale based on cBar ...
//
// Selecting Peak ...
if (!cPeak.IsValid())
{
//
XBoxZone tmpPeaks[];
detector.FillPeakPivots(tmpPeaks);
while (HasChild(tmpPeaks))
{
//
// Find Index ...
int idx = GetLowest(tmpPeaks);
if (!IsValidIndex(idx))
{
break;
}
//
// Select ...
cPeak = tmpPeaks[idx];
ArrayRemove(
tmpPeaks,
idx,
1 //
);
//
// Validate Peak ...
bool isValid = cPeak.lower > cBar.high;
if (isValid)
{
break;
}
//
cPeak.Clean();
}
Clean(tmpPeaks);
}
//
// Selecting Vale ...
if (!cVale.IsValid())
{
//
XBoxZone tmpVales[];
detector.FillValePivots(tmpVales);
while (HasChild(tmpVales))
{
//
// Find Index ...
int idx = GetHighest(tmpVales);
if (!IsValidIndex(idx))
{
break;
}
//
// Select ...
cVale = tmpVales[idx];
ArrayRemove(
tmpVales,
idx,
1 //
);
//
// Validate Vale ...
bool isValid = cVale.upper < cTriggerBlock.trigger.lower &&
cVale.upper < cInsideTriggerBlock.trigger.lower;
if (isValid)
{
break;
}
//
cVale.Clean();
}
Clean(tmpVales);
}
}
//
// Detect Signal Setup Based on Market Conditions ...
if (!result &&
@@ -545,114 +717,342 @@ class XCXCATBEASignaller : XCBase
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);
// Trigger Block Detection ...
result = HasChild(triggerBlocks) &&
ArraySize(triggerBlocks) > 1 &&
!waitsUntilPeakInvalidate &&
!waitsUntilValeInvalidate;
if (result)
{
//
cPeak = detector.peakPivots[peakIDX];
cVale = detector.valePivots[valeIDX];
// Check Newest Trigger Block ...
bool isTriggerBlockSelected = false;
XTriggerBlock tmpTBs[];
Copy(
triggerBlocks,
tmpTBs //
);
while (HasChild(tmpTBs))
{
//
int idx = GetYoungest(tmpTBs);
if (!IsValidIndex(idx))
{
break;
}
//
// Select ...
// and Remove From Collection ...
cTriggerBlock = tmpTBs[idx];
ArrayRemove(
tmpTBs,
idx,
1 //
);
//
// Validate ...
isTriggerBlockSelected =
//
// Check Bar is Valid ...
cBar.IsValid() &&
//
// Currently Happens ...
(cTriggerBlock.trigger.to == zBar.time ||
cTriggerBlock.trigger.to == cBar.time) &&
//
// Price Validations ...
(cTriggerBlock.IsBullish()
? cBar.low > cTriggerBlock.trigger.lower
: cBar.high < cTriggerBlock.trigger.upper)
//
;
if (isTriggerBlockSelected)
{
break;
}
//
// Clean Trigger Block ...
cTriggerBlock.Clean();
}
Clean(tmpTBs);
//
// Trigger Block Detection ...
result = HasChild(triggerBlocks) &&
ArraySize(triggerBlocks) > 1;
// Check Trigger Block Selection ...
result = isTriggerBlockSelected;
if (result)
{
//
// Check Newest Trigger Block ...
int newestIDX = GetYoungest(triggerBlocks);
result = IsValidIndex(newestIDX);
bool isBullish = cTriggerBlock.IsBullish();
bool isBearish = cTriggerBlock.IsBearish();
//
// 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)
{
//
cTriggerBlock = triggerBlocks[newestIDX];
// Now we Have to Detect Peak and Vales ...
result =
cPeak.IsValid() &&
cVale.IsValid();
//
// Check Trigger Block is New ...
int toIDX = cTriggerBlock.ToIndex() == 0;
bool isNewest = toIDX == 0;
if (isNewest)
// If Exists Before Validate them based Trigger Blocks ...
if (result)
{
//
// Now we have to Check Newest Trigger Block Place ...
int insideTBIDX = DetectInsideTriggerBlock(
// Validate cPeak and cVale based on
// cTriggerBlock and cInsideTriggerBlock ...
result =
//
// Peak ...
cPeak.lower > cTriggerBlock.trigger.upper &&
cPeak.lower > cInsideTriggerBlock.trigger.upper &&
//
// Vale ...
cVale.upper < cTriggerBlock.trigger.lower &&
cVale.upper < cInsideTriggerBlock.trigger.lower &&
//
// Bar Validation ...
cBar.IsValid() &&
cBar.low > cVale.upper &&
cBar.high < cPeak.lower
//
;
if (!result)
{
//
cPeak.Clean();
cVale.Clean();
//
waitsUntilPeakInvalidate = false;
waitsUntilValeInvalidate = false;
}
}
//
// if not Exists, or Clean them on Invalidating Process, try to Find Corrects ...
if (!result)
{
//
// Selecting Peak ...
XBoxZone tmpPeaks[];
detector.FillPeakPivots(tmpPeaks);
while (HasChild(tmpPeaks))
{
//
// Find Index ...
int idx = GetLowest(tmpPeaks);
if (!IsValidIndex(idx))
{
break;
}
//
// Select ...
cPeak = tmpPeaks[idx];
ArrayRemove(
tmpPeaks,
idx,
1 //
);
//
// Validate Peak ...
bool isValid =
//
// Bar Validation ...
cBar.IsValid() &&
cBar.high < cPeak.lower &&
//
// Peak Validation ...
cPeak.lower > cTriggerBlock.trigger.upper &&
cPeak.lower > cInsideTriggerBlock.trigger.upper;
if (isValid)
{
break;
}
//
cPeak.Clean();
}
Clean(tmpPeaks);
//
// Selecting Vale ...
XBoxZone tmpVales[];
detector.FillValePivots(tmpVales);
while (HasChild(tmpVales))
{
//
// Find Index ...
int idx = GetHighest(tmpVales);
if (!IsValidIndex(idx))
{
break;
}
//
// Select ...
cVale = tmpVales[idx];
ArrayRemove(
tmpVales,
idx,
1 //
);
//
// Validate Vale ...
bool isValid =
//
// Bar Validation ...
cBar.IsValid() &&
cBar.low > cVale.upper &&
//
// Vale Validation ...
cVale.upper < cTriggerBlock.trigger.lower &&
cVale.upper < cInsideTriggerBlock.trigger.lower;
if (isValid)
{
break;
}
//
cVale.Clean();
}
Clean(tmpVales);
//
// Summarizing Result ...
result =
cPeak.IsValid() &&
cVale.IsValid();
}
//
// Check Peak and Vale Exists ...
if (result)
{
//
// Remove Peak from Detector Collections ...
// and Make it unavailable ...
UseBox(cPeak);
//
// Remove Vale from Detector Collections ...
// and Make it unavailable ...
UseBox(cVale);
//
// 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);
//
// Check InsideTB is Exists and Valid ...
result =
cInsideTriggerBlock.IsValid() &&
IsValidIndex(insideTBIDX);
if (result)
// Update Peak and Vales To ...
cPeak.to = cTime;
cVale.to = cTime;
//
// Draw Peak and Vales ...
if (allowDraws)
{
//
// Remove Peak from Detector Collections ...
// and Make it unavailable ...
ArrayRemove(
detector.peakPivots,
peakIDX,
1 //
);
AddRef(
cPeak,
unavailableZones //
);
drawer.DrawBox(cPeak);
drawer.DrawBox(cVale);
}
//
// Validate Peaks and Vales ...
bool isPeakPassed = false;
bool isValePassed = false;
cInsideTriggerBlock.trigger.to = cTime;
int toIDX = cInsideTriggerBlock.ToIndex();
int fromIDX = cInsideTriggerBlock.FromIndex();
for (int i = toIDX; i < fromIDX; i++)
{
//
// Reading Values ...
//
// Remove Vale from Detector Collections ...
// and Make it unavailable ...
ArrayRemove(
detector.peakPivots,
peakIDX,
1 //
);
AddRef(
cVale,
unavailableZones //
);
double iPeak = helper.GetPeak(i);
double iPPeak = helper.GetPeak(i + 1);
//
// Remove Selected Trigger Block ...
// and Make it unavailable ...
RemoveTriggerBlock(
cTriggerBlock,
triggerBlocks //
);
UseTriggerBlock(cTriggerBlock);
double iVale = helper.GetVale(i);
double iPVale = helper.GetVale(i + 1);
//
// Remove Selected Inside Trigger Block ...
// and Make it unavailable ...
RemoveTriggerBlock(
cInsideTriggerBlock,
triggerBlocks //
);
UseTriggerBlock(cInsideTriggerBlock);
bool isPeakOverLast = iPeak > iPPeak;
bool isPeakUnderLast = iPeak < iPPeak;
//
CleanupArray(
unavailableZones,
maxAllowedCollection //
);
bool isValeOverLast = iVale > iPVale;
bool isValeUnderLast = iVale < iPVale;
//
if (!isPeakPassed)
{
//
isPeakPassed =
isBullish ? isPeakOverLast
: isPeakUnderLast;
}
//
if (!isValePassed)
{
//
isValePassed =
isBullish
? isValeUnderLast
: isPeakOverLast;
}
//
result =
isPeakPassed &&
isValePassed;
if (result)
{
break;
}
}
if (result)
{
//
// Draw Trigger Blocks if Allowed ...
if (allowDraws)
{
//
//
// Draw Blocks ...
datetime cTime = TimeCurrent();
//
// mObjects.Clear();
@@ -679,12 +1079,140 @@ class XCXCATBEASignaller : XCBase
}
//
Print("Salam ...");
if (isBullish)
{
waitsUntilPeakInvalidate = true;
}
else if (isBearish)
{
waitsUntilValeInvalidate = true;
}
//
mConditions.triggerBlock = cTriggerBlock;
}
}
}
}
}
//
// Preparing Conditions based on result ...
if (result)
{
//
bool isBullish = mConditions.triggerBlock.IsBullish();
//
// Preparing mConditions ...
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 //
);
XSignal insideTBSignal;
result =
result &&
ToSignal(
cInsideTriggerBlock.trigger,
insideTBSignal,
targets,
slAdditional //
);
if (result)
{
//
// Try to Use SL Based on Inside Trigger Block ...
double sl = 0;
double tp = 0;
bool useInsideTBForSL = true;
if (useInsideTBForSL)
{
//
sl = insideTBSignal.sl;
tp = insideTBSignal.tp;
//
// Add Target for usuall Signal TP ...
XTarget iTarget;
iTarget.doRF = true;
iTarget.target = mConditions.triggerBlock.signal.tp;
//
AddRef(
iTarget,
mConditions.targets);
//
iTarget.Clean();
}
else
{
//
sl = mConditions.triggerBlock.signal.sl;
tp = mConditions.triggerBlock.signal.tp;
}
//
mConditions.sl = sl;
mConditions.tp = tp;
mConditions.pivot = sl;
mConditions.triggerBlock.signal.provider = provider;
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 ...
);
}
}
}
}
//
@@ -694,6 +1222,10 @@ class XCXCATBEASignaller : XCBase
//
// Cleanup Resource ...
zBar.Clean();
cBar.Clean();
cTriggerBlock.Clean();
cInsideTriggerBlock.Clean();
//
return result;
@@ -852,8 +1384,8 @@ class XCXCATBEASignaller : XCBase
//
allowSignallingBasedOnConditions = false;
allowSignallingBasedOnTriggerBlocks = true;
allowSignallingBasedOnTriggerBlocksInsideOther = false;
allowSignallingBasedOnTriggerBlocks = false;
allowSignallingBasedOnTriggerBlocksInsideOther = true;
//
bool has = inputs.IsValid();
@@ -1090,6 +1622,52 @@ class XCXCATBEASignaller : XCBase
return result;
}
/**
* Use Specified Box and make it Unavailable ...
*
* @param box: XBoxZone instance reference ...
*/
void UseBox(XBoxZone &box)
{
//
// Validate Box ...
bool has = box.IsValid();
if (!has)
{
return;
}
//
// Check Box Added Before or not ...
int idx = -1;
has = FindBoxIndex(
idx,
box,
unavailableZones //
);
if (has)
{
return;
}
//
// Adding Box Reference to
// Unavailable Zones ...
AddRef(
box,
unavailableZones //
);
//
// Cleanup Array ...
CleanupArray(
unavailableZones,
maxAllowedCollection //
);
//
}
/**
* Use Specified Trigger Block and Make it Un Available ...
*
@@ -1109,11 +1687,7 @@ class XCXCATBEASignaller : XCBase
has = tb.trigger.IsValid();
if (has)
{
//
AddRef(
tb.trigger,
unavailableZones //
);
UseBox(tb.trigger);
}
//
@@ -1121,11 +1695,7 @@ class XCXCATBEASignaller : XCBase
has = tb.ob.IsValid();
if (has)
{
//
AddRef(
tb.ob,
unavailableZones //
);
UseBox(tb.ob);
}
//
@@ -1133,11 +1703,7 @@ class XCXCATBEASignaller : XCBase
has = tb.fvg.IsValid();
if (has)
{
//
AddRef(
tb.fvg,
unavailableZones //
);
UseBox(tb.fvg);
}
//
@@ -1145,11 +1711,7 @@ class XCXCATBEASignaller : XCBase
has = tb.fLiquidity.IsValid();
if (has)
{
//
AddRef(
tb.fLiquidity,
unavailableZones //
);
UseBox(tb.fLiquidity);
}
//
@@ -1157,19 +1719,8 @@ class XCXCATBEASignaller : XCBase
has = tb.rLiquidity.IsValid();
if (has)
{
//
AddRef(
tb.rLiquidity,
unavailableZones //
);
UseBox(tb.rLiquidity);
}
//
// Cleaning Up ...
CleanupArray(
unavailableZones,
maxAllowedCollection //
);
}
/**
@@ -32,9 +32,9 @@
//
enum ENUM_XCATB_PIVOTS
{
XCA_NONE, // None
XCA_PEAK, // Peak
XCA_VALE, // Vale
XCA_NONE, // None
XCA_PEAK, // Peak
XCA_VALE, // Vale
};
//
@@ -1258,6 +1258,45 @@ class XCXCATBEAPOIDetector : public XCBase
return ArraySize(peakPivots);
}
//
int FillPeakPivots(XBoxZone &pivots[])
{
//
int result = 0;
//
Clean(pivots);
//
if (!HasPeakPivots())
{
return result;
}
//
int count = CountPeakPivots();
for (int i = 0; i < count; i++)
{
//
XBoxZone iPivot = peakPivots[i];
//
AddRef(
iPivot,
pivots //
);
//
iPivot.Clean();
}
//
result = ArraySize(pivots);
//
return result;
}
//
// VALE ...
@@ -1279,6 +1318,45 @@ class XCXCATBEAPOIDetector : public XCBase
return ArraySize(valePivots);
}
//
int FillValePivots(XBoxZone &pivots[])
{
//
int result = 0;
//
Clean(pivots);
//
if (!HasValePivots())
{
return result;
}
//
int count = CountValePivots();
for (int i = 0; i < count; i++)
{
//
XBoxZone iPivot = valePivots[i];
//
AddRef(
iPivot,
pivots //
);
//
iPivot.Clean();
}
//
result = ArraySize(pivots);
//
return result;
}
//
// Protected ...
protected:
@@ -275,6 +275,68 @@ struct XCATBEAStrategyConditions
//
};
/**
* Converts Strategy Conditions to Signal ...
*/
bool ToSignal(
XSignal &signal,
XCATBEAStrategyConditions &conditions //
)
{
//
bool result = false;
//
// Normalize Args ...
signal.Clean();
//
// Validate Args ...
result =
conditions.IsValid() &&
conditions.IsSetuped() &&
conditions.CanTrigger();
if (!result)
{
return result;
}
//
// Do Converting ...
signal.volume = 0.01;
signal.tp = conditions.tp;
signal.sl = conditions.sl;
signal.entry = conditions.entry;
signal.symbol = conditions.symbol;
signal.period = conditions.period;
signal.mode = X_ORDER_MODE_MARKET;
signal.time = conditions.triggerTime;
signal.provider = conditions.provider;
signal.type = conditions.type ==
X_POSITION_TYPE_LONG
? POSITION_TYPE_BUY
: POSITION_TYPE_SELL;
signal.conditions = conditions
.conditions
.GenerateSummary(
false,
true,
true,
false // Ignore False Conditions ...
);
Copy(
conditions.targets,
signal.targets //
);
//
// Validate Result ...
result = signal.IsValid();
//
return result;
}
/**
* Detect Signal Zone based on Market Conditions ...
*