/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCXGuard ... // Description: Guard Provider Class ... // // // 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" // // Enumeration ... // // Guard Actions ... enum ENUM_X_GUARD_ACTIONS { X_GUARD_ACTION_NONE, // Nothing to Do X_GUARD_ACTION_CLOSE, // Close Specified Position X_GUARD_ACTION_CLOSE_ALL, // Close All Positions X_GUARD_ACTION_CLOSE_LONGS, // Close All Long Positions X_GUARD_ACTION_CLOSE_SHORTS, // Close All Short Position X_GUARD_ACTION_CLOSE_IN_LOSTS, // Close All In Lost Position X_GUARD_ACTION_CLOSE_IN_PROFITS, // Close All In Profit Position X_GUARD_ACTION_CLOSE_IN_LOST_LONGS, // Close All In Lost Long Position X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS, // Close All In Profit Long Position X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS, // Close All In Lost Short Position X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT, // Close All In Profit Short Position X_GUARD_ACTION_PARTIAL_CLOSE, // Partial Close Specified Position X_GUARD_ACTION_TRAIL_STOP, // Trail Stop of Specified Position X_GUARD_ACTION_TRAIL_TARGET, // Trail Target of Specified Position X_GUARD_ACTION_HEDGE, // Hedge Specified Positions }; // // Definitions ... // // Model a Guard Action ... struct XGuard { // // Props ... ENUM_X_GUARD_ACTIONS action; datetime time; // string symbol; string provider; ENUM_TIMEFRAMES period; // // Specified Position ... ulong ticket; // // Partial Close ... double volumeMultiplier; // // SL Trial ... double sl; // // TP Trial ... double tp; // bool force; // // Constructor ... XGuard() { Clean(); } // // Tools ... /** * Cleanup ... */ void Clean() { // time = NULL; action = X_GUARD_ACTION_NONE; // symbol = NULL; period = NULL; provider = NULL; // ticket = 0; // volumeMultiplier = 0; // sl = 0; tp = 0; // force = false; // ZeroMemory(this); } /** * Validate ... * * @return ( bool ) */ bool IsValid() { // bool result = false; // result = // IsValid(time) && IsValid(symbol) && IsValid(period) && IsValid(action) && IsValid(provider) // ; if (!result) { return result; } // // Validate Model Based On Specified Guard Actions ... // return result; } }; // // Extensions ... // bool IsValid(ENUM_X_GUARD_ACTIONS item) { // bool result = false; // result = item != X_GUARD_ACTION_NONE; // return result; } /** * Add Guard to Collection ... * * @param guard: XGuard instance ... * @param guards: XGuard instance Collection ... * * @return ( int ) */ int AddGuard( XGuard &guard, XGuard &guards[] // ) { // int result = 0; // if (!guard.IsValid()) { return result; } // AddRef( guard, guards // ); // result = ArraySize(guards); // return result; } // // Implementation ... class XCGuard : public XCBaseAlert { // // public ... public: // // Props ... double minVolumeFactorForHedge; // Minimum Volume Factor for Hedge Profit Calculation ... double minProfitPerVolumeFactorForHedge; // Minimum Required Profit per Volume Factor for Hedg ... // // Constructor(s) ... XCGuard( XCTrade *&_trader // ) { // trader = _trader; // minVolumeFactorForHedge = 0.01; minProfitPerVolumeFactorForHedge = 0.5; } // // Deconstructor(s) ... ~XCGuard() { // 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) { // string message = "Guard Closed " + ToString(position.type) + " Position (" + ToString(position.ticket) + ") Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " Positions Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " In Lost Positions Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " In Profit Positions Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " Long Positions Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " In Lost Longs Positions Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " In Profit Longs Positions Successfully ..."; // SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // void DoCloseShorts(XGuard &guard) { // bool has = false; // has = guard.IsValid(); if (!has) { return; } // // Do What we want ... } // 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) { // string message = "Guard Closed " + ToString(count) + " In Lost Shorts Positions Successfully ..."; // 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) { // string message = "Guard Closed " + ToString(count) + " In Profit Shorts Positions Successfully ..."; // 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: " + ToString(volume) + " ..."; // has = trader.ClosePartial( position.ticket, volume, comment // ); if (has) { // string message = "Guard Closed Partially " + ToString(volume) + " of " + ToString(position.type) + " Position (" + ToString(position.ticket) + ") Successfully ..."; // 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.action == X_GUARD_ACTION_TRAIL_STOP; if (!has) { return; } // // Retrieve Position ... XPosition position; has = GetPosition( position, guard // ); if (!has) { // position.Clean(); // return; } // bool isLong = IsLong(position.type); // // 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 ... (isLong ? position.price > guard.sl && (position.sl == 0 || position.sl < guard.sl) : position.price < guard.sl && (position.sl == 0 || position.sl > guard.sl)); if (!has) { // position.Clean(); // return; } // string comment = "Guard Trail Stop ..."; // has = trader.Modify( position.ticket, guard.sl, position.tp, comment // ); if (has) { // double before = NormalizePrice(position.sl, position.symbol); double after = NormalizePrice(guard.sl, position.symbol); // string message = "Guard Trail Stop " + ToString(position.type) + " Position (" + ToString(position.ticket) + ")" + " From: " + ToString(before) + "To: " + ToString(after) + " Successfully ..."; // 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.action == X_GUARD_ACTION_TRAIL_TARGET; if (!has) { return; } // // Retrieve Position ... XPosition position; has = GetPosition( position, guard // ); if (!has) { // position.Clean(); // return; } // bool isLong = IsLong(position.type); // // 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 ... (isLong ? guard.tp > position.price : guard.tp < position.price); if (!has) { // position.Clean(); // return; } // string comment = "Guard Trail Target ..."; // has = trader.Modify( position.ticket, position.sl, guard.tp, comment // ); if (has) { // double before = NormalizePrice(position.tp, position.symbol); double after = NormalizePrice(guard.tp, position.symbol); // string message = "Guard Trail Target " + ToString(position.type) + " Position (" + ToString(position.ticket) + ")" + " From: " + ToString(before) + "To: " + ToString(after) + " Successfully ..."; // 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) { // string message = "Guard Hedge " + ToString(closedCount) + " Positions by: " + ToString(hedgeValue) + " Successfully ..."; // SendAlert(message); } // // Cleanup Resources ... // Clean(positions); } // // private ... private: // XCTrade *trader; // }; //