Files
MQL5Data/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5
T
2025-10-01 17:59:26 +03:30

1101 lines
28 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class
// -------------------------------------------------
// Name: XCXFIMASignaller ...
// Description: XFIMA Signaller Class ...
//
//
// 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 XFIMA Signaller Class"
#property strict
//
// Imports ...
#include "../../Classes/x-saherelm.x-signaller.class.mq5"
#include "../../Helpers/x-saherelm.xfima.helper.mq5"
#include "../Classes/x-saherelm.xfima.x-poi.detector.class.mq5"
#include "../Classes/x-saherelm.xfima.x-poi.drawer.class.mq5"
//
// Implementation ...
//
// Base XFIMA base Signaller ...
class XCXFIMABaseSignaller : public XCBaseSignaller
{
//
// Public ...
public:
//
// Props ...
//
XFIMAInputs fimaInputs; // XFIMA Inputs ...
XCXFIMAHelper *fimaHelper; // XFIMA Indicator Helper ...
XCXFIMAPOIDrawer *poiDrawer; // XFIMA POI Drawer ...
XCXFIMAPOIDetector *poiDetector; // XFIMA POI Detector ...
//
// Constructor ...
XCXFIMABaseSignaller(
string _name, // Name ...
string _symbol, // Symbol ...
ENUM_TIMEFRAMES _period, // Period ...
XFIMAInputs &_fimaInputs, // XFIMAInputs ...
bool _processAllTicks = false, // Process All Ticks ...
double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ...
double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ...
double _defaultSignalVolume = 0.01 // Default Signal Volume ...
) : XCBaseSignaller(_name,
_symbol,
_period,
_processAllTicks,
_defaultSignalR2R,
_defaultSignalRiskInPoint,
_defaultSignalVolume //
)
{
//
// Instantiating XFIMA Indicator Helper Class ...
if (_fimaInputs.IsValid())
{
//
fimaHelper = new XCXFIMAHelper();
bool isInited = fimaHelper.Init(
_symbol,
_period,
_fimaInputs //
);
if (isInited)
{
fimaInputs = _fimaInputs;
}
else
{
//
delete fimaHelper;
ZeroMemory(fimaHelper);
}
}
//
poiDrawer = new XCXFIMAPOIDrawer();
poiDetector = new XCXFIMAPOIDetector(fimaHelper);
}
//
// Deconstructor ...
~XCXFIMABaseSignaller()
{
Destroy();
}
//
// Overrides ...
//
// Actions ...
/**
* Destroy ...
*/
void Destroy()
{
//
BeforeDestroy();
//
fimaInputs.Clean();
//
delete fimaHelper;
ZeroMemory(fimaHelper);
//
delete poiDrawer;
ZeroMemory(poiDrawer);
//
delete poiDetector;
ZeroMemory(poiDetector);
}
//
// Virtuals ...
/**
* Before Destroy ...
*/
void virtual BeforeDestroy()
{
}
/**
* Processing Tick ...
*
* @param barIndex: int, Specified Bar Index ...
*/
virtual void ProcessTick(int barIndex = 0)
{
}
/**
* Processing New Bar ...
*
* @param barIndex: int, Specified Bar Index ...
*/
virtual void ProcessNewBar(int barIndex = 0)
{
}
/**
* Check Guards Based on MarketConditions ...
*
* @param guards: XGuard, reference collection to holds result ...
* @param positions: XPosition, reference collection to provides positions ...
* @param barIndex: int
*
* @return ( int )
*/
int virtual CheckForGuard(
XGuard &guards[],
XPosition &positions[],
int barIndex = 0 //
)
{
//
int result = 0;
//
SpecifiedClean(guards);
//
result = ArraySize(guards);
//
return result;
}
/**
* Check Additional Validations on Childs Instances ...
*
* @return ( bool virtual )
*/
bool virtual CheckAdditionslSignallerValidations()
{
//
bool result = false;
//
// Validate Fima Helper Requirements ...
result = fimaInputs.IsValid() &&
fimaHelper != NULL &&
poiDetector != NULL;
//
return result;
}
/**
* Normalizing Signal by Signaller Custom Props ...
*
* @param signal: XSignal ...
*/
void virtual NormalizeSignal(XSignal &signal)
{
}
//
// Protected ...
protected:
//
//
// Protected Actions ...
/**
* Check Specified Bar has Pattern or not ...
*
* @param bar: XOHCL, reference to Specified Bar ...
* @param name: string, reference to holds Detected Patterns Name ...
* @param dir: ENUM_X_DIRECTION, reference to holds Detected Patterns Direction ...
* @param structure: XFIMAMarketStructure, refrence to Provides Market Structure ...
*
* @return ( bool )
*/
bool HasPattern(
XOHCL &bar,
string &patternName,
ENUM_X_DIRECTION &patternDir,
XFIMAMarketStructure &structure //
)
{
//
bool result = false;
//
// Prepare ...
patternName = NULL;
patternDir = X_DIRECTION_NONE;
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Required Pattern Exists ...
bool hasPinnedBar = HasDirection(structure.pinnedDir);
bool hasEngulfedBar = HasDirection(structure.engulfedDir);
bool hasFlagPattern = HasDirection(structure.flagPatternDir);
bool hasStarPattern = HasDirection(structure.starPatternDir);
bool hasRisingPattern = HasDirection(structure.risingPatternDir);
bool hasPiercingPattern = HasDirection(structure.piercingPatternDir);
bool hasSignalKeyBar = HasDirection(structure.signalKeyBarPatternDir);
//
// Check Bar Pattern Exists ...
// and Select Pattern Direction and Price and Price Type ...
result = hasPinnedBar ||
hasEngulfedBar ||
hasFlagPattern ||
hasStarPattern ||
hasSignalKeyBar ||
hasRisingPattern ||
hasPiercingPattern;
//
if (result)
{
//
if (hasPinnedBar)
{
//
patternDir = structure.pinnedDir;
patternName = "XPinned_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
else if (hasEngulfedBar)
{
//
patternDir = structure.engulfedDir;
patternName = "XEngulfed_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
else if (hasFlagPattern)
{
//
patternDir = structure.flagPatternDir;
patternName = "XFlag_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
else if (hasStarPattern)
{
//
patternDir = structure.starPatternDir;
patternName = "XStar_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
else if (hasSignalKeyBar)
{
//
patternDir = structure.risingPatternDir;
patternName = "XRising_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
else if (hasRisingPattern)
{
//
patternDir = structure.piercingPatternDir;
patternName = "XPiercing_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
else if (hasPiercingPattern)
{
//
patternDir = structure.signalKeyBarPatternDir;
patternName = "XSignalKey_" + ToXString(patternDir) + ToXString(TimeToSeconds(bar.time));
}
}
//
result =
result &&
IsXValid(patternName) &&
HasDirection(patternDir);
//
return result;
}
/**
* Validate a Pattern based on MA Band ...
*
* @param bar: XOHCL, reference to Pattern Bar ...
* @param patternName: string, detected pattern's name ...
* @param patternDir: ENUM_X_DIRECTION, detected pattern's direction ...
* @param fimaConditions: XFIMAConditions, reference to Bar Specified XFIMA Conditions ...
*
* @return ( bool )
*/
bool ValidatePatternBasedOnMABand(
XOHCL &bar,
string patternName,
ENUM_X_DIRECTION patternDir,
XFIMAConditions &fimaConditions //
)
{
//
bool result = false;
//
// Validate ...
result = bar.IsValid() &&
IsXValid(patternName) &&
HasDirection(patternDir);
if (!result)
{
return result;
}
//
// Define Requirements ...
bool isBullish = false;
bool isBearish = false;
double iPrice = EMPTY_VALUE;
double iPriceEdge = EMPTY_VALUE;
ENUM_X_PRICE iPriceType = X_PRICE_NONE;
ENUM_X_PRICE iPriceEdgeType = X_PRICE_NONE;
//
// Calculating Price and Price Types ...
//
isBullish = IsXBullish(patternDir);
isBearish = IsXBearish(patternDir);
//
iPriceType = isBullish
? X_PRICE_DOWN
: X_PRICE_UP;
//
iPriceEdgeType = isBullish
? X_PRICE_LOW
: X_PRICE_HIGH;
//
iPrice = bar.GetPrice(iPriceType);
iPriceEdge = bar.GetPrice(iPriceEdgeType);
//
// Validate ...
result =
NotEmptyZero(iPrice) &&
IsXValid(iPriceType) &&
NotEmptyZero(iPriceEdge) &&
IsXValid(iPriceEdgeType) &&
((isBullish && !isBearish) ||
(isBearish && !isBullish));
if (!result)
{
return result;
}
//
// Validate Pattern based on MA Band ...
//
// Retrieve MA Band for Validation ...
double iMABandUpper = fimaConditions.maBandUpperBuffer[0];
double iMABandLower = fimaConditions.maBandLowerBuffer[0];
//
// Validate by Edge Price ...
result =
NotEmptyZero(iMABandUpper) &&
NotEmptyZero(iMABandLower) &&
(isBullish
? iPriceEdge < iMABandLower
: iPriceEdge > iMABandUpper);
if (!result)
{
return result;
}
//
return result;
}
//
// Private ...
private:
//
};
//
// XFIMA Strategy 2 Signaller Class ...
class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
{
//
// Public ...
public:
//
// Props ...
XFIMAPatternDetectorConfig analyserConfig;
//
// Constructor ...
XCXFIMAStrategy1Signaller(
string _symbol, // Symbol ...
ENUM_TIMEFRAMES _period, // Period ...
XFIMAInputs &_fimaInputs, // XFIMAInputs ...
bool _processAllTicks = false, // Process All Ticks ...
double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ...
double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ...
double _defaultSignalVolume = 0.01 // Default Signal Volume ...
) : XCXFIMABaseSignaller("XFIMA1",
_symbol,
_period,
_fimaInputs,
_processAllTicks,
_defaultSignalR2R,
_defaultSignalRiskInPoint,
_defaultSignalVolume //
)
{
//
// Configure Detector ...
//
analyserConfig.Default();
analyserConfig.validMACrossDiffMultiplier = 4;
//
analyserConfig.FullDetect();
}
//
// Deconstructor ...
~XCXFIMAStrategy1Signaller()
{
//
Destroy();
//
analyserConfig.Clean();
}
//
// Overrides ...
/**
* Processing Tick ...
*
* @param barIndex: int, Specified Bar Index ...
*/
virtual void ProcessTick(int barIndex = 0)
{
}
/**
* Processing New Bar ...
*
* @param barIndex: int, Specified Bar Index ...
*/
virtual void ProcessNewBar(int barIndex = 0)
{
//
// Normalize ...
barIndex = NormalizeInt(barIndex, 0);
//
XOHCL iBar;
int count = 0;
XBoxZone iZone;
XSignal iSignal;
bool has = false;
XTarget iTargets[];
string iName = NULL;
bool isBullish = false;
bool isBearish = false;
XFIMAConditions iFIMAConditions;
XFIMAMarketStructure iStructure;
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
//
// Initialize Bar as CBar ...
has = iBar.Init(
symbol,
period,
barIndex //
);
if (!has)
{
//
iBar.Clean();
return;
}
//
// Retrieve Conditions ...
has = fimaHelper.GetConditions(
iFIMAConditions,
barIndex,
10 // Loopback ...
);
if (!has)
{
//
iBar.Clean();
iFIMAConditions.Clean();
//
return;
}
//
// Analyse Market ...
poiDetector.AnalyseMarket(
iBar,
iStructure,
analyserConfig //
);
//
// Disable Signallers ...
has = false;
//
// Strategy 1 ...
// Works on Support or Resistances Areas ...
has = Strategy1HasSignal(
iBar,
iZone,
iTargets,
iDir,
iFIMAConditions,
iStructure //
);
//
// Strategy 2 ...
// Works on MA Crosses ...
if (!has)
{
//
// has = Strategy2HasSignal(
// iBar,
// iZone,
// iTargets,
// iDir,
// iFIMAConditions,
// iStructure //
// );
}
//
has = HasDirection(iDir);
if (has)
{
//
isBullish = IsXBullish(iDir);
isBearish = IsXBearish(iDir);
//
// TODO: Provided SL ...
double _point = GetPoints(iBar.symbol);
double slAddition = 5 * _point;
double slPrice =
isBullish
? iZone.lower - slAddition
: iZone.upper + slAddition;
//
// Prepare Founded Signal ...
has = PrepareSignal(
iSignal,
iDir,
iTargets,
0, // Use Default R2R ...
slPrice, // Provided Price for SL ...
0 // Specified Risk in Point ....
);
if (has)
{
//
// Notify On Signal Event ...
NotifySignalEventListeners(iSignal);
}
}
//
// Cleanup Resources ...
iBar.Clean();
iZone.Clean();
iSignal.Clean();
iStructure.Clean();
iFIMAConditions.Clean();
SpecifiedClean(iTargets);
}
/**
* Check Guards Based on MarketConditions ...
*
* @param guards: XGuard, reference collection to holds result ...
* @param positions: XPosition, reference collection to provides positions ...
* @param barIndex: int
*
* @return ( int )
*/
int virtual CheckForGuard(
XGuard &guards[],
XPosition &positions[],
int barIndex = 0 //
)
{
//
int result = 0;
//
SpecifiedClean(guards);
//
result = ArraySize(guards);
//
return result;
}
//
// Private ...
private:
//
// Props ...
//
// Implementing Strategies ...
/**
* Check Bar Has Signal Based on Strategy 1 ...
*
* @param bar: XOHCL, reference to Bar ...
* @param zone: XBoxZone, reference to holds affected zone ...
* @param targets: XTarget, reference to detected Signal's Targets collections ...
* @param dir: ENUM_X_DIRECTION, detected Signal's direction ...
* @param conditions: XFIMAConditions, reference to Bar Specified XFIMA Conditions ...
* @param structure: XFIMAMarketStructure, refrence to Provides Market Structure ...
*
* @return ( bool )
*/
bool Strategy1HasSignal(
XOHCL &bar,
XBoxZone &zone,
XTarget &targets[],
ENUM_X_DIRECTION &dir,
XFIMAConditions &conditions,
XFIMAMarketStructure &structure //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
XClean(targets);
dir = X_DIRECTION_NONE;
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Check Pattern Exists ...
string patternName = NULL;
ENUM_X_DIRECTION patternDir = X_DIRECTION_NONE;
result = HasPattern(
bar,
patternName,
patternDir,
structure //
);
if (!result)
{
return result;
}
//
// Validate Pattern Based on MA Band ...
result = ValidatePatternBasedOnMABand(
bar,
patternName,
patternDir,
conditions //
);
if (!result)
{
return result;
}
//
// Here i Use Specified Supports and Resistances ...
XBoxZone tmpBox;
bool has = false;
XBoxZone supports[];
XBoxZone resistances[];
//
has = structure.pvAnalysis.IsValid() &&
structure.pvAnalysis.HasSupportBox(tmpBox);
if (has)
{
//
tmpBox.to = bar.time;
AddIfNotExists(
tmpBox,
supports //
);
}
//
has = structure.zigzagAnalysis.IsValid() &&
structure.zigzagAnalysis.HasSupportBox(tmpBox);
if (has)
{
//
tmpBox.to = bar.time;
AddIfNotExists(
tmpBox,
supports //
);
}
//
has = structure.pvAnalysis.IsValid() &&
structure.pvAnalysis.HasResistanceBox(tmpBox);
if (has)
{
//
tmpBox.to = bar.time;
AddIfNotExists(
tmpBox,
resistances //
);
}
//
has = structure.zigzagAnalysis.IsValid() &&
structure.zigzagAnalysis.HasResistanceBox(tmpBox);
if (has)
{
//
tmpBox.to = bar.time;
AddIfNotExists(
tmpBox,
resistances //
);
}
//
// Check Affected Zone ...
// Select a Support or Resistance ...
int insideZoneIDX = -1;
result =
(IsXBullish(patternDir)
? HasInside(
insideZoneIDX,
bar,
supports //
)
: IsXBearish(patternDir)
? HasInside(
insideZoneIDX,
bar,
resistances //
)
: false //
);
if (!result)
{
return result;
}
//
// Filling Affected Zone ...
// and Validate it ...
if (IsXBullish(patternDir))
{
zone = supports[insideZoneIDX];
}
else if (IsXBearish(patternDir))
{
zone = resistances[insideZoneIDX];
}
result = zone.IsValid();
if (!result)
{
return result;
}
//
// Validate affected Zone based on Pattern's Bar ...
result = IsXBullish(patternDir)
? bar.high > zone.upper
: IsXBearish(patternDir)
? bar.low < zone.lower
: false;
if (result)
{
//
dir = patternDir;
//
// Handle Targets Detection ...
//
// Check Reversal FVGS ...
int idx = -1;
XTarget target;
XBoxZone targetZones[];
int numberOfTargets = 3;
double actingDistance = 20;
double iValue = EMPTY_VALUE;
bool ignoreFirstTarget = true;
ENUM_X_DIRECTION targetsDir = Opposit(dir);
int count = ExtractByDirection(
targetZones,
structure.fvgs,
targetsDir //
);
bool has = IsValidSize(count);
if (has)
{
//
// Calculate Value ...
double points = GetPoints(zone.symbol);
double zoneRange = zone.upper - zone.lower;
iValue = IsXBullish(dir)
? (zone.upper + (zoneRange * defaultSignalR2R))
: (zone.lower + (zoneRange * defaultSignalR2R));
double defaultTarget = iValue;
//
// Looping Back ...
for (int i = 0; i < numberOfTargets; i++)
{
//
// Detect Lowest Above Zone ...
if (IsXBullish(dir))
{
//
idx = GetLowestAbove(iValue, targetZones);
has = IsValidIndex(idx);
if (!has)
{
break;
}
//
iValue = targetZones[idx].lower;
}
//
// Detect Highest below Zone ...
else if (IsXBearish(dir))
{
//
idx = GetHighestBelow(iValue, targetZones);
has = IsValidIndex(idx);
if (!has)
{
break;
}
//
iValue = targetZones[idx].upper;
}
//
// Validate Target Value ...
has = NotEmptyZero(iValue) &&
iValue != defaultTarget;
if (has)
{
//
// Init Target ...
target.Clean();
target.doRF = true;
target.target = iValue;
target.actingDistance = actingDistance;
has = target.IsValid();
if (has)
{
//
// Add Target to Targets ...
AddRef(
target,
targets //
);
}
target.Clean();
}
}
//
// Remove Nearest ...
has = ignoreFirstTarget &&
HasChild(targets);
if (has)
{
//
ArrayRemove(
targets,
0,
1 //
);
}
}
//
// Cleanup Resources ...
target.Clean();
XClean(targetZones);
}
//
// TODO: Remove this ...
if (result)
{
//
CArrayObj *zoneObjs;
poiDrawer.DrawBoxes(
supports,
zoneObjs //
);
poiDrawer.DrawBoxes(
resistances,
zoneObjs //
);
poiDrawer.DrawBoxes(
structure.fvgs,
zoneObjs,
false //
);
}
//
// Cleanup Resources ...
if (!result)
{
//
zone.Clean();
XClean(targets);
}
//
return result;
}
/**
* Check Bar Has Signal Based on Strategy 1 ...
*
* @param bar: XOHCL, reference to Bar ...
* @param zone: XBoxZone, reference to holds affected zone ...
* @param targets: XTarget, reference to detected Signal's Targets collections ...
* @param dir: ENUM_X_DIRECTION, detected Signal's direction ...
* @param conditions: XFIMAConditions, reference to Bar Specified XFIMA Conditions ...
* @param structure: XFIMAMarketStructure, refrence to Provides Market Structure ...
*
* @return ( bool )
*/
bool Strategy2HasSignal(
XOHCL &bar,
XBoxZone &zone,
XTarget &targets[],
ENUM_X_DIRECTION &dir,
XFIMAConditions &conditions,
XFIMAMarketStructure &structure //
)
{
//
bool result = false;
//
// Prepare ...
zone.Clean();
XClean(targets);
dir = X_DIRECTION_NONE;
//
// Validate ...
result = bar.IsValid();
if (!result)
{
return result;
}
//
// Detect Specified MA Cross ...
result = HasDirection(structure.maCrossDir);
//
// Prepare zone ...
if (result)
{
//
zone.to = bar.time;
zone.from = GetBarTime(
bar.symbol,
bar.period,
bar.Index() + 2 //
);
zone.symbol = bar.symbol;
zone.period = bar.period;
zone.dir = structure.maCrossDir;
zone.lower = bar.FindLowest(2, MODE_LOW);
zone.upper = bar.FindHighest(2, MODE_HIGH);
zone.type = name + "_" + ToXString(structure.maCrossDir);
//
result = zone.IsValid();
}
//
// Check Result ...
if (result)
{
//
dir = structure.maCrossDir;
//
// Handle Targets Detection ...
}
//
// Cleanup Resources ...
if (!result)
{
//
zone.Clean();
XClean(targets);
}
//
return result;
}
//
};
//