Files
MQL5Data/XCATBEA/Classes/xcatbea.signaller.class.mq5
T

2147 lines
63 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class
// -------------------------------------------------
// Name: XCXCATBEASignaller ...
// Description: Class for XCATBEA Signaller ...
//
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property library
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://saherelm.ir"
#property version "1.00"
#property description "SaherElm XCXCATBEASignaller Class"
#property strict
//
// Imports ...
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
#include "../../Classes/x-saherelm.x-guard.class.mq5"
#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5"
#include "../Classes/xcatbea.x-poi.detector.class.mq5"
#include "../Classes/xcatbea.x-poi.drawer.class.mq5"
#include "../Libraries/xcatbea.lib.mq5"
#include "../Libraries/xcatbea.signaller.lib.mq5"
#include "../Libraries/xcatbea.x-poi.extensions.lib.mq5"
//
// Definitions ...
//
// Configure Signalelrs ...
struct XCATBEASignallingConfigs
{
//
// Signalling Method ...
bool allowSignallingBasedOnConditions; // Signalling Based on Market Conditions
bool allowSignallingBasedOnTriggerBlocks; // Signalling Based on Trigger Blocks
bool allowSignallingBasedOnTriggerBlocksInsideOther; // Signalling Based on Trigger Blocks Seccond inputs
//
// Others ...
bool applyValidateAndFilterOnSelectInsideOthers; // Select Trigger Blocks by Applying Validations and Filterss
bool secondsTriggersSLUsingFirstTriggerBlock; // Use First Trigger Block for SL of Seconds Trigger Block Signalss
//
// Market Conditions Signall Providers ...
bool allowSignallingConditions1; // Allow Market Conditions Signaller to Using Sar Starter Signals
bool allowSignallingConditions2; // Allow Market Conditions Signaller to Using Trend Starter Signals
bool allowSignallingConditions3; // Allow Market Conditions Signaller to Using Delta Starter Signals
bool allowSignallingConditions4; // Allow Market Conditions Signaller to Using Volume Starter Signals
bool allowSignallingConditions5; // Allow Market Conditions Signaller to Using Signal Bar Starter Signals
bool allowSignallingConditions6; // Allow Market Conditions Signaller to Using HK Signal Bar Starter Signals
//
// Constructor ...
XCATBEASignallingConfigs()
{
Clean();
}
//
// Tools ...
//
// Cleaning Up ...
void Clean()
{
//
allowSignallingBasedOnConditions = false;
allowSignallingBasedOnTriggerBlocks = false;
allowSignallingBasedOnTriggerBlocksInsideOther = false;
//
secondsTriggersSLUsingFirstTriggerBlock = false;
applyValidateAndFilterOnSelectInsideOthers = false;
//
allowSignallingConditions1 = false;
allowSignallingConditions2 = false;
allowSignallingConditions3 = false;
allowSignallingConditions4 = false;
allowSignallingConditions5 = false;
allowSignallingConditions6 = false;
}
};
//
struct XCATBEASignallerInputs
{
//
// Pros ...
string symbol;
string provider;
bool allowDraws;
bool allowGuards;
int riskToRewardRatio;
ENUM_TIMEFRAMES period;
double slATRMultiplier;
X121XCatbInputs catbInputs;
XTriggerBlockFilters filters;
XTriggerBlockValidationRules validations;
XCATBEASignallingConfigs signallerConfigs;
//
// Constructor(s) ...
XCATBEASignallerInputs()
{
Clean();
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
symbol = NULL;
period = NULL;
provider = NULL;
filters.Clean();
catbInputs.Clean();
allowDraws = false;
validations.Clean();
allowGuards = false;
slATRMultiplier = 0;
riskToRewardRatio = 0;
signallerConfigs.Clean();
//
ZeroMemory(this);
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result =
IsValid(symbol) &&
IsValid(period) &&
IsValid(provider) &&
catbInputs.IsValid() &&
riskToRewardRatio > 0;
//
return result;
}
//
};
//
// Implementations ...
class XCXCATBEASignaller : XCBase
{
//
// Public ...
public:
//
// Props ...
//
bool allowSignallingBasedOnConditions; // Signalling Based on Market Conditions
bool allowSignallingBasedOnTriggerBlocks; // Signalling Based on Trigger Blocks
bool allowSignallingBasedOnTriggerBlocksInsideOther; // Signalling Based on Trigger Blocks Seccond inputs
//
bool secondsTriggersSLUsingFirstTriggerBlock; // Use First Trigger Block for SL of Seconds Trigger Block Signalss
bool applyValidateAndFilterOnSelectInsideOthers; // Select Trigger Blocks by Applying Validations and Filterss
//
// Market Conditions Signall Providers ...
bool allowSignallingConditions1; // Allow Market Conditions Signaller to Using Sar Starter Signals
bool allowSignallingConditions2; // Allow Market Conditions Signaller to Using Trend Starter Signals
bool allowSignallingConditions3; // Allow Market Conditions Signaller to Using Delta Starter Signals
bool allowSignallingConditions4; // Allow Market Conditions Signaller to Using Volume Starter Signals
bool allowSignallingConditions5; // Allow Market Conditions Signaller to Using Signal Bar Starter Signals
bool allowSignallingConditions6; // Allow Market Conditions Signaller to Using HK Signal Bar Starter Signals
//
bool allowDraws; // Allow Draws or not ...
bool allowGuards; // Allow Guards or not ...
int riskToRewardRatio; // Signals R2R ...
double slATRMultiplier; // SL ATR Multiplier ...
//
XBarTracker barTraker; // Bar Tracker ...
XCX121XCatbHelper *helper; // XCATB Helper Class instance ...
XCBarAnalyser *barAnalyser; // Bar Analyser ...
XCXCATBEAPOIDrawer *drawer; // POI Drawer ...
XTriggerBlockFilters filters; // Trigger Block Filters ...
XCXCATBEAPOIDetector *detector; // POI Detector ...
XTriggerBlockValidationRules validations; // Trigger Block Validations ...
//
XBoxZone cPeak; // Current Peak ...
XBoxZone cVale; // Current Vale ...
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 ...
//
XCATBEAStrategyConditions mConditions;
XCATBEAStrategyConditions mConditionsCollection[];
//
// Constructor ...
XCXCATBEASignaller(XCATBEASignallerInputs &inputs)
{
Init(inputs);
}
//
// Deconstructor ...
~XCXCATBEASignaller()
{
DeInit();
}
//
// Properties ...
//
string GetSymbol()
{
return symbol;
}
//
string GetProvider()
{
return provider;
}
//
ENUM_TIMEFRAMES GetPeriod()
{
return period;
}
//
double GetR2R()
{
return riskToRewardRatio;
}
//
// Tick Analyser ...
/**
* Process Tick ...
*/
void ProcessTick(
XPosition &positions[],
XGuard &guards[],
XCATBEAStrategyConditions &conditions,
bool isActiveSession = true //
)
{
//
Clean(guards);
conditions.Clean();
//
XOHCL bar;
int count = 0;
bool has = false;
int barIndex = 0;
cTriggerBlock.Clean();
cInsideTriggerBlock.Clean();
//
// Check Guards ...
has = DetectGuards(
guards,
positions,
barIndex //
);
//
// Check Triggered Conditions ...
has = HasChild(mConditionsCollection);
if (has)
{
//
int selectedIDX = -1;
count = ArraySize(mConditionsCollection);
for (int i = 0; i < count; i++)
{
//
// Select indexed Conditions ...
XCATBEAStrategyConditions iConditions = mConditionsCollection[i];
//
// Check Conditions Triggered ...
has = DetectSignalTrigger(
iConditions,
barIndex //
);
if (has)
{
//
selectedIDX = i;
conditions = iConditions;
iConditions.Clean();
//
break;
}
//
// When Setup Invalidated
// Signaller Clean Conditions ...
if (!has &&
!iConditions.IsValid())
{
//
selectedIDX = i;
break;
}
//
// Cleanup Resources ...
iConditions.Clean();
}
//
// Check Can Trigger ...
has = IsValidIndex(selectedIDX) &&
conditions.IsValid() &&
conditions.IsSetuped() &&
conditions.CanTrigger();
if (has)
{
//
ArrayRemove(
mConditionsCollection,
selectedIDX,
1 //
);
}
else
{
//
// Check Selected Index for Invalid Conditions ...
if (IsValidIndex(selectedIDX))
{
//
// Remove Invalidated Conditions ...
ArrayRemove(
mConditionsCollection,
selectedIDX,
1 //
);
}
//
// Cleanup Resource ...
conditions.Clean();
}
}
//
// Check Bar Processing ...
if (!barTraker.CanProcessBar())
{
return;
}
//
// Initialize Bar ...
bar.Init(
symbol,
period,
barIndex //
);
//
// Detect POI(s) ...
detector.Detect(barIndex);
//
// Validate POI(s) ...
detector.Validate(
unavailableZones,
barIndex //
);
//
// Check Helper Last Changes ...
helper.Check(barIndex);
//
// Draw POI(s) ...
if (allowDraws)
{
// drawer.Draw(bar.time);
}
//
// Detect Trigger Blocks and Collect them ...
XTriggerBlock iTriggerBlock;
X121XCatbConditions iConditions;
XTriggerBlockFilters iFilters;
XTriggerBlockValidationRules iValidations;
if (applyValidateAndFilterOnSelectInsideOthers)
{
//
// Validations ...
iValidations.forceHasSwing = validations.forceHasSwing;
iValidations.forceOBBarType = validations.forceOBBarType;
iValidations.forceFVGBarType = validations.forceFVGBarType;
iValidations.maxAllowedRange = validations.maxAllowedRange;
iValidations.minAllowedRange = validations.minAllowedRange;
iValidations.minRequiredOBBar = validations.minRequiredOBBar;
iValidations.liquidityLoopback = validations.liquidityLoopback;
iValidations.forceHasFLiquidity = validations.forceHasFLiquidity;
iValidations.forceHasRLiquidity = validations.forceHasRLiquidity;
iValidations.validateGapSequence = validations.validateGapSequence;
iValidations.minAllowedBlockLength = validations.minAllowedBlockLength;
iValidations.validateBlockEdgeBreakout = validations.validateBlockEdgeBreakout;
//
// Clone Filters and Validations ...
iFilters.bosLoopback = filters.bosLoopback;
iFilters.filterBasedOnKI = filters.filterBasedOnKI;
iFilters.filterBasedOnPV = filters.filterBasedOnPV;
iFilters.filterBasedOnSar = filters.filterBasedOnSar;
iFilters.filterBasedOnRSI = filters.filterBasedOnRSI;
iFilters.filterBasedOnADX = filters.filterBasedOnADX;
iFilters.filterBasedOnATR = filters.filterBasedOnATR;
iFilters.forceSarSwitched = filters.forceSarSwitched;
iFilters.forceHasTrendDir = filters.forceHasTrendDir;
iFilters.filterBasedOnTrend = filters.filterBasedOnTrend;
iFilters.filterBasedOnDelta = filters.filterBasedOnDelta;
iFilters.forceSarOnBothSide = filters.forceSarOnBothSide;
iFilters.forceHasTrendPlace = filters.forceHasTrendPlace;
iFilters.forceSarHasBreakout = filters.forceSarHasBreakout;
iFilters.filterBasedOnVolume = filters.filterBasedOnVolume;
iFilters.forceHasRSITrending = filters.forceHasRSITrending;
iFilters.forceHasRSIVPattern = filters.forceHasRSIVPattern;
iFilters.forceHasRSICrossing = filters.forceHasRSICrossing;
iFilters.forceHasADXTrending = filters.forceHasADXTrending;
iFilters.forceHasADXCrossing = filters.forceHasADXCrossing;
iFilters.forceHasATRTrending = filters.forceHasATRTrending;
iFilters.forceHasATRBreakout = filters.forceHasATRBreakout;
iFilters.forceHasTrendChange = filters.forceHasTrendChange;
iFilters.forceHasTrendTrending = filters.forceHasTrendTrending;
iFilters.forceHasTrendRejection = filters.forceHasTrendRejection;
iFilters.filterBasedOnSignalBar = filters.filterBasedOnSignalBar;
iFilters.forceHasTrendLineInside = filters.forceHasTrendLineInside;
iFilters.forceSarHasReversalSide = filters.forceSarHasReversalSide;
iFilters.filterBasedOnHKSignalBar = filters.filterBasedOnHKSignalBar;
iFilters.forceHasTrendDirOnBothSide = filters.forceHasTrendDirOnBothSide;
}
has = DetectTriggerBlock(
helper,
barAnalyser,
iTriggerBlock,
iConditions,
iValidations,
iFilters,
barIndex,
10 // Loopback ...
);
if (has)
{
//
// Add Trigger Block to Collection if not Exists ...
AddIfNotExists(
iTriggerBlock,
triggerBlocks //
);
}
iFilters.Clean();
iConditions.Clean();
iValidations.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
// Session actives ...
// for improvement Calculation Speeds ...
if (isActiveSession)
{
//
// Check Signal Setups ...
has = DetectSignalSetup(barIndex);
if (has)
{
//
barTraker.Waits();
//
AddConditionsIfNotExists();
//
mConditions.Clean();
}
}
//
// Cleanup Resources ...
bar.Clean();
}
//
// Signalling Tools ...
/**
* Detect Setup Conditions based on Signalling ...
*
* @param maxAllowedSLDistanceInPoint: int, Max Allowed SL Distance in Points (if Bigger thn Zero Provided) ...
*
* @return ( bool )
*/
bool DetectSignalSetup(int barIndex = 0)
{
//
bool result = false;
//
// Normalize Args ...
barIndex = NormalizeInt(barIndex, 0);
//
// Update All Required Buffers ...
helper.Update(barIndex);
//
bool has = false;
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 < cBar.low;
if (isValid)
{
break;
}
//
cVale.Clean();
}
Clean(tmpVales);
}
}
//
// Detect Signal Setup Based on Market Conditions ...
if (!result &&
allowSignallingBasedOnConditions)
{
//
// Detect Signalling Zone ...
result = DetectSignalZone(
helper,
drawer,
detector,
barAnalyser,
mConditions.conditions,
mConditions.pivotZone,
allowSignallingConditions1,
allowSignallingConditions2,
allowSignallingConditions3,
allowSignallingConditions4,
allowSignallingConditions5,
allowSignallingConditions6,
barIndex,
10 // Loopback ...
);
if (result)
{
//
// Use Signal Zone ...
UseBox(mConditions.pivotZone);
//
// Prepare Condition ...
//
// Prepare Signal ...
mConditions.dir =
mConditions
.pivotZone
.dir;
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 ...
XSignal iSignal;
result = ToSignal(
mConditions.pivotZone,
iSignal,
targets,
slAdditional //
);
if (result)
{
//
mConditions.sl = iSignal.sl;
mConditions.tp = iSignal.tp;
mConditions.pivot = iSignal.sl;
mConditions.entry = iSignal.entry;
mConditions.point = iSignal.entry;
mConditions.type = ToPositionType(iSignal.type);
//
// Draw Trigger Block ...
if (allowDraws)
{
//
XCBoxObject *iObj;
has = drawer
.drawer
.DrawBox(
mConditions.pivotZone,
iObj //
);
if (has)
{
mObjects.Add(iObj);
}
ZeroMemory(iObj);
}
}
iSignal.Clean();
}
}
//
// 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);
//
// 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 //
);
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)
{
//
// Trigger Block Detection ...
result = HasChild(triggerBlocks) &&
ArraySize(triggerBlocks) > 1 &&
!waitsUntilPeakInvalidate &&
!waitsUntilValeInvalidate;
if (result)
{
//
// 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);
//
// Check Trigger Block Selection ...
result = isTriggerBlockSelected;
if (result)
{
//
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)
{
//
// Now we Have to Detect Peak and Vales ...
result =
cPeak.IsValid() &&
cVale.IsValid();
//
// If Exists Before Validate them based Trigger Blocks ...
if (result)
{
//
// 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);
//
// Update Peak and Vales To ...
cPeak.to = cTime;
cVale.to = cTime;
//
// Draw Peak and Vales ...
if (allowDraws)
{
//
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 ...
//
double iPeak = helper.GetPeak(i);
double iPPeak = helper.GetPeak(i + 1);
//
double iVale = helper.GetVale(i);
double iPVale = helper.GetVale(i + 1);
//
bool isPeakOverLast = iPeak > iPPeak;
bool isPeakUnderLast = iPeak < iPPeak;
//
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 ...
//
// mObjects.Clear();
//
// Detected Block ...
DrawTriggerBlock(
cTriggerBlock,
drawer.drawer,
mObjects,
cTime,
false // Draw Signal ...
);
//
// Inside Block ...
DrawTriggerBlock(
cInsideTriggerBlock,
drawer.drawer,
mObjects,
cTime,
false // Draw Signal ...
);
}
//
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;
if (secondsTriggersSLUsingFirstTriggerBlock)
{
//
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 ...
);
}
}
}
}
//
// Check a Signal Setup Exists or not ...
result = mConditions.IsValid() &&
mConditions.IsSetuped();
//
// Cleanup Resource ...
zBar.Clean();
cBar.Clean();
cTriggerBlock.Clean();
cInsideTriggerBlock.Clean();
//
return result;
}
/**
* Detect Trigger Conditions for Specified Signal ...
*
* @param conditions: XCATBEAStrategyConditions instance Reference, Specified Signal Conditions ...
* @param maxAllowedSetupAge: specified Setup Age for Expiration (if bigger than Zero) ...
*
* @return ( bool )
*/
bool DetectSignalTrigger(
XCATBEAStrategyConditions &conditions,
int barIndex = 0 //
)
{
//
bool result = false;
//
// Normalize Args ...
barIndex = NormalizeInt(barIndex, 0);
//
// Validate Setup ...
result = conditions.IsSetuped();
if (!result)
{
return result;
}
//
bool has = false;
datetime cTime = TimeCurrent();
bool isBullish = IsBullish(conditions.dir);
bool isBearish = IsBearish(conditions.dir);
//
bool isBasedOnPivotZone = conditions.pivotZone.IsValid();
bool isBasedOnTriggerBlock = conditions.triggerBlock.IsValid();
//
// Reading Current Market Conditions ...
X121XCatbConditions cConditions;
result =
result &&
helper.GetConditions(
cConditions,
barIndex,
10 //
);
//
// Validate Direction of Setuped Conditions ...
result =
result &&
(isBullish ||
isBearish);
//
// Detecting Trigger Bar ...
//
ENUM_X_DIRECTION triggerDir;
bool isTriggerBar = barAnalyser
.IsValidForTrigger(
cConditions.bars[0],
triggerDir,
false, // Allow Cond 1 ...
false, // Allow Cond 2 ...
false, // Allow Cond 3 ...
false, // Allow Cond 4 ...
false, // Allow Cond 5 ...
false, // Allow Cond 6 ...
true // Allow Cond 7 ...
//
);
bool isBullishTriggerBar =
isTriggerBar &&
IsBullish(triggerDir);
bool isBearishTriggerBar =
isTriggerBar &&
IsBearish(triggerDir);
//
// Do Triggering Senario based on Trigger Block ...
if (result &&
isBasedOnTriggerBlock)
{
//
// Checking Score ...
double bullishScore = 0;
double bearishScore = 0;
conditions
.conditions
.GenerateScore(
bullishScore,
bearishScore //
);
bool isScorePassed =
isBullish
? bullishScore > bearishScore
: bearishScore > bullishScore;
//
// Complete Conditions Here ...
if (isScorePassed)
{
conditions.triggerTime = TimeCurrent();
}
}
//
// Do Triggering based on Market Conditions PivotZones ...
if (result &&
isBasedOnPivotZone)
{
//
// Update Box To ...
conditions.pivotZone.to = cTime;
//
// Draw Box ...
XCBoxObject *iObj;
has = drawer
.drawer
.DrawBox(
conditions.pivotZone,
iObj //
);
if (has)
{
mObjects.Add(iObj);
}
//
// Check atleast 3 Bars Close Outside of applied Edge ...
// Check Current Bar is a Trigger Bar ...
// TODO: Complete this ...
//
}
//
// Do Other Validation Senarios ...
//
result = conditions.IsValid() &&
conditions.IsSetuped() &&
conditions.CanTrigger();
//
// Check Setup Age or Setup Validations here ...
if (!result)
{
//
// Validate Trigger Block Based Setups ...
//
// Validate Pivot Zone Based Setups ...
//
// Validate Setup Age ...
}
//
// Cleanup Resources ...
//
return result;
}
/**
* Detect Guards bsed on Signalling Class ...
*
* @param guards: XCAEAGuard instance Collection, Holds Provided Guards ...
* @param positions: XPosition instance Collection, Provides Signalling Based Positions for Apply Guards on them ...
* @param provider: X121SMCStrategySignalProviderData instance Reference, Specified Data for Cycles ...
*
* @return ( bool )
*/
bool DetectGuards(
XGuard &guards[],
const XPosition &positions[],
int barIndex = 0 //
)
{
//
bool result = false;
//
// Normalize Args ...
Clean(guards);
barIndex = NormalizeInt(barIndex, 0);
//
result = allowGuards &&
HasChild(positions);
if (!result)
{
return result;
}
//
// TODO: Implement this ...
//
result = HasChild(guards);
//
// Cleanup Resources ...
//
if (!result)
{
Clean(guards);
}
//
return result;
}
//
// Protected ...
protected:
//
/**
* Initialize ...
*/
void Init(XCATBEASignallerInputs &inputs)
{
//
maxAllowedCollection = 100;
//
allowSignallingBasedOnConditions = inputs.signallerConfigs.allowSignallingBasedOnConditions;
allowSignallingBasedOnTriggerBlocks = inputs.signallerConfigs.allowSignallingBasedOnTriggerBlocks;
allowSignallingBasedOnTriggerBlocksInsideOther = inputs.signallerConfigs.allowSignallingBasedOnTriggerBlocksInsideOther;
//
secondsTriggersSLUsingFirstTriggerBlock = inputs.signallerConfigs.secondsTriggersSLUsingFirstTriggerBlock;
applyValidateAndFilterOnSelectInsideOthers = inputs.signallerConfigs.applyValidateAndFilterOnSelectInsideOthers;
//
allowSignallingConditions1 = inputs.signallerConfigs.allowSignallingConditions1;
allowSignallingConditions2 = inputs.signallerConfigs.allowSignallingConditions2;
allowSignallingConditions3 = inputs.signallerConfigs.allowSignallingConditions3;
allowSignallingConditions4 = inputs.signallerConfigs.allowSignallingConditions4;
allowSignallingConditions5 = inputs.signallerConfigs.allowSignallingConditions5;
allowSignallingConditions6 = inputs.signallerConfigs.allowSignallingConditions6;
//
bool has = inputs.IsValid();
if (!has)
{
return;
}
//
symbol = inputs.symbol;
period = inputs.period;
filters = inputs.filters;
provider = inputs.provider;
allowDraws = inputs.allowDraws;
allowGuards = inputs.allowGuards;
validations = inputs.validations;
slATRMultiplier = inputs.slATRMultiplier;
riskToRewardRatio = inputs.riskToRewardRatio;
//
mObjects = new CArrayObj();
//
// Initialize Bar Tracker ...
has = barTraker.Init(
symbol,
period //
);
if (!has)
{
return;
}
//
// Initialize Bar Analyser ...
barAnalyser = new XCBarAnalyser();
//
// initialize Helper ...
helper = new XCX121XCatbHelper();
has = helper.Init(
symbol,
period,
inputs.catbInputs //
);
if (!has)
{
return;
}
//
mConditions.Clean();
Clean(mConditionsCollection);
//
InitPOI();
}
/**
* DeInitialize ...
*/
void DeInit()
{
//
mObjects.Clear();
delete mObjects;
ZeroMemory(mObjects);
//
drawer.Clear();
delete drawer;
ZeroMemory(drawer);
//
detector.CleanPivots();
delete detector;
ZeroMemory(detector);
//
delete helper;
ZeroMemory(helper);
//
delete barAnalyser;
ZeroMemory(barAnalyser);
//
barTraker.Clean();
}
/**
* Add Conditions to Conditions Collection if not Exists ...
*
* @param maxAllowed: int, Specified Max Allowed Holding Conditions ...
*
* @return ( int )
*/
int AddConditionsIfNotExists(
int maxAllowed = 50 //
)
{
//
int result = 0;
//
// Normalize Args ...
maxAllowed = maxAllowedCollection;
//
bool isSetuped = IsValid(mConditions.setupTime) &&
HasDirection(mConditions.dir);
if (!isSetuped)
{
return result;
}
//
int count = ArraySize(mConditionsCollection);
if (IsValidSize(count))
{
//
// Copy Original Items ...
XCATBEAStrategyConditions tmpItems[];
Copy(
mConditionsCollection,
tmpItems //
);
//
// Prese Item Data ...
bool isBullish = IsBullish(mConditions.dir);
//
for (int i = 0; i < count; i++)
{
//
XCATBEAStrategyConditions iItem = tmpItems[i];
//
bool canRemove = mConditions.dir == iItem.dir &&
mConditions.pivot == iItem.pivot;
if (canRemove)
{
//
ArrayRemove(
mConditionsCollection,
i,
1 //
);
}
}
//
Clean(tmpItems);
}
//
AddRef(
mConditions,
mConditionsCollection //
);
//
// Remove Olds ...
CleanupArray(
mConditionsCollection,
maxAllowed //
);
//
result = ArraySize(mConditionsCollection);
//
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 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 ...
*
* @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)
{
UseBox(tb.trigger);
}
//
// Order Block Box ...
has = tb.ob.IsValid();
if (has)
{
UseBox(tb.ob);
}
//
// Fair Value Gap ...
has = tb.fvg.IsValid();
if (has)
{
UseBox(tb.fvg);
}
//
// Following Liquidity ...
has = tb.fLiquidity.IsValid();
if (has)
{
UseBox(tb.fLiquidity);
}
//
// Reversal Liquidity ...
has = tb.rLiquidity.IsValid();
if (has)
{
UseBox(tb.rLiquidity);
}
}
/**
* 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:
//
// Props ...
string symbol;
string provider;
CArrayObj *mObjects;
ENUM_TIMEFRAMES period;
int maxAllowedCollection; // Max Allowed Collection Items ...
//
// Initialize and Configure POI Detector and Drawer ...
void InitPOI()
{
//
// Initialize POI Detector ...
bool has = helper != NULL;
if (has)
{
//
detector = new XCXCATBEAPOIDetector(helper);
//
// Configure ...
//
detector.detectPeakPivots = true;
detector.detectValePivots = true;
//
detector.detectMTBullishPivots = true;
detector.detectMTBearishPivots = true;
//
detector.detectOBBullishPivots = true;
detector.detectOBBearishPivots = true;
}
//
// Initialize POI Drawer ...
has = detector != NULL;
if (has)
{
//
drawer = new XCXCATBEAPOIDrawer(detector);
//
// Configure ...
drawer.drawPeakPivots = true;
drawer.drawValePivots = true;
//
XCATBPivotStyle iStyle;
//
// Styling Peak Pivot ...
iStyle.width = 1;
iStyle.clr = clrMagenta;
iStyle.style = STYLE_SOLID;
//
drawer.peakPivotStyle = iStyle;
//
// Styling Vale Pivot ...
iStyle.width = 1;
iStyle.clr = clrAqua;
iStyle.style = STYLE_SOLID;
//
drawer.valePivotStyle = iStyle;
//
// Cleanup Resources ...
//
iStyle.Clean();
}
}
//
};
//