Files
MQL5Data/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5
T

983 lines
20 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XSCX121Strategy
// 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 "../../Classes/x-saherelm.x-poi.class.mq5"
#include "../../Classes/x-saherelm.xalert.class.mq5"
#include "../../Classes/x-saherelm.xtrade.class.mq5"
#include "../Libraries/x-121.smc.lib.mq5"
//
// Helper(s) ...
//
// XStrategy Class Implementation(s) ...
class XCX121SMCStrategy : public XSCBaseAlert
{
//
// Public ...
public:
//
//
// Constructor(s) ...
void XCX121SMCStrategy(
//
// Base ...
string _symbol, // Trading Symbol
ENUM_TIMEFRAMES _period // Trading TimeFrame
)
{
//
mSymbol = _symbol;
mPeriod = _period;
//
Init();
}
//
// Deconstructor ...
void ~XCX121SMCStrategy()
{
DeInit();
}
//
// Getter / Setter (s) ...
/**
* Retrieve Symbol ...
*
* @return ( string )
*/
string Symbol()
{
return mSymbol;
}
/**
* Retrieve TimeFrame ...
*
* @return ( ENUM_TIMEFRAMES )
*/
ENUM_TIMEFRAMES Period()
{
return mPeriod;
}
/**
* Check Strategy is Disabled or not ...
*
* @return ( bool )
*/
bool IsDisabled()
{
return mForceDisabled;
}
/**
* Get Signal Volume ...
*
* @return ( double )
*/
double Volume()
{
return mVolume;
}
/**
* Set Signal Volume ...
*
* @param value: Double ...
*/
void Volume(double value)
{
//
if (value < 0.01)
{
value = 0.01;
}
//
mVolume = value;
}
/**
* Get Risk/Reward Ratio ...
*
* @return ( double )
*/
double R2R()
{
return mR2R;
}
/**
* Set Risk/Reward Ratio ...
*
* @param value: Double ...
*/
void R2R(double value)
{
//
if (value < 0)
{
value = 1.5;
}
//
mR2R = value;
}
/**
* Get Long Signalling State ...
*
* @return ( bool )
*/
bool AllowLong()
{
return mAllowLong;
}
/**
* Set Long Signalling State ...
*
* @param value: Boolean ...
*/
void AllowLong(bool value)
{
mAllowLong = value;
}
/**
* Get Short Signalling State ...
*
* @return ( bool )
*/
bool AllowShort()
{
return mAllowShort;
}
/**
* Set Short Signalling State ...
*
* @param value: Argument 1
*/
void AllowShort(bool value)
{
mAllowShort = value;
}
//
// Actions ...
/**
* Disable Strategy ...
*/
void Disable()
{
mForceDisabled = true;
}
/**
* Enable Strategy ...
*/
void Enable()
{
mForceDisabled = false;
}
/**
* Register Signal Event Handler ...
*
* @param handler: an Instance of TOnXSignal ...
*/
void AddXSignalEventHandler(TOnX121SMCSignal handler)
{
//
Add(
handler,
mSignalEventHandlers //
);
}
//
// Virtual Actions ...
//
// Check Conditions For Signal and Execute Signal ...
virtual void HandleTick()
{
//
// Check State ...
if (IsDisabled())
{
return;
}
//
// Check Signalling State ...
if (!AllowLong() && !AllowShort())
{
return;
}
//
// Check Bar Tracker State ...
if (!mBarTracker.CanProcessBar())
{
return;
}
//
// Retrieve Current Tick and Check it's Time
// by Last Issued Tick ...
MqlTick cTick;
bool hasTick = GetTick(
mSymbol,
cTick //
);
bool isSameAsLast = cTick.time == mLastTick.time;
if (isSameAsLast)
{
return;
}
//
// Update Last Issued Tick ...
mLastTick = cTick;
//
// Check Current Processing Tick has Signal or not ...
XSignal signal;
X121SMCStrategyConditions conditions;
bool hasSignal = HasSignal(
signal,
conditions //
);
if (!hasSignal)
{
return;
}
//
// Waits Until Next Candle if Current Tick has Signal ...
mBarTracker.Waits();
//
// Notify Signal Event Handlers ...
NotifyOnSignalEventHandlers(
signal,
conditions //
);
}
//
// Check Conditions For Signal ...
virtual bool HasSignal(
XSignal &signal,
X121SMCStrategyConditions &conditions //
)
{
//
bool result = false;
//
signal.Clean();
conditions.Clean();
//
double sl = 0;
double tp = 0;
double risk = 0;
double entry = 0;
double reward = 0;
double r2r = R2R();
double volume = Volume();
ENUM_POSITION_TYPE type = POSITION_TYPE_BUY;
ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET;
//
bool hasLong = false;
bool hasShort = false;
//
// Start Calculations ...
//
double points = GetPoints(mSymbol);
//
int zIndex = 0;
int cIndex = zIndex + 1;
int pIndex = cIndex + 1;
int ppIndex = pIndex + 1;
//
// Retrieve Bars ...
//
// Zero Bar ...
XOHCL zBar;
result = zBar.Init(
mSymbol,
mPeriod,
zIndex //
);
if (!result)
{
return result;
}
//
// Last Bar ...
XOHCL cBar;
result = cBar.Init(
mSymbol,
mPeriod,
cIndex //
);
if (!result)
{
return result;
}
//
// Prepare Conditions ...
//
conditions.symbol = mSymbol;
conditions.period = mPeriod;
conditions.time = cBar.time;
//
int pushers = 0;
string signallers[];
//
// Define Conditions ...
MqlTick ticks[];
int ticksCount = CopyTicks(
mSymbol,
ticks,
COPY_TICKS_ALL,
0,
5 //
);
//
bool isTicksBullishForLong = false;
bool isTicksBearishForLong = false;
bool isTicksBullishForShort = false;
bool isTicksBearishForShort = false;
if (ticksCount == 5)
{
//
isTicksBullishForLong =
//
GetTickEntry(ticks[0], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) &&
GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) &&
GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, mSymbol)
//
;
//
isTicksBearishForLong =
//
GetTickEntry(ticks[0], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) &&
GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) &&
GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[3], POSITION_TYPE_BUY, mSymbol)
//
;
//
isTicksBullishForShort =
//
GetTickEntry(ticks[0], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) &&
GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) &&
GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[3], POSITION_TYPE_SELL, mSymbol)
//
;
//
isTicksBearishForShort =
//
GetTickEntry(ticks[0], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) &&
GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) &&
GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, mSymbol)
//
;
}
//
// Reading POI(s) ...
//
// 4H ...
XPOIState _4HState;
m4HPOI.GetState(_4HState);
//
// 15M ...
XPOIState _15MState;
m15MPOI.GetState(_15MState);
//
// 5M ...
XPOIState _5MState;
m5MPOI.GetState(_5MState);
//
// Try to Implement SMC Based Conditions ...
//
// 1- First Step is Find a Supply and Demand Zone ...
// - [] this Zone must be Fresh ...
// - [] contains Engulfing ...
// - [] has Order Block ...
// - [] has FVG ...
XZone _4hSupplyZone;
XZone _4HDemandZone;
DetectSupplyAndDemandZones(
_4HState,
_4hSupplyZone,
_4HDemandZone //
);
//
if (_4hSupplyZone.IsValid())
{
//
// Update Supply Zone Time ...
string iName = _4hSupplyZone.GetTag();
_4hSupplyZone.to = zBar.time;
//
int count = mDrawnObjects.Total();
if (IsValidSize(count))
{
//
int idx = -1;
for (int i = 0; i < count; i++)
{
//
int type = ((CChartObject *)mDrawnObjects.At(i)).Type();
if (type == (int)X_SUPPLY_ZONE)
{
//
string objName = ((XCZoneObject *)mDrawnObjects.At(i)).ObjName();
if (objName == iName)
{
//
idx = i;
break;
}
}
}
//
if (IsValidIndex(idx))
{
mDrawnObjects.Delete(idx);
}
}
//
iName = _4hSupplyZone.GetTag();
XCZoneObject *iObj;
bool isCreated = iObj.CreateByZone(
ChartID(),
iName,
0,
_4hSupplyZone,
NULL,
true //
);
}
//
// LONGS ...
//
bool hasLong1 =
//
false
//
;
if (hasLong1)
{
//
pushers++;
Add(
"LONG_1",
signallers //
);
//
// TODO: Implement SL/TP Calculation based on R2R ...
//
// sl = 0;
type = POSITION_TYPE_BUY;
}
//
// SHORTS ...
//
bool hasShort1 =
//
// TODO: Implement Long Conditions ...
false
//
;
if (hasShort1)
{
//
pushers++;
Add(
"SHORT_1",
signallers //
);
//
// TODO: Implement SL/TP Calculation based on R2R ...
//
// sl = 0;
type = POSITION_TYPE_SELL;
}
//
// Combine Signals ...
//
hasLong =
//
hasLong1 ||
//
// TODO: Attach other Conditions ...
false
//
;
//
hasShort =
//
hasShort1 ||
//
// TODO: Attach other Conditions ...
false
//
;
//
result = hasLong || hasShort;
if (!result)
{
return result;
}
//
// Retrieve Entry Price based on Position Type ...
entry = GetEntry(mSymbol, type);
//
// Calculate TP and SL ...
// based on Strategy ...
// only when on of TP or SL Provides, using provided R2R ...
if ((tp <= 0 && sl > 0) || (tp > 0 && sl <= 0))
{
//
CalculateTPSLByPrice(
sl,
tp,
type,
entry,
r2r //
);
}
//
// Prepare Signal ...
result = signal.Prepare(
mSymbol,
signallers[0],
mPeriod,
type,
mode,
entry,
volume,
sl,
tp //
);
if (!result)
{
return result;
}
//
signal.pushers = pushers;
//
// Prepare and Normalize Signal for Execution in Strategy ...
result = PrepareSignal(signal);
if (!result)
{
return result;
}
//
// Attach Strategy Lebel ...
signal.provider = X121SMCStrategyToken;
//
return result;
}
//
// Overrides ...
//
// Customize Strategy Identifier ...
string GetTag() override
{
return X121SMCStrategyToken;
}
//
// Protected ...
protected:
//
//
// Props ...
//
// Private ...
private:
//
// Props ...
//
string mSymbol; // Trading Symbol ...
ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ...
bool mForceDisabled; // Force Disabled ...
bool mAllowLong; // Allow Long Signals
bool mAllowShort; // Allow Short Signals
double mR2R; // Risk/Rewar Ratio ...
double mVolume; // Static Volume Per Trades ...
//
MqlTick mLastTick; // Last Issued Tick ...
XBarTracker mBarTracker; // Strategy Time Tracker ...
//
// Point Of Interests ...
XCPOI *m4HPOI;
XCPOI *m15MPOI;
XCPOI *m5MPOI;
//
// Collect all Drawn Objects ...
CArrayObj mDrawnObjects;
//
// Actions ...
/**
* Install all Helpers and Prepare all Configurations for required Indicators ...
*/
void Init()
{
//
mForceDisabled = false;
//
string symbol = Symbol();
ENUM_TIMEFRAMES period = Period();
//
// Initialize Bar Tracker ...
mBarTracker.Init(
symbol,
period //
);
//
// Initialize POIs ...
//
// 4H Period ...
m4HPOI = new XCPOI(
symbol,
PERIOD_H4 //
);
//
m4HPOI.Window(0);
m4HPOI.DisableDrawPOIs();
m4HPOI.ChartID(ChartID());
m4HPOI.MaxNumberOfRequiredPOIs(0);
m4HPOI.SupplyZonePeriod(PERIOD_H4);
m4HPOI.DemandZonePeriod(PERIOD_H4);
//
m4HPOI.Init();
//
// 15M Period ...
m15MPOI = new XCPOI(
symbol,
PERIOD_M15 //
);
//
m15MPOI.Window(0);
m15MPOI.DisableDrawPOIs();
m15MPOI.ChartID(ChartID());
m15MPOI.MaxNumberOfRequiredPOIs(2);
m15MPOI.SupplyZonePeriod(PERIOD_M15);
m15MPOI.DemandZonePeriod(PERIOD_M15);
//
m15MPOI.Init();
//
// Trigger Period ...
m5MPOI = new XCPOI(
symbol,
period //
);
//
m5MPOI.Window(0);
m5MPOI.DisableDrawPOIs();
m5MPOI.ChartID(ChartID());
m5MPOI.MaxNumberOfRequiredPOIs(2);
m5MPOI.SupplyZonePeriod(PERIOD_M5);
m5MPOI.DemandZonePeriod(PERIOD_M5);
//
m5MPOI.Init();
//
}
/**
* De Initialize all Tools ...
*/
void DeInit()
{
//
delete m4HPOI;
delete m5MPOI;
delete m15MPOI;
}
/**
* Reste Bar Tracker ...
*/
void ResetBarTracker()
{
mBarTracker.Clean();
}
/**
* Prepare and Normalize Signal for Execution in Strategy ...
*
* @param signal: XSignal instance ...
*
* @return ( bool )
*/
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);
//
// TODO: Implement Signal Preparation Mechanism here ...
//
return result;
}
/**
* Detect Supply and Demand Zones ...
*
* @param state: Argument 1
* @param supplyZone: Argument 2
* @param demandZone: Argument 3
*/
void DetectSupplyAndDemandZones(
XPOIState &state,
XZone &supplyZone,
XZone &demandZone //
)
{
//
supplyZone.Clean();
demandZone.Clean();
//
int supplyZonesCount = ArraySize(state.supplyZones);
int demandZonesCount = ArraySize(state.demandZones);
if (!IsValidSize(supplyZonesCount) &&
!IsValidSize(demandZonesCount))
{
return;
}
//
XOHCL zBar;
bool isInited = zBar.Init(
Symbol(),
Period(),
0 //
);
if (!isInited)
{
return;
}
//
// Detect Supply Zone ...
for (int i = 0; i < supplyZonesCount; i++)
{
//
XZone iZone = state.supplyZones[i];
//
// Retrieve Zone From Index Based On Current Period ...
int iZoneStartBarIndex = iBarShift(
Symbol(),
Period(),
iZone.from //
);
//
// Check Zone is Fresh Or Not ...
bool isFreshZone = true;
for (int j = iZoneStartBarIndex - 1; j >= 0; j++)
{
//
XOHCL jBar;
bool isInited = jBar.Init(
Symbol(),
Period(),
j //
);
if (!isInited)
{
continue;
}
//
if (jBar.high > iZone.lower)
{
//
isFreshZone = false;
break;
}
//
}
//
if (!isFreshZone)
{
continue;
}
//
supplyZone = iZone;
break;
}
}
//
// On X121 Signal Recieved Event Handler(s) ...
TOnX121SMCSignal mSignalEventHandlers[];
//
/**
* Notified Signal Event Handler(s) ...
*
* @param signal: XSignal instance ...
* @param conditions: XStrategyConditions instance ...
*/
void NotifyOnSignalEventHandlers(
XSignal &signal,
X121SMCStrategyConditions &conditions //
)
{
//
if (!signal.IsValid() || !conditions.IsValid())
{
return;
}
//
int count = ArraySize(mSignalEventHandlers);
if (!IsValidSize(count))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
mSignalEventHandlers[i](
signal,
conditions //
);
}
}
//
};
//