From 87c6321dcbbbbde02a55cb9a4ecccab840067793 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Fri, 9 May 2025 03:43:56 +0330 Subject: [PATCH] add supports for Symbol Restrictions ... --- Experts/x-saherelm.xcaea.ea.mq5 | 55 +- XCAEA/Classes/xcaea.x-trade.manager.class.mq5 | 523 ++++++++++++++++-- 2 files changed, 506 insertions(+), 72 deletions(-) diff --git a/Experts/x-saherelm.xcaea.ea.mq5 b/Experts/x-saherelm.xcaea.ea.mq5 index 33b08583..bb2402e0 100644 --- a/Experts/x-saherelm.xcaea.ea.mq5 +++ b/Experts/x-saherelm.xcaea.ea.mq5 @@ -53,17 +53,19 @@ input double eaConstantBalance = 0.0; // Constant Ba // // Management ... input group "Management"; -input bool eaAllowTrade = true; // Allow Trade on Signals -input bool eaAllowLongs = true; // Allow Long Trades -input bool eaAllowShorts = true; // Allow Short Trades -input int eaMaxAllowedTradesPerDay = 3; // Max Allowed Trades per Day -input int eaMaxAllowedSLsPerDay = 2; // Max Allowed SL(s) per Day -input string eaSessionStartTime = ""; // Trade Start Time -input string eaSessionEndTime = ""; // Trade End Time -input int eaMaxAllowedPositions = 5; // Max Allowed Same Time Trades -input double eaMaxAllowedSpread = 25; // Max Allowed Spread For Trade -input double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade -input string eaCloseAllOpenTradesAt = ""; // Close All Open Trades per Day At Specified Time +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input ENUM_XCAEA_TRADE_RESTRICTION_PERIOD eaRestrictionsPeriod = XCAEA_TRADE_RESTRICATION_DAILY; // Trade Restrictions Period +input int eaMaxAllowedTPs = 2; // Max Allowed TP(s) per Day +input int eaMaxAllowedSLs = 2; // Max Allowed SL(s) per Day +input int eaMaxAllowedTrades = 3; // Max Allowed Trades per Day +input string eaSessionStartTime = ""; // Trade Start Time +input string eaSessionEndTime = ""; // Trade End Time +input int eaMaxAllowedPositions = 5; // Max Allowed Same Time Trades +input double eaMaxAllowedSpread = 25; // Max Allowed Spread For Trade +input double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade +input string eaCloseAllOpenTradesAt = ""; // Close All Open Trades per Day At Specified Time // // Alert ... @@ -662,13 +664,13 @@ void InitRequirements() ); // - // - // - // - // eaMaxAllowedTradesPerDay - // eaMaxAllowedSLsPerDay - // eaSessionStartTime - // eaSessionEndTime + // Setting Trade Restrictions ... + eaTradeManager.SetTradeRestrictions( + eaRestrictionsPeriod, + eaMaxAllowedTPs, + eaMaxAllowedSLs, + eaMaxAllowedTrades // + ); // // EA Signaller ... @@ -711,23 +713,14 @@ void HandleTimeReport() // // Daily Report .... - bool isNewDay = eaTimeTracker.IsNewDay(); - if (isNewDay) + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) { // - // Handle New Day on Trade Manager ... - eaTradeManager.HandleNewDay(); + string msg = "New Day ..."; // - // Reporting New Day if Reuired ... - if (eaReportNewDays) - { - // - string msg = "New Day ..."; - - // - eaAlert.Alert(msg); - } + eaAlert.Alert(msg); } // diff --git a/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 b/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 index e9c2499d..39079e52 100644 --- a/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 +++ b/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 @@ -30,6 +30,29 @@ // // Definitions ... +// +enum ENUM_XCAEA_TRADE_RESTRICTION_PERIOD +{ + XCAEA_TRADE_RESTRICATION_NONE, // None + XCAEA_TRADE_RESTRICATION_HOURLY, // Per Hour + XCAEA_TRADE_RESTRICATION_DAILY, // Per Day + XCAEA_TRADE_RESTRICATION_WEEKLY, // Per Week + XCAEA_TRADE_RESTRICATION_MONTHLY, // Per Month +}; + +// +string ToString(ENUM_XCAEA_TRADE_RESTRICTION_PERIOD value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + // enum ENUM_XCAEA_TRADE_FINALIZATION { @@ -52,6 +75,95 @@ string ToString(ENUM_XCAEA_TRADE_FINALIZATION value) return result; } +// +struct XCAEASymbolInfo +{ + // + string symbol; + + // + int longs; + int shorts; + + // + int trades; + + // + int losses; + int profits; + + // + int managedSLs; + int managedTPs; + int managedTrades; + + // + // Constructor ... + XCAEASymbolInfo() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + + // + longs = 0; + shorts = 0; + + // + trades = 0; + + // + losses = 0; + profits = 0; + + // + managedSLs = 0; + managedTPs = 0; + managedTrades = 0; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(symbol); + + // + return result; + } + + // + bool IsSameAs(XCAEASymbolInfo &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + symbol == item.symbol; + + // + return result; + } +}; + // struct XCAEATrade { @@ -305,6 +417,7 @@ class XCXCAEATradeManager : public XCBaseAlert XCTrade *trader; bool drawSignal; XCPOIDrawer *drawer; + XTimeTracker timeTracker; XCXCAEADataCollector *collector; // @@ -324,6 +437,12 @@ class XCXCAEATradeManager : public XCBaseAlert allowLongs = true; allowShorts = true; + // + maxAllowedTPs = 0; + maxAllowedSLs = 0; + maxAllowedTrades = 0; + restrictionsPeriod = XCAEA_TRADE_RESTRICATION_NONE; + // reportTrades = true; reportSignals = true; @@ -352,6 +471,9 @@ class XCXCAEATradeManager : public XCBaseAlert // Clean(trades); + // + timeTracker.Clean(); + // ZeroMemory(trader); ZeroMemory(drawer); @@ -419,6 +541,27 @@ class XCXCAEATradeManager : public XCBaseAlert allowShorts = _allowShorts; } + // + void SetTradeRestrictions( + ENUM_XCAEA_TRADE_RESTRICTION_PERIOD _period, + int _maxAllowedTPs, + int _maxAllowedSLs, + int _maxAllowedTrades // + ) + { + // + // Normalizing Args ... + _maxAllowedTPs = NormalizeInt(_maxAllowedTPs, 0); + _maxAllowedSLs = NormalizeInt(_maxAllowedSLs, 0); + _maxAllowedTrades = NormalizeInt(_maxAllowedTrades, 0); + + // + restrictionsPeriod = _period; + maxAllowedTPs = _maxAllowedTPs; + maxAllowedSLs = _maxAllowedSLs; + maxAllowedTrades = _maxAllowedTrades; + } + // // Tools ... @@ -428,6 +571,11 @@ class XCXCAEATradeManager : public XCBaseAlert void Manage() { // + // Handle Restrictions ... + HandleRestrictions(); + + // + // Check Contains Trades for Managing ... bool has = HasChild(trades); if (!has) { @@ -435,6 +583,7 @@ class XCXCAEATradeManager : public XCBaseAlert } // + // Update Required Infos of Trades ... int count = ArraySize(trades); for (int i = 0; i < count; i++) { @@ -464,7 +613,7 @@ class XCXCAEATradeManager : public XCBaseAlert } // - // After Update All Trades we can Do Protection ... + // Do Trade Protection ... Protect(); } @@ -823,13 +972,56 @@ class XCXCAEATradeManager : public XCBaseAlert return result; } + // + // Check Symbol Info Exists or not ... + int symbolIDX = -1; + bool isSymbolExists = FindSymbolIndex( + symbolIDX, + signal.symbol // + ); + // // TODO: Complete this ... // Implementing Trade Session Validating ... // - // TODO: Complete this ... // Implementing Trade Permissions Based on SL(s) Count ... + bool hasRestrictions = restrictionsPeriod != XCAEA_TRADE_RESTRICATION_NONE; + if (hasRestrictions) + { + // + // Only Can Check Restrictions when + // Symbol Info Exists ... + if (isSymbolExists) + { + // + bool isTPAllowed = maxAllowedTPs == 0 + ? true + : symbols[symbolIDX].managedTPs < maxAllowedTPs; + bool isSLAllowed = maxAllowedSLs == 0 + ? true + : symbols[symbolIDX].managedSLs < maxAllowedSLs; + bool isTradeAllowed = maxAllowedTrades == 0 + ? true + : symbols[symbolIDX].managedTrades < maxAllowedTrades; + + // + result = isTPAllowed && + isSLAllowed && + isTradeAllowed; + } + + // + // Report Error ... + if (!result) + { + // + executionResult = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + + // + return result; + } + } // return result; @@ -914,6 +1106,7 @@ class XCXCAEATradeManager : public XCBaseAlert if (result) { // + // Draw Signal ... if (drawSignal) { // @@ -933,6 +1126,30 @@ class XCXCAEATradeManager : public XCBaseAlert } // + // Create Symbol Info Struct ... + XCAEASymbolInfo iSymbolInfo; + + // + iSymbolInfo.trades = 1; + iSymbolInfo.managedTrades = 1; + iSymbolInfo.symbol = signal.symbol; + + // + bool isLong = IsLong(signal.type); + if (isLong) + { + iSymbolInfo.longs = 1; + } + else + { + iSymbolInfo.shorts = 1; + } + + // + AddOrUpdateSymbolInfo(iSymbolInfo); + + // + // Create Trade Struct ... XCAEATrade iTrade; // @@ -984,10 +1201,6 @@ class XCXCAEATradeManager : public XCBaseAlert trades[idx].finalizedAt = TimeCurrent(); trades[idx].finalize = XCAEA_TRADE_FINAL_TP; - // - tpCount++; - managedTPCount++; - // // Save Trade ... Save(trades[idx]); @@ -997,6 +1210,20 @@ class XCXCAEATradeManager : public XCBaseAlert string prefix = "TP: " + ToString(trades[idx].profit); HandleReportBalance(prefix); + // + // Handle Symbol Info ... + + // + XCAEASymbolInfo iSymbolInfo; + + // + iSymbolInfo.profits = 1; + iSymbolInfo.managedTPs = 1; + iSymbolInfo.symbol = trades[idx].signal.symbol; + + // + AddOrUpdateSymbolInfo(iSymbolInfo); + // RemoveTrade(idx); } @@ -1027,10 +1254,6 @@ class XCXCAEATradeManager : public XCBaseAlert trades[idx].finalizedAt = TimeCurrent(); trades[idx].finalize = XCAEA_TRADE_FINAL_SL; - // - slCount++; - managedSLCount++; - // // Save Trade ... Save(trades[idx]); @@ -1040,6 +1263,33 @@ class XCXCAEATradeManager : public XCBaseAlert string prefix = "SL: " + ToString(trades[idx].profit); HandleReportBalance(prefix); + // + // Handle Symbol Info ... + + // + bool isInProfit = trades[idx].profit > 0; + + // + XCAEASymbolInfo iSymbolInfo; + + // + if (isInProfit) + { + // + iSymbolInfo.profits = 1; + iSymbolInfo.managedTPs = 1; + } + else + { + // + iSymbolInfo.losses = 1; + iSymbolInfo.managedSLs = 1; + } + iSymbolInfo.symbol = trades[idx].signal.symbol; + + // + AddOrUpdateSymbolInfo(iSymbolInfo); + // RemoveTrade(idx); } @@ -1076,20 +1326,6 @@ class XCXCAEATradeManager : public XCBaseAlert ? XCAEA_TRADE_FINAL_CLOSE_IN_PROFIT : XCAEA_TRADE_FINAL_CLOSE_IN_LOSE; - // - if (isInProfit) - { - // - tpCount++; - managedTPCount++; - } - else - { - // - slCount++; - managedSLCount++; - } - // // Save Trade ... Save(trades[idx]); @@ -1104,6 +1340,30 @@ class XCXCAEATradeManager : public XCBaseAlert ToString(trades[idx].profit); HandleReportBalance(prefix); + // + // Handle Symbol Info ... + + // + XCAEASymbolInfo iSymbolInfo; + + // + if (isInProfit) + { + // + iSymbolInfo.profits = 1; + iSymbolInfo.managedTPs = 1; + } + else + { + // + iSymbolInfo.losses = 1; + iSymbolInfo.managedSLs = 1; + } + iSymbolInfo.symbol = trades[idx].signal.symbol; + + // + AddOrUpdateSymbolInfo(iSymbolInfo); + // RemoveTrade(idx); } @@ -1114,15 +1374,6 @@ class XCXCAEATradeManager : public XCBaseAlert { } - /** - * Handle New Day ... - */ - void HandleNewDay() - { - // - // Clean Managed SL(s) and TP(s) and Positions ... - } - /** * Find Executed Trade by Providing Position Ticket ... * @@ -1381,6 +1632,197 @@ class XCXCAEATradeManager : public XCBaseAlert return result; } + // + // Symbol Info ... + + // + bool FindSymbolIndex( + int &index, + XCAEASymbolInfo &item // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + result = HasChild(symbols); + if (!result) + { + return result; + } + + // + index = FindIndex( + item, + symbols // + ); + + // + result = IsValidIndex(index); + + // + return result; + } + + // + bool FindSymbolIndex( + int &index, + string symbol // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = IsValid(symbol) && + HasChild(symbols); + if (!result) + { + return result; + } + + // + int count = ArraySize(symbols); + for (int i = 0; i < count; i++) + { + // + result = symbols[i].symbol == symbol; + if (result) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + void AddOrUpdateSymbolInfo(XCAEASymbolInfo &item) + { + // + bool has = item.IsValid(); + if (!has) + { + return; + } + + // + int index = -1; + bool isExists = FindSymbolIndex( + index, + item // + ); + if (!isExists) + { + // + AddRef( + item, + symbols // + ); + } + else + { + // + symbols[index].longs += item.longs; + symbols[index].shorts += item.shorts; + symbols[index].trades += item.trades; + symbols[index].losses += item.losses; + symbols[index].profits += item.profits; + symbols[index].managedSLs += item.managedSLs; + symbols[index].managedTPs += item.managedTPs; + symbols[index].managedTrades += item.managedTrades; + } + } + + // + void ResetSymbolsRestrictions() + { + // + bool has = HasChild(symbols); + if (has) + { + // + string prefix = "Protector: "; + + // + int count = ArraySize(symbols); + for (int i = 0; i < count; i++) + { + // + symbols[i].managedSLs = 0; + symbols[i].managedTPs = 0; + symbols[i].managedTrades = 0; + } + + // + string message = prefix + "Reset Symbols Restrictions"; + HandleReportProtector(message); + } + } + + // + void HandleRestrictions() + { + // + bool isNewDay = timeTracker.IsNewDay(); + bool isNewHour = timeTracker.IsNewHour(); + bool isNewWeek = timeTracker.IsNewWeek(); + bool isNewMonth = timeTracker.IsNewMonth(); + + // + bool canResetRestrictions = + ( + // + // Hourly ... + (isNewHour && + restrictionsPeriod == XCAEA_TRADE_RESTRICATION_HOURLY) + // + || + // + // Daily ... + (isNewDay && + restrictionsPeriod == XCAEA_TRADE_RESTRICATION_DAILY) + // + || + // + // Weekly ... + (isNewWeek && + restrictionsPeriod == XCAEA_TRADE_RESTRICATION_WEEKLY) + // + || + // + // Monthly ... + (isNewMonth && + restrictionsPeriod == XCAEA_TRADE_RESTRICATION_MONTHLY) + // + ) + // + ; + if (canResetRestrictions) + { + ResetSymbolsRestrictions(); + } + } + // // Private ... private: @@ -1392,17 +1834,15 @@ class XCXCAEATradeManager : public XCBaseAlert bool allowLongs; bool allowShorts; + // + int maxAllowedTPs; + int maxAllowedSLs; + int maxAllowedTrades; + ENUM_XCAEA_TRADE_RESTRICTION_PERIOD restrictionsPeriod; + // bool mSaveTrades; - // - int slCount; - int tpCount; - - // - int managedSLCount; - int managedTPCount; - // bool reportTrades; bool reportSignals; @@ -1414,6 +1854,7 @@ class XCXCAEATradeManager : public XCBaseAlert // XCAEATrade trades[]; + XCAEASymbolInfo symbols[]; }; //