From 39de34195de414269586815a2711a32e775249ab Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 2 Nov 2024 18:52:49 +0330 Subject: [PATCH] Last ... --- Experts/x-saherelm.x-121.smc.ea.mq5 | 33 +- .../Classes/x-121.smc.base.strategy.class.mq5 | 1446 +++++++++++++++++ .../Classes/x-121.smc.chart.objects.class.mq5 | 991 +++++++++++ X121SMCEA/Libraries/x-121.smc.lib.mq5 | 56 +- .../Strategy/x-121.smc.ob.strategy.class.mq5 | Bin 0 -> 3598 bytes ...q5 => x-121.smc.supdem.strategy.class.mq5} | Bin 194986 -> 137882 bytes 6 files changed, 2504 insertions(+), 22 deletions(-) create mode 100644 X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 create mode 100644 X121SMCEA/Classes/x-121.smc.chart.objects.class.mq5 create mode 100644 X121SMCEA/Strategy/x-121.smc.ob.strategy.class.mq5 rename X121SMCEA/Strategy/{x-121.smc.strategy.class.mq5 => x-121.smc.supdem.strategy.class.mq5} (67%) 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 0000000000000000000000000000000000000000..a823b8e2c8b2e90649c30f0be6fa8bdf46097795 GIT binary patch literal 3598 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 literal 194986 zcmeHwZF3yQk>-4M#Qle%H$n%?HYDn-FSd7A6iJDU6-6CE$@DrL3<}^2ECQqfQm?!B z)9)^yPCUr0>a6bSo}R$~>|jWZnW@go%*waQ%BuQ*|M!E%Cjb49#jl$F_*^db7Ecy0 z7Ec!^i`$Eri=)MIad+`h{(n=xJ6^nLepxQ=E&li7i^a#y_b=s*Q~9@)Zw?pV%9~H* zzn>Nc^Y@GC{u$ISrJp0g=a16!BfHRKc_1*Bi~o>udb0Rg{(CC_mWvyL1MuBxzDJwKi|>*) zkEJczd?Gx-D8G__yF$||;p1=4v0z`Dl0){#=W_A6;P|THJLvhU8JX8Y<4H4O%6a4T zznqO7Tl^&NycFtFNsL;7^4G!(NW*jC#~XR`*CI#lZ$DamD3bNR7Qd4gH5&5khMQ5J z!0cGY1wEn1H-f>b$N;$gL-TJ}K2ryu3MEG}Mu&o98Rqv5Z%(BZq#2N}%R3*+zw$e$ z(lhAZmnS$+?(+$~KN8#^-){sXFWYQ`=f5=cKrh}lnuFdkHXoe*|EBz+_5tJe!Qw}; z1#SB9E&4i?w@k-&1%rQzl_3@2-0D3+uT_@T-8V&djv^@irIFvIw8B5&k8k~F*bxuS><3!CcE71T_U{5# z4ln-<-az|QuigsAZyMccbAph+Z{!_brJo-=N&ke9)9JroF32gbxop8Ft-!I^zoqz# zQ?Z6e!t+NW;ljp^slD-JhRxZD*PIuzO25&cYi{qF_`4=abEd_#-_&(@a3ND@p6|4)@1*6{7<*4kEX`^EsSNi^PAzxZS{F$XsPh=(^HSo>6i4u= z&laSVx4G8$zSqcceDn~;^6{p`cF;n^d3z!yem1fc*+V>at9d?YJewY)1>#$nM)p+%~;WFmeuz=soC&c$U*Z$(1 zYccOrD`)=2Q`f~gJepze%BS>`_aq;PCy9IuEy7+Cxi1%g5zRXmjeI3@=qYRipux)IJj=Z} z+bJF%i|Oq{yN^^R+A>$-9&N-l-0QLyhyyhbrxH2LX0$2p<|;?S%bk~|Sk_A#N!>DN z+iE%5eA;H~(Z;rWRE_`Zvm(d<9yfk&x%ft`2>c!9n5#t?ut%D80Hi)!lD76(jEg5c zgw-v@6ddZZ6t@yy4YL!T(w)W&7}ve@tiu){(|Wx%w(8MhdqZz$n5njYDA6onrDMg` zZR^foO7`n0lVrpz)@RyF8+yri(DOcM<}csLtQK?XADV~}5%~l8OXJ{+)13#Bt$)zu zQ2IwaoueMfdw6#&cj#HC<<7eFhI~pbkI6`Cv0`a1N#AwQ0pP9R&2c@5%n=*XUAoFR9}qF$VqD0V4s9ypkJ;`g4P&8;-Ua=o>3P|6^hY#Qd%NTzyR+@!Z%bKnr4AbcpUY-0M$vSH(i?2Mwss?hxW2NwRGvCJg zzOKUMt0co{^w6fF@R?Z9m$E7{o<_`!o;UL(u48&HfYmUpL8>00vI`kZt!pURZ9kvk zDqE^=SRpYusH0FnfJ_|L9PtTjGfNp?WX2y#-uSqwt}y>p>OGb9?*+nP6T#k){~u&9 zjJA}ro%0@9t)~?rzW0=dG!FPBvlpsOrN~|}i|Z$-hiPxW3*oaZ)>#eH5{=OL5=MCr zE1FfLd{&$Cjr5C^ueUOSSlO$!F%c}R#c+L6>sAf~y0=)W{i$D2Ny3cfw#;hq{#$uR zwbytO$qwo&J?2Ha@$}LY}Uu3Fd%lT?)9W<3f%0n!T{MAPhshwnt z_UQAMA@mvd>*I0lhg4q+Vl|Aza`B%0!%9-@eSb45^R*eipaKf3U|O#P$)J+ad+a_p#Fmkj;AN_rqiXkEg;4QpLk55c($;~dVq@V!2W z$6Xvw$7&3|DwRHN$fJxjT0*@Ba>ulj%ci~$w$0D7FjGYw*Hsy*_6U0fEEYyZu6>H_ zwe1;;_94V`BdxAZXG}44^YR*(q}aiSWBvpGZ+LdcC!V6d=mgb`DVAk>#nGl+=aUh` zwX>1&m~L0J@E74EqEtxF*FyOl`Gk4$mts|aluxLLw9E*qaFPAU<+D!`%Q0(dmSA{c zR-kecS=5rhR-O7%bO01RYhr6Z3SC*GG)mx@^66nB2jroaGaDBxpF=puT1ZdV<-wk| zRO88$^U6*iOL8RJS%h4g2yI;6r!Dn)M#n5&twqai^?Ql6j&0i*YyFuY%{j)JVOM*{u6Pm$w zL*9Bg!ke0=YDAWup7WW%ov$0_?+?)lwa_{*(;Y5|S6((*cI>)^_lF%zefp3d zQpwT%)`*h;5t5^Mvah5U)pvNBG#^H38qzCm$Il{Ph({5PX@4c{+ZpPi#T;!%Z-i8$LC4oJqFm{y8{hqbk$-ACLt zRF7W|9A~z_=y6VM>s20SizjqN#;St95|58n4qY>YcgCuRukU1w@?5}M9`(3gy~MWZ z@>#_P!ZUw5g=UnyPYbBCw^$YF_MzIB<<{G4DKVGRRTPcG3`%-ON4YT$bDO10E$ zOP?Nijhq(8NdLNhFzU#VSHuZn(K%{Z{lsddo#BPLDbU_t&$Aida6GQdse4PQ^G0pv zsbHg(=1-gKDk4Sw4Sk{}48Nj&;I-tWfW5Az;T#)OE%4KSHdw-f8fLUcd}<_uzEM{K zKD-bd(4W11)XaE*)3=R1#;IS(tiOLF`39F`n*9X+5<9QzMmitWUASbeUCr#Zu= z+fA-1WAR(kFW+O-=6)BYzX#| zVNcXg;*}01WBs&QtBCkr;wCltT9aA%Mqr_K{=mWO#$#NCci-5nm+M+TrZnVFyt$dI zGxnEa1r~lA>kDtii^4BQ+_y8b5ocgkTx;-=v1WD)I)d|AaeftiblD$wNeIrqdL(Z{ zI(}bV7ovUK5o}c2aF#aS!D76kF`nKWTP{ybr7yJI=IGS|-(m9)9 zE8GHr^?>gRwJB^@j;+|D&!*Tos3od>AXGa z-?tdszaKgEsNH-}dCA*&Ox`7#fmUI?7dv3}^la4r9mwBadMrQkuT|1-E4s+AXq1Mt zPh$z&ZTh36vaen7hRFILZtETqlfW`Hetg*jq@~NYQqqkYWLz)@{I?ETPS5a0wu(LB zt^_@WiL`X}Td(n;mzCq#1B&<^vx(CtE{4Y4?P$?&g;UP@o?zRwz7Y|4)RS*9z9+R< z_k?@cr-;ZI=Oacv#x1SqRXCnjupvhIO1R8wP}Z;E8`GtdJ=>KLu~YwPU01;l@`8P@ zn9n>H=v^}z%CwCv&W}D8%g+jJ!ciVWmLji<-Pv6@v!A|aZil_q(LLZ(^wO;-Q_+(4 z63gSXG?}#Bl`-tH+}#$GaZpJXrih68tQsXnB_fr=yuOufOV4TQhjZw8ZMNz?GW(dP z{nV;j{heqcF{#mW_E*cP)GDExojZ--!F3h5Ydx3!@yX0Y2@;}1p9_Poa!p`Q>`&Bt z-At1hlzOh4&k>4^)3EpA=wuiS)Q=;h6j!!C7A~RI9V;)jqr48uQICPln69#=R+mvr zjUOS;Bdslsrk5i`QXh5H(-S_QwOpe`OY!QqW9*}DhR4>m7_oh>wYVM2*43a#>Uq_= z+-t@NRb;VtQ#uH}?+G{xA6d|L&sZJZksZ-`#*;-lL;FehzL-WLM~ckW%bu7%rvtM* zJL?zmruBe3Uvwu+x0lOd+I}97A8P7-Zwhlr6f#sIqMWbKDjyEyRaXwvuflk(uZxp& z4i2TXHY>t@G&{mi`E&K$3GhdK0nc(=HFh>gQS|J8ohs(!&UMS__?hl>(Wc%WRGtA& zN6%)XXr(KTqdh0-6T2-8y-prS+sJo&pgPY}t99!8tZ$Xcp|Lb~Gf%OiKn)(dvcUKI zqO3j1bYj2XL(%S9Zq<4?@*~QXmgfAmu({JV-gRB$gKDXzq~Wi2nek*8FMXt><7GWe8snUqByD?*{J`C9|!b2@eX+9IZq4TDi zS`GGFi=So8RhEpKejcS5-|1Xu9Yas8oiAhQtxAlgZ-E{7H=7lOv@-W^9rE(`&U1#y zZ$4}JP6_5oP$j+(oq@FBdHQ2rB<_6HX#iW-Qq1;NYxqEPm3C)XMwPJQ(HxfBB&@RD zje~bx?CMb7)at{!GYD97v6FHv+Uw77rEgj;3V*40BER!z{-!@Gg|YJx2#_pz16o`C zGz5Z0j|#&+4}sD?Q^tQY1d?B2B~|{W>mjhBvxm~}hCxH+Dyrkbah|=SGmwYkHJ*z{ z?vw3&{OxpJJ0&?iUv4N&t-8Sef9%1*OyO~MrsnQhWrns<4s^xhefsU=Ang%38SDu{ zox#(lI+}WhY`AG1xwT5~d0YvKYx5*|WU1Kqy*(}(uBo$bL(X}R&)7?Z6NXXEuCkcs zK0P<%_aR}(X+O>^Z!Iq&t2igo)^YOK|8=Xy9}}#}V^0^qqy5)$)4pB{ z?|mQr@73Ph5Z?`B^&uE#P@|_Epnl$;7{NMsoaO{A#kiv`25;Go;De;6Y^xTT2C+9uKz~F-e>FhMudEX1)FTv&7J67bN1K8uBmZWss zV7iWIIU$XYaq7Lkuewxox)yQdGwlKOdHwgkAxqrVs_cmv=lA!6HREx&sQ1Huzwvev zH)Ag!$Cp@H#rkR_0kOQ1=lvMMHYuhWr?UOs`DQ>DbZDxJG%EM+Md(wtGo@^zE z{+B)R$?=RK|GD9_m-bXE38kA`sg3s<*)>|xsPyp%{t1x?_K9Hx$~%3i$S%SDg4p`mXNtzp+a15=#3+xRij+;i9btTg(5ERd8O408dsVkj2m|E&n=bvw!?ep%k8uZy%y-N3{*~s`kYKqfp zd(k2sf7{S_?T)m~woU8N zX+t3w|CF)9DJM9cA?1znOnWay`P&yC)YDbc7;0Iry?{(_JjV>=PTOwqmlA*5e55^% zeP@mTXCydv98jWxG(I|y24MfFHIa9<9ol?1e|lINPki44QL9zqoy#!-d+DRZG6#nu z<*7ALdW^o^=0rHm9{#QIqB*wwJswYD)Ru$v8~A(mDk(PIP=`d%#N?N7Cd^;?tgQ}> z=iKA;#PUp@Hz^0&kjHv%zbCHdcA-srZjamSxl_;Wc|#k7{3{~d%j~&Jbd_w`?73^~ z1?^eeZt#~9f4vP->6$$^c(z@h+iOkPbL;$f{hr%nllm=68=tf1Mx9Cj`j)rwTFJGP zb20NB=-V{!RxEQIXD{x(xQ*&(GL|R7h+b}Q-cMi2>&#w#ySzFxNX%s3l9}%_`KP|7 zwDvd8;=eoNP?~ke$$HGOtAC8LyY!JI9pUdBn>R8hIFTeBn|qQK$IAT;nZIMrjw>p^ zak-0KX~Bvu;AL$}u|i2d4JXLP&UxnBaAFQVUfbgPb+hwW8c7TL?2bU?xyF)U4ts&Nz^7}*4pROew z3nsv|z9-1H@pNpZQ_4rrsht+K>20T}U5M>K$s$@lGu2W=QL9u!p+D@V;dw;SSYqX0 z&s2XRmKGHYX*C=z3ZHEZ_4Hj>ty8ht3gbX*Xvx+Nu@^BPJuWup9>uL+KJKVh|` z&e|^*pPY}9`jLaCC!SEN{p;D&=$Se?9{vkC1J@u;4aJ3cB{IHeJg)JJZhv}DG}7~B$eXFm4S6${reW`T zIT`k*r?kE6Y1V)RAaByl~$>DUAiXBL%ZD&{)m+rYrXk8-H(g$K7pqGR(kG?LBT&>V0+Y zsO9aZJ;l)18`>D71~iQbYB`i*5YwMx5Vt8~Fa?)BorF%4fJKU&y6l&r}CD z-7`lo?l<<{N-gs+bv#bvIdVuL#aWt^r--^RBYPv6pKUT9U8 zLG!|jO)URiQWn3l2`Srj&y=#b-+C#F-!~qwL(2O4TusW#@^!PRbC~8n;?riW+s&_T3sycB*%q991h7t=qRh*_i+y5i zlxm}mXy1NN4|z(eN_HdqUi~K4&n(Mp*<4W8zsoqCUtot^1goUQ!~iF)VCNU+#j9cv z!zy8rucSnLqII|{)R|8~)?fEp$2}VVuxGaK9J~_jn4cbYESHSJF2fF5io05 zlDmyq$BpbiPECj@j-c531)H`!`?gK_$C)InO~EJJBG*R^Y|206)a24Fx$G~04x^5552cdt zdE4<1XGfs9!zJZ!LUGM5MfRRQ$5LT_5&4L_&FZ+GC#F^c66wE<*FAG=N}r8S-BE4n zeSRO?uGL`TO#1(nI*u>pOme;F=P&Zt1Nr;5c!tmA|Es}gd{UmxlDg8f)|%w+)4Jp% z9LE*;+xh2lT1F^i<&^K61bI*SP&^(gZicLI5@O$TRg5(kaaU^UP#5_|aM0ED4Pf9uDIYcv8gz1YI)`d^$gh0<=gzUVB%YPP7@nElQWxfAGPI^bxwFga73l` zPm+mYmOJ$UX{`8JbB5t*aa}#9g8E#F2-%#@cw=i>u)OsaJD$gR(=8tfojH?i*T$MaUuKlymk7bwNs?X0)D#NMf$Om6U1c2M`xZD1%{6$QLM*}5DQ^f=& z_=f4_iVynfxmvM8iQesu7;0*`sMYzC>pOZ@$frrA6L$EPcbnvpN}sI-2kDt+mb#9(ikPmu&V~J~UhhIkwf2|o`JCe|a-!xr ztpwNPS?(1)_Z)+DkC(<^52W7dAM)S+dA;vNMq$_~kzzAG4lBc|wFK1sQg)`?!)1-d zYACu|(O8+{s~nH%ZJ?T~+H1}W!(C=SG$-F_1VuZ(dv*)&9m$VAmzM3;t431R(;UOK zE%qG4d7ji-ZvPJcrX`j;@`uHeP!L)601I}eLJi92X1w|=KFm5{bq*} z&Dq$IR^>^1uWHPfVS81h{(OxJBfvj}@{=0Yt$X0 zm{GqJtExAvcWDND;!`zj)!i9=J0+DnHT9VOJQ}0VQ&($IX#+}g>pq+>*BVD3HJ4>h zZ8pMoi>dVFwVVBtvYqp5oW4C}X5aXy{h6@^M7@oJb#Oy zYrO{B=TDO$?5d&riw2_^A;L=J&Wg z0{fM50+Zg5LT_>r^&ZIk<{0@Xzcwa{;22#~MMF_99^1)|I!HJD(!0ZQRTd= zH9ghq>hEfeM*m%j0;bv3I!6JqrHsD4N>Kp!aL#!Ujx;&4S`18RHCYh)t2ysMuEkG{ zTK3$&(#@~?#5*r*GaL3cYrp1wt(uw8^GA(8J`;1bau-IU$-ui3tIQdTu`3s~SZ zUZq&&YGf=T{hvL5F1P7t_5As+l#AR|QQC2MQ)*KBZr@1P^-GXyHJ%!dHFm2%wDZ48 z@D0<;wbIc~&((?-O7w1L%urMFmFl*AVvRKSw)(8jy7#t5`Hy#RZ)?PbY39M}u8W}* z&3jwP2|UL}n}l&SBCfRNK!~d%ljg=|B%JEqD-d5ZkWU-sJWo~Pe zdt0OEWsc#dtLU6#xVg@U9>PDV`_s%6YF5nJQ3(D1a9`&s!QWRqiYxDJjjX4xYvp@e zeam(2ZS{Syva?S6hE>(Y(son!mLdCaob2X94nlXfT zmaOJe+4HxQbH=daYbm$fV3)#k`Kx?yYgx*D@06=p%6-djDUWhqrHEUp^3vT!M~MfB zs=y80Q8k7OzW;76_?A<1;igcbw+7?x(Dn{_>&Rr z+F?g>-Cq8_`<_kHb9kOp4FaM z<+X0Zg7M%l3TvZ)&MOz?Tx*kc{>bVOA%N^slIBFr`OZ~Q9D?{qp; zE7#QgwtVxK679y*+-9hc!O0-2`XJ)KXSq*rr{Z3Hi*B3G-uP^fau>z0wQalXdrvJ3 zd$~+wj~fu+fqriGiyVkH|9CdmsL_rzh;Qt--bi8mR^VLkf$_QpBZcZ=M7WeB`jPD1 z54u$1UpzJ#ABN zmMASn{Fg}v{b=nE94)rL=+R2$_9~B7t}$J@QMRsKZ&9=UT`Y)=?+eiyoJOdXn6Y<; z{mRe3+Lbu!wfuwLjXML{EW*X%V0^%-GCv3RiBPRo>pEF+@AkF3lwSGYKm3e$KgE_zchVbIdXGImCYHc@9x_ zC!YC&kH*!pbJaUC$MbcBo=5W>6{B-C=crx_F)Qry0;TAS_F;(EOsiJws{D4E{7w6w z+jg#JSH?@D6U~-lw~c!C59QgP>qDNXwx9gIqILBY--x)G-s1CmHq&>hZfi5WKM?C0 zR~lLWY2J<6z-OPyCg%<oG=3|5viIakm*8u1SxF z|6=h62Wfiv`FY~&=;7nFQ-D#PW(3j`^}iQ=Ic!!|y%u)Mbi5LkN@X_$c-^*c#g&mM z+&XEGSNu!x+tU1=a0E35{Q+XcpW-h72-t{s#>`hN;JKjp?Yrlj!k5Y`*9%Fwa zhSe<$na|mpVjTIkb0sMSj2mN0_$xdO^MvUAsM!DL+=MUp*1K(m;wL!U8 zKii6X^(}_=YNM2|qIgO)`d%*Dx3>76w`KeyX^!R@%F9?fqxP|UMZFz}R33>RKrIZb z=el}}+G}q^G!F8t6=$d~fTu?kX4bL$6y--!ZIDL`es6zFee@PMqCW6+@wdg_3soJu z8xxW9v!0rX8XHfY_Iv=~HDh_xHfm%O) zy4lPT;k!{!HZHzU-h2OJ_Z@XxI#@=`V7-m^Cv+*U@oI^Uh^@x>+*SDmGopbY@#!rA7hw@+dU00q**ay4$JFe2ZsdCTSKQ{g@sxI!3 zOMP5qJB!_rdHYo4`i)fGJZd%f9PXw3LnMYe`}-2#)_J+K=1bqhym#11lR1>=?zOR=FNY1v48x1{f8DrkyBEx{ zk4A0wiL+0P>`@-K^K;2g@%Q{`Gn#ppM&3m6Q;n|H$5ZU7WRv+jpYg1$``58^He_Z{ z%`(Q9`8UV=vJ^^W6-#{Uo5iK|XE}x!?aNZSQ$M@?zAVK)8nxM%&Ax2*WwhFLPxH^i zasY%L`?7vry&Ar({vO0gE=#dgJm+IIb6mNpHmj=5amH}Qdq+QuZDV!O z{;?ao?e~xo{{Ucr|QOT`#n{J|Lmz|Pc?fg`jEP(dEa%--e{4phNs#)zX2Beto78Y zx^=YZ?mhDdwezV6%2*#2!7_|4)KyPgpLLuF-!*$JF0kGIVF z4)+IyQQ}bF%2O9M+u{pIqw(pocmiTR`+>QB@K;iQRrhabF70yp0qVq6@dEy|x3RmM zcvhTQxOz|E`)6J5>N}j;7+thC@N{~gx$VBd<89+JdxY5|yz3spYsOWngHn8V5hv6+=t#63n7$#$93=ve1-NpKeKJ2#JTSVB~h|NA@_8ITC z&xrKns(6n4bi}$_&RMy2)SOA7XEorKG0o!*pHIYa#?L2Wc!t--dW$~nw%c38*yB8( z!}Ak;YF0*T^9`FgL19e(InFz4bm`Ci7`E0KL5+4G*5@%w5m%lSV$OCu&risuz}F{f zWXe@CJtO$jWDjEZIWjpX__**@i<$FS}M3c?w75(VEHiY?!pK95Jp9Fbufz_(I*6Iw~cdr1k6`w=yL*_fPOpp_J#xmjSv@VNGbW2YBt9~2#*pdyv z_shitnc=5*I}D5V5C^C4kB#?Akj6)RC5YP+^Y!Dm-BDi&|2giP>mVabPwq;da-g^C~am}%!A7vYvb;pVi z3O;O(7VBq}>B!-h`2+cPS5E8wQuOW3;pG;uM~jz7D&mNc ze2afgzimg4rQ0U=L|1V3!G3d!4a=1a12PG~5DlOYnFrCtAN0Od*H7#jey-`-Tq9U7pCz+iiI9 zos?}D?b(RlP;q_nQF8~uJ>kZla1A%?;RcT9(p$_;@DR{!4X+l5Hv$uP6Qk$bqK9A0 zEi8}ao|DJT+1-1hoe$-|`|`_U`RlLp?QOwnDg4EGv%sqZ}bBZd)Z7F6R zD#E=4^O11!j%X9Ca2ux1*t<^OXJk5*&tEhn`1vSKmuT_)!+izbAEg;y+&YEx(QPg2 zcS8RI`J84fe8xlh4Y;fpk87$U?t9Goe(&#r(DEm|#B0%{*be5c_oa32p|N&N>R1CA zTe>#1TplSqb?@8F*=>83_thomY+ENIeNy4aKk|0$O`lWnzb;o@$J4St*S)_TW74ga z7cnYrjE2ejWg8dzd{~VBvo%Y0fLfdCjD4afxhpp48}V*95%fT;?cw5QvCDcJk@j9% zk0-2dKh0Ks7J}_+Z#XdS)aGW{Lmj?sU5hu{dk@bUvPNuWIUKq=&%TD@#xW;eyE5v? z!7Uemmj5i;j^i=*nm>o}lWz~jo$qNrqt55@o&1^8UuU0lDE!uT%`h3z<(J1rN7;W>5eeq`B?`b?5_rY<9)MJ#-oQCoAYK%!c0=(!^X=8M?$7PO5k%8Sg&!fh-Zp|@i ze>NfaS&SkqCVL@Ve%`EVU{!dIN^_3YeQsO+s}z++QB-M0(VfSo-7d|SPecOK%)6~* z`Pp(l54UQmA-JM9-iy3!)^XT(n$>P+vrFrQhzadx%B9To^{&}G7rB&mrk{$xeIYuD zwJ*G{D~a%cM*{nMd15Z0cM)Pn;8&P^WNdOrv?r!(Af}c6>?#fKa zQ@tZAD#Omd8MCk)U9;Iu|QqkUTLapdtIcdkB-uuAswam=#*!$s31kHE2>CwcV%e? zYpXDnpyeX3aI{$+^8zQK?Zv(Xubc7M5(a9-;xWj%5z(E_J4<}f`fbSQq448CxPbh_ zbCFK0-eca4xwzJO!rLI40q0HxH)JEm&&6@_4ExbJc-k}K@^O{1QPjmArmV?LIczdu zJpD=5B##r08b4ERmg?poC2u1#@O+E)Ys{P=&J(otvPOPOx=c%WEuleoZ(Fs9?%h!z zb4}_QqX;^+rFbL7i<%ni7k^zxHh{B9;N4eebCis2Su%2MC;rCIlpoNe+IpMKb7WOrZkueR^Q{Gj(> zCBH%+2LB3A0$)P-$MW}m$qchjH?4IbZFOFjFkwGa8xTwOk;5XzVOKmhV*O- zu*;J>O(pqIcB4>Nkbm2ee>dgd3;Fg$#?Na3H2pWCai+=s*Hfw7x*>01W{1dR_Z)KD zu5kSM%yCk{Cgz)!&>O6*e1`R zq5Mm^(9gxTwI;57mTVD!C--);wWySP^_e>4OFVxdVaI3khFMhK9w_1!;gfP_NPZ7k zrEfF;WVpqam-y64NFTQe&D)W~9{J`wS1X^>WmAxCLxh4IrIs~{tw4VS7)LL(XvhO# zcPS&6eUZ_dt-09vh$V`5FKQ*8G`HzPR5{&jI@P3Db4r>*dvy6`#M}*zxrDCp*d~?4#C?%2NC9#@pGsu%N}`4DL_WK;m~?UG_)79X{#19BW?QvNbD8a0 zigd57VdU}Y;|DEEntiaIa~!9cHPuR2ZN4ZWo9CX$9PaXc^1J1GX+ z>W>t=*#qTvF#bGypo1pcsnXnMBXb^h`xdtDZZ(w$Vm9WLcp;pWIb@!6dbXE@?;=;( zS6>px)j6a-j`n$-9G+peo!+O6@3wg%JJpT*Sao(>H?EuXK6{CDa(1^p{wKz7tOwHF zovY1&#=UKs^Pw}0J}svuKyBU~lVXD7&fA)XJn+4o5_ zCAc(OGKe0pZS`3Z4==mFB2668&3de~_igf3DP|YxrRF?cZ1v%N=R94?o2h0=`Po#% zPG#b{5-M>0*}y!J!)7O|tu*CW68@@QsUPp{^ichHUv6)eu11wcf0G_8UE_%{+8(b~ zgYE3;Qi~dYn)88IB_H@eR-m{CM)%o_^L424N#W2NP37&{n6ige{ap?2+v)LYFuzJZ zuPg%>=k-cBZL8la;X8Z2*w>}s&Yo{OJYPC0%SCzSSIScB{FzyKJs*v$23@OS%<1Jd zz#dXu`PnTyB|J%Kgl}C9u*ZxPj-~sbLSf1oFnn)zL+9@OIKXxwS|;Bl7%#pkX#W zCOy=HKz2DN+@6_J7nWl^mado8<;G|e`DCta+}m@_F!>liXK&Z$%T)8NZK)Z)BOVvG zf32PeoU4Z0(&E1v8gq8tY#g2ZYy7t{-J}OIiDv)XxGwN(9hZ|AJ5AMeXO@A_6|Jvc)av;G&0(&%r}i+x&w z(f0VY8f<4zM_bzUob!m=Q9;#JQPLMdTl|pL{EqW=$O)xz=#4B_H+-jzw|B^<#63)r zV~imi?%V0{YPf!td|p`wF3#(faN1VCSHgGpd|e)ozs;U+J3Jr9gHN6LrJuZaEZr}| zGrRM1%JmMjdriFkop>JHAigL6Kamqk^bT~K`WDshMt8Yu<8z)^2!cq=DX z5?1@na^E+5w)UuetGm}My`jf$7bE4}{lr!wJzD&^l$y7m@#q`wC;3QF4${%SnzE8Fcn@$Qv%)*qjqonC}0 zc7GN~Iqq%Sf%snL@_GYzGT=OTFBN+4oqop=@E^Jp}0grDf*4|rB9Oid+mwD zC9G;A+ion0O-b+gJD-ovcPO;0kL$;CXuMjF-A%EMdQY+6O|e=uYI@q<9ih_Qe{Ot) zRqS2J>HImiVwmgRZR?-+z|Va%O17i+wYie|6}Hcxb&|=qYGr`!*HH_V##!u%&-mAJ zR=z|LzAxSFP-lz%tpek1v4_I?lGSXndANRS?0fe#T&y)NVRbpIvB%ybXn52Nd1ZGSgzm%{_( zG(=;)PJi&JMCZ82SXXgPt4!7|-aGW;IQxpo*3s7I&yo$y+wt>d_Z8_%`!K8S*Zfws z>M5*9(^s+T^?8-FawDheqHTK0rPSYC7Mq^Z5RLSDZF*n-+hEiCaGY)WY||qSXrx}h z=eY!<^gZSiJ|%^?HYP zkK5o6+E~pVAhJ=6%Jb*D9@WzV)LCgCeeg}QY(uSd1Z@>7JvNqaQ*zNZI^vA+`LfvP zh>G>v=ys3WV58eu%{F?r(GdqUO1HgxOR0t7Zq*tK9qouTyD`i@N3b?youi(Oii@?) z-MC$pWiFll5ZAKsP8pM}bz0>;xuFT`JgWbdCVCOa}CR}tPOs9z60b` zYHx2W4&>jCNQnMYvM_nv9#^TbRs8GN8Wxk5rPQD5jbp>CG2b#PHr5ssQi)GfuVk9N zW6wszwpijeW|zwj6aURvVeQT9;qbFbr>P~RUr>x@3;ZjonW+2su4OG)cgnhQtNN<5 z!&*zLZ~ID&p;kDBvpE}__Pae6xP;f`u)itx>$SeVFG}w=*x(4SOLeHV7Ky}v2@dXc4nBmX}T{f%<7xxbkA{iM5+$sf&O=O-J* zCz3>bF8OtZn^&3C^+VkFWc_)3+LYPhVe^A;lM0v|GoGcgiia6ehtfye#b$5%u)7RC zrf$5~>2p$Th$ZggXBjnEZqf(Mdq|%)r&e5+{Ci%Bp38acTWIU~?6WvSZM|RB&oP?9 z*4NJ_`Y4+%J!Qb2<+FyPHPf{AzckwGwe>l5RlRuiE`NuT#?}98O$`HO zWj8y6bEjGP$Elss{FJb+h4@CWQjGb2j5&WTQNZ8f-SxcUF{ zKmA^w-qY=z!{(bquzVz3@Y3%g_gCAp7G9}37R-JS>bhVWeM7M9ui_;pyFw2nN3Bb& z@8sxBIsX^uWWN#ZxYckz)^)b$7 ze)eBP)(?coFNDL_i_)FG1CQ`h{yUL(_T{e=(Gg(!RAjx(8I|2#IgdH*b+0+e`wKbA z`>~AkefdNfLuAk}+>^Z(L#e_$ZK|NtsN(ojXot%^PEFBm;VXRdPlM^QH`~q$gNSMD4c(-&5iDw?ZGROiH8nXRQ$xrR^iid`~ydb(NZ?!P7dF9q@P8>~m}MyBeQD?4Tb@bOQhXci2F@K$ zHG|Od-f^48k7u_#z)nL__C&AXZ2<=uY46%{nYGoMOxW7f+og-}2`T|c;uU=q*3AKH zi(3V5h5Y5Z7c?BB3U7khC8&#`le=iWOxl-wL5%yA#1gU_Bu{nso zbyIZdiHuk}W?dY7BqMz&dj6gCd365w>EdsTzdI_GvOA509Y{;QgMMyFkB}!nW|We9 zi+>76Y>ghiXz+V;{+&_8U-X`bQ{g#e$olf|yD8G_u}Ux~Q{EiOd0mLo)9rFOVl@EAiK_M+Ff6K zES{vMWo^6b8N9AhQr>8+2fum8AGj63G)(B?KA-+DY&@S3nlo}%G6DU_iY zT^A2`T`0RJJjnG2W82Qg!A`foS8D?bJQa|U{4?YMQo+1g>W|?wAxnqyf8;k{KW;aF zVP1l>MUaa;5E+B^?TF@K=Sn*gdf4>BK1iSWeaM%O1FVm<2inm(%5F4TzdGfj;r171sKTQBD>=${3ZEBz0c)?-*-i? zI(K^3PZ7Wi#fQ@NLzlJiwDt98vC3WHFESSx4~&m; zTIB_OlyGUsFSU?{;As~9xWP`P2a*-XDw=_UzNT{2)<$wDiip}7L+y>$U-i7inFt~> ze-=rO<9G~rGvg5V9o?MqnaB|Q?T(BWv>*B~j8mZKwfysUHmwddt)ADj>ZX9|*Hov1 zN)G5wd+vT)9b4!HGQ4Whb^UBQ=qZQqiw%dIpST+`R;M7XVISJZ5X%D|AuFUa!Bdxy zQS0FIEVgbytHNhrw&iuhAy`{@JFLF=?2Ex2g1OpEdcDI&3lA4ROHZuJ;Y{4-Fq23P!(&F}NFZ|VxhsG9{2u)*N5}Ml zJmfQlLc8fbN2*ULRey2O6Cv`MLXJG$G?2&pZ(_=4ig9hc;oIptwX0*y@0ynEy_e26eo?Np$J*((e3P;y1zLXgcR{IbwBb%Gg zU(FAG)S+7`CYgE?T6!uWf9Rhnw-A%FfTDb}BO?#h0e~~lajP_b~e$%=;z2+J% ztLUwVGNsmfxI=YTEnQh_J?x=6I|TNWI_q)Xw8r|rr_fidU2R5RZIx`(`nryJ;k~o$ z?kf6f9NCpsm3Bt4E7H8zk%Px9%i}jJhOLJ@rA~Q_H?32??{PX6RdL0uRj_foW~9~n z$Uigl#g(Xsl50a%RhskR45e!w3D7+SK2J1kEeX*FRtu5$!K$BSLedpiVwJbIc|l!! zvukzjZOm%h=RJ7dkcv|FD5p-NUFLug6Dt-&V4`M4GxLOV+N}Sj^wdk1X3llIG#^@* zLoKgLDn!UYlwYk|tBk8pu-2s1AFo8SL4ozOni*&g)~Pk49AzuZRHram!=q#4$M=^( zYqN*VOdOhoda-==WWA_w{8&~sQ#qi75)Rfv^+s>3TfaSnj_kbEgpdO}(yR4Qip8ul z{;pV_Z_aY^sAf|>?uZ<;`$Qc<-#(b=z2)N1&00bqKhpJZav|nDe?4jJ7S`~m+xbGi z12%V&LcqOK6q4q>KQRTy4SczC?kxM?# zS42{hW4W~2VyuWT-q5NeSRlUbSKv@LWcA|xHYkU@Ep|Xh8q)ksJeT(elo~$Cg>D)4 z(!LJKyxG|Ceen>ekk#mbasw~S{lBl3}+iBnmK}%YUf3Qf}jKQeDc=%q8uP?F zC{>-cWy7#Exj^KTj-X07J>q+fEa)i2vTiMv_uZ|!c*p3dttqK}h~tBj