From 6b05f48cdeaa26b90d4e53a0c5ba76d3efa1c9ff Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Wed, 5 Jun 2024 06:25:20 +0330 Subject: [PATCH] apply signaller's Policies in EA signal manager before Execute Signals ... --- Classes/x-saherelm.x121.provider.class.mq5 | 51 ++++ Classes/x-saherelm.x121.xea.class.mq5 | 230 ++++++++++++++++++ Classes/x-saherelm.x121.xmcycle.class.mq5 | 64 ++++- Classes/x-saherelm.xtrade.class.mq5 | 36 +++ Libraries/x-saherelm.common.lib.mq5 | 17 +- .../x-saherelm.x110.signaller.class.mq5 | 18 ++ .../x-saherelm.x121.signaller.class.mq5 | 18 ++ .../x-saherelm.x786.signaller.class.mq5 | 28 ++- 8 files changed, 447 insertions(+), 15 deletions(-) diff --git a/Classes/x-saherelm.x121.provider.class.mq5 b/Classes/x-saherelm.x121.provider.class.mq5 index 5c6cfe1c..34e2d289 100644 --- a/Classes/x-saherelm.x121.provider.class.mq5 +++ b/Classes/x-saherelm.x121.provider.class.mq5 @@ -1778,6 +1778,57 @@ struct X121ProviderDescriptor // return result; } + + // + // Find Specific Signaller Index ... + int FindSignallerIndex(ENUM_XSIGNAL_PROVIDERS name) + { + // + int result = -1; + + // + // Converts Provided Signaller Name to String ... + string strName = ToString(name); + + // + result = FindSignallerIndex(strName); + + // + return result; + } + + // + // Find Specific Signaller Index ... + int FindSignallerIndex(string name) + { + // + int result = -1; + + // + int signallersCount = ArraySize(signallers); + if (!IsValid() || + !IsValid(name) || + !IsValidSize(signallersCount) || + name == ToString(PROVIDER_NONE)) + { + return result; + } + + // + for (int i = 0; i < signallersCount; i++) + { + // + if (signallers[i].GetName() == name) + { + // + result = i; + break; + } + } + + // + return result; + } }; // \ No newline at end of file diff --git a/Classes/x-saherelm.x121.xea.class.mq5 b/Classes/x-saherelm.x121.xea.class.mq5 index 02b7c27a..9b5c0273 100644 --- a/Classes/x-saherelm.x121.xea.class.mq5 +++ b/Classes/x-saherelm.x121.xea.class.mq5 @@ -272,6 +272,236 @@ public: return false; } + // + // Here we Manage Signals for Executing ... + // - Check Policies based on their Signaller ... + // - Check Same Time Open Positions ... + // - Check Signal Age for new Trade ... + // and etc ... + int HandleSignalManagement(XSignal &signals[]) + { + // + int result = 0; + + // + int signalsCount = ArraySize(signals); + if (!IsValidSize(signalsCount)) + { + return result; + } + + // + XSignal tmpSignals[]; + Copy( + signals, + tmpSignals // + ); + + // + Clean(signals); + + // + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = tmpSignals[i]; + + // + // Find Provider Descriptor Which Issued this Signal ... + int iProviderIDX = FindDescriptorIndex( + iSignal.symbol, + iSignal.period); + if (!IsValidIndex(iProviderIDX)) + { + // + string message = "Couldn't find Signal Descriptor ..."; + Log(message); + + // + continue; + } + + // + // Now we Have to Find Signaller Which Issued this Signal ... + int iSignallerIDX = mDescriptors[iProviderIDX] + .FindSignallerIndex(iSignal.provider); + if (!IsValidIndex(iSignallerIDX)) + { + // + string message = "Couldn't find Signal Provider ..."; + Log(message); + + // + continue; + } + + // + // Check Position Type is Enabled or not ... + bool isLong = IsLong(iSignal.type); + bool isAllowedType = isLong + ? mDescriptors[iProviderIDX].signallers[iSignallerIDX].allowLong + : mDescriptors[iProviderIDX].signallers[iSignallerIDX].allowShort; + if (!isAllowedType) + { + // + string message = "ignore Signal due Type Policy ..."; + Log(message); + + // + continue; + } + + // + // Retrieve Long and Short Signals of same Provider ... + XPosition longs[]; + XPosition shorts[]; + mTrader.GetPositions( + longs, + shorts, + iSignal.symbol, + iSignal.provider, + iSignal.period // + ); + int longsCount = ArraySize(longs); + int shortsCount = ArraySize(shorts); + + // + // Check Max Number of Positions ... + bool isMaxNumberOfPositionsPassed = isLong + ? mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedLong <= 0 + ? true + : longsCount < mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedLong + : mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedShort <= 0 + ? true + : shortsCount < mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedShort; + if (!isMaxNumberOfPositionsPassed) + { + // + string message = "ignore Signal due Max Allowed Positions Reached ..."; + Log(message); + + // + continue; + } + + // + // Check Delay Between Two Same Type Signals ... + // Check Open Next Behaviour ... + if (longsCount > 0 || shortsCount > 0) + { + // + // Check if Signaller Configured for Check Delay between Same type Signals ... + if (mDescriptors[iProviderIDX].signallers[iSignallerIDX].delayBetweenTwoSameTypeSignals > 0) + { + // + bool isDelayPassed = true; + + // + if (longsCount > 0) + { + // + XPosition youngestLong; + int youngestLongAge = GetYoungest( + youngestLong, + longs // + ); + + // + if (isLong) + { + isDelayPassed = youngestLongAge >= mDescriptors[iProviderIDX].signallers[iSignallerIDX].delayBetweenTwoSameTypeSignals; + } + } + + // + if (shortsCount > 0) + { + // + XPosition youngestShort; + int youngetsShortAge = GetYoungest( + youngestShort, + shorts // + ); + + // + if (!isLong) + { + isDelayPassed = youngetsShortAge >= mDescriptors[iProviderIDX].signallers[iSignallerIDX].delayBetweenTwoSameTypeSignals; + } + } + + // + if (!isDelayPassed) + { + // + string message = "ignore Signal due Delay Between Same Type Policy ..."; + Log(message); + + // + continue; + } + } + + // + // Check Next Position ... + if (mDescriptors[iProviderIDX].signallers[iSignallerIDX].openNextPositionOnProfit) + { + // + bool isNextPassed = true; + + // + if (isLong && longsCount > 0) + { + // + double profit = SpecifiedCalculatePositionsProfit(longs); + isNextPassed = profit > 0; + } + + // + if (!isLong && shortsCount > 0) + { + // + double profit = SpecifiedCalculatePositionsProfit(shorts); + isNextPassed = profit > 0; + } + + // + // Check Ignore for Opposit Signals ... + if (!isNextPassed && + ((isLong && shortsCount > longsCount) || + (!isLong && longsCount > shortsCount))) + { + isNextPassed = mDescriptors[iProviderIDX].signallers[iSignallerIDX].ignoreProfitForOppositeSignals; + } + + // + if (!isNextPassed) + { + // + string message = "ignore Signal due Next Must be In Profit Policy ..."; + Log(message); + + // + continue; + } + } + } + + // + // Finally Add Filtered Signals into Result ... + AddRef( + iSignal, + signals // + ); + } + + // + result = ArraySize(signals); + + // + return result; + } + // // Tools ... diff --git a/Classes/x-saherelm.x121.xmcycle.class.mq5 b/Classes/x-saherelm.x121.xmcycle.class.mq5 index a7b716e6..4cc721eb 100644 --- a/Classes/x-saherelm.x121.xmcycle.class.mq5 +++ b/Classes/x-saherelm.x121.xmcycle.class.mq5 @@ -2537,18 +2537,36 @@ public: // Props ... // - ENUM_XSIGNAL_PROVIDERS name; + ENUM_XSIGNAL_PROVIDERS name; // Signaller Name // - bool allowLong; - bool allowShort; + bool allowLong; // Allow Long Positions + bool allowShort; // Allow Short Positions // - double r2r; + double r2r; // Risk To Reward Ratio + + // + double staticVolumeLong; // Static Volume for Long + double staticVolumeShort; // Static Volume For Short + + // + int maxAllowedLong; // Max Allowed Same Time Long Open Positions + int maxAllowedShort; // Max Allowed Same Time Short Open Positions + + // + int delayBetweenTwoSameTypeSignals; // Delay between Two Same Type Signals + int maxAllowedOpenPositionAge; // Close Position if Still Alive bigger than this value + + // + double minRequiredProfitPerTrade; // Minimum Required Profit Per Trade for Hedging + double minRequiredProfitPerTradeVolumeFactor; // Calculate Required Profit Based on Volume Factor for Hedging + + // + bool openNextPositionOnProfit; // Open Next Signaller Position only When Previous Signals in Profit + bool ignoreProfitForOppositeSignals; // Ignore In Profit Policy when Opposite Signal Comming // - double staticVolumeLong; - double staticVolumeShort; // // Constructor ... @@ -2576,6 +2594,20 @@ public: // staticVolumeLong = 0; staticVolumeShort = 0; + + // + maxAllowedLong = 0; + maxAllowedShort = 0; + maxAllowedOpenPositionAge = 0; + delayBetweenTwoSameTypeSignals = 0; + + // + minRequiredProfitPerTrade = 0; + minRequiredProfitPerTradeVolumeFactor = 0; + + // + openNextPositionOnProfit = false; + ignoreProfitForOppositeSignals = false; } // @@ -2604,11 +2636,31 @@ public: } // + // Retrieve Signaller Name as String ... string GetName() { return ToString(name); } + // + // Check Hedge is Enable or Not ... + bool AllowHedge() + { + // + bool result = false; + + // + result = + // + minRequiredProfitPerTrade > 0 && + minRequiredProfitPerTradeVolumeFactor > 0 + // + ; + + // + return result; + } + // // Generate Signal ... bool GenerateSignal( diff --git a/Classes/x-saherelm.xtrade.class.mq5 b/Classes/x-saherelm.xtrade.class.mq5 index 81a7cec9..6274b659 100644 --- a/Classes/x-saherelm.xtrade.class.mq5 +++ b/Classes/x-saherelm.xtrade.class.mq5 @@ -2131,6 +2131,42 @@ public: return mResult; } + // + void GetPositions( + XPosition &longs[], // Hold's Longs Result + XPosition &shorts[], // Hold's Shorts Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + // Retrieve Long Positions ... + GetPositions( + longs, + symbol, + provider, + period, + POSITION_TYPE_BUY, + filterByMagic, + forceClean // + ); + + // + // Retrieve Short Positions ... + GetPositions( + shorts, + symbol, + provider, + period, + POSITION_TYPE_SELL, + filterByMagic, + forceClean // + ); + } + // // Select In Profit Positions ... int GetInProfitPositions( diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index a78067bd..d73c240d 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -3850,6 +3850,13 @@ bool IsValidSize(T &buffer[]) return result; } +// +// Check a Given Index is Valid or not ... +bool IsValidIndex(int index) +{ + return index >= 0; +} + // // Normalize Index Based On Specified Buffer ... template @@ -5776,12 +5783,12 @@ void Copy( // Copy Items from a Buffer ... template int Copy( - int start, // Start - int count, // Number of Items for read - T &source[], // Source Buffer - T &dest[], // Dest Buffer + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer bool forceClean = true, // Force To Clean buffer - bool forceStart = true // Force To Clean buffer + bool forceStart = true // Force To Clean buffer ) { // diff --git a/Signallers/x-saherelm.x110.signaller.class.mq5 b/Signallers/x-saherelm.x110.signaller.class.mq5 index 976272b1..14c97d50 100644 --- a/Signallers/x-saherelm.x110.signaller.class.mq5 +++ b/Signallers/x-saherelm.x110.signaller.class.mq5 @@ -307,8 +307,26 @@ public: // r2r = 1; + // + maxAllowedLong = 3; + maxAllowedShort = 3; + // staticVolumeLong = 0.01; staticVolumeShort = 0.01; + + // + maxAllowedOpenPositionAge = 576; // Two Days on 5 Min + delayBetweenTwoSameTypeSignals = 12; // 1 Hour on 5 Min + + // + // Set 10 $ Per each Trade on 0.01 Volume + // is Enough for Hedging ... + minRequiredProfitPerTrade = 10; + minRequiredProfitPerTradeVolumeFactor = 0.01; + + // + openNextPositionOnProfit = true; + ignoreProfitForOppositeSignals = true; } }; \ No newline at end of file diff --git a/Signallers/x-saherelm.x121.signaller.class.mq5 b/Signallers/x-saherelm.x121.signaller.class.mq5 index d8ac18cb..95e7fce4 100644 --- a/Signallers/x-saherelm.x121.signaller.class.mq5 +++ b/Signallers/x-saherelm.x121.signaller.class.mq5 @@ -181,8 +181,26 @@ public: // r2r = 1; + // + maxAllowedLong = 3; + maxAllowedShort = 3; + // staticVolumeLong = 0.01; staticVolumeShort = 0.01; + + // + maxAllowedOpenPositionAge = 576; // Two Days on 5 Min + delayBetweenTwoSameTypeSignals = 12; // 1 Hour on 5 Min + + // + // Set 10 $ Per each Trade on 0.01 Volume + // is Enough for Hedging ... + minRequiredProfitPerTrade = 10; + minRequiredProfitPerTradeVolumeFactor = 0.01; + + // + openNextPositionOnProfit = true; + ignoreProfitForOppositeSignals = true; } }; \ No newline at end of file diff --git a/Signallers/x-saherelm.x786.signaller.class.mq5 b/Signallers/x-saherelm.x786.signaller.class.mq5 index 9ca8f9fe..23f043ba 100644 --- a/Signallers/x-saherelm.x786.signaller.class.mq5 +++ b/Signallers/x-saherelm.x786.signaller.class.mq5 @@ -104,9 +104,10 @@ public: conditions.isSMHKBullish)) // ; - + // - if (result) { + if (result) + { sl = conditions.donLowerHs[1]; } @@ -165,9 +166,10 @@ public: conditions.isSMHKBearish)) // ; - + // - if (result) { + if (result) + { sl = conditions.donUpperLs[1]; } @@ -186,8 +188,26 @@ public: // r2r = 1; + // + maxAllowedLong = 3; + maxAllowedShort = 3; + // staticVolumeLong = 0.01; staticVolumeShort = 0.01; + + // + maxAllowedOpenPositionAge = 576; // Two Days on 5 Min + delayBetweenTwoSameTypeSignals = 12; // 1 Hour on 5 Min + + // + // Set 10 $ Per each Trade on 0.01 Volume + // is Enough for Hedging ... + minRequiredProfitPerTrade = 10; + minRequiredProfitPerTradeVolumeFactor = 0.01; + + // + openNextPositionOnProfit = true; + ignoreProfitForOppositeSignals = true; } }; \ No newline at end of file