diff --git a/Classes/x-saherelm.x-chart-objects.class.mq5 b/Classes/x-saherelm.x-chart-objects.class.mq5 index 398dd25e..dfc64384 100644 --- a/Classes/x-saherelm.x-chart-objects.class.mq5 +++ b/Classes/x-saherelm.x-chart-objects.class.mq5 @@ -41,6 +41,7 @@ enum ENUM_XCHARTOBJECTS X_BAR_ARROW_OBJ = 7862, // X_SIGNAL_OBJ = 8860, + X_TREND_OBJ = 8861, // // Structured ... X_TRADE_DAY_OBJ = 9860, @@ -1941,3 +1942,214 @@ class XCBearishFVGObject : public XCZoneObject }; // + +// +// XTrend ... +class XCTrendObject : public XCBaseObject +{ + // + public: + // + + // + // Constructor ... + void XCTrendObject() + { + } + + // + // Deconstructor ... + void ~XCTrendObject() + { + // + Clean(mSwingLows); + Clean(mSwingHighs); + + // + mTrend.Delete(); + } + + bool CreateByTrend( + long chart_id, + const int window, + XTrend &trend // + ) + { + // + bool result = false; + + // + result = trend.IsValid(); + if (!result) + { + return result; + } + + // + string name = trend.GetTag(); + string nameHash = ToMD5(name); + + // + int swingLowsCount = ArraySize(trend.swingLows); + int swingHighsCount = ArraySize(trend.swingHighs); + + // + double price1 = 0; + double price2 = 0; + datetime from = NULL; + if (trend.isBullish) + { + // + from = trend.swingLows[0].time; + price1 = trend.swingLows[0].GetDown(); + price2 = trend.swingLows[swingLowsCount - 1].GetDown(); + } + else + { + // + from = trend.swingHighs[0].time; + price1 = trend.swingHighs[0].GetUp(); + price2 = trend.swingHighs[swingHighsCount - 1].GetUp(); + } + + // + string trendName = name; + result = mTrend.Create( + chart_id, + trendName, + window, + from, + price1, + trend.at, + price2 // + ); + if (!result) + { + return result; + } + + // + mTrend.Width(1); + color clrTrend = trend.isBullish + ? clrAqua + : trend.isBearish + ? clrMagenta + : clrGray; + mTrend.Color(clrTrend); + mTrend.Style(STYLE_SOLID); + + // + int arrowCode = 108; + if (trend.isBullish) + { + // + for (int i = 0; i < swingLowsCount; i++) + { + // + XOHCL iBar = trend.swingLows[i]; + + // + string iName = "XSPL_" + nameHash; + + // + XCSwingLowObject iObj; + result = iObj.CreateBySwing( + chart_id, + iName, + window, + iBar, + arrowCode // + ); + if (!result) + { + break; + } + + // + iObj.ArrowWidth(5); + iObj.ArrowColor(clrAqua); + iObj.ArrowAnchor(ANCHOR_TOP); + + // + AddRef( + iObj, + mSwingLows // + ); + } + } + else if (trend.isBearish) + { + // + for (int i = 0; i < swingHighsCount; i++) + { + // + XOHCL iBar = trend.swingHighs[i]; + + // + string iName = "XSPH_" + nameHash; + + // + XCSwingHighObject iObj; + result = iObj.CreateBySwing( + chart_id, + iName, + window, + iBar, + arrowCode // + ); + if (!result) + { + break; + } + + // + iObj.ArrowWidth(5); + iObj.ArrowColor(clrMagenta); + iObj.ArrowAnchor(ANCHOR_BOTTOM); + + // + AddRef( + iObj, + mSwingHighs // + ); + } + } + + // + if (result) + { + ObjName(name); + } + else + { + // + mTrend.Delete(); + Clean(mSwingLows); + Clean(mSwingHighs); + } + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual ENUM_XCHARTOBJECTS Type() + { + return X_TREND_OBJ; + } + + // + private: + // + CChartObjectTrend mTrend; + XCSwingLowObject mSwingLows[]; + XCSwingHighObject mSwingHighs[]; + + // +}; + +// diff --git a/Classes/x-saherelm.xexpert.class.mq5 b/Classes/x-saherelm.xexpert.class.mq5 index 3a7bef9e..652e9e62 100644 --- a/Classes/x-saherelm.xexpert.class.mq5 +++ b/Classes/x-saherelm.xexpert.class.mq5 @@ -731,6 +731,25 @@ class XCBaseExpert : public XSCBaseAlert { } + // + // Time Handlers ... + + virtual void HandleOnNewMonth() + { + } + + virtual void HandleOnNewWeek() + { + } + + virtual void HandleOnNewDay() + { + } + + virtual void HandleOnNewHour() + { + } + /** * Generate Identifier Tag ... * @@ -798,50 +817,74 @@ class XCBaseExpert : public XSCBaseAlert { // // Monthly Report .... - if (mReportNewMonths && - mTimeTracker.IsNewMonth()) + if (mTimeTracker.IsNewMonth()) { // - string msg = "New Month ..."; + HandleOnNewMonth(); // - Alert(msg); + if (mReportNewMonths) + { + // + string msg = "New Month ..."; + + // + Alert(msg); + } } // // Weekly Report .... - if (mReportNewWeeks && - mTimeTracker.IsNewWeek()) + if (mTimeTracker.IsNewWeek()) { // - string msg = "New Week ..."; + HandleOnNewWeek(); // - Alert(msg); + if (mReportNewWeeks) + { + // + string msg = "New Week ..."; + + // + Alert(msg); + } } // // Daily Report .... - if (mReportNewDays && - mTimeTracker.IsNewDay()) + if (mTimeTracker.IsNewDay()) { // - string msg = "New Day ..."; + HandleOnNewDay(); // - Alert(msg); + if (mReportNewDays) + { + // + string msg = "New Day ..."; + + // + Alert(msg); + } } // // Hourly Report .... - if (mReportNewHours && - mTimeTracker.IsNewHour()) + if (mTimeTracker.IsNewHour()) { // - string msg = "New Hour ..."; + HandleOnNewHour(); // - Alert(msg); + if (mReportNewHours) + { + // + string msg = "New Hour ..."; + + // + Alert(msg); + } } } diff --git a/Documents/BKP/121.smc.strategy.tmp.mq5 b/Documents/BKP/121.smc.strategy.tmp.mq5 index 26e37223..29b6f68f 100644 --- a/Documents/BKP/121.smc.strategy.tmp.mq5 +++ b/Documents/BKP/121.smc.strategy.tmp.mq5 @@ -1129,3 +1129,119 @@ // result = isConditionReadyForDemand || isConditionReadyForSupply; + +////////////////////////////////////////////////////////////////// + + + // + // Detect Trend ... + // // + // bool d1HasBullishTrend = HasBullishTrend(_1DState); + // bool d1HasBearishTrend = HasBearishTrend(_1DState); + + // // + // bool h4HasBullishTrend = HasBullishTrend(_4HState); + // bool h4HasBearishTrend = HasBearishTrend(_4HState); + + // // + // bool m15HasBullishTrend = HasBullishTrend(_15MState); + // bool m15HasBearishTrend = HasBearishTrend(_15MState); + + // // + // bool m5HasBullishTrend = HasBullishTrend(_5MState); + // bool m5HasBearishTrend = HasBearishTrend(_5MState); + + // // + // bool m1HasBullishTrend = HasBullishTrend(_1MState); + // bool m1HasBearishTrend = HasBearishTrend(_1MState); + + // // + // bool isBullishTrendValid = m15HasBullishTrend && + // m5HasBullishTrend; + // // + // bool isBearishTrendValid = m15HasBearishTrend && + // m5HasBearishTrend; + + // // + // if (isBullishTrendValid) + // { + // Print("isBullishTrendValid"); + // } + + // // + // if (isBearishTrendValid) + // { + // Print("isBearishTrendValid"); + // } + + // // + // XOHCL tmpSWH[]; + // XOHCL tmpSWL[]; + + // // + // XOHCL m15Bar; + // result = m15Bar.Init( + // _symbol, + // PERIOD_M15, + // cIndex // + // ); + // if (!result) + // { + // return result; + // } + // bool m15HasBullishTrend = + // m15Bar.HasBullishTrend( + // tmpSWH, + // tmpSWL, + // true // + // ); + // bool m15HasBearishTrend = + // m15Bar.HasBearishTrend( + // tmpSWH, + // tmpSWL, + // true // + // ); + + // // + // XOHCL m5Bar; + // result = m5Bar.Init( + // _symbol, + // PERIOD_M5, + // cIndex // + // ); + // if (!result) + // { + // return result; + // } + // bool m5HasBullishTrend = + // m5Bar.HasBullishTrend( + // tmpSWH, + // tmpSWL // + // ); + // bool m5HasBearishTrend = + // m5Bar.HasBearishTrend( + // tmpSWH, + // tmpSWL // + // ); + + // // + // bool hasBullishTrend = + // m15HasBullishTrend && + // m5HasBullishTrend; + + // // + // bool hasBearishTrend = + // m15HasBearishTrend && + // m5HasBearishTrend; + + // // + // if (hasBullishTrend) + // { + // Print("hasBullishTrend"); + // } + + // // + // if (hasBearishTrend) + // { + // Print("hasBearishTrend"); + // } diff --git a/Documents/BKP/x-121.smc.test.strategy.class copy 2.mq5 b/Documents/BKP/x-121.smc.test.strategy.class copy 2.mq5 new file mode 100644 index 00000000..f5d5afd2 Binary files /dev/null and b/Documents/BKP/x-121.smc.test.strategy.class copy 2.mq5 differ diff --git a/Documents/BKP/x-121.smc.test.strategy.class copy.mq5 b/Documents/BKP/x-121.smc.test.strategy.class copy.mq5 new file mode 100644 index 00000000..8d97ebf9 Binary files /dev/null and b/Documents/BKP/x-121.smc.test.strategy.class copy.mq5 differ diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index a1673603..e4305224 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -36,6 +36,15 @@ enum ENUM_X_PRICE X_PRICE_LOW }; +// +enum ENUM_X_DIRECTION +{ + X_DIRECTION_ALL, + X_DIRECTION_NONE, + X_DIRECTION_BULLISH, + X_DIRECTION_BEARISH, +}; + // // Swing Types Enum ... enum ENUM_X_SWING_TYPE @@ -5038,6 +5047,219 @@ struct XOHCL } }; +struct XTrend +{ + // + string symbol; + ENUM_TIMEFRAMES period; + + // + datetime at; + + // + XOHCL swingHighs[]; + XOHCL swingLows[]; + + // + bool isBullish; + bool isBearish; + + // + void XTrend() + { + Clean(); + } + + // + // Tools ... + + /** + * Initialize ... + * + * @param _symbol: String ... + * @param _period: ENUM_TIMEFRAMES member ... + * + * @return ( bool ) + */ + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period = NULL // + ) + { + // + bool result = false; + + // + NormalizePeriod(_period); + + // + result = IsValid(_symbol) && + IsValid(_period); + if (!result) + { + return result; + } + + // + symbol = _symbol; + period = _period; + + // + XOHCL bar; + result = bar.Init( + symbol, + period, + 0 // + ); + if (!result) + { + return result; + } + + // + XOHCL tmpBULLSWH[]; + XOHCL tmpBULLSWL[]; + bool hasBullishTrend = bar.HasBullishTrend( + tmpBULLSWH, + tmpBULLSWL, + true // + ); + + // + XOHCL tmpBEARSWH[]; + XOHCL tmpBEARSWL[]; + bool hasBearishTrend = bar.HasBearishTrend( + tmpBEARSWH, + tmpBEARSWL, + true // + ); + + // + if (hasBullishTrend) + { + // + Copy( + tmpBULLSWH, + swingHighs // + ); + + // + Copy( + tmpBULLSWL, + swingLows // + ); + } + // + else if (hasBearishTrend) + { + // + Copy( + tmpBEARSWH, + swingHighs // + ); + + // + Copy( + tmpBEARSWL, + swingLows // + ); + } + + // + if (hasBullishTrend || + hasBullishTrend) + { + at = TimeCurrent(); + } + + // + result = IsValid(); + + // + return result; + } + + /** + * Clean ... + */ + void Clean() + { + // + symbol = NULL; + period = NULL; + at = NULL; + + // + isBullish = false; + isBearish = false; + + // + Clean(swingLows); + Clean(swingHighs); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + IsValid(symbol) && + IsValid(period) && + IsValid(at) && + (isBullish || + isBearish) && + (ArraySize(swingHighs) > 0 || + ArraySize(swingLows) > 0); + + // + return result; + } + + /** + * Generate Unique Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + string hash = symbol + "," + ToString(period) + "," + ToFormatString(at); + hash = ToMD5(hash); + + // + result = + // + "XTrend_" + + (isBullish ? "Bullish_" : "Bearish_") + + symbol + "_" + + ToString(period) + "_" + + hash + // + ; + + // + return result; + } + + // +}; + // // Tracking Times ... struct XTimeTracker @@ -8660,6 +8882,32 @@ MqlDateTime MilliSecondsToStruct( return result; } +// +// Converts Hours to Seconds ... +int HoursToSeconds(int value) +{ + // + int result = 0; + + // + if (value < 0) + { + value = 0; + } + + // + if (value == 0) + { + return result; + } + + // + result = value * 60 * 60; + + // + return result; +} + // // Retrieve DateTime Structure ... MqlDateTime GetCurrentTime() @@ -12971,4 +13219,33 @@ int GetCycleLengthOn( return result; } +// +// Direction ... + +// +bool IsBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} + +// +bool IsBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} + // \ No newline at end of file diff --git a/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 b/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 index ff9ae218..ae8c2818 100644 --- a/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 +++ b/X121SMCEA/Classes/x-121.smc.base.strategy.class.mq5 @@ -535,6 +535,11 @@ class XCX121SMCBaseStrategy : public XSCBaseAlert return result; } + // + bool useSwings = true; + bool useMomentumBars = true; + bool useRejectionBars = true; + // Clean(candidates); @@ -547,27 +552,39 @@ class XCX121SMCBaseStrategy : public XSCBaseAlert // // Swing Lows ... - Copy( - conditions.swingLows, - candidateBars, - false // - ); + if (useSwings) + { + // + Copy( + conditions.swingLows, + candidateBars, + false // + ); + } // // Bullish Momentum Bars ... - Copy( - conditions.bullishMomentumBars, - candidateBars, - false // - ); + if (useMomentumBars) + { + // + Copy( + conditions.bullishMomentumBars, + candidateBars, + false // + ); + } // // Bullish Rejection Bars ... - Copy( - conditions.bullishRejectionBars, - candidateBars, - false // - ); + if (useRejectionBars) + { + // + Copy( + conditions.bullishRejectionBars, + candidateBars, + false // + ); + } // int count = ArraySize(candidateBars); @@ -598,27 +615,39 @@ class XCX121SMCBaseStrategy : public XSCBaseAlert // // Swing Highs ... - Copy( - conditions.swingHighs, - candidateBars, - false // - ); + if (useSwings) + { + // + Copy( + conditions.swingHighs, + candidateBars, + false // + ); + } // // Bearish Momentum Bars ... - Copy( - conditions.bearishMomentumBars, - candidateBars, - false // - ); + if (useMomentumBars) + { + // + Copy( + conditions.bearishMomentumBars, + candidateBars, + false // + ); + } // // Bearish Rejection Bars ... - Copy( - conditions.bearishRejectionBars, - candidateBars, - false // - ); + if (useRejectionBars) + { + // + Copy( + conditions.bearishRejectionBars, + candidateBars, + false // + ); + } // int count = ArraySize(candidateBars); diff --git a/X121SMCEA/Classes/x-121.smc.xtradehandler.class.mq5 b/X121SMCEA/Classes/x-121.smc.xtradehandler.class.mq5 index c4d2e1c4..0907a488 100644 --- a/X121SMCEA/Classes/x-121.smc.xtradehandler.class.mq5 +++ b/X121SMCEA/Classes/x-121.smc.xtradehandler.class.mq5 @@ -437,7 +437,7 @@ struct X121SMCTradeData struct X121SMCProtectedPosition { // - XPosition main; // Main Position ... + XPosition main; // Main Position ... X121SMCTradeData data; // Trade Handler Data ... // @@ -495,6 +495,191 @@ struct X121SMCProtectedPosition } }; +// +struct X121SMCSymbolPositionInfo +{ + // + string symbol; + + // + datetime enableAt; + + // + int longSLs; + int longTPs; + + // + int shortSLs; + int shortTPs; + + // + int countedSLs; + + // + void X121SMCSymbolPositionInfo() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + longSLs = 0; + longTPs = 0; + + // + shortSLs = 0; + shortTPs = 0; + + // + countedSLs = 0; + + // + enableAt = NULL; + } + + /** + * Check is own Symbol Info ... + * + * @param _symbol: String ... + * + * @return ( bool ) + */ + bool IsOwn(string _symbol) + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + _symbol == symbol + // + ; + + // + return result; + } + + /** + * Check Symbol Trading is Enable or not ... + * + * @param time: DateTime ... + * + * @return ( bool ) + */ + bool IsEnable(datetime time = NULL) + { + // + bool result = false; + + // + time = NormalizeTime(time); + + // + bool isEnableAtValid = IsValid(enableAt); + + // + result = + !isEnableAtValid + ? true + : time > enableAt; + if (result && + isEnableAtValid) + { + Reset(); + } + + // + return result; + } + + /** + * Pause Symbol Trading ... + * + * @param seconds: Integer ... + */ + void Pause(int seconds) + { + // + if (seconds <= 0) + { + return; + } + + // + datetime _enableAt = ((datetime)((int)TimeCurrent() + seconds)); + enableAt = _enableAt; + } + + /** + * Handle Stop Loss ... + * + * @param _type: ENUM_POSITION_TYPE member ... + */ + void HandleSL(ENUM_POSITION_TYPE _type) + { + // + bool isLong = IsLong(_type); + if (isLong) + { + longSLs++; + } + else + { + shortSLs++; + } + + // + countedSLs++; + } + + /** + * Handle Take Profit ... + * + * @param _type: ENUM_POSITION_TYPE member ... + */ + void HandleTP(ENUM_POSITION_TYPE _type) + { + // + bool isLong = IsLong(_type); + if (isLong) + { + longTPs++; + } + else + { + shortTPs++; + } + + // + countedSLs--; + if (countedSLs < 0) + { + countedSLs = 0; + } + } + + /** + * Reset Counter ... + */ + void Reset() + { + // + countedSLs = 0; + enableAt = NULL; + } + + // +}; + // // Implementations ... @@ -1092,6 +1277,44 @@ class XC121SMCTradeHandler : public XSCBaseAlert mDelayBarBetweenTwoSignal = value; } + // + int MaxAllowedSLToPause() + { + return mMaxAllowedSLToPause; + } + + // + void MaxAllowedSLToPause(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSLToPause = value; + } + + // + int MaxAllowedSLReachedPauseDelay() + { + return mMaxAllowedSLReachedPauseDelay; + } + +// + void MaxAllowedSLReachedPauseDelay(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedSLReachedPauseDelay = value; + } + // double AcceptNextSameTypeSignalWhenLastInProfit() { @@ -1779,9 +2002,73 @@ class XC121SMCTradeHandler : public XSCBaseAlert mData[idx].endTime = deal.time; mData[idx].profit = deal.profit; + // + bool isTP = deal.reason == DEAL_REASON_TP; + bool isSL = deal.reason == DEAL_REASON_SL; + // mData[idx].message = - deal.reason == DEAL_REASON_TP ? "TP" : "SL"; + isTP + ? "TP" + : isSL + ? "SL" + : ""; + + // + if (isTP || isSL) + { + // + int symbolIDX = -1; + bool hasInfo = HasSymbol( + mData[idx].symbol, + symbolIDX // + ); + + // + X121SMCSymbolPositionInfo info; + if (!hasInfo) + { + // + // Add New One ... + info.symbol = mData[idx].symbol; + } + else + { + // + // Update Exists ... + info = mSymbolInfos[symbolIDX]; + + // + // Remove Exists ... + ArrayRemove( + mSymbolInfos, + symbolIDX, + 1 // + ); + } + + // + ENUM_POSITION_TYPE xType = IsLong(mData[idx].type) + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + if (isTP) + { + info.HandleTP(xType); + } + else if (isSL) + { + info.HandleSL(xType); + } + + // + AddRef( + info, + mSymbolInfos // + ); + + // + HandlePauseSymbol(mData[idx].symbol); + } // Save(idx); @@ -1815,7 +2102,72 @@ class XC121SMCTradeHandler : public XSCBaseAlert mData[idx].message = comment; // - Save(idx); + bool handleForceClose = true; + if (handleForceClose) + { + // + bool isTP = position.profit > 0; + bool isSL = position.profit < 0; + + // + if (isTP || isSL) + { + // + int symbolIDX = -1; + bool hasInfo = HasSymbol( + mData[idx].symbol, + symbolIDX // + ); + + // + X121SMCSymbolPositionInfo info; + if (!hasInfo) + { + // + // Add New One ... + info.symbol = mData[idx].symbol; + } + else + { + // + // Update Exists ... + info = mSymbolInfos[symbolIDX]; + + // + // Remove Exists ... + ArrayRemove( + mSymbolInfos, + symbolIDX, + 1 // + ); + } + + // + ENUM_POSITION_TYPE xType = IsLong(mData[idx].type) + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + if (isTP) + { + info.HandleTP(xType); + } + else if (isSL) + { + info.HandleSL(xType); + } + + // + AddRef( + info, + mSymbolInfos // + ); + + // + HandlePauseSymbol(mData[idx].symbol); + } + + // + Save(idx); + } } // @@ -1992,7 +2344,24 @@ class XC121SMCTradeHandler : public XSCBaseAlert { return result; } - + + // + int symbolIDX = -1; + bool hasSymbolInfo = HasSymbol( + signal.symbol, + symbolIDX // + ); + + // + // Check rading Not Paused ... + result = + !hasSymbolInfo || + mSymbolInfos[symbolIDX].IsEnable(); + if (!result) + { + return result; + } + // bool isLong = IsLong(signal.type); @@ -2105,39 +2474,39 @@ class XC121SMCTradeHandler : public XSCBaseAlert return result; } + // + XPosition longs[]; + XPosition shorts[]; + + // + // Counting Positions ... + if (mUseMaxAllowedTradesPerSymbol) + { + // + mTrader.GetPositions( + longs, + shorts, + signal.symbol // + ); + } + else + { + // + mTrader.GetPositions( + longs, + shorts, + NULL // All Symbols ... + ); + } + + // + int longsCount = ArraySize(longs); + int shortsCount = ArraySize(shorts); + // // Check Trades Count ... if (mMaxAllowedLongs > 0 || mMaxAllowedShorts > 0) { - // - XPosition longs[]; - XPosition shorts[]; - - // - // Counting Positions ... - if (mUseMaxAllowedTradesPerSymbol) - { - // - mTrader.GetPositions( - longs, - shorts, - signal.symbol // - ); - } - else - { - // - mTrader.GetPositions( - longs, - shorts, - NULL // All Symbols ... - ); - } - - // - int longsCount = ArraySize(longs); - int shortsCount = ArraySize(shorts); - // result = // @@ -2159,48 +2528,48 @@ class XC121SMCTradeHandler : public XSCBaseAlert state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } + } + + // + // Check Position Delays ... + if (result && mDelayBarBetweenTwoSignal > 0) + { + // + int youngestAge = 0; + XPosition youngestPosition; // - // Check Position Delays ... - if (result && mDelayBarBetweenTwoSignal > 0) + // Long Positions when there are Longs ... + if (isLong && longsCount > 0) { // - int youngestAge = 0; - XPosition youngestPosition; + youngestAge = GetYoungest( + youngestPosition, + longs // + ); + } + // + // Short Positions when there are Shorts ... + else if (!isLong && shortsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + shorts // + ); + } + // + // Only Check when there is must to check and conditions happens ... + if (youngestAge > 0 && youngestPosition.IsValid()) + { // - // Long Positions when there are Longs ... - if (isLong && longsCount > 0) + result = youngestAge >= mDelayBarBetweenTwoSignal; + if (!result) { // - youngestAge = GetYoungest( - youngestPosition, - longs // - ); - } - // - // Short Positions when there are Shorts ... - else if (!isLong && shortsCount > 0) - { - // - youngestAge = GetYoungest( - youngestPosition, - shorts // - ); - } - - // - // Only Check when there is must to check and conditions happens ... - if (youngestAge > 0 && youngestPosition.IsValid()) - { - // - result = youngestAge >= mDelayBarBetweenTwoSignal; - if (!result) - { - // - state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; - return result; - } + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; } } } @@ -2346,11 +2715,35 @@ class XC121SMCTradeHandler : public XSCBaseAlert } } + /** + * Reset All Paused Symbols ... + */ + void ResumePausedSymbols() + { + // + int count = ArraySize(mSymbolInfos); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + mSymbolInfos[i].Reset(); + } + + // + string message = "Force Resume Paused Symbols ..."; + Alert(message); + } + // // Protected ... protected: // - XSCTrade *mTrader; // Instance of Trader Class + XSCTrade *mTrader; // Instance of Trader Class X121SMCTradeCollector *mCollector; // Instance of Trade Collector Class // @@ -2583,8 +2976,8 @@ class XC121SMCTradeHandler : public XSCBaseAlert * Handle Protecting Position ... */ bool HandlePositionProtecting( - XPosition &position, // Main Position - XPosition &supports[], // Supports + XPosition &position, // Main Position + XPosition &supports[], // Supports X121SMCProtectedPosition &positions[] // All Positions ) { @@ -3286,6 +3679,57 @@ class XC121SMCTradeHandler : public XSCBaseAlert // Trailling ... } + /** + * Pause Specified Symbol Trading ... + * + * @param symbol: String ... + */ + void HandlePauseSymbol(string symbol) + { + // + if (!IsValid(symbol)) + { + return; + } + + // + int idx = -1; + bool hasItem = HasSymbol( + symbol, + idx // + ); + if (!hasItem) + { + return; + } + + // + int maxAllowedSLToPause = MaxAllowedSLToPause(); + int pauseDelay = MaxAllowedSLReachedPauseDelay(); + if (maxAllowedSLToPause <= 0 || pauseDelay <= 0) + { + return; + } + + // + bool canPauseSymbol = + mSymbolInfos[idx].IsEnable() && + mSymbolInfos[idx].countedSLs >= maxAllowedSLToPause; + if (!canPauseSymbol) + { + return; + } + + // + mSymbolInfos[idx].Pause(pauseDelay); + + // + string message = "Pause (" + symbol + ") until: (" + ToString(mSymbolInfos[idx].enableAt) + ") ..."; + Alert(message); + + // + } + // // Private ... private: @@ -3317,8 +3761,10 @@ class XC121SMCTradeHandler : public XSCBaseAlert // Protector ... // - bool mUseForceMomentumsInProtection; // Use Force Momentums In Protection; int mDelayBarBetweenTwoSignal; // Delay Bars Between Two Signal + int mMaxAllowedSLToPause; // Max Allowed SL Per Symbol + int mMaxAllowedSLReachedPauseDelay; // Pause Symbol Trading After Mx Allowed SL Reached + bool mUseForceMomentumsInProtection; // Use Force Momentums In Protection double mAcceptNextSameTypeSignalWhenLastInProfit; // Accept Next Same Type Signal When Last in Profit in Point // @@ -3364,6 +3810,64 @@ class XC121SMCTradeHandler : public XSCBaseAlert double mHedgeHEMinProfitPerVolumeStep; // Minimum Required Profit For HE Hedge Per Volume Step double mHedgeBEMinProfitPerVolumeStep; // Minimum Required Profit For BE Hedge Per Volume Step + // + X121SMCSymbolPositionInfo mSymbolInfos[]; + + /** + * Find Specific Symbo Indo Item index ... + * + * @param symbol: String ... + * @param index: Integer ... + * + * @return ( bool ) + */ + bool HasSymbol( + string symbol, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = IsValid(symbol); + if (!result) + { + return result; + } + + // + int count = ArraySize(mSymbolInfos); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mSymbolInfos[i] + .IsOwn(symbol); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + // // Common Functions ... diff --git a/X121SMCEA/Experts/x-121.smc.expert.class.mq5 b/X121SMCEA/Experts/x-121.smc.expert.class.mq5 index f60004a2..af6e9d61 100644 --- a/X121SMCEA/Experts/x-121.smc.expert.class.mq5 +++ b/X121SMCEA/Experts/x-121.smc.expert.class.mq5 @@ -237,18 +237,8 @@ class XC121SMCExpert : public XCBaseExpert signal.conditions = conditionsSummary; // - // TODO: Check Signal Delay ... - // datetime currentTime = TimeCurrent(); - // int delay = mDelayBarBetweenTwoSignal; - // bool isDelayPassed = delay <= 0 - // ? true - // : !IsValid(lastSignalOn) - // ? true - // : MathAbs(TimeToSeconds(currentTime)) - MathAbs(TimeToSeconds(lastSignalOn)) >= ulong(delay * PeriodSeconds(_Period)); - // if (!isDelayPassed) - // { - // return; - // } + datetime currentTime = TimeCurrent(); + // // Execute Signal Using Trade Handler ... ENUM_X_SIGNAL_EXECUTION_RESULT state; @@ -260,7 +250,7 @@ class XC121SMCExpert : public XCBaseExpert // if (isExecuted) { - // lastSignalOn = currentTime; + mLastSignalOn = currentTime; } } @@ -469,6 +459,11 @@ class XC121SMCExpert : public XCBaseExpert // // TODO: Make This Configurable Later ... + // + mTradeHandler.DelayBarBetweenTwoSignal(3); + mTradeHandler.MaxAllowedSLToPause(0); + mTradeHandler.MaxAllowedSLReachedPauseDelay(HoursToSeconds(24)); + // // Configure Trade Management ... mTradeHandler.AllowLong(AllowLong()); @@ -720,7 +715,13 @@ class XC121SMCExpert : public XCBaseExpert HandleReportBalance(); } - // + /** + * Reset All Paused Symbols on Each New Days ... + */ + void HandleOnNewDay() override + { + mTradeHandler.ResumePausedSymbols(); + } /** * Generate Identifier Tag ... @@ -758,6 +759,9 @@ class XC121SMCExpert : public XCBaseExpert // // Props ... + // + datetime mLastSignalOn; + // XC121SMCTradeHandler *mTradeHandler; // Trade Handler ... XCX121SMCBaseStrategy *mStrategies[]; // Registere Strategies in EA ... diff --git a/X121SMCEA/Handler/x-saherelm.x121.smc.trade.handler.mq5 b/X121SMCEA/Handler/x-saherelm.x121.smc.trade.handler.mq5 deleted file mode 100644 index 8d763b8d..00000000 --- a/X121SMCEA/Handler/x-saherelm.x121.smc.trade.handler.mq5 +++ /dev/null @@ -1 +0,0 @@ -// Complete this ... \ 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 edfe1351..4c49b373 100644 --- a/X121SMCEA/Libraries/x-121.smc.lib.mq5 +++ b/X121SMCEA/Libraries/x-121.smc.lib.mq5 @@ -54,30 +54,36 @@ struct X121SMCStrategyConditions // Conditions ... // + XOHCL swingHigh; XZone supplyZone; - XZone bearishOrderBlock; XZone bearishFVG; + XOHCL resistance; + XZone bearishOrderBlock; + XOHCL bullishMomentumBar; + XOHCL bullishRejectionBar; // - XZone bearishOrderBlocks[]; + XZone demandZones[]; XZone bearishFVGs[]; - - // + XZone bearishOrderBlocks[]; XOHCL swingHighs[]; XOHCL resistances[]; XOHCL bearishMomentumBars[]; XOHCL bearishRejectionBars[]; // + XOHCL support; + XOHCL swingLow; XZone demandZone; - XZone bullishOrderBlock; XZone bullishFVG; + XZone bullishOrderBlock; + XOHCL bearishMomentumBar; + XOHCL bearishRejectionBar; // - XZone bullishOrderBlocks[]; + XZone supplyZones[]; XZone bullishFVGs[]; - - // + XZone bullishOrderBlocks[]; XOHCL supports[]; XOHCL swingLows[]; XOHCL bullishMomentumBars[]; @@ -93,8 +99,9 @@ struct X121SMCStrategyConditions // // Tools ... - // - // Cleanup ... + /** + * Cleanup ... + */ void Clean() { // @@ -103,99 +110,63 @@ struct X121SMCStrategyConditions time = NULL; // - supplyZone.Clean(); - bearishFVG.Clean(); - bearishOrderBlock.Clean(); - - // - Clean(bearishFVGs); - Clean(bearishOrderBlocks); - - // - demandZone.Clean(); - bullishFVG.Clean(); - bullishOrderBlock.Clean(); - - // - Clean(bullishFVGs); - Clean(bullishOrderBlocks); - - // - Clean(swingHighs); - Clean(resistances); - Clean(bearishMomentumBars); - Clean(bearishRejectionBars); - - // - Clean(swingLows); - Clean(supports); - Clean(bullishMomentumBars); - Clean(bullishRejectionBars); + CleanDemand(); + CleanSupply(); } + /** + * Cleanup Demand Related ... + */ void CleanDemand() { // + support.Clean(); + swingLow.Clean(); demandZone.Clean(); bullishFVG.Clean(); bullishOrderBlock.Clean(); + bullishMomentumBar.Clean(); + bullishRejectionBar.Clean(); // Clean(supports); Clean(swingLows); + Clean(supplyZones); Clean(bullishFVGs); Clean(bullishOrderBlocks); Clean(bullishMomentumBars); Clean(bullishRejectionBars); } + /** + * Cleanup Supply Related ... + */ void CleanSupply() { // + swingHigh.Clean(); supplyZone.Clean(); bearishFVG.Clean(); + resistance.Clean(); bearishOrderBlock.Clean(); + bearishMomentumBar.Clean(); + bearishRejectionBar.Clean(); // Clean(swingHighs); - Clean(resistances); + Clean(demandZones); Clean(bearishFVGs); + Clean(resistances); Clean(bearishOrderBlocks); Clean(bearishMomentumBars); Clean(bearishRejectionBars); } - bool ValidateSupply() - { - // - bool result = false; - - // - result = IsValid(); - if (!result) - { - return result; - } - - // - result = - // - supplyZone.IsValid() && - bearishFVG.IsValid() && - bearishOrderBlock.IsValid() && - (ArraySize(swingHighs) > 0 || - ArraySize(bearishFVGs) > 0 || - ArraySize(resistances) > 0 || - ArraySize(bearishOrderBlocks) > 0 || - ArraySize(bearishMomentumBars) > 0 || - ArraySize(bearishRejectionBars) > 0) - // - ; - - // - return result; - } - + /** + * Validate Demand ... + * + * @return ( bool ) + */ bool ValidateDemand() { // @@ -211,11 +182,17 @@ struct X121SMCStrategyConditions // result = // + support.IsValid() && + swingLow.IsValid() && demandZone.IsValid() && bullishFVG.IsValid() && bullishOrderBlock.IsValid() && + bullishMomentumBar.IsValid() && + bullishRejectionBar.IsValid() && + // (ArraySize(supports) > 0 || ArraySize(swingLows) > 0 || + ArraySize(supplyZones) > 0 || ArraySize(bullishFVGs) > 0 || ArraySize(bullishOrderBlocks) > 0 || ArraySize(bullishMomentumBars) > 0 || @@ -227,6 +204,48 @@ struct X121SMCStrategyConditions return result; } + /** + * Validate Supply ... + * + * @return ( bool ) + */ + bool ValidateSupply() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = + // + swingHigh.IsValid() && + supplyZone.IsValid() && + bearishFVG.IsValid() && + resistance.IsValid() && + bearishOrderBlock.IsValid() && + bearishMomentumBar.IsValid() && + bearishRejectionBar.IsValid() && + // + (ArraySize(swingHighs) > 0 || + ArraySize(demandZones) > 0 || + ArraySize(bearishFVGs) > 0 || + ArraySize(resistances) > 0 || + ArraySize(bearishOrderBlocks) > 0 || + ArraySize(bearishMomentumBars) > 0 || + ArraySize(bearishRejectionBars) > 0) + // + ; + + // + return result; + } + // // Validate ... bool IsValid() @@ -650,4 +669,188 @@ struct XRange // }; +// +struct XRangeStructure +{ + // + XRange range; + + // + XZone demandZones[]; + XZone supplyZones[]; + + // + XZone bearishOrderBlocks[]; + XZone bearishFVGs[]; + + // + XOHCL swingHighs[]; + XOHCL resistances[]; + XOHCL bearishMomentumBars[]; + XOHCL bearishRejectionBars[]; + + // + XZone bullishOrderBlocks[]; + XZone bullishFVGs[]; + + // + XOHCL supports[]; + XOHCL swingLows[]; + XOHCL bullishMomentumBars[]; + XOHCL bullishRejectionBars[]; + + // + // Constructor ... + void XRangeStructure() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + range.Clean(); + + // + Clean(supports); + Clean(swingLows); + Clean(swingHighs); + Clean(demandZones); + Clean(supplyZones); + Clean(bearishFVGs); + Clean(resistances); + Clean(bullishFVGs); + Clean(bearishOrderBlocks); + Clean(bullishOrderBlocks); + Clean(bearishMomentumBars); + Clean(bearishRejectionBars); + Clean(bullishMomentumBars); + Clean(bullishRejectionBars); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = range.IsValid(); + if (!result) + { + return result; + } + + // + result = + // + ArraySize(supports) > 0 || + ArraySize(swingLows) > 0 || + ArraySize(swingHighs) > 0 || + ArraySize(demandZones) > 0 || + ArraySize(supplyZones) > 0 || + ArraySize(bearishFVGs) > 0 || + ArraySize(resistances) > 0 || + ArraySize(bullishFVGs) > 0 || + ArraySize(bearishOrderBlocks) > 0 || + ArraySize(bullishOrderBlocks) > 0 || + ArraySize(bearishMomentumBars) > 0 || + ArraySize(bearishRejectionBars) > 0 || + ArraySize(bullishMomentumBars) > 0 || + ArraySize(bullishRejectionBars) > 0 + // + ; + + // + return result; + } + + /** + * Generate Tag ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = NULL; + + // + string hash = range.GetTag(); + hash = ToMD5(hash); + + // + result = X121SMCMarketStructureToken + "_" + hash; + + // + return result; + } +}; + +/** + * Check a Zone is Between to other Zones ... + * + * @param source: XZone instance ... + * @param upper: XZone instance ... + * @param lower: XZone instance ... + * + * @return ( bool ) + */ +bool IsBetween( + XZone &source, + XRange &range // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + range.IsValid(); + if (!result) + { + return result; + } + + // + result = source.upper <= range.upper && + source.lower >= range.lower; + + // + return result; +} +bool IsBetween( + XOHCL &source, + XRange &range // +) +{ + // + bool result = false; + + // + result = source.IsValid() && + range.IsValid(); + if (!result) + { + return result; + } + + // + result = source.high <= range.upper && + source.low >= range.lower; + + // + return result; +} + // \ No newline at end of file diff --git a/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 index f40dae94..bf1b3405 100644 Binary files a/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 and b/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 differ