1689 lines
34 KiB
Plaintext
1689 lines
34 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// --------------------------------------
|
|
// Name: XSCBaseStrategy
|
|
// Description: provides all based classes for use ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
/// Imports ...
|
|
#include "../Libraries/x-saherelm.tools.lib.mq5"
|
|
#include "../Classes/x-saherelm.xtrade.class.mq5"
|
|
#include "../Classes/x-saherelm.xalert.class.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
class XSCBaseStrategy : public XSCBaseAlert
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Constructors ...
|
|
void XSCBaseStrategy(
|
|
string _symbol, // Trading Symbol
|
|
ENUM_TIMEFRAMES _period, // Trading TimeFrame
|
|
ENUM_TIMEFRAMES _analizePeriod, // Important Area Detect Time Frame
|
|
double _volume, // Voluem
|
|
double _r2r, // Risk/Reward Ratio
|
|
int _slippage, // Trader Slippage
|
|
long _magicNumber, // Trader Magic Number
|
|
bool _ignoreSignalExecution = false, // Ignore Signal Execution
|
|
bool _useTPSLAsPoint = false, // Converts TP and SL by Provided Points
|
|
bool _forceMaxTPSLAsPoint = false, // Force Max TP and SL by Provided Points
|
|
double _tpPoint = 0, // TP As Point
|
|
double _slPoint = 0, // SL As Point
|
|
bool _ignoreTP = false, // TP set to 0
|
|
bool _ignoreSL = false, // SL set to 0
|
|
bool _allowLong = true,
|
|
bool _allowShort = true,
|
|
int _maxAllowedLongs = 0,
|
|
int _maxAllowedShorts = 0 //
|
|
)
|
|
{
|
|
//
|
|
// Fill Properties ...
|
|
mR2R = _r2r;
|
|
mVolume = _volume;
|
|
mSymbol = _symbol;
|
|
mPeriod = _period;
|
|
mTPPoint = _tpPoint;
|
|
mSLPoint = _slPoint;
|
|
mIgnoreTP = _ignoreTP;
|
|
mIgnoreSL = _ignoreSL;
|
|
mSlippage = _slippage;
|
|
mAllowLong = _allowLong;
|
|
mAllowShort = _allowShort;
|
|
mMagicNumber = _magicNumber;
|
|
mAnalizePeriod = _analizePeriod;
|
|
mUseTPSLAsPoint = _useTPSLAsPoint;
|
|
mMaxAllowedLongs = _maxAllowedLongs;
|
|
mMaxAllowedShorts = _maxAllowedShorts;
|
|
mForceMaxTPSLAsPoint = _forceMaxTPSLAsPoint;
|
|
mIgnoreSignalExecution = _ignoreSignalExecution;
|
|
|
|
//
|
|
mForceDisabled = false;
|
|
|
|
//
|
|
// Initial Trader Class Instance ...
|
|
trader = new XSCTrade(
|
|
mSlippage,
|
|
mMagicNumber //
|
|
);
|
|
|
|
//
|
|
// Initial Time Tracker ...
|
|
barTracker.Init(
|
|
mSymbol,
|
|
mPeriod //
|
|
);
|
|
|
|
//
|
|
SetAlertPrefix(GetTag());
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XSCBaseStrategy()
|
|
{
|
|
//
|
|
delete trader;
|
|
|
|
//
|
|
Reset();
|
|
}
|
|
|
|
//
|
|
// Getter and Setter (s) ...
|
|
|
|
//
|
|
int Slippage()
|
|
{
|
|
return mSlippage;
|
|
}
|
|
|
|
//
|
|
long MagicNumber()
|
|
{
|
|
return mMagicNumber;
|
|
}
|
|
|
|
//
|
|
string Symbol()
|
|
{
|
|
return mSymbol;
|
|
}
|
|
|
|
//
|
|
ENUM_TIMEFRAMES Period()
|
|
{
|
|
return mPeriod;
|
|
}
|
|
|
|
//
|
|
bool IsDisabled()
|
|
{
|
|
return mForceDisabled;
|
|
}
|
|
|
|
//
|
|
void Disable()
|
|
{
|
|
mForceDisabled = true;
|
|
}
|
|
|
|
//
|
|
void Enable()
|
|
{
|
|
mForceDisabled = false;
|
|
}
|
|
|
|
//
|
|
double Volume()
|
|
{
|
|
return mVolume;
|
|
}
|
|
|
|
//
|
|
void Volume(double value)
|
|
{
|
|
//
|
|
if (value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
mVolume = value;
|
|
}
|
|
|
|
//
|
|
double R2R()
|
|
{
|
|
return mR2R;
|
|
}
|
|
|
|
//
|
|
bool AllowLong()
|
|
{
|
|
return mAllowLong;
|
|
}
|
|
|
|
//
|
|
void AllowLong(bool value)
|
|
{
|
|
mAllowLong = value;
|
|
}
|
|
|
|
//
|
|
bool AllowShort()
|
|
{
|
|
return mAllowShort;
|
|
}
|
|
|
|
//
|
|
void AllowShort(bool value)
|
|
{
|
|
mAllowShort = value;
|
|
}
|
|
|
|
//
|
|
int MaxAllowedLongs()
|
|
{
|
|
return mMaxAllowedLongs;
|
|
}
|
|
|
|
//
|
|
void MaxAllowedLongs(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedLongs = value;
|
|
}
|
|
|
|
//
|
|
int MaxAllowedShorts()
|
|
{
|
|
return mMaxAllowedShorts;
|
|
}
|
|
|
|
//
|
|
void MaxAllowedShorts(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedShorts = value;
|
|
}
|
|
|
|
//
|
|
int RequiredPivots()
|
|
{
|
|
return mRequiredPivots;
|
|
}
|
|
|
|
//
|
|
void RequiredPivots(int value)
|
|
{
|
|
//
|
|
if (value < 3)
|
|
{
|
|
value = 3;
|
|
}
|
|
|
|
//
|
|
mRequiredPivots = value;
|
|
}
|
|
|
|
//
|
|
int RequiredShoulders()
|
|
{
|
|
return mRequiredShoulders;
|
|
}
|
|
|
|
//
|
|
void RequiredShoulders(int value)
|
|
{
|
|
//
|
|
if (value < 5)
|
|
{
|
|
value = 5;
|
|
}
|
|
|
|
//
|
|
mRequiredShoulders = value;
|
|
}
|
|
|
|
//
|
|
bool UseTPSLAsPoint()
|
|
{
|
|
return mUseTPSLAsPoint;
|
|
}
|
|
|
|
//
|
|
void UseTPSLAsPoint(bool value)
|
|
{
|
|
mUseTPSLAsPoint = value;
|
|
}
|
|
|
|
//
|
|
bool ForceMaxTPSLAsPoint()
|
|
{
|
|
return mForceMaxTPSLAsPoint;
|
|
}
|
|
|
|
//
|
|
void ForceMaxTPSLAsPoint(bool value)
|
|
{
|
|
mForceMaxTPSLAsPoint = value;
|
|
}
|
|
|
|
//
|
|
double TPPoint()
|
|
{
|
|
return mTPPoint;
|
|
}
|
|
|
|
//
|
|
void TPPoint(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mTPPoint = value;
|
|
}
|
|
|
|
//
|
|
double SLPoint()
|
|
{
|
|
return mSLPoint;
|
|
}
|
|
|
|
//
|
|
void SLPoint(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mSLPoint = value;
|
|
}
|
|
|
|
//
|
|
bool IgnoreTP()
|
|
{
|
|
return mIgnoreTP;
|
|
}
|
|
|
|
//
|
|
void IgnoreTP(bool value)
|
|
{
|
|
mIgnoreTP = value;
|
|
}
|
|
|
|
//
|
|
bool IgnoreSL()
|
|
{
|
|
return mIgnoreSL;
|
|
}
|
|
|
|
//
|
|
void IgnoreSL(bool value)
|
|
{
|
|
mIgnoreSL = value;
|
|
}
|
|
|
|
//
|
|
bool IgnoreSignalExecution()
|
|
{
|
|
return mIgnoreSignalExecution;
|
|
}
|
|
|
|
//
|
|
void IgnoreSignalExecution(bool value)
|
|
{
|
|
mIgnoreSignalExecution = value;
|
|
}
|
|
|
|
//
|
|
// On Signal Handlers ...
|
|
void AddSignalEventHandler(TOnSignal handler)
|
|
{
|
|
//
|
|
Add(
|
|
handler,
|
|
mOnSignalEventHandlers //
|
|
);
|
|
}
|
|
|
|
//
|
|
ENUM_TIMEFRAMES AnalizePeriod()
|
|
{
|
|
return mAnalizePeriod;
|
|
}
|
|
|
|
//
|
|
void AnalizePeriod(ENUM_TIMEFRAMES value)
|
|
{
|
|
mAnalizePeriod = value;
|
|
}
|
|
|
|
//
|
|
bool DrawImportantAreas()
|
|
{
|
|
return mDrawImportantAreas;
|
|
}
|
|
|
|
//
|
|
void DrawImportantAreas(bool value)
|
|
{
|
|
mDrawImportantAreas = value;
|
|
}
|
|
|
|
//
|
|
// Important Areas Getters ...
|
|
|
|
//
|
|
bool GetSupport(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
result = support.IsValid();
|
|
if (result)
|
|
{
|
|
bar = support;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetResistance(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
result = resistance.IsValid();
|
|
if (result)
|
|
{
|
|
bar = resistance;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetBullishOB(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
result = bullishOB.IsValid();
|
|
if (result)
|
|
{
|
|
bar = bullishOB;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetBearishOB(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
result = bearishOB.IsValid();
|
|
if (result)
|
|
{
|
|
bar = bearishOB;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetBullishFVG(
|
|
XOHCL &bar,
|
|
double upper,
|
|
double lower //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
bar.Clean();
|
|
|
|
//
|
|
result = bullishFVG.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
bar = bullishFVG;
|
|
upper = bullishFVGUpper;
|
|
lower = bullishFVGLower;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetBearishFVG(
|
|
XOHCL &bar,
|
|
double upper,
|
|
double lower //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
bar.Clean();
|
|
|
|
//
|
|
result = bearishFVG.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
bar = bearishFVG;
|
|
upper = bearishFVGUpper;
|
|
lower = bearishFVGLower;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetBullishTrend(
|
|
XOHCL &bar,
|
|
XOHCL &swingHighs[],
|
|
XOHCL &swingLows[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
Clean(swingHighs);
|
|
Clean(swingLows);
|
|
|
|
//
|
|
result = bullishTrend.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
bar = bullishTrend;
|
|
|
|
//
|
|
Copy(
|
|
bullishTrendSwingHighs,
|
|
swingHighs //
|
|
);
|
|
Copy(
|
|
bullishTrendSwingLows,
|
|
swingLows //
|
|
);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetBearishTrend(
|
|
XOHCL &bar,
|
|
XOHCL &swingHighs[],
|
|
XOHCL &swingLows[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
Clean(swingHighs);
|
|
Clean(swingLows);
|
|
|
|
//
|
|
result = bearishTrend.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
bar = bearishTrend;
|
|
|
|
//
|
|
Copy(
|
|
bearishTrendSwingHighs,
|
|
swingHighs //
|
|
);
|
|
Copy(
|
|
bearishTrendSwingLows,
|
|
swingLows //
|
|
);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Virtual Methods ...
|
|
|
|
//
|
|
// Tag ...
|
|
virtual string GetTag()
|
|
{
|
|
return "XBaseStrategy";
|
|
}
|
|
|
|
//
|
|
// Check Conditions for Signal ...
|
|
// this must be Override based on each Strategy ...
|
|
virtual bool HasSignal(
|
|
XSignal &signal //
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Check Conditions For Signal and Execute Signal ...
|
|
virtual void HandleTick()
|
|
{
|
|
//
|
|
if (IsDisabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!AllowLong() && !AllowShort())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!barTracker.CanProcessBar())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
MqlTick cTick;
|
|
bool hasTick = GetTick(
|
|
mSymbol,
|
|
cTick //
|
|
);
|
|
bool isSameAsLast = cTick.time == lastTick.time;
|
|
if (isSameAsLast)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
lastTick = cTick;
|
|
|
|
//
|
|
XSignal signal;
|
|
bool hasSignal = HasSignal(signal);
|
|
if (!hasSignal)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
barTracker.Waits();
|
|
|
|
//
|
|
Execute(signal);
|
|
}
|
|
|
|
//
|
|
// Handle Signal Execution ...
|
|
virtual bool Execute(XSignal &signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Prepare and Normalize Signal ...
|
|
result = PrepareSignal(signal);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Notify Signal Event Handler(s) ...
|
|
NotifyOnSignalEventHandlers(signal);
|
|
|
|
//
|
|
// Check Signal Execution Enabled or not ...
|
|
result = !mIgnoreSignalExecution;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT state;
|
|
result = trader.ExecuteSignal(
|
|
signal,
|
|
state //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
string message = "Execute " + (isLong ? "Long" : "Short") + " " + signal.symbol + "/" + ToString(signal.period) + " ...";
|
|
Alert(message);
|
|
|
|
//
|
|
OnSignalExecuted(signal);
|
|
}
|
|
else
|
|
{
|
|
OnSignalExecutionFailed(signal, state);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calls When a Signal Executed Successfully ...
|
|
virtual void OnSignalExecuted(XSignal &signal)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Calls When a Signal Execution Failed ...
|
|
virtual void OnSignalExecutionFailed(
|
|
XSignal &signal,
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT result //
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
int mSlippage; // Trader Slippage
|
|
long mMagicNumber; // Trader Magic Number
|
|
bool mForceDisabled; // Force Disabled
|
|
bool mAllowLong; // Allow Long Signals
|
|
bool mAllowShort; // Allow Short Signals
|
|
int mMaxAllowedLongs; // Max Allowed Longs
|
|
int mMaxAllowedShorts; // Max Allowed Shorts
|
|
|
|
//
|
|
bool mUseTPSLAsPoint; // Converts TP and SL by Provided Points
|
|
bool mForceMaxTPSLAsPoint; // Force Max TP and SL by Provided Points
|
|
double mTPPoint; // TP As Point
|
|
double mSLPoint; // SL As Point
|
|
bool mIgnoreTP; // TP set to 0
|
|
bool mIgnoreSL; // SL set to 0
|
|
bool mIgnoreSignalExecution; // Ignore Signal Execution
|
|
|
|
//
|
|
string mSymbol; // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ...
|
|
|
|
//
|
|
double mR2R; // Risk/Rewar Ratio ...
|
|
double mVolume; // Static Volume Per Trades ...
|
|
|
|
//
|
|
XBarTracker barTracker; // Strategy Time Tracker ...
|
|
|
|
//
|
|
// Trend Detecting ...
|
|
int mRequiredPivots; // Required Pivots For Trend Detecting ...
|
|
int mRequiredShoulders; // Required Pivots Shoulders ...
|
|
|
|
//
|
|
XSCTrade *trader;
|
|
|
|
//
|
|
MqlTick lastTick;
|
|
|
|
//
|
|
void Reset()
|
|
{
|
|
barTracker.Clean();
|
|
}
|
|
|
|
//
|
|
// Prepare and Normalize Signal for Execution in Strategy ...
|
|
bool PrepareSignal(XSignal &signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Strategy Is Enables ...
|
|
result = !IsDisabled();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Signal ...
|
|
result = signal.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
// Check Type Enabled ...
|
|
result =
|
|
//
|
|
isLong
|
|
? AllowLong()
|
|
: AllowShort()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Max Allowed Trades Limitation ...
|
|
if (
|
|
(isLong && MaxAllowedLongs() > 0) ||
|
|
(!isLong && MaxAllowedShorts() > 0))
|
|
{
|
|
//
|
|
// Here We Have to Count Positions ...
|
|
|
|
//
|
|
// Get and Count Positions ...
|
|
XPosition longs[];
|
|
XPosition shorts[];
|
|
trader.GetPositions(
|
|
longs,
|
|
shorts,
|
|
signal.symbol //
|
|
);
|
|
|
|
//
|
|
int longsCount = ArraySize(longs);
|
|
int shortsCount = ArraySize(shorts);
|
|
|
|
//
|
|
result =
|
|
//
|
|
isLong
|
|
? longsCount < MaxAllowedLongs()
|
|
: shortsCount < MaxAllowedShorts()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check TP and SL ...
|
|
double points = GetPoints(signal.symbol);
|
|
if (mUseTPSLAsPoint)
|
|
{
|
|
//
|
|
double sl = 0;
|
|
double tp = 0;
|
|
bool isCalculated = !(mSLPoint > 0 || mTPPoint > 0)
|
|
? false
|
|
: CalculateTPSLByPoint(
|
|
sl,
|
|
tp,
|
|
signal.type,
|
|
signal.entry,
|
|
points,
|
|
mR2R,
|
|
mSLPoint,
|
|
mTPPoint //
|
|
);
|
|
if (isCalculated)
|
|
{
|
|
//
|
|
signal.sl = sl;
|
|
signal.tp = tp;
|
|
}
|
|
}
|
|
else if (mForceMaxTPSLAsPoint)
|
|
{
|
|
//
|
|
if (mSLPoint > 0)
|
|
{
|
|
//
|
|
double risk = signal.GetRisk();
|
|
double riskPoints = risk / points;
|
|
|
|
//
|
|
if (riskPoints > mSLPoint)
|
|
{
|
|
//
|
|
signal.sl =
|
|
isLong
|
|
? signal.entry - (mSLPoint * points)
|
|
: signal.entry + (mSLPoint * points);
|
|
}
|
|
}
|
|
|
|
//
|
|
if (mTPPoint > 0)
|
|
{
|
|
//
|
|
double reward = signal.GetReward();
|
|
double rewardPoints = reward / points;
|
|
|
|
//
|
|
if (rewardPoints > mTPPoint)
|
|
{
|
|
//
|
|
signal.tp =
|
|
isLong
|
|
? signal.entry + (mTPPoint * points)
|
|
: signal.entry - (mTPPoint * points);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (mIgnoreTP)
|
|
{
|
|
signal.tp = 0;
|
|
}
|
|
|
|
//
|
|
if (mIgnoreSL)
|
|
{
|
|
signal.sl = 0;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Notified Signal Event Handler(s) ...
|
|
void NotifyOnSignalEventHandlers(XSignal &signal)
|
|
{
|
|
//
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(mOnSignalEventHandlers);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
mOnSignalEventHandlers[i](signal);
|
|
}
|
|
}
|
|
|
|
//
|
|
ENUM_TIMEFRAMES mAnalizePeriod; // Important Area Detect Time Frame
|
|
bool mDrawImportantAreas; // Draw Important Areas where Founded in Analyzing Time Frame
|
|
|
|
//
|
|
XOHCL support;
|
|
XOHCL resistance;
|
|
XOHCL bullishOB;
|
|
XOHCL bearishOB;
|
|
|
|
//
|
|
double bullishFVGUpper;
|
|
double bullishFVGLower;
|
|
XOHCL bullishFVG;
|
|
|
|
//
|
|
double bearishFVGUpper;
|
|
double bearishFVGLower;
|
|
XOHCL bearishFVG;
|
|
|
|
//
|
|
XOHCL bullishTrendSwingHighs[];
|
|
XOHCL bullishTrendSwingLows[];
|
|
XOHCL bullishTrend;
|
|
|
|
//
|
|
XOHCL bearishTrendSwingHighs[];
|
|
XOHCL bearishTrendSwingLows[];
|
|
XOHCL bearishTrend;
|
|
|
|
//
|
|
void DetectImportantAreas()
|
|
{
|
|
//
|
|
int zIndex = 0;
|
|
int cIndex = zIndex + 1;
|
|
|
|
//
|
|
// Last Bar ...
|
|
XOHCL cBar;
|
|
bool result = cBar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
cIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Analyzing Bar ...
|
|
XOHCL aBar;
|
|
if (IsValid(mAnalizePeriod))
|
|
{
|
|
//
|
|
result = aBar.Init(
|
|
mSymbol,
|
|
mAnalizePeriod,
|
|
cIndex //
|
|
);
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aBar = cBar;
|
|
}
|
|
|
|
//
|
|
// Support nad Resistance ...
|
|
|
|
//
|
|
// Check Support Exists or Find ...
|
|
bool hasSupport = support.IsValid();
|
|
if (!hasSupport)
|
|
{
|
|
//
|
|
hasSupport =
|
|
//
|
|
aBar.HasSupport(support)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (hasSupport)
|
|
{
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawSupport(
|
|
support,
|
|
ChartID() //
|
|
);
|
|
}
|
|
|
|
//
|
|
supportTime = aBar.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Resistance Exists or Find ...
|
|
bool hasResistance = resistance.IsValid();
|
|
if (!hasResistance)
|
|
{
|
|
//
|
|
hasResistance =
|
|
//
|
|
aBar.HasResistance(resistance)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (hasResistance)
|
|
{
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawResistance(
|
|
resistance,
|
|
ChartID() //
|
|
);
|
|
}
|
|
|
|
//
|
|
resistanceTime = aBar.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Order Blocks ...
|
|
|
|
//
|
|
bool hasBullishOB = bullishOB.IsValid();
|
|
if (!hasBullishOB)
|
|
{
|
|
//
|
|
hasBullishOB =
|
|
//
|
|
aBar.HasBullishOrderBlock(bullishOB)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (hasBullishOB)
|
|
{
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawBullishOrderBlock(
|
|
bullishOB,
|
|
ChartID() //
|
|
);
|
|
}
|
|
|
|
//
|
|
bullishOBTime = aBar.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
bool hasBearishOB = bearishOB.IsValid();
|
|
if (!hasBearishOB)
|
|
{
|
|
//
|
|
hasBearishOB =
|
|
//
|
|
aBar.HasBearishOrderBlock(bearishOB)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (hasBearishOB)
|
|
{
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawBearishOrderBlock(
|
|
bearishOB,
|
|
ChartID() //
|
|
);
|
|
}
|
|
|
|
//
|
|
bearishOBTime = aBar.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
// FVG ...
|
|
|
|
//
|
|
bool hasBullishFVG = bullishFVG.IsValid();
|
|
if (!hasBullishFVG)
|
|
{
|
|
//
|
|
hasBullishFVG =
|
|
//
|
|
aBar.HasBullishFVG(
|
|
bullishFVGUpper,
|
|
bullishFVGLower //
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (hasBullishFVG)
|
|
{
|
|
//
|
|
bullishFVG = aBar;
|
|
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawBullishFVG(
|
|
bullishFVG,
|
|
bullishFVGUpper,
|
|
bullishFVGLower,
|
|
ChartID() //
|
|
);
|
|
}
|
|
|
|
//
|
|
bullishFVGTime = aBar.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
bool hasBearishFVG = bearishFVG.IsValid();
|
|
if (!hasBearishFVG)
|
|
{
|
|
//
|
|
hasBearishFVG =
|
|
//
|
|
aBar.HasBearishFVG(
|
|
bearishFVGUpper,
|
|
bearishFVGLower //
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (hasBearishFVG)
|
|
{
|
|
//
|
|
bearishFVG = aBar;
|
|
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawBearishFVG(
|
|
bearishFVG,
|
|
bearishFVGUpper,
|
|
bearishFVGLower,
|
|
ChartID() //
|
|
);
|
|
}
|
|
|
|
//
|
|
bearishFVGTime = aBar.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
// TREND ...
|
|
|
|
//
|
|
bool hasBullishTrend = bullishTrend.IsValid();
|
|
if (!hasBullishTrend)
|
|
{
|
|
//
|
|
hasBullishTrend = aBar.HasBullishTrend(
|
|
bullishTrendSwingHighs,
|
|
bullishTrendSwingLows,
|
|
false //
|
|
);
|
|
|
|
//
|
|
if (hasBullishTrend)
|
|
{
|
|
//
|
|
bullishTrend = aBar;
|
|
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawBullishTrend(
|
|
bullishTrend,
|
|
bullishTrendSwingHighs,
|
|
bullishTrendSwingLows,
|
|
ChartID() //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
bool hasBearishTrend = bearishTrend.IsValid();
|
|
if (!hasBearishTrend)
|
|
{
|
|
//
|
|
hasBearishTrend = aBar.HasBearishTrend(
|
|
bearishTrendSwingHighs,
|
|
bearishTrendSwingLows,
|
|
false //
|
|
);
|
|
|
|
//
|
|
if (hasBearishTrend)
|
|
{
|
|
//
|
|
bearishTrend = aBar;
|
|
|
|
//
|
|
if (mDrawImportantAreas)
|
|
{
|
|
//
|
|
DrawBearishTrend(
|
|
bearishTrend,
|
|
bearishTrendSwingHighs,
|
|
bearishTrendSwingLows,
|
|
ChartID() //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
void DestroyImportantAreas()
|
|
{
|
|
//
|
|
bool hasSupport = support.IsValid();
|
|
if (hasSupport)
|
|
{
|
|
//
|
|
supportTime = NULL;
|
|
isSupportTested = false;
|
|
RemoveSupport(support);
|
|
support.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasResistance = resistance.IsValid();
|
|
if (hasResistance)
|
|
{
|
|
//
|
|
resistanceTime = NULL;
|
|
isResistanceTested = false;
|
|
RemoveResistance(resistance);
|
|
resistance.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBullishOB = bullishOB.IsValid();
|
|
if (hasBullishOB)
|
|
{
|
|
//
|
|
bullishOBTime = NULL;
|
|
RemoveBullishOrderBlock(bullishOB);
|
|
bullishOB.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBearishOB = bearishOB.IsValid();
|
|
if (hasBearishOB)
|
|
{
|
|
//
|
|
bearishOBTime = NULL;
|
|
RemoveBearishOrderBlock(bearishOB);
|
|
bearishOB.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBullishFVG = bullishFVG.IsValid();
|
|
if (hasBullishFVG)
|
|
{
|
|
//
|
|
bullishFVGUpper = 0;
|
|
bullishFVGLower = 0;
|
|
bullishFVGTime = NULL;
|
|
RemoveBullishFVG(bullishFVG);
|
|
bullishFVG.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBearishFVG = bearishFVG.IsValid();
|
|
if (hasBearishFVG)
|
|
{
|
|
//
|
|
bearishFVGUpper = 0;
|
|
bearishFVGLower = 0;
|
|
bearishFVGTime = NULL;
|
|
RemoveBullishFVG(bearishFVG);
|
|
bearishFVG.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBullishTrend = bullishTrend.IsValid();
|
|
if (hasBullishTrend)
|
|
{
|
|
//
|
|
RemoveBullishTrend(bullishTrend);
|
|
bullishTrend.Clean();
|
|
}
|
|
|
|
//
|
|
bool hasBearishTrend = bearishTrend.IsValid();
|
|
if (hasBearishTrend)
|
|
{
|
|
//
|
|
RemoveBearishTrend(bearishTrend);
|
|
bearishTrend.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
void CheckImportantAreasValidation()
|
|
{
|
|
//
|
|
CheckSupportValidation();
|
|
CheckResistanceValidation();
|
|
|
|
//
|
|
CheckBullishOBValidation();
|
|
CheckBearishOBValidation();
|
|
|
|
//
|
|
CheckBullishFVGValidation();
|
|
CheckBearishFVgValidation();
|
|
|
|
//
|
|
CheckBullishTrendValidation();
|
|
CheckBearishTrendValidation();
|
|
}
|
|
|
|
//
|
|
bool isSupportTested;
|
|
datetime supportTime;
|
|
void CheckSupportValidation()
|
|
{
|
|
//
|
|
if (!isSupportTested)
|
|
{
|
|
//
|
|
if (support.IsValid() && IsValid(supportTime))
|
|
{
|
|
//
|
|
int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(supportTime))) / PeriodSeconds(mPeriod));
|
|
if (age >= 50)
|
|
{
|
|
//
|
|
isSupportTested = false;
|
|
supportTime = NULL;
|
|
RemoveSupport(support);
|
|
support.Clean();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
XOHCL cBar;
|
|
bool isInited = cBar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
1 //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double points = GetPoints(mSymbol);
|
|
|
|
//
|
|
// Find Price Distance ...
|
|
double highDiff = MathAbs(cBar.high - support.high);
|
|
double lowDiff = MathAbs(cBar.low - support.high);
|
|
|
|
//
|
|
bool isBreaked = MathMax(highDiff, lowDiff) >= 100 * points;
|
|
if (!isBreaked)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
isSupportTested = false;
|
|
RemoveSupport(support);
|
|
supportTime = NULL;
|
|
support.Clean();
|
|
}
|
|
|
|
//
|
|
bool isResistanceTested;
|
|
datetime resistanceTime;
|
|
void CheckResistanceValidation()
|
|
{
|
|
//
|
|
if (!isResistanceTested)
|
|
{
|
|
//
|
|
if (resistance.IsValid() && IsValid(resistanceTime))
|
|
{
|
|
//
|
|
int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(resistanceTime))) / PeriodSeconds(mPeriod));
|
|
if (age >= 50)
|
|
{
|
|
//
|
|
isResistanceTested = false;
|
|
resistanceTime = NULL;
|
|
RemoveResistance(resistance);
|
|
resistance.Clean();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
XOHCL cBar;
|
|
bool isInited = cBar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
1 //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double points = GetPoints(mSymbol);
|
|
|
|
//
|
|
// Find Price Distance ...
|
|
double highDiff = MathAbs(cBar.high - resistance.low);
|
|
double lowDiff = MathAbs(cBar.low - resistance.low);
|
|
|
|
//
|
|
bool isBreaked = MathMax(highDiff, lowDiff) >= 100 * points;
|
|
if (!isBreaked)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
isResistanceTested = false;
|
|
RemoveResistance(resistance);
|
|
resistanceTime = NULL;
|
|
resistance.Clean();
|
|
}
|
|
|
|
//
|
|
datetime bullishOBTime;
|
|
void CheckBullishOBValidation()
|
|
{
|
|
//
|
|
if (!IsValid(bullishOBTime))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bullishOBTime))) / PeriodSeconds(mPeriod));
|
|
if (age >= 50)
|
|
{
|
|
//
|
|
bullishOBTime = NULL;
|
|
RemoveBullishOrderBlock(bullishOB);
|
|
bullishOB.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
datetime bearishOBTime;
|
|
void CheckBearishOBValidation()
|
|
{
|
|
//
|
|
if (!IsValid(bearishOBTime))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bearishOBTime))) / PeriodSeconds(mPeriod));
|
|
if (age >= 50)
|
|
{
|
|
//
|
|
bearishOBTime = NULL;
|
|
RemoveBearishOrderBlock(bearishOB);
|
|
bearishOB.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
datetime bullishFVGTime;
|
|
void CheckBullishFVGValidation()
|
|
{
|
|
//
|
|
if (!IsValid(bullishFVGTime))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bullishFVGTime))) / PeriodSeconds(mPeriod));
|
|
if (age >= 50)
|
|
{
|
|
//
|
|
bullishFVGTime = NULL;
|
|
RemoveBullishFVG(bullishFVG);
|
|
bullishFVG.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
datetime bearishFVGTime;
|
|
void CheckBearishFVgValidation()
|
|
{
|
|
//
|
|
if (!IsValid(bearishFVGTime))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bearishFVGTime))) / PeriodSeconds(mPeriod));
|
|
if (age >= 50)
|
|
{
|
|
//
|
|
bearishFVGTime = NULL;
|
|
RemoveBearishFVG(bearishFVG);
|
|
bearishFVG.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
void CheckBullishTrendValidation()
|
|
{
|
|
//
|
|
// TODO: Complete this ...
|
|
}
|
|
|
|
//
|
|
void CheckBearishTrendValidation()
|
|
{
|
|
//
|
|
// TODO: Complete this ...
|
|
}
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// On Signal Recieved Event Handler(s) ...
|
|
TOnSignal mOnSignalEventHandlers[];
|
|
};
|
|
|
|
// |