diff --git a/Classes/x-saherelm.x-guard.class.mq5 b/Classes/x-saherelm.x-guard.class.mq5 index db459ae4..ea21fc6d 100644 --- a/Classes/x-saherelm.x-guard.class.mq5 +++ b/Classes/x-saherelm.x-guard.class.mq5 @@ -22,7 +22,8 @@ // // Imports ... -#include "../Classes/x-saherelm.base.class.mq5"; +#include "../Classes/x-saherelm.x-alert.class.mq5"; +#include "../Classes/x-saherelm.x-trade.class.mq5"; // // Enumeration ... @@ -31,15 +32,21 @@ // 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_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 + 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 }; // @@ -57,6 +64,7 @@ struct XGuard // string symbol; string provider; + ENUM_TIMEFRAMES period; // // Specified Position ... @@ -74,6 +82,9 @@ struct XGuard // TP Trial ... double tp; + // + bool force; + // // Constructor ... XGuard() @@ -95,6 +106,7 @@ struct XGuard // symbol = NULL; + period = NULL; provider = NULL; // @@ -107,6 +119,9 @@ struct XGuard sl = 0; tp = 0; + // + force = false; + // ZeroMemory(this); } @@ -126,10 +141,12 @@ struct XGuard // IsValid(time) && IsValid(symbol) && - IsValid(provider) && - action != X_GUARD_ACTION_NONE + IsValid(period) && + IsValid(action) && + IsValid(provider) // ; + if (!result) { return result; @@ -196,3 +213,1793 @@ int AddGuard( // // 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; + + // +}; + +// \ No newline at end of file diff --git a/Documents/BKP/tmp.guards.mq5 b/Documents/BKP/tmp.guards.mq5 new file mode 100644 index 00000000..8bcb4212 --- /dev/null +++ b/Documents/BKP/tmp.guards.mq5 @@ -0,0 +1,1167 @@ + // + // Guards ... + + // + // Do All Provided Guards ... + void DoGuards(XGuard &guards[]) + { + // + int guardsCount = ArraySize(guards); + if (guardsCount <= 0) + { + return; + } + + // + for (int i = 0; i < guardsCount; i++) + { + // + XGuard iGuard = guards[i]; + + // + switch (iGuard.action) + { + // + // Hedge In Profit Specified Positions ... + case X_GUARD_ACTION_HEDGE: + HandleGuardHedgeAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Trail Stop Loss in Specified Positions ... + case X_GUARD_ACTION_TRAIL_STOP: + HandleGuardTrailingStopAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period, + iGuard.dblPayLoad); + break; + + // + // Force Close Specified Positions ... + case X_GUARD_ACTION_FORCE_CLOSE: + HandleGuardForceCloseAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Generate and Place Support Signals ... + case X_GUARD_ACTION_ADD_SUPPORT_SIGNAL: + HandleGuardAddSupportPositionAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Delete All Placed Pending Orders ... + case X_GUARD_ACTION_CANCEL_PENDING_ORDERS: + HandleGuardCancelPendingOrdersAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + } + } + } + + // + // Close All Specified Provider's Positions in Profit Summary ... + void HandleGuardHedgeAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + double minProfitForHedging = 1 // Specified Profit for Hedge + ) + { + // + XPosition positions[]; + int positionsCount = mTrader + .GetPositions( + positions, + symbol, + provider, + period, + type + // + ); + if (positionsCount <= 1) + { + return; + } + + // + double profit = CalculatePositionsProfit(positions); + double requiredProfit = CalculateRequiredProfitForHedge(positions); + + // + bool isReadyForHedge = profit >= requiredProfit; + if (!isReadyForHedge) + { + return; + } + + // + string comment = "Guard Hedge " + provider; + int closed = mTrader.Close( + positions, + comment + // + ); + if (closed > 0) + { + // + string message = "Guard Hedge " + provider + "'s Positions on Profit: " + ToString(profit); + + // + mAlert.Alert(message); + } + } + + // + // Close Max In Profit Trade Guard Action ... + void HandleGuardCloseInProfitAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method + ) + { + // + XPosition positions[]; + int positionsCount = mTrader + .GetInProfitPositions( + positions, + symbol, + provider, + period, + type, + method + // + ); + if (positionsCount <= 0) + { + return; + } + + // + string comment = "Close InProfit ..."; + mTrader.Close( + positions, + comment + // + ); + + // + string message = "Guard Close (" + ToString(positionsCount) + ") Postion(s) In Profit ..."; + + // + mAlert.Alert(message); + } + + // + // Close Max In Drawdown Trade Guard Action ... + void HandleGuardCloseInDrawdownAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method + ) + { + // + XPosition positions[]; + int positionsCount = mTrader + .GetInDrawdownPositions( + positions, + symbol, + provider, + period, + type, + method + // + ); + if (positionsCount <= 0) + { + return; + } + + // + string comment = "Close InDrawdown ..."; + mTrader.Close( + positions, + comment + // + ); + + // + string message = "Guard Close (" + ToString(positionsCount) + ") Position(s) In Drawdown ..."; + + // + mAlert.Alert(message); + } + + // + // Force Close Specified Set Of Position ... + void HandleGuardForceCloseAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ulong ticket = 0 // Specific Ticket + ) + { + // + string comment = ""; + + // + // Close All Positions ... + if (ticket == 0) + { + // + XPosition positions[]; + int positionsCount = mTrader.GetPositions( + positions, + symbol, + provider, + period, + type + // + ); + if (positionsCount <= 0) + { + return; + } + + // + comment = provider + " Force Close Guard ..."; + + // + mTrader.Close( + positions, + comment + // + ); + } + // + // Close Specific Position ... + else + { + // + XPosition position; + bool hasPosition = mTrader + .GetPosition( + ticket, + position + // + ); + + // + if (hasPosition) + { + // + comment = provider + "(" + ToString(ticket) + ")" + " Force Close Guard ..."; + + // + mTrader.Close( + ticket, + comment + // + ); + } + } + + // + if (IsValid(comment)) + { + mAlert.Alert(comment); + } + } + + // + // Trailing Specified Set Of Positions Stop Losses ... + void HandleGuardTrailingStopAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + double sl // Desired SL Value ... + ) + { + // + if (sl <= 0) + { + return; + } + + // + NormalizePrice( + sl, + symbol + // + ); + + // + XPosition positions[]; + int positionsCount = mTrader + .GetPositions( + positions, + symbol, + provider, + period, + type + // + ); + if (positionsCount <= 0) + { + return; + } + + // + int modified = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string comment = PrepareSLTrailTag(iPosition.comment); + + // + if (iPosition.sl == sl) + { + continue; + } + + // + bool isModified = mTrader.Modify( + iPosition.ticket, + sl, + iPosition.tp, + comment); + if (isModified) + { + modified++; + } + } + + // + if (modified > 0) + { + // + string message = "(" + ToString(modified) + ") Position's Stop Trailed Successfully ..."; + + // + mAlert.Alert(message); + } + } + + // + // Add Support Signal for Specified Positions ... + void HandleGuardAddSupportPositionAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period // Specified Time Frame + ) + { + // + XSignal support; + bool hasSupport = RequestForSupport( + support, + provider, + symbol, + type, + period + // + ); + + // + if (!hasSupport || !support.IsValid()) + { + return; + } + + // + // TODO: May be need to add Support Tag to comments ... + + // + ENUM_X_SIGNAL_EXECUTION_RESULT reason = NULL; + bool isExecuted = mTrader.ExecuteSignal( + support, + reason); + + // + string comment = NULL; + if (!isExecuted) + { + comment = "Support Execution Failed doue " + ToString(reason); + } + else + { + comment = "Guard Support Signal Executed Successfully ..."; + } + + // + if (IsValid(comment)) + { + mAlert.Alert(comment); + } + } + + // + // Cancel all Placed Orders ... + void HandleGuardCancelPendingOrdersAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period // Specified Time Frame + ) + { + // + XOrder orders[]; + int ordersCount = mTrader.GetOrders( + orders, + symbol, + provider, + period, + ToOrderType(type), + ORDER_STATE_PLACED, + true // Filter by Magic ... + // + ); + if (ordersCount <= 0) + { + return; + } + + // + int canceledOrdersCount = mTrader.CancelOrders(orders); + + // + if (canceledOrdersCount > 0) + { + // + string message = "Guard Cancel (" + ToString(canceledOrdersCount) + ") Pending Orders ..."; + + // + mAlert.Alert(message); + } + } + +////////////////////////////////////////////////////////////////// + + /** + * Handle Guard Actions ... + * + * @param guards: X121SMCGuard instance Collection ... + */ + void HandleGuards(X121SMCGuard &guards[]) + { + // + int count = ArraySize(guards); + if (!IsValidSize(guards)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + X121SMCGuard iGuard = guards[i]; + + // + if (!iGuard.IsValid()) + { + continue; + } + + // + // Here we Have to Handle Guard Actions ... + + // + // Close ... + bool canClose = + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE; + + // + // Close All ... + bool canCloseAll = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_ALL; + + // + // Close Longs ... + bool canCloseLongs = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_LONGS; + + // + // Close Shorts ... + bool canCloseShorts = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_SHORTS; + + // + // Partial Close ... + bool canPartialClose = + NotEmpty(iGuard.ticket) && + iGuard.volumeMultiplier > 0 && + iGuard.action == X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE; + + // + // Trail Stop ... + bool canTrailStop = + iGuard.sl > 0 && + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + // Trail Target ... + bool canTrailTarget = + iGuard.tp > 0 && + NotEmpty(iGuard.ticket) && + iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_TARGET; + + // + // Hedge ... + bool canHedge = iGuard.action == X_121_SMC_GUARD_ACTION_HEDGE; + + // + // Check is Guard Valid ... + bool isValidGuardAction = + canHedge || + canClose || + canCloseAll || + canTrailStop || + canCloseLongs || + canTrailTarget || + canCloseShorts || + canPartialClose; + if (!isValidGuardAction) + { + continue; + } + + // + // Now we Sure to Have a Valid Guard ... + // Start to o Guard Actions ... + + // + // Close All ... + if (canCloseAll) + { + // + XPosition positions[]; + int positionsCount = + mTrader + .GetPositions( + positions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + X_POSITION_TYPE_ALL, // All Types ... + true // Filter by Magic ... + ); + if (IsValidSize(positionsCount)) + { + // + string comment = "Guard Close All ..."; + string message = "Guard Close All (" + ToString(positionsCount) + ") Positions Successfully ..."; + int forceClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (forceClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close Longs ... + if (canCloseLongs) + { + // + XPosition longPositions[]; + XPosition shortPositions[]; + mTrader + .GetPositions( + longPositions, // Result ... + shortPositions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + true // Filter by Magic ... + ); + + // + int longPositionsCount = ArraySize(longPositions); + bool hasLongPositions = IsValidSize(longPositionsCount); + + // + int shortPositionsCount = ArraySize(shortPositions); + bool hasShortPositions = IsValidSize(shortPositionsCount); + + // + if (hasLongPositions) + { + // + string comment = "Guard Close Longs ..."; + string message = "Guard Close (" + ToString(longPositionsCount) + ") Long Positions Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + longPositions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close Shorts ... + if (canCloseShorts) + { + // + XPosition longPositions[]; + XPosition shortPositions[]; + mTrader + .GetPositions( + longPositions, // Result ... + shortPositions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + true // Filter by Magic ... + ); + + // + int longPositionsCount = ArraySize(longPositions); + bool hasLongPositions = IsValidSize(longPositionsCount); + + // + int shortPositionsCount = ArraySize(shortPositions); + bool hasShortPositions = IsValidSize(shortPositionsCount); + + // + if (hasShortPositions) + { + // + string comment = "Guard Close Shorts ..."; + string message = "Guard Close (" + ToString(shortPositionsCount) + ") Short Positions Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + shortPositions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Close ... + if (canClose) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + if (hasPosition) + { + // + XPosition positions[]; + AddRef( + iPosition, + positions // + ); + + // + string comment = "Guard Close ..."; + string message = "Guard Close " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + + // + // Partial Close ... + if (canPartialClose) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + if (hasPosition) + { + // + // Normalize Volume Multiplier ... + double vMult = iGuard.volumeMultiplier; + if (vMult > 0.5) + { + vMult = 0.5; + } + if (vMult < 0) + { + vMult = 0.5; + } + + // + // Calculate and Normalize Volume ... + double volume = iPosition.volume * iGuard.volumeMultiplier; + volume = NormalizeVolume( + volume, + iPosition.symbol // + ); + + // + string comment = "Guard Partially Closed: " + ToString(volume) + " ..."; + string message = "Guard Partially Closed " + (isLong ? "Long" : "Short") + ": " + ToString(volume) + " Successfully ..."; + bool isModified = mTrader.ClosePartial( + iPosition.ticket, + volume, + comment // + ); + if (isModified) + { + // + mTradeHandler.Alert(message); + + // + if (volume == iPosition.volume) + { + // + mTradeHandler.Finish( + iPosition.ticket, + iPosition, + comment // + ); + + // + RestEA(120 * 60); + } + } + } + } + + // + // Hedge ... + if (canHedge) + { + // + XPosition positions[]; + int positionsCount = + mTrader + .GetPositions( + positions, // Result ... + iGuard.symbol, + iGuard.provider, + NULL, // Period ... + X_POSITION_TYPE_ALL, // All Types ... + true // Filter by Magic ... + ); + if (IsValidSize(positionsCount)) + { + // + int longs = 0; + double longProfits = 0; + double longVolumes = 0; + + // + int shorts = 0; + double shortProfits = 0; + double shortVolumes = 0; + CountPositions( + positions, + longs, + longProfits, + longVolumes, + shorts, + shortProfits, + shortVolumes // + ); + + // + int count = longs + shorts; + double profits = longProfits + shortProfits; + double volumes = longVolumes + shortVolumes; + + // + bool canDoHedge = + count > 0 && + profits > 0 && + volumes > 0; + if (canDoHedge) + { + // + string comment = "Guard Hedge ..."; + string message = "Guard Hedge (" + ToString(count) + ") Positions by: (" + ToString(profits) + ") Successfully ..."; + bool isClosed = mTradeHandler.ForceClose( + positions, + comment, + message // + ); + + // + if (isClosed) + { + RestEA(120 * 60); + } + } + } + } + + // + // Trail Stop ... + if (canTrailStop) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + bool canDoTrail = + hasPosition && + iPosition.profit > 0 && + isLong + ? iPosition.price > iGuard.sl && + (iPosition.sl == 0 || + iPosition.sl < iGuard.sl) + : iPosition.price < iGuard.sl && + (iPosition.sl == 0 || + iPosition.sl > iGuard.sl); + if (canDoTrail) + { + // + string comment = "Guard Trail Stop ..."; + string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Stop Successfully ..."; + bool isModified = mTrader.Modify( + iPosition.ticket, + iGuard.sl, + iPosition.tp, + comment // + ); + if (isModified) + { + mTradeHandler.Alert(message); + } + } + } + + // + // Trail Target ... + if (canTrailTarget) + { + // + XPosition iPosition; + bool hasPosition = mTrader.GetPosition( + iGuard.ticket, + iPosition // + ); + + // + bool isLong = IsLong(iPosition.type); + + // + bool canDoTrail = + hasPosition && + iGuard.tp != iPosition.tp && + isLong + ? iGuard.tp > iPosition.price + : iGuard.tp < iPosition.price; + if (canDoTrail) + { + // + string comment = "Guard Trail Target ..."; + string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Target Successfully ..."; + bool isModified = mTrader.Modify( + iPosition.ticket, + iPosition.sl, + iGuard.tp, + comment // + ); + if (isModified) + { + mTradeHandler.Alert(message); + } + } + } + } + + // + Clean(guards); + ArrayFree(guards); + } + +////////////////////////////////////////////////////////////////// + + + // // + // eaTB.Clean(); + // eaSignal.Clean(); + // eaConditions.Clean(); + // eaCatbConditions.Clean(); + + // // + // bool has = false; + // int barIndex = 0; + // int cBarIndex = 0; + + // // + // // Check Bar Processing ... + // if (!eaBarTraker.CanProcessBar()) + // { + // return; + // } + + // // + // eaHelper.Check(barIndex); + + // // + // // Reading Required Bars ... + // XOHCL zBar; + // XOHCL cBar; + // has = zBar.Init( + // _Symbol, + // _Period, + // barIndex // + // ); + // has = + // has && + // zBar.GetPreviousBar(cBar); + // if (!has) + // { + // // + // zBar.Clean(); + // cBar.Clean(); + + // // + // return; + // } + + // // + // cBarIndex = barIndex + 1; + + // // + // // Update All Required Buffers ... + // eaHelper.Update(cBarIndex); + + // // + // // Check Trigger Block Detected or Not ... + // if (tradeUsingTriggerBlock) + // { + // // + // // Trigger Block Detection ... + // has = DetectTriggerBlock1( + // eaHelper, + // eaBarAnalyser, + // eaTB, + // eaCatbConditions, + // eaValidations, + // eaFilters, + // barIndex, + // 10 // Loopback ... + // ); + + // // + // if (has) + // { + // // + // // Wait for Next Bar for anything ... + // eaBarTraker.Waits(); + + // // + // // Prepare Target ... + // double targets[]; + // for (int i = 1; i <= eaSignalR2R; i++) + // { + // // + // Add( + // (double)i, + // targets // + // ); + // } + + // // + // // Calculate SL Additions ... + // double iATR = 0; + // if (barIndex > 0 && + // barIndex < ArraySize(eaHelper.atrBuffer)) + // { + // iATR = eaHelper.atrBuffer[barIndex]; + // } + // double slAdditional = eaSLAtrMultiplier * iATR; + + // // + // // Preparing Signal ... + // has = ToSignal( + // eaTB.trigger, + // eaTB.signal, + // targets, + // slAdditional // + // ); + + // // + // // Draw Trigger Block ... + // DrawTriggerBlock( + // eaTB, + // eaDrawer, + // eaObjects, + // NULL // + // ); + + // // + // // Attach Signal ... + // eaSignal = eaTB.signal; + + // // + // // Check Signal Type ... + // bool isLong = IsLong(eaSignal.type); + + // // + // // Update Entry ... + // eaSignal.entry = GetEntry( + // eaSignal.symbol, + // eaSignal.type // + // ); + + // // + // // Update Signal Targets ... + // UpdateSignalTargets(eaSignal); + + // // + // // Handle Volume Management ... + // double iVolume = eaVolume.CalculateVolume(eaSignal); + // if (iVolume > X_MIN_VOLUME && + // iVolume != eaSignal.volume) + // { + // eaSignal.volume = iVolume; + // } + + // // + // eaConditions.sl = eaSignal.sl; + // eaConditions.tp = eaSignal.tp; + // eaConditions.pivot = eaSignal.sl; + // eaConditions.time = eaSignal.time; + // eaConditions.reward = eaSignalR2R; + // eaConditions.point = eaSignal.entry; + // eaConditions.entry = eaSignal.entry; + // eaConditions.symbol = eaSignal.symbol; + // eaConditions.period = eaSignal.period; + // eaConditions.setupTime = eaSignal.time; + // eaConditions.triggerTime = eaSignal.time; + // eaConditions.decisionZone = eaTB.trigger; + // eaConditions.provider = eaSignal.provider; + // eaConditions.conditions = eaCatbConditions; + // eaConditions.type = ToPositionType(eaSignal.type); + // eaConditions.dir = + // isLong + // ? X_DIRECTION_BULLISH + // : X_DIRECTION_BEARISH; + // Copy( + // eaSignal.targets, + // eaConditions.targets // + // ); + // eaSignal.conditions = + // eaCatbConditions + // .GenerateSummary( + // false, // Commons ... + // true, // Conditions ... + // true, // Scores ... + // false // Ignore Falses ... + // ); + + // // + // // Execute Signal ... + // has = eaTradeManager.Execute( + // eaSignal, + // eaConditions // + // ); + // } + + // // + // eaTB.Clean(); + // } + + // // + // // Trade Using Market Conditions ... + // if (tradeUsingMarketConditions1) + // { + // // + // XBoxZone signalZone; + // X121XCatbConditions conditions; + // has = DetectSignalZone( + // eaDrawer, + // eaHelper, + // eaBarAnalyser, + // signalZone, + // conditions, + // barIndex // + // ); + // if (has) + // { + // // + // // Convert Box to Signal ... + // } + // } + + // // + // // Cleanup Resources ... + + // // + // zBar.Clean(); + // cBar.Clean(); + // eaTB.Clean(); + // eaSignal.Clean(); + // eaConditions.Clean(); + // eaCatbConditions.Clean(); diff --git a/Experts/x-saherelm.x121.xcatb.ea.mq5 b/Experts/x-saherelm.x121.xcatb.ea.mq5 new file mode 100644 index 00000000..9b296ea1 --- /dev/null +++ b/Experts/x-saherelm.x121.xcatb.ea.mq5 @@ -0,0 +1,615 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Expert Advisor +// ------------------------------------------------- +// Name: X121XCATB +// Description: X121XCATB base Expert Advisor ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121XCATB based Expert Advisor" +#property strict + +// +#define ShortName "X121XCATBEA" + +// +// Importts ... +#include "../XCATBEA/Classes/xcatbea.expert.class.mq5"; + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 1694056; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Detector ... +input group "Detector"; + +// +// Validating ... +input group "Validations"; +input bool eaForceHasSwing = false; // Force Block to Has Propper Swing +input bool eaForceOBBarType = false; // Force Order Block to Has InDirectional Bars +input int eaMinRequiredOBBar = 0; // Min Required OB Bar +input bool eaForceFVGBarType = false; // Force Fair Value Gaps Bars Type +input int eaLiquidityLoopback = 0; // Liquidity Detection Loopback +input double eaMaxAllowedRange = 0.0; // Max Allowed Order Block Range +input double eaMinAllowedRange = 0.0; // Min Allowed Order Block Range +input bool eaForceHasFLiquidity = false; // Force Order Block To Has Reversal Liquidity +input bool eaForceHasRLiquidity = false; // Force Order Block to Has Following Liquidity +input bool eaValidateGapSequence = false; // Validate Fair Value Gaps Bar Sequences +input int eaMinAllowedBlockLength = 0; // Min Allowed Block Length +input bool eaValidateBlockEdgeBreakout = false; // Validate Order Block Edge Breakeout + +// +// Filtering ... +input group "Filters"; +input bool eaFilterBasedOnKI = false; // Filter Based On KI Flats +input bool eaFilterBasedOnPV = false; // Filter Based On PV +input int eaBosLoopback = 0; // PV Based Filtering BOS Lookup +input bool eaFilterBasedOnSar = false; // Filter Based On SAR +input bool eaForceSarSwitched = false; // SAR Switched on Sides for Filtering +input bool eaForceSarOnBothSide = false; // SAR Check on Both Sides for Filtering +input bool eaForceSarHasBreakout = false; // SAR Must Breakout +input bool eaForceSarHasReversalSide = false; // SAR Must Has Reversal Direction +input bool eaFilterBasedOnRSI = false; // Filter Based On RSI +input bool eaForceHasRSITrending = false; // RSI Must Has Trending +input bool eaForceHasRSIVPattern = false; // RSI Must Has Pattern +input bool eaForceHasRSICrossing = false; // RSI Must Has Crossing Levels +input bool eaFilterBasedOnADX = false; // Filter Based On ADX +input bool eaForceHasADXTrending = false; // ADX Must Has Trending +input bool eaForceHasADXCrossing = false; // ADX Must Has Crossing +DI/-DI +input bool eaFilterBasedOnATR = false; // Filter Based On ATR +input bool eaForceHasATRTrending = false; // ATR Must Has Trending +input bool eaForceHasATRBreakout = false; // ATR Must Has Breakout +input bool eaFilterBasedOnTrend = false; // Filter Based On Trend +input bool eaForceHasTrendDir = false; // TREND Must Has Following Direction +input bool eaForceHasTrendPlace = false; // TREND Place Based Filtering +input bool eaForceHasTrendChange = false; // TREND Change Filtering +input bool eaForceHasTrendTrending = false; // TREND Must Has Trending +input bool eaForceHasTrendRejection = false; // TREND Line Must Rejected +input bool eaForceHasTrendLineInside = false; // TREND Line has Inside +input bool eaForceHasTrendDirOnBothSide = false; // TREND Must Has Following Direction in Both Side +input bool eaFilterBasedOnDelta = false; // Filter Based On Delta +input bool eaFilterBasedOnVolume = false; // Filter Based On Volume +input bool eaFilterBasedOnSignalBar = false; // Filter Based on Signal Bar +input bool eaFilterBasedOnRoundPrice = false; // Filter Based On Round Prices +input bool eaFilterBasedOnHKSignalBar = false; // Filter Based On HK Signal Bar + +// +// Signal ... +input group "Signal"; +input int eaSignalR2R = 2; // Risk Reward Ratio +input double eaSLATRMultiplier = 0; // ATR Multiplier for SL + +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_EQUITY; // Volume Applying Type +input double eaStaticVoluem = 0.0; // Static Volume +input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +input double eaConstantPercent = 0.5; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 0.0; // Constant Balance for Calculations + +// +// Management ... +// eaSymbols => comma separated Symbols for Trading, use Default if not Provided ... +// eaSessions => (SYDNEY_02:00_14:00),(NY_19:00_23:00) +input group "Management"; +input string eaSymbols = ""; // Allowed Trading Symbols +input bool eaAllowGuards = false; // Allow Guards +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input string eaSessions = ""; // Active Sessions +input ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD eaRestrictionsPeriod = XCATBEA_TRADE_RESTRICATION_NONE; // Restrictions Period +input int eaMaxAllowedTPs = 0; // Max Allowed TP(s) in Restrictions Period +input int eaMaxAllowedSLs = 0; // Max Allowed SL(s) in Restrictions Period +input int eaMaxAllowedTrades = 0; // Max Allowed Trades in Restrictions Period +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 ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = true; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours +input bool eaReportTrades = true; // Report Trades +input bool eaReportSignals = true; // Report Signals +input bool eaReportProtector = true; // Report Protector Actions +input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished + +// +// Collector ... +input group "Collector"; +input bool eaSaveTrades = false; // Save Trades +input bool eaSaveSignals = false; // Save Signals +input bool eaSaveWins = false; // Save Winning Conditions +input bool eaSaveLosts = false; // Save Lost Conditions + +// +// Variables ... + +// +XCXCATBEAExpert *eaExpert; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Preparing Tags ... + string eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Configure EA Expert Class ... + eaExpert = new XCXCATBEAExpert(); + + // + // Setting All Inputs to Expert Adviser Class ... + + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + + // + // Detector ... + + // + // Validations ... + eaExpert.eaForceHasSwing = eaForceHasSwing; + eaExpert.eaForceOBBarType = eaForceOBBarType; + eaExpert.eaMinRequiredOBBar = eaMinRequiredOBBar; + eaExpert.eaForceFVGBarType = eaForceFVGBarType; + eaExpert.eaLiquidityLoopback = eaLiquidityLoopback; + eaExpert.eaMaxAllowedRange = eaMaxAllowedRange; + eaExpert.eaMinAllowedRange = eaMinAllowedRange; + eaExpert.eaForceHasFLiquidity = eaForceHasFLiquidity; + eaExpert.eaForceHasRLiquidity = eaForceHasRLiquidity; + eaExpert.eaValidateGapSequence = eaValidateGapSequence; + eaExpert.eaMinAllowedBlockLength = eaMinAllowedBlockLength; + eaExpert.eaValidateBlockEdgeBreakout = eaValidateBlockEdgeBreakout; + + // + // Filters ... + eaExpert.eaFilterBasedOnKI = eaFilterBasedOnKI; + eaExpert.eaFilterBasedOnPV = eaFilterBasedOnPV; + eaExpert.eaBosLoopback = eaBosLoopback; + eaExpert.eaFilterBasedOnSar = eaFilterBasedOnSar; + eaExpert.eaForceSarSwitched = eaForceSarSwitched; + eaExpert.eaForceSarOnBothSide = eaForceSarOnBothSide; + eaExpert.eaForceSarHasBreakout = eaForceSarHasBreakout; + eaExpert.eaForceSarHasReversalSide = eaForceSarHasReversalSide; + eaExpert.eaFilterBasedOnRSI = eaFilterBasedOnRSI; + eaExpert.eaForceHasRSITrending = eaForceHasRSITrending; + eaExpert.eaForceHasRSIVPattern = eaForceHasRSIVPattern; + eaExpert.eaForceHasRSICrossing = eaForceHasRSICrossing; + eaExpert.eaFilterBasedOnADX = eaFilterBasedOnADX; + eaExpert.eaForceHasADXTrending = eaForceHasADXTrending; + eaExpert.eaForceHasADXCrossing = eaForceHasADXCrossing; + eaExpert.eaFilterBasedOnATR = eaFilterBasedOnATR; + eaExpert.eaForceHasATRTrending = eaForceHasATRTrending; + eaExpert.eaForceHasATRBreakout = eaForceHasATRBreakout; + eaExpert.eaFilterBasedOnTrend = eaFilterBasedOnTrend; + eaExpert.eaForceHasTrendDir = eaForceHasTrendDir; + eaExpert.eaForceHasTrendPlace = eaForceHasTrendPlace; + eaExpert.eaForceHasTrendChange = eaForceHasTrendChange; + eaExpert.eaForceHasTrendTrending = eaForceHasTrendTrending; + eaExpert.eaForceHasTrendRejection = eaForceHasTrendRejection; + eaExpert.eaForceHasTrendLineInside = eaForceHasTrendLineInside; + eaExpert.eaForceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; + eaExpert.eaFilterBasedOnDelta = eaFilterBasedOnDelta; + eaExpert.eaFilterBasedOnVolume = eaFilterBasedOnVolume; + eaExpert.eaFilterBasedOnSignalBar = eaFilterBasedOnSignalBar; + eaExpert.eaFilterBasedOnRoundPrice = eaFilterBasedOnRoundPrice; + eaExpert.eaFilterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + + // + // Signal ... + eaExpert.eaSignalR2R = eaSignalR2R; + eaExpert.eaSLATRMultiplier = eaSLATRMultiplier; + + // + // Volume ... + eaExpert.eaVolumeSelect = eaVolumeSelect; + eaExpert.eaStaticVoluem = eaStaticVoluem; + eaExpert.eaDynamicVolumeStepBalance = eaDynamicVolumeStepBalance; + eaExpert.eaDynamicVolumeStepVolume = eaDynamicVolumeStepVolume; + eaExpert.eaConstantRiskBalance = eaConstantRiskBalance; + eaExpert.eaConstantPercent = eaConstantPercent; + eaExpert.eaConstantBalance = eaConstantBalance; + + // + // Management ... + eaExpert.eaSymbols = eaSymbols; + eaExpert.eaAllowGuards = eaAllowGuards; + eaExpert.eaAllowTrade = eaAllowTrade; + eaExpert.eaAllowLongs = eaAllowLongs; + eaExpert.eaAllowShorts = eaAllowShorts; + eaExpert.eaRestrictionsPeriod = eaRestrictionsPeriod; + eaExpert.eaMaxAllowedTPs = eaMaxAllowedTPs; + eaExpert.eaMaxAllowedSLs = eaMaxAllowedSLs; + eaExpert.eaMaxAllowedTrades = eaMaxAllowedTrades; + eaExpert.eaMaxAllowedPositions = eaMaxAllowedPositions; + eaExpert.eaMaxAllowedSpread = eaMaxAllowedSpread; + eaExpert.eaMaxAllowedDrawdownFactor = eaMaxAllowedDrawdownFactor; + eaExpert.eaCloseAllOpenTradesAt = eaCloseAllOpenTradesAt; + + // + // Alert ... + eaExpert.eaEnableAlerts = eaEnableAlerts; + eaExpert.eaLogAlerts = eaLogAlerts; + eaExpert.eaMailAlerts = eaMailAlerts; + eaExpert.eaPushAlerts = eaPushAlerts; + eaExpert.eaTerminalAlerts = eaTerminalAlerts; + + // + // Reports ... + eaExpert.eaReportNewMonths = eaReportNewMonths; + eaExpert.eaReportNewWeeks = eaReportNewWeeks; + eaExpert.eaReportNewDays = eaReportNewDays; + eaExpert.eaReportNewHours = eaReportNewHours; + eaExpert.eaReportTrades = eaReportTrades; + eaExpert.eaReportSignals = eaReportSignals; + eaExpert.eaReportProtector = eaReportProtector; + eaExpert.eaReportAfterTradesBalance = eaReportAfterTradesBalance; + + // + // Collector ... + eaExpert.eaSaveTrades = eaSaveTrades; + eaExpert.eaSaveSignals = eaSaveSignals; + eaExpert.eaSaveWins = eaSaveWins; + eaExpert.eaSaveLosts = eaSaveLosts; + + // + // Attach Event Handlers ... + eaExpert.OnModifyEventHandler = OnPositionModified; + eaExpert.OnDealsChangedEventHandler = OnDealsChanged; + eaExpert.OnStopLossEventHandler = OnStopLossTriggered; + eaExpert.OnOrdersChangedEventHandler = OnOrdersChanged; + eaExpert.OnForceCloseEventHandler = OnPositionForceClosed; + eaExpert.OnTakeProfitEventHandler = OnTakeProfitTriggered; + eaExpert.OnPositionsChangedEventHandler = OnPositionsChanged; + eaExpert.OnPartialCloseEventHandler = OnPositionPartialClosed; + eaExpert.OnTradeStateChangedEventHandler = OnTradeStateChanged; + + // + bool isInited = eaExpert.HandleOnInit(); + if (!isInited) + { + // + Print(ShortName + " Initialization Failed ..."); + return INIT_FAILED; + } + + // + // Init Succeed ... + Print(ShortName + " Initialization 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 + + // + // Destroy Timer ... + eaExpert.HandleOnDeInit(); + + // + delete eaExpert; + ZeroMemory(eaExpert); + + // + Print(ShortName + " Deinitialized Successfully ..."); +} + +// +// On Tick Handler ... +void OnTick() +{ + eaExpert.HandleOnTick(); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaExpert.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + eaExpert.HandleOnTimer(); +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); +} + +// +// Event Listeners ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaExpert.HandleOnStopLossTriggered(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaExpert.HandleOnTakeProfitTriggered(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: String ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ + eaExpert.HandleOnDealsChanged(count); +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ + eaExpert.HandleOnOrdersChanged(count); +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + eaExpert.HandleOnPositionsChanged(count); +} + +/** + * Handle Position Modified ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionModified( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionModified( + ticket, + profit, + comment // + ); +} + +/** + * Handle Position Partial Closed ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionPartialClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Trade State Changed ... + * + * @param state: XOnTradeHandlerState instance ... + */ +void OnTradeStateChanged(const XOnTradeHandlerState &state) +{ + eaExpert.HandleOnTradeStateChanged(state); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// \ No newline at end of file diff --git a/Experts/xcatb.test.ea.mq5 b/Experts/xcatb.test.ea.mq5 index c0bc4cca..0e0e1efb 100644 --- a/Experts/xcatb.test.ea.mq5 +++ b/Experts/xcatb.test.ea.mq5 @@ -20,15 +20,10 @@ // // Include Common Library ... -#include "../Classes/x-saherelm.x-alert.class.mq5" -#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" -#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" -#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-saherelm.x-guard.class.mq5" #include "../Classes/x-saherelm.x-volume.class.mq5" -#include "../Helpers/x-saherelm.x121.xcatb.helper.mq5" #include "../XCATBEA/Classes/xcatbea.signaller.class.mq5" #include "../XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5" -#include "../XCATBEA/Libraries/xcatbea.signaller.lib.mq5" // #define ShortName "XCATBEA" @@ -66,6 +61,7 @@ input bool eaValidateBlockEdgeBreakout = false; // Validate Order Block Edge Bre // // Filtering ... input group "Filters"; +input bool eaFilterBasedOnKI = false; // Filter Based On KI Flats input bool eaFilterBasedOnPV = false; // Filter Based On PV input int eaBosLoopback = 0; // PV Based Filtering BOS Lookup input bool eaFilterBasedOnSar = false; // Filter Based On SAR @@ -94,13 +90,14 @@ input bool eaForceHasTrendDirOnBothSide = false; // TREND Must Has Following Dir input bool eaFilterBasedOnDelta = false; // Filter Based On Delta input bool eaFilterBasedOnVolume = false; // Filter Based On Volume input bool eaFilterBasedOnSignalBar = false; // Filter Based on Signal Bar +input bool eaFilterBasedOnRoundPrice = false; // Filter Based On Round Prices input bool eaFilterBasedOnHKSignalBar = false; // Filter Based On HK Signal Bar // // Signal ... input group "Signal"; input int eaSignalR2R = 2; // Risk Reward Ratio -input double eaSLAtrMultiplier = 0; // ATR Multiplier for SL +input double eaSLATRMultiplier = 0; // ATR Multiplier for SL // // Volume ... @@ -117,6 +114,7 @@ input double eaConstantBalance = 0.0; // Constant Ba // Management ... // eaSessions => (SYDNEY_02:00_14:00),(NY_19:00_23:00) input group "Management"; +input bool eaAllowGuards = false; // Allow Guards input bool eaAllowTrade = true; // Allow Trade on Signals input bool eaAllowLongs = true; // Allow Long Trades input bool eaAllowShorts = true; // Allow Short Trades @@ -165,13 +163,14 @@ input bool eaSaveLosts = false; // Save Lost Conditions // Variables ... // -XCAlert *eaAlert; -XCTrade *eaTrade; -string eaTag = ""; -XCVolume *eaVolume; -XTimeTracker eaTimeTracker; -XCXCATBEASignaller *eaSignallers[]; -XCXCATBEATradeManager *eaTradeManager; +XCAlert *eaAlert; // EA Scope Alert Handler ... +XCTrade *eaTrade; // EA Scope Trade Handler ... +XCGuard *eaGuard; // EA Scope Guard Handler ... +string eaTag = ""; // Specified Alert Tag for EA ... +XCVolume *eaVolume; // EA Scope Voluem Handler ... +XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... +XCXCATBEASignaller *eaSignallers[]; // EA Signallers Collection ... +XCXCATBEATradeManager *eaTradeManager; // EA Scope Trade Manager ... // // Event Handlers ... @@ -227,6 +226,10 @@ void OnDeinit(const int reason) delete eaTrade; ZeroMemory(eaTrade); + // + delete eaGuard; + ZeroMemory(eaGuard); + // delete eaVolume; ZeroMemory(eaVolume); @@ -234,6 +237,13 @@ void OnDeinit(const int reason) // eaTimeTracker.Clean(); + // + Clean(eaSignallers); + + // + delete eaTradeManager; + ZeroMemory(eaTradeManager); + // DestroyTimer(); } @@ -345,6 +355,7 @@ void OnTick() { // // Handle Guards Firing ... + eaGuard.DoGuards(guards); } // @@ -354,6 +365,7 @@ void OnTick() { // // Handle Conditions Triggering ... + TriggerConditions(conditions); } // @@ -362,226 +374,6 @@ void OnTick() // Clean(guards); Clean(conditions); - - // // - // eaTB.Clean(); - // eaSignal.Clean(); - // eaConditions.Clean(); - // eaCatbConditions.Clean(); - - // // - // bool has = false; - // int barIndex = 0; - // int cBarIndex = 0; - - // // - // // Check Bar Processing ... - // if (!eaBarTraker.CanProcessBar()) - // { - // return; - // } - - // // - // eaHelper.Check(barIndex); - - // // - // // Reading Required Bars ... - // XOHCL zBar; - // XOHCL cBar; - // has = zBar.Init( - // _Symbol, - // _Period, - // barIndex // - // ); - // has = - // has && - // zBar.GetPreviousBar(cBar); - // if (!has) - // { - // // - // zBar.Clean(); - // cBar.Clean(); - - // // - // return; - // } - - // // - // cBarIndex = barIndex + 1; - - // // - // // Update All Required Buffers ... - // eaHelper.Update(cBarIndex); - - // // - // // Check Trigger Block Detected or Not ... - // if (tradeUsingTriggerBlock) - // { - // // - // // Trigger Block Detection ... - // has = DetectTriggerBlock1( - // eaHelper, - // eaBarAnalyser, - // eaTB, - // eaCatbConditions, - // eaValidations, - // eaFilters, - // barIndex, - // 10 // Loopback ... - // ); - - // // - // if (has) - // { - // // - // // Wait for Next Bar for anything ... - // eaBarTraker.Waits(); - - // // - // // Prepare Target ... - // double targets[]; - // for (int i = 1; i <= eaSignalR2R; i++) - // { - // // - // Add( - // (double)i, - // targets // - // ); - // } - - // // - // // Calculate SL Additions ... - // double iATR = 0; - // if (barIndex > 0 && - // barIndex < ArraySize(eaHelper.atrBuffer)) - // { - // iATR = eaHelper.atrBuffer[barIndex]; - // } - // double slAdditional = eaSLAtrMultiplier * iATR; - - // // - // // Preparing Signal ... - // has = ToSignal( - // eaTB.trigger, - // eaTB.signal, - // targets, - // slAdditional // - // ); - - // // - // // Draw Trigger Block ... - // DrawTriggerBlock( - // eaTB, - // eaDrawer, - // eaObjects, - // NULL // - // ); - - // // - // // Attach Signal ... - // eaSignal = eaTB.signal; - - // // - // // Check Signal Type ... - // bool isLong = IsLong(eaSignal.type); - - // // - // // Update Entry ... - // eaSignal.entry = GetEntry( - // eaSignal.symbol, - // eaSignal.type // - // ); - - // // - // // Update Signal Targets ... - // UpdateSignalTargets(eaSignal); - - // // - // // Handle Volume Management ... - // double iVolume = eaVolume.CalculateVolume(eaSignal); - // if (iVolume > X_MIN_VOLUME && - // iVolume != eaSignal.volume) - // { - // eaSignal.volume = iVolume; - // } - - // // - // eaConditions.sl = eaSignal.sl; - // eaConditions.tp = eaSignal.tp; - // eaConditions.pivot = eaSignal.sl; - // eaConditions.time = eaSignal.time; - // eaConditions.reward = eaSignalR2R; - // eaConditions.point = eaSignal.entry; - // eaConditions.entry = eaSignal.entry; - // eaConditions.symbol = eaSignal.symbol; - // eaConditions.period = eaSignal.period; - // eaConditions.setupTime = eaSignal.time; - // eaConditions.triggerTime = eaSignal.time; - // eaConditions.decisionZone = eaTB.trigger; - // eaConditions.provider = eaSignal.provider; - // eaConditions.conditions = eaCatbConditions; - // eaConditions.type = ToPositionType(eaSignal.type); - // eaConditions.dir = - // isLong - // ? X_DIRECTION_BULLISH - // : X_DIRECTION_BEARISH; - // Copy( - // eaSignal.targets, - // eaConditions.targets // - // ); - // eaSignal.conditions = - // eaCatbConditions - // .GenerateSummary( - // false, // Commons ... - // true, // Conditions ... - // true, // Scores ... - // false // Ignore Falses ... - // ); - - // // - // // Execute Signal ... - // has = eaTradeManager.Execute( - // eaSignal, - // eaConditions // - // ); - // } - - // // - // eaTB.Clean(); - // } - - // // - // // Trade Using Market Conditions ... - // if (tradeUsingMarketConditions1) - // { - // // - // XBoxZone signalZone; - // X121XCatbConditions conditions; - // has = DetectSignalZone( - // eaDrawer, - // eaHelper, - // eaBarAnalyser, - // signalZone, - // conditions, - // barIndex // - // ); - // if (has) - // { - // // - // // Convert Box to Signal ... - // } - // } - - // // - // // Cleanup Resources ... - - // // - // zBar.Clean(); - // cBar.Clean(); - // eaTB.Clean(); - // eaSignal.Clean(); - // eaConditions.Clean(); - // eaCatbConditions.Clean(); } // @@ -835,6 +627,8 @@ void InitRequirements() eaMaxAllowedPositions, eaMaxAllowedDrawdownFactor // ); + + // eaTrade.AddOnStopLossEventHandler(OnStopLossTriggered); eaTrade.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); eaTrade.AddOnForceClosePositionEventHandler(OnPositionForceClosed); @@ -845,6 +639,7 @@ void InitRequirements() eaTradeManager = new XCXCATBEATradeManager( eaTrade // ); + // eaTradeManager.SetAlertPrefix(eaTag); eaTradeManager.SetAlertLogAlerts(eaLogAlerts); @@ -852,6 +647,7 @@ void InitRequirements() eaTradeManager.SetAlertPushAlerts(eaPushAlerts); eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts); eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); + // eaTradeManager.SaveWins(eaSaveWins); eaTradeManager.SaveLosts(eaSaveLosts); @@ -887,6 +683,20 @@ void InitRequirements() eaMaxAllowedTrades // ); + // + // EA Guard Initialization ... + eaGuard = new XCGuard( + eaTrade // + ); + + // + eaGuard.SetAlertPrefix(eaTag); + eaGuard.SetAlertLogAlerts(eaLogAlerts); + eaGuard.SetAlertMailAlerts(eaMailAlerts); + eaGuard.SetAlertPushAlerts(eaPushAlerts); + eaGuard.SetAlertEnableAlerts(eaEnableAlerts); + eaGuard.SetAlertTerminalAlerts(eaTerminalAlerts); + // // Initializing Sessions ... string sessions[]; @@ -974,12 +784,23 @@ void InitRequirements() // Provider Name ... iSignallerInputs.period = _Period; iSignallerInputs.provider = "XTRGB"; + iSignallerInputs.allowGuards = eaAllowGuards; + iSignallerInputs.riskToRewardRatio = eaSignalR2R; + iSignallerInputs.allowDraws = IsRunningOnTestMode(); + iSignallerInputs.slATRMultiplier = eaSLATRMultiplier; // // CATB Indicator ... iSignallerInputs.catbInputs.Default(); iSignallerInputs.catbInputs.Hide(); + // + // Make Available all Requirement Buffers of XCATB indicator ... + iSignallerInputs.catbInputs.showPV = true; + iSignallerInputs.catbInputs.showKI = true; + iSignallerInputs.catbInputs.showATRBand = true; + iSignallerInputs.catbInputs.showPVGolden = true; + // // Trigger Block Validations ... iSignallerInputs.validations.forceHasSwing = eaForceHasSwing; @@ -1036,11 +857,15 @@ void InitRequirements() iSignallerInputs.filters.forceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; // + iSignallerInputs.filters.filterBasedOnKI = eaFilterBasedOnKI; iSignallerInputs.filters.filterBasedOnDelta = eaFilterBasedOnDelta; iSignallerInputs.filters.filterBasedOnVolume = eaFilterBasedOnVolume; iSignallerInputs.filters.filterBasedOnSignalBar = eaFilterBasedOnSignalBar; + iSignallerInputs.filters.filterBasedOnRoundPrice = eaFilterBasedOnRoundPrice; iSignallerInputs.filters.filterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + // + // // Loop Through Symbols for Signalling Initializing ... int symbolsCount = ArraySize(symbols); @@ -1233,4 +1058,97 @@ void UpdateSignalTargets(XSignal &signal) ); } +/** + * Convert a Triggered Conditions to Signal and + * Execute it ... + */ +void TriggerConditions(XCATBEAStrategyConditions &conditions[]) +{ + // + int count = 0; + bool has = false; + + // + has = HasChild(conditions); + if (!has) + { + return; + } + + // + count = ArraySize(conditions); + for (int i = 0; i < count; i++) + { + // + // Retrieve Indexed Conditions ... + XCATBEAStrategyConditions iConditions = conditions[i]; + + // + // Prepare Signal Based on Conditions ... + XSignal iSignal; + + // + // Check if a Trigger Block Attached and Has Signal ... + // use it ... + has = + iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger() && + iConditions.triggerBlock.IsValid() && + iConditions.triggerBlock.signal.IsValid(); + if (has) + { + iSignal = iConditions.triggerBlock.signal; + } + + // + // if we Have any other Signalling senarios we can Handle them here ... + + // + // Validate Signal ... + has = iSignal.IsValid(); + if (has) + { + // + // Retrieve Signal Type ... + bool isLong = IsLong(iSignal.type); + + // + // Update Signal Entry ... + iSignal.entry = GetEntry( + iSignal.symbol, + iSignal.type // + ); + + // + // Update Signal Targets ... + UpdateSignalTargets(iSignal); + + // + // Handle Volume Management ... + double iVolume = eaVolume.CalculateVolume(iSignal); + has = iVolume > X_MIN_VOLUME && + iVolume != iSignal.volume; + if (has) + { + iSignal.volume = iVolume; + } + + // + // Execute Signal ... + has = eaTradeManager.Execute( + iSignal, + iConditions // + ); + } + + // + // Cleanup Resources ... + + // + iSignal.Clean(); + iConditions.Clean(); + } +} + // \ No newline at end of file diff --git a/XCATBEA/Classes/xcatbea.expert.class.mq5 b/XCATBEA/Classes/xcatbea.expert.class.mq5 new file mode 100644 index 00000000..e354d125 --- /dev/null +++ b/XCATBEA/Classes/xcatbea.expert.class.mq5 @@ -0,0 +1,1103 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXCATBEAExpert ... +// Description: XCATB Expert 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 XCATB Expert Class" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-guard.class.mq5" +#include "../../Classes/x-saherelm.x-trade.class.mq5" +#include "../../Classes/x-saherelm.x-volume.class.mq5" +#include "../Classes/xcatbea.signaller.class.mq5" +#include "../Classes/xcatbea.x-trade.manager.class.mq5" + +// +// Definitions ... + +// +// Implementation ... +class XCXCATBEAExpert : public XCBase +{ + // + // public ... + public: + // + // Props ... + + // + // Common ... + long eaMagicNumber; // Magic Number + int eaSlippage; // Slippgae + string eaLogSuffix; // Log Suffix + + // + // Detector ... + + // + // Validating ... + bool eaForceHasSwing; // Force Block to Has Propper Swing + bool eaForceOBBarType; // Force Order Block to Has InDirectional Bars + int eaMinRequiredOBBar; // Min Required OB Bar + bool eaForceFVGBarType; // Force Fair Value Gaps Bars Type + int eaLiquidityLoopback; // Liquidity Detection Loopback + double eaMaxAllowedRange; // Max Allowed Order Block Range + double eaMinAllowedRange; // Min Allowed Order Block Range + bool eaForceHasFLiquidity; // Force Order Block To Has Reversal Liquidity + bool eaForceHasRLiquidity; // Force Order Block to Has Following Liquidity + bool eaValidateGapSequence; // Validate Fair Value Gaps Bar Sequences + int eaMinAllowedBlockLength; // Min Allowed Block Length + bool eaValidateBlockEdgeBreakout; // Validate Order Block Edge Breakeout + + // + // Filtering ... + bool eaFilterBasedOnKI; // Filter Based On KI Flats + bool eaFilterBasedOnPV; // Filter Based On PV + int eaBosLoopback; // PV Based Filtering BOS Lookup + bool eaFilterBasedOnSar; // Filter Based On SAR + bool eaForceSarSwitched; // SAR Switched on Sides for Filtering + bool eaForceSarOnBothSide; // SAR Check on Both Sides for Filtering + bool eaForceSarHasBreakout; // SAR Must Breakout + bool eaForceSarHasReversalSide; // SAR Must Has Reversal Direction + bool eaFilterBasedOnRSI; // Filter Based On RSI + bool eaForceHasRSITrending; // RSI Must Has Trending + bool eaForceHasRSIVPattern; // RSI Must Has Pattern + bool eaForceHasRSICrossing; // RSI Must Has Crossing Levels + bool eaFilterBasedOnADX; // Filter Based On ADX + bool eaForceHasADXTrending; // ADX Must Has Trending + bool eaForceHasADXCrossing; // ADX Must Has Crossing +DI/-DI + bool eaFilterBasedOnATR; // Filter Based On ATR + bool eaForceHasATRTrending; // ATR Must Has Trending + bool eaForceHasATRBreakout; // ATR Must Has Breakout + bool eaFilterBasedOnTrend; // Filter Based On Trend + bool eaForceHasTrendDir; // TREND Must Has Following Direction + bool eaForceHasTrendPlace; // TREND Place Based Filtering + bool eaForceHasTrendChange; // TREND Change Filtering + bool eaForceHasTrendTrending; // TREND Must Has Trending + bool eaForceHasTrendRejection; // TREND Line Must Rejected + bool eaForceHasTrendLineInside; // TREND Line has Inside + bool eaForceHasTrendDirOnBothSide; // TREND Must Has Following Direction in Both Side + bool eaFilterBasedOnDelta; // Filter Based On Delta + bool eaFilterBasedOnVolume; // Filter Based On Volume + bool eaFilterBasedOnSignalBar; // Filter Based on Signal Bar + bool eaFilterBasedOnRoundPrice; // Filter Based On Round Prices + bool eaFilterBasedOnHKSignalBar; // Filter Based On HK Signal Bar + + // + // Signal ... + int eaSignalR2R; // Risk Reward Ratio + double eaSLATRMultiplier; // ATR Multiplier for SL + + // + // Volume ... + ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect; // Volume Applying Type + double eaStaticVoluem; // Static Volume + double eaDynamicVolumeStepBalance; // Step of Balance for Increase Volume + double eaDynamicVolumeStepVolume; // Step of Volume Increasing + double eaConstantRiskBalance; // Constant Risk Balance per Trade + double eaConstantPercent; // Constant Percent of Balance Per Trade + double eaConstantBalance; // Constant Balance for Calculations + + // + // Management ... + string eaSymbols; // Allowed Trading Symbols + bool eaAllowGuards; // Allow Guards + bool eaAllowTrade; // Allow Trade on Signals + bool eaAllowLongs; // Allow Long Trades + bool eaAllowShorts; // Allow Short Trades + string eaSessions; // Active Sessions + ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD eaRestrictionsPeriod; // Restrictions Period + int eaMaxAllowedTPs; // Max Allowed TP(s) in Restrictions Period + int eaMaxAllowedSLs; // Max Allowed SL(s) in Restrictions Period + int eaMaxAllowedTrades; // Max Allowed Trades in Restrictions Period + int eaMaxAllowedPositions; // Max Allowed Same Time Trades + double eaMaxAllowedSpread; // Max Allowed Spread For Trade + double eaMaxAllowedDrawdownFactor; // Max Allowed DrawDown for Trade + string eaCloseAllOpenTradesAt; // Close All Open Trades per Day At Specified Time + + // + // Alert ... + bool eaEnableAlerts; // Enable Alerts + bool eaLogAlerts; // Log Alerts + bool eaMailAlerts; // Mail Alerts + bool eaPushAlerts; // Push Alerts + bool eaTerminalAlerts; // Terminal Alerts + + // + // Time Report ... + bool eaReportNewMonths; // Report New Month + bool eaReportNewWeeks; // Report New Weeks + bool eaReportNewDays; // Report New Days + bool eaReportNewHours; // Report New Hours + bool eaReportTrades; // Report Trades + bool eaReportSignals; // Report Signals + bool eaReportProtector; // Report Protector Actions + bool eaReportAfterTradesBalance; // Report Balance after a Trade Finished + + // + // Collector ... + bool eaSaveTrades; // Save Trades + bool eaSaveSignals; // Save Signals + bool eaSaveWins; // Save Winning Conditions + bool eaSaveLosts; // Save Lost Conditions + + // + // Trade Event Handlers ... + TOnModify OnModifyEventHandler; + TOnStopLoss OnStopLossEventHandler; + TOnForceClose OnForceCloseEventHandler; + TOnTakeProfit OnTakeProfitEventHandler; + TOnPartialClose OnPartialCloseEventHandler; + TOnDealsChanged OnDealsChangedEventHandler; + TOnOrdersChanged OnOrdersChangedEventHandler; + TOnPositionsChanged OnPositionsChangedEventHandler; + TOnTradeStateChanged OnTradeStateChangedEventHandler; + + // + // Requirements ... + + // + XCAlert *eaAlert; // EA Scope Alert Handler ... + XCTrade *eaTrade; // EA Scope Trade Handler ... + XCGuard *eaGuard; // EA Scope Guard Handler ... + XCVolume *eaVolume; // EA Scope Voluem Handler ... + XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... + XCXCATBEASignaller *eaSignallers[]; // EA Signallers Collection ... + XCXCATBEATradeManager *eaTradeManager; // EA Scope Trade Manager ... + + // + // Tools / Actions / Handlers ... + + // + // Validators ... + + /** + * Validate Inputs ... + * + * @return ( bool ) + */ + bool ValidateInputs() + { + // + bool result = false; + + // + // Implement all Inputs Validation ... + result = eaMagicNumber > 0 && + eaSignalR2R > 0; + + // + return result; + } + + // + // Expert Advisor Event Handlers ... + + /** + * Handle Initialization of Expert ... + * + * @return ( bool ) + */ + bool HandleOnInit() + { + // + bool result = false; + + // + // Validate Inputs ... + result = ValidateInputs(); + if (!result) + { + return result; + } + + // + // Initialize Alert Handler ... + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogSuffix); + eaAlert.SetLogAlerts(eaLogAlerts); + eaAlert.SetMailAlerts(eaMailAlerts); + eaAlert.SetPushAlerts(eaPushAlerts); + eaAlert.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // Initialize Volume Manager ... + eaVolume = new XCVolume(); + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + if (!result) + { + return result; + } + + // + // Initialize Trader ... + eaTrade = new XCTrade( + eaSlippage, + eaMagicNumber, + eaMaxAllowedSpread, + eaMaxAllowedPositions, + eaMaxAllowedDrawdownFactor // + ); + eaTrade.AddOnStopLossEventHandler(OnStopLossEventHandler); + eaTrade.AddOnTakeProfitEventHandler(OnTakeProfitEventHandler); + eaTrade.AddOnModifyPositionEventHandler(OnModifyEventHandler); + eaTrade.AddOnDealsChangedEventHandler(OnDealsChangedEventHandler); + eaTrade.AddOnOrdersChangedEventHandler(OnOrdersChangedEventHandler); + eaTrade.AddOnForceClosePositionEventHandler(OnForceCloseEventHandler); + eaTrade.AddOnPartialClosePositionEventHandler(OnPartialCloseEventHandler); + eaTrade.AddOnPositionsChangedEventHandler(OnPositionsChangedEventHandler); + eaTrade.AddOnTradeStateChangedEventHandler(OnTradeStateChangedEventHandler); + + // + // Initialize Guard Handler ... + eaGuard = new XCGuard( + eaTrade // + ); + + // + eaGuard.SetAlertPrefix(eaLogSuffix); + eaGuard.SetAlertLogAlerts(eaLogAlerts); + eaGuard.SetAlertMailAlerts(eaMailAlerts); + eaGuard.SetAlertPushAlerts(eaPushAlerts); + eaGuard.SetAlertEnableAlerts(eaEnableAlerts); + eaGuard.SetAlertTerminalAlerts(eaTerminalAlerts); + + // + // Initialize Trae Manager ... + eaTradeManager = new XCXCATBEATradeManager( + eaTrade // + ); + + // + eaTradeManager.SetAlertPrefix(eaLogSuffix); + eaTradeManager.SetAlertLogAlerts(eaLogAlerts); + eaTradeManager.SetAlertMailAlerts(eaMailAlerts); + eaTradeManager.SetAlertPushAlerts(eaPushAlerts); + eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts); + eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); + + // + eaTradeManager.SaveWins(eaSaveWins); + eaTradeManager.SaveLosts(eaSaveLosts); + eaTradeManager.SaveTrades(eaSaveTrades); + eaTradeManager.SaveSignals(eaSaveSignals); + + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // Setting Trade Restrictions ... + eaTradeManager + .SetTradeRestrictions( + eaRestrictionsPeriod, + eaMaxAllowedTPs, + eaMaxAllowedSLs, + eaMaxAllowedTrades // + ); + + // + // Parsing Symbols ... + + // + string symbols[]; + int symbolsCount = 0; + if (IsValid(eaSymbols)) + { + // + symbolsCount = SplitContent( + symbols, + eaSymbols, + "," // + ); + } + + // + // Adding Default Symbol, if eaSymbols not Filled ... + if (!HasChild(symbols)) + { + // + Add( + _Symbol, + symbols // + ); + + // + symbolsCount = ArraySize(symbols); + } + bool hasSymbols = HasChild(symbols); + + // + // Initializing Sessions ... + string sessions[]; + int sessionsCount = 0; + bool hasSession = IsValid(eaSessions); + if (hasSession) + { + // + // Extract Per Symbol Sessions ... + sessionsCount = SplitContent( + sessions, + eaSessions, + "," // + ); + + // + // Try to Extract Start and End Times Series ... + hasSession = IsValidSize(sessionsCount); + if (hasSession) + { + // + // Iterate Sessions ... + for (int i = 0; i < sessionsCount; i++) + { + // + // Ignore unused Cases and Extracts only Content ... + string iSessionDescriptorStr = ExtractString(sessions[i]); + bool isInited = IsValid(iSessionDescriptorStr); + if (isInited) + { + // + // Extract Session Descriptor Data ... + string parts[]; + int partsCount = SplitContent( + parts, + iSessionDescriptorStr, + "_" // + ); + isInited = IsValidSize(partsCount) && partsCount == 3; + if (isInited) + { + // + string iName = parts[0]; + string iStart = parts[1]; + string iEnd = parts[2]; + isInited = IsValid(iName) && + IsValid(iStart) && + IsValid(iEnd); + if (isInited) + { + // + // Set Active Session Per Symbols ... + if (hasSymbols) + { + // + for (int j = 0; j < symbolsCount; j++) + { + // + eaTradeManager + .SetTradeSession( + symbols[j], + iStart, + iEnd, + iName // + ); + } + } + } + } + } + } + } + } + + // + // Initialize Signallers ... + if (hasSymbols) + { + // + // Prepare Signaller Inputs ... + XCATBEASignallerInputs iSignallerInputs; + + // + // Common Configs ... + + // + // Provider Name ... + iSignallerInputs.period = _Period; + iSignallerInputs.provider = "XTRGB"; + iSignallerInputs.allowGuards = eaAllowGuards; + iSignallerInputs.riskToRewardRatio = eaSignalR2R; + iSignallerInputs.allowDraws = IsRunningOnTestMode(); + iSignallerInputs.slATRMultiplier = eaSLATRMultiplier; + + // + // CATB Indicator ... + iSignallerInputs.catbInputs.Default(); + iSignallerInputs.catbInputs.Hide(); + + // + // Make Available all Requirement Buffers of XCATB indicator ... + iSignallerInputs.catbInputs.showPV = true; + iSignallerInputs.catbInputs.showKI = true; + iSignallerInputs.catbInputs.showATRBand = true; + iSignallerInputs.catbInputs.showPVGolden = true; + + // + // Prepare Trigger Block Validations ... + + // + iSignallerInputs.validations.forceHasSwing = eaForceHasSwing; + iSignallerInputs.validations.forceOBBarType = eaForceOBBarType; + iSignallerInputs.validations.minRequiredOBBar = eaMinRequiredOBBar; + iSignallerInputs.validations.forceFVGBarType = eaForceFVGBarType; + iSignallerInputs.validations.liquidityLoopback = eaLiquidityLoopback; + iSignallerInputs.validations.maxAllowedRange = eaMaxAllowedRange; + iSignallerInputs.validations.minAllowedRange = eaMinAllowedRange; + iSignallerInputs.validations.forceHasFLiquidity = eaForceHasFLiquidity; + iSignallerInputs.validations.forceHasRLiquidity = eaForceHasRLiquidity; + iSignallerInputs.validations.validateGapSequence = eaValidateGapSequence; + iSignallerInputs.validations.minAllowedBlockLength = eaMinAllowedBlockLength; + iSignallerInputs.validations.validateBlockEdgeBreakout = eaValidateBlockEdgeBreakout; + + // + // Prepare Trigger Block Filters ... + + // + iSignallerInputs.filters.filterBasedOnPV = eaFilterBasedOnPV; + iSignallerInputs.filters.bosLoopback = eaBosLoopback; + + // + iSignallerInputs.filters.filterBasedOnSar = eaFilterBasedOnSar; + iSignallerInputs.filters.forceSarSwitched = eaForceSarSwitched; + iSignallerInputs.filters.forceSarOnBothSide = eaForceSarOnBothSide; + iSignallerInputs.filters.forceSarHasBreakout = eaForceSarHasBreakout; + iSignallerInputs.filters.forceSarHasReversalSide = eaForceSarHasReversalSide; + + // + iSignallerInputs.filters.filterBasedOnRSI = eaFilterBasedOnRSI; + iSignallerInputs.filters.forceHasRSITrending = eaForceHasRSITrending; + iSignallerInputs.filters.forceHasRSIVPattern = eaForceHasRSIVPattern; + iSignallerInputs.filters.forceHasRSICrossing = eaForceHasRSICrossing; + + // + iSignallerInputs.filters.filterBasedOnADX = eaFilterBasedOnADX; + iSignallerInputs.filters.forceHasADXTrending = eaForceHasADXTrending; + iSignallerInputs.filters.forceHasADXCrossing = eaForceHasADXCrossing; + + // + iSignallerInputs.filters.filterBasedOnATR = eaFilterBasedOnATR; + iSignallerInputs.filters.forceHasATRTrending = eaForceHasATRTrending; + iSignallerInputs.filters.forceHasATRBreakout = eaForceHasATRBreakout; + + // + iSignallerInputs.filters.filterBasedOnTrend = eaFilterBasedOnTrend; + iSignallerInputs.filters.forceHasTrendDir = eaForceHasTrendDir; + iSignallerInputs.filters.forceHasTrendPlace = eaForceHasTrendPlace; + iSignallerInputs.filters.forceHasTrendChange = eaForceHasTrendChange; + iSignallerInputs.filters.forceHasTrendTrending = eaForceHasTrendTrending; + iSignallerInputs.filters.forceHasTrendRejection = eaForceHasTrendRejection; + iSignallerInputs.filters.forceHasTrendLineInside = eaForceHasTrendLineInside; + iSignallerInputs.filters.forceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; + + // + iSignallerInputs.filters.filterBasedOnKI = eaFilterBasedOnKI; + iSignallerInputs.filters.filterBasedOnDelta = eaFilterBasedOnDelta; + iSignallerInputs.filters.filterBasedOnVolume = eaFilterBasedOnVolume; + iSignallerInputs.filters.filterBasedOnSignalBar = eaFilterBasedOnSignalBar; + iSignallerInputs.filters.filterBasedOnRoundPrice = eaFilterBasedOnRoundPrice; + iSignallerInputs.filters.filterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + + // + // Loop through Symbols and Initialize Signaller + // for it, then Attached it to eaSignallers ... + for (int i = 0; i < symbolsCount; i++) + { + // + iSignallerInputs.symbol = symbols[i]; + if (iSignallerInputs.IsValid()) + { + // + // Initialize Signaller ... + XCXCATBEASignaller *iSignaller = new XCXCATBEASignaller(iSignallerInputs); + + // + // Add it to the Signallers List ... + Add( + iSignaller, + eaSignallers // + ); + + // + ZeroMemory(iSignaller); + } + } + + // + // Cleanup Resources ... + iSignallerInputs.Clean(); + } + + // + // since atleast one Signaller must + // exists to Expert works ... + // we check it as Last Step ... + result = hasSymbols && + HasChild(eaSignallers); + + // + return result; + } + + /** + * Handle De Initialization of Expert ... + */ + void HandleOnDeInit() + { + // + delete eaAlert; + ZeroMemory(eaAlert); + + // + delete eaTrade; + ZeroMemory(eaTrade); + + // + delete eaGuard; + ZeroMemory(eaGuard); + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + eaTimeTracker.Clean(); + + // + Clean(eaSignallers); + + // + delete eaTradeManager; + ZeroMemory(eaTradeManager); + } + + /** + * Handle Tick ... + */ + void HandleOnTick() + { + // + // Time Report Handling ... + HandleTimeReport(); + + // + // Position Management / Protections Handling ... + eaTradeManager.Manage(); + + // + // Check Signallers Registered ... + bool has = HasChild(eaSignallers); + if (!has) + { + return; + } + + // + // Define Collection of Requirements ... + XGuard guards[]; + XCATBEAStrategyConditions conditions[]; + + // + // Loop through Registered Signallers to Proccess Ticks and + // Collect: + // - Guards; + // - Triggered Conditions; + // - ... + int count = ArraySize(eaSignallers); + for (int i = 0; i < count; i++) + { + // + // Retrieve indexed Signaller ... + XCXCATBEASignaller *iSignaller = eaSignallers[i]; + + // + string iSymbol = iSignaller.GetSymbol(); + string iProvider = iSignaller.GetProvider(); + ENUM_TIMEFRAMES iPeriod = iSignaller.GetPeriod(); + + // + // Now we Have to Check Handle Tick Resoult ... + + // + // Requirements ... + XGuard iGuards[]; // Hold Provided Guards ... + XPosition iPositions[]; // Retrieve Signaller Positions ... + XCATBEAStrategyConditions iConditions; // Recieve Triggered Conditions ... + + // + // Reading Signaller Positions ... + eaTradeManager.GetPositions( + iPositions, + iSymbol, + iProvider, + iPeriod // + ); + + // + // Processing Tick for Signaller ... + iSignaller.ProcessTick( + iPositions, + iGuards, + iConditions // + ); + + // + // Check Results ... + has = HasChild(iGuards); + if (has) + { + // + Copy( + iGuards, + guards, + false // Force Clean ... + ); + } + + // + // Check Triggered Conditions ... + has = iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger(); + if (has) + { + // + AddRef( + iConditions, + conditions // + ); + } + + // + // Cleanup Resources ... + Clean(iGuards); + Clean(iPositions); + iConditions.Clean(); + } + + // + // Do Actions Based on Provided Info ... + + // + // Guards ... + has = HasChild(guards); + if (has) + { + // + // Handle Guards Firing ... + eaGuard.DoGuards(guards); + } + + // + // Triggers ... + has = HasChild(conditions); + if (has) + { + // + // Handle Conditions Triggering ... + TriggerConditions(conditions); + } + + // + // Cleanup Resources ... + + // + Clean(guards); + Clean(conditions); + } + + /** + * Handle Trade ... + */ + void HandleOnTrade() + { + } + + /** + * Handle Timer ... + */ + void HandleOnTimer() + { + } + + /** + * Handle Chart Event ... + * + * @param id: int, Event id ... + * @param lparam: long, Event Long Parameter ... + * @param dparam: double, Event Double Parameter ... + * @param sparam: string, Event String Parameter ... + */ + void HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Trade Event Handlers ... + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnStopLossTriggered(const XDeal &deal) + { + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) + { + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + } + + /** + * Handle Position Modified Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Position Partially Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Deals Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void HandleOnDealsChanged(int count) + { + } + + /** + * Handle Orders Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void HandleOnOrdersChanged(int count) + { + } + + /** + * Handle Positions Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void HandleOnPositionsChanged(int count) + { + } + + /** + * Handle all Trades States Changed Event ... + * + * @param state: XOnTradeHandlerState instance refrence, Changed Trade State data ... + */ + void HandleOnTradeStateChanged(const XOnTradeHandlerState &state) + { + } + + // + // protected ... + protected: + // + + /** + * Report Time Changes based on Given Configurations ... + */ + void HandleTimeReport() + { + // + if (eaAlert == NULL) + { + return; + } + + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.SendAlert(msg); + } + } + + /** + * Update Signal Targets ... + */ + void UpdateSignalTargets(XSignal &signal) + { + // + bool has = signal.IsValid(); + if (!has) + { + return; + } + + // + // Clean Signal Targets ... + Clean(signal.targets); + + // + // Calculate Requirements ... + double r2r = eaSignalR2R > 0 + ? eaSignalR2R + : 1; + double risk = signal.GetRisk(); + double reward = risk * r2r; + + // + double isLong = IsLong(signal.type); + + // + // Handling Signal TP ... + signal.tp = + isLong + ? signal.entry + reward + : signal.entry - reward; + + // + // Try to Apply Money Management ... + + // + // Sort Targets ... + ENUM_X_DIRECTION sortingDir = + isLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + ApplySortOnTargets( + sortingDir, + signal.targets // + ); + } + + /** + * Convert a Triggered Conditions to Signal and + * Execute it ... + */ + void TriggerConditions(XCATBEAStrategyConditions &conditions[]) + { + // + int count = 0; + bool has = false; + + // + has = HasChild(conditions); + if (!has) + { + return; + } + + // + count = ArraySize(conditions); + for (int i = 0; i < count; i++) + { + // + // Retrieve Indexed Conditions ... + XCATBEAStrategyConditions iConditions = conditions[i]; + + // + // Prepare Signal Based on Conditions ... + XSignal iSignal; + + // + // Check if a Trigger Block Attached and Has Signal ... + // use it ... + has = + iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger() && + iConditions.triggerBlock.IsValid() && + iConditions.triggerBlock.signal.IsValid(); + if (has) + { + iSignal = iConditions.triggerBlock.signal; + } + + // + // if we Have any other Signalling senarios we can Handle them here ... + + // + // Validate Signal ... + has = iSignal.IsValid(); + if (has) + { + // + // Retrieve Signal Type ... + bool isLong = IsLong(iSignal.type); + + // + // Update Signal Entry ... + iSignal.entry = GetEntry( + iSignal.symbol, + iSignal.type // + ); + + // + // Update Signal Targets ... + UpdateSignalTargets(iSignal); + + // + // Handle Volume Management ... + double iVolume = eaVolume.CalculateVolume(iSignal); + has = iVolume > X_MIN_VOLUME && + iVolume != iSignal.volume; + if (has) + { + iSignal.volume = iVolume; + } + + // + // Execute Signal ... + has = eaTradeManager.Execute( + iSignal, + iConditions // + ); + } + + // + // Cleanup Resources ... + + // + iSignal.Clean(); + iConditions.Clean(); + } + } + + // + // private ... + private: + // + + // +}; + +// \ No newline at end of file diff --git a/XCATBEA/Classes/xcatbea.signaller.class.mq5 b/XCATBEA/Classes/xcatbea.signaller.class.mq5 index 5ffaaf13..bb03e76c 100644 --- a/XCATBEA/Classes/xcatbea.signaller.class.mq5 +++ b/XCATBEA/Classes/xcatbea.signaller.class.mq5 @@ -41,7 +41,11 @@ struct XCATBEASignallerInputs // Pros ... string symbol; string provider; - ENUM_TIMEFRAMES period; + bool allowDraws; + bool allowGuards; + ENUM_TIMEFRAMES period; + double slATRMultiplier; + double riskToRewardRatio; X121XCatbInputs catbInputs; XTriggerBlockFilters filters; XTriggerBlockValidationRules validations; @@ -66,7 +70,11 @@ struct XCATBEASignallerInputs provider = NULL; filters.Clean(); catbInputs.Clean(); + allowDraws = false; validations.Clean(); + allowGuards = false; + slATRMultiplier = 0; + riskToRewardRatio = 0; // ZeroMemory(this); @@ -84,7 +92,8 @@ struct XCATBEASignallerInputs IsValid(symbol) && IsValid(period) && IsValid(provider) && - catbInputs.IsValid(); + catbInputs.IsValid() && + riskToRewardRatio > 0; // return result; @@ -102,8 +111,10 @@ class XCXCATBEASignaller : XCBase // Props ... // - bool useGuards; // Use Guards or not ... - bool allowDraws; // Allow Draws or not ... + bool allowDraws; // Allow Draws or not ... + bool allowGuards; // Allow Guards or not ... + double slATRMultiplier; // SL ATR Multiplier ... + double riskToRewardRatio; // Signals R2R ... // XBarTracker barTraker; // Bar Tracker ... @@ -112,6 +123,9 @@ class XCXCATBEASignaller : XCBase XCXCATBEAPOIDrawer *drawer; // POI Drawer ... XCXCATBEAPOIDetector *detector; // POI Detector ... + // + XBoxZone unavailableZones[]; // Un Available Zones ... + // XCATBEAStrategyConditions mConditions; XCATBEAStrategyConditions mConditionsCollection[]; @@ -151,6 +165,12 @@ class XCXCATBEASignaller : XCBase return period; } + // + double GetR2R() + { + return riskToRewardRatio; + } + // // Tick Analyser ... @@ -168,6 +188,7 @@ class XCXCATBEASignaller : XCBase conditions.Clean(); // + XOHCL bar; int count = 0; bool has = false; int barIndex = 0; @@ -212,6 +233,18 @@ class XCXCATBEASignaller : XCBase } // + // When Setup Invalidated + // Signaller Clean Conditions ... + if (!has && + !iConditions.IsValid()) + { + // + selectedIDX = i; + break; + } + + // + // Cleanup Resources ... iConditions.Clean(); } @@ -232,6 +265,21 @@ class XCXCATBEASignaller : XCBase } else { + // + // Check Selected Index for Invalid Conditions ... + if (IsValidIndex(selectedIDX)) + { + // + // Remove Invalidated Conditions ... + ArrayRemove( + mConditionsCollection, + selectedIDX, + 1 // + ); + } + + // + // Cleanup Resource ... conditions.Clean(); } } @@ -242,11 +290,38 @@ class XCXCATBEASignaller : XCBase { return; } - + + // + // Initialize Bar ... + bar.Init( + symbol, + period, + barIndex // + ); + + // + // Detect POI(s) ... + detector.Detect(barIndex); + + // + // Validate POI(s) ... + detector.Validate( + unavailableZones, + barIndex // + ); + + // + // Draw POI(s) ... + if (allowDraws) + { + drawer.Draw(bar.time); + } + // // Check Signal Setups ... has = DetectSignalSetup(barIndex); - if (has) { + if (has) + { // barTraker.Waits(); @@ -256,6 +331,10 @@ class XCXCATBEASignaller : XCBase // mConditions.Clean(); } + + // + // Cleanup Resources ... + bar.Clean(); } // @@ -312,6 +391,40 @@ class XCXCATBEASignaller : XCBase return result; } + // + bool isBullish = IsBullish(conditions.dir); + bool isBearish = IsBearish(conditions.dir); + + // + // Validate Direction of Setuped Conditions ... + result = + result && + (isBullish || + isBearish); + + // + // Do Triggering Senario based on Trigger Block ... + if (result && + conditions.triggerBlock.IsValid()) + { + // + // Complete Conditions Here ... + } + + // + // Do Other Validation Senarios ... + + // + result = conditions.IsValid() && + conditions.IsSetuped() && + conditions.CanTrigger(); + + // + // Check Setup Age or Setup Validations here ... + if (!result) + { + } + // // Cleanup Resources ... @@ -339,14 +452,32 @@ class XCXCATBEASignaller : XCBase // // Normalize Args ... + Clean(guards); barIndex = NormalizeInt(barIndex, 0); + // + result = allowGuards && + HasChild(positions); + if (!result) + { + return result; + } + // // TODO: Implement this ... + // + result = HasChild(guards); + // // Cleanup Resources ... + // + if (!result) + { + Clean(guards); + } + // return result; } @@ -372,6 +503,9 @@ class XCXCATBEASignaller : XCBase symbol = inputs.symbol; period = inputs.period; provider = inputs.provider; + allowGuards = inputs.allowGuards; + slATRMultiplier = inputs.slATRMultiplier; + riskToRewardRatio = inputs.riskToRewardRatio; // // Initialize Bar Tracker ... @@ -540,6 +674,8 @@ class XCXCATBEASignaller : XCBase // // Configure ... + detector.detectPeakPivots = true; + detector.detectValePivots = true; } // @@ -552,6 +688,35 @@ class XCXCATBEASignaller : XCBase // // Configure ... + drawer.drawPeakPivots = true; + drawer.drawValePivots = true; + + // + XCATBPivotStyle iStyle; + + // + // Styling Peak Pivot ... + iStyle.width = 1; + iStyle.clr = clrMagenta; + iStyle.style = STYLE_SOLID; + + // + drawer.peakPivotStyle = iStyle; + + // + // Styling Vale Pivot ... + iStyle.width = 1; + iStyle.clr = clrAqua; + iStyle.style = STYLE_SOLID; + + // + drawer.valePivotStyle = iStyle; + + // + // Cleanup Resources ... + + // + iStyle.Clean(); } } diff --git a/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 b/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 index c548f343..f55934f3 100644 --- a/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 +++ b/XCATBEA/Classes/xcatbea.x-poi.drawer.class.mq5 @@ -27,7 +27,7 @@ // // Definitions ... -struct XCAPivotStyle +struct XCATBPivotStyle { // // Properties ... @@ -37,7 +37,7 @@ struct XCAPivotStyle // // Constructor ... - XCAPivotStyle() + XCATBPivotStyle() { Default(); } @@ -89,12 +89,12 @@ class XCXCATBEAPOIDrawer : public XCBase // Styling ... // - XCAPivotStyle defaultBullishStyle; - XCAPivotStyle defaultBearishStyle; + XCATBPivotStyle defaultBullishStyle; + XCATBPivotStyle defaultBearishStyle; // - XCAPivotStyle peakPivotStyle; - XCAPivotStyle valePivotStyle; + XCATBPivotStyle peakPivotStyle; + XCATBPivotStyle valePivotStyle; // // Constructors ... @@ -250,7 +250,7 @@ class XCXCATBEAPOIDrawer : public XCBase { // // Select Styling Config ... - XCAPivotStyle style; + XCATBPivotStyle style; // if (box.IsBullish()) @@ -569,7 +569,7 @@ class XCXCATBEAPOIDrawer : public XCBase // void ApplyPivotStyle( XCBoxObject *&object, - XCAPivotStyle &style // + XCATBPivotStyle &style // ) { // diff --git a/XCATBEA/Libraries/xcatbea.lib.mq5 b/XCATBEA/Libraries/xcatbea.lib.mq5 index dd9cd7f5..1b734402 100644 --- a/XCATBEA/Libraries/xcatbea.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.lib.mq5 @@ -24,7 +24,6 @@ // Imports ... #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" -#include "../Libraries/xcatbea.lib.mq5" // // Definiions ... @@ -194,6 +193,7 @@ struct XTriggerBlockFilters { // // Props ... + bool filterBasedOnKI; // Filter Based On KI Flats ... bool filterBasedOnPV; // Filter Based On PV ... bool filterBasedOnSar; // Filter Based On SAR ... bool filterBasedOnRSI; // Filter Based On RSI ... @@ -203,6 +203,7 @@ struct XTriggerBlockFilters bool filterBasedOnDelta; // Filter Based On Delta ... bool filterBasedOnVolume; // Filter Based On Volume ... bool filterBasedOnSignalBar; // Filter Based on Signal Bar ... + bool filterBasedOnRoundPrice; // Filter Based On Round Prices ... bool filterBasedOnHKSignalBar; // Filter Based On HK Signal Bar ... // @@ -251,6 +252,7 @@ struct XTriggerBlockFilters void Clean() { // + filterBasedOnKI = false; filterBasedOnPV = false; filterBasedOnSar = false; filterBasedOnRSI = false; @@ -260,6 +262,7 @@ struct XTriggerBlockFilters filterBasedOnDelta = false; filterBasedOnVolume = false; filterBasedOnSignalBar = false; + filterBasedOnRoundPrice = false; filterBasedOnHKSignalBar = false; // @@ -1158,6 +1161,34 @@ bool FilterTriggerBlock( // // Checking Conditions ... + // + // Filter Based KI ... + if (result && + filters.filterBasedOnKI) + { + // + int count = 0; + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + double lKI = conditions.kiBuffer[zIDX]; + for (int i = toIDX; i < fromIDX; i++) + { + // + double iKI = helper.GetKI(i); + if (iKI == lKI) + { + count++; + } + else + { + break; + } + } + + // + result = count >= 3; + } + // // Filter Based On PV ... if (result && @@ -2230,6 +2261,15 @@ bool FilterTriggerBlock( } } + // + // Filter Based Round Price ... + if (result && + filters.filterBasedOnRoundPrice) + { + // + // TODO: Implement this ... + } + // if (!result) { diff --git a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 index 9ab706f6..d9b9f7aa 100644 --- a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 @@ -21,10 +21,11 @@ // // Imports ... +#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" #include "../../Libraries/x-saherelm.common.lib.mq5" #include "../../Libraries/x-saherelm.x-poi.lib.mq5" #include "../../Libraries/x-saherelm.x-trade.lib.mq5" -#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" +#include "../Libraries/xcatbea.lib.mq5" // // Definitions ... @@ -60,8 +61,9 @@ struct XCATBEAStrategyConditions datetime triggerTime; // + XBoxZone pivotZone; ENUM_X_DIRECTION dir; - XBoxZone decisionZone; + XTriggerBlock triggerBlock; ENUM_X_POSITION_TYPES type; X121XCatbConditions conditions; @@ -102,8 +104,9 @@ struct XCATBEAStrategyConditions Clean(targets); // + pivotZone.Clean(); conditions.Clean(); - decisionZone.Clean(); + triggerBlock.Clean(); // dir = X_DIRECTION_NONE; diff --git a/XCATBEA/Test/xcatb.test.ea.mq5 b/XCATBEA/Test/xcatb.test.ea.mq5 new file mode 100644 index 00000000..0e0e1efb --- /dev/null +++ b/XCATBEA/Test/xcatb.test.ea.mq5 @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XCATB MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XCAEA +// Description: an Exper Advisor which used XCATB +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "EA based on X121 XCATB indicator" +#property strict + +// +// Include Common Library ... +#include "../Classes/x-saherelm.x-guard.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" +#include "../XCATBEA/Classes/xcatbea.signaller.class.mq5" +#include "../XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5" + +// +#define ShortName "XCATBEA" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 1694056; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Detector ... +input group "Detector"; + +// +// Validating ... +input group "Validations"; +input bool eaForceHasSwing = false; // Force Block to Has Propper Swing +input bool eaForceOBBarType = false; // Force Order Block to Has InDirectional Bars +input int eaMinRequiredOBBar = 0; // Min Required OB Bar +input bool eaForceFVGBarType = false; // Force Fair Value Gaps Bars Type +input int eaLiquidityLoopback = 0; // Liquidity Detection Loopback +input double eaMaxAllowedRange = 0.0; // Max Allowed Order Block Range +input double eaMinAllowedRange = 0.0; // Min Allowed Order Block Range +input bool eaForceHasFLiquidity = false; // Force Order Block To Has Reversal Liquidity +input bool eaForceHasRLiquidity = false; // Force Order Block to Has Following Liquidity +input bool eaValidateGapSequence = false; // Validate Fair Value Gaps Bar Sequences +input int eaMinAllowedBlockLength = 0; // Min Allowed Block Length +input bool eaValidateBlockEdgeBreakout = false; // Validate Order Block Edge Breakeout + +// +// Filtering ... +input group "Filters"; +input bool eaFilterBasedOnKI = false; // Filter Based On KI Flats +input bool eaFilterBasedOnPV = false; // Filter Based On PV +input int eaBosLoopback = 0; // PV Based Filtering BOS Lookup +input bool eaFilterBasedOnSar = false; // Filter Based On SAR +input bool eaForceSarSwitched = false; // SAR Switched on Sides for Filtering +input bool eaForceSarOnBothSide = false; // SAR Check on Both Sides for Filtering +input bool eaForceSarHasBreakout = false; // SAR Must Breakout +input bool eaForceSarHasReversalSide = false; // SAR Must Has Reversal Direction +input bool eaFilterBasedOnRSI = false; // Filter Based On RSI +input bool eaForceHasRSITrending = false; // RSI Must Has Trending +input bool eaForceHasRSIVPattern = false; // RSI Must Has Pattern +input bool eaForceHasRSICrossing = false; // RSI Must Has Crossing Levels +input bool eaFilterBasedOnADX = false; // Filter Based On ADX +input bool eaForceHasADXTrending = false; // ADX Must Has Trending +input bool eaForceHasADXCrossing = false; // ADX Must Has Crossing +DI/-DI +input bool eaFilterBasedOnATR = false; // Filter Based On ATR +input bool eaForceHasATRTrending = false; // ATR Must Has Trending +input bool eaForceHasATRBreakout = false; // ATR Must Has Breakout +input bool eaFilterBasedOnTrend = false; // Filter Based On Trend +input bool eaForceHasTrendDir = false; // TREND Must Has Following Direction +input bool eaForceHasTrendPlace = false; // TREND Place Based Filtering +input bool eaForceHasTrendChange = false; // TREND Change Filtering +input bool eaForceHasTrendTrending = false; // TREND Must Has Trending +input bool eaForceHasTrendRejection = false; // TREND Line Must Rejected +input bool eaForceHasTrendLineInside = false; // TREND Line has Inside +input bool eaForceHasTrendDirOnBothSide = false; // TREND Must Has Following Direction in Both Side +input bool eaFilterBasedOnDelta = false; // Filter Based On Delta +input bool eaFilterBasedOnVolume = false; // Filter Based On Volume +input bool eaFilterBasedOnSignalBar = false; // Filter Based on Signal Bar +input bool eaFilterBasedOnRoundPrice = false; // Filter Based On Round Prices +input bool eaFilterBasedOnHKSignalBar = false; // Filter Based On HK Signal Bar + +// +// Signal ... +input group "Signal"; +input int eaSignalR2R = 2; // Risk Reward Ratio +input double eaSLATRMultiplier = 0; // ATR Multiplier for SL + +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_EQUITY; // Volume Applying Type +input double eaStaticVoluem = 0.0; // Static Volume +input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +input double eaConstantPercent = 0.5; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 0.0; // Constant Balance for Calculations + +// +// Management ... +// eaSessions => (SYDNEY_02:00_14:00),(NY_19:00_23:00) +input group "Management"; +input bool eaAllowGuards = false; // Allow Guards +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input string eaSessions = ""; // Active Sessions +input ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD eaRestrictionsPeriod = XCATBEA_TRADE_RESTRICATION_NONE; // Restrictions Period +input int eaMaxAllowedTPs = 0; // Max Allowed TP(s) in Restrictions Period +input int eaMaxAllowedSLs = 0; // Max Allowed SL(s) in Restrictions Period +input int eaMaxAllowedTrades = 0; // Max Allowed Trades in Restrictions Period +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 ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = true; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours +input bool eaReportTrades = true; // Report Trades +input bool eaReportSignals = true; // Report Signals +input bool eaReportProtector = true; // Report Protector Actions +input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished + +// +// Collector ... +input group "Collector"; +input bool eaSaveTrades = false; // Save Trades +input bool eaSaveSignals = false; // Save Signals +input bool eaSaveWins = false; // Save Winning Conditions +input bool eaSaveLosts = false; // Save Lost Conditions + +// +// Variables ... + +// +XCAlert *eaAlert; // EA Scope Alert Handler ... +XCTrade *eaTrade; // EA Scope Trade Handler ... +XCGuard *eaGuard; // EA Scope Guard Handler ... +string eaTag = ""; // Specified Alert Tag for EA ... +XCVolume *eaVolume; // EA Scope Voluem Handler ... +XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... +XCXCATBEASignaller *eaSignallers[]; // EA Signallers Collection ... +XCXCATBEATradeManager *eaTradeManager; // EA Scope Trade Manager ... + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initial Requirements ... + InitRequirements(); + + // + // Initialize Volume Manger ... + if (!InitVolume()) + { + return INIT_FAILED; + } + + // + 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 + + // + delete eaAlert; + ZeroMemory(eaAlert); + + // + delete eaTrade; + ZeroMemory(eaTrade); + + // + delete eaGuard; + ZeroMemory(eaGuard); + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + eaTimeTracker.Clean(); + + // + Clean(eaSignallers); + + // + delete eaTradeManager; + ZeroMemory(eaTradeManager); + + // + DestroyTimer(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + // Time Report Handling ... + HandleTimeReport(); + + // + // Position Management / Protections Handling ... + eaTradeManager.Manage(); + + // + // Count Signallers ... + bool has = HasChild(eaSignallers); + if (!has) + { + return; + } + + // + XGuard guards[]; + XCATBEAStrategyConditions conditions[]; + + // + int count = ArraySize(eaSignallers); + for (int i = 0; i < count; i++) + { + // + // Retrieve indexed Signaller ... + XCXCATBEASignaller *iSignaller = eaSignallers[i]; + + // + string iSymbol = iSignaller.GetSymbol(); + string iProvider = iSignaller.GetProvider(); + ENUM_TIMEFRAMES iPeriod = iSignaller.GetPeriod(); + + // + // Now we Have to Check Handle Tick Resoult ... + + // + // Requirements ... + XGuard iGuards[]; // Hold Provided Guards ... + XPosition iPositions[]; // Retrieve Signaller Positions ... + XCATBEAStrategyConditions iConditions; // Recieve Triggered Conditions ... + + // + // Reading Signaller Positions ... + eaTradeManager.GetPositions( + iPositions, + iSymbol, + iProvider, + iPeriod // + ); + + // + // Processing Tick for Signaller ... + iSignaller.ProcessTick( + iPositions, + iGuards, + iConditions // + ); + + // + // Check Results ... + has = HasChild(iGuards); + if (has) + { + // + Copy( + iGuards, + guards, + false // Force Clean ... + ); + } + + // + // Check Triggered Conditions ... + has = iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger(); + if (has) + { + // + AddRef( + iConditions, + conditions // + ); + } + + // + // Cleanup Resources ... + Clean(iGuards); + Clean(iPositions); + iConditions.Clean(); + } + + // + // Do Actions Based on Provided Info ... + + // + // Guards ... + has = HasChild(guards); + if (has) + { + // + // Handle Guards Firing ... + eaGuard.DoGuards(guards); + } + + // + // Triggers ... + has = HasChild(conditions); + if (has) + { + // + // Handle Conditions Triggering ... + TriggerConditions(conditions); + } + + // + // Cleanup Resources ... + + // + Clean(guards); + Clean(conditions); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrade.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ +} + +// +// Event Listeners ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaTradeManager.HandleSL(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaTradeManager.HandleTP(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: string ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + eaTradeManager.HandleForceClose(position); +} + +/** + * Handle Position Partially Closed Event ... + * + * @param ticket: ULONG ... + * @param profit: double ... + * @param comment: string ... + */ +void OnPositionPartiallyClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + eaTradeManager.HandlePartiallyClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +/** + * Initial Volume Manager Class Based on Given Configuration ... + * + * @return ( bool ) + */ +bool InitVolume() +{ + // + bool result = false; + + // + eaVolume = new XCVolume(); + + // + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + + // + return result; +} + +/** + * Initial Requirements of EA ... + */ +void InitRequirements() +{ + // + // Preparing Tags ... + eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogSuffix); + eaAlert.SetLogAlerts(eaLogAlerts); + eaAlert.SetMailAlerts(eaMailAlerts); + eaAlert.SetPushAlerts(eaPushAlerts); + eaAlert.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // EA Trade ... + eaTrade = new XCTrade( + eaSlippage, + eaMagicNumber, + eaMaxAllowedSpread, + eaMaxAllowedPositions, + eaMaxAllowedDrawdownFactor // + ); + + // + eaTrade.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrade.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrade.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaTrade.AddOnPartialClosePositionEventHandler(OnPositionPartiallyClosed); + + // + // EA Trae Manager ... + eaTradeManager = new XCXCATBEATradeManager( + eaTrade // + ); + + // + eaTradeManager.SetAlertPrefix(eaTag); + eaTradeManager.SetAlertLogAlerts(eaLogAlerts); + eaTradeManager.SetAlertMailAlerts(eaMailAlerts); + eaTradeManager.SetAlertPushAlerts(eaPushAlerts); + eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts); + eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); + + // + eaTradeManager.SaveWins(eaSaveWins); + eaTradeManager.SaveLosts(eaSaveLosts); + eaTradeManager.SaveTrades(eaSaveTrades); + eaTradeManager.SaveSignals(eaSaveSignals); + + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // Setting Trade Restrictions ... + eaTradeManager + .SetTradeRestrictions( + eaRestrictionsPeriod, + eaMaxAllowedTPs, + eaMaxAllowedSLs, + eaMaxAllowedTrades // + ); + + // + // EA Guard Initialization ... + eaGuard = new XCGuard( + eaTrade // + ); + + // + eaGuard.SetAlertPrefix(eaTag); + eaGuard.SetAlertLogAlerts(eaLogAlerts); + eaGuard.SetAlertMailAlerts(eaMailAlerts); + eaGuard.SetAlertPushAlerts(eaPushAlerts); + eaGuard.SetAlertEnableAlerts(eaEnableAlerts); + eaGuard.SetAlertTerminalAlerts(eaTerminalAlerts); + + // + // Initializing Sessions ... + string sessions[]; + int sessionsCount = 0; + bool hasSession = IsValid(eaSessions); + if (hasSession) + { + // + // Extract Per Symbol Sessions ... + sessionsCount = SplitContent( + sessions, + eaSessions, + "," // + ); + + // + // Try to Extract Start and End Times Series ... + hasSession = IsValidSize(sessionsCount); + if (hasSession) + { + // + // Iterate Sessions ... + for (int i = 0; i < sessionsCount; i++) + { + // + // Ignore unused Cases and Extracts only Content ... + string iSessionDescriptorStr = ExtractString(sessions[i]); + bool isInited = IsValid(iSessionDescriptorStr); + if (isInited) + { + // + // Extract Session Descriptor Data ... + string parts[]; + int partsCount = SplitContent( + parts, + iSessionDescriptorStr, + "_" // + ); + isInited = IsValidSize(partsCount) && partsCount == 3; + if (isInited) + { + // + string iName = parts[0]; + string iStart = parts[1]; + string iEnd = parts[2]; + isInited = IsValid(iName) && + IsValid(iStart) && + IsValid(iEnd); + if (isInited) + { + // + // Set Active Session ... + eaTradeManager + .SetTradeSession( + _Symbol, + iStart, + iEnd, + iName // + ); + } + } + } + } + } + } + + // + // Initializing Signaller(s) ... + string symbols[]; + Add( + _Symbol, + symbols // + ); + bool hasSymbols = HasChild(symbols); + if (hasSymbols) + { + // + // Prepare Signaller Inputs ... + XCATBEASignallerInputs iSignallerInputs; + + // + // Common Configs ... + + // + // Provider Name ... + iSignallerInputs.period = _Period; + iSignallerInputs.provider = "XTRGB"; + iSignallerInputs.allowGuards = eaAllowGuards; + iSignallerInputs.riskToRewardRatio = eaSignalR2R; + iSignallerInputs.allowDraws = IsRunningOnTestMode(); + iSignallerInputs.slATRMultiplier = eaSLATRMultiplier; + + // + // CATB Indicator ... + iSignallerInputs.catbInputs.Default(); + iSignallerInputs.catbInputs.Hide(); + + // + // Make Available all Requirement Buffers of XCATB indicator ... + iSignallerInputs.catbInputs.showPV = true; + iSignallerInputs.catbInputs.showKI = true; + iSignallerInputs.catbInputs.showATRBand = true; + iSignallerInputs.catbInputs.showPVGolden = true; + + // + // Trigger Block Validations ... + iSignallerInputs.validations.forceHasSwing = eaForceHasSwing; + iSignallerInputs.validations.forceOBBarType = eaForceOBBarType; + iSignallerInputs.validations.minRequiredOBBar = eaMinRequiredOBBar; + iSignallerInputs.validations.forceFVGBarType = eaForceFVGBarType; + iSignallerInputs.validations.liquidityLoopback = eaLiquidityLoopback; + iSignallerInputs.validations.maxAllowedRange = eaMaxAllowedRange; + iSignallerInputs.validations.minAllowedRange = eaMinAllowedRange; + iSignallerInputs.validations.forceHasFLiquidity = eaForceHasFLiquidity; + iSignallerInputs.validations.forceHasRLiquidity = eaForceHasRLiquidity; + iSignallerInputs.validations.validateGapSequence = eaValidateGapSequence; + iSignallerInputs.validations.minAllowedBlockLength = eaMinAllowedBlockLength; + iSignallerInputs.validations.validateBlockEdgeBreakout = eaValidateBlockEdgeBreakout; + + // + // Trigger Block Filters ... + + // + iSignallerInputs.filters.filterBasedOnPV = eaFilterBasedOnPV; + iSignallerInputs.filters.bosLoopback = eaBosLoopback; + + // + iSignallerInputs.filters.filterBasedOnSar = eaFilterBasedOnSar; + iSignallerInputs.filters.forceSarSwitched = eaForceSarSwitched; + iSignallerInputs.filters.forceSarOnBothSide = eaForceSarOnBothSide; + iSignallerInputs.filters.forceSarHasBreakout = eaForceSarHasBreakout; + iSignallerInputs.filters.forceSarHasReversalSide = eaForceSarHasReversalSide; + + // + iSignallerInputs.filters.filterBasedOnRSI = eaFilterBasedOnRSI; + iSignallerInputs.filters.forceHasRSITrending = eaForceHasRSITrending; + iSignallerInputs.filters.forceHasRSIVPattern = eaForceHasRSIVPattern; + iSignallerInputs.filters.forceHasRSICrossing = eaForceHasRSICrossing; + + // + iSignallerInputs.filters.filterBasedOnADX = eaFilterBasedOnADX; + iSignallerInputs.filters.forceHasADXTrending = eaForceHasADXTrending; + iSignallerInputs.filters.forceHasADXCrossing = eaForceHasADXCrossing; + + // + iSignallerInputs.filters.filterBasedOnATR = eaFilterBasedOnATR; + iSignallerInputs.filters.forceHasATRTrending = eaForceHasATRTrending; + iSignallerInputs.filters.forceHasATRBreakout = eaForceHasATRBreakout; + + // + iSignallerInputs.filters.filterBasedOnTrend = eaFilterBasedOnTrend; + iSignallerInputs.filters.forceHasTrendDir = eaForceHasTrendDir; + iSignallerInputs.filters.forceHasTrendPlace = eaForceHasTrendPlace; + iSignallerInputs.filters.forceHasTrendChange = eaForceHasTrendChange; + iSignallerInputs.filters.forceHasTrendTrending = eaForceHasTrendTrending; + iSignallerInputs.filters.forceHasTrendRejection = eaForceHasTrendRejection; + iSignallerInputs.filters.forceHasTrendLineInside = eaForceHasTrendLineInside; + iSignallerInputs.filters.forceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; + + // + iSignallerInputs.filters.filterBasedOnKI = eaFilterBasedOnKI; + iSignallerInputs.filters.filterBasedOnDelta = eaFilterBasedOnDelta; + iSignallerInputs.filters.filterBasedOnVolume = eaFilterBasedOnVolume; + iSignallerInputs.filters.filterBasedOnSignalBar = eaFilterBasedOnSignalBar; + iSignallerInputs.filters.filterBasedOnRoundPrice = eaFilterBasedOnRoundPrice; + iSignallerInputs.filters.filterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + + // + + // + // Loop Through Symbols for Signalling Initializing ... + int symbolsCount = ArraySize(symbols); + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = symbols[i]; + + // + iSignallerInputs.symbol = iSymbol; + if (iSignallerInputs.IsValid()) + { + // + // Initialize Signaller ... + XCXCATBEASignaller *iSignaller = new XCXCATBEASignaller(iSignallerInputs); + + // + // Add it to the Signallers List ... + Add( + iSignaller, + eaSignallers // + ); + + // + ZeroMemory(iSignaller); + } + } + + // + // Cleanup Resources ... + iSignallerInputs.Clean(); + } + + // +} + +/** + * Handling Time Reporting ... + */ +void HandleTimeReport() +{ + // + if (eaAlert == NULL) + { + return; + } + + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.SendAlert(msg); + } +} + +/** + * Update Signal Targets ... + */ +void UpdateSignalTargets(XSignal &signal) +{ + // + bool has = signal.IsValid(); + if (!has) + { + return; + } + + // + // Clean Signal Targets ... + Clean(signal.targets); + + // + // Calculate Requirements ... + double r2r = eaSignalR2R > 0 + ? eaSignalR2R + : 1; + double risk = signal.GetRisk(); + double reward = risk * r2r; + + // + double isLong = IsLong(signal.type); + + // + // Handling Signal TP ... + signal.tp = + isLong + ? signal.entry + reward + : signal.entry - reward; + + // + // Try to Apply Money Management ... + + // + // if (r2r <= 1) + // { + // return; + // } + + // + // XTarget iTarget; + + // // + // // Partial Close 0.5 of Position on Reward 1 ... + // reward = risk * 1; + // iTarget.target = + // isLong + // ? signal.entry + reward + // : signal.entry - reward; + // iTarget.volumeMultiplier = 0.5; + + // // + // AddRef(iTarget, signal.targets); + // iTarget.Clean(); + + // // + // if (r2r <= 2) + // { + // return; + // } + + // + // Making Loop ... + // for (int i = 2; i < ((int)r2r - 1); i++) + // { + // // + // iTarget.Clean(); + + // // + // reward = i * risk; + // iTarget.target = + // isLong + // ? signal.entry + reward + // : signal.entry - reward; + // iTarget.volumeMultiplier = 1 / (r2r - 2); + + // // + // AddRef(iTarget, signal.targets); + // } + + // + // Sort Targets ... + ENUM_X_DIRECTION sortingDir = + isLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + ApplySortOnTargets( + sortingDir, + signal.targets // + ); +} + +/** + * Convert a Triggered Conditions to Signal and + * Execute it ... + */ +void TriggerConditions(XCATBEAStrategyConditions &conditions[]) +{ + // + int count = 0; + bool has = false; + + // + has = HasChild(conditions); + if (!has) + { + return; + } + + // + count = ArraySize(conditions); + for (int i = 0; i < count; i++) + { + // + // Retrieve Indexed Conditions ... + XCATBEAStrategyConditions iConditions = conditions[i]; + + // + // Prepare Signal Based on Conditions ... + XSignal iSignal; + + // + // Check if a Trigger Block Attached and Has Signal ... + // use it ... + has = + iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger() && + iConditions.triggerBlock.IsValid() && + iConditions.triggerBlock.signal.IsValid(); + if (has) + { + iSignal = iConditions.triggerBlock.signal; + } + + // + // if we Have any other Signalling senarios we can Handle them here ... + + // + // Validate Signal ... + has = iSignal.IsValid(); + if (has) + { + // + // Retrieve Signal Type ... + bool isLong = IsLong(iSignal.type); + + // + // Update Signal Entry ... + iSignal.entry = GetEntry( + iSignal.symbol, + iSignal.type // + ); + + // + // Update Signal Targets ... + UpdateSignalTargets(iSignal); + + // + // Handle Volume Management ... + double iVolume = eaVolume.CalculateVolume(iSignal); + has = iVolume > X_MIN_VOLUME && + iVolume != iSignal.volume; + if (has) + { + iSignal.volume = iVolume; + } + + // + // Execute Signal ... + has = eaTradeManager.Execute( + iSignal, + iConditions // + ); + } + + // + // Cleanup Resources ... + + // + iSignal.Clean(); + iConditions.Clean(); + } +} + +// \ No newline at end of file