diff --git a/Classes/x-saherelm.xtrade.class.mq5 b/Classes/x-saherelm.xtrade.class.mq5 index 02df7ef3..c82acdf0 100644 --- a/Classes/x-saherelm.xtrade.class.mq5 +++ b/Classes/x-saherelm.xtrade.class.mq5 @@ -4464,6 +4464,8 @@ public: // item.recoveryTPPoint = mRecoveryTPPoint; item.recoverySLPoint = mRecoverySLPoint; + item.maxAllowedRecover = mMaxAllowedRecover; + item.recoveryVolumeMultiplier = mRecoveryVolumeMultiplier; } // @@ -4685,8 +4687,6 @@ public: } } - // - // // Do Force Closing ... @@ -4699,15 +4699,18 @@ public: double profit = mData[i].profit; double volume = mData[i].volume; string symbol = mData[i].symbol; + string provider = mData[i].provider; bool isLong = IsLong(mData[i].type); ENUM_TIMEFRAMES period = mData[i].period; double points = GetPoints(mData[i].symbol); bool ignoreTPOnTrail = mData[i].ignoreTPOnTrail; + double recoveryTPPoint = mData[i].recoveryTPPoint; + double recoverySLPoint = mData[i].recoverySLPoint; + int maxAllowedRecover = mData[i].maxAllowedRecover; double trailStepInPoints = mData[i].trailStepInPoint; double trailStartInPoint = mData[i].trailStartInPoint; bool trailBasedOnProfit = mData[i].trailBasedOnProfit; - double recoveryTPPoint = mData[i].recoveryTPPoint; - double recoverySLPoint = mData[i].recoverySLPoint; + double recoveryVolumeMultiplier = mData[i].recoveryVolumeMultiplier; // XPosition iPosition; @@ -4731,6 +4734,132 @@ public: continue; } + // + // Handle Recovery Break Event ... + if (mData[i].allowRecover) + { + // + if (mData[i].recoveryLevel <= 0) + { + // + if (profit > 0) + { + // + double proftiInPoints = profit / volume; + bool canClose = proftiInPoints >= recoveryTPPoint; + if (canClose) + { + // + string comment = "Recovery TP ..."; + bool isClosed = mTrader.Close( + ticket, + comment // + ); + if (isClosed) + { + // + string msg = "Position (" + ToString(ticket) + ") Hit's Recovery TP ..."; + Alert(msg); + break; + } + } + } + } + else + { + // + XPosition positions[]; + int positionsCount = mTrader.GetPositions( + positions, + symbol, + provider, + period // + ); + if (positionsCount > 0) + { + // + XPosition recoveries[]; + int recoveriesCount = ExtractRecoveries( + ticket, + positions, + recoveries // + ); + + // + if (recoveriesCount > 0) + { + // + XPosition mustClose[]; + AddRef( + iPosition, + mustClose // + ); + + // + double requiredProfitPoints = (mData[i].recoveryLevel + 1) * recoveryTPPoint; + + // + double rSwap = mData[i].swap; + double rVolume = volume; + double rProfit = profit; + double rCommission = mData[i].commission; + for (int i = 0; i < recoveriesCount; i++) + { + // + rSwap += recoveries[i].swap; + rProfit += recoveries[i].profit; + rVolume += recoveries[i].volume; + rCommission += mTrader.GetPositionCommission(recoveries[i].ticket); + + // + AddRef( + recoveries[i], + mustClose // + ); + } + + // + double profitSummary = + rProfit + (-1 * rSwap) - MathAbs(rCommission); + if (profitSummary > 0) + { + // + double rProfitInPoints = profitSummary / volume; + + // + bool canFinishRecovery = rProfitInPoints >= requiredProfitPoints; + if (canFinishRecovery) + { + // + // Here we Have to close All Recoveries + // and Position it Self ... + + // + string comment = "Recovery Done ..."; + + // + int closeds = mTrader.Close( + mustClose, + comment // + ); + if (closeds > 0) + { + // + string msg = "EQM Done Recovery (" + ToString(closeds) + ") Positions ..."; + Alert(msg); + } + } + + // + Clean(mustClose); + Clean(positions); + Clean(recoveries); + } + } + } + } + } + // // Retriece CIndex Bar ... XOHCL cBar; @@ -4762,6 +4891,14 @@ public: tmpLSW, true // ); + bool isBullishSigns = + // + isBullishTrend && + hasBullishPower && + hasBullishPattern && + hasBullishPressure + // + ; // // Bearish ... @@ -4771,8 +4908,16 @@ public: bool isBearishTrend = cBar.HasBearishTrend( tmpHSW, tmpLSW, - false // + true // ); + bool isBearishSigns = + // + isBearishTrend && + hasBearishPower && + hasBearishPattern && + hasBearishPressure + // + ; // // Trail ... @@ -4954,65 +5099,228 @@ public: // // Profit Must be Negative ... if ( - profit < 0 && recoveryTPPoint > 0 && - recoverySLPoint > 0) + recoverySLPoint > 0 && + mData[i].recoveryLevel < maxAllowedRecover) { // // Current Profit ... - double drawdownInPoints = (MathAbs(profit) / volume); + double distanceInPoints = (MathAbs(profit) / volume); + double _volume = volume * ((mData[i].recoveryLevel + 1) * recoveryVolumeMultiplier); + string _comment = GenerateRecoveryTag(ticket); // // Try to Remove SL of Recovery Signals ... - if (iPosition.sl > 0) + if (iPosition.sl > 0 || iPosition.tp > 0) { // - string comment = "EQM Recover Remove SL"; + string comment = "EQM Recover Remove TP/SL"; bool isSLRemoved = mTrader.Modify( ticket, 0, - iPosition.tp, + 0, comment // ); } - else + + // + if (profit < 0) { // - // Check Position TP ... - double rewardInPoints = iPosition.GetReward() / points; - if (rewardInPoints != recoveryTPPoint) + if (mRecoverBasedOnPressures) { // - double reward = recoveryTPPoint * points; - double tp = - isLong - ? iPosition.entry + reward - : iPosition.entry - reward; - string comment = "EQM Recover Fix TP"; - bool isSLRemoved = mTrader.Modify( - ticket, - iPosition.sl, - tp, - comment // - ); + bool canRecover = distanceInPoints >= recoverySLPoint * 0.75; + if (canRecover) + { + // + XSignal rSignal; + bool isPrepared = false; + double longEntry = GetEntry(symbol, POSITION_TYPE_BUY); + double shortEntry = GetEntry(symbol, POSITION_TYPE_SELL); + + // + if (isBullishSigns) + { + // + rSignal.Clean(); + isPrepared = rSignal.Prepare( + symbol, + provider, + period, + POSITION_TYPE_BUY, + X_ORDER_MODE_MARKET, + longEntry, + _volume, + 0, + 0 // + ); + } + else if (isBearishSigns) + { + // + rSignal.Clean(); + isPrepared = rSignal.Prepare( + symbol, + provider, + period, + POSITION_TYPE_SELL, + X_ORDER_MODE_MARKET, + shortEntry, + _volume, + 0, + 0 // + ); + } + + // + if (isPrepared) + { + // + rSignal.comment = _comment; + + // + bool isExecuted = ExecuteRecoverySignal(rSignal); + if (isExecuted) + { + mData[i].recoveryLevel++; + } + } + } } else { // - // Check Price Distance For Recovery ... - bool canLookForPressure = - // - // in 75% ... - drawdownInPoints > ((recoverySLPoint / 3) * 2) - // - ; - - // - if (canLookForPressure) + bool canRecover = distanceInPoints >= recoverySLPoint; + if (canRecover) { // - // Looking for Signal Direction and - // Founding Pressure ... + ENUM_POSITION_TYPE _type = + isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + double _entry = GetEntry(symbol, _type); + + // + XSignal rSignal; + bool isPrepared = rSignal.Prepare( + symbol, + provider, + period, + _type, + X_ORDER_MODE_MARKET, + _entry, + _volume, + 0, + 0 // + ); + if (isPrepared) + { + // + rSignal.comment = _comment; + + // + bool isExecuted = ExecuteRecoverySignal(rSignal); + if (isExecuted) + { + mData[i].recoveryLevel++; + } + } + } + } + } + else if (profit >= 0 && mData[i].recoveryLevel > 0) + { + // + if (mRecoverBasedOnPressures) + { + // + XSignal rSignal; + bool isPrepared = false; + double longEntry = GetEntry(symbol, POSITION_TYPE_BUY); + double shortEntry = GetEntry(symbol, POSITION_TYPE_SELL); + + // + if (isBullishSigns) + { + // + rSignal.Clean(); + isPrepared = rSignal.Prepare( + symbol, + provider, + period, + POSITION_TYPE_BUY, + X_ORDER_MODE_MARKET, + longEntry, + _volume, + 0, + 0 // + ); + } + else if (isBearishSigns) + { + // + rSignal.Clean(); + isPrepared = rSignal.Prepare( + symbol, + provider, + period, + POSITION_TYPE_SELL, + X_ORDER_MODE_MARKET, + shortEntry, + _volume, + 0, + 0 // + ); + } + + // + if (isPrepared) + { + // + rSignal.comment = _comment; + + // + bool isExecuted = ExecuteRecoverySignal(rSignal); + if (isExecuted) + { + mData[i].recoveryLevel++; + } + } + } + else + { + // + ENUM_POSITION_TYPE _type = + isLong + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + double _entry = GetEntry(symbol, _type); + + // + XSignal rSignal; + bool isPrepared = rSignal.Prepare( + symbol, + provider, + period, + _type, + X_ORDER_MODE_MARKET, + _entry, + _volume, + 0, + 0 // + ); + if (isPrepared) + { + // + rSignal.comment = _comment; + + // + bool isExecuted = ExecuteRecoverySignal(rSignal); + if (isExecuted) + { + mData[i].recoveryLevel++; + } } } } @@ -5342,6 +5650,26 @@ private: requiredProfitsForHedge -= commissions; } + // + bool ExecuteRecoverySignal(XSignal &signal) + { + // + bool result = false; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = mTrader.ExecuteSignal( + signal, + state, + ORDER_TIME_GTC, + NULL, + false // + ); + + // + return result; + } + // }; diff --git a/Experts/x-test-strategies.ea.mq5 b/Experts/x-test-strategies.ea.mq5 index f2d10b1b..aa97aec9 100644 --- a/Experts/x-test-strategies.ea.mq5 +++ b/Experts/x-test-strategies.ea.mq5 @@ -43,8 +43,8 @@ double eaAllowLong = true; // Allow Long Positions double eaAllowShort = true; // Allow Short Positions // -int eaMaxAllowedLongs = 0; // Max Allowed Long Positions -int eaMaxAllowedShorts = 0; // Max Allowed Short Positions +int eaMaxAllowedLongs = 1; // Max Allowed Long Positions +int eaMaxAllowedShorts = 1; // Max Allowed Short Positions // double eaTPPoint = 100; // Static TP Point @@ -113,8 +113,8 @@ int OnInit() drawPrefix = ShortName; // - EventSetTimer(5); - // EventSetMillisecondTimer(100); + // EventSetTimer(1); + EventSetMillisecondTimer(100); // // Init Succeed ... diff --git a/Libraries/x-saherelm.xtrade.lib.mq5 b/Libraries/x-saherelm.xtrade.lib.mq5 index e840a6bd..656b5a85 100644 --- a/Libraries/x-saherelm.xtrade.lib.mq5 +++ b/Libraries/x-saherelm.xtrade.lib.mq5 @@ -3507,7 +3507,7 @@ struct XTradeData (maxDrawdown == 0 || MathAbs(profit) > MathAbs(maxDrawdown))) { - profit = maxDrawdown; + maxDrawdown = profit; } // @@ -3785,18 +3785,22 @@ struct XTradeData // Recovery ... // - bool allowRecover; // Allow Recover Specified Position - double recoveryTPPoint; // Recovery TP Point - double recoverySLPoint; // Recovery SL Point - int maxAllowedRecover; // Max Allowed Recovery + bool allowRecover; // Allow Recover Specified Position + double recoveryTPPoint; // Recovery TP Point + double recoverySLPoint; // Recovery SL Point + int maxAllowedRecover; // Max Allowed Recovery + int recoveryLevel; // Number of Recovery Signals + double recoveryVolumeMultiplier; // Recovery Volume Multiplier // void ResetRecovery() { // allowRecover = false; + recoveryLevel = 0; recoveryTPPoint = 0; recoverySLPoint = 0; + recoveryVolumeMultiplier = 0; } // @@ -5418,8 +5422,9 @@ int ExtractRecoveries( XPosition iSource = source[i]; // - ulong isRecovery = ExtractRecoveredTicket(iSource.comment) > 0; - if (isRecovery && iSource.ticket == ticket) + ulong parentTicket = ExtractRecoveredTicket(iSource.comment); + bool isRecovery = parentTicket > 0; + if (isRecovery && parentTicket == ticket) { // AddRef(