diff --git a/Experts/x-saherelm.x-121.smc.ea.mq5 b/Experts/x-saherelm.x-121.smc.ea.mq5 index 869c8cea..617b5e6a 100644 --- a/Experts/x-saherelm.x-121.smc.ea.mq5 +++ b/Experts/x-saherelm.x-121.smc.ea.mq5 @@ -28,7 +28,8 @@ #include "../Helpers/x-saherelm.xcc.helper.mq5" #include "../Helpers/x-saherelm.xct.helper.mq5" #include "../X121SMCEA/Classes/x-121.smc.ea.panel.class.mq5" -#include "../X121SMCEA/Strategy/x-121.smc.strategy.class.mq5" +#include "../X121SMCEA/Strategy/x-121.smc.ob.strategy.class.mq5" +#include "../X121SMCEA/Strategy/x-121.smc.supdem.strategy.class.mq5" // // Inputs ... @@ -75,14 +76,14 @@ input bool eaReportNewHours = false; // Report New Hours // Define Local Variables ... // -string eaLogTag; // EA Log Prefix ... -XSCAlert *eaAlert; // Alert Provider for Expert Adviser ... -XSCTrade *eaTrader; // Trader of Expert Adviser ... -XTimeTracker eaTimeTracker; // Time Tracker for Providing Reports ... -XSCXCTHelper *eaCTHelper; // Bar Timer Indicator Helper class ... -XSCXCCHelper *eaCCHelper; // Chart Styler Indicator Helper Class ... -X121CAppDialog eaMainWindow; // EA Main Dialog ... -XCX121SMCStrategy *eaStrategies[]; // Registere Strategies in EA ... +string eaLogTag; // EA Log Prefix ... +XSCAlert *eaAlert; // Alert Provider for Expert Adviser ... +XSCTrade *eaTrader; // Trader of Expert Adviser ... +XTimeTracker eaTimeTracker; // Time Tracker for Providing Reports ... +XSCXCTHelper *eaCTHelper; // Bar Timer Indicator Helper class ... +XSCXCCHelper *eaCCHelper; // Chart Styler Indicator Helper Class ... +X121CAppDialog eaMainWindow; // EA Main Dialog ... +XCX121SMCBaseStrategy *eaStrategies[]; // Registere Strategies in EA ... // // Signalling Controller Conditions ... @@ -447,8 +448,8 @@ bool InitEA() // // Create Class Instance ... - XCX121SMCStrategy *iX121SMCStrategy; - iX121SMCStrategy = new XCX121SMCStrategy( + XCX121SMCBaseStrategy *iX121SMCStrategy; + iX121SMCStrategy = new XCX121SMCOBStrategy( _Symbol, _Period // ); @@ -512,8 +513,8 @@ bool InitEA() { // // Create Class Instance ... - XCX121SMCStrategy *iX121SMCStrategy; - iX121SMCStrategy = new XCX121SMCStrategy( + XCX121SMCBaseStrategy *iX121SMCStrategy; + iX121SMCStrategy = new XCX121SMCOBStrategy( iSymbol, _Period // ); @@ -727,7 +728,7 @@ void InitControllerConditions() /** * Configure Startegy ... */ -void ConfigureStrategy(XCX121SMCStrategy *&strategy) +void ConfigureStrategy(XCX121SMCBaseStrategy *&strategy) { // if (strategy == NULL) @@ -767,9 +768,9 @@ void ConfigureStrategy(XCX121SMCStrategy *&strategy) /** * Register an Strategy in EA ... * - * @param strategy: XCX121SMCStrategy instance ... + * @param strategy: XCX121SMCBaseStrategy instance ... */ -void RegisterStrategy(XCX121SMCStrategy *strategy) +void RegisterStrategy(XCX121SMCBaseStrategy *strategy) { // if (strategy == NULL) diff --git a/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 b/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 new file mode 100644 index 00000000..ff9ae218 --- /dev/null +++ b/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 @@ -0,0 +1,1446 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XSCX121SMCBaseStrategy +// 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 "../Classes/x-121.smc.chart.objects.class.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Helper(s) ... + +// +// XStrategy Class Implementation(s) ... +class XCX121SMCBaseStrategy : public XSCBaseAlert +{ + // + // Public ... + public: + // + + // + // Constructor(s) ... + void XCX121SMCBaseStrategy( + // + // Base ... + string _symbol, // Trading Symbol + ENUM_TIMEFRAMES _period // Trading TimeFrame + ) + { + // + mSymbol = _symbol; + mPeriod = _period; + + // + Init(); + } + + // + // Deconstructor ... + void ~XCX121SMCBaseStrategy() + { + DeInit(); + } + + // + // Getter / Setter (s) ... + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string GetSymbol() + { + return mSymbol; + } + + /** + * Retrieve TimeFrame ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + /** + * Check Strategy is Disabled or not ... + * + * @return ( bool ) + */ + bool IsDisabled() + { + return mForceDisabled; + } + + /** + * Get Chart Id ... + * + * @return ( long ) + */ + long ChartIdentification() + { + return mChartID; + } + + /** + * Set Chart Id ... + * + * @param value: Long ... + */ + void ChartIdentification(long value) + { + // + if (value < 0) + { + value = 0; + } + + // + mChartID = value; + if (mPOIDrawer != NULL) + { + mPOIDrawer.ChartIdentification(value); + } + } + + /** + * Get Sub Window Id ... + * + * @return ( int ) + */ + int SubWindowIdentification() + { + return mSubWindow; + } + + /** + * Set Sub Window Id ... + * + * @param value: Integer ... + */ + void SubWindowIdentification(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSubWindow = value; + if (mPOIDrawer != NULL) + { + mPOIDrawer.SubWindowIdentification(value); + } + } + + /** + * 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 Max Allowed Spread ... + * + * @return ( double ) + */ + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + /** + * Set Max Allowed Spread ... + * + * @param value: Double ... + */ + void MaxAllowedSpread(double value) + { + mMaxAllowedSpread = 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 ... + + /** + * Handle Tick Processing ... + */ + 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; + SaveTickData(); + CleanupTicks(); + + // + // Update POIs ... + + // + ENUM_XPOI_EVENTS _1DStates[]; + m1DPOI.Update(_1DStates); + + // + ENUM_XPOI_EVENTS _4HStates[]; + m4HPOI.Update(_4HStates); + + // + ENUM_XPOI_EVENTS _15MStates[]; + m15MPOI.Update(_15MStates); + + // + ENUM_XPOI_EVENTS _5MStates[]; + m5MPOI.Update(_5MStates); + + // + ENUM_XPOI_EVENTS _1MStates[]; + m1MPOI.Update(_1MStates); + + // + // Read all POI States ... + m1DPOI.GetState(_1DState); + m4HPOI.GetState(_4HState); + m15MPOI.GetState(_15MState); + m5MPOI.GetState(_5MState); + m1MPOI.GetState(_1MState); + + // + // Combine States ... + XPOIState _States[]; + AddRef( + _1DState, + _States // + ); + AddRef( + _4HState, + _States // + ); + AddRef( + _15MState, + _States // + ); + AddRef( + _5MState, + _States // + ); + AddRef( + _1MState, + _States // + ); + CombineStates( + _CombineState, + _States // + ); + + // + // 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 // + ); + + // + DrawSignal(signal); + } + + /** + * Check For Signal ... + * + * @param signal: XSignal instance ... + * @param conditions: X121SMCStrategyConditions instance ... + * + * @return ( virtual bool ) + */ + virtual bool HasSignal( + XSignal &signal, + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + signal.Clean(); + conditions.Clean(); + + // + return result; + } + + /** + * Detect Valid Market Conditions ... + * + * @param conditions: X121SMCStrategyConditions instance ... + * + * @return ( virtual bool ) + */ + virtual bool DetecConditions(X121SMCStrategyConditions &conditions) + { + // + bool result = false; + + // + conditions.Clean(); + + // + return result; + } + + /** + * Detect Market Structure based on Conditions ... + * + * @param structure: X121SMCMarketStructure instance ... + * @param conditions: X121SMCStrategyConditions instance ... + */ + virtual void DetectMarketStructure( + X121SMCMarketStructure &structure, + X121SMCStrategyConditions &conditions // + ) + { + } + + /** + * Remove Specific Conditions if Exists ... + * + * @param conditions: X121SMCStrategyConditions instance ... + */ + virtual void RemoveConditionsIfExists(X121SMCStrategyConditions &conditions) + { + } + + /** + * Search Conditions for Find SL Candidates ... + * + * @param candidates: Double Array ... + * @param entry: Double ... + * @param structure: X121SMCStrategyConditions instance ... + * @param type: ENUM_X_POSITION_TYPES member ... + * + * @return ( virtual int ) + */ + virtual int DetectSLCandidates( + double &candidates[], + double entry, + X121SMCStrategyConditions &conditions, + ENUM_X_POSITION_TYPES type // + ) + { + // + int result = 0; + + // + if (type == X_POSITION_TYPE_NONE || + type == X_POSITION_TYPE_ALL) + { + return result; + } + + // + Clean(candidates); + + // + XOHCL candidateBars[]; + if (type == X_POSITION_TYPE_LONG) + { + // + // Search Bullish Momentum, Rejection Bars and Swing Lows ... + + // + // Swing Lows ... + Copy( + conditions.swingLows, + candidateBars, + false // + ); + + // + // Bullish Momentum Bars ... + Copy( + conditions.bullishMomentumBars, + candidateBars, + false // + ); + + // + // Bullish Rejection Bars ... + Copy( + conditions.bullishRejectionBars, + candidateBars, + false // + ); + + // + int count = ArraySize(candidateBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = candidateBars[i]; + + // + if (iBar.low < entry) + { + // + Add( + iBar.low, + candidates // + ); + } + } + } + } + else if (type == X_POSITION_TYPE_SHORT) + { + // + // Search Bearish Momentum, Rejection Bars and Swing Highs ... + + // + // Swing Highs ... + Copy( + conditions.swingHighs, + candidateBars, + false // + ); + + // + // Bearish Momentum Bars ... + Copy( + conditions.bearishMomentumBars, + candidateBars, + false // + ); + + // + // Bearish Rejection Bars ... + Copy( + conditions.bearishRejectionBars, + candidateBars, + false // + ); + + // + int count = ArraySize(candidateBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = candidateBars[i]; + + // + if (iBar.high > entry) + { + // + Add( + iBar.low, + candidates // + ); + } + } + } + } + + // + Clean(candidateBars); + result = ArraySize(candidates); + + // + return result; + } + + /** + * Customize Strategy Identifier ... + * + * @return ( virtual string ) + */ + virtual string GetTag() + { + return X121SMCStrategyToken; + } + + // + // Protected ... + protected: + // + + // + // Props ... + + // + // Point Of Interests ... + XCPOI *m1DPOI; + XCPOI *m4HPOI; + XCPOI *m15MPOI; + XCPOI *m5MPOI; + XCPOI *m1MPOI; + + // + XPOIState _1DState; + XPOIState _4HState; + XPOIState _15MState; + XPOIState _5MState; + XPOIState _1MState; + XPOIState _CombineState; + + // + XCPOIDrawer *mPOIDrawer; // POI Drawer Class ... + CArrayObj mDrawnObjects; + + // + XTick mTicks[]; // Hold Ticks Data ... + MqlTick mLastTick; // Last Issued Tick ... + + // + X121SMCStrategyConditions mConditions[]; + + // + XBarTracker mBarTracker; // Strategy Time Tracker ... + + // + // Actions ... + + /** + * Check Spread Passed for Positions... + * + * @return ( bool ) + */ + bool IsSpreadPass() + { + // + bool result = false; + + // + int length = 5; + double pointValue = GetPoints(mSymbol); + double maxAllowedSpread = MaxAllowedSpread(); + if (maxAllowedSpread > 0) + { + maxAllowedSpread *= pointValue; + } + else + { + maxAllowedSpread = 0; + } + + // + int ticksCount = ArraySize(mTicks); + if (ticksCount <= length) + { + return result; + } + + // + int start = -1; + int end = -1; + CalculateTicksParams( + start, + end, + length + 1 // + ); + result = IsValidIndex(start) && + IsValidIndex(end); + if (!result) + { + return result; + } + + // + end -= 1; + double spreadAVG = 0; + for (int i = start; i < end; i++) + { + spreadAVG += mTicks[i].spread; + } + spreadAVG /= length; + + // + double lastSpread = mTicks[ticksCount - 1].spread; + + // + result = lastSpread <= spreadAVG && + (maxAllowedSpread <= 0 + ? true + : lastSpread <= maxAllowedSpread); + + // + return result; + } + + /** + * Check Ticks is Bullish or not ... + * + * @return ( bool ) + */ + bool IsTicksBullish() + { + // + bool result = false; + + // + int start = -1; + int end = -1; + int requiredBullishTicks = 5; + CalculateTicksParams( + start, + end, + requiredBullishTicks // + ); + result = IsValidIndex(start) && + IsValidIndex(end); + if (!result) + { + return result; + } + + // + result = true; + for (int i = start + 1; i < end; i++) + { + // + XTick iTick = mTicks[i]; + XTick prevTick = mTicks[i - 1]; + + // + bool isBullish = iTick.bid >= prevTick.bid; + result = result && isBullish; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check Ticks is Bearish or not ... + * + * @return ( bool ) + */ + bool IsTicksBearish() + { + // + bool result = false; + + // + int start = -1; + int end = -1; + int requiredBearishTicks = 5; + CalculateTicksParams( + start, + end, + requiredBearishTicks // + ); + result = IsValidIndex(start) && + IsValidIndex(end); + if (!result) + { + return result; + } + + // + result = true; + for (int i = start + 1; i < end; i++) + { + // + XTick iTick = mTicks[i]; + XTick prevTick = mTicks[i - 1]; + + // + bool isBearish = iTick.bid <= prevTick.bid; + result = result && isBearish; + if (!result) + { + break; + } + } + + // + return result; + } + + /** + * Check Ticks Has Momentum or not ... + * + * @return ( bool ) + */ + bool IsTicksHasMomentum() + { + // + bool result = false; + + // + int start = -1; + int end = -1; + int requiredTicksForMomentum = 5; + CalculateTicksParams( + start, + end, + requiredTicksForMomentum // + ); + result = IsValidIndex(start) && + IsValidIndex(end); + if (!result) + { + return result; + } + + // + result = true; + int lastDiff = 0; + for (int i = start + 1; i < end; i++) + { + // + XTick iTick = mTicks[i]; + XTick prevTick = mTicks[i - 1]; + + // + int timeDiff = MathAbs((int)iTick.time - (int)prevTick.bid); + if (lastDiff <= 0) + { + lastDiff = timeDiff; + } + result = result && timeDiff >= lastDiff; + if (!result) + { + break; + } + + // + lastDiff = timeDiff; + } + + // + return result; + } + + /** + * 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; + } + + /** + * Clear All Conditions ... + */ + void ClearConditions() + { + Clean(mConditions); + } + + // + /** + * 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 // + ); + } + } + + // + // Draw Functions ... + + /** + * Clear all Drawn Objects ... + */ + void ClearDraws() + { + mDrawnObjects.Clear(); + } + + /** + * Remove Specified Drawn Object ... + * + * @param name: Object name ... + */ + void RemoveObject(string name) + { + // + if (!IsValid(name)) + { + return; + } + + // + int count = mDrawnObjects.Total(); + if (!IsValidSize(count)) + { + return; + } + + // + int idx = -1; + for (int i = 0; i < count; i++) + { + // + string iName = ((CChartObject *)mDrawnObjects.At(i)).Name(); + string iObjName = NULL; + if (!IsValid(iName)) + { + iObjName = ((XCBaseObject *)mDrawnObjects.At(i)).ObjName(); + } + + // + if ((IsValid(iName) && + iName == name) || + (IsValid(iObjName) && + iObjName == name)) + { + // + idx = i; + break; + } + } + + // + if (IsValidIndex(idx)) + { + mDrawnObjects.Delete(idx); + } + } + + /** + * Draw Specified Signal ... + * + * @param signal: XSignal instance ... + */ + void DrawSignal(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + + // + // DrawConditions(conditions); + + // + string name = signal.GetTag(); + RemoveObject(name); + + // + XCSignalObject *iObj; + iObj = new XCSignalObject(); + + // + bool isCreated = iObj.Create( + ChartIdentification(), + name, + SubWindowIdentification(), + signal // + ); + if (!isCreated) + { + return; + } + + // + iObj.TPWidth(1); + iObj.TPColor(clrGreen); + iObj.TPWidth(STYLE_DOT); + + // + iObj.SLWidth(1); + iObj.SLColor(clrRed); + iObj.SLWidth(STYLE_DOT); + + // + iObj.EntryWidth(1); + iObj.EntryColor(clrYellow); + iObj.EntryWidth(STYLE_DOT); + + // + mDrawnObjects.Add(iObj); + } + + /** + * Draw Conditions ... + * + * @param conditions: X121SMCStrategyConditions instance ... + */ + void DrawConditions(X121SMCStrategyConditions &conditions) + { + // + XC121SMCConditionsObject *iObj; + iObj = new XC121SMCConditionsObject(mPOIDrawer); + bool isCreated = iObj.CreateByConditions( + ChartIdentification(), + conditions.GetTag(true), + SubWindowIdentification(), + conditions // + ); + if (isCreated) + { + mDrawnObjects.Add(iObj); + } + } + + /** + * Draw Market Structure ... + * + * @param structure: X121SMCMarketStructure instance ... + */ + void DrawMarketStructure(X121SMCMarketStructure &structure) + { + // + XC121SMCMarketStructureObject *iObj; + iObj = new XC121SMCMarketStructureObject(mPOIDrawer); + bool isCreated = iObj.CreateByStructure( + ChartIdentification(), + structure.GetTag(), + SubWindowIdentification(), + structure // + ); + if (isCreated) + { + mDrawnObjects.Add(iObj); + } + } + + // + // 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 ... + double mMaxAllowedSpread; // Max Allowed Spread ... + + // + long mChartID; // Chart ID ... + int mSubWindow; // Sub Window ID ... + + // + // On X121 Signal Recieved Event Handler(s) ... + TOnX121SMCSignal mSignalEventHandlers[]; + + // + // Actions ... + + /** + * Install all Helpers and Prepare all Configurations for required Indicators ... + */ + void Init() + { + // + mForceDisabled = false; + + // + R2R(1); + Volume(0.01); + + // + ChartIdentification(0); + SubWindowIdentification(0); + + // + // Configure POI Drawer if Required ... + mPOIDrawer = new XCPOIDrawer(); + mPOIDrawer.ChartIdentification(0); + mPOIDrawer.SubWindowIdentification(0); + + // + mPOIDrawer.DemandZoneFill(false); + mPOIDrawer.SupplyZoneFill(false); + mPOIDrawer.BullishFVGFill(false); + mPOIDrawer.BearishFVGFill(false); + mPOIDrawer.SupportZoneFill(false); + mPOIDrawer.ResistanceZoneFill(false); + mPOIDrawer.BullishOrderBlockFill(false); + mPOIDrawer.BearishOrderBlockFill(false); + + // + string symbol = Symbol(); + ENUM_TIMEFRAMES period = Period(); + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + symbol, + period // + ); + + // + // Initialize POIs ... + + // + // 1D Period ... + // POI Detector ... + m1DPOI = new XCPOI( + symbol, + PERIOD_D1 // + ); + + // + m1DPOI.DisableDrawPOIs(); + m1DPOI.SupplyZonePeriod(PERIOD_W1); + m1DPOI.DemandZonePeriod(PERIOD_W1); + m1DPOI.SubWindowIdentification(0); + m1DPOI.ChartIdentification(ChartID()); + + // + m1DPOI.Init(); + + // + // 4H Period ... + // POI Detector ... + m4HPOI = new XCPOI( + symbol, + PERIOD_H4 // + ); + + // + m4HPOI.DisableDrawPOIs(); + m4HPOI.SupplyZonePeriod(PERIOD_D1); + m4HPOI.DemandZonePeriod(PERIOD_D1); + m4HPOI.SubWindowIdentification(0); + m4HPOI.ChartIdentification(ChartID()); + + // + m4HPOI.Init(); + + // + // 15M Period ... + // POI Detector ... + m15MPOI = new XCPOI( + symbol, + PERIOD_M15 // + ); + + // + m15MPOI.DisableDrawPOIs(); + m15MPOI.MaxNumberOfRequiredPOIs(2); + m15MPOI.SupplyZonePeriod(PERIOD_H4); + m15MPOI.DemandZonePeriod(PERIOD_H4); + m15MPOI.SubWindowIdentification(0); + m15MPOI.ChartIdentification(ChartID()); + + // + m15MPOI.Init(); + + // + // 5M Period ... + // POI Detector ... + m5MPOI = new XCPOI( + symbol, + PERIOD_M5 // + ); + + // + m5MPOI.DisableDrawPOIs(); + m5MPOI.MaxNumberOfRequiredPOIs(2); + m5MPOI.SupplyZonePeriod(PERIOD_M15); + m5MPOI.DemandZonePeriod(PERIOD_M15); + m5MPOI.SubWindowIdentification(0); + m5MPOI.ChartIdentification(ChartID()); + + // + m5MPOI.Init(); + + // + // 1M Period ... + // POI Detector ... + m1MPOI = new XCPOI( + symbol, + PERIOD_M1 // + ); + + // + m1MPOI.DisableDrawPOIs(); + m1MPOI.SupplyZonePeriod(PERIOD_M5); + m1MPOI.DemandZonePeriod(PERIOD_M5); + m1MPOI.SubWindowIdentification(0); + m1MPOI.ChartIdentification(ChartID()); + + // + m1MPOI.Init(); + + // + } + + /** + * De Initialize all Tools ... + */ + void DeInit() + { + // + delete m1DPOI; + delete m4HPOI; + delete m5MPOI; + delete m1MPOI; + delete m15MPOI; + + // + delete mPOIDrawer; + + // + // ClearDraws(); + } + + /** + * Reste Bar Tracker ... + */ + void ResetBarTracker() + { + mBarTracker.Clean(); + } + + /** + * Cleanup Ticks Size ... + */ + void CleanupTicks() + { + // + int maxRequiredTicks = 50; + int ticksCount = ArraySize(mTicks); + if (!IsValidSize(ticksCount) || + ticksCount <= maxRequiredTicks) + { + return; + } + + // + int removeCount = ticksCount - maxRequiredTicks; + if (!IsValidSize(removeCount)) + { + return; + } + + // + ArrayRemove( + mTicks, + 0, + removeCount // + ); + } + + /** + * Add new Tick Data to Collection ... + */ + void SaveTickData() + { + // + XTick tick; + bool isInited = tick.Init(mSymbol); + if (!isInited) + { + return; + } + + // + AddRef( + tick, + mTicks // + ); + } + + /** + * Calculate Ticks Param for Looping through Last n items ... + * + * @param start: Integer Reference to Start ... + * @param end: Integer Reference to End ... + * @param numOfLastTicks: Integer Max Number of Required N Last Ticks ... + */ + void CalculateTicksParams( + int &start, + int &end, + int numOfLastTicks = 5 // + ) + { + // + start = -1; + end = -1; + + // + int count = ArraySize(mTicks); + + // + start = count - numOfLastTicks; + if (start < 0) + { + start = 0; + } + + // + end = start + numOfLastTicks; + if (end > count) + { + end = count; + } + } + + // +}; + +// \ No newline at end of file diff --git a/X121SMCEA/Classes/x-121.smc.chart.objects.class.mq5 b/X121SMCEA/Classes/x-121.smc.chart.objects.class.mq5 new file mode 100644 index 00000000..686d4a4b --- /dev/null +++ b/X121SMCEA/Classes/x-121.smc.chart.objects.class.mq5 @@ -0,0 +1,991 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XChartObjects +// Description: provides all require Chart Objects ... +// +// +// 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 + +// +#include "../../Classes/x-saherelm.x-chart-objects.class.mq5" +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +#include + +// +// Definitions ... + +enum ENUM_X121SMC_CHARTOBJECTS +{ + // + // Global ... + X_121SMC_CONDITIONS_OBJ = 110121, + X_121SMC_MARKET_STRUCTURE_OBJ = 110122, +}; + +// +// Implementations ... + +// +// Market Conditions ... +class XC121SMCConditionsObject : public XCBaseObject +{ + // + public: + // + + // + // Constructor ... + void XC121SMCConditionsObject(XCPOIDrawer *_poiDrawer) + { + mPOIDrawer = _poiDrawer; + } + + // + // Deconstructor ... + void ~XC121SMCConditionsObject() + { + } + + /** + * Create a Conditions Object on Chart ... + * + * @param chart_id: Long ... + * @param name: String ... + * @param window: Integer ... + * @param conditions: X121SMCStrategyConditions instance ... + * + * @return ( bool ) + */ + bool CreateByConditions( + long chart_id, + const string name, + const int window, + X121SMCStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + result = IsValid(name); + if (!result) + { + return result; + } + + // + string nameMD5 = ToMD5(name); + string suffix = "_" + nameMD5; + + // + // Supply Zone ... + bool isCreated = mPOIDrawer.CreateSupplyZone( + conditions.supplyZone, + mSupplyZoneObj // + ); + + // + // Demnd Zone ... + isCreated = mPOIDrawer.CreateDemandZone( + conditions.demandZone, + mDemandZoneObj // + ); + + // + // Bullish Order Block ... + isCreated = mPOIDrawer.CreateBullishOrderBlock( + conditions.bullishOrderBlock, + mBullishOBObj // + ); + + // + // Bearish Order Block ... + isCreated = mPOIDrawer.CreateBearishOrderBlock( + conditions.bearishOrderBlock, + mBearishOBObj // + ); + + // + // Collections ... + + // + // Order Blocks ... + + // + // Bullish ... + int count = ArraySize(conditions.bullishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = conditions.bullishOrderBlocks[i]; + + // + XCBullishOrderBlockObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishOrderBlock( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBullishOBObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(conditions.bearishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = conditions.bearishOrderBlocks[i]; + + // + XCBearishOrderBlockObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishOrderBlock( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBearishOBObjs.Add(iObj); + } + } + } + + // + // Fair Value Gaps ... + + // + // Bullish ... + count = ArraySize(conditions.bullishFVGs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = conditions.bullishFVGs[i]; + + // + XCBullishFVGObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishFVG( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBullishFVGObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(conditions.bearishFVGs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = conditions.bearishFVGs[i]; + + // + XCBearishFVGObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishFVG( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBearishFVGObjs.Add(iObj); + } + } + } + + // + // Support and Resistance Zones ... + + // + // Supports ... + count = ArraySize(conditions.supports); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.supports[i]; + + // + XCSupportZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateSupportZone( + iBar, + iObj // + ); + + // + if (isCreated) + { + mSupportZoneObjs.Add(iObj); + } + } + } + + // + // Resistances ... + count = ArraySize(conditions.resistances); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.resistances[i]; + + // + XCResistanceZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateResistanceZone( + iBar, + iObj // + ); + + // + if (isCreated) + { + mResistanceZoneObjs.Add(iObj); + } + } + } + + // + // Swings ... + + // + // High ... + count = ArraySize(conditions.swingHighs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.swingHighs[i]; + + // + XCSwingHighObject *iObj; + bool isCreated = mPOIDrawer.CreateSwingHigh( + iBar, + iObj // + ); + + // + if (isCreated) + { + mSwingHighObjs.Add(iObj); + } + } + } + + // + // Low ... + count = ArraySize(conditions.swingLows); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.swingLows[i]; + + // + XCSwingLowObject *iObj; + bool isCreated = mPOIDrawer.CreateSwingLow( + iBar, + iObj // + ); + + // + if (isCreated) + { + mSwingLowObjs.Add(iObj); + } + } + } + + // + // Momentum Bars ... + + // + // Bullish ... + count = ArraySize(conditions.bullishMomentumBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.bullishMomentumBars[i]; + + // + XCBullishMomentumBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishMomentumBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBullishMomentumBarObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(conditions.bearishMomentumBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.bearishMomentumBars[i]; + + // + XCBearishMomentumBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishMomentumBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBearishMomentumBarObjs.Add(iObj); + } + } + } + + // + // Rejection Bars ... + + // + // Bullish ... + count = ArraySize(conditions.bullishRejectionBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.bullishRejectionBars[i]; + + // + XCBullishRejectionBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishRejectionBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBullishRejectionBarObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(conditions.bearishRejectionBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = conditions.bearishRejectionBars[i]; + + // + XCBearishRejectionBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishRejectionBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBearishRejectionBarObjs.Add(iObj); + } + } + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_X121SMC_CHARTOBJECTS ) + */ + virtual ENUM_X121SMC_CHARTOBJECTS Type() + { + return X_121SMC_CONDITIONS_OBJ; + } + + // + private: + // + XCPOIDrawer *mPOIDrawer; + + // + XCSupplyZoneObject *mSupplyZoneObj; + XCDemandZoneObject *mDemandZoneObj; + + // + XCBullishOrderBlockObject *mBullishOBObj; + XCBearishOrderBlockObject *mBearishOBObj; + + // + CArrayObj mBullishOBObjs; + CArrayObj mBearishOBObjs; + + // + CArrayObj mBullishFVGObjs; + CArrayObj mBearishFVGObjs; + + // + CArrayObj mSupportZoneObjs; + CArrayObj mResistanceZoneObjs; + + // + CArrayObj mSwingHighObjs; + CArrayObj mSwingLowObjs; + + // + CArrayObj mBullishMomentumBarObjs; + CArrayObj mBearishMomentumBarObjs; + + // + CArrayObj mBullishRejectionBarObjs; + CArrayObj mBearishRejectionBarObjs; + + // +}; + +// +// Market Structure ... +class XC121SMCMarketStructureObject : public XCBaseObject +{ + // + public: + // + + // + // Constructor ... + void XC121SMCMarketStructureObject(XCPOIDrawer *_poiDrawer) + { + mPOIDrawer = _poiDrawer; + } + + // + // Deconstructor ... + void ~XC121SMCMarketStructureObject() + { + } + + /** + * Create a Conditions Object on Chart ... + * + * @param chart_id: Long ... + * @param name: String ... + * @param window: Integer ... + * @param conditions: X121SMCStrategyConditions instance ... + * + * @return ( bool ) + */ + bool CreateByStructure( + long chart_id, + const string name, + const int window, + X121SMCMarketStructure &structure // + ) + { + // + bool result = false; + + // + result = IsValid(name); + if (!result) + { + return result; + } + + // + string nameMD5 = ToMD5(name); + string suffix = "_" + nameMD5; + + // + // Supply Zone ... + bool isCreated = mPOIDrawer.CreateSupplyZone( + structure.supplyZone, + mSupplyZoneObj // + ); + + // + // Demnd Zone ... + isCreated = mPOIDrawer.CreateDemandZone( + structure.demandZone, + mDemandZoneObj // + ); + + // + // Bullish Order Block ... + isCreated = mPOIDrawer.CreateBullishOrderBlock( + structure.bullishOrderBlock, + mBullishOBObj // + ); + + // + // Bearish Order Block ... + isCreated = mPOIDrawer.CreateBearishOrderBlock( + structure.bearishOrderBlock, + mBearishOBObj // + ); + + // + // Collections ... + + // + // Order Blocks ... + + // + // Bullish ... + int count = ArraySize(structure.bullishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = structure.bullishOrderBlocks[i]; + + // + XCBullishOrderBlockObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishOrderBlock( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBullishOBObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(structure.bearishOrderBlocks); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = structure.bearishOrderBlocks[i]; + + // + XCBearishOrderBlockObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishOrderBlock( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBearishOBObjs.Add(iObj); + } + } + } + + // + // Fair Value Gaps ... + + // + // Bullish ... + count = ArraySize(structure.bullishFVGs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = structure.bullishFVGs[i]; + + // + XCBullishFVGObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishFVG( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBullishFVGObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(structure.bearishFVGs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XZone iZone = structure.bearishFVGs[i]; + + // + XCBearishFVGObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishFVG( + iZone, + iObj // + ); + + // + if (isCreated) + { + mBearishFVGObjs.Add(iObj); + } + } + } + + // + // Support and Resistance Zones ... + + // + // Supports ... + count = ArraySize(structure.supports); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.supports[i]; + + // + XCSupportZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateSupportZone( + iBar, + iObj // + ); + + // + if (isCreated) + { + mSupportZoneObjs.Add(iObj); + } + } + } + + // + // Resistances ... + count = ArraySize(structure.resistances); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.resistances[i]; + + // + XCResistanceZoneObject *iObj; + bool isCreated = mPOIDrawer.CreateResistanceZone( + iBar, + iObj // + ); + + // + if (isCreated) + { + mResistanceZoneObjs.Add(iObj); + } + } + } + + // + // Swings ... + + // + // High ... + count = ArraySize(structure.swingHighs); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.swingHighs[i]; + + // + XCSwingHighObject *iObj; + bool isCreated = mPOIDrawer.CreateSwingHigh( + iBar, + iObj // + ); + + // + if (isCreated) + { + mSwingHighObjs.Add(iObj); + } + } + } + + // + // Low ... + count = ArraySize(structure.swingLows); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.swingLows[i]; + + // + XCSwingLowObject *iObj; + bool isCreated = mPOIDrawer.CreateSwingLow( + iBar, + iObj // + ); + + // + if (isCreated) + { + mSwingLowObjs.Add(iObj); + } + } + } + + // + // Momentum Bars ... + + // + // Bullish ... + count = ArraySize(structure.bullishMomentumBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.bullishMomentumBars[i]; + + // + XCBullishMomentumBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishMomentumBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBullishMomentumBarObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(structure.bearishMomentumBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.bearishMomentumBars[i]; + + // + XCBearishMomentumBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishMomentumBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBearishMomentumBarObjs.Add(iObj); + } + } + } + + // + // Rejection Bars ... + + // + // Bullish ... + count = ArraySize(structure.bullishRejectionBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.bullishRejectionBars[i]; + + // + XCBullishRejectionBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBullishRejectionBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBullishRejectionBarObjs.Add(iObj); + } + } + } + + // + // Bearish ... + count = ArraySize(structure.bearishRejectionBars); + if (IsValidSize(count)) + { + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = structure.bearishRejectionBars[i]; + + // + XCBearishRejectionBarObject *iObj; + bool isCreated = mPOIDrawer.CreateBearishRejectionBar( + iBar, + iObj // + ); + + // + if (isCreated) + { + mBearishRejectionBarObjs.Add(iObj); + } + } + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_X121SMC_CHARTOBJECTS ) + */ + virtual ENUM_X121SMC_CHARTOBJECTS Type() + { + return X_121SMC_MARKET_STRUCTURE_OBJ; + } + + // + private: + // + XCPOIDrawer *mPOIDrawer; + + // + XCSupplyZoneObject *mSupplyZoneObj; + XCDemandZoneObject *mDemandZoneObj; + + // + XCBullishOrderBlockObject *mBullishOBObj; + XCBearishOrderBlockObject *mBearishOBObj; + + // + CArrayObj mBullishOBObjs; + CArrayObj mBearishOBObjs; + + // + CArrayObj mBullishFVGObjs; + CArrayObj mBearishFVGObjs; + + // + CArrayObj mSupportZoneObjs; + CArrayObj mResistanceZoneObjs; + + // + CArrayObj mSwingHighObjs; + CArrayObj mSwingLowObjs; + + // + CArrayObj mBullishMomentumBarObjs; + CArrayObj mBearishMomentumBarObjs; + + // + CArrayObj mBullishRejectionBarObjs; + CArrayObj mBearishRejectionBarObjs; + + // +}; + +// \ No newline at end of file diff --git a/X121SMCEA/Libraries/x-121.smc.lib.mq5 b/X121SMCEA/Libraries/x-121.smc.lib.mq5 index 3b7b40b3..e3c01fbd 100644 --- a/X121SMCEA/Libraries/x-121.smc.lib.mq5 +++ b/X121SMCEA/Libraries/x-121.smc.lib.mq5 @@ -32,6 +32,10 @@ // // Specific Identifier(s) of XStrategy ... string X121SMCStrategyToken = "X121SMC"; +string X121SMCOBStrategyToken = "X121SMCOB"; +string X121SMCSUPDEMStrategyToken = "X121SMCSUPDEM"; +string X121SMCConditionsToken = "X121SMCConditions"; +string X121SMCMarketStructureToken = "X121SMCMarketStructure"; // // Condition Structure ... @@ -51,6 +55,7 @@ struct X121SMCStrategyConditions // XZone supplyZone; + XZone bearishOrderBlock; // XZone bearishOrderBlocks[]; @@ -64,6 +69,7 @@ struct X121SMCStrategyConditions // XZone demandZone; + XZone bullishOrderBlock; // XZone bullishOrderBlocks[]; @@ -96,6 +102,7 @@ struct X121SMCStrategyConditions // supplyZone.Clean(); + bearishOrderBlock.Clean(); // Clean(bearishFVGs); @@ -103,6 +110,7 @@ struct X121SMCStrategyConditions // demandZone.Clean(); + bearishOrderBlock.Clean(); // Clean(bullishFVGs); @@ -125,6 +133,7 @@ struct X121SMCStrategyConditions { // demandZone.Clean(); + bullishOrderBlock.Clean(); // Clean(supports); @@ -139,6 +148,7 @@ struct X121SMCStrategyConditions { // supplyZone.Clean(); + bearishOrderBlock.Clean(); // Clean(swingHighs); @@ -273,15 +283,24 @@ struct X121SMCStrategyConditions if (fullTag) { // - result = X121SMCStrategyToken + "_" + - "Conditions_" + - symbol + "_" + - ToString(period) + "_" + - ToFormatString(time); + result = + // + symbol + "," + + ToString(period) + "," + + ToFormatString(time) + "_" + + demandZone.GetTag() + "," + + supplyZone.GetTag() + "_" + + bullishOrderBlock.GetTag() + "," + + bearishOrderBlock.GetTag() + // + ; + + // + result = X121SMCConditionsToken + "_" + ToMD5(result); } else { - result = X121SMCStrategyToken; + result = X121SMCConditionsToken; } // @@ -299,6 +318,10 @@ struct X121SMCMarketStructure XZone demandZone; XZone supplyZone; + // + XZone bullishOrderBlock; + XZone bearishOrderBlock; + // XZone demandZones[]; XZone supplyZones[]; @@ -346,6 +369,27 @@ struct X121SMCMarketStructure Clean(bullishMomentumBars); Clean(bullishRejectionBars); } + + // + string GetTag() + { + // + string result = NULL; + + // + result = + // + demandZone.GetTag() + "," + + supplyZone.GetTag() + "_" + + bullishOrderBlock.GetTag() + "," + + bearishOrderBlock.GetTag() + // + ; + result = X121SMCMarketStructureToken + "_" + ToMD5(X121SMCMarketStructureToken); + + // + return result; + } }; // diff --git a/X121SMCEA/Strategy/x-121.smc.ob.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.ob.strategy.class.mq5 new file mode 100644 index 00000000..a823b8e2 Binary files /dev/null and b/X121SMCEA/Strategy/x-121.smc.ob.strategy.class.mq5 differ diff --git a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.supdem.strategy.class.mq5 similarity index 67% rename from X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 rename to X121SMCEA/Strategy/x-121.smc.supdem.strategy.class.mq5 index 4da2d21e..625285a3 100644 Binary files a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 and b/X121SMCEA/Strategy/x-121.smc.supdem.strategy.class.mq5 differ