diff --git a/Classes/x-saherelm.x-poi.class.mq5 b/Classes/x-saherelm.x-poi.class.mq5 new file mode 100644 index 00000000..ec9f8c22 --- /dev/null +++ b/Classes/x-saherelm.x-poi.class.mq5 @@ -0,0 +1,1827 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOI +// Description: Provides Point of Interests ... +// - Swing Highs; +// - Swing Lows; +// +// 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.xalert.class.mq5" +#include +#include +#include + +// +// Definitions ... + +// +// All Available POI(s) ... +enum ENUM_XPOIS +{ + // + // Momentum Bar ... + X_POI_MOMENTUM_BAR, // Momentum Bar ... + // + // Rejection Bar ... + X_POI_REJECTION_BAR, // Rejection Bar ... + // + // Swings ... + X_POI_SWING_HIGH, // Simple Swing High ... + X_POI_SWING_LOW, // Simple Swing Low ... + // + // Support nad Resistance ... + X_POI_SUPPORT, // Support Zone ... + X_POI_RESISTANCE, // Resistance Zone ... +}; + +// +// Event Types ... +enum ENUM_XPOI_EVENTS +{ + // + // Momentum Bar ... + X_MOMENTUM_BAR_DETECTED, // Momentum Bar ... + // + // Rejection Bar ... + X_REJECTION_BAR_DETECTED, // Rejection Bar ... + // + // Swings ... + X_SWING_HIGH_DETECTED, + X_SWING_LOW_DETECTED, + // + // Support nad Resistance ... + X_SUPPORT_DETECTED, + X_RESISTANCE_DETECTED, +}; + +// +// XOHCL Event Handler ... +typedef void (*TXOHCLEventHandler)( + XOHCL &bar // +); + +// +// Extensions ... + +/** + * Converts ENUM_XPOI value to String Representation ... + * + * @param value: ENUM_XPOI member ... + * + * @return ( string ) + */ +string ToString(ENUM_XPOIS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_POI_MOMENTUM_BAR: + result = "XMNTMB"; + break; + + // + case X_POI_REJECTION_BAR: + result = "XRJCTB"; + break; + + // + case X_POI_SWING_HIGH: + result = "XSPH"; + break; + + // + case X_POI_SWING_LOW: + result = "XSPL"; + break; + + // + case X_POI_SUPPORT: + result = "XSUP"; + break; + + // + case X_POI_RESISTANCE: + result = "XRES"; + break; + } + + // + return result; +} + +// +// Implementation ... + +// +class XCPOI : public XSCBaseAlert +{ + // + public: + // + + // + // Constructors ... + /** + * Create an Instance ... + * + * @param symbol: String ... + * @param period: ENUM_TIMEFRAMES member ... + */ + void XCPOI( + string symbol, + ENUM_TIMEFRAMES period // + ) + { + // + // Attach Required Properties ... + mSymbol = symbol; + mPeriod = period; + + // + // Initialize Bar Tracker ... + mBarTracker.Init( + mSymbol, + mPeriod // + ); + + // + // Apply Default Configurations ... + ApplyDefaultConfig(); + } + + // + // Deconstructor ... + void ~XCPOI() + { + // + DestroyPOIs(); + DestroyObjects(); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Get Chart ID ... + * + * @return ( long ) + */ + long ChartID() + { + return mChartID; + } + + /** + * Set Chart ID ... + * + * @param value: Long + */ + void ChartID(long value) + { + // + if (value < 0) + { + value = 0; + } + + // + mChartID = value; + } + + /** + * Get Sub Window Number ... + * + * @return ( int ) + */ + int Window() + { + return mWindow; + } + + /** + * Get Sub Window Number ... + * + * @param value: Integer ... + */ + void Window(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mWindow = value; + } + + /** + * Get Max Number of POIs which holds ... + * + * @return ( int ) + */ + int MaxNumberOfPOIs() + { + return mMaxNumberOfPOIs; + } + + /** + * Set Max Number of POIs which holds ... + * 0 => Infinity ... + * + * @param value: Integer ... + */ + void MaxNumberOfPOIs(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxNumberOfPOIs = value; + } + + /** + * Get Number of POI(s) which must Find at Initializations ... + * + * @return ( int ) + */ + int MaxNumberOfRequiredPOIs() + { + return mMaxNumberOfRequiredPOIs; + } + + /** + * Set Number of POI(s) which must Find at Initializations ... + * 2 is Default ... + * + * @param value: Integer ... + */ + void MaxNumberOfRequiredPOIs(int value) + { + // + if (value < 2) + { + value = 2; + } + + // + mMaxNumberOfRequiredPOIs = value; + } + + /** + * Check Is Locked or not ... + * + * @return ( bool ) + */ + bool IsLocked() + { + return mLock; + } + + // + // POI(s) Configs ... + + // + // Swing High ... + + /** + * Get Draw Swing Highs State ... + * + * @return ( bool ) + */ + bool AllowDrawSwingHighs() + { + return mAllowDrawSwingHighs; + } + + /** + * Set Draw Swing Highs State ... + * + * @param value: Boolean + */ + void AllowDrawSwingHighs(bool value) + { + mAllowDrawSwingHighs = value; + } + + /** + * Get Threshold Required for Swing High Detection ... + * + * @return ( double ) + */ + double SwingHighThreshold() + { + return mSwingHighThreshold; + } + + /** + * Set Threshold Required for Swing High Detection ... + * + * @param value: Double ... + */ + void SwingHighThreshold(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSwingHighThreshold = value; + } + + /** + * Get Swing High Arrow Code ... + * + * @return ( char ) + */ + char SwingHighArrowCode() + { + return mSwingHighArrowCode; + } + + /** + * Set Swing High Arrow Code ... + * + * @param value: Char ... + */ + void SwingHighArrowCode(char value) + { + mSwingHighArrowCode = value; + } + + /** + * Get Swing High Color ... + * + * @return ( color ) + */ + color SwingHighColor() + { + return mSwingHighColor; + } + + /** + * Get Swing High Color ... + * + * @param value: Color + */ + void SwingHighColor(color value) + { + mSwingHighColor = value; + } + + /** + * Get Swing High Width ... + * + * @return ( int ) + */ + int SwingHighWidth() + { + return mSwingHighWidth; + } + + /** + * Set Swing High Width ... + * + * @param value: Integer ... + */ + void SwingHighWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingHighWidth = value; + } + + // + // Swing Low ... + + /** + * Get Draw Swing Lows State ... + * + * @return ( bool ) + */ + bool AllowDrawSwingLows() + { + return mAllowDrawSwingLows; + } + + /** + * Set Draw Swing Lows State ... + * + * @param value: Boolean + */ + void AllowDrawSwingLows(bool value) + { + mAllowDrawSwingLows = value; + } + + /** + * Get Threshold Required for Swing Low Detection ... + * + * @return ( double ) + */ + double SwingLowThreshold() + { + return mSwingLowThreshold; + } + + /** + * Set Threshold Required for Swing Low Detection ... + * + * @param value: Double ... + */ + void SwingLowThreshold(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSwingLowThreshold = value; + } + + /** + * Get Swing Low Arrow Code ... + * + * @return ( char ) + */ + char SwingLowArrowCode() + { + return mSwingLowArrowCode; + } + + /** + * Set Swing Low Arrow Code ... + * + * @param value: Char ... + */ + void SwingLowArrowCode(char value) + { + mSwingLowArrowCode = value; + } + + /** + * Get Swing Low Color ... + * + * @return ( color ) + */ + color SwingLowColor() + { + return mSwingLowColor; + } + + /** + * Get Swing Low Color ... + * + * @param value: Color + */ + void SwingLowColor(color value) + { + mSwingLowColor = value; + } + + /** + * Get Swing Low Width ... + * + * @return ( int ) + */ + int SwingLowWidth() + { + return mSwingLowWidth; + } + + /** + * Set Swing Low Width ... + * + * @param value: Integer ... + */ + void SwingLowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSwingLowWidth = value; + } + + // + // Momentum Bars ... + + /** + * Get Draw Momentum Bars State ... + * + * @return ( bool ) + */ + bool AllowDrawMomentumBars() + { + return mAllowDrawMomentumBars; + } + + /** + * Set Draw Momentum Bars State ... + * + * @param value: Boolean + */ + void AllowDrawMomentumBars(bool value) + { + mAllowDrawMomentumBars = value; + } + + /** + * Get Momentum Bar Percent ... + * + * @return ( int ) + */ + int MomentumBarPercent() + { + return mMomentumBarPercent; + } + + /** + * Set Momentum Bar Percent ... + * + * @param value: Integer + */ + void MomentumBarPercent(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMomentumBarPercent = value; + } + + /** + * Get Momentum Bar Sharp Ratio ... + * + * @return ( double ) + */ + double MomentumBarSharpRatio() + { + return mMomentumBarSharpRatio; + } + + /** + * Set Momentum Bar Sharp Ratio ... + * + * @param value: Double ... + */ + void MomentumBarSharpRatio(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMomentumBarSharpRatio = value; + } + + /** + * Get Momentum Bar Loopback ... + * + * @return ( int ) + */ + int MomentumBarLoopBack() + { + return mMomentumBarLoopBack; + } + + /** + * Set Momentum Bar Loopback ... + * + * @param value: Integer ... + */ + void MomentumBarLoopBack(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMomentumBarLoopBack = value; + } + + /** + * Get Momentum Bar Width ... + * + * @return ( int ) + */ + int MomentumBarWidth() + { + return mMomentumBarWidth; + } + + /** + * Set Momentum Bar Width ... + * + * @param value: Integer ... + */ + void MomentumBarWidth(int value) + { + mMomentumBarWidth = value; + } + + /** + * Get Bullish Momentum Bar Arrow Code ... + * + * @return ( char ) + */ + char MomentumBarBullishArrowCode() + { + return mMomentumBarBullishArrowCode; + } + + /** + * Set Bullish Momentum Bar Arrow Code ... + * + * @param value: Char ... + */ + void MomentumBarBullishArrowCode(char value) + { + mMomentumBarBullishArrowCode = value; + } + + /** + * Get Bullish Momentum Bar Color ... + * + * @return ( char ) + */ + char MomentumBarBearishArrowCode() + { + return mMomentumBarBearishArrowCode; + } + + /** + * Set Bullish Momentum Bar Color ... + * + * @param value: Color ... + */ + void MomentumBarBearishArrowCode(char value) + { + mMomentumBarBearishArrowCode = value; + } + + /** + * Get Bearish Momentum Bar Arrow Code ... + * + * @return ( color ) + */ + color MomentumBarBullishColor() + { + return mMomentumBarBullishColor; + } + + /** + * Set Bearish Momentum Bar Arrow Code ... + * + * @param value: Color ... + */ + void MomentumBarBullishColor(color value) + { + mMomentumBarBullishColor = value; + } + + /** + * Get Bearish Momentum Bar Color ... + * + * @return ( color ) + */ + color MomentumBarBearishColor() + { + return mMomentumBarBearishColor; + } + + /** + * Set Bearish Momentum Bar Color ... + * + * @param value: Color ... + */ + void MomentumBarBearishColor(color value) + { + mMomentumBarBearishColor = value; + } + + // + // Actions ... + + /** + * Initialize POI Detector ... + */ + void Init() + { + // + // Detect Previous POI(s) ... + DetectRequiredPOIs(); + } + + /** + * Update POI(s) ... + * + * @param state: an Array Refrence of ENUM_XPOI_EVENTS members ... + */ + int Update( + ENUM_XPOI_EVENTS &state[] // + ) + { + // + int result = 0; + + // + Clean(state); + + // + // Check Bar Tracker if Waits ... + if (!mBarTracker.IsNewBar()) + { + return result; + } + + // + int cIndex = 1; + int pIndex = cIndex + 1; + + // + XOHCL cBar; + bool isInited = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!isInited) + { + return result; + } + + // + XOHCL pBar; + isInited = pBar.Init( + mSymbol, + mPeriod, + pIndex // + ); + if (!isInited) + { + return result; + } + + // + // Detect Swing High ... + int swingHighsCount = ArraySize(mSwingHighs); + bool isSingHigh = pBar.IsSimpleSwingHigh(SwingHighThreshold()); + if (isSingHigh) + { + // + AddRef( + pBar, + mSwingHighs // + ); + swingHighsCount = ArraySize(mSwingHighs); + + // + DrawSwingHighs(); + + // + Add( + X_SWING_HIGH_DETECTED, + state // + ); + OnSwingHighDetected(pBar); + NotifySwingHighEventListeners(pBar); + } + + // + // Detect Swing Low ... + int swingLowsCount = ArraySize(mSwingLows); + bool isSingLow = pBar.IsSimpleSwingLow(SwingLowThreshold()); + if (isSingLow) + { + // + AddRef( + pBar, + mSwingLows // + ); + swingLowsCount = ArraySize(mSwingLows); + + // + DrawSwingLows(); + + // + Add( + X_SWING_LOW_DETECTED, + state // + ); + OnSwingLowDetected(pBar); + NotifySwingLowEventListeners(pBar); + } + + // + // Detect Momentum Bar ... + int momentumBarsCount = ArraySize(mMomentumBars); + bool isStrongBar = cBar.IsStrong(MomentumBarPercent()); + bool isSharpBullish = cBar.IsSharpBullish( + MomentumBarLoopBack(), + MomentumBarSharpRatio() // + ); + bool isSharpBearish = cBar.IsSharpBearish( + MomentumBarLoopBack(), + MomentumBarSharpRatio() // + ); + bool isMomentumBar = + isStrongBar && + (isSharpBearish || + isSharpBullish); + if (isMomentumBar) + { + // + AddRef( + cBar, + mMomentumBars // + ); + momentumBarsCount = ArraySize(mMomentumBars); + + // + DrawMomentumBars(); + + // + Add( + X_MOMENTUM_BAR_DETECTED, + state // + ); + OnMomentumBarDetected(pBar); + NotifyMomentumBarEventListeners(pBar); + } + + // + mBarTracker.Waits(); + + // + result = ArraySize(state); + + // + return result; + } + + /** + * Enable Draw All POI(s) ... + */ + void EnableDrawPOIs() + { + // + bool state = true; + + // + AllowDrawSwingHighs(state); + AllowDrawSwingLows(state); + AllowDrawMomentumBars(state); + } + + /** + * Disable Draw All POI(s) ... + */ + void DisableDrawPOIs() + { + // + bool state = false; + + // + AllowDrawSwingHighs(state); + AllowDrawSwingLows(state); + AllowDrawMomentumBars(state); + } + + // + // Virtual Actions ... + + /** + * Apply Default Configurations ... + */ + virtual void ApplyDefaultConfig() + { + // + ChartID(0); + Window(0); + + // + MaxNumberOfPOIs(10); + MaxNumberOfRequiredPOIs(2); + + // + SwingHighWidth(5); + SwingHighThreshold(3); + SwingHighArrowCode(108); + SwingHighColor(clrMagenta); + + // + SwingLowWidth(5); + SwingLowThreshold(3); + SwingLowArrowCode(108); + SwingLowColor(clrAqua); + + // + MomentumBarPercent(55); + MomentumBarLoopBack(3); + MomentumBarSharpRatio(1.2); + MomentumBarWidth(5); + MomentumBarBullishArrowCode((char)225); + MomentumBarBearishArrowCode((char)226); + MomentumBarBullishColor(clrAqua); + MomentumBarBearishColor(clrMagenta); + } + + // + // Event Listeners ... + + /** + * Calls When new Swing High Detected ... + * + * @param bar: XOHCL instance ... + */ + virtual void OnSwingHighDetected(XOHCL &bar) + { + } + + /** + * Register an Event Listener for New Swing High Detected ... + * + * @param listener: TXOHCLEventHandler instance ... + */ + void AddSwingHighEventListener(TXOHCLEventHandler listener) + { + // + Add( + listener, + mSwingHighEventListeners // + ); + } + + /** + * Calls When new Swing Low Detected ... + * + * @param bar: XOHCL instance ... + */ + virtual void OnSwingLowDetected(XOHCL &bar) + { + } + + /** + * Register an Event Listener for New Swing Low Detected ... + * + * @param listener: TXOHCLEventHandler instance ... + */ + void AddSwingLowEventListener(TXOHCLEventHandler listener) + { + // + Add( + listener, + mSwingLowEventListeners // + ); + } + + /** + * Calls When new Momentum Bar Detected ... + * + * @param bar: XOHCL instance ... + */ + virtual void OnMomentumBarDetected(XOHCL &bar) + { + } + + /** + * Register an Event Listener for New Momentum Bar Detected ... + * + * @param listener: TXOHCLEventHandler instance ... + */ + void AddMomentumBarEventListener(TXOHCLEventHandler listener) + { + // + Add( + listener, + mMomentumBarEventListeners // + ); + } + + // + protected: + // + + // + // Actions ... + + /** + * Lock ... + */ + void Lock() + { + mLock = true; + } + + /** + * Unlock ... + */ + void Unlock() + { + mLock = false; + } + + /** + * Detect Required POI(s) ... + * + * @param barIndex: Integer Start bar index ... + * 0 is Default ... + */ + void DetectRequiredPOIs(int barIndex = 0) + { + // + // Validate Reuired POI(s) ... + int requiredPOIs = MaxNumberOfRequiredPOIs(); + if (requiredPOIs <= 0) + { + return; + } + + // + Lock(); + + // + // Normalize Bar Index ... + if (barIndex < 0) + { + barIndex = 0; + } + + // + // Define Index of Bars ... + int zIndex = barIndex; + int cIndex = zIndex + 1; + + // + XOHCL cBar; + bool isRetrieved = mBarTracker.GetBar(cBar, cIndex); + if (!isRetrieved) + { + return; + } + + // + // Detect POI(s) based On Current Bar ... + + // + // Swing Highs ... + int swingHighsCount = ArraySize(mSwingHighs); + if (swingHighsCount < requiredPOIs) + { + // + bool isSwingHigh = cBar.IsSimpleSwingHigh(SwingHighThreshold()); + if (isSwingHigh) + { + // + AddRef( + cBar, + mSwingHighs // + ); + + // + swingHighsCount = ArraySize(mSwingHighs); + } + } + + // + // Swing Low ... + int swingLowsCount = ArraySize(mSwingLows); + if (swingLowsCount < requiredPOIs) + { + // + bool isSwingLow = cBar.IsSimpleSwingLow(SwingLowThreshold()); + if (isSwingLow) + { + // + AddRef( + cBar, + mSwingLows // + ); + + // + swingLowsCount = ArraySize(mSwingLows); + } + } + + // + // Momentum Bars ... + int momentumBarsCount = ArraySize(mMomentumBars); + if (momentumBarsCount < requiredPOIs) + { + // + bool isStrongBar = cBar.IsStrong(MomentumBarPercent()); + + // + // Bullish ... + bool isSharpBullish = cBar.IsSharpBullish( + MomentumBarLoopBack(), + MomentumBarSharpRatio() // + ); + + // + // Bearish ... + bool isSharpBearish = cBar.IsSharpBearish( + MomentumBarLoopBack(), + MomentumBarSharpRatio() // + ); + + // + bool isMomentumBar = + isStrongBar && + (isSharpBearish || + isSharpBullish); + if (isMomentumBar) + { + // + AddRef( + cBar, + mMomentumBars // + ); + + // + momentumBarsCount = ArraySize(mMomentumBars); + } + } + + // + bool canContinue = + // + swingHighsCount < requiredPOIs || + swingLowsCount < requiredPOIs || + momentumBarsCount < requiredPOIs + // + ; + if (canContinue) + { + DetectRequiredPOIs(barIndex + 1); + } + else + { + // + // Complete Calculations ... + + // + XOHCL tmpBars[]; + + // + // Reverse Swing Highs ... + Copy( + mSwingHighs, + tmpBars // + ); + Clean(mSwingHighs); + ArrayReverse(tmpBars); + Copy( + tmpBars, + mSwingHighs // + ); + Clean(tmpBars); + + // + // Reverse Swing Lows ... + Copy( + mSwingLows, + tmpBars // + ); + Clean(mSwingLows); + ArrayReverse(tmpBars); + Copy( + tmpBars, + mSwingLows // + ); + Clean(tmpBars); + + // + // Reverse Momentum Bars ... + Copy( + mMomentumBars, + tmpBars // + ); + Clean(mMomentumBars); + ArrayReverse(tmpBars); + Copy( + tmpBars, + mMomentumBars // + ); + Clean(tmpBars); + + // + Unlock(); + DrawPOIs(); + } + } + + // + // Destroy POIs ... + + /** + * Destroy All POI(s) ... + */ + void DestroyPOIs() + { + // + DestroySwingHighs(); + DestroySwingLows(); + + // + DestroyMomentumBars(); + } + + /** + * Destroy Swing Highs ... + */ + void DestroySwingHighs() + { + Clean(mSwingHighs); + } + + /** + * Destroy Swing Lows ... + */ + void DestroySwingLows() + { + Clean(mSwingLows); + } + + /** + * Destroy Momentum Bars ... + */ + void DestroyMomentumBars() + { + Clean(mMomentumBars); + } + + // + // Draw Actions ... + + /** + * Draw All POI(s) ... + */ + void DrawPOIs() + { + // + DrawSwingHighs(); + DrawSwingLows(); + + // + DrawMomentumBars(); + } + + /** + * Draw Swing Highs ... + */ + void DrawSwingHighs() + { + // + bool allow = AllowDrawSwingHighs(); + if (!allow) + { + return; + } + + // + int count = ArraySize(mSwingHighs); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XOHCL iSwing = mSwingHighs[i]; + + // + string iName = iSwing.GetTag(ToString(X_POI_SWING_HIGH)); + int iIDX = HasObject( + iName, + mSwingHighObjects // + ); + if (IsValidIndex(iIDX)) + { + continue; + } + + // + CreateSwingHighObject(iSwing, iName); + } + } + + /** + * Draw Swing Lows ... + */ + void DrawSwingLows() + { + // + bool allow = AllowDrawSwingLows(); + if (!allow) + { + return; + } + + // + int count = ArraySize(mSwingLows); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XOHCL iSwing = mSwingLows[i]; + + // + string iName = iSwing.GetTag(ToString(X_POI_SWING_LOW)); + int iIDX = HasObject( + iName, + mSwingLowObjects // + ); + if (IsValidIndex(iIDX)) + { + continue; + } + + // + CreateSwingLowObject(iSwing, iName); + } + } + + /** + * Draw Momentum Bars ... + */ + void DrawMomentumBars() + { + // + bool allow = AllowDrawMomentumBars(); + if (!allow) + { + return; + } + + // + int count = ArraySize(mMomentumBars); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XOHCL iBar = mMomentumBars[i]; + + // + string iName = iBar.GetTag(ToString(X_POI_MOMENTUM_BAR)); + int iIDX = HasObject( + iName, + mMomentumBarObjects // + ); + if (IsValidIndex(iIDX)) + { + continue; + } + + // + CreateMomentumBarObject(iBar, iName); + } + } + + /** + * Clean All Drawn Objects ... + */ + void DestroyObjects() + { + // + DestroySwingHighObjects(); + DestroySwingLowObjects(); + DestroyMomentumBarObjects(); + } + + /** + * Clean Swing Highs Drawn Objects ... + */ + void DestroySwingHighObjects() + { + mSwingHighObjects.Clear(); + } + + /** + * Clean Swing Lows Drawn Objects ... + */ + void DestroySwingLowObjects() + { + mSwingLowObjects.Clear(); + } + + /** + * Clean Momentum Bars Drawn Objects ... + */ + void DestroyMomentumBarObjects() + { + mMomentumBarObjects.Clear(); + } + + /** + * Detect an Object Exists in Array or not ... + * + * @param name: String ... + * @param array: CArrayObj instance ... + * + * @return ( int ): index of Object ... + */ + int HasObject( + string name, + CArrayObj &array // + ) + { + // + int result = -1; + + // + if (!IsValid(name)) + { + return result; + } + + // + int count = array.Total(); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + CChartObject iObj = array.At(i); + + // + if (iObj.Name() == name) + { + // + result = i; + break; + } + } + + // + return result; + } + + // + // Event Handler Notifiers ... + + /** + * Notify New Swing High Point Event Handlers ... + * + * @param bar: XOHCL instance ... + */ + void NotifySwingHighEventListeners(XOHCL &bar) + { + // + if (!bar.IsValid()) + { + return; + } + + // + int count = ArraySize(mSwingHighEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TXOHCLEventHandler iListener = mSwingHighEventListeners[i]; + iListener(bar); + } + } + + /** + * Notify New Swing Low Point Event Handlers ... + * + * @param bar: XOHCL instance ... + */ + void NotifySwingLowEventListeners(XOHCL &bar) + { + // + if (!bar.IsValid()) + { + return; + } + + // + int count = ArraySize(mSwingLowEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TXOHCLEventHandler iListener = mSwingLowEventListeners[i]; + iListener(bar); + } + } + + /** + * Notify New Momentum Bar Event Handlers ... + * + * @param bar: XOHCL instance ... + */ + void NotifyMomentumBarEventListeners(XOHCL &bar) + { + // + if (!bar.IsValid()) + { + return; + } + + // + int count = ArraySize(mMomentumBarEventListeners); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TXOHCLEventHandler iListener = mMomentumBarEventListeners[i]; + iListener(bar); + } + } + + // + private: + // + + // + // Props ... + + // + bool mLock; // Lock State ... + string mSymbol; // Market Symbol ... + ENUM_TIMEFRAMES mPeriod; // Market Period ... + long mChartID; // Chart ID ... + int mWindow; // Window ID ... + int mMaxNumberOfPOIs; // Max Allowed Number of POI(s) which Can Holds ... + int mMaxNumberOfRequiredPOIs; // Max Allowed Number of POI(s) which Must Find at Initializion Time ... + + // + XBarTracker mBarTracker; // Market Bar Tracker ... + + // + // POI Holders ... + + // + // Swing Highs ... + + bool mAllowDrawSwingHighs; // Draw Swing Highs ... + char mSwingHighArrowCode; // Swing High Arrow Code ... + color mSwingHighColor; // Swing High Color ... + int mSwingHighWidth; // Swing High Width ... + double mSwingHighThreshold; // Threshold Required for Swing High Detection ... + XOHCL mSwingHighs[]; // Swing Highs ... + CArrayObj mSwingHighObjects; // Swing High Chart Objects ... + TXOHCLEventHandler mSwingHighEventListeners[]; // Swing High Event Listeners ... + + /** + * Create an Object to Represent Swing High on Chart ... + * + * @param bar: XOHCL instance ... + * @param name: String ... + */ + void CreateSwingHighObject( + XOHCL &bar, + string name // + ) + { + // + if (!bar.IsValid() || + !IsValid(name)) + { + return; + } + + // + CChartObjectArrow *iObj; + iObj = new CChartObjectArrow(); + bool isCreated = iObj.Create( + ChartID(), + name, + Window(), + bar.time, + bar.high, + SwingHighArrowCode() // + ); + if (!isCreated) + { + return; + } + + // + // Configure Object ... + iObj.Width(SwingHighWidth()); + iObj.Color(SwingHighColor()); + iObj.Anchor(ANCHOR_BOTTOM); + + // + mSwingHighObjects.Add(iObj); + } + + // + // Swing Lows ... + + bool mAllowDrawSwingLows; // Draw Swing Lows ... + char mSwingLowArrowCode; // Swing Low Arrow Code ... + color mSwingLowColor; // Swing Low Color ... + int mSwingLowWidth; // Swing Low Width ... + double mSwingLowThreshold; // Threshold Required for Swing Low Detection ... + XOHCL mSwingLows[]; // Swing Lows ... + CArrayObj mSwingLowObjects; // Swing Low Chart Objects ... + TXOHCLEventHandler mSwingLowEventListeners[]; // Swing Low Event Listeners ... + + /** + * Create an Object to Represent Swing Low on Chart ... + * + * @param bar: XOHCL instance ... + * @param name: String ... + */ + void CreateSwingLowObject( + XOHCL &bar, + string name // + ) + { + // + if (!bar.IsValid() || + !IsValid(name)) + { + return; + } + + // + CChartObjectArrow *iObj; + iObj = new CChartObjectArrow(); + bool isCreated = iObj.Create( + ChartID(), + name, + Window(), + bar.time, + bar.low, + SwingLowArrowCode() // + ); + if (!isCreated) + { + return; + } + + // + // Configure Object ... + iObj.Width(SwingLowWidth()); + iObj.Color(SwingLowColor()); + iObj.Anchor(ANCHOR_TOP); + + // + mSwingLowObjects.Add(iObj); + } + + // + // Momentum Bar ... + + bool mAllowDrawMomentumBars; // Draw Momentum Bars ... + int mMomentumBarPercent; // Momentum Bar Percent ... + double mMomentumBarSharpRatio; // Momentum Bar Sharp Ratio ... + int mMomentumBarLoopBack; // Momentum Bar Loopback ... + int mMomentumBarWidth; // Momentum Bar Width ... + char mMomentumBarBullishArrowCode; // Bullish Momentum Bar Arrow Code ... + char mMomentumBarBearishArrowCode; // Bullish Momentum Bar Color ... + color mMomentumBarBullishColor; // Bearish Momentum Bar Arrow Code ... + color mMomentumBarBearishColor; // Bearish Momentum Bar Color ... + XOHCL mMomentumBars[]; // Momentum Bars ... + CArrayObj mMomentumBarObjects; // Momentm Bar Chart Objects ... + TXOHCLEventHandler mMomentumBarEventListeners[]; // Momentum Bars Event Listeners ... + + /** + * Create an Object to Represent Momentum Bar on Chart ... + * + * @param bar: XOHCL instance ... + * @param name: String ... + */ + void CreateMomentumBarObject( + XOHCL &bar, + string name // + ) + { + // + if (!bar.IsValid() || + !IsValid(name)) + { + return; + } + + // + bool isBullish = bar.IsBullish(); + double price = + isBullish + ? bar.low + : bar.high; + char arrowCode = + isBullish + ? MomentumBarBullishArrowCode() + : MomentumBarBearishArrowCode(); + color clr = + isBullish + ? MomentumBarBullishColor() + : MomentumBarBearishColor(); + ENUM_ARROW_ANCHOR anchor = + isBullish + ? ANCHOR_TOP + : ANCHOR_BOTTOM; + + // + CChartObjectArrow *iObj; + iObj = new CChartObjectArrow(); + bool isCreated = iObj.Create( + ChartID(), + name, + Window(), + bar.time, + price, + arrowCode // + ); + if (!isCreated) + { + return; + } + + // + // Configure Object ... + iObj.Width(MomentumBarWidth()); + iObj.Color(clr); + iObj.Anchor(anchor); + + // + mMomentumBarObjects.Add(iObj); + } + + // +}; + +// \ No newline at end of file diff --git a/Experts/x-saherelm.x-121.smc.ea.mq5 b/Experts/x-saherelm.x-121.smc.ea.mq5 index 5490163f..ba025e17 100644 --- a/Experts/x-saherelm.x-121.smc.ea.mq5 +++ b/Experts/x-saherelm.x-121.smc.ea.mq5 @@ -28,6 +28,12 @@ #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" + +// +// TEST ... +#include "../Classes/x-saherelm.x-poi.class.mq5" +XCPOI *eaPOI; // // Inputs ... @@ -39,6 +45,12 @@ input long eaMagicNumber = 78692110; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix +// +// Symbols ... +input group "Symbols"; +input bool eaMultiSymbol = false; // Use Multi Symbol +input string eaSymbols = "EURUSDb,GBPUSDb,USDJPYb,USDCHFb,DowJones30,XAUUSDb"; // Trading Symbols + // // Alert ... // Here we Provider All Requirements for @@ -62,13 +74,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 ... +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 ... // // Event Handlers ... @@ -159,6 +172,15 @@ void OnTick() HandleReportTime(); UpdatePositionsState(); + // + // TEST ... + ENUM_XPOI_EVENTS states[]; + int statesCount = eaPOI.Update(states); + if (IsValidSize(statesCount)) + { + eaAlert.Log("POI Events Happens: " + ToString(statesCount)); + } + // // TODO: Implemetn Tick Processors Algorithm ... } @@ -241,6 +263,21 @@ void OnPositionForceClosed( HandleReportBalance(); } +/** + * Do What we Want by Specific Signal ... + * + * @param signal: XSignal instance ... + * @param conditions: XStrategyConditions instance ... + */ +void OnSignalRecieved( + XSignal &signal, + XStrategyConditions &conditions // +) +{ + // + // TODO: Implement this ... +} + // // Custom Functions ... @@ -387,6 +424,111 @@ bool InitEA() eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + // + // TEST ... + eaPOI = new XCPOI( + _Symbol, + _Period // + ); + eaPOI.EnableDrawPOIs(); + eaPOI.AllowDrawSwingHighs(false); + eaPOI.AllowDrawSwingLows(false); + eaPOI.Init(); + + // // + // // Symbols Parsing ... + + // // + // // Parsers ... + // XSymbolParser _symbolParser; + + // // + // // Single Symbol ... + // if (!eaMultiSymbol) + // { + + // // + // // Register Strategy ... + // } + // // + // // Multi Symbol ... + // else + // { + // // + // // Parse Symbols ... + // string symbols[]; + // int symbolsCount = SplitContent( + // symbols, + // eaSymbols // + // ); + // result = IsValidSize(symbolsCount); + // if (!result) + // { + // return result; + // } + + // // + // for (int i = 0; i < symbolsCount; i++) + // { + // // + // // Select Symbol ... + // string iSymbol = symbols[i]; + + // // + // // Register Strategy Based On Symbol ... + + // // + // // Parse Symbol ... + // bool isEURUSD = _symbolParser.IsEURUSD(_Symbol); + // bool isGBPUSD = _symbolParser.IsGBPUSD(_Symbol); + // bool isEURGBP = _symbolParser.IsEURGBP(_Symbol); + // bool isUSDCHF = _symbolParser.IsUSDCHF(_Symbol); + // bool isEURCHF = _symbolParser.IsEURCHF(_Symbol); + // bool isUSDJPY = _symbolParser.IsUSDJPY(_Symbol); + // bool isEURJPY = _symbolParser.IsEURJPY(_Symbol); + // bool isUSDCAD = _symbolParser.IsUSDCAD(_Symbol); + // bool isEURCAD = _symbolParser.IsEURCAD(_Symbol); + // bool isAUDUSD = _symbolParser.IsAUDUSD(_Symbol); + // bool isEURAUD = _symbolParser.IsEURAUD(_Symbol); + // bool isNZDUSD = _symbolParser.IsNZDUSD(_Symbol); + // bool isEURNZD = _symbolParser.IsEURNZD(_Symbol); + + // // + // // Check Symbol Can Register or not ... + // bool canRegisterStrategy = true; + + // // + // if (canRegisterStrategy) + // { + // // + // // Create Class Instance ... + // XCX121SMCStrategy *iX121SMCStrategy; + // iX121SMCStrategy = new XCX121SMCStrategy( + // iSymbol, + // _Period // + // ); + + // // + // // Configuere Strategy ... + // // iX121SMCStrategy.DrawImportantAreas(false); + // // iX121SMCStrategy.AddXSignalEventHandler(OnSignalRecieved); + + // // // + // // // Configure Alerts ... + // // iX121SMCStrategy.SetAlertPrefix(eaLogTag); + // // iX121SMCStrategy.SetAlertEnableAlerts(eAEnableAlerts); + // // iX121SMCStrategy.SetAlertLogAlerts(eALogAlerts); + // // iX121SMCStrategy.SetAlertMailAlerts(eAMailAlerts); + // // iX121SMCStrategy.SetAlertPushAlerts(eAPushAlerts); + // // iX121SMCStrategy.SetAlertTerminalAlerts(eATerminalAlerts); + + // // + // // Register Strategy ... + // RegisterStrategy(iX121SMCStrategy); + // } + // } + // } + // return result; } @@ -402,6 +544,10 @@ void DestroyEA() // delete eaAlert; + + // + // TEST ... + delete eaPOI; } /** @@ -566,3 +712,28 @@ void HandleReportTime() } // + +/** + * Register an Strategy in EA ... + * + * @param strategy: XCX121SMCStrategy instance ... + */ +void RegisterStrategy(XCX121SMCStrategy *strategy) +{ + // + if (strategy == NULL) + { + return; + } + + // + ArrayResize( + eaStrategies, + ArraySize(eaStrategies) + 1 // + ); + + // + eaStrategies[ArraySize(eaStrategies) - 1] = strategy; +} + +// diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index 0ac2629d..e9baf5db 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -1130,6 +1130,44 @@ struct XOHCL return result; } + // + bool GetNextBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + result = idx > 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + this.symbol, + this.period, + idx - 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + // bool GetPreviousBar(XOHCL &bar) { @@ -1196,7 +1234,7 @@ struct XOHCL // result = - IsStrong() && IsBullish(); + IsStrong(percent) && IsBullish(); // return result; @@ -1212,7 +1250,7 @@ struct XOHCL // result = - IsStrong() && IsBearish(); + IsStrong(percent) && IsBearish(); // return result; @@ -2822,6 +2860,57 @@ struct XOHCL return result; } + // + // Find Simple 3 Candle Based Swing High ... + bool IsSimpleSwingHigh(double thresholdInPoint = 1) + { + // + bool result = false; + + // + int index = Index(); + result = index > 0; + if (!result) + { + return result; + } + + // + XOHCL nextBar; + result = GetNextBar(nextBar); + if (!result) + { + return result; + } + + // + XOHCL prevBar; + result = GetPreviousBar(prevBar); + if (!result) + { + return result; + } + + // + double point = GetPoints(symbol); + double requiredOffset = point * thresholdInPoint; + + // + result = + high > nextBar.high && + high > prevBar.high && + (thresholdInPoint <= 0 + ? true + : MathAbs( + MathMax( + nextBar.high, + prevBar.high) - + high) >= requiredOffset); + + // + return result; + } + // // Find Last Swing High ... bool FindLastSwingHigh(XOHCL &swing) @@ -2947,6 +3036,57 @@ struct XOHCL return result; } + // + // Find Simple 3 Candle Based Swing Low ... + bool IsSimpleSwingLow(double thresholdInPoint = 1) + { + // + bool result = false; + + // + int index = Index(); + result = index > 0; + if (!result) + { + return result; + } + + // + XOHCL nextBar; + result = GetNextBar(nextBar); + if (!result) + { + return result; + } + + // + XOHCL prevBar; + result = GetPreviousBar(prevBar); + if (!result) + { + return result; + } + + // + double point = GetPoints(symbol); + double requiredOffset = point * thresholdInPoint; + + // + result = + low < nextBar.low && + low < prevBar.low && + (thresholdInPoint <= 0 + ? true + : MathAbs( + MathMax( + nextBar.low, + prevBar.low) - + low) >= requiredOffset); + + // + return result; + } + // // Find Last Swing Low ... bool FindLastSwingLow(XOHCL &swing) @@ -4147,6 +4287,21 @@ struct XOHCL // // Other ... + string GetTag(string prefix) + { + // + string result = NULL; + + // + result = + (IsValid(prefix) + ? prefix + "_" + : "") + + "XOHCL_" + symbol + "_" + ToString(period) + "_" + ToFormatString(time); + + // + return result; + } // // Convert to String Representation ... diff --git a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 new file mode 100644 index 00000000..c4109261 --- /dev/null +++ b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 @@ -0,0 +1,1802 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XSCX121Strategy +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include "../../Classes/x-saherelm.xalert.class.mq5" +#include "../../Classes/x-saherelm.xtrade.class.mq5" + +// +// Helper(s) ... + +// +// Definitions ... + +// +// Specific Identifier(s) of XStrategy ... +string X121SMCStrategyToken = "X121SMC"; + +// +// Condition Structure ... +struct XStrategyConditions +{ + // + // Props ... + + // + // Common ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + // Important Ares attached ... + + // + XOHCL support; + XOHCL resistance; + XOHCL bullishOB; + XOHCL bearishOB; + + // + double bullishFVGUpper; + double bullishFVGLower; + XOHCL bullishFVG; + + // + double bearishFVGUpper; + double bearishFVGLower; + XOHCL bearishFVG; + + // + XOHCL bullishTrendSwingHighs[]; + XOHCL bullishTrendSwingLows[]; + XOHCL bullishTrend; + + // + XOHCL bearishTrendSwingHighs[]; + XOHCL bearishTrendSwingLows[]; + XOHCL bearishTrend; + + // + // Helper Conditions ... + + // + // Constructor ... + void XStrategyConditions() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + period = NULL; + time = NULL; + + // + // Clean Helpers Conditions ... + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(time) && + IsValid(symbol) && + IsValid(period) + // + ; + + // + return result; + } + + // + // Generate Provided Scores ... + void GenerateScore( + double &bullishScore, + double &bearishScore // + ) + { + // + bullishScore = 0; + bearishScore = 0; + + // + if (!IsValid()) + { + return; + } + + // + double bullScore = 0; + double bearScore = 0; + + // + // Generate Helpers Conitions Scores ... + } + + // + // Generate Summary ... + string GenerateSummary( + bool onlyCommons = false, + bool onlyConditions = false, + bool includeScores = true, + bool ignoreFalseConditions = true, + string separator = "\n" // + ) + { + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + GenerateScore( + bullishScore, + bearishScore // + ); + + // + string commonStr = GenerateSpecifiedCommonSummary( + this, + separator, + includeScores, + true // + ); + + // + // Generate Helpers Conditions Strings ... + + // + // Combine Helpers Conditions Strings ... + string conditionsStr = + // + "" + separator + + "" + // + ; + + // + result = + // + "[" + GetTag() + "]" + separator + + "----------" + separator + + (onlyConditions + ? "" + : commonStr) + + " " + separator + + (onlyCommons + ? "" + : conditionsStr) + + "" + // + ; + + // + return result; + } + + // + string GetTag() + { + return X121SMCStrategyToken; + } + + // +}; + +// +// On Signal Event Handler ... +typedef void (*TOnXSignal)( + XSignal &signal, + XStrategyConditions &conditions // +); + +// +// XStrategy Class Implementation(s) ... +class XCX121SMCStrategy : public XSCBaseAlert +{ + // + // Public ... + public: + // + // Constructor(s) ... + void XCX121SMCStrategy( + // + // Base ... + string _symbol, // Trading Symbol + ENUM_TIMEFRAMES _period // Trading TimeFrame + ) + { + // + SetAlertPrefix(GetTag()); + + // + PrepareRequirements(); + } + + // + // Deconstructor ... + void ~XCX121SMCStrategy() + { + } + + // + // Getter / Setter (s) ... + + /** + * Retrieve Symbol ... + * + * @return ( string ) + */ + string Symbol() + { + return mSymbol; + } + + /** + * Retrieve TimeFrame ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES Period() + { + return mPeriod; + } + + /** + * Check Strategy is Disabled or not ... + * + * @return ( bool ) + */ + bool IsDisabled() + { + return mForceDisabled; + } + + /** + * Get Signal Volume ... + * + * @return ( double ) + */ + double Volume() + { + return mVolume; + } + + /** + * Set Signal Volume ... + * + * @param value: Double ... + */ + void Volume(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mVolume = value; + } + + /** + * Get Risk/Reward Ratio ... + * + * @return ( double ) + */ + double R2R() + { + return mR2R; + } + + /** + * Set Risk/Reward Ratio ... + * + * @param value: Double ... + */ + void R2R(double value) + { + // + if (value < 0) + { + value = 1.5; + } + + // + mR2R = value; + } + + /** + * Get Long Signalling State ... + * + * @return ( bool ) + */ + bool AllowLong() + { + return mAllowLong; + } + + /** + * Set Long Signalling State ... + * + * @param value: Boolean ... + */ + void AllowLong(bool value) + { + mAllowLong = value; + } + + /** + * Get Short Signalling State ... + * + * @return ( bool ) + */ + bool AllowShort() + { + return mAllowShort; + } + + /** + * Set Short Signalling State ... + * + * @param value: Argument 1 + */ + void AllowShort(bool value) + { + mAllowShort = value; + } + + // + // Actions ... + + /** + * Disable Strategy ... + */ + void Disable() + { + mForceDisabled = true; + } + + /** + * Enable Strategy ... + */ + void Enable() + { + mForceDisabled = false; + } + + /** + * Register Signal Event Handler ... + * + * @param handler: an Instance of TOnXSignal ... + */ + void AddXSignalEventHandler(TOnXSignal handler) + { + // + Add( + handler, + mSignalEventHandlers // + ); + } + + // + // Virtual Actions ... + + // + // Check Conditions For Signal and Execute Signal ... + virtual void HandleTick() + { + // + // Check State ... + if (IsDisabled()) + { + return; + } + + // + // Check Signalling State ... + if (!AllowLong() && !AllowShort()) + { + return; + } + + // + // Check Bar Tracker State ... + if (!mBarTracker.CanProcessBar()) + { + return; + } + + // + // Retrieve Current Tick and Check it's Time + // by Last Issued Tick ... + MqlTick cTick; + bool hasTick = GetTick( + mSymbol, + cTick // + ); + bool isSameAsLast = cTick.time == mLastTick.time; + if (isSameAsLast) + { + return; + } + + // + // Update Last Issued Tick ... + mLastTick = cTick; + + // + // Check Current Processing Tick has Signal or not ... + XSignal signal; + XStrategyConditions conditions; + bool hasSignal = HasSignal( + signal, + conditions // + ); + if (!hasSignal) + { + return; + } + + // + // Waits Until Next Candle if Current Tick has Signal ... + mBarTracker.Waits(); + + // + // Notify Signal Event Handlers ... + NotifyOnSignalEventHandlers( + signal, + conditions // + ); + } + + // + // Check Conditions For Signal ... + virtual bool HasSignal( + XSignal &signal, + XStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + signal.Clean(); + conditions.Clean(); + + // + double sl = 0; + double tp = 0; + double risk = 0; + double entry = 0; + double reward = 0; + double r2r = R2R(); + double volume = Volume(); + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + + // + bool hasLong = false; + bool hasShort = false; + + // + // Retrieve Helper Conditions ... + + // + // Start Calculations ... + + // + double points = GetPoints(mSymbol); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + // Retrieve Bars ... + + // + // Last Bar ... + XOHCL cBar; + result = cBar.Init( + mSymbol, + mPeriod, + cIndex // + ); + if (!result) + { + return result; + } + + // + // Prepare Conditions ... + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = cBar.time; + + // + // Attach Helpers Conditins ... + + // + result = conditions.IsValid(); + if (!result) + { + return result; + } + + // + // Previous Bar of Last Bar ... + XOHCL pBar; + result = cBar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Last Swing Low Bar ... + XOHCL lastSwingLow; + result = cBar.FindLastSwingLow(lastSwingLow); + if (!result) + { + return result; + } + + // + // Last Swing High Bar ... + XOHCL lastSwingHigh; + result = cBar.FindLastSwingHigh(lastSwingHigh); + if (!result) + { + return result; + } + + // + int pushers = 0; + string signallers[]; + + // + // Retrieve all Helpers Based Configurations Here ... + + // + // Common Conditions For Bullish and Bearish Powers ... + + // + // For Trend ... + XOHCL tmpHSW[]; + XOHCL tmpLSW[]; + + // + // Detect Bullish/Bearish Patterns and Trends ... + + // + // Bullish ... + bool hasBullishPower = cBar.HasBullishPower(); + bool hasBullishPattern = HasBullishPattern(cBar); + bool hasBullishPressure = cBar.HasBullishPressure(); + bool isBullishTrend = cBar.HasBullishTrend( + tmpHSW, + tmpLSW, + true // + ); + bool isBullishTrend1 = cBar.HasBullishTrend( + tmpHSW, + tmpLSW, + false // + ); + bool hasBullishTrend = + // + isBullishTrend + // + || + // + isBullishTrend1 + // + ; + + // + // Bearish ... + bool hasBearishPower = cBar.HasBearishPower(); + bool hasBearishPattern = HasBearishPattern(cBar); + bool hasBearishPressure = cBar.HasBearishPressure(); + bool isBearishTrend = cBar.HasBearishTrend( + tmpHSW, + tmpLSW, + true // + ); + bool isBearishTrend1 = cBar.HasBearishTrend( + tmpHSW, + tmpLSW, + false // + ); + bool hasBearishTrend = + // + isBearishTrend + // + || + // + isBearishTrend1 + // + ; + + // + bool hasBearishDecision = + // + cBar.IsBearishDecision() + // + ; + + // + bool hasBullishDecision = + // + cBar.IsBullishDecision() + // + ; + + // + // Define Conditions ... + MqlTick ticks[]; + int ticksCount = CopyTicks( + mSymbol, + ticks, + COPY_TICKS_ALL, + 0, + 5 // + ); + + // + bool isTicksBullishForLong = false; + bool isTicksBearishForLong = false; + bool isTicksBullishForShort = false; + bool isTicksBearishForShort = false; + if (ticksCount == 5) + { + // + isTicksBullishForLong = + // + GetTickEntry(ticks[0], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) && + GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) && + GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, mSymbol) + // + ; + + // + isTicksBearishForLong = + // + GetTickEntry(ticks[0], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) && + GetTickEntry(ticks[1], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) && + GetTickEntry(ticks[2], POSITION_TYPE_BUY, mSymbol) < GetTickEntry(ticks[3], POSITION_TYPE_BUY, mSymbol) + // + ; + + // + isTicksBullishForShort = + // + GetTickEntry(ticks[0], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) && + GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) && + GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) > GetTickEntry(ticks[3], POSITION_TYPE_SELL, mSymbol) + // + ; + + // + isTicksBearishForShort = + // + GetTickEntry(ticks[0], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) && + GetTickEntry(ticks[1], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) && + GetTickEntry(ticks[2], POSITION_TYPE_SELL, mSymbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, mSymbol) + // + ; + } + + // + // TODO: Complete this ... + bool notHaveBearishPower = false; + + // + // TODO: Complete this ... + bool notHaveBullishPower = false; + + // + // Detecting Signals ... + + // + bool hasBaseLongConditions = + cBar.IsBullish() && + hasBullishTrend && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) && + notHaveBearishPower && + isTicksBullishForLong; + + // + bool hasBaseShortConditions = + cBar.IsBearish() && + hasBearishTrend && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) && + notHaveBullishPower && + isTicksBullishForShort; + + // + // LONGS ... + + // + bool hasLong1 = + // + hasBaseLongConditions && + // + // TODO: Implement Long Conditions ... + false + // + ; + if (hasLong1) + { + // + pushers++; + Add( + "LONG_1", + signallers // + ); + + // + // TODO: Implement SL/TP Calculation based on R2R ... + + // + // sl = 0; + type = POSITION_TYPE_BUY; + } + + // + // SHORTS ... + + // + bool hasShort1 = + // + hasBaseShortConditions && + // + // TODO: Implement Long Conditions ... + false + // + ; + if (hasShort1) + { + // + pushers++; + Add( + "SHORT_1", + signallers // + ); + + // + // TODO: Implement SL/TP Calculation based on R2R ... + + // + // sl = 0; + type = POSITION_TYPE_SELL; + } + + // + // Combine Signals ... + + // + hasLong = + // + hasLong1 || + // + // TODO: Attach other Conditions ... + false + // + ; + + // + hasShort = + // + hasShort1 || + // + // TODO: Attach other Conditions ... + false + // + ; + + // + result = hasLong || hasShort; + if (!result) + { + // + CheckImportantAreasValidation(); + + // + return result; + } + + // + DestroyImportantAreas(); + + // + // Retrieve Entry Price based on Position Type ... + entry = GetEntry(mSymbol, type); + + // + // Calculate TP and SL ... + // based on Strategy ... + // only when on of TP or SL Provides, using provided R2R ... + if ((tp <= 0 && sl > 0) || (tp > 0 && sl <= 0)) + { + // + CalculateTPSLByPrice( + sl, + tp, + type, + entry, + r2r // + ); + } + + // + // Prepare Signal ... + result = signal.Prepare( + mSymbol, + signallers[0], + mPeriod, + type, + mode, + entry, + volume, + sl, + tp // + ); + if (!result) + { + return result; + } + + // + signal.pushers = pushers; + + // + // Prepare and Normalize Signal for Execution in Strategy ... + result = PrepareSignal(signal); + if (!result) + { + return result; + } + + // + // Attach Strategy Lebel ... + signal.provider = X121SMCStrategyToken; + + // + return result; + } + + // + // Overrides ... + + // + // Customize Strategy Identifier ... + string GetTag() override + { + return X121SMCStrategyToken; + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Helpers Inputs and Classes Instance ... + + // + // Private ... + private: + // + // Props ... + + // + string mSymbol; // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ... + bool mForceDisabled; // Force Disabled ... + bool mAllowLong; // Allow Long Signals + bool mAllowShort; // Allow Short Signals + double mR2R; // Risk/Rewar Ratio ... + double mVolume; // Static Volume Per Trades ... + + // + MqlTick mLastTick; // Last Issued Tick ... + XBarTracker mBarTracker; // Strategy Time Tracker ... + + // + // Actions ... + + /** + * Reste Bar Tracker ... + */ + void ResetBarTracker() + { + mBarTracker.Clean(); + } + + /** + * Prepare and Normalize Signal for Execution in Strategy ... + * + * @param signal: XSignal instance ... + * + * @return ( bool ) + */ + bool PrepareSignal(XSignal &signal) + { + // + bool result = false; + + // + // Check Strategy Is Enables ... + result = !IsDisabled(); + if (!result) + { + return result; + } + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + bool isLong = IsLong(signal.type); + + // + // TODO: Implement Signal Preparation Mechanism here ... + + // + return result; + } + + // + // On X121 Signal Recieved Event Handler(s) ... + TOnXSignal mSignalEventHandlers[]; + + // + /** + * Notified Signal Event Handler(s) ... + * + * @param signal: XSignal instance ... + * @param conditions: XStrategyConditions instance ... + */ + void NotifyOnSignalEventHandlers( + XSignal &signal, + XStrategyConditions &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 // + ); + } + } + + /** + * Install all Helpers and Prepare all Configurations for required Indicators ... + */ + void PrepareRequirements() + { + // + mForceDisabled = false; + + // + support.Clean(); + supportTime = NULL; + isSupportTested = false; + + // + resistance.Clean(); + resistanceTime = NULL; + isResistanceTested = false; + + // + // Initialize Bar Tracker ... + // + // Initial Time Tracker ... + mBarTracker.Init( + mSymbol, + mPeriod // + ); + + // + SetAlertPrefix(GetTag()); + + // + // Prepare Default Inputs and Configure Indicator Helpers here ... + + // + } + + // + void FillConditionsImportantAreas(XStrategyConditions &conditions) + { + // + if (!conditions.IsValid()) + { + return; + } + + // + conditions.support = support; + conditions.resistance = resistance; + conditions.bullishOB = bullishOB; + conditions.bearishOB = bearishOB; + conditions.bullishFVG = bullishFVG; + conditions.bearishFVG = bearishFVG; + conditions.bullishTrend = bullishTrend; + conditions.bearishTrend = bearishTrend; + + // + conditions.bullishFVGUpper = bullishFVGUpper; + conditions.bullishFVGLower = bullishFVGLower; + conditions.bearishFVGUpper = bearishFVGUpper; + conditions.bearishFVGLower = bearishFVGLower; + + // + Copy( + bullishTrendSwingHighs, + conditions.bullishTrendSwingHighs, + true // + ); + + // + Copy( + bullishTrendSwingLows, + conditions.bullishTrendSwingLows, + true // + ); + + // + Copy( + bearishTrendSwingHighs, + conditions.bearishTrendSwingHighs, + true // + ); + + // + Copy( + bearishTrendSwingLows, + conditions.bearishTrendSwingLows, + true // + ); + } + + // + // Important Areas ... + + // + bool mDrawImportantAreas; // Draw Important ... + + // + XOHCL support; + XOHCL resistance; + XOHCL bullishOB; + XOHCL bearishOB; + + // + double bullishFVGUpper; + double bullishFVGLower; + XOHCL bullishFVG; + + // + double bearishFVGUpper; + double bearishFVGLower; + XOHCL bearishFVG; + + // + XOHCL bullishTrendSwingHighs[]; + XOHCL bullishTrendSwingLows[]; + XOHCL bullishTrend; + + // + XOHCL bearishTrendSwingHighs[]; + XOHCL bearishTrendSwingLows[]; + XOHCL bearishTrend; + + // + void DetectImportantAreas() + { + // // + // int zIndex = 0; + // int cIndex = zIndex + 1; + + // // + // // Last Bar ... + // XOHCL cBar; + // bool result = cBar.Init( + // mSymbol, + // mPeriod, + // cIndex // + // ); + // if (!result) + // { + // return; + // } + + // // + // // Analyzing Bar ... + // XOHCL aBar; + // if (IsValid(mAnalizePeriod)) + // { + // // + // result = aBar.Init( + // mSymbol, + // mAnalizePeriod, + // cIndex // + // ); + + // // + // if (!result) + // { + // return; + // } + // } + // else + // { + // aBar = cBar; + // } + + // // + // // Support nad Resistance ... + + // // + // // Check Support Exists or Find ... + // bool hasSupport = support.IsValid(); + // if (!hasSupport) + // { + // // + // hasSupport = + // // + // aBar.HasSupport(support) + // // + // ; + + // // + // if (hasSupport) + // { + // // + // if (mDrawImportantAreas) + // { + // // + // DrawSupport( + // support, + // ChartID() // + // ); + // } + + // // + // supportTime = aBar.time; + // } + // } + + // // + // // Check Resistance Exists or Find ... + // bool hasResistance = resistance.IsValid(); + // if (!hasResistance) + // { + // // + // hasResistance = + // // + // aBar.HasResistance(resistance) + // // + // ; + + // // + // if (hasResistance) + // { + // // + // if (mDrawImportantAreas) + // { + // // + // DrawResistance( + // resistance, + // ChartID() // + // ); + // } + + // // + // resistanceTime = aBar.time; + // } + // } + + // // + // // Order Blocks ... + + // // + // bool hasBullishOB = bullishOB.IsValid(); + // if (!hasBullishOB) + // { + // // + // hasBullishOB = + // // + // aBar.HasBullishOrderBlock(bullishOB) + // // + // ; + + // // + // if (hasBullishOB) + // { + // // + // if (mDrawImportantAreas) + // { + // // + // DrawBullishOrderBlock( + // bullishOB, + // ChartID() // + // ); + // } + + // // + // bullishOBTime = aBar.time; + // } + // } + + // // + // bool hasBearishOB = bearishOB.IsValid(); + // if (!hasBearishOB) + // { + // // + // hasBearishOB = + // // + // aBar.HasBearishOrderBlock(bearishOB) + // // + // ; + + // // + // if (hasBearishOB) + // { + // // + // if (mDrawImportantAreas) + // { + // // + // DrawBearishOrderBlock( + // bearishOB, + // ChartID() // + // ); + // } + + // // + // bearishOBTime = aBar.time; + // } + // } + + // // + // // FVG ... + + // // + // bool hasBullishFVG = bullishFVG.IsValid(); + // if (!hasBullishFVG) + // { + // // + // hasBullishFVG = + // // + // aBar.HasBullishFVG( + // bullishFVGUpper, + // bullishFVGLower // + // ) + // // + // ; + + // // + // if (hasBullishFVG) + // { + // // + // bullishFVG = aBar; + + // // + // if (mDrawImportantAreas) + // { + // // + // DrawBullishFVG( + // bullishFVG, + // bullishFVGUpper, + // bullishFVGLower, + // ChartID() // + // ); + // } + + // // + // bullishFVGTime = aBar.time; + // } + // } + + // // + // bool hasBearishFVG = bearishFVG.IsValid(); + // if (!hasBearishFVG) + // { + // // + // hasBearishFVG = + // // + // aBar.HasBearishFVG( + // bearishFVGUpper, + // bearishFVGLower // + // ) + // // + // ; + + // // + // if (hasBearishFVG) + // { + // // + // bearishFVG = aBar; + + // // + // if (mDrawImportantAreas) + // { + // // + // DrawBearishFVG( + // bearishFVG, + // bearishFVGUpper, + // bearishFVGLower, + // ChartID() // + // ); + // } + + // // + // bearishFVGTime = aBar.time; + // } + // } + + // // + // // TREND ... + + // // + // bool hasBullishTrend = bullishTrend.IsValid(); + // if (!hasBullishTrend) + // { + // // + // hasBullishTrend = aBar.HasBullishTrend( + // bullishTrendSwingHighs, + // bullishTrendSwingLows, + // false // + // ); + + // // + // if (hasBullishTrend) + // { + // // + // bullishTrend = aBar; + + // // + // if (mDrawImportantAreas) + // { + // // + // DrawBullishTrend( + // bullishTrend, + // bullishTrendSwingHighs, + // bullishTrendSwingLows, + // ChartID() // + // ); + // } + // } + // } + + // // + // bool hasBearishTrend = bearishTrend.IsValid(); + // if (!hasBearishTrend) + // { + // // + // hasBearishTrend = aBar.HasBearishTrend( + // bearishTrendSwingHighs, + // bearishTrendSwingLows, + // false // + // ); + + // // + // if (hasBearishTrend) + // { + // // + // bearishTrend = aBar; + + // // + // if (mDrawImportantAreas) + // { + // // + // DrawBearishTrend( + // bearishTrend, + // bearishTrendSwingHighs, + // bearishTrendSwingLows, + // ChartID() // + // ); + // } + // } + // } + + // + } + + // + void DestroyImportantAreas() + { + // + bool hasSupport = support.IsValid(); + if (hasSupport) + { + // + supportTime = NULL; + isSupportTested = false; + RemoveSupport(support); + support.Clean(); + } + + // + bool hasResistance = resistance.IsValid(); + if (hasResistance) + { + // + resistanceTime = NULL; + isResistanceTested = false; + RemoveResistance(resistance); + resistance.Clean(); + } + + // + bool hasBullishOB = bullishOB.IsValid(); + if (hasBullishOB) + { + // + bullishOBTime = NULL; + RemoveBullishOrderBlock(bullishOB); + bullishOB.Clean(); + } + + // + bool hasBearishOB = bearishOB.IsValid(); + if (hasBearishOB) + { + // + bearishOBTime = NULL; + RemoveBearishOrderBlock(bearishOB); + bearishOB.Clean(); + } + + // + bool hasBullishFVG = bullishFVG.IsValid(); + if (hasBullishFVG) + { + // + bullishFVGUpper = 0; + bullishFVGLower = 0; + bullishFVGTime = NULL; + RemoveBullishFVG(bullishFVG); + bullishFVG.Clean(); + } + + // + bool hasBearishFVG = bearishFVG.IsValid(); + if (hasBearishFVG) + { + // + bearishFVGUpper = 0; + bearishFVGLower = 0; + bearishFVGTime = NULL; + RemoveBullishFVG(bearishFVG); + bearishFVG.Clean(); + } + + // + bool hasBullishTrend = bullishTrend.IsValid(); + if (hasBullishTrend) + { + // + RemoveBullishTrend(bullishTrend); + bullishTrend.Clean(); + } + + // + bool hasBearishTrend = bearishTrend.IsValid(); + if (hasBearishTrend) + { + // + RemoveBearishTrend(bearishTrend); + bearishTrend.Clean(); + } + } + + // + void CheckImportantAreasValidation() + { + // + CheckSupportValidation(); + CheckResistanceValidation(); + + // + CheckBullishOBValidation(); + CheckBearishOBValidation(); + + // + CheckBullishFVGValidation(); + CheckBearishFVgValidation(); + + // + CheckBullishTrendValidation(); + CheckBearishTrendValidation(); + } + + // + bool isSupportTested; + datetime supportTime; + void CheckSupportValidation() + { + // + if (!isSupportTested) + { + // + if (support.IsValid() && IsValid(supportTime)) + { + // + int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(supportTime))) / PeriodSeconds(mPeriod)); + if (age >= 50) + { + // + isSupportTested = false; + supportTime = NULL; + RemoveSupport(support); + support.Clean(); + } + } + return; + } + + // + XOHCL cBar; + bool isInited = cBar.Init( + mSymbol, + mPeriod, + 1 // + ); + if (!isInited) + { + return; + } + + // + double points = GetPoints(mSymbol); + + // + // Find Price Distance ... + double highDiff = MathAbs(cBar.high - support.high); + double lowDiff = MathAbs(cBar.low - support.high); + + // + bool isBreaked = MathMax(highDiff, lowDiff) >= 100 * points; + if (!isBreaked) + { + return; + } + + // + isSupportTested = false; + RemoveSupport(support); + supportTime = NULL; + support.Clean(); + } + + // + bool isResistanceTested; + datetime resistanceTime; + void CheckResistanceValidation() + { + // + if (!isResistanceTested) + { + // + if (resistance.IsValid() && IsValid(resistanceTime)) + { + // + int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(resistanceTime))) / PeriodSeconds(mPeriod)); + if (age >= 50) + { + // + isResistanceTested = false; + resistanceTime = NULL; + RemoveResistance(resistance); + resistance.Clean(); + } + } + return; + } + + // + XOHCL cBar; + bool isInited = cBar.Init( + mSymbol, + mPeriod, + 1 // + ); + if (!isInited) + { + return; + } + + // + double points = GetPoints(mSymbol); + + // + // Find Price Distance ... + double highDiff = MathAbs(cBar.high - resistance.low); + double lowDiff = MathAbs(cBar.low - resistance.low); + + // + bool isBreaked = MathMax(highDiff, lowDiff) >= 100 * points; + if (!isBreaked) + { + return; + } + + // + isResistanceTested = false; + RemoveResistance(resistance); + resistanceTime = NULL; + resistance.Clean(); + } + + // + datetime bullishOBTime; + void CheckBullishOBValidation() + { + // + if (!IsValid(bullishOBTime)) + { + return; + } + + // + int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bullishOBTime))) / PeriodSeconds(mPeriod)); + if (age >= 50) + { + // + bullishOBTime = NULL; + RemoveBullishOrderBlock(bullishOB); + bullishOB.Clean(); + } + } + + // + datetime bearishOBTime; + void CheckBearishOBValidation() + { + // + if (!IsValid(bearishOBTime)) + { + return; + } + + // + int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bearishOBTime))) / PeriodSeconds(mPeriod)); + if (age >= 50) + { + // + bearishOBTime = NULL; + RemoveBearishOrderBlock(bearishOB); + bearishOB.Clean(); + } + } + + // + datetime bullishFVGTime; + void CheckBullishFVGValidation() + { + // + if (!IsValid(bullishFVGTime)) + { + return; + } + + // + int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bullishFVGTime))) / PeriodSeconds(mPeriod)); + if (age >= 50) + { + // + bullishFVGTime = NULL; + RemoveBullishFVG(bullishFVG); + bullishFVG.Clean(); + } + } + + // + datetime bearishFVGTime; + void CheckBearishFVgValidation() + { + // + if (!IsValid(bearishFVGTime)) + { + return; + } + + // + int age = (int)(((int)(TimeToSeconds(TimeCurrent()) - TimeToSeconds(bearishFVGTime))) / PeriodSeconds(mPeriod)); + if (age >= 50) + { + // + bearishFVGTime = NULL; + RemoveBearishFVG(bearishFVG); + bearishFVG.Clean(); + } + } + + // + void CheckBullishTrendValidation() + { + // + // TODO: Complete this ... + } + + // + void CheckBearishTrendValidation() + { + // + // TODO: Complete this ... + } + + // +}; + +// \ No newline at end of file