3174 lines
87 KiB
Plaintext
3174 lines
87 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.parser.class.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 ...
|
|
|
|
//
|
|
CArrayObj drawnObjects; // Drawing Objects Holder ...
|
|
XFIMAInputs fimaInputs; // XFIMA Inputs ...
|
|
XCXFIMAHelper *fimaHelper; // XFIMA Indicator Helper ...
|
|
XCXFIMAPOIDrawer *poiDrawer; // XFIMA POI Drawer ...
|
|
XCXFIMAHelperParser *fimaParser; // XFIMA Helper Parser ...
|
|
XCXFIMAPOIDetector *poiDetector; // XFIMA POI Detector ...
|
|
XFIMAMarketStructureConfig structureConfig; // XFIMA Market Structure Detector Config ...
|
|
XFIMAMarketStructureDrawerConfig structureDrawConfig; // XFIMA Market Structure Draw Config ...
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Instantiate XFIMA Helper Parser ...
|
|
fimaParser = new XCXFIMAHelperParser(fimaHelper);
|
|
|
|
//
|
|
poiDrawer = new XCXFIMAPOIDrawer();
|
|
poiDetector = new XCXFIMAPOIDetector(fimaHelper, fimaParser);
|
|
|
|
//
|
|
// Configure ...
|
|
structureConfig.Default();
|
|
structureDrawConfig.Default();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCXFIMABaseSignaller()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
/**
|
|
* Destroy ...
|
|
*/
|
|
void Destroy()
|
|
{
|
|
//
|
|
BeforeDestroy();
|
|
|
|
//
|
|
fimaInputs.Clean();
|
|
|
|
//
|
|
delete fimaHelper;
|
|
ZeroMemory(fimaHelper);
|
|
|
|
//
|
|
delete poiDrawer;
|
|
ZeroMemory(poiDrawer);
|
|
|
|
//
|
|
delete poiDetector;
|
|
ZeroMemory(poiDetector);
|
|
|
|
//
|
|
structureConfig.Clean();
|
|
structureDrawConfig.Clean();
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Normalizing Signal by Signaller Custom Props ...
|
|
*
|
|
* @param signal: XSignal ...
|
|
*/
|
|
void virtual NormalizeSignal(XSignal &signal)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
|
|
//
|
|
// Protected Actions ...
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
};
|
|
|
|
//
|
|
// XFIMA Strategy 2 Signaller Class ...
|
|
class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// 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 //
|
|
)
|
|
{
|
|
//
|
|
structureConfig.Default();
|
|
structureDrawConfig.Default();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCXFIMAStrategy1Signaller()
|
|
{
|
|
//
|
|
Destroy();
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
XBoxZone iZone;
|
|
XSignal iSignal;
|
|
bool has = false;
|
|
XTarget iTargets[];
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
ENUM_X_DIRECTION iDir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Initialize Bar as CBar ...
|
|
has = iBar.Init(
|
|
symbol,
|
|
period,
|
|
barIndex //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Strategy X ...
|
|
has = HasSignal(
|
|
iBar,
|
|
iZone,
|
|
iTargets,
|
|
iDir //
|
|
);
|
|
|
|
//
|
|
// Handle Resting Signals ...
|
|
has = HasDirection(iDir) &&
|
|
iZone.IsValid();
|
|
|
|
//
|
|
// Prepare Signal ...
|
|
if (has)
|
|
{
|
|
//
|
|
isBullish = IsXBullish(iDir);
|
|
isBearish = IsXBearish(iDir);
|
|
|
|
//
|
|
// Provided SL ...
|
|
double points = GetPoints(symbol);
|
|
double spread = GetSpread(symbol);
|
|
double entry = GetEntry(symbol, iDir);
|
|
|
|
//
|
|
// Calculate SL Addition ...
|
|
double slAddition =
|
|
slAdditionDistance <= 0
|
|
? 0
|
|
: slAdditionDistance * points;
|
|
|
|
//
|
|
// Calculate SL Price ...
|
|
double sl =
|
|
isBullish
|
|
? iZone.lower - slAddition
|
|
: iZone.upper + slAddition;
|
|
|
|
//
|
|
// Prepare Signal ...
|
|
has = PrepareSignal(
|
|
iSignal,
|
|
iDir,
|
|
iTargets,
|
|
0, // Use Default R2R ...
|
|
sl, // Provided Price for SL ...
|
|
0 // Specified Risk in Point ....
|
|
);
|
|
}
|
|
|
|
//
|
|
// Notify On Signal Event ...
|
|
if (has)
|
|
{
|
|
NotifySignalEventListeners(iSignal);
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
iBar.Clean();
|
|
iZone.Clean();
|
|
iSignal.Clean();
|
|
XClean(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;
|
|
|
|
//
|
|
XClean(guards);
|
|
return result;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Requirements ...
|
|
XGuard iGuard;
|
|
bool has = false;
|
|
int samePeaks = 0;
|
|
int sameVales = 0;
|
|
double iValue = 0;
|
|
double points10 = 0;
|
|
double points50 = 0;
|
|
double points100 = 0;
|
|
int samePVValidation = 5;
|
|
bool isPeakOverLast = false;
|
|
bool isValeUnderLast = false;
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
points10 = 10 * positions[i].GetPointsValue();
|
|
points50 = 50 * positions[i].GetPointsValue();
|
|
points100 = 100 * positions[i].GetPointsValue();
|
|
|
|
//
|
|
// Near to TP Guard ...
|
|
has = positions[i].profit > 0;
|
|
if (has)
|
|
{
|
|
//
|
|
// Has Same Peaks or Vales ...
|
|
samePeaks = fimaParser.CountSamePeaks(barIndex);
|
|
sameVales = fimaParser.CountSameVales(barIndex);
|
|
isPeakOverLast = (fimaParser.IsPeakOverLast(barIndex) ||
|
|
fimaParser.IsPeakOverLast(barIndex + 1));
|
|
isValeUnderLast = (fimaParser.IsValeUnderLast(barIndex) ||
|
|
fimaParser.IsValeUnderLast(barIndex + 1));
|
|
has = (positions[i].IsBullish()
|
|
? (
|
|
isPeakOverLast &&
|
|
sameVales >= samePVValidation &&
|
|
fimaHelper.GetVale(barIndex) > positions[i].sl)
|
|
: positions[i].IsBearish()
|
|
? (
|
|
isValeUnderLast &&
|
|
samePeaks >= samePVValidation &&
|
|
fimaHelper.GetPeak(barIndex) < positions[i].sl)
|
|
: false);
|
|
if (has)
|
|
{
|
|
//
|
|
iGuard.Clean();
|
|
iGuard.time = TimeCurrent();
|
|
iGuard.symbol = positions[i].symbol;
|
|
iGuard.period = positions[i].period;
|
|
iGuard.ticket = positions[i].ticket;
|
|
iGuard.provider = positions[i].provider;
|
|
iGuard.sl = positions[i].IsBullish()
|
|
? fimaHelper.GetVale(barIndex) - points10
|
|
: fimaHelper.GetPeak(barIndex) + points10;
|
|
iGuard.action = X_GUARD_ACTION_TRAIL_STOP;
|
|
|
|
//
|
|
has = iGuard.IsValid();
|
|
if (has)
|
|
{
|
|
//
|
|
AddRef(iGuard, guards);
|
|
|
|
//
|
|
// //
|
|
// // Remove TP if in Profit SL ...
|
|
// iValue = (positions[i].IsBullish() ? positions[i].entry + points10 : positions[i].entry - points10);
|
|
// has =
|
|
// (positions[i].IsBullish() && HasResistance())
|
|
// ? (iGuard.sl >= iValue &&
|
|
// positions[i].tp < resistance.lower)
|
|
// : (positions[i].IsBearish() && HasSupport())
|
|
// ? (iGuard.sl <= iValue &&
|
|
// positions[i].tp > support.upper)
|
|
// : false;
|
|
// if (has)
|
|
// {
|
|
// //
|
|
// iGuard.Clean();
|
|
// iGuard.force = false;
|
|
// iGuard.tp = positions[i].IsBullish()
|
|
// ? resistance.lower
|
|
// : support.upper;
|
|
// iGuard.time = TimeCurrent();
|
|
// iGuard.symbol = positions[i].symbol;
|
|
// iGuard.period = positions[i].period;
|
|
// iGuard.ticket = positions[i].ticket;
|
|
// iGuard.provider = positions[i].provider;
|
|
// iGuard.action = X_GUARD_ACTION_TRAIL_TARGET;
|
|
|
|
// //
|
|
// has = iGuard.IsValid();
|
|
// if (has)
|
|
// {
|
|
// AddRef(iGuard, guards);
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(guards);
|
|
|
|
//
|
|
// Cleanup ...
|
|
iGuard.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Implementing Strategies ...
|
|
|
|
/**
|
|
* Check Bar Has Signal Based on Strategy X ...
|
|
*
|
|
* @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 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSignal(
|
|
XOHCL &bar,
|
|
XBoxZone &zone,
|
|
XTarget &targets[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Configuration Flags ...
|
|
|
|
//
|
|
// Signaller Flags ...
|
|
bool useSignaller1 = true;
|
|
bool useSignaller2 = false;
|
|
bool useSignaller3 = false;
|
|
bool useSignaller4 = false;
|
|
|
|
//
|
|
XBoxZone tmpZone;
|
|
string provider = NULL;
|
|
ENUM_X_DIRECTION tmpDir;
|
|
|
|
//
|
|
bool signaller1HasSignal = false;
|
|
bool signaller2HasSignal = false;
|
|
bool signaller3HasSignal = false;
|
|
bool signaller4HasSignal = false;
|
|
|
|
//
|
|
// Validator Flags ...
|
|
bool validateByOrderFlow = false;
|
|
|
|
//
|
|
// Target Flags ...
|
|
bool hasPartialCloseOnTp1 = false;
|
|
|
|
//
|
|
bool doRFOnEntryOnTP1 = false;
|
|
|
|
//
|
|
// Draw Flags ...
|
|
bool draw = true;
|
|
bool drawZone = true;
|
|
bool drawMarketStructurePivots = false;
|
|
bool drawMarketStructureAnalysis = false;
|
|
bool drawMarketStructureOrderFlow = false;
|
|
XPOIDrawConfig iDrawConfig;
|
|
|
|
//
|
|
// Signal Checking ...
|
|
|
|
//
|
|
// Analyse Market Strucutre ...
|
|
XFIMAMarketStructure marketStructure;
|
|
|
|
//
|
|
// Signal Detection Flags ...
|
|
|
|
//
|
|
// Signaller 1 ...
|
|
if (useSignaller1)
|
|
{
|
|
//
|
|
signaller1HasSignal = Strategy1HasSignal(
|
|
bar,
|
|
tmpZone,
|
|
targets,
|
|
tmpDir //
|
|
);
|
|
|
|
//
|
|
if (signaller1HasSignal)
|
|
{
|
|
//
|
|
provider += "1";
|
|
|
|
//
|
|
if (!zone.IsValid())
|
|
{
|
|
//
|
|
dir = tmpDir;
|
|
zone = tmpZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpZone.Clean();
|
|
tmpDir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
// Signaller 2 ...
|
|
if (useSignaller2)
|
|
{
|
|
//
|
|
signaller2HasSignal = Strategy2HasSignal(
|
|
bar,
|
|
tmpZone,
|
|
targets,
|
|
tmpDir //
|
|
);
|
|
|
|
//
|
|
if (signaller2HasSignal)
|
|
{
|
|
//
|
|
provider += "2";
|
|
|
|
//
|
|
if (!zone.IsValid())
|
|
{
|
|
//
|
|
dir = tmpDir;
|
|
zone = tmpZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpZone.Clean();
|
|
tmpDir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
// Signaller 3 ...
|
|
if (useSignaller3)
|
|
{
|
|
//
|
|
signaller3HasSignal = Strategy3HasSignal(
|
|
bar,
|
|
tmpZone,
|
|
targets,
|
|
tmpDir //
|
|
);
|
|
|
|
//
|
|
if (signaller3HasSignal)
|
|
{
|
|
//
|
|
provider += "3";
|
|
|
|
//
|
|
if (!zone.IsValid())
|
|
{
|
|
//
|
|
dir = tmpDir;
|
|
zone = tmpZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpZone.Clean();
|
|
tmpDir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
// Signaller 4 ...
|
|
if (useSignaller4)
|
|
{
|
|
//
|
|
signaller4HasSignal = Strategy4HasSignal(
|
|
bar,
|
|
tmpZone,
|
|
targets,
|
|
tmpDir //
|
|
);
|
|
|
|
//
|
|
if (signaller4HasSignal)
|
|
{
|
|
//
|
|
provider += "4";
|
|
|
|
//
|
|
if (!zone.IsValid())
|
|
{
|
|
//
|
|
dir = tmpDir;
|
|
zone = tmpZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpZone.Clean();
|
|
tmpDir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
// Summarize Signallers Result ...
|
|
result = signaller1HasSignal ||
|
|
signaller2HasSignal ||
|
|
signaller3HasSignal ||
|
|
signaller4HasSignal;
|
|
|
|
//
|
|
// Signal Validating ...
|
|
|
|
//
|
|
// Validate Signals by Order Flow ...
|
|
if (result && validateByOrderFlow)
|
|
{
|
|
//
|
|
// Analyse Market Structure if Required ...
|
|
if (!marketStructure.IsValid())
|
|
{
|
|
//
|
|
poiDetector.AnalyseMarket(
|
|
marketStructure,
|
|
structureConfig,
|
|
bar.Index() //
|
|
);
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsXBullish(dir) &&
|
|
marketStructure.HasBullishOrderFlow();
|
|
|
|
//
|
|
bool isBearish = IsXBearish(dir) &&
|
|
marketStructure.HasBearishOrderFlow();
|
|
|
|
//
|
|
// Summarizing result ...
|
|
result = isBullish ||
|
|
isBearish;
|
|
}
|
|
|
|
//
|
|
// Targets, Restrictions and Risk Management ...
|
|
if (result)
|
|
{
|
|
//
|
|
// Requirements ...
|
|
XTarget iTarget;
|
|
|
|
//
|
|
// Checking Direction of Signal ...
|
|
bool isBullish = IsXBullish(dir);
|
|
bool isBearish = IsXBearish(dir);
|
|
|
|
//
|
|
// Provided SL ...
|
|
double points = GetPoints(symbol);
|
|
double spread = GetSpread(symbol);
|
|
double entry = GetEntry(symbol, dir);
|
|
|
|
//
|
|
// Calculate SL Addition ...
|
|
double slAddition =
|
|
slAdditionDistance <= 0
|
|
? 0
|
|
: slAdditionDistance * points;
|
|
|
|
//
|
|
// Calculate SL Price ...
|
|
double sl =
|
|
isBullish
|
|
? zone.lower - slAddition
|
|
: zone.upper + slAddition;
|
|
|
|
//
|
|
// Calculate Risk ...
|
|
double risk = MathAbs(entry - sl);
|
|
|
|
//
|
|
// Calculate Reward ...
|
|
double reward = defaultSignalR2R * risk;
|
|
|
|
//
|
|
// Calculate TP1 ...
|
|
double tp1 = isBullish
|
|
? entry + risk
|
|
: entry - risk;
|
|
double tp2 = isBullish
|
|
? entry + (2 * risk)
|
|
: entry - (2 * risk);
|
|
|
|
//
|
|
// Calculate TP ...
|
|
double tp = isBullish
|
|
? entry + reward
|
|
: entry - reward;
|
|
|
|
//
|
|
// Check Max Allowed Risk ...
|
|
bool hasTooMuchRisk = maxAllowedRiskDistance <= 0
|
|
? false
|
|
: risk >= (maxAllowedRiskDistance * points);
|
|
if (hasTooMuchRisk)
|
|
{
|
|
//
|
|
// Clean Signal if Too much Risk ...
|
|
zone.Clean();
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
// Common Targets ...
|
|
|
|
//
|
|
// Partial Close on TP 1 ...
|
|
if (hasPartialCloseOnTp1)
|
|
{
|
|
//
|
|
iTarget.Clean();
|
|
iTarget.target = tp1;
|
|
iTarget.actingDistance = 5;
|
|
iTarget.volumeMultiplier = 0.8;
|
|
iTarget.doRFOnEntry = doRFOnEntryOnTP1;
|
|
|
|
//
|
|
AddRef(iTarget, targets);
|
|
}
|
|
|
|
//
|
|
// Custom Signaller Targets ...
|
|
|
|
//
|
|
// Restrictions Handling ...
|
|
if (risk > 0 && HasRestrictions())
|
|
{
|
|
//
|
|
// Reset Restricitons if necessary ...
|
|
ResetRestrictions();
|
|
|
|
//
|
|
// Handle Custom Restrictions Senario ...
|
|
}
|
|
|
|
//
|
|
// Ignore Targets ...
|
|
if (ignoreTargets)
|
|
{
|
|
XClean(targets);
|
|
}
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = zone.IsValid() &&
|
|
HasDirection(dir);
|
|
|
|
//
|
|
// Cleanup ...
|
|
iTarget.Clean();
|
|
}
|
|
|
|
//
|
|
// Draws ...
|
|
if (result && draw)
|
|
{
|
|
//
|
|
// Prepare Draw Config ...
|
|
iDrawConfig = structureDrawConfig.drawConfig;
|
|
iDrawConfig.zonesWidth = 3;
|
|
iDrawConfig.zonesStyle = STYLE_DASH;
|
|
iDrawConfig.bullishColor = clrYellow;
|
|
iDrawConfig.bearishColor = clrDarkOrange;
|
|
|
|
//
|
|
// Draw Zone ...
|
|
if (drawZone)
|
|
{
|
|
poiDrawer.DrawZone(zone, iDrawConfig);
|
|
}
|
|
|
|
//
|
|
// Draw Market Structure ...
|
|
|
|
//
|
|
// Analyse Market Structure if Required ...
|
|
if (!marketStructure.IsValid())
|
|
{
|
|
//
|
|
poiDetector.AnalyseMarket(
|
|
marketStructure,
|
|
structureConfig,
|
|
bar.Index() //
|
|
);
|
|
}
|
|
if (marketStructure.IsValid())
|
|
{
|
|
//
|
|
// Order Flow ...
|
|
if (drawMarketStructureOrderFlow && marketStructure.HasOrderFlow())
|
|
{
|
|
poiDrawer.DrawZones(marketStructure.orderFlow, iDrawConfig);
|
|
}
|
|
|
|
//
|
|
// Pivots ...
|
|
if (drawMarketStructurePivots)
|
|
{
|
|
//
|
|
XPivot pivots[];
|
|
int pivotsCount = marketStructure.CollectPivots(
|
|
pivots,
|
|
true // Contains Patterns ...
|
|
);
|
|
if (IsValidSize(pivotsCount))
|
|
{
|
|
poiDrawer.DrawPivots(pivots, iDrawConfig);
|
|
}
|
|
|
|
//
|
|
XClean(pivots);
|
|
}
|
|
|
|
//
|
|
// Analysis ...
|
|
if (drawMarketStructureAnalysis)
|
|
{
|
|
//
|
|
}
|
|
}
|
|
|
|
//
|
|
// Other Drawing Materials ...
|
|
Print("Signaller Providers: ", provider);
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
tmpZone.Clean();
|
|
iDrawConfig.Clean();
|
|
marketStructure.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Custom Signal Strategies ...
|
|
|
|
/**
|
|
* Check Bar Has Signal Based on Strategy 3 ...
|
|
*
|
|
* @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 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Strategy1HasSignal(
|
|
XOHCL &bar,
|
|
XBoxZone &zone,
|
|
XTarget &targets[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validator Flags ...
|
|
bool validateByZones = false;
|
|
bool validateHasLiquidity = false;
|
|
bool validateByXFIMARejected = true;
|
|
bool validateByXFIMAMACrossed = false;
|
|
bool validateByCyclesMATresnding = false;
|
|
bool validateByHasDirectionalZones = false;
|
|
bool validateByHasInDirectionalZones = false;
|
|
bool validateByInDirectionalZonesPlacement = false;
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
XOHCL p3Bar;
|
|
XBoxZone zones[];
|
|
double rejecteds[];
|
|
XBoxZone liquidity;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
XBoxZone directionalZone;
|
|
XBoxZone inDirectionalZone;
|
|
XPatternAnalysis pBarPatterns;
|
|
XPatternAnalysis p2BarPatterns;
|
|
XPatternAnalysis p3BarPatterns;
|
|
XPatternAnalysisConfig iPatternsConfig;
|
|
|
|
//
|
|
// Reading Bars ...
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
result = result &&
|
|
p2Bar.GetPreviousBar(p3Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Bar Patterns ...
|
|
iPatternsConfig.Default();
|
|
iPatternsConfig.FullPattern();
|
|
result =
|
|
result &&
|
|
poiDetector.AnalyseBarPatterns(
|
|
pBar,
|
|
pBarPatterns,
|
|
iPatternsConfig //
|
|
);
|
|
result =
|
|
result &&
|
|
poiDetector.AnalyseBarPatterns(
|
|
p2Bar,
|
|
p2BarPatterns,
|
|
iPatternsConfig //
|
|
);
|
|
result =
|
|
result &&
|
|
poiDetector.AnalyseBarPatterns(
|
|
p3Bar,
|
|
p3BarPatterns,
|
|
iPatternsConfig //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
pBarPatterns.Clean();
|
|
p2BarPatterns.Clean();
|
|
p3BarPatterns.Clean();
|
|
iPatternsConfig.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect Pin Bar ...
|
|
bool isPBarIsPinBar = false &&
|
|
poiDetector.IsPinnedBar(
|
|
pBar,
|
|
dir,
|
|
3,
|
|
4,
|
|
true //
|
|
);
|
|
bool isPBarIsPinBarBullish = isPBarIsPinBar && IsXBullish(dir);
|
|
bool isPBarIsPinBarBearish = isPBarIsPinBar && IsXBearish(dir);
|
|
if (isPBarIsPinBar)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isPBarIsPinBarBullish =
|
|
isPBarIsPinBarBullish &&
|
|
pBar.GetHighShadow() < pBar.GetBody();
|
|
|
|
//
|
|
// Bearish ...
|
|
isPBarIsPinBarBearish =
|
|
isPBarIsPinBarBearish &&
|
|
pBar.GetLowShadow() < pBar.GetBody();
|
|
|
|
//
|
|
isPBarIsPinBar = isPBarIsPinBarBullish || isPBarIsPinBarBearish;
|
|
}
|
|
|
|
//
|
|
// Detect Signal Key Bar ...
|
|
bool isPBarSignalKeyBar = poiDetector.IsSignalKeyBarPattern(
|
|
pBar,
|
|
dir,
|
|
3,
|
|
4,
|
|
true //
|
|
);
|
|
bool isPBarSignalKeyBarBullish = isPBarSignalKeyBar && IsXBullish(dir);
|
|
bool isPBarSignalKeyBarBearish = isPBarSignalKeyBar && IsXBearish(dir);
|
|
if (isPBarSignalKeyBar)
|
|
{
|
|
//
|
|
// Bullish ...
|
|
isPBarSignalKeyBarBullish =
|
|
isPBarSignalKeyBarBullish &&
|
|
p2Bar.GetHighShadow() < p2Bar.GetBody();
|
|
|
|
//
|
|
// Bearish ...
|
|
isPBarSignalKeyBarBearish =
|
|
isPBarSignalKeyBarBearish &&
|
|
p2Bar.GetLowShadow() < p2Bar.GetBody();
|
|
|
|
//
|
|
isPBarSignalKeyBar = isPBarSignalKeyBarBullish || isPBarSignalKeyBarBearish;
|
|
}
|
|
|
|
//
|
|
bool hasBullishBar = isPBarIsPinBarBullish ||
|
|
isPBarSignalKeyBarBullish;
|
|
|
|
//
|
|
bool hasBearishBar = isPBarIsPinBarBearish ||
|
|
isPBarSignalKeyBarBearish;
|
|
|
|
//
|
|
isBullish = hasBullishBar;
|
|
|
|
//
|
|
isBearish = hasBearishBar;
|
|
|
|
//
|
|
result = isBullish || isBearish;
|
|
|
|
//
|
|
// Prepare Zone Based on Started Conditions ...
|
|
if (result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
dir = hasBullishBar
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
if (isPBarIsPinBar)
|
|
{
|
|
//
|
|
result = ToBox(
|
|
pBar,
|
|
zone,
|
|
dir,
|
|
X_BAR_PATTERN_PINNED //
|
|
);
|
|
}
|
|
else if (isPBarSignalKeyBar)
|
|
{
|
|
//
|
|
result = ToBox(
|
|
pBar,
|
|
zone,
|
|
dir,
|
|
X_BAR_PATTERN_SIGNALKEY //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
|
|
//
|
|
// Forward Zone to Break By Shadow ...
|
|
if (result)
|
|
{
|
|
//
|
|
XOHCL tmpBar;
|
|
int idx = zone.FromIndex() - 1;
|
|
bool canContinue = true;
|
|
while (canContinue)
|
|
{
|
|
//
|
|
idx++;
|
|
tmpBar.Clean();
|
|
canContinue = bar.BarAt(idx, tmpBar);
|
|
if (!canContinue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
canContinue =
|
|
isBullish
|
|
? tmpBar.low > zone.lower
|
|
: tmpBar.high < zone.upper;
|
|
if (!canContinue)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
zone.from = tmpBar.time;
|
|
}
|
|
|
|
//
|
|
// Detect Liquidity Zone ...
|
|
if (zone.IsValid() && tmpBar.IsValid())
|
|
{
|
|
//
|
|
liquidity = zone;
|
|
|
|
//
|
|
if (isBullish)
|
|
{
|
|
//
|
|
liquidity.upper = zone.lower;
|
|
liquidity.lower = tmpBar.low;
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
//
|
|
liquidity.lower = zone.upper;
|
|
liquidity.upper = tmpBar.high;
|
|
}
|
|
|
|
//
|
|
liquidity.type = "XLiquidoty";
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
tmpBar.Clean();
|
|
}
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = false;
|
|
isBullish = false;
|
|
isBearish = false;
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate By Liquidity Zone ...
|
|
if (result && validateHasLiquidity)
|
|
{
|
|
//
|
|
result = result &&
|
|
liquidity.IsValid();
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = false;
|
|
isBullish = false;
|
|
isBearish = false;
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate By XFIMA Rejections ...
|
|
if (result && validateByXFIMARejected)
|
|
{
|
|
//
|
|
XOHCL rejectedBar;
|
|
if (isPBarIsPinBar)
|
|
{
|
|
rejectedBar = pBar;
|
|
}
|
|
else if (isPBarSignalKeyBar)
|
|
{
|
|
rejectedBar = p2Bar;
|
|
}
|
|
|
|
//
|
|
result = rejectedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION forDir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
int count = poiDetector.IsRejectXFIMA(
|
|
rejectedBar,
|
|
rejecteds,
|
|
forDir //
|
|
);
|
|
result = IsValidSize(count);
|
|
}
|
|
|
|
//
|
|
rejectedBar.Clean();
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = false;
|
|
isBullish = false;
|
|
isBearish = false;
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate Rejection by Cycleas MA Trending ...
|
|
if (result && validateByCyclesMATresnding)
|
|
{
|
|
//
|
|
int barIDX = pBar.Index();
|
|
|
|
//
|
|
bool isCyclesMABulliah =
|
|
fimaParser.IsHCMABullish(barIDX) &&
|
|
fimaParser.IsHCMAOverLast(barIDX);
|
|
|
|
//
|
|
bool isCyclesMABearish =
|
|
fimaParser.IsHCMABearish(barIDX) &&
|
|
fimaParser.IsHCMAUnderLast(barIDX);
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
isCyclesMABulliah;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
isCyclesMABearish;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Validate by Has a Zone (FVG, Support, Resistance) ...
|
|
if (result && validateByZones)
|
|
{
|
|
//
|
|
int bullishCount = 0;
|
|
int bearishCount = 0;
|
|
XBoxZone bullishZones[];
|
|
XBoxZone bearishZones[];
|
|
|
|
//
|
|
// Detect Zones ...
|
|
int zonesCount = poiDetector.DetectZones(
|
|
bar,
|
|
zones,
|
|
true, // Validated Zones ...
|
|
false, // Contains Order Block ...
|
|
true, // Contains Fair Value Gaps ...
|
|
true, // Contains Supports ...
|
|
true, // Contains Resistances ...
|
|
50, // Loopback ...
|
|
X_DIRECTION_ALL, // For All Directions ...
|
|
X_SORT_BY_DATE, // Sort by Date ...
|
|
X_DIRECTION_BEARISH, // Sorting Direction ...
|
|
10, // Zones Validation Points Factor ...
|
|
5, // Zones Loopback ...
|
|
3, // Zones Validation ...
|
|
0 // All Zones ...
|
|
);
|
|
UpdateToTime(zones, bar.time);
|
|
|
|
//
|
|
// Validate by Zones Existance ...
|
|
result = result && IsValidSize(zonesCount);
|
|
|
|
//
|
|
// Validate By Direction Zones Existance ...
|
|
if (result)
|
|
{
|
|
//
|
|
// Separate Bullish Zones ...
|
|
bullishCount = ExtractByDirection(
|
|
bullishZones,
|
|
zones,
|
|
X_DIRECTION_BULLISH //
|
|
);
|
|
|
|
//
|
|
// Separate Bearish Zones ...
|
|
bearishCount = ExtractByDirection(
|
|
bearishZones,
|
|
zones,
|
|
X_DIRECTION_BEARISH //
|
|
);
|
|
|
|
//
|
|
// Select Directional Zone ...
|
|
int idx = -1;
|
|
if (isBullish && IsValidSize(bullishCount))
|
|
{
|
|
idx = GetYoungest(bullishZones);
|
|
}
|
|
else if (isBearish && IsValidSize(bearishCount))
|
|
{
|
|
idx = GetYoungest(bearishZones);
|
|
}
|
|
if (IsValidIndex(idx))
|
|
{
|
|
if (isBullish)
|
|
{
|
|
directionalZone = bullishZones[idx];
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
directionalZone = bearishZones[idx];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select Indirectional Zone ...
|
|
idx = -1;
|
|
if (isBullish && IsValidSize(bearishCount))
|
|
{
|
|
idx = GetYoungest(bearishZones);
|
|
}
|
|
else if (isBearish && IsValidSize(bullishCount))
|
|
{
|
|
idx = GetYoungest(bullishZones);
|
|
}
|
|
if (IsValidIndex(idx))
|
|
{
|
|
if (isBullish)
|
|
{
|
|
inDirectionalZone = bearishZones[idx];
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
inDirectionalZone = bullishZones[idx];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate by Has Directional Zones ...
|
|
if (result && validateByHasDirectionalZones)
|
|
{
|
|
result = result && directionalZone.IsValid();
|
|
}
|
|
|
|
//
|
|
// Validate by Has InDirectional Zones ...
|
|
if (result && validateByHasInDirectionalZones)
|
|
{
|
|
result = result && inDirectionalZone.IsValid();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate Directional and In Directional Zones Distance ...
|
|
if (result && validateByInDirectionalZonesPlacement)
|
|
{
|
|
//
|
|
double points = GetPoints(bar.symbol);
|
|
double slAddition =
|
|
slAdditionDistance > 0
|
|
? slAdditionDistance * points
|
|
: 0;
|
|
double spread = GetSpread(bar.symbol);
|
|
double entry = GetEntry(bar.symbol, dir);
|
|
double sl = isBullish
|
|
? zone.lower - slAddition
|
|
: zone.upper + slAddition;
|
|
double risk = MathAbs(entry - sl);
|
|
double reward = risk * defaultSignalR2R;
|
|
double tp = isBullish
|
|
? entry + reward
|
|
: entry - reward;
|
|
|
|
//
|
|
if (inDirectionalZone.IsValid())
|
|
{
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
tp < inDirectionalZone.lower &&
|
|
entry < inDirectionalZone.lower;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
tp > inDirectionalZone.upper &&
|
|
entry > inDirectionalZone.upper;
|
|
|
|
//
|
|
result = isBullish || isBearish;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
XClean(bullishZones);
|
|
XClean(bearishZones);
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = false;
|
|
isBullish = false;
|
|
isBearish = false;
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate Detected Zone By Crossed MA Fast Slow ...
|
|
if (result && validateByXFIMAMACrossed)
|
|
{
|
|
//
|
|
bool isBarHasBullishCross = fimaParser.IsMAFastCrossedOverLast(bar.Index()) &&
|
|
fimaParser.IsMAFastCrossedOverSlow(bar.Index());
|
|
bool isPBarHasBullishCross = fimaParser.IsMAFastCrossedOverLast(pBar.Index()) &&
|
|
fimaParser.IsMAFastCrossedOverSlow(pBar.Index());
|
|
bool isP2BarHasBullishCross = fimaParser.IsMAFastCrossedOverLast(p2Bar.Index()) &&
|
|
fimaParser.IsMAFastCrossedOverSlow(p2Bar.Index());
|
|
bool isP3BarHasBullishCross = fimaParser.IsMAFastCrossedOverLast(p3Bar.Index()) &&
|
|
fimaParser.IsMAFastCrossedOverSlow(p3Bar.Index());
|
|
bool hasBullishCross = isBarHasBullishCross ||
|
|
isPBarHasBullishCross ||
|
|
isP2BarHasBullishCross ||
|
|
isP3BarHasBullishCross;
|
|
|
|
//
|
|
bool isBarHasBearishCross = fimaParser.IsMAFastCrossedUnderLast(bar.Index()) &&
|
|
fimaParser.IsMAFastCrossedUnderSlow(bar.Index());
|
|
bool isPBarHasBearishCross = fimaParser.IsMAFastCrossedUnderLast(pBar.Index()) &&
|
|
fimaParser.IsMAFastCrossedUnderSlow(pBar.Index());
|
|
bool isP2BarHasBearishCross = fimaParser.IsMAFastCrossedUnderLast(p2Bar.Index()) &&
|
|
fimaParser.IsMAFastCrossedUnderSlow(p2Bar.Index());
|
|
bool isP3BarHasBearishCross = fimaParser.IsMAFastCrossedUnderLast(p3Bar.Index()) &&
|
|
fimaParser.IsMAFastCrossedUnderSlow(p3Bar.Index());
|
|
bool hasBearishCross = isBarHasBearishCross ||
|
|
isPBarHasBearishCross ||
|
|
isP2BarHasBearishCross ||
|
|
isP3BarHasBearishCross;
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
hasBullishCross;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
hasBearishCross;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// TODO: Remove this and Put inside Draws Part ...
|
|
if (result)
|
|
{
|
|
//
|
|
XPOIDrawConfig iConfig = structureDrawConfig.drawConfig;
|
|
XPatternAnalysisDrawConfig iPatternsConfig = structureDrawConfig.barAnalysisDrawConfig;
|
|
iConfig.trendRayLeft = false;
|
|
iConfig.trendRayRight = false;
|
|
|
|
//
|
|
// Draw Rejected Lines ...
|
|
if (HasChild(rejecteds))
|
|
{
|
|
//
|
|
XTrend tmpTrend;
|
|
bool has = false;
|
|
int count = ArraySize(rejecteds);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
tmpTrend.Clean();
|
|
has = tmpTrend.Init(
|
|
bar.symbol,
|
|
bar.period,
|
|
bar.time,
|
|
rejecteds[i],
|
|
p2Bar.BeforeOn(),
|
|
rejecteds[i],
|
|
bar.time //
|
|
);
|
|
|
|
//
|
|
if (has)
|
|
{
|
|
poiDrawer.DrawTrendLine(tmpTrend, iConfig);
|
|
}
|
|
}
|
|
|
|
//
|
|
tmpTrend.Clean();
|
|
}
|
|
|
|
//
|
|
// Draw Detected Zones ...
|
|
if (HasChild(zones))
|
|
{
|
|
poiDrawer.DrawZones(zones, iConfig);
|
|
}
|
|
|
|
//
|
|
// Draw Crossed Trends ...
|
|
if (validateByXFIMAMACrossed)
|
|
{
|
|
//
|
|
XTrend fastTrend;
|
|
XTrend slowTrend;
|
|
bool has = fastTrend.Init(
|
|
p2Bar.symbol,
|
|
p2Bar.period,
|
|
bar.time,
|
|
fimaHelper.GetMAFast(p2Bar.Index()),
|
|
p2Bar.time,
|
|
fimaHelper.GetMAFast(bar.Index()),
|
|
bar.time //
|
|
);
|
|
if (has)
|
|
{
|
|
poiDrawer.DrawTrendLine(fastTrend, iConfig);
|
|
}
|
|
has = slowTrend.Init(
|
|
p2Bar.symbol,
|
|
p2Bar.period,
|
|
bar.time,
|
|
fimaHelper.GetMASlow(p2Bar.Index()),
|
|
p2Bar.time,
|
|
fimaHelper.GetMASlow(bar.Index()),
|
|
bar.time //
|
|
);
|
|
if (has)
|
|
{
|
|
poiDrawer.DrawTrendLine(slowTrend, iConfig);
|
|
}
|
|
fastTrend.Clean();
|
|
slowTrend.Clean();
|
|
}
|
|
|
|
//
|
|
// Draw Liquidity Zone ...
|
|
if (liquidity.IsValid())
|
|
{
|
|
//
|
|
iConfig.bullishColor = clrGreen;
|
|
iConfig.bearishColor = clrRed;
|
|
poiDrawer.DrawZone(liquidity, iConfig);
|
|
iConfig.bullishColor = structureDrawConfig.drawConfig.bullishColor;
|
|
iConfig.bearishColor = structureDrawConfig.drawConfig.bearishColor;
|
|
}
|
|
|
|
//
|
|
// Specified Zones ...
|
|
XPOIDrawConfig iSConfig = iConfig;
|
|
iSConfig.zonesWidth = 2;
|
|
iSConfig.bullishColor = clrYellow;
|
|
iSConfig.zonesStyle = STYLE_DASHDOTDOT;
|
|
iSConfig.bearishColor = clrDarkOrange;
|
|
|
|
//
|
|
// Draw Zone ...
|
|
if (zone.IsValid())
|
|
{
|
|
//
|
|
// iSConfig.zonesStyle = STYLE_SOLID;
|
|
// poiDrawer.DrawZone(zone, iSConfig);
|
|
// iSConfig.zonesStyle = STYLE_DASHDOTDOT;
|
|
}
|
|
|
|
//
|
|
// Draw Directional Zone ...
|
|
if (directionalZone.IsValid())
|
|
{
|
|
poiDrawer.DrawZone(directionalZone, iSConfig);
|
|
}
|
|
|
|
//
|
|
// Draw InDirectional Zone ...
|
|
if (inDirectionalZone.IsValid())
|
|
{
|
|
poiDrawer.DrawZone(inDirectionalZone, iSConfig);
|
|
}
|
|
|
|
//
|
|
iConfig.Clean();
|
|
iSConfig.Clean();
|
|
}
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
DebugBreak();
|
|
|
|
//
|
|
// result = false;
|
|
// isBullish = false;
|
|
// isBearish = false;
|
|
}
|
|
|
|
//
|
|
// Detecting Direction ...
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
result = HasDirection(dir);
|
|
}
|
|
|
|
//
|
|
// Prepare Zone ...
|
|
if (result)
|
|
{
|
|
//
|
|
// Since Zone Prepared in Above Steps ...
|
|
// here we only Validate it ...
|
|
result = zone.IsValid();
|
|
|
|
//
|
|
// Replace Zones SL Edge based on Sweeped Liquidity ...
|
|
if (liquidity.IsValid())
|
|
{
|
|
//
|
|
if (isBullish)
|
|
{
|
|
zone.lower = liquidity.lower;
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
zone.upper = liquidity.upper;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare Targets ...
|
|
if (result)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
XClean(zones);
|
|
XClean(rejecteds);
|
|
liquidity.Clean();
|
|
pBarPatterns.Clean();
|
|
p2BarPatterns.Clean();
|
|
p3BarPatterns.Clean();
|
|
iPatternsConfig.Clean();
|
|
directionalZone.Clean();
|
|
inDirectionalZone.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bar Has Signal Based on Strategy 2 ...
|
|
*
|
|
* Strategy 2:
|
|
* ===========
|
|
* - Works Based On PBar Patterns Focused on PinBar ...
|
|
* - Looking for a Bar Directional Pattern Happens ...
|
|
* - Validate Fast Ma Over/Under Slow ...
|
|
* - Validate P2Peak/Vale doesnt Under or Over Last (InDirectional) ...
|
|
* - Validate P2Bar Has Directional Market Strucuture Zone (OB, FVG, Support/Resistance) ...
|
|
*
|
|
* Manipulations:
|
|
* ================
|
|
* there are Some Flags properties to Change Validations in Strategy ...
|
|
* we can use them for Testing Purposes ...
|
|
*
|
|
* @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 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Strategy2HasSignal(
|
|
XOHCL &bar,
|
|
XBoxZone &zone,
|
|
XTarget &targets[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
XOHCL p3Bar;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
|
|
//
|
|
// Read PBar ...
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
result = result &&
|
|
p2Bar.GetPreviousBar(p3Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading pBar Patterns ...
|
|
XPatternAnalysis pBarPatterns;
|
|
poiDetector.AnalyseBarPatterns(
|
|
pBar,
|
|
pBarPatterns,
|
|
structureConfig.barsAnalysisConfig //
|
|
);
|
|
bool hasSupport = pBarPatterns.IsSupport();
|
|
bool hasResistance = pBarPatterns.IsResistance();
|
|
|
|
//
|
|
// Check Boundary Trend ...
|
|
XTrend boundaryTrend;
|
|
bool hasBoundaryTrend = fimaParser.HasBoundaryTrend(boundaryTrend, pBar.Index());
|
|
bool hasBoundaryBullishTrend = hasBoundaryTrend && boundaryTrend.IsBullish();
|
|
bool hasBoundaryBearishTrend = hasBoundaryTrend && boundaryTrend.IsBearish();
|
|
|
|
//
|
|
// Check Bar Patterns ...
|
|
|
|
//
|
|
// Bars Sequences ...
|
|
bool hasBullishSequence = p3Bar.IsBearish() &&
|
|
pBar.IsBullish();
|
|
bool hasBearishSequence = p3Bar.IsBullish() &&
|
|
pBar.IsBearish();
|
|
|
|
//
|
|
// Bullish ...
|
|
bool isPBarHasBullishPatterns =
|
|
(bar.close > pBar.low ||
|
|
bar.open > pBar.low) &&
|
|
(
|
|
//
|
|
pBarPatterns.IsPinned(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsEngulfed(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsMomentum(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsPiercing(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsSignalKey(X_DIRECTION_BULLISH)
|
|
//
|
|
);
|
|
|
|
//
|
|
// Bearish ...
|
|
bool isPBarHasBearishPatterns =
|
|
(bar.close < pBar.high ||
|
|
bar.open < pBar.high) &&
|
|
(
|
|
//
|
|
pBarPatterns.IsPinned(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsEngulfed(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsMomentum(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsPiercing(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsSignalKey(X_DIRECTION_BEARISH)
|
|
//
|
|
);
|
|
|
|
//
|
|
double peak = fimaHelper.GetPeak(bar.Index());
|
|
double vale = fimaHelper.GetVale(bar.Index());
|
|
double pPeak = fimaHelper.GetPeak(pBar.Index());
|
|
double pVale = fimaHelper.GetVale(pBar.Index());
|
|
double p2Peak = fimaHelper.GetPeak(p2Bar.Index());
|
|
double p2Vale = fimaHelper.GetVale(p2Bar.Index());
|
|
bool isPPeakOverLast = fimaParser.IsPeakOverLast(pBar.Index());
|
|
bool isPValeUnderLast = fimaParser.IsValeUnderLast(pBar.Index());
|
|
bool isP2PeakOverLast = fimaParser.IsPeakOverLast(p2Bar.Index());
|
|
bool isP2ValeUnderLast = fimaParser.IsValeUnderLast(p2Bar.Index());
|
|
bool isPeakOverLast = isPPeakOverLast ||
|
|
isP2PeakOverLast;
|
|
bool isValeUnderLast = isPValeUnderLast ||
|
|
isP2ValeUnderLast;
|
|
bool isP2ValeOverLast = pVale > p2Vale;
|
|
bool isP2PeakUnderLast = pPeak < p2Peak;
|
|
|
|
//
|
|
// Check PBar Close Over Under Fast Ma ...
|
|
bool isPBarCloseOverFast = pBar.close > fimaHelper.GetMAFast(pBar.Index());
|
|
bool isPBarCloseUnderFast = pBar.close < fimaHelper.GetMAFast(pBar.Index());
|
|
bool isFastOverLast = fimaHelper.GetMAFast(pBar.Index()) > fimaHelper.GetMAFast(p2Bar.Index());
|
|
bool isFastUnderLast = fimaHelper.GetMAFast(pBar.Index()) < fimaHelper.GetMAFast(p2Bar.Index());
|
|
|
|
//
|
|
// Force P2Bar is Pin Bar ...
|
|
ENUM_X_DIRECTION p2Dir;
|
|
bool isP2BarPinned = poiDetector.IsPinnedBar(
|
|
p2Bar,
|
|
p2Dir //
|
|
);
|
|
bool isP2BarBullishPinned =
|
|
isP2BarPinned &&
|
|
IsXBullish(p2Dir);
|
|
bool isP2BarBearishPinned =
|
|
isP2BarPinned &&
|
|
IsXBearish(p2Dir);
|
|
|
|
//
|
|
// Check Based On LC and HC MA State ...
|
|
|
|
//
|
|
bool isLCMABullish = fimaParser.IsLCMABullish(pBar.Index());
|
|
bool isHCMABullish = fimaParser.IsHCMABullish(pBar.Index());
|
|
bool isCycleMABullish = isLCMABullish && isHCMABullish;
|
|
|
|
//
|
|
bool isLCMABearish = fimaParser.IsLCMABearish(pBar.Index());
|
|
bool isHCMABearish = fimaParser.IsHCMABearish(pBar.Index());
|
|
bool isCycleMABearish = isLCMABearish && isHCMABearish;
|
|
|
|
//
|
|
// Do ...
|
|
|
|
//
|
|
isBullish =
|
|
//
|
|
hasSupport &&
|
|
isFastOverLast &&
|
|
isValeUnderLast &&
|
|
isCycleMABullish &&
|
|
hasBullishSequence &&
|
|
!isP2PeakUnderLast &&
|
|
isPBarCloseOverFast &&
|
|
isP2BarBullishPinned &&
|
|
hasBoundaryBullishTrend &&
|
|
isPBarHasBullishPatterns
|
|
//
|
|
;
|
|
|
|
//
|
|
isBearish =
|
|
//
|
|
hasResistance &&
|
|
isPeakOverLast &&
|
|
isFastUnderLast &&
|
|
isCycleMABearish &&
|
|
!isP2ValeOverLast &&
|
|
hasBearishSequence &&
|
|
isPBarCloseUnderFast &&
|
|
isP2BarBearishPinned &&
|
|
hasBoundaryBearishTrend &&
|
|
isPBarHasBearishPatterns
|
|
//
|
|
;
|
|
|
|
//
|
|
// Validate ...
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
result = HasDirection(dir);
|
|
}
|
|
|
|
//
|
|
// Prepare Zone ...
|
|
if (result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = ToBox(
|
|
p2Bar,
|
|
zone,
|
|
dir,
|
|
X_BAR_PATTERN_PINNED //
|
|
);
|
|
|
|
//
|
|
// Draws ...
|
|
if (result)
|
|
{
|
|
//
|
|
// XPOIDrawConfig iConfig = structureDrawConfig.drawConfig;
|
|
// iConfig.trendRayLeft = false;
|
|
// iConfig.trendRayRight = false;
|
|
// poiDrawer.DrawTrendLine(boundaryTrend, iConfig);
|
|
// poiDrawer.DrawZone(zone, structureDrawConfig.drawConfig);
|
|
// iConfig.Clean();
|
|
|
|
//
|
|
// DebugBreak();
|
|
}
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
}
|
|
|
|
//
|
|
// Prepare Targets ...
|
|
if (result)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
pBarPatterns.Clean();
|
|
boundaryTrend.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bar Has Signal Based on Strategy 3 ...
|
|
*
|
|
* Strategy 3:
|
|
* ===========
|
|
* - Works Based On Breaked Support or Resistances ...
|
|
* - Looking for a Support or Resistance to Breaked ...
|
|
* - Validate Breaker Bar to Change Peak or Vale ...
|
|
* - Validate Bar Opposit Side of Breaker Bar's Shadow ...
|
|
* - Validate by Checking Market Strucutre to Has Directional Zone
|
|
* (Support for Resistance Break / Resistance for Support Break) ...
|
|
* - Validate Breaker Bar to Has Directional FVG ...
|
|
*
|
|
* Manipulations:
|
|
* ================
|
|
* there are Some Flags properties to Change Validations in Strategy ...
|
|
* we can use them for Testing Purposes ...
|
|
*
|
|
* @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 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Strategy3HasSignal(
|
|
XOHCL &bar,
|
|
XBoxZone &zone,
|
|
XTarget &targets[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validation Flags ...
|
|
|
|
//
|
|
bool validateByPVChanges = true;
|
|
bool validateByGapExists = true;
|
|
bool validateByBarShadows = true;
|
|
bool validateHasDirectionalZone = true;
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
XOHCL p3Bar;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
|
|
//
|
|
// Read PBar ...
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
result = result &&
|
|
p2Bar.GetPreviousBar(p3Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Do ...
|
|
|
|
//
|
|
// Retrieve pBar Patterns ...
|
|
XBoxZone _fvg;
|
|
XBoxZone _support;
|
|
XBoxZone _resistance;
|
|
XPatternAnalysis pBarPatterns;
|
|
XPatternAnalysis p2BarPatterns;
|
|
XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig;
|
|
|
|
//
|
|
poiDetector.AnalyseBarPatterns(
|
|
pBar,
|
|
pBarPatterns,
|
|
patternConfig //
|
|
);
|
|
poiDetector.AnalyseBarPatterns(
|
|
p2Bar,
|
|
p2BarPatterns,
|
|
patternConfig //
|
|
);
|
|
|
|
//
|
|
// Price Must Break Support or Resistance ...
|
|
|
|
//
|
|
// Extract Support and Resistance ...
|
|
bool hasSupport = p2BarPatterns.IsSupport();
|
|
bool hasResistance = p2BarPatterns.IsResistance();
|
|
if (hasSupport)
|
|
{
|
|
//
|
|
XOHCL tmpBar;
|
|
XPivot tmpPivot;
|
|
hasSupport = p2BarPatterns.GetSupport(tmpBar, tmpPivot, _support);
|
|
tmpBar.Clean();
|
|
tmpPivot.Clean();
|
|
}
|
|
if (hasResistance)
|
|
{
|
|
//
|
|
XOHCL tmpBar;
|
|
XPivot tmpPivot;
|
|
hasResistance = p2BarPatterns.GetResistance(tmpBar, tmpPivot, _resistance);
|
|
tmpBar.Clean();
|
|
tmpPivot.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBreakedSupport = hasSupport &&
|
|
pBar.close < _support.lower &&
|
|
p2Bar.close > _support.lower;
|
|
bool hasBreakedResistance = hasResistance &&
|
|
pBar.close > _resistance.upper &&
|
|
p2Bar.close < _resistance.upper;
|
|
|
|
//
|
|
isBullish = hasBreakedResistance;
|
|
isBearish = hasBreakedSupport;
|
|
|
|
//
|
|
result = isBullish || isBearish;
|
|
|
|
//
|
|
// Validate By PV Changed ...
|
|
// Breaker Bar must Change Peak or Value ...
|
|
if (result && validateByPVChanges)
|
|
{
|
|
//
|
|
bool isPeakOverLast = fimaParser.IsPeakOverLast(pBar.Index());
|
|
bool isValeUnderLast = fimaParser.IsValeUnderLast(pBar.Index());
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
isPeakOverLast;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
isValeUnderLast;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Validate by Bar Shadows ...
|
|
// Breakre Bar Side Shadow must not Reached ...
|
|
if (result && validateByBarShadows)
|
|
{
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
pBar.low > p2Bar.low;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
pBar.high < p2Bar.high;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Validate Has Directional Zone ...
|
|
if (result && validateHasDirectionalZone)
|
|
{
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
hasSupport;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
hasResistance;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Validate By Gap Exists ...
|
|
if (result && validateByGapExists)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION tmpDir;
|
|
bool hasFVG = poiDetector.HasFVG(
|
|
pBar,
|
|
tmpDir,
|
|
_fvg //
|
|
);
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
hasFVG &&
|
|
IsXBullish(tmpDir);
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
hasFVG &&
|
|
IsXBearish(tmpDir);
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Prepare Direction and Zone ...
|
|
if (result)
|
|
{
|
|
//
|
|
if (isBullish)
|
|
{
|
|
//
|
|
zone = _resistance;
|
|
zone.dir = Opposit(_resistance.dir);
|
|
dir = zone.dir;
|
|
zone.upper = MathMax(zone.upper, _fvg.upper);
|
|
zone.lower = MathMin(zone.lower, _fvg.lower);
|
|
}
|
|
|
|
//
|
|
if (isBearish)
|
|
{
|
|
//
|
|
zone = _support;
|
|
zone.dir = Opposit(_support.dir);
|
|
dir = zone.dir;
|
|
zone.upper = MathMax(zone.upper, _fvg.upper);
|
|
zone.lower = MathMin(zone.lower, _fvg.lower);
|
|
}
|
|
|
|
//
|
|
// Zone Validation Base ...
|
|
result = zone.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
// Validate By Trend of Zone ...
|
|
XTrend zoneTrend;
|
|
XTrend zoneToTrend;
|
|
|
|
//
|
|
// Detecting Trends ...
|
|
result = poiDetector.HasBoundaryTrend(zone, zoneTrend, false);
|
|
result = result &&
|
|
poiDetector.HasBoundaryTrend(zone, zoneToTrend, true);
|
|
|
|
//
|
|
// Validate Trend ...
|
|
result =
|
|
result &&
|
|
zone.dir == zoneTrend.dir &&
|
|
zone.dir == zoneToTrend.dir;
|
|
|
|
//
|
|
// Draw ...
|
|
if (result)
|
|
{
|
|
// //
|
|
// XPOIDrawConfig iConfig = structureDrawConfig.drawConfig;
|
|
// iConfig.trendRayLeft = false;
|
|
// iConfig.trendRayRight = false;
|
|
|
|
// //
|
|
// poiDrawer.DrawTrendLine(zoneTrend, iConfig);
|
|
// poiDrawer.DrawTrendLine(zoneToTrend, iConfig);
|
|
|
|
// //
|
|
// iConfig.Clean();
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
zoneTrend.Clean();
|
|
zoneToTrend.Clean();
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
isBullish = false;
|
|
isBearish = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
}
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
if (_support.IsValid())
|
|
{
|
|
poiDrawer.DrawZone(_support, structureDrawConfig.drawConfig);
|
|
}
|
|
|
|
//
|
|
if (_resistance.IsValid())
|
|
{
|
|
poiDrawer.DrawZone(_resistance, structureDrawConfig.drawConfig);
|
|
}
|
|
|
|
//
|
|
if (pBarPatterns.IsValid())
|
|
{
|
|
poiDrawer.DrawPatternAnalysis(pBarPatterns, structureDrawConfig.barAnalysisDrawConfig);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
pBarPatterns.Clean();
|
|
p2BarPatterns.Clean();
|
|
patternConfig.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bar Has Signal Based on Strategy 4 ...
|
|
*
|
|
* Strategy 4:
|
|
* ===========
|
|
* - Works Based on Order Flow ...
|
|
* - Looking for new and Fresh Order Flow ...
|
|
* - Validate Bar is Inside Order Flow ...
|
|
* - Validate Bar has Proper Pattern ...
|
|
* - Validate Bar Based on ATR Band in two Step:
|
|
* - Step 1: Bars is Inside ATR Band (Middle) ...
|
|
* - Step 2: Trigger Bars Close Price based on ATR Band ...
|
|
* - Validate Order Flow based on Market Structure Zone ...
|
|
* - Validate Trigger Bar based on InDirectional Market Structure Zones ...
|
|
*
|
|
* Manipulations:
|
|
* ================
|
|
* there are Some Flags properties to Change Validations in Strategy ...
|
|
* we can use them for Testing Purposes ...
|
|
*
|
|
* @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 ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Strategy4HasSignal(
|
|
XOHCL &bar,
|
|
XBoxZone &zone,
|
|
XTarget &targets[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare ...
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
// Validate ...
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validation Flags ...
|
|
bool validateBarInsideZone = true;
|
|
bool validateByBarPatterns = true;
|
|
bool validateByXFIMABoundary = true;
|
|
bool validateByBarInsideATRBand = true;
|
|
bool validateByBarBasedOnATRBand = true;
|
|
bool validateByXFIMABoundaryTrend = true;
|
|
bool validateMarketStructureHasDirectionalZone = true;
|
|
bool validateMarketStructureDirectionalZoneInsideOrderFlow = true;
|
|
bool validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP = true;
|
|
|
|
//
|
|
// Define Requirements ...
|
|
|
|
//
|
|
XOHCL pBar;
|
|
XOHCL p2Bar;
|
|
XOHCL p3Bar;
|
|
bool isBullish = false;
|
|
bool isBearish = false;
|
|
|
|
//
|
|
// Read PBar ...
|
|
result = bar.GetPreviousBar(pBar);
|
|
result = result &&
|
|
pBar.GetPreviousBar(p2Bar);
|
|
result = result &&
|
|
p2Bar.GetPreviousBar(p3Bar);
|
|
if (!result)
|
|
{
|
|
//
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Do ...
|
|
|
|
//
|
|
// Retrieve pBar Patterns ...
|
|
XPatternAnalysis pBarPatterns;
|
|
XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig;
|
|
|
|
//
|
|
poiDetector.AnalyseBarPatterns(
|
|
pBar,
|
|
pBarPatterns,
|
|
patternConfig //
|
|
);
|
|
|
|
//
|
|
// Detecting OrderFlow ...
|
|
XBoxZone oFlow[];
|
|
bool hasOrderFlow = poiDetector.HasOrderFlow(
|
|
p3Bar,
|
|
dir,
|
|
oFlow,
|
|
structureConfig.orderFlowValidation,
|
|
structureConfig.orderFlowUseOB,
|
|
structureConfig.orderFlowUseFVG,
|
|
structureConfig.orderFlowUseSupportAndResistance,
|
|
patternConfig.supportAndResistanceLoopbackLength,
|
|
patternConfig.supportAndResistanceValidationLength,
|
|
structureConfig.loopback //
|
|
);
|
|
|
|
//
|
|
XTrend boundaryTrend;
|
|
XTrend boundaryZoneTrend;
|
|
|
|
//
|
|
double atrBandUpper = EMPTY_VALUE;
|
|
double atrBandLower = EMPTY_VALUE;
|
|
double atrBandMiddle = EMPTY_VALUE;
|
|
|
|
//
|
|
isBullish = hasOrderFlow &&
|
|
IsXBullish(dir);
|
|
|
|
//
|
|
isBearish = hasOrderFlow &&
|
|
IsXBearish(dir);
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
|
|
//
|
|
// Force Price of p2Bar is Inside Order Flow ...
|
|
if (result && validateBarInsideZone)
|
|
{
|
|
//
|
|
double orderFlowUpper = 0;
|
|
double orderFlowLower = 0;
|
|
|
|
//
|
|
int idx = -1;
|
|
idx = GetHighest(oFlow);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
orderFlowUpper = oFlow[idx].upper;
|
|
}
|
|
idx = GetLowest(oFlow);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
orderFlowLower = oFlow[idx].lower;
|
|
}
|
|
|
|
//
|
|
result = NotEmptyZero(orderFlowUpper) &&
|
|
NotEmptyZero(orderFlowLower) &&
|
|
orderFlowUpper > orderFlowLower &&
|
|
(isBullish
|
|
? p2Bar.low < orderFlowUpper
|
|
: p2Bar.high > orderFlowLower);
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
isBullish = false;
|
|
isBearish = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force PBar Has Pattern ...
|
|
if (result && validateByBarPatterns)
|
|
{
|
|
//
|
|
// Analyse Bar Patterns ...
|
|
result = pBarPatterns.IsValid();
|
|
|
|
//
|
|
// Bullish ...
|
|
bool isPBarHasBullishPatterns =
|
|
result &&
|
|
// (bar.close > pBar.low ||
|
|
// bar.open > pBar.low) &&
|
|
(
|
|
//
|
|
pBarPatterns.IsPinned(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsEngulfed(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsMomentum(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsPiercing(X_DIRECTION_BULLISH) ||
|
|
pBarPatterns.IsSignalKey(X_DIRECTION_BULLISH)
|
|
//
|
|
);
|
|
|
|
//
|
|
// Bearish ...
|
|
bool isPBarHasBearishPatterns =
|
|
result &&
|
|
// (bar.close < pBar.high ||
|
|
// bar.open < pBar.high) &&
|
|
(
|
|
//
|
|
pBarPatterns.IsPinned(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsEngulfed(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsMomentum(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsPiercing(X_DIRECTION_BEARISH) ||
|
|
pBarPatterns.IsSignalKey(X_DIRECTION_BEARISH)
|
|
//
|
|
);
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
isPBarHasBullishPatterns &&
|
|
!isPBarHasBearishPatterns;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
isPBarHasBearishPatterns &&
|
|
!isPBarHasBullishPatterns;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
isBullish = false;
|
|
isBearish = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force P2Bar Place Checking based on ATR Band ...
|
|
if (result && validateByBarInsideATRBand)
|
|
{
|
|
//
|
|
atrBandUpper = fimaHelper.GetATRBandUpper(p2Bar.Index());
|
|
atrBandLower = fimaHelper.GetATRBandLower(p2Bar.Index());
|
|
|
|
//
|
|
atrBandMiddle = atrBandLower + ((atrBandUpper - atrBandLower) / 2);
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
NotEmptyZero(atrBandMiddle) &&
|
|
p2Bar.low < atrBandMiddle;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
NotEmptyZero(atrBandMiddle) &&
|
|
p2Bar.high > atrBandMiddle;
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
isBullish = false;
|
|
isBearish = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force PBar Place Checking based on ATR Band ...
|
|
if (result && validateByBarBasedOnATRBand)
|
|
{
|
|
//
|
|
atrBandUpper = fimaHelper.GetATRBandUpper(pBar.Index());
|
|
atrBandLower = fimaHelper.GetATRBandLower(pBar.Index());
|
|
|
|
//
|
|
result =
|
|
NotEmptyZero(atrBandUpper) &&
|
|
NotEmptyZero(atrBandLower) &&
|
|
(isBullish
|
|
? pBar.close > atrBandLower
|
|
: pBar.close < atrBandUpper);
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
isBullish = false;
|
|
isBearish = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// for Bullish has Support ...
|
|
// for Bearish has Resistance ...
|
|
if (result && validateMarketStructureHasDirectionalZone)
|
|
{
|
|
//
|
|
XOHCL tmpBar;
|
|
XPivot tmpPivot;
|
|
XBoxZone _support;
|
|
XBoxZone _resistance;
|
|
|
|
//
|
|
// Check Market Strucutre Has Support / Resistance ...
|
|
bool hasSupport = pBarPatterns.IsSupport();
|
|
bool hasResistance = pBarPatterns.IsResistance();
|
|
|
|
//
|
|
// Retrieve Support / Resistance Zone ...
|
|
if (hasSupport)
|
|
{
|
|
pBarPatterns.GetSupport(tmpBar, tmpPivot, _support);
|
|
}
|
|
if (hasResistance)
|
|
{
|
|
pBarPatterns.GetResistance(tmpBar, tmpPivot, _resistance);
|
|
}
|
|
|
|
//
|
|
// Validate Support and Resistance by Order Flow ...
|
|
|
|
//
|
|
// Converts Order Flow to Zone ...
|
|
XBoxZone ofZone;
|
|
bool hasOFBox = ToBox(ofZone, oFlow);
|
|
|
|
//
|
|
// Check Market Strucutre Support and Resistance Validation ...
|
|
if (validateMarketStructureDirectionalZoneInsideOrderFlow)
|
|
{
|
|
//
|
|
hasSupport =
|
|
hasOFBox &&
|
|
hasSupport &&
|
|
ofZone.lower < _support.lower &&
|
|
ofZone.upper > _support.upper;
|
|
|
|
//
|
|
hasResistance =
|
|
hasOFBox &&
|
|
hasResistance &&
|
|
ofZone.lower < _resistance.lower &&
|
|
ofZone.upper > _resistance.upper;
|
|
}
|
|
|
|
//
|
|
// Validate Directional Support or Resistance Exists ...
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
hasSupport;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
hasResistance;
|
|
|
|
//
|
|
// Cleanup ...
|
|
ofZone.Clean();
|
|
tmpBar.Clean();
|
|
_support.Clean();
|
|
tmpPivot.Clean();
|
|
_resistance.Clean();
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Validate Makret Structure Has Not Indirectional Zone ...
|
|
if (result && validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP)
|
|
{
|
|
//
|
|
XOHCL tmpBar;
|
|
XPivot tmpPivot;
|
|
XBoxZone _support;
|
|
XBoxZone _resistance;
|
|
|
|
//
|
|
// Check Market Strucutre Has Support / Resistance ...
|
|
bool hasSupport = pBarPatterns.IsSupport();
|
|
bool hasResistance = pBarPatterns.IsResistance();
|
|
|
|
//
|
|
// Retrieve Support / Resistance Zone ...
|
|
if (hasSupport)
|
|
{
|
|
pBarPatterns.GetSupport(tmpBar, tmpPivot, _support);
|
|
}
|
|
if (hasResistance)
|
|
{
|
|
pBarPatterns.GetResistance(tmpBar, tmpPivot, _resistance);
|
|
}
|
|
|
|
//
|
|
// Converts Order Flow to Zone ...
|
|
XBoxZone ofZone;
|
|
bool hasOFBox = ToBox(ofZone, oFlow);
|
|
|
|
//
|
|
bool hasIndirectionalZone =
|
|
(isBullish && hasResistance) ||
|
|
(isBearish && hasSupport);
|
|
if (hasIndirectionalZone)
|
|
{
|
|
//
|
|
// Here we Have to Validate Zone Place ...
|
|
|
|
//
|
|
double point = GetPoints(bar.symbol);
|
|
double entry = GetEntry(bar.symbol, dir);
|
|
double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0;
|
|
double risk = MathAbs(entry - (isBullish ? oFlow[0].lower : oFlow[0].upper)) + (slAddition * point);
|
|
double reward = (defaultSignalR2R * risk);
|
|
double tp = isBullish
|
|
? entry + reward
|
|
: entry - reward;
|
|
|
|
//
|
|
// Bullish ...
|
|
if (isBullish && hasResistance)
|
|
{
|
|
hasResistance = _resistance.lower <= tp;
|
|
}
|
|
|
|
//
|
|
// Bearish ...
|
|
if (isBearish && hasSupport)
|
|
{
|
|
hasSupport = _support.upper >= tp;
|
|
}
|
|
}
|
|
|
|
//
|
|
isBullish =
|
|
isBullish &&
|
|
!hasResistance;
|
|
|
|
//
|
|
isBearish =
|
|
isBearish &&
|
|
!hasSupport;
|
|
|
|
//
|
|
// Cleanup ...
|
|
ofZone.Clean();
|
|
tmpBar.Clean();
|
|
_support.Clean();
|
|
tmpPivot.Clean();
|
|
_resistance.Clean();
|
|
|
|
//
|
|
// Summarize Result ...
|
|
result = isBullish || isBearish;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
result = isBullish || isBearish;
|
|
if (result)
|
|
{
|
|
//
|
|
dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
result = HasDirection(dir);
|
|
}
|
|
|
|
//
|
|
// Prepare Zone and do Zone Based Validations ...
|
|
if (result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = ToBox(
|
|
p2Bar,
|
|
zone,
|
|
dir,
|
|
X_BAR_PATTERN_PINNED //
|
|
);
|
|
|
|
//
|
|
// Refine Zone ...
|
|
zone.to = bar.time;
|
|
zone.upper = MathMax(zone.upper, atrBandMiddle);
|
|
zone.lower = MathMin(zone.lower, atrBandMiddle);
|
|
|
|
//
|
|
// Validate by XFIMA Boundary ...
|
|
if (result && validateByXFIMABoundary)
|
|
{
|
|
//
|
|
// Try to Retrieve Boundary To Trend ...
|
|
result = poiDetector.HasBoundaryTrend(
|
|
zone,
|
|
boundaryTrend,
|
|
true //
|
|
);
|
|
|
|
//
|
|
// Try to Retrieve Boundary Zone Trend ...
|
|
result =
|
|
result &&
|
|
poiDetector.HasBoundaryTrend(
|
|
zone,
|
|
boundaryZoneTrend,
|
|
false //
|
|
);
|
|
|
|
//
|
|
// Check and Validate Trend Direction ...
|
|
result =
|
|
result &&
|
|
zone.dir == boundaryTrend.dir &&
|
|
zone.dir == boundaryZoneTrend.dir;
|
|
|
|
//
|
|
// Reset Flags ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
result = false;
|
|
isBullish = false;
|
|
isBearish = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Manage Stops ...
|
|
if (result)
|
|
{
|
|
//
|
|
// Since Stop Management Changes Zones Edge(s) ...
|
|
// we do it here for Refining Zone ...
|
|
}
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
}
|
|
|
|
//
|
|
// Prepare Targets ...
|
|
if (result)
|
|
{
|
|
//
|
|
XTarget iTarget;
|
|
|
|
//
|
|
// Calculate Requirements ...
|
|
double point = GetPoints(bar.symbol);
|
|
double entry = GetEntry(bar.symbol, dir);
|
|
double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0;
|
|
double risk = MathAbs(entry - (isBullish ? zone.lower : zone.upper)) + (slAddition * point);
|
|
double reward = (defaultSignalR2R * risk);
|
|
double tp = isBullish
|
|
? entry + reward
|
|
: entry - reward;
|
|
|
|
//
|
|
// High Risk Target is Used to Protect In Profit Positiions
|
|
// from Reversal Patterns ...
|
|
double highRiskR2r = (defaultSignalR2R / 5) * 4;
|
|
double highRiskReward = highRiskR2r * risk;
|
|
double highRiskTP = isBullish
|
|
? entry + highRiskReward
|
|
: entry - highRiskReward;
|
|
iTarget.Clean();
|
|
iTarget.actingDistance = 5;
|
|
iTarget.doRFOnEntry = true;
|
|
iTarget.target = highRiskTP;
|
|
iTarget.volumeMultiplier = 0.8;
|
|
// AddRef(iTarget, targets);
|
|
|
|
//
|
|
// Cleanup ...
|
|
iTarget.Clean();
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
if (!result)
|
|
{
|
|
//
|
|
zone.Clean();
|
|
XClean(targets);
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
pBar.Clean();
|
|
p2Bar.Clean();
|
|
p3Bar.Clean();
|
|
XClean(oFlow);
|
|
pBarPatterns.Clean();
|
|
boundaryTrend.Clean();
|
|
patternConfig.Clean();
|
|
boundaryZoneTrend.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
// |