/////////////////////////////////////////////////////// // // 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 // ); } } // }; //