/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XSCBaseStrategy // 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 "../Libraries/x-saherelm.tools.lib.mq5" #include "../Classes/x-saherelm.xtrade.class.mq5" #include "../Classes/x-saherelm.xalert.class.mq5" // // Definitions ... // class XSCBaseStrategy : public XSCBaseAlert { // // Public ... public: // // Constructors ... void XSCBaseStrategy( string _symbol, // Trading Symbol ENUM_TIMEFRAMES _period, // Trading TimeFrame ENUM_TIMEFRAMES _analizePeriod, // Important Area Detect Time Frame double _volume, // Voluem double _r2r, // Risk/Reward Ratio int _slippage, // Trader Slippage long _magicNumber, // Trader Magic Number bool _ignoreSignalExecution = false, // Ignore Signal Execution bool _useTPSLAsPoint = false, // Converts TP and SL by Provided Points bool _forceMaxTPSLAsPoint = false, // Force Max TP and SL by Provided Points double _tpPoint = 0, // TP As Point double _slPoint = 0, // SL As Point bool _ignoreTP = false, // TP set to 0 bool _ignoreSL = false, // SL set to 0 bool _allowLong = true, bool _allowShort = true, int _maxAllowedLongs = 0, int _maxAllowedShorts = 0 // ) { // // Fill Properties ... mR2R = _r2r; mVolume = _volume; mSymbol = _symbol; mPeriod = _period; mTPPoint = _tpPoint; mSLPoint = _slPoint; mIgnoreTP = _ignoreTP; mIgnoreSL = _ignoreSL; mSlippage = _slippage; mAllowLong = _allowLong; mAllowShort = _allowShort; mMagicNumber = _magicNumber; mAnalizePeriod = _analizePeriod; mUseTPSLAsPoint = _useTPSLAsPoint; mMaxAllowedLongs = _maxAllowedLongs; mMaxAllowedShorts = _maxAllowedShorts; mForceMaxTPSLAsPoint = _forceMaxTPSLAsPoint; mIgnoreSignalExecution = _ignoreSignalExecution; // mForceDisabled = false; // // Initial Trader Class Instance ... trader = new XSCTrade( mSlippage, mMagicNumber // ); // // Initial Time Tracker ... barTracker.Init( mSymbol, mPeriod // ); // SetAlertPrefix(GetTag()); } // // Deconstructor ... void ~XSCBaseStrategy() { // delete trader; // Reset(); } // // Getter and Setter (s) ... // int Slippage() { return mSlippage; } // long MagicNumber() { return mMagicNumber; } // string Symbol() { return mSymbol; } // ENUM_TIMEFRAMES Period() { return mPeriod; } // bool IsDisabled() { return mForceDisabled; } // void Disable() { mForceDisabled = true; } // void Enable() { mForceDisabled = false; } // double Volume() { return mVolume; } // void Volume(double value) { // if (value < 0.01) { value = 0.01; } // mVolume = value; } // double R2R() { return mR2R; } // bool AllowLong() { return mAllowLong; } // void AllowLong(bool value) { mAllowLong = value; } // bool AllowShort() { return mAllowShort; } // void AllowShort(bool value) { mAllowShort = value; } // int MaxAllowedLongs() { return mMaxAllowedLongs; } // void MaxAllowedLongs(int value) { // if (value < 0) { value = 0; } // mMaxAllowedLongs = value; } // int MaxAllowedShorts() { return mMaxAllowedShorts; } // void MaxAllowedShorts(int value) { // if (value < 0) { value = 0; } // mMaxAllowedShorts = value; } // int RequiredPivots() { return mRequiredPivots; } // void RequiredPivots(int value) { // if (value < 3) { value = 3; } // mRequiredPivots = value; } // int RequiredShoulders() { return mRequiredShoulders; } // void RequiredShoulders(int value) { // if (value < 5) { value = 5; } // mRequiredShoulders = value; } // bool UseTPSLAsPoint() { return mUseTPSLAsPoint; } // void UseTPSLAsPoint(bool value) { mUseTPSLAsPoint = value; } // bool ForceMaxTPSLAsPoint() { return mForceMaxTPSLAsPoint; } // void ForceMaxTPSLAsPoint(bool value) { mForceMaxTPSLAsPoint = value; } // double TPPoint() { return mTPPoint; } // void TPPoint(double value) { // if (value < 0) { value = 0; } // mTPPoint = value; } // double SLPoint() { return mSLPoint; } // void SLPoint(double value) { // if (value < 0) { value = 0; } // mSLPoint = value; } // bool IgnoreTP() { return mIgnoreTP; } // void IgnoreTP(bool value) { mIgnoreTP = value; } // bool IgnoreSL() { return mIgnoreSL; } // void IgnoreSL(bool value) { mIgnoreSL = value; } // bool IgnoreSignalExecution() { return mIgnoreSignalExecution; } // void IgnoreSignalExecution(bool value) { mIgnoreSignalExecution = value; } // // On Signal Handlers ... void AddSignalEventHandler(TOnSignal handler) { // Add( handler, mOnSignalEventHandlers // ); } // ENUM_TIMEFRAMES AnalizePeriod() { return mAnalizePeriod; } // void AnalizePeriod(ENUM_TIMEFRAMES value) { mAnalizePeriod = value; } // bool DrawImportantAreas() { return mDrawImportantAreas; } // void DrawImportantAreas(bool value) { mDrawImportantAreas = value; } // // Important Areas Getters ... // bool GetSupport( XOHCL &bar // ) { // bool result = false; // bar.Clean(); // result = support.IsValid(); if (result) { bar = support; } // return result; } // bool GetResistance( XOHCL &bar // ) { // bool result = false; // bar.Clean(); // result = resistance.IsValid(); if (result) { bar = resistance; } // return result; } // bool GetBullishOB( XOHCL &bar // ) { // bool result = false; // bar.Clean(); // result = bullishOB.IsValid(); if (result) { bar = bullishOB; } // return result; } // bool GetBearishOB( XOHCL &bar // ) { // bool result = false; // bar.Clean(); // result = bearishOB.IsValid(); if (result) { bar = bearishOB; } // return result; } // bool GetBullishFVG( XOHCL &bar, double upper, double lower // ) { // bool result = false; // upper = 0; lower = 0; bar.Clean(); // result = bullishFVG.IsValid(); if (result) { // bar = bullishFVG; upper = bullishFVGUpper; lower = bullishFVGLower; } // return result; } // bool GetBearishFVG( XOHCL &bar, double upper, double lower // ) { // bool result = false; // upper = 0; lower = 0; bar.Clean(); // result = bearishFVG.IsValid(); if (result) { // bar = bearishFVG; upper = bearishFVGUpper; lower = bearishFVGLower; } // return result; } // bool GetBullishTrend( XOHCL &bar, XOHCL &swingHighs[], XOHCL &swingLows[] // ) { // bool result = false; // bar.Clean(); Clean(swingHighs); Clean(swingLows); // result = bullishTrend.IsValid(); if (result) { // bar = bullishTrend; // Copy( bullishTrendSwingHighs, swingHighs // ); Copy( bullishTrendSwingLows, swingLows // ); } // return result; } // bool GetBearishTrend( XOHCL &bar, XOHCL &swingHighs[], XOHCL &swingLows[] // ) { // bool result = false; // bar.Clean(); Clean(swingHighs); Clean(swingLows); // result = bearishTrend.IsValid(); if (result) { // bar = bearishTrend; // Copy( bearishTrendSwingHighs, swingHighs // ); Copy( bearishTrendSwingLows, swingLows // ); } // return result; } // // Virtual Methods ... // // Tag ... virtual string GetTag() { return "XBaseStrategy"; } // // Check Conditions for Signal ... // this must be Override based on each Strategy ... virtual bool HasSignal( XSignal &signal // ) { return false; } // // Check Conditions For Signal and Execute Signal ... virtual void HandleTick() { // if (IsDisabled()) { return; } // if (!AllowLong() && !AllowShort()) { return; } // if (!barTracker.CanProcessBar()) { return; } // MqlTick cTick; bool hasTick = GetTick( mSymbol, cTick // ); bool isSameAsLast = cTick.time == lastTick.time; if (isSameAsLast) { return; } // lastTick = cTick; // XSignal signal; bool hasSignal = HasSignal(signal); if (!hasSignal) { return; } // barTracker.Waits(); // Execute(signal); } // // Handle Signal Execution ... virtual bool Execute(XSignal &signal) { // bool result = false; // result = !IsDisabled(); if (!result) { return result; } // result = signal.IsValid(); if (!result) { return result; } // bool isLong = IsLong(signal.type); // result = // isLong ? AllowLong() : AllowShort() // ; if (!result) { return result; } // // Check Max Allowed Trades Limitation ... if ( (isLong && MaxAllowedLongs() > 0) || (!isLong && MaxAllowedShorts() > 0)) { // // Here We Have to Count Positions ... // // Get and Count Positions ... XPosition positions[]; int positionsCount = trader.GetPositions( positions // ); // // Get and Count Lng and Short Positions ... XPosition longs[]; XPosition shorts[]; ExtractPositions( positions, longs, shorts // ); int longsCount = ArraySize(longs); int shortsCount = ArraySize(shorts); // result = // isLong ? longsCount < MaxAllowedLongs() : shortsCount < MaxAllowedShorts() // ; if (!result) { return result; } } // // Check TP and SL ... double points = GetPoints(signal.symbol); if (mUseTPSLAsPoint) { // double sl = 0; double tp = 0; bool isCalculated = !(mSLPoint > 0 || mTPPoint > 0) ? false : CalculateTPSLByPoint( sl, tp, signal.type, signal.entry, points, mR2R, mSLPoint, mTPPoint // ); if (isCalculated) { // signal.sl = sl; signal.tp = tp; } } else if (mForceMaxTPSLAsPoint) { // if (mSLPoint > 0) { // double risk = signal.GetRisk(); double riskPoints = risk / points; // if (riskPoints > mSLPoint) { // signal.sl = isLong ? signal.entry - (mSLPoint * points) : signal.entry + (mSLPoint * points); } } // if (mTPPoint > 0) { // double reward = signal.GetReward(); double rewardPoints = reward / points; // if (rewardPoints > mTPPoint) { // signal.tp = isLong ? signal.entry + (mTPPoint * points) : signal.entry - (mTPPoint * points); } } } // if (mIgnoreTP) { signal.tp = 0; } // if (mIgnoreSL) { signal.sl = 0; } // // Notify Signal Event Handler(s) ... NotifyOnSignalEventHandlers(signal); // // Check Signal Execution Enabled or not ... result = !mIgnoreSignalExecution; if (!result) { return result; } // ENUM_X_SIGNAL_EXECUTION_RESULT state; result = trader.ExecuteSignal( signal, state // ); if (result) { // string message = "Execute " + (isLong ? "Long" : "Short") + " " + signal.symbol + "/" + ToString(signal.period) + " ..."; Alert(message); // OnSignalExecuted(signal); } else { OnSignalExecutionFailed(signal, state); } // return result; } // // Calls When a Signal Executed Successfully ... virtual void OnSignalExecuted(XSignal &signal) { } // // Calls When a Signal Execution Failed ... virtual void OnSignalExecutionFailed( XSignal &signal, ENUM_X_SIGNAL_EXECUTION_RESULT result // ) { } // // Protected ... protected: // int mSlippage; // Trader Slippage long mMagicNumber; // Trader Magic Number bool mForceDisabled; // Force Disabled bool mAllowLong; // Allow Long Signals bool mAllowShort; // Allow Short Signals int mMaxAllowedLongs; // Max Allowed Longs int mMaxAllowedShorts; // Max Allowed Shorts // bool mUseTPSLAsPoint; // Converts TP and SL by Provided Points bool mForceMaxTPSLAsPoint; // Force Max TP and SL by Provided Points double mTPPoint; // TP As Point double mSLPoint; // SL As Point bool mIgnoreTP; // TP set to 0 bool mIgnoreSL; // SL set to 0 bool mIgnoreSignalExecution; // Ignore Signal Execution // string mSymbol; // Trading Symbol ... ENUM_TIMEFRAMES mPeriod; // Trading TimeFrame ... // double mR2R; // Risk/Rewar Ratio ... double mVolume; // Static Volume Per Trades ... // XBarTracker barTracker; // Strategy Time Tracker ... // // Trend Detecting ... int mRequiredPivots; // Required Pivots For Trend Detecting ... int mRequiredShoulders; // Required Pivots Shoulders ... // XSCTrade *trader; // MqlTick lastTick; // void Reset() { barTracker.Clean(); } // // Notified Signal Event Handler(s) ... void NotifyOnSignalEventHandlers(XSignal &signal) { // if (!signal.IsValid()) { return; } // int count = ArraySize(mOnSignalEventHandlers); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { mOnSignalEventHandlers[i](signal); } } // ENUM_TIMEFRAMES mAnalizePeriod; // Important Area Detect Time Frame bool mDrawImportantAreas; // Draw Important Areas where Founded in Analyzing Time Frame // 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 ... } // // Private ... private: // // Props ... // // On Signal Recieved Event Handler(s) ... TOnSignal mOnSignalEventHandlers[]; }; //