diff --git a/Classes/x-saherelm.x121.xtrade.handler.class.mq5 b/Classes/x-saherelm.x121.xtrade.handler.class.mq5 index 50e39fbd..6ac00396 100644 --- a/Classes/x-saherelm.x121.xtrade.handler.class.mq5 +++ b/Classes/x-saherelm.x121.xtrade.handler.class.mq5 @@ -54,13 +54,12 @@ struct X121TradeData string conditions; // Signal Conditions // - int trailStep; // Trail Step - bool freezed; // Position Freezed or not - int protectionStep; // Protection Step - datetime lastProtectedOn; // Last Protection Date - double lastProtectedInProfit; // Last Protection In Profit - double lastProtectedInDrawdown; // Last Protection In Drawdown - bool partiallyClosed; // Partially Closed or not + bool freezed; // Position Freezed or not + int trailStep; // Trail Step + int supportLevel; // Support Level + bool partiallyClosed; // Partially Closed or not + datetime lastSupportedOn; // Last Support Date + double lastSupportDistance; // Last Support Distance // // Constructor ... @@ -201,11 +200,10 @@ struct X121TradeData // trailStep = 0; freezed = false; - protectionStep = 0; + supportLevel = 0; + lastSupportedOn = NULL; partiallyClosed = false; - lastProtectedOn = NULL; - lastProtectedInProfit = 0; - lastProtectedInDrawdown = 0; + lastSupportDistance = 0; // signal.Clean(); @@ -917,6 +915,7 @@ class X121SCTradeHandler : public XSCBaseAlert { // mTrader = trader; + mAdditionalVolume = 0; mCollector = new X121TradeCollector(); } @@ -1064,25 +1063,6 @@ class X121SCTradeHandler : public XSCBaseAlert // // Protector Start ... - // - double ProtectorStartDistanceInPoint() - { - return mProtectorStartDistanceInPoint; - } - - // - void ProtectorStartDistanceInPoint(double value) - { - // - if (value < 0) - { - value = 0; - } - - // - mProtectorStartDistanceInPoint = value; - } - // int DelayBarBetweenTwoSameSignal() { @@ -1106,37 +1086,28 @@ class X121SCTradeHandler : public XSCBaseAlert // In Profit Position Protecting ... // - bool AllowTrailStopInProfits() + // Trail ... + + // + bool AllowTrail() { - return mAllowTrailStopInProfits; + return mAllowTrail; } // - void AllowTrailStopInProfits(bool value) + void AllowTrail(bool value) { - mAllowTrailStopInProfits = value; + mAllowTrail = value; } // - bool OnlyTrailUnprotectedPositions() + double TrailStartDistance() { - return mOnlyTrailUnprotectedPositions; + return mTrailStartDistance; } // - void OnlyTrailUnprotectedPositions(bool value) - { - mOnlyTrailUnprotectedPositions = value; - } - - // - double TrailStopStepsInPoint() - { - return mTrailStopStepsInPoint; - } - - // - void TrailStopStepsInPoint(double value) + void TrailStartDistance(double value) { // if (value < 0) @@ -1145,17 +1116,17 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mTrailStopStepsInPoint = value; + mTrailStartDistance = value; } // - int RmoveTPOnTrailStep() + double TrailStep() { - return mRmoveTPOnTrailStep; + return mTrailStep; } // - void RmoveTPOnTrailStep(int value) + void TrailStep(double value) { // if (value < 0) @@ -1164,17 +1135,32 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mRmoveTPOnTrailStep = value; + mTrailStep = value; } // - double PartialCloseOnSpecificPointOfProfit() + bool OnlyTrailUnprotected() { - return mPartialCloseOnSpecificPointOfProfit; + return mOnlyTrailUnprotected; } // - void PartialCloseOnSpecificPointOfProfit(double value) + void OnlyTrailUnprotected(bool value) + { + mOnlyTrailUnprotected = value; + } + + // + // Partial Close (In Profit) ... + + // + double PartialCloseInProfitDistance() + { + return mPartialCloseInProfitDistance; + } + + // + void PartialCloseInProfitDistance(double value) { // if (value < 0) @@ -1183,17 +1169,17 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mPartialCloseOnSpecificPointOfProfit = value; + mPartialCloseInProfitDistance = value; } // - double PartialCloseVolumeInProfit() + double PartialCloseInProfitVolume() { - return mPartialCloseVolumeInProfit; + return mPartialCloseInProfitVolume; } // - void PartialCloseVolumeInProfit(double value) + void PartialCloseInProfitVolume(double value) { // if (value < 0) @@ -1202,32 +1188,33 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mPartialCloseVolumeInProfit = value; + mPartialCloseInProfitVolume = value; } // // In Drawdown Positions Protecting ... // - bool FreezeInDrawdon() + // Freeze ... + bool AllowFreeze() { - return mFreezeInDrawdon; + return mAllowFreeze; } // - void FreezeInDrawdon(bool value) + void AllowFreeze(bool value) { - mFreezeInDrawdon = value; + mAllowFreeze = value; } // - double FreezePoint() + double FreezeDistance() { - return mFreezePoint; + return mFreezeDistance; } // - void FreezePoint(double value) + void FreezeDistance(double value) { // if (value < 0) @@ -1236,17 +1223,56 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mFreezePoint = value; + mFreezeDistance = value; } // - double FreezeVolume() + bool RemoveFreezedPositionTPSL() { - return mFreezeVolume; + return mRemoveFreezedPositionTPSL; } // - void FreezeVolume(double value) + void RemoveFreezedPositionTPSL(bool value) + { + mRemoveFreezedPositionTPSL = value; + } + + // + bool DisableTrailWhenFreezedPosition() + { + return mDisableTrailWhenFreezedPosition; + } + + // + void DisableTrailWhenFreezedPosition(bool value) + { + mDisableTrailWhenFreezedPosition = value; + } + + // + // Support ... + + // + bool AllowSupport() + { + return mAllowSupport; + } + + // + void AllowSupport(bool value) + { + mAllowSupport = value; + } + + // + double SupportStartDistance() + { + return mSupportStartDistance; + } + + // + void SupportStartDistance(double value) { // if (value < 0) @@ -1255,41 +1281,17 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mFreezeVolume = value; + mSupportStartDistance = value; } // - bool RemoveFreezedPositionsTPSL() + double SupportVolumeMultiplier() { - return mRemoveFreezedPositionsTPSL; + return mSupportVolumeMultiplier; } // - void RemoveFreezedPositionsTPSL(bool value) - { - mRemoveFreezedPositionsTPSL = value; - } - - // - bool AllowRecoverInDrawdowns() - { - return mAllowRecoverInDrawdowns; - } - - // - void AllowRecoverInDrawdowns(bool value) - { - mAllowRecoverInDrawdowns = value; - } - - // - double RecoveryMultiplier() - { - return mRecoveryMultiplier; - } - - // - void RecoveryMultiplier(double value) + void SupportVolumeMultiplier(double value) { // if (value < 0) @@ -1298,29 +1300,41 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mRecoveryMultiplier = value; + mSupportVolumeMultiplier = value; } // - bool ApplyRecoveryLevelOnVolume() + bool MultiplySupportLevelOnVolume() { - return mApplyRecoveryLevelOnVolume; + return mMultiplySupportLevelOnVolume; } // - void ApplyRecoveryLevelOnVolume(bool value) + void MultiplySupportLevelOnVolume(bool value) { - mApplyRecoveryLevelOnVolume = value; + mMultiplySupportLevelOnVolume = value; } // - int RecoveryDelayInMinute() + bool DoSupportOnConditions() { - return mRecoveryDelayInMinute; + return mDoSupportOnConditions; } // - void RecoveryDelayInMinute(int value) + void DoSupportOnConditions(bool value) + { + mDoSupportOnConditions = value; + } + + // + int DelayBetweenTwoSupport() + { + return mDelayBetweenTwoSupport; + } + + // + void DelayBetweenTwoSupport(int value) { // if (value < 0) @@ -1329,17 +1343,20 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mRecoveryDelayInMinute = value; + mDelayBetweenTwoSupport = value; } // - double RecoveryDistanceInPoint() + // Partial Close (In Drawdown) ... + + // + double PartialCloseInDrawdownDistance() { - return mRecoveryDistanceInPoint; + return mPartialCloseInDrawdownDistance; } // - void RecoveryDistanceInPoint(double value) + void PartialCloseInDrawdownDistance(double value) { // if (value < 0) @@ -1348,17 +1365,17 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mRecoveryDistanceInPoint = value; + mPartialCloseInDrawdownDistance = value; } // - double PartialCloseOnSpecificPointOfDrawdown() + double PartialCloseInDrawdownVolume() { - return mPartialCloseOnSpecificPointOfDrawdown; + return mPartialCloseInDrawdownVolume; } // - void PartialCloseOnSpecificPointOfDrawdown(double value) + void PartialCloseInDrawdownVolume(double value) { // if (value < 0) @@ -1367,26 +1384,7 @@ class X121SCTradeHandler : public XSCBaseAlert } // - mPartialCloseOnSpecificPointOfDrawdown = value; - } - - // - double PartialCloseVolumeInDrawdown() - { - return mPartialCloseVolumeInDrawdown; - } - - // - void PartialCloseVolumeInDrawdown(double value) - { - // - if (value < 0) - { - value = 0; - } - - // - mPartialCloseVolumeInDrawdown = value; + mPartialCloseInDrawdownVolume = value; } // @@ -1529,6 +1527,12 @@ class X121SCTradeHandler : public XSCBaseAlert return drawdownPercent; } + // + double AdditionalVolume() + { + return mAdditionalVolume; + } + // // Position Retrievers ... @@ -2153,6 +2157,10 @@ class X121SCTradeHandler : public XSCBaseAlert } } + // + // Add Additional Volume to Signal ... + signal.volume += mAdditionalVolume; + // // Execute Signal ... result = mTrader.ExecuteSignal( @@ -2226,14 +2234,6 @@ class X121SCTradeHandler : public XSCBaseAlert } } - // - // Loop Through Main Positions ... - double requiredDistance = ProtectorStartDistanceInPoint(); - if (requiredDistance <= 0) - { - return; - } - // int protectedPositions = 0; for (int i = 0; i < pPositionsCount; i++) @@ -2241,24 +2241,17 @@ class X121SCTradeHandler : public XSCBaseAlert // // Check Position is Protectable or not ... XProtectedPosition iProtected = pPositions[i]; - - // XPosition iPosition = iProtected.main; // - double iDistance = MathAbs(iPosition.GetProfitInPoint()); - bool isDistancePassed = iDistance >= requiredDistance; - if (isDistancePassed) + bool isProtected = HandlePositionProtecting( + iPosition, + iProtected.supports, + pPositions // + ); + if (isProtected) { - // - bool isProtected = HandlePositionProtecting( - iPosition, - iProtected.supports // - ); - if (isProtected) - { - protectedPositions++; - } + protectedPositions++; } } @@ -2518,8 +2511,9 @@ class X121SCTradeHandler : public XSCBaseAlert * Handle Protecting Position ... */ bool HandlePositionProtecting( - XPosition &position, // Main Position - XPosition &supports[] // Supports + XPosition &position, // Main Position + XPosition &supports[], // Supports + XProtectedPosition &positions[] // All Positions ) { // @@ -2543,10 +2537,134 @@ class X121SCTradeHandler : public XSCBaseAlert // bool isLong = IsLong(position.type); bool isInProfit = position.profit > 0; + datetime currentTime = TimeCurrent(); // int supportsCount = ArraySize(supports); double profitInPoint = position.GetProfitInPoint(); + double pointValue = position.GetPointsValue(); + + // + // Determines there is a Freezed Position or not ... + bool hasFreezed = false; + int positionsCount = ArraySize(positions); + if (IsValidSize(positionsCount)) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + int iSupportsCount = ArraySize(positions[i].supports); + + // + hasFreezed = iSupportsCount == 1 && + positions[i].main.tp == 0 && + positions[i].main.sl == 0 && + positions[i].supports[0].tp == 0 && + positions[i].supports[0].sl == 0 && + positions[i].main.volume == positions[i].supports[0].volume; + if (hasFreezed) + { + break; + } + } + } + + // + // Reading Requirements for Trailling Stops ... + bool allowTrail = AllowTrail(); + double trailStep = TrailStep(); + double trailStartDistance = TrailStartDistance(); + bool allowOnlyUnprotecteds = OnlyTrailUnprotected(); + bool disableTrailWhenFreezedPosition = DisableTrailWhenFreezedPosition(); + bool canTrail = isInProfit && + allowTrail && + trailStep > 0 && + profitInPoint > 0 && + trailStartDistance > 0 && + (!allowOnlyUnprotecteds + ? true + : supportsCount <= 0) && + profitInPoint >= trailStartDistance && + (!disableTrailWhenFreezedPosition + ? true + : !hasFreezed); + + // + // Reading Requirements for Partial Close ... + // In Profit ... + double partialCloseInProfitDistance = PartialCloseInProfitDistance(); + double partialCloseInProfitVolume = PartialCloseInProfitVolume(); + bool canPartialCloseInProfit = isInProfit && + profitInPoint > 0 && + !mData[iDX].partiallyClosed && + partialCloseInProfitVolume > 0 && + profitInPoint >= partialCloseInProfitDistance; + + // + // In Drawdown ... + double partialCloseInDrawdownDistance = PartialCloseInProfitDistance(); + double partialCloseInDrawdownVolume = PartialCloseInProfitVolume(); + bool canPartialCloseInDrawdown = !isInProfit && + profitInPoint < 0 && + !mData[iDX].partiallyClosed && + partialCloseInDrawdownVolume > 0 && + MathAbs(profitInPoint) >= partialCloseInDrawdownDistance; + + // + double partialCloseVolume = canPartialCloseInProfit + ? partialCloseInProfitVolume + : canPartialCloseInDrawdown + ? partialCloseInDrawdownVolume + : 0; + + // + bool canPartialClose = partialCloseVolume > 0 && + (canPartialCloseInProfit || + canPartialCloseInDrawdown); + + // + // Reading Requirement for Freezing Positions ... + + // + bool allowFreeze = AllowFreeze(); + double freezeDistance = FreezeDistance(); + bool removeFreezedPositionTPSL = RemoveFreezedPositionTPSL(); + bool canFreeze = !isInProfit && + profitInPoint < 0 && + freezeDistance > 0 && + !mData[iDX].freezed && + MathAbs(profitInPoint) >= freezeDistance; + + // + // Reading Requirement for Support Positions ... + bool allowSupport = AllowSupport(); + double supportStartDistance = SupportStartDistance(); + int delayBetweenTwoSupport = DelayBetweenTwoSupport(); + double supportVolumeMultiplier = SupportVolumeMultiplier(); + bool multiplySupportLevelOnVolume = MultiplySupportLevelOnVolume(); + bool doSupportOnConditions = DoSupportOnConditions(); + bool canSupport = (!isInProfit || + (isInProfit && supportsCount > 0)) && + supportStartDistance >= 0 && + supportVolumeMultiplier > 0 && + MathAbs(profitInPoint) >= supportStartDistance && + // + // Check Delay ... + (!IsValid(mData[iDX].lastSupportedOn) + ? true + : (TimeToSeconds(currentTime) - TimeToSeconds(mData[iDX].lastSupportedOn)) >= ulong(delayBetweenTwoSupport)); + + // + result = + canTrail || + canFreeze || + canSupport || + canPartialClose; + if (!result) + { + return result; + } // int zIndex = 0; @@ -2672,36 +2790,36 @@ class X121SCTradeHandler : public XSCBaseAlert // bool isTicksBullishForLong = // - GetTickExit(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) && - GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) && - GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[3], POSITION_TYPE_BUY, position.symbol) + GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) && + GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) && + GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) // ; // bool isTicksBearishForLong = // - GetTickExit(ticks[0], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) && - GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) && - GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[3], POSITION_TYPE_BUY, position.symbol) + GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) && + GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) && + GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) // ; // bool isTicksBullishForShort = // - GetTickExit(ticks[0], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) && - GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) && - GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[3], POSITION_TYPE_SELL, position.symbol) + GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) && + GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) && + GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) // ; // bool isTicksBearishForShort = // - GetTickExit(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) && - GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) && - GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[3], POSITION_TYPE_SELL, position.symbol) + GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) && + GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) && + GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) // ; @@ -2750,524 +2868,249 @@ class X121SCTradeHandler : public XSCBaseAlert ; // - bool allowFreeze = FreezeInDrawdon(); - double freezePoint = FreezePoint(); - double freezeVolumeMultiplier = FreezeVolume(); - bool canFreeze = allowFreeze && - freezePoint > 0 && - freezeVolumeMultiplier > 0; - - // - // In Profit ... - // When a Position running in Profit, we have to look pressures by Same Direction - // of Main Position. for eaxmple if it is long, we look for Bullish Pressures and - // if it is short we look for Bearish Pressures. - // when pressure happens we must Trail position Stop ... - if (isInProfit) + // Do Trail ... + bool isTrailed = false; + if (canTrail) { // - // Do In Profit Protection Mechanism ... - - // - // Trail Stops ... - // Remove Trailed Positions TP ... - bool allowTrailStop = AllowTrailStopInProfits(); - double trailStep = TrailStopStepsInPoint(); - bool allowOnlyUnprotecteds = OnlyTrailUnprotectedPositions(); - bool isProtectionTrailPassed = !allowOnlyUnprotecteds - ? true - : supportsCount == 0; - if (allowTrailStop && trailStep > 0 && isProtectionTrailPassed) + bool hasTrailConditions = + isLong + ? (isTicksBullishForLong && + hasBullishConditions) + : (isTicksBearishForShort && + hasBearishConditions); + if (hasTrailConditions) { // - // Temp Vaiables ... - bool canTrailStop = false; + double entry = position.entry; + int lastTrailedStep = mData[iDX].trailStep; // - if (isLong) + double requiredProfit = + lastTrailedStep == 0 + ? trailStartDistance + : trailStartDistance + (lastTrailedStep * trailStep); + + // + bool isProfitsPassed = profitInPoint > requiredProfit; + if (isProfitsPassed) { // - // Check Conditions ... - canTrailStop = isTicksBullishForLong && - hasBullishConditions; - } - else - { - // - // Check Conditions ... - canTrailStop = isTicksBearishForShort && - hasBearishConditions; - } - - // - // Do Stop Trailling ... - if (canTrailStop) - { - // - int lastTrailedStep = mData[iDX].trailStep; + double delta = (requiredProfit * pointValue); // - double entry = position.entry; - double pointValue = position.GetPointsValue(); - double profitInPoint = position.GetProfitInPoint(); + double sl = + isLong + ? entry + delta + : entry - delta; // - double requiredProfit = - lastTrailedStep == 0 - ? ProtectorStartDistanceInPoint() - : ProtectorStartDistanceInPoint() + (lastTrailedStep * trailStep); + string comment = "EQM Trail Stop ..."; // - bool isProfitsPassed = profitInPoint > requiredProfit; - if (isProfitsPassed) - { - // - double delta = (requiredProfit * pointValue); - - // - double sl = - isLong - ? entry + delta - : entry - delta; - - // - string comment = "EQM Trail Stop ..."; - - // - // Try to Modify Position ... - result = mTrader.Modify( - position.ticket, - sl, - position.tp, - comment // - ); - if (result) - { - // - mData[iDX].trailStep++; - - // - string message = "EQM Trail (" + ToString(position.ticket) + ") Stop ..."; - Alert(message); - - // - XPosition trailedPosition; - bool hasPosition = mTrader.GetPosition( - position.ticket, - trailedPosition // - ); - - // - // Check Remove Trailed Positions TP Conditions ... - int removeTPOnTrailStep = RmoveTPOnTrailStep(); - if (removeTPOnTrailStep > 0 && mData[iDX].trailStep == removeTPOnTrailStep && trailedPosition.tp != 0) - { - // - string comment = "EQM Removes TP ..."; - - // - // Remove Position's TP ... - result = mTrader.Modify( - trailedPosition.ticket, - trailedPosition.sl, - 0, - comment // - ); - if (result) - { - // - string message = "EQM Removes (" + ToString(trailedPosition.ticket) + ") TP ..."; - Alert(message); - } - } - } - } - } - } - - // - bool allowRecover = AllowRecoverInDrawdowns(); - double volumeMultiplier = RecoveryMultiplier(); - if (allowRecover && !canFreeze && volumeMultiplier > 0 && supportsCount > 0) - { - // - bool canRecover = false; - int delayMinutes = RecoveryDelayInMinute(); - double recoveryDistancePoint = RecoveryDistanceInPoint(); - - // - // Temparory Requirement for Recover Signal ... - double sl = 0; - double tp = 0; - double entry = 0; - ENUM_POSITION_TYPE type = NULL; - ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; - double lastStep = mData[iDX].protectionStep; - double volume = position.volume * volumeMultiplier; - bool applyLevel = ApplyRecoveryLevelOnVolume(); - if (applyLevel) - { - // - volume = supportsCount <= 0 - ? position.volume * volumeMultiplier - : position.volume * ((supportsCount + 1) * volumeMultiplier); - } - - // - datetime currentTime = TimeCurrent(); - double currentProfit = position.GetProfitInPoint(); - datetime lastProtectedOn = mData[iDX].lastProtectedOn; - double lastProtectedProfit = mData[iDX].lastProtectedInProfit; - bool isRecoveryConditionsPassed = - // - // Check Regular Conditions ... - delayMinutes > 0 && - recoveryDistancePoint > 0 && - IsValid(lastProtectedOn) && - // - // Check Time Delay Passed ... - (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) && - // - // Check Recovery Distance Passed ... - MathAbs(currentProfit) - MathAbs(lastProtectedProfit) >= recoveryDistancePoint; - - // - if (isRecoveryConditionsPassed) - { - // - // Long Recovery ... - if (isLong) - { - // - // Same Direction ... - canRecover = - // - isTicksBullishForLong && - hasBullishTrend && - (hasBullishPower || - hasBullishPattern || - hasBullishPressure) - // - ; - if (canRecover) - { - // - sl = position.sl; - tp = position.tp; - type = POSITION_TYPE_BUY; - } - } - // - // Short Recovery ... - else - { - // - // Same Direction ... - canRecover = - // - isTicksBearishForShort && - hasBearishTrend && - (hasBearishPower || - hasBearishPattern || - hasBearishPressure) - // - ; - if (canRecover) - { - // - sl = position.sl; - tp = position.tp; - type = POSITION_TYPE_SELL; - } - } - - // - if (canRecover) - { - // - XSignal signal; - entry = GetEntry( - position.symbol, - type // - ); - - // - // Prepare Signal ... - result = signal.Prepare( - position.symbol, - position.provider, - position.period, - type, - mode, - entry, - volume, - sl, - tp // - ); - - // - if (result) - { - // - // Generate Comment for Recover and Support ... - string comment = GenerateSupportTag(position.ticket); - - // - signal.comment = comment; - - // - ENUM_X_SIGNAL_EXECUTION_RESULT state; - result = ExecuteSignal( - signal, - state, - true // Support Signal need to Ignore Policies ... - ); - if (result) - { - // - mData[iDX].protectionStep++; - mData[iDX].lastProtectedOn = currentTime; - mData[iDX].lastProtectedInProfit = currentProfit; - - // - string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " + - ToString(lastStep + 1) + - " for (" + ToString(position.ticket) + ")"; - Alert(message); - } - } - } - } - } - - // - // Check Points of Profit and Do Partial Closing ... - double partialCloseVolume = PartialCloseVolumeInProfit(); - double partialCloseProfitPoint = PartialCloseOnSpecificPointOfProfit(); - if (partialCloseVolume > 0 && partialCloseProfitPoint > 0) - { - // - double profitPoints = position.GetProfitInPoint(); - if (profitPoints >= partialCloseProfitPoint && !mData[iDX].partiallyClosed) - { - // - string comment = "EQM Partial Close ..."; - - // - // Do Partial Closing ... - result = mTrader.ClosePartial( + // Try to Modify Position ... + isTrailed = mTrader.Modify( position.ticket, - partialCloseVolume, + sl, + position.tp, comment // ); - if (result) + if (isTrailed) { // - mData[iDX].partiallyClosed = true; + mData[iDX].trailStep++; // - string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + string message = "EQM Trail (" + ToString(position.ticket) + ") Stop in Level: " + ToString(mData[iDX].trailStep) + " ..."; Alert(message); } } } } + // - // In Drawdown ... - // When a Position running in Drawdown, we have to look for pressures by Indirection - // of Main Position. for example if it is long, we Look For Bearish Pressures and if - // it is short we Look for Bullish Pressure. - // when indirectional pressure found we must Open a Recovery Position. - // also if Same Direction Pressure Found we try to Recover Same Direction using Grid ... - else + // Do Partial Close ... + bool isPartialClosed = false; + if (canPartialClose) { // - bool allowRecover = AllowRecoverInDrawdowns(); - double volumeMultiplier = RecoveryMultiplier(); - if (allowRecover && !canFreeze && volumeMultiplier > 0) + string comment = "EQM Partial Close ..."; + + // + // Do Partial Closing ... + isPartialClosed = mTrader.ClosePartial( + position.ticket, + partialCloseVolume, + comment // + ); + if (isPartialClosed) { // - bool canRecover = false; - int delayMinutes = RecoveryDelayInMinute(); - double recoveryDistancePoint = RecoveryDistanceInPoint(); + mData[iDX].partiallyClosed = true; // - // Temparory Requirement for Recover Signal ... - double sl = 0; - double tp = 0; - double entry = 0; - ENUM_POSITION_TYPE type = NULL; - ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; - double lastStep = mData[iDX].protectionStep; - double volume = position.volume * volumeMultiplier; - bool applyLevel = ApplyRecoveryLevelOnVolume(); - if (applyLevel) + string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ") ..."; + Alert(message); + } + } + + // + // Freeze ... + bool isFreezed = false; + if (canFreeze) + { + // + // Temparory Requirement for Recover Signal ... + double sl = removeFreezedPositionTPSL ? 0 : position.tp; + double tp = removeFreezedPositionTPSL ? 0 : position.sl; + ENUM_POSITION_TYPE type = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + double entry = GetEntry( + position.symbol, + type // + ); + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + + // + // Prepare Signal ... + XSignal signal; + bool isPrepared = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + position.volume, + sl, + tp // + ); + + // + if (isPrepared) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + bool isFreezed = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (isFreezed) { // - volume = supportsCount <= 0 - ? position.volume * volumeMultiplier - : position.volume * ((supportsCount + 1) * volumeMultiplier); - } - - // - datetime currentTime = TimeCurrent(); - double currentDrawdown = position.GetProfitInPoint(); - datetime lastProtectedOn = mData[iDX].lastProtectedOn; - double lastProtectedDrawdown = mData[iDX].lastProtectedInDrawdown; - bool isRecoveryConditionsPassed = supportsCount <= 0 - ? true - : - // - // Check Regular Conditions ... - delayMinutes > 0 && - recoveryDistancePoint > 0 && - IsValid(lastProtectedOn) && - lastProtectedDrawdown < 0 && - // - // Check Time Delay Passed ... - (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) && - // - // Check Recovery Distance Passed ... - MathAbs(currentDrawdown) - MathAbs(lastProtectedDrawdown) >= recoveryDistancePoint; - - // - if (isRecoveryConditionsPassed) - { - // - // Long Recovery ... - if (isLong) - { - // - // Opposit Direction ... - canRecover = - // - isTicksBearishForShort && - hasBearishTrend && - (hasBearishPower || - hasBearishPattern || - hasBearishPressure) - // - ; - if (canRecover) - { - // - sl = position.tp; - tp = position.sl; - type = POSITION_TYPE_SELL; - } - } - // - // Short Recovery ... - else - { - // - // Opposit Direction ... - canRecover = - // - isTicksBullishForLong && - hasBullishTrend && - (hasBullishPower || - hasBullishPattern || - hasBullishPressure) - // - ; - if (canRecover) - { - // - sl = position.tp; - tp = position.sl; - type = POSITION_TYPE_BUY; - } - } + mData[iDX].freezed = true; // - if (canRecover) + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Freeze Position for (" + ToString(position.ticket) + ") ..."; + Alert(message); + + // + if (removeFreezedPositionTPSL) { // - XSignal signal; - entry = GetEntry( - position.symbol, - type // + string comment = "EQM Removes Freezed TP/SL ..."; + bool isModified = mTrader.Modify( + position.ticket, + 0, + 0, + comment // ); // - // Prepare Signal ... - result = signal.Prepare( - position.symbol, - position.provider, - position.period, - type, - mode, - entry, - volume, - sl, - tp // - ); - - // - if (result) + if (isModified) { // - // Generate Comment for Recover and Support ... - string comment = GenerateSupportTag(position.ticket); - - // - signal.comment = comment; - - // - ENUM_X_SIGNAL_EXECUTION_RESULT state; - result = ExecuteSignal( - signal, - state, - true // Support Signal need to Ignore Policies ... - ); - if (result) - { - // - mData[iDX].protectionStep++; - mData[iDX].lastProtectedOn = currentTime; - mData[iDX].lastProtectedInDrawdown = currentDrawdown; - - // - string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " + - ToString(lastStep + 1) + - " for (" + ToString(position.ticket) + ")"; - Alert(message); - } + string message = "EQM Remove Freezed Position (" + ToString(position.ticket) + ") TP/SL ..."; + Alert(message); } } } } + } + + // + // Support ... + bool isSupported = false; + if (canSupport) + { + // + // supportsCount + // bool isDistancePassed = + // supportStartDistance <= 0 + // ? true + // : mData[iDX].lastSupportDistance < 0 + // ? profitInPoint < 0 && (true) + // : profitInPoint > 0 && (true); // - if (canFreeze && - supportsCount <= 0 && - position.profit < 0 && - !mData[iDX].freezed && - MathAbs(profitInPoint) >= freezePoint) + bool hasLongSupportCondition = !doSupportOnConditions + ? true + : (isTicksBullishForLong && + hasBullishConditions); + + // + bool hasShortSupportConditions = !doSupportOnConditions + ? true + : (isTicksBearishForShort && + hasBearishConditions); + + // + bool hasSupportConditions = + !doSupportOnConditions + ? true + : (hasLongSupportCondition || + hasShortSupportConditions); + if (hasSupportConditions) { - // - bool removeTPSL = RemoveFreezedPositionsTPSL(); // // Temparory Requirement for Recover Signal ... - double sl = removeTPSL ? 0 : position.tp; - double tp = removeTPSL ? 0 : position.sl; - ENUM_POSITION_TYPE type = isLong - ? POSITION_TYPE_SELL - : POSITION_TYPE_BUY; + double sl = + isLong + ? hasLongSupportCondition + ? position.sl + : position.tp + : hasLongSupportCondition + ? position.tp + : position.sl; + double tp = + isLong + ? hasLongSupportCondition + ? position.tp + : position.sl + : hasLongSupportCondition + ? position.sl + : position.tp; + ENUM_POSITION_TYPE type = + hasLongSupportCondition + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; double entry = GetEntry( position.symbol, type // ); ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; - double volume = position.volume * freezeVolumeMultiplier; - - // - XSignal signal; + double volume = position.volume * supportVolumeMultiplier; + if (multiplySupportLevelOnVolume) + { + // + volume = supportsCount <= 0 + ? position.volume * supportVolumeMultiplier + : position.volume * ((supportsCount + 1) * supportVolumeMultiplier); + } // // Prepare Signal ... - result = signal.Prepare( + XSignal signal; + bool isPrepared = signal.Prepare( position.symbol, position.provider, position.period, @@ -3280,7 +3123,7 @@ class X121SCTradeHandler : public XSCBaseAlert ); // - if (result) + if (isPrepared) { // // Generate Comment for Recover and Support ... @@ -3291,73 +3134,35 @@ class X121SCTradeHandler : public XSCBaseAlert // ENUM_X_SIGNAL_EXECUTION_RESULT state; - result = ExecuteSignal( + bool isSupported = ExecuteSignal( signal, state, true // Support Signal need to Ignore Policies ... ); - if (result) + if (isSupported) { // - mData[iDX].freezed = true; + mData[iDX].supportLevel++; + mData[iDX].lastSupportedOn = currentTime; + mData[iDX].lastSupportDistance = profitInPoint; // - string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Freeze Position for (" + ToString(position.ticket) + ")"; - Alert(message); - - // - string comment = "EQM Removes Freezed TP/SL ..."; - result = mTrader.Modify( - position.ticket, - 0, - 0, - comment // - ); - - // - if (result) - { - // - string message = "EQM Remove Freezed Position (" + ToString(position.ticket) + ") TP/SL .."; - Alert(message); - } - } - } - } - - // - // Check Points of Drawdown and Do Partial Closing ... - double partialCloseVolume = PartialCloseVolumeInDrawdown(); - double partialCloseDrawdownPoint = PartialCloseOnSpecificPointOfDrawdown(); - if (partialCloseVolume > 0 && partialCloseDrawdownPoint > 0) - { - // - double profitPoints = position.GetProfitInPoint(); - if (profitPoints < 0 && MathAbs(profitPoints) >= partialCloseDrawdownPoint && !mData[iDX].partiallyClosed) - { - // - string comment = "EQM Partial Close ..."; - - // - // Do Partial Closing ... - result = mTrader.ClosePartial( - position.ticket, - partialCloseVolume, - comment // - ); - if (result) - { - // - mData[iDX].partiallyClosed = true; - - // - string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Support Position in Level: " + + ToString(mData[iDX].supportLevel) + + " for (" + ToString(position.ticket) + ") ..."; Alert(message); } } } } + // + result = + isTrailed || + isFreezed || + isSupported || + isPartialClosed; + // return result; } @@ -3367,6 +3172,7 @@ class X121SCTradeHandler : public XSCBaseAlert private: // // Props ... + double mAdditionalVolume; // Volume Additional // // Read Only ... @@ -3389,31 +3195,46 @@ class X121SCTradeHandler : public XSCBaseAlert double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades // - int mDelayBarBetweenTwoSameSignal; // Delay Bars Between Two Same Type Signal - double mProtectorStartDistanceInPoint; // Protector Start Distance in Point + int mDelayBarBetweenTwoSameSignal; // Delay Bars Between Two Same Type Signal // // In Profit Positions Protecting ... - bool mAllowTrailStopInProfits; // Allow Trail Stops for In Profit Positions - bool mOnlyTrailUnprotectedPositions; // Only Trail UnProtected Positions - double mTrailStopStepsInPoint; // Trail Stop Steps in Point - int mRmoveTPOnTrailStep; // Remove Position TP if Trailed specific times - double mPartialCloseOnSpecificPointOfProfit; // Partial Close Position on Specific Points of Profit - double mPartialCloseVolumeInProfit; // Partial Close Volume + + // + // Trail ... + bool mAllowTrail; // Allow Trail Stop for Positions + double mTrailStartDistance; // Specify Trail Start in Point + double mTrailStep; // Trail Step in Point + bool mOnlyTrailUnprotected; // Only Trail Unprotected Positionss + + // + // Partial Close (In Profit) ... + double mPartialCloseInProfitDistance; // Specify Partial Close Profit in Point + double mPartialCloseInProfitVolume; // Specify Partial Close in Profit Volume // // In Drawdown Positions Protecting ... - bool mFreezeInDrawdon; // Freeze In Drawdown Position by Lock it - double mFreezePoint; // Freezing Drawdown Point - double mFreezeVolume; // Freezing Volume Multiplier - bool mRemoveFreezedPositionsTPSL; // Removes Freezed Positions TP and SL - bool mAllowRecoverInDrawdowns; // Allow Recovery For In Drawdown Positions - double mRecoveryMultiplier; // Recovery Volume Multiplier - bool mApplyRecoveryLevelOnVolume; // Apply Recovery Level on Volume Calculation - int mRecoveryDelayInMinute; // Delay Between Two Recovery in Minutes - double mRecoveryDistanceInPoint; // Distance Between Two Recovery in Point - double mPartialCloseOnSpecificPointOfDrawdown; // Partial Close Position on Specific Points of Drawdown - double mPartialCloseVolumeInDrawdown; // Partial Close Volume + + // + // Freeze ... + bool mAllowFreeze; // Allow Freezing + double mFreezeDistance; // Specify Freeze Start Drawdown in Point + bool mRemoveFreezedPositionTPSL; // Remove Freezed Positions TPSL + bool mDisableTrailWhenFreezedPosition; // Disable Trail when has Freezed Position + + // + // Support ... + bool mAllowSupport; // Allow Support + double mSupportStartDistance; // Specify Start Support Drawdown in Point + double mSupportVolumeMultiplier; // Specify Support Volume Multiplier + bool mMultiplySupportLevelOnVolume; // Multiply Support Level on Volume Multiplier + bool mDoSupportOnConditions; // Do Support on Conditions + int mDelayBetweenTwoSupport; // Delay Between To Support in Second + + // + // Partial Close (In Drawdown) ... + double mPartialCloseInDrawdownDistance; // Specify Partial Close Drawdown in Point + double mPartialCloseInDrawdownVolume; // Specify Partial Close in Drawdown Volume // // Hedging Properties ... diff --git a/Documents/BKP/protection-conditions.txt b/Documents/BKP/protection-conditions.txt new file mode 100644 index 00000000..dffae9f6 --- /dev/null +++ b/Documents/BKP/protection-conditions.txt @@ -0,0 +1,200 @@ + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + // Last Bar ... + XOHCL cBar; + result = cBar.Init( + position.symbol, + position.period, + cIndex // + ); + 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; + } + + // + // 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 + // + ; + + // + // Define Conditions ... + MqlTick ticks[]; + int ticksCount = CopyTicks( + position.symbol, + ticks, + COPY_TICKS_ALL, + 0, + 5 // + ); + + // + // TODO: Check Volume if Required ... + + // + bool isTicksBullishForLong = + // + GetTickExit(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[3], POSITION_TYPE_BUY, position.symbol) + // + ; + + // + bool isTicksBearishForLong = + // + GetTickExit(ticks[0], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[3], POSITION_TYPE_BUY, position.symbol) + // + ; + + // + bool isTicksBullishForShort = + // + GetTickExit(ticks[0], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[3], POSITION_TYPE_SELL, position.symbol) + // + ; + + // + bool isTicksBearishForShort = + // + GetTickExit(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[3], POSITION_TYPE_SELL, position.symbol) + // + ; + + // + bool hasBullishDecision = + // + cBar.IsBullishDecision() + // + ; + + // + bool hasBearishDecision = + // + cBar.IsBearishDecision() + // + ; + + // + bool hasBullishConditions = + // + ( + // + hasBullishTrend && + hasBullishDecision && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ) + // + ; + + // + bool hasBearishConditions = + // + ( + // + hasBearishTrend && + hasBearishDecision && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ) + // + ; diff --git a/Documents/BKP/protection.txt b/Documents/BKP/protection.txt new file mode 100644 index 00000000..64ee7c19 --- /dev/null +++ b/Documents/BKP/protection.txt @@ -0,0 +1,601 @@ + + // + // In Profit ... + // When a Position running in Profit, we have to look pressures by Same Direction + // of Main Position. for eaxmple if it is long, we look for Bullish Pressures and + // if it is short we look for Bearish Pressures. + // when pressure happens we must Trail position Stop ... + if (isInProfit) + { + // + // Do In Profit Protection Mechanism ... + + // + // Trail Stops ... + // Remove Trailed Positions TP ... + bool allowTrailStop = AllowTrailStopInProfits(); + double trailStep = TrailStopStepsInPoint(); + bool allowOnlyUnprotecteds = OnlyTrailUnprotectedPositions(); + bool isProtectionTrailPassed = !allowOnlyUnprotecteds + ? true + : supportsCount == 0; + if (allowTrailStop && trailStep > 0 && isProtectionTrailPassed) + { + // + // Temp Vaiables ... + bool canTrailStop = false; + + // + if (isLong) + { + // + // Check Conditions ... + canTrailStop = isTicksBullishForLong && + hasBullishConditions; + } + else + { + // + // Check Conditions ... + canTrailStop = isTicksBearishForShort && + hasBearishConditions; + } + + // + // Do Stop Trailling ... + if (canTrailStop) + { + // + int lastTrailedStep = mData[iDX].trailStep; + + // + double entry = position.entry; + double pointValue = position.GetPointsValue(); + double profitInPoint = position.GetProfitInPoint(); + + // + double requiredProfit = + lastTrailedStep == 0 + ? ProtectorStartDistanceInPoint() + : ProtectorStartDistanceInPoint() + (lastTrailedStep * trailStep); + + // + bool isProfitsPassed = profitInPoint > requiredProfit; + if (isProfitsPassed) + { + // + double delta = (requiredProfit * pointValue); + + // + double sl = + isLong + ? entry + delta + : entry - delta; + + // + string comment = "EQM Trail Stop ..."; + + // + // Try to Modify Position ... + result = mTrader.Modify( + position.ticket, + sl, + position.tp, + comment // + ); + if (result) + { + // + mData[iDX].trailStep++; + + // + string message = "EQM Trail (" + ToString(position.ticket) + ") Stop ..."; + Alert(message); + + // + XPosition trailedPosition; + bool hasPosition = mTrader.GetPosition( + position.ticket, + trailedPosition // + ); + + // + // Check Remove Trailed Positions TP Conditions ... + int removeTPOnTrailStep = RmoveTPOnTrailStep(); + if (removeTPOnTrailStep > 0 && mData[iDX].trailStep == removeTPOnTrailStep && trailedPosition.tp != 0) + { + // + string comment = "EQM Removes TP ..."; + + // + // Remove Position's TP ... + result = mTrader.Modify( + trailedPosition.ticket, + trailedPosition.sl, + 0, + comment // + ); + if (result) + { + // + string message = "EQM Removes (" + ToString(trailedPosition.ticket) + ") TP ..."; + Alert(message); + } + } + } + } + } + } + + // + bool allowRecover = AllowRecoverInDrawdowns(); + double volumeMultiplier = RecoveryMultiplier(); + if (allowRecover && !canFreeze && volumeMultiplier > 0 && supportsCount > 0) + { + // + bool canRecover = false; + int delayMinutes = RecoveryDelayInMinute(); + double recoveryDistancePoint = RecoveryDistanceInPoint(); + + // + // Temparory Requirement for Recover Signal ... + double sl = 0; + double tp = 0; + double entry = 0; + ENUM_POSITION_TYPE type = NULL; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + double lastStep = mData[iDX].protectionStep; + double volume = position.volume * volumeMultiplier; + bool applyLevel = ApplyRecoveryLevelOnVolume(); + if (applyLevel) + { + // + volume = supportsCount <= 0 + ? position.volume * volumeMultiplier + : position.volume * ((supportsCount + 1) * volumeMultiplier); + } + + // + datetime currentTime = TimeCurrent(); + double currentProfit = position.GetProfitInPoint(); + datetime lastProtectedOn = mData[iDX].lastProtectedOn; + double lastProtectedProfit = mData[iDX].lastProtectedInProfit; + bool isRecoveryConditionsPassed = + // + // Check Regular Conditions ... + delayMinutes > 0 && + recoveryDistancePoint > 0 && + IsValid(lastProtectedOn) && + // + // Check Time Delay Passed ... + (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) && + // + // Check Recovery Distance Passed ... + MathAbs(currentProfit) - MathAbs(lastProtectedProfit) >= recoveryDistancePoint; + + // + if (isRecoveryConditionsPassed) + { + // + // Long Recovery ... + if (isLong) + { + // + // Same Direction ... + canRecover = + // + isTicksBullishForLong && + hasBullishTrend && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ; + if (canRecover) + { + // + sl = position.sl; + tp = position.tp; + type = POSITION_TYPE_BUY; + } + } + // + // Short Recovery ... + else + { + // + // Same Direction ... + canRecover = + // + isTicksBearishForShort && + hasBearishTrend && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ; + if (canRecover) + { + // + sl = position.sl; + tp = position.tp; + type = POSITION_TYPE_SELL; + } + } + + // + if (canRecover) + { + // + XSignal signal; + entry = GetEntry( + position.symbol, + type // + ); + + // + // Prepare Signal ... + result = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + volume, + sl, + tp // + ); + + // + if (result) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (result) + { + // + mData[iDX].protectionStep++; + mData[iDX].lastProtectedOn = currentTime; + mData[iDX].lastProtectedInProfit = currentProfit; + + // + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " + + ToString(lastStep + 1) + + " for (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + } + + // + // Check Points of Profit and Do Partial Closing ... + double partialCloseVolume = PartialCloseVolumeInProfit(); + double partialCloseProfitPoint = PartialCloseOnSpecificPointOfProfit(); + if (partialCloseVolume > 0 && partialCloseProfitPoint > 0) + { + // + double profitPoints = position.GetProfitInPoint(); + if (profitPoints >= partialCloseProfitPoint && !mData[iDX].partiallyClosed) + { + // + string comment = "EQM Partial Close ..."; + + // + // Do Partial Closing ... + result = mTrader.ClosePartial( + position.ticket, + partialCloseVolume, + comment // + ); + if (result) + { + // + mData[iDX].partiallyClosed = true; + + // + string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + // + // In Drawdown ... + // When a Position running in Drawdown, we have to look for pressures by Indirection + // of Main Position. for example if it is long, we Look For Bearish Pressures and if + // it is short we Look for Bullish Pressure. + // when indirectional pressure found we must Open a Recovery Position. + // also if Same Direction Pressure Found we try to Recover Same Direction using Grid ... + else + { + // + bool allowRecover = AllowRecoverInDrawdowns(); + double volumeMultiplier = RecoveryMultiplier(); + if (allowRecover && !canFreeze && volumeMultiplier > 0) + { + // + bool canRecover = false; + int delayMinutes = RecoveryDelayInMinute(); + double recoveryDistancePoint = RecoveryDistanceInPoint(); + + // + // Temparory Requirement for Recover Signal ... + double sl = 0; + double tp = 0; + double entry = 0; + ENUM_POSITION_TYPE type = NULL; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + double lastStep = mData[iDX].protectionStep; + double volume = position.volume * volumeMultiplier; + bool applyLevel = ApplyRecoveryLevelOnVolume(); + if (applyLevel) + { + // + volume = supportsCount <= 0 + ? position.volume * volumeMultiplier + : position.volume * ((supportsCount + 1) * volumeMultiplier); + } + + // + datetime currentTime = TimeCurrent(); + double currentDrawdown = position.GetProfitInPoint(); + datetime lastProtectedOn = mData[iDX].lastProtectedOn; + double lastProtectedDrawdown = mData[iDX].lastProtectedInDrawdown; + bool isRecoveryConditionsPassed = supportsCount <= 0 + ? true + : + // + // Check Regular Conditions ... + delayMinutes > 0 && + recoveryDistancePoint > 0 && + IsValid(lastProtectedOn) && + lastProtectedDrawdown < 0 && + // + // Check Time Delay Passed ... + (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) && + // + // Check Recovery Distance Passed ... + MathAbs(currentDrawdown) - MathAbs(lastProtectedDrawdown) >= recoveryDistancePoint; + + // + if (isRecoveryConditionsPassed) + { + // + // Long Recovery ... + if (isLong) + { + // + // Opposit Direction ... + canRecover = + // + isTicksBearishForShort && + hasBearishTrend && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ; + if (canRecover) + { + // + sl = position.tp; + tp = position.sl; + type = POSITION_TYPE_SELL; + } + } + // + // Short Recovery ... + else + { + // + // Opposit Direction ... + canRecover = + // + isTicksBullishForLong && + hasBullishTrend && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ; + if (canRecover) + { + // + sl = position.tp; + tp = position.sl; + type = POSITION_TYPE_BUY; + } + } + + // + if (canRecover) + { + // + XSignal signal; + entry = GetEntry( + position.symbol, + type // + ); + + // + // Prepare Signal ... + result = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + volume, + sl, + tp // + ); + + // + if (result) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (result) + { + // + mData[iDX].protectionStep++; + mData[iDX].lastProtectedOn = currentTime; + mData[iDX].lastProtectedInDrawdown = currentDrawdown; + + // + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " + + ToString(lastStep + 1) + + " for (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + } + + // + if (canFreeze && + supportsCount <= 0 && + position.profit < 0 && + !mData[iDX].freezed && + MathAbs(profitInPoint) >= freezePoint) + { + // + bool removeTPSL = RemoveFreezedPositionsTPSL(); + // + // Temparory Requirement for Recover Signal ... + double sl = removeTPSL ? 0 : position.tp; + double tp = removeTPSL ? 0 : position.sl; + ENUM_POSITION_TYPE type = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + double entry = GetEntry( + position.symbol, + type // + ); + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + double volume = position.volume * freezeVolumeMultiplier; + + // + XSignal signal; + + // + // Prepare Signal ... + result = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + volume, + sl, + tp // + ); + + // + if (result) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (result) + { + // + mData[iDX].freezed = true; + + // + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Freeze Position for (" + ToString(position.ticket) + ")"; + Alert(message); + + // + string comment = "EQM Removes Freezed TP/SL ..."; + result = mTrader.Modify( + position.ticket, + 0, + 0, + comment // + ); + + // + if (result) + { + // + string message = "EQM Remove Freezed Position (" + ToString(position.ticket) + ") TP/SL .."; + Alert(message); + } + } + } + } + + // + // Check Points of Drawdown and Do Partial Closing ... + double partialCloseVolume = PartialCloseVolumeInDrawdown(); + double partialCloseDrawdownPoint = PartialCloseOnSpecificPointOfDrawdown(); + if (partialCloseVolume > 0 && partialCloseDrawdownPoint > 0) + { + // + double profitPoints = position.GetProfitInPoint(); + if (profitPoints < 0 && MathAbs(profitPoints) >= partialCloseDrawdownPoint && !mData[iDX].partiallyClosed) + { + // + string comment = "EQM Partial Close ..."; + + // + // Do Partial Closing ... + result = mTrader.ClosePartial( + position.ticket, + partialCloseVolume, + comment // + ); + if (result) + { + // + mData[iDX].partiallyClosed = true; + + // + string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } diff --git a/Documents/BKP/x-saherelm.x121.ea.mq5 b/Documents/BKP/x-saherelm.x121.ea.mq5 new file mode 100644 index 00000000..f807d1d2 --- /dev/null +++ b/Documents/BKP/x-saherelm.x121.ea.mq5 @@ -0,0 +1,1035 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: X121EA +// Description: an Exper Advisor which used to +// XCH and XCHCHE Strategy to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121EA" +#property strict + +// +#define ShortName "X121EA" + +// +// Imports ... +#include "../Classes/x-saherelm.x121.xtrade.handler.class.mq5" +#include "../Helpers/x-saherelm.xcc.helper.mq5" +#include "../Helpers/x-saherelm.xct.helper.mq5" + +// +#include "../Parsers/x-saherelm.xch.parser.mq5" +#include "../Strategies/x-saherelm.xch.strategy.mq5" + +// +#include "../Parsers/x-saherelm.xch.che.parser.mq5" +#include "../Strategies/x-saherelm.xch.che.strategy.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +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 bool eaUseMaxAllowedTradesPerSymbol = true; // Use Max Allowed Trades Per Symbol +input string eaSymbols = "EURUSDb,GBPUSDb,EURGBPb,USDJPYb,EURJPYb,USDCHFb,EURCHFb,AUDUSDb,EURAUDb,NZDUSDb,EURNZDb,USDCADb,EURCADb,XAUUSDb,XAGUSDb,BRENT,DowJones30"; // Trading Symbols + +// +// Risk Management ... +input group "Risk Management"; + +// +// Risk Management > Risk / Reward Calculation ... +input group "Risk/Reward"; +input bool eaIgnoreTP = false; // Ignore TP +input bool eaIgnoreSL = false; // Ignore SL +input double eaTPPoint = 200; // Static TP Point +input double eaSLPoint = 200; // Static SL Point + +// +// Risk Management > Volume Calculation ... +input group "Volume"; +input bool eaUseDynamicVolume = false; // Use Dynamic Volume +input double eaDynamicVolumeStep = 0.01; // Increase Volume Step +input double eaDynamicVolumeBalanceFactor = 200; // Balance Factor for Generate Dynamic Volume +input double eaVolume = 0.01; // Static Volume + +// +// Risk Management > Trade Management ... +input group "Trade Management"; +input bool eaAllowLong = true; // Allow Long Positions +input bool eaAllowShort = true; // Allow Short Positions +input int eaMaxAllowedLongs = 2; // Max Allowed Long Positions +input int eaMaxAllowedShorts = 2; // Max Allowed Short Positions +input double eaMaxDrawdownPercentForOpenTrades = 3; // Max Drawdown Percent for Open Trades + +// +// Protector ... +input group "Protector"; +input int eaDelayBarBetweenTwoSameSignal = 5; // Delay Bars Between Two Same Type Signal +input double eaProtectorStartDistanceInPoint = 35; // Protector Start Distance in Point + +// +// Protector > Hedging Properties ... +input group "Hedging"; +input bool eaAllowHedge = true; // Allow Protector to Hedge Positions +input double eaHedgeMinVolumeStep = 0.01; // Minimum Volume Step For Hedge +input int eaMinimumOpenPositionsForHEHedge = 2; // Minimum Open Positions For HE Hedge +input double eaHedgeHEMinProfitPerVolumeStep = 1; // Minimum Required Profit For HE Hedge Per Volume Step +input double eaHedgeBEMinProfitPerVolumeStep = 0.1; // Minimum Required Profit For BE Hedge Per Volume Step + +// +// Protector > In Profit Positions Protecting ... +input group "In Profit Positions Protecting"; +input bool eaAllowTrailStopInProfits = true; // Allow Trail Stops for In Profit Positions +input bool eaOnlyTrailUnprotectedPositions = true; // Only Trail UnProtected Positions +input double eaTrailStopStepsInPoint = 10; // Trail Stop Steps in Point +input int eaRmoveTPOnTrailStep = 5; // Remove Position TP if Trailed specific times +input double eaPartialCloseOnSpecificPointOfProfit = 0; // Partial Close Position on Specific Points of Profit +input double eaPartialCloseVolumeInProfit = 0; // Partial Close Volume + +// +// Protector > In Drawdown Positions Protecting ... +input group "In Drawdown Positions Protecting"; +input bool eaFreezeInDrawdon = true; // Freeze In Drawdown Position by Lock it +input double eaFreezePoint = 100; // Freezing Drawdown Point +input double eaFreezeVolume = 2; // Freezing Volume Multiplier +input bool eaRemoveFreezedPositionsTPSL = true; // Removes Freezed Positions TP and SL +input bool eaAllowRecoverInDrawdowns = false; // Allow Recovery For In Drawdown Positions +input double eaRecoveryMultiplier = 1; // Recovery Volume Multiplier +input bool eaApplyRecoveryLevelOnVolume = false; // Apply Recovery Level on Volume Calculation +input int eaRecoveryDelayInMinute = 1; // Delay Between Two Recovery in Minutes +input double eaRecoveryDistanceInPoint = 30; // Distance Between Two Recovery in Point +input double eaPartialCloseOnSpecificPointOfDrawdown = 0; // Partial Close Position on Specific Points of Drawdown +input double eaPartialCloseVolumeInDrawdown = 0; // Partial Close Volume + +// +// Alert ... +input group "Alert"; +input bool eAEnableAlerts = true; // Enable Alerts +input bool eALogAlerts = true; // Log Alerts +input bool eAMailAlerts = false; // Mail Alerts +input bool eAPushAlerts = false; // Push Alerts +input bool eATerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaAlertNewMonths = false; // Alert New Month +input bool eaAlertNewWeeks = false; // Alert New Weeks +input bool eaAlertNewDays = true; // Alert New Days +input bool eaAlertNewHours = false; // Alert New Hours +input bool eaAlertRawSignals = false; // Alert Raw Signals +input bool eaAlertStrongSignals = false; // Alert Strong Signals + +// +// Variables ... + +// +// Bar Style nad Time Instances ... +XSCXCTHelper *mCTHelper; +XSCXCCHelper *mCCHelper; + +// +// Registred Strategies ... +XSCBaseStrategy *strategies[]; + +// +// Trader Instance Class ... +XSCTrade *eaTrader; + +// +// Alert Class ... +XSCAlert *eaAlert; + +// +// Time Tracker ... +XTimeTracker eaTimeTracker; + +// +// Trade Handler Instance Class ... +X121SCTradeHandler *eaTradeHandler; + +// +string mTag = ""; + +// +double eaR2R = 1.5; +bool eaUseFixedTPSLPoints = true; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + if (!InitialEA()) + { + return INIT_FAILED; + } + + // + mTag = + !IsValid(eaLogSuffix) + ? ShortName + : ShortName + "_" + eaLogSuffix; + + // + drawPrefix = mTag; + + // + // EventSetTimer(1); + // EventSetMillisecondTimer(100); + + // + // Alert Initialization ... + string msg = "Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + eaAlert.Alert(msg); + + // + // De Initialize XSampleEA Providers ... + delete mCTHelper; + delete mCCHelper; + + // + delete eaAlert; + delete eaTrader; + delete eaTradeHandler; + + // + Clean(strategies); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + HandleTradeState(); + HandleTimeReport(); + HandleStrategiesOnTick(); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrader.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + // + // HandleTradeState(); + // HandleTimeReport(); + // HandleStrategiesOnTick(); +} + +// +// Custom Functions ... + +// +// Validate Inputs ... +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + bool isSymbolsValid = ( + // + eaMultiSymbol + ? IsValid(eaSymbols) + : true + // + ); + if (!isSymbolsValid) + { + // + errMessage += "symbols configurations error;" + "\n"; + } + + // + bool isRiskRewardValid = ( + // + (eaUseFixedTPSLPoints + ? eaTPPoint > 0 || + eaSLPoint > 0 + : eaR2R > 0) && + !(eaIgnoreTP && + eaIgnoreSL) + // + ); + if (!isRiskRewardValid) + { + // + errMessage += "risk/reward configurations error;" + "\n"; + } + + // + bool isVolumeValid = ( + // + eaUseDynamicVolume + ? eaDynamicVolumeStep >= 0.01 && + eaDynamicVolumeBalanceFactor > 0 + : eaVolume >= 0.01 + // + ); + if (!isVolumeValid) + { + // + errMessage += "volume configurations error;" + "\n"; + } + + // + bool isTradeManagementValid = ( + // + !(!eaAllowLong && !eaAllowShort) && + eaMaxAllowedLongs >= 0 && + eaMaxAllowedShorts >= 0 + // + ); + if (!isTradeManagementValid) + { + // + errMessage += "trade management configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Symbols ... + isSymbolsValid && + // + // Risk/Reward ... + isRiskRewardValid && + // + // Volume ... + isVolumeValid && + // + // Trade Management ... + isTradeManagementValid + // + ; + + // + if (!result) + { + Print("Errors: \n", errMessage); + } + + // + return result; +} + +// +// Initialize all Requirements ... +bool InitialEA() +{ + // + bool result = false; + + // + // Bar Timer ... + XCTInputs ctInputs; + ctInputs.Default(); + mCTHelper = new XSCXCTHelper(); + result = mCTHelper.Init( + _Symbol, + _Period, + ctInputs // + ); + if (!result) + { + return result; + } + + // + // Bar Styles ... + XCCInputs ccInputs; + ccInputs.Default(); + mCCHelper = new XSCXCCHelper(); + result = mCCHelper.Init( + _Symbol, + _Period, + ccInputs // + ); + if (!result) + { + return result; + } + + // + // Create Instance of Alert Class ... + eaAlert = new XSCAlert(); + eaAlert.SetPrefix(mTag); + eaAlert.SetLogAlerts(eALogAlerts); + eaAlert.SetMailAlerts(eAMailAlerts); + eaAlert.SetPushAlerts(eAPushAlerts); + eaAlert.SetEnableAlerts(eAEnableAlerts); + eaAlert.SetTerminalAlerts(eATerminalAlerts); + + // + // Create Trader Instance ... + eaTrader = new XSCTrade( + eaSlippage, + eaMagicNumber // + ); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // + // Initialize Trade Handler ... + eaTradeHandler = new X121SCTradeHandler(eaTrader); + eaTradeHandler.SaveTrades(true); + eaTradeHandler.SaveSignals(true); + eaTradeHandler.SaveConditions(true); + + // + // Configure Alerts ... + eaTradeHandler.SetAlertPrefix(mTag); + eaTradeHandler.SetAlertEnableAlerts(eAEnableAlerts); + eaTradeHandler.SetAlertLogAlerts(eALogAlerts); + eaTradeHandler.SetAlertMailAlerts(eAMailAlerts); + eaTradeHandler.SetAlertPushAlerts(eAPushAlerts); + eaTradeHandler.SetAlertTerminalAlerts(eATerminalAlerts); + + // + // Configure Trade Management ... + eaTradeHandler.AllowLong(eaAllowLong); + eaTradeHandler.AllowShort(eaAllowShort); + eaTradeHandler.MaxAllowedLongs(eaMaxAllowedLongs); + eaTradeHandler.MaxAllowedShorts(eaMaxAllowedShorts); + eaTradeHandler.UseMaxAllowedTradesPerSymbol(eaUseMaxAllowedTradesPerSymbol); + eaTradeHandler.MaxDrawdownPercentForOpenTrades(eaMaxDrawdownPercentForOpenTrades); + + // + // Configure Position Protector ... + + // + eaTradeHandler.DelayBarBetweenTwoSameSignal(eaDelayBarBetweenTwoSameSignal); + eaTradeHandler.ProtectorStartDistanceInPoint(eaProtectorStartDistanceInPoint); + + // + // Configure Hedging ... + eaTradeHandler.AllowHedge(eaAllowHedge); + eaTradeHandler.HedgeMinVolumeStep(eaHedgeMinVolumeStep); + eaTradeHandler.MinimumOpenPositionsForHEHedge(eaMinimumOpenPositionsForHEHedge); + eaTradeHandler.HedgeHEMinProfitPerVolumeStep(eaHedgeHEMinProfitPerVolumeStep); + eaTradeHandler.HedgeBEMinProfitPerVolumeStep(eaHedgeBEMinProfitPerVolumeStep); + + // + // In Profit Position Protecting ... + eaTradeHandler.AllowTrailStopInProfits(eaAllowTrailStopInProfits); + eaTradeHandler.OnlyTrailUnprotectedPositions(eaOnlyTrailUnprotectedPositions); + eaTradeHandler.TrailStopStepsInPoint(eaTrailStopStepsInPoint); + eaTradeHandler.RmoveTPOnTrailStep(eaRmoveTPOnTrailStep); + eaTradeHandler.PartialCloseOnSpecificPointOfProfit(eaPartialCloseOnSpecificPointOfProfit); + eaTradeHandler.PartialCloseVolumeInProfit(eaPartialCloseVolumeInProfit); + + // + // Protector > In Drawdown Positions Protecting ... + eaTradeHandler.FreezeInDrawdon(eaFreezeInDrawdon); + eaTradeHandler.FreezePoint(eaFreezePoint); + eaTradeHandler.FreezeVolume(eaFreezeVolume); + eaTradeHandler.RemoveFreezedPositionsTPSL(eaRemoveFreezedPositionsTPSL); + eaTradeHandler.AllowRecoverInDrawdowns(eaAllowRecoverInDrawdowns); + eaTradeHandler.RecoveryMultiplier(eaRecoveryMultiplier); + eaTradeHandler.ApplyRecoveryLevelOnVolume(eaApplyRecoveryLevelOnVolume); + eaTradeHandler.RecoveryDelayInMinute(eaRecoveryDelayInMinute); + eaTradeHandler.RecoveryDistanceInPoint(eaRecoveryDistanceInPoint); + eaTradeHandler.PartialCloseOnSpecificPointOfDrawdown(eaPartialCloseOnSpecificPointOfDrawdown); + eaTradeHandler.PartialCloseVolumeInDrawdown(eaPartialCloseVolumeInDrawdown); + + // + // TODO: Implement ... + + // + // Configure Strategies ... + + // + // Single Symbol ... + if (!eaMultiSymbol) + { + // + // Register XCH Strategy ... + + // + // Create Class Instance ... + XSCXCHStrategy *xchStrategy; + xchStrategy = new XSCXCHStrategy( + _Symbol, + _Period, + PERIOD_H1, // Analyzing Period + eaVolume, + eaR2R, // R2R ... + eaSlippage, + eaMagicNumber, + true, // Ignore Signal Execution + eaUseFixedTPSLPoints, // Use TP SL Point + false, // Use Max + eaTPPoint, // TP + eaSLPoint, // SL + eaIgnoreTP, + eaIgnoreSL, + eaAllowLong, + eaAllowShort, + eaMaxAllowedLongs, // Max Longs + eaMaxAllowedShorts // Max Shorts + ); + + // + // Configuere Strategy ... + xchStrategy.EnableXCHM(true); + xchStrategy.EnableXCHHK(true); + xchStrategy.EnableXCHSTR(true); + xchStrategy.EnableXCHCHE(true); + xchStrategy.DrawImportantAreas(false); + xchStrategy.AddXCHSignalEventHandler(OnSignalRecieved); + + // + // Configure Alerts ... + xchStrategy.SetAlertPrefix(mTag); + xchStrategy.SetAlertEnableAlerts(eAEnableAlerts); + xchStrategy.SetAlertLogAlerts(eALogAlerts); + xchStrategy.SetAlertMailAlerts(eAMailAlerts); + xchStrategy.SetAlertPushAlerts(eAPushAlerts); + xchStrategy.SetAlertTerminalAlerts(eATerminalAlerts); + + // + // Register Strategy ... + RegisterStrategy(xchStrategy); + + // + // Register XCHCHE Strategy ... + + // + // Create Class Instance ... + XSCXCHCHEStrategy *xchcheStrategy; + xchcheStrategy = new XSCXCHCHEStrategy( + _Symbol, + _Period, + PERIOD_H1, // Analyzing Period + eaVolume, + eaR2R, // R2R ... + eaSlippage, + eaMagicNumber, + true, // Ignore Signal Execution + eaUseFixedTPSLPoints, // Use TP SL Point + false, // Use Max + eaTPPoint, // TP + eaSLPoint, // SL + eaIgnoreTP, + eaIgnoreSL, + eaAllowLong, + eaAllowShort, + eaMaxAllowedLongs, // Max Longs + eaMaxAllowedShorts // Max Shorts + ); + + // + // Configuere Strategy ... + xchcheStrategy.DrawImportantAreas(false); + xchcheStrategy.AddXCHSignalEventHandler(OnSignalRecieved); + + // + // Configure Alerts ... + xchcheStrategy.SetAlertPrefix(mTag); + xchcheStrategy.SetAlertEnableAlerts(eAEnableAlerts); + xchcheStrategy.SetAlertLogAlerts(eALogAlerts); + xchcheStrategy.SetAlertMailAlerts(eAMailAlerts); + xchcheStrategy.SetAlertPushAlerts(eAPushAlerts); + xchcheStrategy.SetAlertTerminalAlerts(eATerminalAlerts); + + // + // Register Strategy ... + RegisterStrategy(xchcheStrategy); + } + // + // 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 XCH Strategy ... + + // + // Create Class Instance ... + XSCXCHStrategy *iXCHStrategy; + iXCHStrategy = new XSCXCHStrategy( + iSymbol, + _Period, + PERIOD_H1, // Analyzing Period + eaVolume, + eaR2R, // R2R ... + eaSlippage, + eaMagicNumber, + true, // Ignore Signal Execution + eaUseFixedTPSLPoints, // Use TP SL Point + false, // Use Max + eaTPPoint, // TP + eaSLPoint, // SL + eaIgnoreTP, + eaIgnoreSL, + eaAllowLong, + eaAllowShort, + eaMaxAllowedLongs, // Max Longs + eaMaxAllowedShorts // Max Shorts + ); + + // + // Configuere Strategy ... + iXCHStrategy.EnableXCHM(true); + iXCHStrategy.EnableXCHHK(true); + iXCHStrategy.EnableXCHSTR(true); + iXCHStrategy.EnableXCHCHE(true); + iXCHStrategy.DrawImportantAreas(false); + iXCHStrategy.AddXCHSignalEventHandler(OnSignalRecieved); + + // + // Configure Alerts ... + iXCHStrategy.SetAlertPrefix(mTag); + iXCHStrategy.SetAlertEnableAlerts(eAEnableAlerts); + iXCHStrategy.SetAlertLogAlerts(eALogAlerts); + iXCHStrategy.SetAlertMailAlerts(eAMailAlerts); + iXCHStrategy.SetAlertPushAlerts(eAPushAlerts); + iXCHStrategy.SetAlertTerminalAlerts(eATerminalAlerts); + + // + // Register Strategy ... + RegisterStrategy(iXCHStrategy); + + // + // Register XCHCHE Strategy ... + + // + // Create Class Instance ... + XSCXCHCHEStrategy *iXCHCHEStrategy; + iXCHCHEStrategy = new XSCXCHCHEStrategy( + iSymbol, + _Period, + PERIOD_H1, // Analyzing Period + eaVolume, + eaR2R, // R2R ... + eaSlippage, + eaMagicNumber, + true, // Ignore Signal Execution + eaUseFixedTPSLPoints, // Use TP SL Point + false, // Use Max + eaTPPoint, // TP + eaSLPoint, // SL + eaIgnoreTP, + eaIgnoreSL, + eaAllowLong, + eaAllowShort, + eaMaxAllowedLongs, // Max Longs + eaMaxAllowedShorts // Max Shorts + ); + + // + // Configuere Strategy ... + iXCHCHEStrategy.DrawImportantAreas(false); + iXCHCHEStrategy.AddXCHSignalEventHandler(OnSignalRecieved); + + // + // Configure Alerts ... + iXCHCHEStrategy.SetAlertPrefix(mTag); + iXCHCHEStrategy.SetAlertEnableAlerts(eAEnableAlerts); + iXCHCHEStrategy.SetAlertLogAlerts(eALogAlerts); + iXCHCHEStrategy.SetAlertMailAlerts(eAMailAlerts); + iXCHCHEStrategy.SetAlertPushAlerts(eAPushAlerts); + iXCHCHEStrategy.SetAlertTerminalAlerts(eATerminalAlerts); + + // + // Register Strategy ... + RegisterStrategy(iXCHCHEStrategy); + } + } + + // + return result; +} + +// +// Register Strategy ... +void RegisterStrategy(XSCBaseStrategy *strategy) +{ + // + if (strategy == NULL) + { + return; + } + + // + ArrayResize( + strategies, + ArraySize(strategies) + 1 // + ); + + // + strategies[ArraySize(strategies) - 1] = strategy; +} + +// +// Call All Registered Strategis Tick Handler Functions ... +void HandleStrategiesOnTick() +{ + // + int count = ArraySize(strategies); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + // Call Tick Handler Function ... + strategies[i].HandleTick(); + } +} + +// +// Manage Trading States ... +void HandleTradeState() +{ + // + // Implement All Trade States here ... + eaTradeHandler.UpdateData(); + + // + // Do Protection Senarios ... + eaTradeHandler.HandleProtection(); +} + +// +// Time Reporting ... +void HandleTimeReport() +{ + // + // Monthly Report .... + if (eaAlertNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.Alert(msg); + } + + // + // Weekly Report .... + if (eaAlertNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.Alert(msg); + } + + // + // Daily Report .... + if (eaAlertNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.Alert(msg); + } + + // + // Hourly Report .... + if (eaAlertNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.Alert(msg); + } +} + +// +// SIGNAL EVENT Handlers ... +// + +// +// All Signals from Strategies Comming Here for Execution or +// Analyzing ... +void OnSignalRecieved( + XSignal &signal, + XCHStrategyConditions &conditions // +) +{ + // + // Check Signal and Conditions Validations ... + + // + if (!signal.IsValid()) + { + return; + } + + // + if (!conditions.IsValid()) + { + return; + } + + // + // Notify When a Raw (Unfiltered) Signal Recieved + // if it's Provided ... + if (eaAlertRawSignals) + { + // + string msg = "Raw " + (IsLong(signal.type) ? "Long" : "Short") + " Signal Recieved: (" + signal.provider + "," + signal.symbol + "," + ToString(signal.period) + ") ..."; + eaAlert.Alert(msg); + } + + // + // Prepare Signal Dynamic Volume + // if Provided ... + if (eaUseDynamicVolume && + eaDynamicVolumeStep > 0 && + eaDynamicVolumeBalanceFactor > 0) + { + // + double dVolume = eaTrader.GetDynamicVolume( + signal.symbol, + eaDynamicVolumeBalanceFactor, + eaDynamicVolumeStep // + ); + + // + if (dVolume > 0) + { + signal.volume = dVolume; + } + + // + eaTradeHandler.UpdateSignal(signal); + } + + // + // Since Signal Filtering done based on + // Strategy and it's not related to Public + // TradeHandler for Seperation of Concern issue, + // we do this here ... + XCHStartegyConditionsParser chParser; + XCHCHEStartegyConditionsParser chcheParser; + + // + bool isXCHSignal = signal.provider == XCHStartegyToken; + bool isXCHCHESignal = signal.provider == XCHCHEStartegyToken; + bool isFiltered = + isXCHSignal + ? chParser.IsFiltered( + signal, + conditions // + ) + : isXCHCHESignal + ? chcheParser.IsFiltered( + signal, + conditions // + ) + : true; + if (isFiltered) + { + // + eaTradeHandler.RemoveSignal(signal); + return; + } + + // + // Attach Conditions Summary to Signal ... + string conditionsSummary = conditions.GenerateSummary( + false, + false, + true, + false // + ); + + // + signal.conditions = + isXCHSignal + ? chParser.GenerateSignalConditions( + signal, + conditions // + ) + : isXCHCHESignal + ? chcheParser.GenerateSignalConditions( + signal, + conditions // + ) + : conditionsSummary; + + // + // Execute Signal Using Trade Handler ... + ENUM_X_SIGNAL_EXECUTION_RESULT state; + bool isExecuted = eaTradeHandler.ExecuteSignal( + signal, + state // + ); +} + +// +// Handle StopLoss Triggered Positions ... +void OnStopLossTriggered(const XDeal &deal) +{ + // + // Finish ... + eaTradeHandler.Finish(deal); + + // + ReportBalance(); +} + +// +// Handle Take Profit Triggered Positions ... +void OnTakeProfitTriggered(const XDeal &deal) +{ + // + // Finish ... + eaTradeHandler.Finish(deal); + + // + ReportBalance(); +} + +// +// Handle Force Close a Position ... +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + // Finish ... + eaTradeHandler.Finish( + ticket, + position, + comment // + ); + + // + ReportBalance(); +} + +// +// Report Account Balance ... +void ReportBalance() +{ + // + if (!IsRunningOnTestMode()) + { + return; + } + + // + string msg = "Balance: " + ToString(eaTrader.mAccount.GetBalance()); + eaAlert.Log(msg); +} + +// \ No newline at end of file diff --git a/Documents/BKP/x-saherelm.x121.xtrade.handler.class.mq5 b/Documents/BKP/x-saherelm.x121.xtrade.handler.class.mq5 new file mode 100644 index 00000000..5e07997c --- /dev/null +++ b/Documents/BKP/x-saherelm.x121.xtrade.handler.class.mq5 @@ -0,0 +1,3680 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: X121SCTradeHandler +// Description: provides all Trade Handling requirements ... +// +// +// 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.xtrade.class.mq5" + +// +// Definitions ... + +// +// an Structure for Holding Positions Data ... +struct X121TradeData +{ + // + datetime time; // Issue Time (Open Position) + string symbol; // Trading Symbol + double entry; // Entry Price + double volume; // Volume + string provider; // Signaller + ENUM_TIMEFRAMES period; // Trading Timeframe + ENUM_X_POSITION_TYPES type; // Position Type + + // + ulong ticket; // Position Ticket + double swap; // Swap + double profit; // Profit on Close + double commission; // Commission + double maxDrawdown; // Max Position Drawdown + string message; // Close Reason + datetime endTime; // End Time + + // + XSignal signal; // Signal Object + int pushers; // Signal Pushers + string conditions; // Signal Conditions + + // + int trailStep; // Trail Step + bool freezed; // Position Freezed or not + int protectionStep; // Protection Step + datetime lastProtectedOn; // Last Protection Date + double lastProtectedInProfit; // Last Protection In Profit + double lastProtectedInDrawdown; // Last Protection In Drawdown + bool partiallyClosed; // Partially Closed or not + + // + // Constructor ... + void XTradeInfo() + { + Clean(); + } + + // + // Filling Trade Handler ... + bool Fill(XSignal &_signal) + { + // + bool result = false; + + // + Clean(); + + // + // Check Signal Validation ... + result = _signal.IsValid(); + if (!result) + { + return result; + } + + // + signal = _signal; + time = _signal.time; + entry = _signal.entry; + symbol = _signal.symbol; + volume = _signal.volume; + period = _signal.period; + pushers = _signal.pushers; + provider = _signal.provider; + conditions = _signal.conditions; + type = ToPositionType(_signal.type); + + // + if (_signal.IsExecuted()) + { + ticket = _signal.positionId; + } + + // + return result; + } + + // + // Filling Trade Handler ... + bool Fill(XPosition &_position) + { + // + bool result = false; + + // + Clean(); + + // + // Check Signal Validation ... + result = _position.IsValid(); + if (!result) + { + return result; + } + + // + time = _position.openAt; + symbol = _position.symbol; + entry = _position.entry; + volume = _position.volume; + provider = _position.provider; + period = _position.period; + type = ToPositionType(_position.type); + + // + ticket = _position.ticket; + + // + return result; + } + + // + // Update Data ... + bool Update(XPosition &_position) + { + // + bool result = false; + + // + result = _position.IsValid(); + if (!result) + { + return result; + } + + // + profit = _position.profit; + swap = _position.swap; + + // + if (profit < 0 && + (maxDrawdown == 0 || + MathAbs(profit) > MathAbs(maxDrawdown))) + { + maxDrawdown = profit; + } + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + time = NULL; + type = NULL; + symbol = NULL; + period = NULL; + endTime = NULL; + message = NULL; + provider = NULL; + + // + swap = 0; + entry = 0; + ticket = 0; + profit = 0; + volume = 0; + commission = 0; + maxDrawdown = 0; + + // + trailStep = 0; + freezed = false; + protectionStep = 0; + partiallyClosed = false; + lastProtectedOn = NULL; + lastProtectedInProfit = 0; + lastProtectedInDrawdown = 0; + + // + signal.Clean(); + } + + // + // Validation ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ticket > 0 && + IsValid(time) && + IsValid(symbol) && + IsValid(period) + // + ; + + // + return result; + } + + // + // Retrieve Trade Data Age ... + int GetAge() + { + // + int result = -1; + + // + if (!IsValid(symbol) || + !IsValid(time) || + !IsValid(endTime) || + !IsValid(period)) + { + return result; + } + + // + int startIndex = iBarShift( + symbol, + period, + time, + false // + ); + + // + int endIndex = iBarShift( + symbol, + period, + endTime, + false // + ); + + // + result = MathAbs(startIndex - endIndex); + + // + return result; + } + + // + // Check Own of Trade Data ... + // based on Ticket ... + bool IsOwn( + ulong _ticket // + ) + { + // + bool result = false; + + // + result = _ticket == ticket; + + // + return result; + } + + // + // Check Own of Trade Data ... + // based on Symbol/Provider and Period ... + bool IsOwn( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_symbol) && + IsValid(_period) && + IsValid(_provider) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE && + // + type == _type && + period == _period && + symbol == _symbol && + provider == _provider + // + ; + + // + return result; + } + + // + // Data Collector ... + + // + // Get Data File Name ... + string GetFileName() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + symbol + "\\" + + ToString(type) + "\\" + + (profit >= 0 ? "Profit" : "Loss") + "\\" + + ToString(ticket) + "_" + + ToString(period) + "_" + + ToFormatString(time) + // + ; + + // + return result; + } + + // + // Get Signal File Name ... + string GetSignalFileName() + { + // + string result = NULL; + + // + result = + // + symbol + "\\" + + ToString(type) + "\\" + + provider + "_" + + ToFormatString(time) + // + ; + + // + return result; + } + + // + // Convert(s) To String Representation(s) ... + string ToString( + bool onlySignals = false // + ) + { + // + string result = NULL; + + // + int age = GetAge(); + + // + result = + // + (onlySignals ? "" : ToString("Ticket", ticket)) + + ToString("Symbol", symbol) + + ToString("Period", period) + + ToString("Entry", entry) + + ToString("Provider", provider) + + ToString("Type", ToString(type)) + + ToString("Time", time) + + // + // Attach Trade Info ... + (onlySignals ? "" : + // + "-------------" + "\n" + + ToString("Volume", volume) + + ToString("Profit", profit) + + ToString("Commission", commission) + + ToString("Swap", swap) + + ToString("Max Drawdown", maxDrawdown) + + ToString("End Time", endTime) + + ToString("Age", age) + + ToString("Message", message) + + "" + // + ) + + // + // Attach Conditions to Signals ... + (!onlySignals ? "" : + // + "-------------" + "\n" + + ToString("Pushers", pushers) + + "Conditions:" + "\n" + + "-------------" + "\n" + + conditions + + "" + // + ) + + // + "" + // + ; + + // + return result; + } + + // +}; + +// +// Model a Position and it's Protected Positions ... +struct XProtectedPosition +{ + // + XPosition main; // Main Position ... + X121TradeData data; // Trade Handler Data ... + + // + XPosition supports[]; // Support Positions ... + + /** + * Count Supported Positions + */ + int CountSupports() + { + return ArraySize(supports); + } + + /** + * Extract All Positions into Specified Array + * of Positions ... + */ + int ExtractPositions( + XPosition &positions[] // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + if (main.IsValid()) + { + // + AddRef( + main, + positions // + ); + } + + // + int supportsCount = CountSupports(); + if (IsValidSize(supportsCount)) + { + // + Copy( + supports, + positions, + false // + ); + } + + // + result = ArraySize(positions); + + // + return result; + } +}; + +// +// Implementation ... + +// +// a Class For Read and Write Trade Info Data in Files ... +class X121TradeCollector +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor(s) ... + void X121TradeCollector( + string _path = NULL // Base Path + ) + { + // + mAccount = new XSCAccount(); + + // + if (IsValid(_path)) + { + mPath = _path; + } + else + { + mPath = "X121TradeData" + "\\" + mAccount.GetCompany(); + } + } + + // + // Deconstructor ... + void ~X121TradeCollector() + { + } + + // + bool IsExists(X121TradeData &item) + { + // + bool result = false; + + // + int mHandler = GetFileHandlerForRead(item); + result = mHandler != INVALID_HANDLE; + FileClose(mHandler); + + // + return result; + } + + // + bool Save(X121TradeData &item) + { + // + bool result = false; + + // + // Check info is Valid ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + string content = item.ToString(); + content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true); + + // + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + // + bool SaveSignal(X121TradeData &item) + { + // + bool result = false; + + // + string content = item.ToString(true); + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetSignalFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + // + // Conditions only save for Loss Signals ... + // this means the profit must be Lower than Zero ... + // ans also message Contains SL ... + bool SaveConditions(X121TradeData &item) + { + // + bool result = false; + + // + // Validate Item ... + result = + // + item.profit < 0 && + Contains("SL", item.message) + // + ; + if (!result) + { + return result; + } + + // + string content = item.signal.conditions; + result = IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetConditionsFileHandlerForWrite(item); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileSeek(mHandler, 0, SEEK_END); + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + + // + string mPath; // Base Path ... + + // + XSCAccount *mAccount; + + // + string GetFilePath(X121TradeData &item) + { + // + string fileName = item.GetFileName(); + + // + return GetFilePath(fileName); + } + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetSignalFilePath(X121TradeData &item) + { + // + string fileName = item.GetSignalFileName(); + + // + return GetSignalFilePath(fileName); + } + string GetSignalFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetConditionsFilePath(X121TradeData &item) + { + // + bool isLong = IsLong(item.type); + + // + string fileName = + item.symbol + "\\" + + (isLong ? "Longs" : "Shorts"); + + // + return GetConditionsFilePath(fileName); + } + string GetConditionsFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + int GetFileHandlerForRead(X121TradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetFileHandlerForWrite(X121TradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetSignalFileHandlerForRead(X121TradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetSignalFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetSignalFileHandlerForWrite(X121TradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetSignalFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetConditionsFileHandlerForRead(X121TradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetConditionsFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT // + ); + + // + return result; + } + int GetConditionsFileHandlerForWrite(X121TradeData &item) + { + // + int result = INVALID_HANDLE; + + // + string filePath = GetConditionsFilePath(item); + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } +}; + +// +// Trade Handler Class ... +class X121SCTradeHandler : public XSCBaseAlert +{ + // + // Public ... + public: + // + + // + // Constructor(s) ... + void X121SCTradeHandler(XSCTrade *trader) + { + // + mTrader = trader; + mCollector = new X121TradeCollector(); + } + + // + // Deconstructor ... + void ~X121SCTradeHandler() + { + // + delete mTrader; + delete mCollector; + } + + // + // Getter(s) / Setter(s) ... + + // + bool SaveSignals() + { + return mSaveSignals; + } + + // + void SaveSignals(bool value) + { + mSaveSignals = value; + } + + // + bool SaveTrades() + { + return mSaveTrades; + } + + // + void SaveTrades(bool value) + { + mSaveTrades = value; + } + + // + bool SaveConditions() + { + return mSaveConditions; + } + + // + void SaveConditions(bool value) + { + mSaveConditions = value; + } + + // + 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; + } + + // + bool UseMaxAllowedTradesPerSymbol() + { + return mUseMaxAllowedTradesPerSymbol; + } + + // + void UseMaxAllowedTradesPerSymbol(bool value) + { + mUseMaxAllowedTradesPerSymbol = value; + } + + // + double MaxDrawdownPercentForOpenTrades() + { + return mMaxDrawdownPercentForOpenTrades; + } + + // + void MaxDrawdownPercentForOpenTrades(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxDrawdownPercentForOpenTrades = value; + } + + // + // Protector Start ... + + // + double ProtectorStartDistanceInPoint() + { + return mProtectorStartDistanceInPoint; + } + + // + void ProtectorStartDistanceInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mProtectorStartDistanceInPoint = value; + } + + // + int DelayBarBetweenTwoSameSignal() + { + return mDelayBarBetweenTwoSameSignal; + } + + // + void DelayBarBetweenTwoSameSignal(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDelayBarBetweenTwoSameSignal = value; + } + + // + // In Profit Position Protecting ... + + // + bool AllowTrailStopInProfits() + { + return mAllowTrailStopInProfits; + } + + // + void AllowTrailStopInProfits(bool value) + { + mAllowTrailStopInProfits = value; + } + + // + double TrailStartDistanceInPoint() + { + return mTrailStartDistanceInPoint; + } + + // + void TrailStartDistanceInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mTrailStartDistanceInPoint = value; + } + + // + bool OnlyTrailUnprotectedPositions() + { + return mOnlyTrailUnprotectedPositions; + } + + // + void OnlyTrailUnprotectedPositions(bool value) + { + mOnlyTrailUnprotectedPositions = value; + } + + // + double TrailStopStepsInPoint() + { + return mTrailStopStepsInPoint; + } + + // + void TrailStopStepsInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mTrailStopStepsInPoint = value; + } + + // + int RmoveTPOnTrailStep() + { + return mRmoveTPOnTrailStep; + } + + // + void RmoveTPOnTrailStep(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRmoveTPOnTrailStep = value; + } + + // + double PartialCloseOnSpecificPointOfProfit() + { + return mPartialCloseOnSpecificPointOfProfit; + } + + // + void PartialCloseOnSpecificPointOfProfit(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPartialCloseOnSpecificPointOfProfit = value; + } + + // + double PartialCloseVolumeInProfit() + { + return mPartialCloseVolumeInProfit; + } + + // + void PartialCloseVolumeInProfit(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPartialCloseVolumeInProfit = value; + } + + // + // In Drawdown Positions Protecting ... + + // + bool FreezeInDrawdon() + { + return mFreezeInDrawdon; + } + + // + void FreezeInDrawdon(bool value) + { + mFreezeInDrawdon = value; + } + + // + double FreezePoint() + { + return mFreezePoint; + } + + // + void FreezePoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mFreezePoint = value; + } + + // + double FreezeVolume() + { + return mFreezeVolume; + } + + // + void FreezeVolume(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mFreezeVolume = value; + } + + // + bool RemoveFreezedPositionsTPSL() + { + return mRemoveFreezedPositionsTPSL; + } + + // + void RemoveFreezedPositionsTPSL(bool value) + { + mRemoveFreezedPositionsTPSL = value; + } + + // + bool AllowRecoverInDrawdowns() + { + return mAllowRecoverInDrawdowns; + } + + // + void AllowRecoverInDrawdowns(bool value) + { + mAllowRecoverInDrawdowns = value; + } + + // + double RecoveryMultiplier() + { + return mRecoveryMultiplier; + } + + // + void RecoveryMultiplier(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRecoveryMultiplier = value; + } + + // + bool ApplyRecoveryLevelOnVolume() + { + return mApplyRecoveryLevelOnVolume; + } + + // + void ApplyRecoveryLevelOnVolume(bool value) + { + mApplyRecoveryLevelOnVolume = value; + } + + // + int RecoveryDelayInMinute() + { + return mRecoveryDelayInMinute; + } + + // + void RecoveryDelayInMinute(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRecoveryDelayInMinute = value; + } + + // + double RecoveryDistanceInPoint() + { + return mRecoveryDistanceInPoint; + } + + // + void RecoveryDistanceInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRecoveryDistanceInPoint = value; + } + + // + double PartialCloseOnSpecificPointOfDrawdown() + { + return mPartialCloseOnSpecificPointOfDrawdown; + } + + // + void PartialCloseOnSpecificPointOfDrawdown(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPartialCloseOnSpecificPointOfDrawdown = value; + } + + // + double PartialCloseVolumeInDrawdown() + { + return mPartialCloseVolumeInDrawdown; + } + + // + void PartialCloseVolumeInDrawdown(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPartialCloseVolumeInDrawdown = value; + } + + // + // Hedge Props ... + + // + bool AllowHedge() + { + return mAllowHedge; + } + + // + void AllowHedge(bool value) + { + mAllowHedge = value; + } + + // + double HedgeMinVolumeStep() + { + return mHedgeMinVolumeStep; + } + + // + // Min: 0.01 + // Max 0.1 + void HedgeMinVolumeStep(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + if (value > 0.1) + { + value = 0.1; + } + + // + mHedgeMinVolumeStep = value; + } + + // + int MinimumOpenPositionsForHEHedge() + { + return mMinimumOpenPositionsForHEHedge; + } + + // + void MinimumOpenPositionsForHEHedge(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMinimumOpenPositionsForHEHedge = value; + } + + // + double HedgeHEMinProfitPerVolumeStep() + { + return mHedgeHEMinProfitPerVolumeStep; + } + + // + // Min: 0.01 + void HedgeHEMinProfitPerVolumeStep(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mHedgeHEMinProfitPerVolumeStep = value; + } + + // + double HedgeBEMinProfitPerVolumeStep() + { + return mHedgeBEMinProfitPerVolumeStep; + } + + // + // Min: 0.01 + void HedgeBEMinProfitPerVolumeStep(double value) + { + // + if (value < 0.01) + { + value = 0.01; + } + + // + mHedgeBEMinProfitPerVolumeStep = value; + } + + // + // Read Only Props ... + + // + int MaxSameTimeTrades() + { + return maxSameTimeTrades; + } + + // + // Calculate Max Drawdown and it's Percent ... + double GetMaxDrawdown() + { + // + XPosition positions[]; + int positionsCount = mTrader.GetPositions(positions); + if (IsValidSize(positionsCount)) + { + double mEquity = mTrader.mAccount.GetEquity(); + if (mEquity > maxDrawdown) + { + maxDrawdown = mEquity; + } + + // + drawdownPercent = (maxDrawdown - mEquity) / (staticBalanceForCalculateDrawdown > 0 ? staticBalanceForCalculateDrawdown : maxDrawdown) * 100; + drawdownPercent = NormalizeDouble(drawdownPercent, 3); + } + else + { + // + maxDrawdown = 0.0; + drawdownPercent = 0.0; + } + + // + return drawdownPercent; + } + + // + // Position Retrievers ... + + /** + * Retrieve Positions as XProtetedPosition structure + * @param positions: Argument 1 + * @return ( int ) + */ + int GetPositions( + XProtectedPosition &positions[] // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + // Retrieve Positions from Trader Class ... + XPosition allPositions[]; + int allPositionsCount = mTrader.GetPositions( + allPositions, + NULL, // All Symbols ... + NULL, // All Providers ... + NULL, // All Periods ... + X_POSITION_TYPE_ALL, // Long and Short ... + false, // Filter By Magic ... + true // Force Clean ... + ); + if (!IsValidSize(allPositionsCount)) + { + return result; + } + + // + // Filter Support Positions ... + XPosition mainPositions[]; + XPosition supportPositions[]; + for (int i = 0; i < allPositionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + // Check Validation ... + if (!iPosition.IsValid()) + { + continue; + } + + // + // Check Position Support or not ... + bool isSupport = IsSupport(iPosition.comment); + if (isSupport) + { + // + AddRef( + iPosition, + supportPositions // + ); + continue; + } + + // + AddRef( + iPosition, + mainPositions // + ); + } + + // + // Check Main Positions Count ... + int mainPositionsCount = ArraySize(mainPositions); + if (!IsValidSize(mainPositionsCount)) + { + return result; + } + + // + int supportPositionsCount = ArraySize(supportPositions); + + // + for (int i = 0; i < mainPositionsCount; i++) + { + // + XPosition iPosition = mainPositions[i]; + + // + XProtectedPosition iProtected; + iProtected.main = iPosition; + Clean(iProtected.supports); + + // + // Loop Through Support Positions To Find iPositions Support ... + if (IsValidSize(supportPositionsCount)) + { + // + for (int j = 0; j < supportPositionsCount; j++) + { + // + XPosition jSupport = supportPositions[j]; + + // + ulong supportParentTicket = ExtractSupportedTicket(jSupport.comment); + bool isSupport = supportParentTicket > 0; + if (isSupport && + supportParentTicket == iPosition.ticket) + { + // + AddRef( + jSupport, + iProtected.supports // + ); + } + + // + ulong eqmSupportParentTicket = ExtractEQMSupportedTicket(jSupport.comment); + bool isEQMSupport = eqmSupportParentTicket > 0; + if (isEQMSupport && + eqmSupportParentTicket == iPosition.ticket) + { + // + AddRef( + jSupport, + iProtected.supports // + ); + } + } + } + + // + // Findout X121TradeData ... + int iIDX = -1; + bool hasItem = HasItem( + iPosition.ticket, + iIDX // + ); + if (hasItem && IsValidIndex(iIDX)) + { + iProtected.data = mData[iIDX]; + } + + // + AddRef( + iProtected, + positions // + ); + } + + // + Clean(allPositions); + Clean(mainPositions); + Clean(supportPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + // Trade Handling Functions ... + + // + // First Step of Trade Handling ... + // Since Must Call when a Signal Executed ... + void AddData( + XSignal &signal, // Executed Signal + double commission = 0 // Commission + ) + { + // + // Check Signal Valid ... + if (!signal.IsValid()) + { + return; + } + + // + // Check Signal Support or Recovery ... + bool isSupport = IsSupport(signal.comment); + bool isRecovery = ExtractRecoveredTicket(signal.comment) > 0; + + // + X121TradeData item; + bool isFilled = item.Fill(signal); + if (!isFilled) + { + return; + } + + // + item.commission = commission; + + // + Add(item); + + // + SaveSignal(item); + } + + // + void Finish(const XDeal &deal) + { + // + int idx = -1; + bool hasItem = HasItem( + deal.positionId, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Item Info ... + mData[idx].swap = deal.swap; + mData[idx].endTime = deal.time; + mData[idx].profit = deal.profit; + + // + mData[idx].message = + deal.reason == DEAL_REASON_TP ? "TP" : "SL"; + + // + Save(idx); + } + + // + void Finish( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + int idx = -1; + bool hasItem = HasItem( + ticket, + idx // + ); + if (!hasItem) + { + return; + } + + // + // Update Item Info ... + mData[idx].swap = position.swap; + mData[idx].endTime = TimeCurrent(); + mData[idx].profit = position.profit; + + // + mData[idx].message = comment; + + // + Save(idx); + } + + // + // this Method call's by a Timer, + // or in OnTick for Update Positions, + // Data ... + void UpdateData() + { + // + XPosition positions[]; + int count = mTrader.GetPositions(positions); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + int idx = -1; + bool isExists = HasItem( + iPosition.ticket, + idx // + ); + if (!isExists) + { + // + // Add New Data ... + + // + // Find Executed Signal Deal History ... + XDeal deals[]; + double commission = 0; + int dealsCount = mTrader.GetDeals( + deals, + iPosition.symbol, + iPosition.provider, + iPosition.period, + NULL, + DEAL_ENTRY_IN // + ); + if (IsValidSize(dealsCount)) + { + // + for (int i = 0; i < dealsCount; i++) + { + // + XDeal iDeal = deals[i]; + if (iDeal.positionId == iPosition.ticket) + { + // + commission = iDeal.commission; + break; + } + } + } + + // + X121TradeData iData; + iData.Fill( + iPosition // + ); + + // + iData.ticket = iPosition.ticket; + + // + Add(iData); + } + else + { + // + // Update Exists ... + mData[idx].Update(iPosition); + } + } + + // + count = Count(); + if (count > maxSameTimeTrades) + { + maxSameTimeTrades = count; + } + + // + GetMaxDrawdown(); + } + + // + void UpdateSignal(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + + // + int count = Count(); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isOwn = mData[i].IsOwn( + signal.symbol, + signal.provider, + signal.period, + ToPositionType(signal.type) // + ); + if (isOwn) + { + mData[i].Fill(signal); + } + } + } + + // + void RemoveSignal(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + + // + int signalIDX = -1; + ENUM_X_POSITION_TYPES xType = ToPositionType(signal.type); + bool hasSignal = HasItem( + signal.symbol, + signal.provider, + signal.period, + xType, + signalIDX // + ); + if (!hasSignal || !IsValidIndex(signalIDX)) + { + return; + } + + // + // Remove Item From List ... + ArrayRemove( + mData, + signalIDX, + 1 // + ); + } + + // + // Position Execute and Sync Functions ... + + /** + * this Method Synchronize + * all Exists Positions and parse them + * and add them into mData Collection if + * their not Exists ... + */ + void Sync() + { + // + // TODO: Implement here ... + } + + /** + * Validate Signal For Execution ... + */ + bool CanExecute(XSignal &signal) + { + // + bool result = false; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Execute Specific Signal using Trade Handler ... + */ + bool ExecuteSignal( + XSignal &signal, // Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State + bool ignorePolicies = false // Ignore Execution Policies + ) + { + // + bool result = false; + + // + // Check Signal Validation ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + // Filter Signals if Necessary ... + result = CanExecute(signal); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + // Check Policies ... + if (!ignorePolicies) + { + // + bool isLong = IsLong(signal.type); + + // + // Check Allow Trade Type ... + result = + isLong + ? mAllowLong + : mAllowShort; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + return result; + } + + // + // 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 = + // + // Long ... + isLong + ? mMaxAllowedLongs <= 0 + ? true + : longsCount < mMaxAllowedLongs + // + // Short ... + : mMaxAllowedShorts <= 0 + ? true + : shortsCount < mMaxAllowedShorts + // + ; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + + // + // Check Position Delays ... + if (result && mDelayBarBetweenTwoSameSignal > 0) + { + // + int youngestAge = 0; + XPosition youngestPosition; + + // + // Long Positions when there are Longs ... + if (isLong && longsCount > 0) + { + // + 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 >= mDelayBarBetweenTwoSameSignal; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + } + } + } + + // + // Check Drawdown ... + if (mMaxDrawdownPercentForOpenTrades > 0) + { + // + drawdownPercent = GetMaxDrawdown(); + + // + result = + drawdownPercent <= 0 + ? true + : drawdownPercent < mMaxDrawdownPercentForOpenTrades; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; + return result; + } + } + } + + // + // Execute Signal ... + result = mTrader.ExecuteSignal( + signal, + state // + ); + if (result) + { + // + double commission = mTrader.GetPositionCommission(signal.positionId); + + // + // Add Signal to Trade Handler ... + AddData( + signal, + commission // + ); + + // + string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + + " Signal Provided by: " + signal.provider + + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + + " on: " + signal.symbol + + " in: " + ToString(signal.period) + + " Executed Successfully ..."; + Alert(msg); + } + + // + return result; + } + + // + // Protection Functions ... + + /** + * Handle Positiona Protections + */ + void HandleProtection() + { + // + // Retrieve Positions ... + XProtectedPosition pPositions[]; + int pPositionsCount = GetPositions( + pPositions // + ); + + // + // Validate Count ... + if (!IsValidSize(pPositionsCount)) + { + return; + } + + // + bool isHedged = HandleHedge(pPositions); + if (isHedged) + { + // + // Renew Data ... + Clean(pPositions); + int pPositionsCount = GetPositions( + pPositions // + ); + + // + // Validate Count ... + if (!IsValidSize(pPositionsCount)) + { + return; + } + } + + // + // Loop Through Main Positions ... + double requiredDistance = ProtectorStartDistanceInPoint(); + if (requiredDistance <= 0) + { + return; + } + + // + int protectedPositions = 0; + for (int i = 0; i < pPositionsCount; i++) + { + // + // Check Position is Protectable or not ... + XProtectedPosition iProtected = pPositions[i]; + + // + XPosition iPosition = iProtected.main; + + // + double iDistance = MathAbs(iPosition.GetProfitInPoint()); + bool isDistancePassed = iDistance >= requiredDistance; + if (isDistancePassed) + { + // + bool isProtected = HandlePositionProtecting( + iPosition, + iProtected.supports // + ); + if (isProtected) + { + protectedPositions++; + } + } + } + + // + if (protectedPositions > 0) + { + // + // Renew Data ... + Clean(pPositions); + int pPositionsCount = GetPositions( + pPositions // + ); + + // + // Validate Count ... + if (!IsValidSize(pPositionsCount)) + { + return; + } + } + } + + // + // Protected ... + protected: + // + XSCTrade *mTrader; // Instance of Trader Class + X121TradeCollector *mCollector; // Instance of Trade Collector Class + + // + X121TradeData mData[]; // Hold Trade Data + + // + // Hedge Related Functions ... + + /** + * Handle Hedging On Positions ... + */ + bool HandleHedge(XProtectedPosition &positions[]) + { + // + bool result = false; + + // + // Check Hedging is Enabled Or Not ... + result = AllowHedge(); + if (!result) + { + return result; + } + + // + // Check Minimum Volume Step is Provided or not ... + double minVolumeStep = HedgeMinVolumeStep(); + result = minVolumeStep > 0; + if (!result) + { + return result; + } + + // + // Check Positions ... + int positionsCount = ArraySize(positions); + result = IsValidSize(positionsCount); + if (!result) + { + return result; + } + + // + // Calculate Required Info ... + double swaps = 0; // Summary of Positions Swaps ... + double profits = 0; // Summary of Positions and Supports Profits ... + double volumes = 0; // Summary of Positions and Supports Volumes ... + int supportsCount = 0; // Number of Protecting Positions ... + double commissions = 0; // Summary of Positions and Supports Commissions ... + XPosition flatPositions[]; // Flat Positions ... + for (int i = 0; i < positionsCount; i++) + { + // + XProtectedPosition iProtected = positions[i]; + + // + XPosition iPositions[]; + int iPositionsCount = iProtected.ExtractPositions(iPositions); + if (IsValidSize(iPositionsCount)) + { + // + Copy( + iPositions, + flatPositions, + false // + ); + } + + // + // Collect Main Positions Data ... + swaps += iProtected.main.swap; + profits += iProtected.main.profit; + volumes += iProtected.main.volume; + commissions += mTrader.GetPositionCommission(iProtected.main.ticket); + + // + int iSupportsCount = iProtected.CountSupports(); + supportsCount += iSupportsCount; + + // + if (IsValidSize(iSupportsCount)) + { + // + // Collectiong Supports Positions Data ... + for (int j = 0; j < iSupportsCount; j++) + { + // + XPosition jSupport = iProtected.supports[j]; + + // + swaps += jSupport.swap; + profits += jSupport.profit; + volumes += jSupport.volume; + + // + commissions += mTrader.GetPositionCommission(jSupport.ticket); + } + } + } + + // + // First Step is Handle HE Hedge ... + + // + int minOpenPositions = MinimumOpenPositionsForHEHedge(); + double heMinProfitPerVolumeStep = HedgeHEMinProfitPerVolumeStep(); + double beMinProfitPerVolumeStep = HedgeBEMinProfitPerVolumeStep(); + + // + // Check HE Hedge Conditions ... + bool allowHEHedge = minOpenPositions > 0 && heMinProfitPerVolumeStep > 0; + if (allowHEHedge) + { + // + // Implement HE Hedge ... + + // + // Check Main Positions Count and also not Support Positions ... + result = supportsCount == 0 && + positionsCount >= minOpenPositions; + if (result) + { + // + // Check Profits ... + result = profits > 0; + if (result) + { + // + // Calculate Required Profit ... + double volumeSteps = volumes / minVolumeStep; + double minRequiredProfit = (volumeSteps * heMinProfitPerVolumeStep) + + commissions + (-1 * swaps); + + // + // Check Profits Satisfied Required Profit's For Hedge or not ... + result = profits >= minRequiredProfit; + if (result) + { + // + int flatPositionsCount = ArraySize(flatPositions); + result = IsValidSize(flatPositionsCount); + if (result) + { + // + string comment = "EQM HE Hedge ..."; + int closed = mTrader.Close( + flatPositions, + comment // + ); + + // + result = closed > 0; + if (result) + { + // + string message = "EQM HE Hedge Close (" + ToString(flatPositionsCount) + ") Positions by: " + ToString(profits); + Alert(message); + + // + return result; + } + } + } + } + } + } + + // + // Check BE Hedge Conditions ... + bool allowBEHedge = positionsCount >= 1 && + supportsCount >= 1 && + beMinProfitPerVolumeStep > 0; + if (allowBEHedge) + { + // + // Implement BE Hedge ... + + // + // Check Profits ... + result = profits > 0; + if (result) + { + // + // Calculate Required Profit ... + double volumeSteps = volumes / minVolumeStep; + double minRequiredProfit = (volumeSteps * beMinProfitPerVolumeStep) + + commissions + (-1 * swaps); + + // + // Check Profits Satisfied Required Profit's For Hedge or not ... + result = profits >= minRequiredProfit; + if (result) + { + // + int flatPositionsCount = ArraySize(flatPositions); + result = IsValidSize(flatPositionsCount); + if (result) + { + // + string comment = "EQM BE Hedge ..."; + int closed = mTrader.Close( + flatPositions, + comment // + ); + + // + result = closed > 0; + if (result) + { + // + string message = "EQM BE Hedge Close (" + ToString(flatPositionsCount) + ") Positions by: " + ToString(profits); + Alert(message); + + // + return result; + } + } + } + } + + // + return result; + } + + // + return result; + } + + /** + * Handle Protecting Position ... + */ + bool HandlePositionProtecting( + XPosition &position, // Main Position + XPosition &supports[] // Supports + ) + { + // + bool result = false; + + // + // Find Position's Item Data ... + int iDX = -1; + result = HasItem( + position.ticket, + iDX // + ); + if (!result) + { + return result; + } + + // + // Here we Make Sure this Position has reached Proper distance ... + + // + bool isLong = IsLong(position.type); + bool isInProfit = position.profit > 0; + + // + int supportsCount = ArraySize(supports); + double profitInPoint = position.GetProfitInPoint(); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + // Last Bar ... + XOHCL cBar; + result = cBar.Init( + position.symbol, + position.period, + cIndex // + ); + 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; + } + + // + // 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 + // + ; + + // + // Define Conditions ... + MqlTick ticks[]; + int ticksCount = CopyTicks( + position.symbol, + ticks, + COPY_TICKS_ALL, + 0, + 5 // + ); + + // + // TODO: Check Volume if Required ... + + // + bool isTicksBullishForLong = + // + GetTickExit(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickExit(ticks[3], POSITION_TYPE_BUY, position.symbol) + // + ; + + // + bool isTicksBearishForLong = + // + GetTickExit(ticks[0], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_BUY, position.symbol) < GetTickExit(ticks[3], POSITION_TYPE_BUY, position.symbol) + // + ; + + // + bool isTicksBullishForShort = + // + GetTickExit(ticks[0], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) > GetTickExit(ticks[3], POSITION_TYPE_SELL, position.symbol) + // + ; + + // + bool isTicksBearishForShort = + // + GetTickExit(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) && + GetTickExit(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickExit(ticks[3], POSITION_TYPE_SELL, position.symbol) + // + ; + + // + bool hasBullishDecision = + // + cBar.IsBullishDecision() + // + ; + + // + bool hasBearishDecision = + // + cBar.IsBearishDecision() + // + ; + + // + bool hasBullishConditions = + // + ( + // + hasBullishTrend && + hasBullishDecision && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ) + // + ; + + // + bool hasBearishConditions = + // + ( + // + hasBearishTrend && + hasBearishDecision && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ) + // + ; + + // + // Reading Requirement for Freezing Positions ... + bool allowFreeze = FreezeInDrawdon(); + double freezePoint = FreezePoint(); + double freezeVolumeMultiplier = FreezeVolume(); + bool canFreeze = allowFreeze && + freezePoint > 0 && + freezeVolumeMultiplier > 0; + + // + // Reading Requirements for Partial Close ... + double partialCloseInProfitDistance = PartialCloseInProfitDistance(); + + // + // Reading Requirement for Recovery Positions ... + + // + // Reading Requirements for Trailling Stops ... + bool allowTrailStop = AllowTrailStopInProfits(); + double trailStep = TrailStopStepsInPoint(); + double trailStartDistance = TrailStartDistanceInPoint(); + bool allowOnlyUnprotecteds = OnlyTrailUnprotectedPositions(); + bool canTrail = inProfit && + trailStep > 0 && + allowTrailStop && + trailStartDistance > 0 && + (!allowOnlyUnprotecteds + ? true + : supportsCount <= 0) && + profitInPoint > trailStartDistance; + + // + // In Profit ... + // When a Position running in Profit, we have to look pressures by Same Direction + // of Main Position. for eaxmple if it is long, we look for Bullish Pressures and + // if it is short we look for Bearish Pressures. + // when pressure happens we must Trail position Stop ... + if (isInProfit) + { + // + // Do In Profit Protection Mechanism ... + + // + // Trail Stops ... + // Remove Trailed Positions TP ... + bool allowTrailStop = AllowTrailStopInProfits(); + double trailStep = TrailStopStepsInPoint(); + bool allowOnlyUnprotecteds = OnlyTrailUnprotectedPositions(); + bool isProtectionTrailPassed = !allowOnlyUnprotecteds + ? true + : supportsCount == 0; + if (allowTrailStop && trailStep > 0 && isProtectionTrailPassed) + { + // + // Temp Vaiables ... + bool canTrailStop = false; + + // + if (isLong) + { + // + // Check Conditions ... + canTrailStop = isTicksBullishForLong && + hasBullishConditions; + } + else + { + // + // Check Conditions ... + canTrailStop = isTicksBearishForShort && + hasBearishConditions; + } + + // + // Do Stop Trailling ... + if (canTrailStop) + { + // + int lastTrailedStep = mData[iDX].trailStep; + + // + double entry = position.entry; + double pointValue = position.GetPointsValue(); + double profitInPoint = position.GetProfitInPoint(); + + // + double requiredProfit = + lastTrailedStep == 0 + ? ProtectorStartDistanceInPoint() + : ProtectorStartDistanceInPoint() + (lastTrailedStep * trailStep); + + // + bool isProfitsPassed = profitInPoint > requiredProfit; + if (isProfitsPassed) + { + // + double delta = (requiredProfit * pointValue); + + // + double sl = + isLong + ? entry + delta + : entry - delta; + + // + string comment = "EQM Trail Stop ..."; + + // + // Try to Modify Position ... + result = mTrader.Modify( + position.ticket, + sl, + position.tp, + comment // + ); + if (result) + { + // + mData[iDX].trailStep++; + + // + string message = "EQM Trail (" + ToString(position.ticket) + ") Stop ..."; + Alert(message); + + // + XPosition trailedPosition; + bool hasPosition = mTrader.GetPosition( + position.ticket, + trailedPosition // + ); + + // + // Check Remove Trailed Positions TP Conditions ... + int removeTPOnTrailStep = RmoveTPOnTrailStep(); + if (removeTPOnTrailStep > 0 && mData[iDX].trailStep == removeTPOnTrailStep && trailedPosition.tp != 0) + { + // + string comment = "EQM Removes TP ..."; + + // + // Remove Position's TP ... + result = mTrader.Modify( + trailedPosition.ticket, + trailedPosition.sl, + 0, + comment // + ); + if (result) + { + // + string message = "EQM Removes (" + ToString(trailedPosition.ticket) + ") TP ..."; + Alert(message); + } + } + } + } + } + } + + // + bool allowRecover = AllowRecoverInDrawdowns(); + double volumeMultiplier = RecoveryMultiplier(); + if (allowRecover && !canFreeze && volumeMultiplier > 0 && supportsCount > 0) + { + // + bool canRecover = false; + int delayMinutes = RecoveryDelayInMinute(); + double recoveryDistancePoint = RecoveryDistanceInPoint(); + + // + // Temparory Requirement for Recover Signal ... + double sl = 0; + double tp = 0; + double entry = 0; + ENUM_POSITION_TYPE type = NULL; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + double lastStep = mData[iDX].protectionStep; + double volume = position.volume * volumeMultiplier; + bool applyLevel = ApplyRecoveryLevelOnVolume(); + if (applyLevel) + { + // + volume = supportsCount <= 0 + ? position.volume * volumeMultiplier + : position.volume * ((supportsCount + 1) * volumeMultiplier); + } + + // + datetime currentTime = TimeCurrent(); + double currentProfit = position.GetProfitInPoint(); + datetime lastProtectedOn = mData[iDX].lastProtectedOn; + double lastProtectedProfit = mData[iDX].lastProtectedInProfit; + bool isRecoveryConditionsPassed = + // + // Check Regular Conditions ... + delayMinutes > 0 && + recoveryDistancePoint > 0 && + IsValid(lastProtectedOn) && + // + // Check Time Delay Passed ... + (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) && + // + // Check Recovery Distance Passed ... + MathAbs(currentProfit) - MathAbs(lastProtectedProfit) >= recoveryDistancePoint; + + // + if (isRecoveryConditionsPassed) + { + // + // Long Recovery ... + if (isLong) + { + // + // Same Direction ... + canRecover = + // + isTicksBullishForLong && + hasBullishTrend && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ; + if (canRecover) + { + // + sl = position.sl; + tp = position.tp; + type = POSITION_TYPE_BUY; + } + } + // + // Short Recovery ... + else + { + // + // Same Direction ... + canRecover = + // + isTicksBearishForShort && + hasBearishTrend && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ; + if (canRecover) + { + // + sl = position.sl; + tp = position.tp; + type = POSITION_TYPE_SELL; + } + } + + // + if (canRecover) + { + // + XSignal signal; + entry = GetEntry( + position.symbol, + type // + ); + + // + // Prepare Signal ... + result = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + volume, + sl, + tp // + ); + + // + if (result) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (result) + { + // + mData[iDX].protectionStep++; + mData[iDX].lastProtectedOn = currentTime; + mData[iDX].lastProtectedInProfit = currentProfit; + + // + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " + + ToString(lastStep + 1) + + " for (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + } + + // + // Check Points of Profit and Do Partial Closing ... + double partialCloseVolume = PartialCloseVolumeInProfit(); + double partialCloseProfitPoint = PartialCloseOnSpecificPointOfProfit(); + if (partialCloseVolume > 0 && partialCloseProfitPoint > 0) + { + // + double profitPoints = position.GetProfitInPoint(); + if (profitPoints >= partialCloseProfitPoint && !mData[iDX].partiallyClosed) + { + // + string comment = "EQM Partial Close ..."; + + // + // Do Partial Closing ... + result = mTrader.ClosePartial( + position.ticket, + partialCloseVolume, + comment // + ); + if (result) + { + // + mData[iDX].partiallyClosed = true; + + // + string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + // + // In Drawdown ... + // When a Position running in Drawdown, we have to look for pressures by Indirection + // of Main Position. for example if it is long, we Look For Bearish Pressures and if + // it is short we Look for Bullish Pressure. + // when indirectional pressure found we must Open a Recovery Position. + // also if Same Direction Pressure Found we try to Recover Same Direction using Grid ... + else + { + // + bool allowRecover = AllowRecoverInDrawdowns(); + double volumeMultiplier = RecoveryMultiplier(); + if (allowRecover && !canFreeze && volumeMultiplier > 0) + { + // + bool canRecover = false; + int delayMinutes = RecoveryDelayInMinute(); + double recoveryDistancePoint = RecoveryDistanceInPoint(); + + // + // Temparory Requirement for Recover Signal ... + double sl = 0; + double tp = 0; + double entry = 0; + ENUM_POSITION_TYPE type = NULL; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + double lastStep = mData[iDX].protectionStep; + double volume = position.volume * volumeMultiplier; + bool applyLevel = ApplyRecoveryLevelOnVolume(); + if (applyLevel) + { + // + volume = supportsCount <= 0 + ? position.volume * volumeMultiplier + : position.volume * ((supportsCount + 1) * volumeMultiplier); + } + + // + datetime currentTime = TimeCurrent(); + double currentDrawdown = position.GetProfitInPoint(); + datetime lastProtectedOn = mData[iDX].lastProtectedOn; + double lastProtectedDrawdown = mData[iDX].lastProtectedInDrawdown; + bool isRecoveryConditionsPassed = supportsCount <= 0 + ? true + : + // + // Check Regular Conditions ... + delayMinutes > 0 && + recoveryDistancePoint > 0 && + IsValid(lastProtectedOn) && + lastProtectedDrawdown < 0 && + // + // Check Time Delay Passed ... + (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) >= ulong(delayMinutes * 60) && + // + // Check Recovery Distance Passed ... + MathAbs(currentDrawdown) - MathAbs(lastProtectedDrawdown) >= recoveryDistancePoint; + + // + if (isRecoveryConditionsPassed) + { + // + // Long Recovery ... + if (isLong) + { + // + // Opposit Direction ... + canRecover = + // + isTicksBearishForShort && + hasBearishTrend && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ; + if (canRecover) + { + // + sl = position.tp; + tp = position.sl; + type = POSITION_TYPE_SELL; + } + } + // + // Short Recovery ... + else + { + // + // Opposit Direction ... + canRecover = + // + isTicksBullishForLong && + hasBullishTrend && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ; + if (canRecover) + { + // + sl = position.tp; + tp = position.sl; + type = POSITION_TYPE_BUY; + } + } + + // + if (canRecover) + { + // + XSignal signal; + entry = GetEntry( + position.symbol, + type // + ); + + // + // Prepare Signal ... + result = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + volume, + sl, + tp // + ); + + // + if (result) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (result) + { + // + mData[iDX].protectionStep++; + mData[iDX].lastProtectedOn = currentTime; + mData[iDX].lastProtectedInDrawdown = currentDrawdown; + + // + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Recovery Position in Level: " + + ToString(lastStep + 1) + + " for (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + } + + // + if (canFreeze && + supportsCount <= 0 && + position.profit < 0 && + !mData[iDX].freezed && + MathAbs(profitInPoint) >= freezePoint) + { + // + bool removeTPSL = RemoveFreezedPositionsTPSL(); + // + // Temparory Requirement for Recover Signal ... + double sl = removeTPSL ? 0 : position.tp; + double tp = removeTPSL ? 0 : position.sl; + ENUM_POSITION_TYPE type = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + double entry = GetEntry( + position.symbol, + type // + ); + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; + double volume = position.volume * freezeVolumeMultiplier; + + // + XSignal signal; + + // + // Prepare Signal ... + result = signal.Prepare( + position.symbol, + position.provider, + position.period, + type, + mode, + entry, + volume, + sl, + tp // + ); + + // + if (result) + { + // + // Generate Comment for Recover and Support ... + string comment = GenerateSupportTag(position.ticket); + + // + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + result = ExecuteSignal( + signal, + state, + true // Support Signal need to Ignore Policies ... + ); + if (result) + { + // + mData[iDX].freezed = true; + + // + string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Freeze Position for (" + ToString(position.ticket) + ")"; + Alert(message); + + // + string comment = "EQM Removes Freezed TP/SL ..."; + result = mTrader.Modify( + position.ticket, + 0, + 0, + comment // + ); + + // + if (result) + { + // + string message = "EQM Remove Freezed Position (" + ToString(position.ticket) + ") TP/SL .."; + Alert(message); + } + } + } + } + + // + // Check Points of Drawdown and Do Partial Closing ... + double partialCloseVolume = PartialCloseVolumeInDrawdown(); + double partialCloseDrawdownPoint = PartialCloseOnSpecificPointOfDrawdown(); + if (partialCloseVolume > 0 && partialCloseDrawdownPoint > 0) + { + // + double profitPoints = position.GetProfitInPoint(); + if (profitPoints < 0 && MathAbs(profitPoints) >= partialCloseDrawdownPoint && !mData[iDX].partiallyClosed) + { + // + string comment = "EQM Partial Close ..."; + + // + // Do Partial Closing ... + result = mTrader.ClosePartial( + position.ticket, + partialCloseVolume, + comment // + ); + if (result) + { + // + mData[iDX].partiallyClosed = true; + + // + string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + // Read Only ... + int maxSameTimeTrades; // Max Same Time Trades + double maxDrawdown; // Max Drawdown + double drawdownPercent; // Drawdown Percent + double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation + + // + bool mSaveSignals; // Save Signals + bool mSaveTrades; // Save Trades + bool mSaveConditions; // Save SL Conditions + + // + bool mAllowLong; // Allow Long/Buy Trade Type + bool mAllowShort; // Allow Short/Sell Trade Type + int mMaxAllowedLongs; // Max Allowe Long/Buy Trades + int mMaxAllowedShorts; // Max Allowe Short/Sell Trades + bool mUseMaxAllowedTradesPerSymbol; // Use Max Allowed Trades Per Symbol + double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades + + // + int mDelayBarBetweenTwoSameSignal; // Delay Bars Between Two Same Type Signal + double mProtectorStartDistanceInPoint; // Protector Start Distance in Point + + // + // In Profit Positions Protecting ... + bool mAllowTrailStopInProfits; // Allow Trail Stops for In Profit Positions + double mTrailStartDistanceInPoint; // Start Trail on Specific Point of Profit + bool mOnlyTrailUnprotectedPositions; // Only Trail UnProtected Positions + double mTrailStopStepsInPoint; // Trail Stop Steps in Point + int mRmoveTPOnTrailStep; // Remove Position TP if Trailed specific times + double mPartialCloseOnSpecificPointOfProfit; // Partial Close Position on Specific Points of Profit + double mPartialCloseVolumeInProfit; // Partial Close Volume + + // + // In Drawdown Positions Protecting ... + bool mFreezeInDrawdon; // Freeze In Drawdown Position by Lock it + double mFreezePoint; // Freezing Drawdown Point + double mFreezeVolume; // Freezing Volume Multiplier + bool mRemoveFreezedPositionsTPSL; // Removes Freezed Positions TP and SL + bool mAllowRecoverInDrawdowns; // Allow Recovery For In Drawdown Positions + double mRecoveryMultiplier; // Recovery Volume Multiplier + bool mApplyRecoveryLevelOnVolume; // Apply Recovery Level on Volume Calculation + int mRecoveryDelayInMinute; // Delay Between Two Recovery in Minutes + double mRecoveryDistanceInPoint; // Distance Between Two Recovery in Point + double mPartialCloseOnSpecificPointOfDrawdown; // Partial Close Position on Specific Points of Drawdown + double mPartialCloseVolumeInDrawdown; // Partial Close Volume + + // + // Hedging Properties ... + bool mAllowHedge; // Allow Protector to Hedge Positions + double mHedgeMinVolumeStep; // Minimum Volume Step For Hedge + int mMinimumOpenPositionsForHEHedge; // Minimum Open Positions For HE Hedge + double mHedgeHEMinProfitPerVolumeStep; // Minimum Required Profit For HE Hedge Per Volume Step + double mHedgeBEMinProfitPerVolumeStep; // Minimum Required Profit For BE Hedge Per Volume Step + + // + // Common Functions ... + + // + // Count Data ... + int Count() + { + return ArraySize(mData); + } + + // + // Add Item ... + bool Add(X121TradeData &item) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + int index = -1; + if (item.ticket > 0) + { + // + result = !HasItem( + item.ticket, + index // + ); + } + else + { + // + result = !HasItem( + item.symbol, + item.provider, + item.period, + item.type, + index // + ); + } + if (!result || IsValidIndex(index)) + { + // + result = false; + return result; + } + + // + AddRef( + item, + mData // + ); + + // + return result; + } + + // + // Find Item Index ... + bool HasItem( + ulong ticket, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + result = mData[i].IsOwn(ticket); + if (result) + { + // + index = i; + break; + } + } + + // + return result; + } + + // + // Find Item Index ... + bool HasItem( + string symbol, + string provider, + ENUM_TIMEFRAMES period, + ENUM_X_POSITION_TYPES type, + int &index // + ) + { + // + bool result = false; + + // + index = -1; + + // + // Validate ... + result = + // + IsValid(symbol) && + IsValid(period) && + IsValid(provider) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + if (!result) + { + return result; + } + + // + int count = Count(); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + result = mData[i].IsOwn( + symbol, + provider, + period, + type // + ); + if (result) + { + // + index = i; + break; + } + } + + // + return result; + } + + // + void Save(int index) + { + // + int count = Count(); + if (!IsValidIndex(index) || index > count - 1) + { + return; + } + + // + // Save Trade ... + if (mSaveTrades) + { + mCollector.Save(mData[index]); + } + + // + if (mSaveConditions) + { + mCollector.SaveConditions(mData[index]); + } + + // + // Remove Item From List ... + ArrayRemove( + mData, + index, + 1 // + ); + } + + // + void SaveSignal(X121TradeData &item) + { + // + if (!mSaveSignals) + { + return; + } + + // + // Save Signal ... + mCollector.SaveSignal(item); + } + + // +}; + +// \ No newline at end of file diff --git a/Experts/x-saherelm.x121.ea.mq5 b/Experts/x-saherelm.x121.ea.mq5 index f807d1d2..f1c3cd3d 100644 --- a/Experts/x-saherelm.x121.ea.mq5 +++ b/Experts/x-saherelm.x121.ea.mq5 @@ -100,27 +100,48 @@ input double eaHedgeBEMinProfitPerVolumeStep = 0.1; // Minimum Required Profit F // // Protector > In Profit Positions Protecting ... input group "In Profit Positions Protecting"; -input bool eaAllowTrailStopInProfits = true; // Allow Trail Stops for In Profit Positions -input bool eaOnlyTrailUnprotectedPositions = true; // Only Trail UnProtected Positions -input double eaTrailStopStepsInPoint = 10; // Trail Stop Steps in Point -input int eaRmoveTPOnTrailStep = 5; // Remove Position TP if Trailed specific times -input double eaPartialCloseOnSpecificPointOfProfit = 0; // Partial Close Position on Specific Points of Profit -input double eaPartialCloseVolumeInProfit = 0; // Partial Close Volume + +// +// Trail ... +input group "Trail"; +input bool eaAllowTrail = true; // Allow Trail Stop for Positions +input double eaTrailStartDistance = 35; // Specify Trail Start in Point +input double eaTrailStep = 10; // Trail Step in Point +input bool eaOnlyTrailUnprotected = true; // Only Trail Unprotected Positionss + +// +// Partial Close (In Profit) ... +input group "Partial Close"; +input double eaPartialCloseInProfitDistance = 0; // Specify Partial Close Profit in Point +input double eaPartialCloseInProfitVolume = 0; // Specify Partial Close in Profit Volume // // Protector > In Drawdown Positions Protecting ... input group "In Drawdown Positions Protecting"; -input bool eaFreezeInDrawdon = true; // Freeze In Drawdown Position by Lock it -input double eaFreezePoint = 100; // Freezing Drawdown Point -input double eaFreezeVolume = 2; // Freezing Volume Multiplier -input bool eaRemoveFreezedPositionsTPSL = true; // Removes Freezed Positions TP and SL -input bool eaAllowRecoverInDrawdowns = false; // Allow Recovery For In Drawdown Positions -input double eaRecoveryMultiplier = 1; // Recovery Volume Multiplier -input bool eaApplyRecoveryLevelOnVolume = false; // Apply Recovery Level on Volume Calculation -input int eaRecoveryDelayInMinute = 1; // Delay Between Two Recovery in Minutes -input double eaRecoveryDistanceInPoint = 30; // Distance Between Two Recovery in Point -input double eaPartialCloseOnSpecificPointOfDrawdown = 0; // Partial Close Position on Specific Points of Drawdown -input double eaPartialCloseVolumeInDrawdown = 0; // Partial Close Volume + +// +// Freeze ... +input group "Freeze"; +input bool eaAllowFreeze = false; // Allow Freezing +input double eaFreezeDistance = 100; // Specify Freeze Start Drawdown in Point +input bool eaRemoveFreezedPositionTPSL = true; // Remove Freezed Positions TPSL +input bool eaDisableTrailWhenFreezedPosition = true; // Disable Trail when has Freezed Position + +// +// Support ... +input group "Support"; +input bool eaAllowSupport = false; // Allow Support +input double eaSupportStartDistance = 0; // Specify Start Support Drawdown in Point +input double eaSupportVolumeMultiplier = 1; // Specify Support Volume Multiplier +input bool eaMultiplySupportLevelOnVolume = false; // Multiply Support Level on Volume Multiplier +input bool eaDoSupportOnConditions = true; // Do Support on Conditions +input int eaDelayBetweenTwoSupport = 60; // Delay Between To Support in Second + +// +// Partial Close (In Drawdown) ... +input group "Partial Close"; +input double eaPartialCloseInDrawdownDistance = 0; // Specify Partial Close Drawdown in Point +input double eaPartialCloseInDrawdownVolume = 0; // Specify Partial Close in Drawdown Volume // // Alert ... @@ -483,7 +504,6 @@ bool InitialEA() // eaTradeHandler.DelayBarBetweenTwoSameSignal(eaDelayBarBetweenTwoSameSignal); - eaTradeHandler.ProtectorStartDistanceInPoint(eaProtectorStartDistanceInPoint); // // Configure Hedging ... @@ -495,29 +515,42 @@ bool InitialEA() // // In Profit Position Protecting ... - eaTradeHandler.AllowTrailStopInProfits(eaAllowTrailStopInProfits); - eaTradeHandler.OnlyTrailUnprotectedPositions(eaOnlyTrailUnprotectedPositions); - eaTradeHandler.TrailStopStepsInPoint(eaTrailStopStepsInPoint); - eaTradeHandler.RmoveTPOnTrailStep(eaRmoveTPOnTrailStep); - eaTradeHandler.PartialCloseOnSpecificPointOfProfit(eaPartialCloseOnSpecificPointOfProfit); - eaTradeHandler.PartialCloseVolumeInProfit(eaPartialCloseVolumeInProfit); // - // Protector > In Drawdown Positions Protecting ... - eaTradeHandler.FreezeInDrawdon(eaFreezeInDrawdon); - eaTradeHandler.FreezePoint(eaFreezePoint); - eaTradeHandler.FreezeVolume(eaFreezeVolume); - eaTradeHandler.RemoveFreezedPositionsTPSL(eaRemoveFreezedPositionsTPSL); - eaTradeHandler.AllowRecoverInDrawdowns(eaAllowRecoverInDrawdowns); - eaTradeHandler.RecoveryMultiplier(eaRecoveryMultiplier); - eaTradeHandler.ApplyRecoveryLevelOnVolume(eaApplyRecoveryLevelOnVolume); - eaTradeHandler.RecoveryDelayInMinute(eaRecoveryDelayInMinute); - eaTradeHandler.RecoveryDistanceInPoint(eaRecoveryDistanceInPoint); - eaTradeHandler.PartialCloseOnSpecificPointOfDrawdown(eaPartialCloseOnSpecificPointOfDrawdown); - eaTradeHandler.PartialCloseVolumeInDrawdown(eaPartialCloseVolumeInDrawdown); + // Trail ... + eaTradeHandler.AllowTrail(eaAllowTrail); + eaTradeHandler.TrailStartDistance(eaTrailStartDistance); + eaTradeHandler.TrailStep(eaTrailStep); + eaTradeHandler.OnlyTrailUnprotected(eaOnlyTrailUnprotected); // - // TODO: Implement ... + // Partial Close (In Profit) ... + eaTradeHandler.PartialCloseInProfitDistance(eaPartialCloseInProfitDistance); + eaTradeHandler.PartialCloseInProfitVolume(eaPartialCloseInProfitVolume); + + // + // In Drawdown Positions Protecting ... + + // + // Freeze ... + eaTradeHandler.AllowFreeze(eaAllowFreeze); + eaTradeHandler.FreezeDistance(eaFreezeDistance); + eaTradeHandler.RemoveFreezedPositionTPSL(eaRemoveFreezedPositionTPSL); + eaTradeHandler.DisableTrailWhenFreezedPosition(eaDisableTrailWhenFreezedPosition); + + // + // Support ... + eaTradeHandler.AllowSupport(eaAllowSupport); + eaTradeHandler.SupportStartDistance(eaSupportStartDistance); + eaTradeHandler.SupportVolumeMultiplier(eaSupportVolumeMultiplier); + eaTradeHandler.MultiplySupportLevelOnVolume(eaMultiplySupportLevelOnVolume); + eaTradeHandler.DoSupportOnConditions(eaDoSupportOnConditions); + eaTradeHandler.DelayBetweenTwoSupport(eaDelayBetweenTwoSupport); + + // + // Partial Close (In Profit) ... + eaTradeHandler.PartialCloseInDrawdownDistance(eaPartialCloseInDrawdownDistance); + eaTradeHandler.PartialCloseInDrawdownVolume(eaPartialCloseInDrawdownVolume); // // Configure Strategies ... @@ -906,6 +939,10 @@ void OnSignalRecieved( { signal.volume = dVolume; } + else + { + signal.volume = eaVolume; + } // eaTradeHandler.UpdateSignal(signal); diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index 170576c7..5a1d874d 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -7274,7 +7274,7 @@ bool GetTick( /** * Retrieve Tick Entry ... */ -double GetTickEnty( +double GetTickEntry( MqlTick &mTick, ENUM_POSITION_TYPE type, string mSymbol = NULL //