/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCXGuard ... // Description: Guard Provider Class ... // Ued in XCTradeManager ... // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm Guard Provider Class" #property strict // // Imports ... #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-trade.class.mq5" #include "../Libraries/x-saherelm.x-guard.lib.mq5" // // Implementation ... class XCGuard : public XCBase { // // public ... public: // // Props ... double minVolumeFactorForHedge; // Minimum Volume Factor for Hedge Profit Calculation ... double minProfitPerVolumeFactorForHedge; // Minimum Required Profit per Volume Factor for Hedg ... TOnGuarded onGuardEventListener; // On Guard Event Listener ... // // Constructor(s) ... XCGuard( XCAlert *_alert, XCTrade *_trader // ) { // alert = _alert; trader = _trader; // minVolumeFactorForHedge = 0.01; minProfitPerVolumeFactorForHedge = 0.5; } // // Deconstructor(s) ... ~XCGuard() { // ZeroMemory(alert); ZeroMemory(trader); } // // Tools ... void DoGuards(XGuard &guards[]) { // bool has = HasChild(guards); if (!has) { return; } // XGuard tmp[]; Copy( guards, tmp // ); while (HasChild(tmp)) { // XGuard iGuard = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // // Do Guard Action ... DoGuard(iGuard); } // Clean(tmp); } // void DoGuard(XGuard &guard) { // bool has = false; // // Validate and Do Guard ... has = guard.IsValid(); if (!has) { return; } // // Switch Based on Guard Action ... switch (guard.action) { // // Close ... case X_GUARD_ACTION_CLOSE: DoClose(guard); break; // // Close All ... case X_GUARD_ACTION_CLOSE_ALL: DoCloseAll(guard); break; // // Close All Long Positions ... case X_GUARD_ACTION_CLOSE_LONGS: DoCloseLongs(guard); break; // // Close All Short Positions ... case X_GUARD_ACTION_CLOSE_SHORTS: DoCloseShorts(guard); break; // // Close In Losts ... case X_GUARD_ACTION_CLOSE_IN_LOSTS: DoCloseInLosts(guard); break; // // Close In Profits ... case X_GUARD_ACTION_CLOSE_IN_PROFITS: DoCloseInProfits(guard); break; // // Close In Lost Longs ... case X_GUARD_ACTION_CLOSE_IN_LOST_LONGS: DoCloseInLostLongs(guard); break; // // Close In Profit Longs ... case X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS: DoCloseInProfitLongs(guard); break; // // Close In Lost Shorts ... case X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS: DoCloseInLostShorts(guard); break; // // Close In Profit Shorts ... case X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT: DoCloseInProfitShorts(guard); break; // // Partial Close ... case X_GUARD_ACTION_PARTIAL_CLOSE: DoPartialClose(guard); break; // // Trail Stop ... case X_GUARD_ACTION_TRAIL_STOP: DoTrailStop(guard); break; // // Trail Target ... case X_GUARD_ACTION_TRAIL_TARGET: DoTrailTarget(guard); break; // // Hedge Positions ... case X_GUARD_ACTION_HEDGE: DoHedge(guard); break; // } } // // protected ... protected: // // bool GetPosition( XPosition &position, XGuard &guard // ) { // bool result = false; // position.Clean(); // result = guard.IsValid() && guard.ticket > 0; if (!result) { return result; } // // Get Position ... result = trader.GetPosition( guard.ticket, position // ); if (!result) { // position.Clean(); // return result; } // // Validate Position ... result = position.IsValid() && position.symbol == guard.symbol && position.provider == guard.provider && position.period == guard.period; if (!result) { // position.Clean(); // return result; } // return result; } // int GetPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // result = trader.GetPositions( positions, guard.symbol, guard.provider, guard.period, NULL, // All Types ... true, // Filter By Magc ... true // Force Clean ... ); // result = ArraySize(positions); // return result; } // int GetLongPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // result = trader.GetPositions( positions, guard.symbol, guard.provider, guard.period, X_POSITION_TYPE_LONG, // Specified Types ... true, // Filter By Magc ... true // Force Clean ... ); // result = ArraySize(positions); // return result; } // int GetShortPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // result = trader.GetPositions( positions, guard.symbol, guard.provider, guard.period, X_POSITION_TYPE_SHORT, // Specified Types ... true, // Filter By Magc ... true // Force Clean ... ); // result = ArraySize(positions); // return result; } // int GetInProfitPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // XPosition allPositions[]; int allPositionsCount = GetPositions( allPositions, guard // ); has = IsValidSize(allPositionsCount); if (!has) { return result; } // while (HasChild(allPositions)) { // XPosition iPosition = allPositions[0]; ArrayRemove( allPositions, 0, 1 // ); // if (iPosition.profit > 0) { // AddRef( iPosition, positions // ); } // iPosition.Clean(); } Clean(allPositions); // result = ArraySize(positions); // return result; } // int GetInLostPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // XPosition allPositions[]; int allPositionsCount = GetPositions( allPositions, guard // ); has = IsValidSize(allPositionsCount); if (!has) { return result; } // while (HasChild(allPositions)) { // XPosition iPosition = allPositions[0]; ArrayRemove( allPositions, 0, 1 // ); // if (iPosition.profit < 0) { // AddRef( iPosition, positions // ); } // iPosition.Clean(); } Clean(allPositions); // result = ArraySize(positions); // return result; } // int GetInProfitLongPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // XPosition allPositions[]; int allPositionsCount = GetLongPositions( allPositions, guard // ); has = IsValidSize(allPositionsCount); if (!has) { return result; } // while (HasChild(allPositions)) { // XPosition iPosition = allPositions[0]; ArrayRemove( allPositions, 0, 1 // ); // if (iPosition.profit > 0) { // AddRef( iPosition, positions // ); } // iPosition.Clean(); } Clean(allPositions); // result = ArraySize(positions); // return result; } // int GetInLostLongPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // XPosition allPositions[]; int allPositionsCount = GetLongPositions( allPositions, guard // ); has = IsValidSize(allPositionsCount); if (!has) { return result; } // while (HasChild(allPositions)) { // XPosition iPosition = allPositions[0]; ArrayRemove( allPositions, 0, 1 // ); // if (iPosition.profit < 0) { // AddRef( iPosition, positions // ); } // iPosition.Clean(); } Clean(allPositions); // result = ArraySize(positions); // return result; } // int GetInProfitShortPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // XPosition allPositions[]; int allPositionsCount = GetShortPositions( allPositions, guard // ); has = IsValidSize(allPositionsCount); if (!has) { return result; } // while (HasChild(allPositions)) { // XPosition iPosition = allPositions[0]; ArrayRemove( allPositions, 0, 1 // ); // if (iPosition.profit > 0) { // AddRef( iPosition, positions // ); } // iPosition.Clean(); } Clean(allPositions); // result = ArraySize(positions); // return result; } // int GetInLostShortPositions( XPosition &positions[], XGuard &guard // ) { // int result = 0; // Clean(positions); // bool has = guard.IsValid(); if (!has) { return result; } // XPosition allPositions[]; int allPositionsCount = GetShortPositions( allPositions, guard // ); has = IsValidSize(allPositionsCount); if (!has) { return result; } // while (HasChild(allPositions)) { // XPosition iPosition = allPositions[0]; ArrayRemove( allPositions, 0, 1 // ); // if (iPosition.profit < 0) { // AddRef( iPosition, positions // ); } // iPosition.Clean(); } Clean(allPositions); // result = ArraySize(positions); // return result; } // // Guard Handlers ... // void DoClose(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... // // Validate Action and Requirements ... has = NotEmpty(guard.ticket) && guard.action == X_GUARD_ACTION_CLOSE; if (!has) { return; } // // Retrieve Position ... XPosition position; has = GetPosition( position, guard // ); if (!has) { // position.Clean(); // return; } // string comment = "Guard Close ..."; // has = trader.Close( position.ticket, comment // ); if (has) { // HandleNotifyPositionGuard(guard.action, position); // string message = "Guard Closed " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // position.Clean(); } // void DoCloseAll(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_ALL; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseInLosts(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOSTS; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetInLostPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All In Losts ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " In Lost Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseInProfits(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFITS; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetInProfitPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All In Profits ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " In Profit Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseLongs(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_LONGS; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetLongPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close Longs ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " Long Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseInLostLongs(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOST_LONGS; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetInLostLongPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All In Lost Longs ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " In Lost Longs Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseInProfitLongs(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetInProfitLongPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All In Profit Longs ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " In Profit Longs Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseShorts(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetShortPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close Shorts ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " Long Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseInLostShorts(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetInLostShortPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All In Lost Shorts ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Closed " + ToXString(count) + " In Lost Shorts Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseInProfitShorts(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetInProfitShortPositions( positions, guard // ); has = IsValidSize(count); if (!has) { // Clean(positions); // return; } // string comment = "Guard Close All In Profit Shorts ..."; // has = trader.Close( positions, comment // ); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // // string message = "Guard Closed " + ToXString(count) + " In Profit Shorts Positions Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoPartialClose(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... // // Validate Action and Requirements ... has = NotEmpty(guard.ticket) && guard.volumeMultiplier > 0 && guard.action == X_GUARD_ACTION_PARTIAL_CLOSE; if (!has) { return; } // // Retrieve Position ... XPosition position; has = GetPosition( position, guard // ); if (!has) { // position.Clean(); // return; } // // Normalize Volume Multiplier ... double vMult = guard.volumeMultiplier; if (vMult > 0.5) { vMult = 0.5; } if (vMult < 0) { vMult = 0.5; } // // Calculate and Normalize Volume ... double volume = position.volume * vMult; volume = NormalizeVolume( volume, position.symbol // ); // string comment = "Guard Partially Closed: " + ToXString(volume) + " ..."; // has = trader.ClosePartial( position.ticket, volume, comment // ); if (has) { // HandleNotifyPositionGuard(guard.action, position); // string message = "Guard Closed Partially " + ToXString(volume) + " of " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // position.Clean(); } // void DoTrailStop(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... // // Validate Action and Requirements ... has = guard.sl >= 0 && NotEmpty(guard.ticket) && (guard.sl <= 0 ? guard.force : true) && guard.action == X_GUARD_ACTION_TRAIL_STOP; if (!has) { return; } // // Normalize SL ... if (guard.sl < 0) { guard.sl = 0; } // // Retrieve Position ... XPosition position; has = GetPosition( position, guard // ); if (!has) { // position.Clean(); // return; } // bool isLong = IsLong(position.type); bool isGuardPassed = guard.sl > 0 ? (isLong ? position.price > guard.sl && (position.sl == 0 || position.sl < guard.sl) : position.price < guard.sl && (position.sl == 0 || position.sl > guard.sl)) : (guard.sl == 0 && guard.force); // // Check Can Trail Stop or not ... has = // // Position Exists ... has && // // Positions in Profit for Trailling Stop ... position.profit > 0 && // // Validate SL based on Position Type ... isGuardPassed; if (!has) { // position.Clean(); // return; } // string comment = "Guard Trail Stop ..."; // has = trader.Modify( position.ticket, guard.sl, position.tp, comment // ); if (has) { // HandleNotifyPositionGuard(guard.action, position); // double before = NormalizePrice(position.sl, position.symbol); double after = NormalizePrice(guard.sl, position.symbol); // string message = "Guard Trail Stop " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ")" + " From: " + ToXString(before) + "To: " + ToXString(after) + " Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // position.Clean(); } // void DoTrailTarget(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... // // Validate Action and Requirements ... has = guard.tp >= 0 && NotEmpty(guard.ticket) && (guard.tp <= 0 ? guard.force : true) && guard.action == X_GUARD_ACTION_TRAIL_TARGET; if (!has) { return; } // // Normalize ... if (guard.tp < 0) { guard.tp = 0; } // // Retrieve Position ... XPosition position; has = GetPosition( position, guard // ); if (!has) { // position.Clean(); // return; } // bool isLong = IsLong(position.type); bool isGuardPassed = guard.tp > 0 ? (isLong ? guard.tp > position.price : guard.tp < position.price) : (guard.tp == 0 && guard.force); // // Check Can Trail Stop or not ... has = // // Position Exists ... has && // // Check TP is not Same ... guard.tp != position.tp && // // Validate TP based on Current Price ... isGuardPassed; if (!has) { // position.Clean(); // return; } // string comment = "Guard Trail Target ..."; // has = trader.Modify( position.ticket, position.sl, guard.tp, comment // ); if (has) { // HandleNotifyPositionGuard(guard.action, position); // double before = NormalizePrice(position.tp, position.symbol); double after = NormalizePrice(guard.tp, position.symbol); // string message = "Guard Trail Target " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ")" + " From: " + ToXString(before) + "To: " + ToXString(after) + " Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // position.Clean(); } // void DoHedge(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... // // Validate Action and Requirements ... has = (guard.force ? true : (minVolumeFactorForHedge > 0 && minProfitPerVolumeFactorForHedge > 0)) && guard.action == X_GUARD_ACTION_HEDGE; if (!has) { return; } // // Retrieve Positions ... XPosition positions[]; int count = GetPositions( positions, guard // ); has = HasChild(positions); if (!has) { // Clean(positions); // return; } // // Calculate Positions Profits and Volumes ... double swaps = 0; double profits = 0; double volumes = 0; double commissions = 0; for (int i = 0; i < count; i++) { // swaps += positions[i].swap; profits += positions[i].profit; volumes += positions[i].volume; commissions += positions[i].commission; } // // Check Profits and Volumes for Hedging ... double hedgeValue = profits + (-1 * swaps) + commissions; // // Check Force Hedging ... if (!guard.force) { // // Calculate Minimum Required Profit for Hedging ... double minRequiredProfit = (volumes / minVolumeFactorForHedge) * minProfitPerVolumeFactorForHedge; // has = hedgeValue >= minRequiredProfit; } else { has = hedgeValue > 0; } // if (!has) { // Clean(positions); // return; } // string comment = "Guard Hedge ..."; // // Loop through Positions and Close them One by One ... // this is because of Trade Manager to Handle Close Trades ... int closedCount = 0; for (int i = 0; i < count; i++) { // has = trader.Close( positions[i].ticket, comment // ); if (has) { closedCount++; } } // has = IsValidSize(closedCount); if (has) { // HandleNotifyPositionsGuard(guard.action, positions); // string message = "Guard Hedge " + ToXString(closedCount) + " Positions by: " + ToXString(hedgeValue) + " Successfully ..."; // alert.SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // // private ... private: // XCTrade *trader; XCAlert *alert; // void HandleNotifyPositionGuard( ENUM_X_GUARD_ACTIONS action, XPosition &position // ) { // if (!IsSpecifiedValid(action) || !position.IsValid() || onGuardEventListener == NULL) { return; } // XPosition positions[]; AddRef( position, positions // ); HandleNotifyPositionsGuard(action, positions); } // void HandleNotifyPositionsGuard( ENUM_X_GUARD_ACTIONS action, XPosition &positions[] // ) { // if (!IsSpecifiedValid(action) || !HasChild(positions) || onGuardEventListener == NULL) { return; } // onGuardEventListener(action, positions); } // }; //