diff --git a/Experts/x-saherelm.xcaea.ea.mq5 b/Experts/x-saherelm.xcaea.ea.mq5 index 6cfe9fb1..7d83502e 100644 --- a/Experts/x-saherelm.xcaea.ea.mq5 +++ b/Experts/x-saherelm.xcaea.ea.mq5 @@ -50,6 +50,17 @@ input double eaConstantRiskBalance = 0.0; // Constant Ri input double eaConstantPercent = 0.5; // Constant Percent of Balance Per Trade input double eaConstantBalance = 0.0; // Constant Balance for Calculations +// +// Management ... +input group "Management"; +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input int eaMaxAllowedTradesPerDay = 3; // Max Allowed Trades per Day +input int eaMaxAllowedSLsPerDay = 2; // Max Allowed SL(s) per Day +input string eaSessionStartTime = ""; // Trade Start Time +input string eaSessionEndTime = ""; // Trade End Time + // // Alert ... // Here we Provider All Requirements for @@ -64,10 +75,14 @@ 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 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 // // Variables, Instances ... @@ -327,6 +342,8 @@ void OnTick() eaSignal.time = eaConditions.time; eaSignal.symbol = eaConditions.symbol; eaSignal.period = eaConditions.period; + eaSignal.partialCloseOnTPLevel = eaConditions.partialCloseOnTPLevel; + eaSignal.partialCloseMultiplier = eaConditions.partialCloseMultiplier; // Copy( @@ -627,6 +644,34 @@ void InitRequirements() eaTradeManager.SetAlertPushAlerts(eaPushAlerts); eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // + // + // + // eaMaxAllowedTradesPerDay + // eaMaxAllowedSLsPerDay + // eaSessionStartTime + // eaSessionEndTime + // // EA Signaller ... eaSignaller = new XCXCAEASignaller( diff --git a/Libraries/x-saherelm.x-trade.lib.mq5 b/Libraries/x-saherelm.x-trade.lib.mq5 index a1054a05..999728d2 100644 --- a/Libraries/x-saherelm.x-trade.lib.mq5 +++ b/Libraries/x-saherelm.x-trade.lib.mq5 @@ -952,6 +952,32 @@ struct XPosition } } + // + // Calculate Touched Reward ... + double CalculateTouchedReward() + { + // + double result = 0.0; + + // + bool has = IsValid() && + profit > 0; + if (!has) + { + return result; + } + + // + double risk = MathAbs(entry - sl); + double currentReward = MathAbs(price - entry); + + // + result = currentReward / risk; + + // + return result; + } + // // Calculate Age ... int GetAge( @@ -1111,6 +1137,7 @@ struct XSignal // // TP ... double fullTPLevel; // Full TP ... + bool isPartiallyClosed; // Check Partially Closed Before or not ... double partialCloseMultiplier; // Amount of Partial Close ... double partialCloseOnTPLevel; // Do Partial Close on TP Level ... @@ -1121,10 +1148,10 @@ struct XSignal // // Traget ... - double targets[]; // Force Risk Free On Targets ... + double targets[]; // Force Risk Free On Targets ... bool isTargetApplied; // Target Applied ... int appliedTargetIDX; // Last Applied Target Index ... - bool ignoreEAVolume; // Ignore EA Volume ... + bool ignoreEAVolume; // Ignore EA Volume ... // // SL Trail ... @@ -1697,6 +1724,7 @@ struct XSignal fullTPLevel = 0; tpLevelForBreakEven = 0; partialCloseOnTPLevel = 0; + isPartiallyClosed = false; partialCloseMultiplier = 0; trailSLStartOnReachTPLevel = 0; @@ -1709,7 +1737,8 @@ struct XSignal // // Default Values ... - void Default() { + void Default() + { // entry = 0; volume = 0; @@ -1739,6 +1768,7 @@ struct XSignal // fullTPLevel = 0; tpLevelForBreakEven = 0; + isPartiallyClosed = false; partialCloseOnTPLevel = 0; partialCloseMultiplier = 0; trailSLStartOnReachTPLevel = 0; @@ -2029,12 +2059,13 @@ struct XSignal } // - bool IsSameAs(XSignal &item) { + bool IsSameAs(XSignal &item) + { // bool result = false; // - result = + result = // IsValid() && item.IsValid() && @@ -2054,6 +2085,28 @@ struct XSignal // return result; } + + // + string GetMessage() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = ToString(type) + + " Signal Provided by: " + provider + + " on (" + symbol + ")" + + " in: " + ToString(period); + + // + return result; + } }; // @@ -5239,7 +5292,6 @@ bool IsStateFilterPassed( // - // // // Calculate Positions Profit Summary ... diff --git a/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 b/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 index f8fdfa60..44adf9c6 100644 --- a/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 +++ b/XCAEA/Classes/xcaea.x-trade.manager.class.mq5 @@ -319,6 +319,17 @@ class XCXCAEATradeManager : public XCBaseAlert drawSignal = true; drawer = new XCPOIDrawer(); + // + allowTrade = true; + allowLongs = true; + allowShorts = true; + + // + reportTrades = true; + reportSignals = true; + reportProtector = true; + reportAfterTradesBalance = true; + // SaveTrades(false); @@ -362,6 +373,52 @@ class XCXCAEATradeManager : public XCBaseAlert mSaveTrades = value; } + // + // TODO: Implement this ... + void SetTradeSession( + string start, + string end // + ) + { + // + bool has = IsValid(start) || + IsValid(end); + if (!has) + { + return; + } + + // + } + + // + void SetTradeReports( + bool _reportTrades, + bool _reportSignals, + bool _reportProtector, + bool _reportAfterTradesBalance // + ) + { + // + reportTrades = _reportTrades; + reportSignals = _reportSignals; + reportProtector = _reportProtector; + reportAfterTradesBalance = _reportAfterTradesBalance; + } + + // + void SetTradePermissions( + bool _allowTrade, + bool _allowLongs, + bool _allowShorts // + ) + { + // + allowTrade = _allowTrade; + allowLongs = _allowLongs; + allowShorts = _allowShorts; + } + // // Tools ... @@ -543,6 +600,7 @@ class XCXCAEATradeManager : public XCBaseAlert if (iPosition.profit > 0) { // + // Handle Risk Free On Targets ... double targets[]; Copy( trades[idx].signal.targets, @@ -624,7 +682,55 @@ class XCXCAEATradeManager : public XCBaseAlert ToString(iPosition.ticket) + " RF On Traget: " + ToString(jTarget) + " Successfully ..."; - Alert(message); + HandleReportProtector(message); + } + } + } + } + + // + // Handle Partial Close on Specified Targets ... + has = !trades[idx].signal.isPartiallyClosed && + trades[idx].signal.partialCloseOnTPLevel > 0 && + trades[idx].signal.partialCloseMultiplier > 0; + if (has) + { + // + // Check Reward Touched ... + double iCurrReward = iPosition.CalculateTouchedReward(); + has = iCurrReward >= trades[idx].signal.partialCloseOnTPLevel; + if (has) + { + // + // Check Volume Multiplier ... + double volumeMultiplier = trades[idx].signal.partialCloseMultiplier; + has = volumeMultiplier > 0 && + volumeMultiplier <= 1; + if (has) + { + // + // Do Partial Closing ... + double volume = iPosition.volume * volumeMultiplier; + string comment = "PC On Target ..."; + has = trader.ClosePartial( + iPosition.ticket, + volume, + comment // + ); + if (has) + { + // + // Update Model ... + trades[idx].signal.isPartiallyClosed = true; + + // + string message = prefix + + ToString(iPosition.type) + + " Position: " + + ToString(iPosition.ticket) + + " PC (" + ToString(volume) + ") On Traget: " + ToString(iCurrReward) + + " Successfully ..."; + HandleReportProtector(message); } } } @@ -633,6 +739,93 @@ class XCXCAEATradeManager : public XCBaseAlert } } + /** + * Check Signal Execution Conditions ... + * + * @param signal: XSignal instance reference ... + * @param executionResult: ENUM_X_SIGNAL_EXECUTION_RESULT member reference ... + * + * @return ( bool ) + */ + bool CheckSignal( + XSignal &signal, + ENUM_X_SIGNAL_EXECUTION_RESULT &executionResult // + ) + { + // + bool result = false; + + // + // Cleanup ... + executionResult = X_SIGNAL_EXECUTION_UNKNOWN; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + // Reporting Signal ... + if (reportSignals) + { + // + string message = signal.GetMessage(); + Alert(message); + } + + // + // Check Trade Permission ... + if (!allowTrade) + { + // + result = false; + executionResult = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + + // + return result; + } + + // + bool isLong = IsLong(signal.type); + bool isShort = IsShort(signal.type); + + // + bool isLongAndAllowed = + isLong && + allowLongs; + + // + bool isShortAndAllowed = + isShort && + allowShorts; + + // + result = isLongAndAllowed || + isShortAndAllowed; + if (!result) + { + // + executionResult = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + + // + return result; + } + + // + // TODO: Complete this ... + // Implementing Trade Session Validating ... + + // + // TODO: Complete this ... + // Implementing Trade Permissions Based on SL(s) Count ... + + // + return result; + } + /** * Execute Specified Signal ... * @@ -670,15 +863,30 @@ class XCXCAEATradeManager : public XCBaseAlert // ENUM_X_SIGNAL_EXECUTION_RESULT executionResult; - result = trader.ExecuteSignal( + + // + // Checking Signal For Execution ... + result = CheckSignal( signal, executionResult // ); + if (result) + { + // + result = trader.ExecuteSignal( + signal, + executionResult // + ); + } // // Alert Signal Execution ... - string executionMessage = ToString(executionResult); - Alert(executionMessage); + if (reportTrades) + { + // + string executionMessage = ToString(executionResult); + Alert(executionMessage); + } // if (result) @@ -762,6 +970,11 @@ class XCXCAEATradeManager : public XCBaseAlert // Save Trade ... Save(trades[idx]); + // + // Handle Balance Reporting ... + string prefix = "TP: " + ToString(trades[idx].profit); + HandleReportBalance(prefix); + // RemoveTrade(idx); } @@ -800,6 +1013,11 @@ class XCXCAEATradeManager : public XCBaseAlert // Save Trade ... Save(trades[idx]); + // + // Handle Balance Reporting ... + string prefix = "SL: " + ToString(trades[idx].profit); + HandleReportBalance(prefix); + // RemoveTrade(idx); } @@ -854,6 +1072,16 @@ class XCXCAEATradeManager : public XCBaseAlert // Save Trade ... Save(trades[idx]); + // + // Handle Balance Reporting ... + string prefix = "Force Close " + + (isInProfit + ? "Profit" + : "Loss") + + ": " + + ToString(trades[idx].profit); + HandleReportBalance(prefix); + // RemoveTrade(idx); } @@ -1045,6 +1273,41 @@ class XCXCAEATradeManager : public XCBaseAlert return result; } + // + void HandleReportBalance(string prefix = NULL) + { + // + if (!reportAfterTradesBalance) + { + return; + } + + // + double balance = trader.mAccount.GetBalance(); + string currency = trader.mAccount.GetCurrency(); + + // + string message = + (IsValid(prefix) + ? prefix + "\n" + : "") + + "Account Balance: " + ToString(balance) + currency; + Alert(message); + } + + // + void HandleReportProtector(string message = NULL) + { + // + if (!reportProtector) + { + return; + } + + // + Alert(message); + } + // bool Save( XCAEATrade &trade, @@ -1093,6 +1356,11 @@ class XCXCAEATradeManager : public XCBaseAlert // // Props ... + // + bool allowTrade; + bool allowLongs; + bool allowShorts; + // bool mSaveTrades; @@ -1104,6 +1372,12 @@ class XCXCAEATradeManager : public XCBaseAlert int managedSLCount; int managedTPCount; + // + bool reportTrades; + bool reportSignals; + bool reportProtector; + bool reportAfterTradesBalance; + // CArrayObj mObjects; diff --git a/XCAEA/Libraries/xcaea.signaller.lib.mq5 b/XCAEA/Libraries/xcaea.signaller.lib.mq5 index 06249a27..85119687 100644 --- a/XCAEA/Libraries/xcaea.signaller.lib.mq5 +++ b/XCAEA/Libraries/xcaea.signaller.lib.mq5 @@ -79,6 +79,10 @@ struct XCAEAStrategyConditions datetime setupTime; datetime triggerTime; + // + double partialCloseOnTPLevel; + double partialCloseMultiplier; + // ENUM_X_DIRECTION dir; XBoxZone decisionZone; @@ -118,6 +122,10 @@ struct XCAEAStrategyConditions setupTime = NULL; triggerTime = NULL; + // + partialCloseOnTPLevel = 0; + partialCloseMultiplier = 0; + // Clean(targets); @@ -711,6 +719,14 @@ bool DetectDecisionZone( double p2FastState = conditions.fastStateBuffer[p2IDX]; double p3FastState = conditions.fastStateBuffer[p3IDX]; + // + // RSI ... + double zRSI = conditions.rsiBuffer[zIDX]; + double cRSI = conditions.rsiBuffer[cIDX]; + double pRSI = conditions.rsiBuffer[pIDX]; + double p2RSI = conditions.rsiBuffer[p2IDX]; + double p3RSI = conditions.rsiBuffer[p3IDX]; + // // Create Custom Conditions ... @@ -912,7 +928,19 @@ bool DetectDecisionZone( bool isSarSwitchedToBearish = cFastState < 0 && isSarSwitchedInFiboStrongBearish; - ; + + // + // RSI Conditions ... + + // + bool isRSICrossedOverOS = + p3RSI < conditions.rsiOSLevel && + cRSI > conditions.rsiOSLevel; + + // + bool isRSICrossedUnderOB = + p3RSI > conditions.rsiOBLevel && + cRSI < conditions.rsiOBLevel; // // Testing Conditions ... @@ -1047,12 +1075,14 @@ bool DetectDecisionZone( // bool isCond1Bullish = isCIsValePivot && + isRSICrossedOverOS && !isFiboSectionChanged && isSarSwitchedToBullish; // bool isCond1Bearish = isCIsPeakPivot && + isRSICrossedUnderOB && !isFiboSectionChanged && isSarSwitchedToBearish; @@ -1167,18 +1197,12 @@ bool DetectDecisionZone( } // - bool isCond2 = - (cPeak == pPeak && - cPeak == cSWH && - cPeak == cResistance) && - (cVale == pVale && - cVale == cSWL && - cVale == cSupport); - if (isCond2) - { - // - Print("Decision Zone Full Cond1"); - } + // bool isCond2 = isFiboSectionChanged; + // if (isCond2) + // { + // // + // Print("Decision Zone Full Cond1"); + // } // // Summarise Result ... @@ -1232,6 +1256,275 @@ bool DetectDecisionZone( // // Trigger Conditions ... +// +// Detect Trigger Based On Decision Zone's +// Volume and Score ... +bool CanTriggerCond0( + XCXCAEAHelper *helper, + XBoxZone &box, + ENUM_X_DIRECTION &dir, + double &sl, + double &tp, + int barIndex = 0, + int loopback = 5, + double scorePassMultiplier = 1 // +) +{ + // + bool result = false; + + // + // Normalize Args ... + sl = 0; + tp = 0; + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 5); + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate Decision Box ... + result = box.IsValid() && + helper != NULL; + if (!result) + { + return result; + } + + // + // Define Requirements ... + + // + bool isBullish = box.IsBullish(); + bool isBearish = box.IsBearish(); + + // + // Scores ... + double bullScores[]; + double bearScores[]; + + // + // Volumes ... + double bullVolumes[]; + double bearVolumes[]; + + // + // Create a Loop through Loopack ... + XOHCL iBar; + bool has = false; + int start = barIndex; + XCAEAConditions iConditions; + int end = barIndex + loopback; + for (int i = end; i >= start; i--) + { + // + // Retrieve Bar ... + has = iBar.Init( + box.symbol, + box.period, + i // + ); + if (!has) + { + // + iBar.Clean(); + iConditions.Clean(); + + // + continue; + } + + // + // Retrieve Conditions ... + has = helper.GetConditions( + iConditions, + i // + ); + if (!has) + { + // + iBar.Clean(); + iConditions.Clean(); + + // + continue; + } + + // + // Retrieve Scores ... + double iBullScore = 0; + double iBearScore = 0; + iConditions + .GenerateScore( + iBullScore, + iBearScore // + ); + Add( + iBullScore, + bullScores // + ); + Add( + iBearScore, + bearScores // + ); + + // + // Retrieve Volumes ... + double iBullVolume = 0; + double iBearVolume = 0; + helper + .barAnalyser + .CalculateRangeVolume( + iBar, + iBullVolume, + iBearVolume, + 2 // Loopback ... + ); + Add( + iBullVolume, + bullVolumes // + ); + Add( + iBearVolume, + bearVolumes // + ); + + // + iBar.Clean(); + iConditions.Clean(); + } + + // + // Calculating Requirements ... + + // + // Scores ... + + // + // Bullish ... + double bullScore = GetSum(bullScores); + double bullScoreMax = GetMax(bullScores); + double bullScoreMin = GetMin(bullScores); + + // + // Bearish ... + double bearScore = GetSum(bearScores); + double bearScoreMax = GetMax(bearScores); + double bearScoreMin = GetMin(bearScores); + + // + // Volumes ... + + // + // Bullish ... + double bullVolume = GetSum(bullVolumes); + double bullVolumeMax = GetMax(bullVolumes); + double bullVolumeMin = GetMin(bullVolumes); + + // + // Bearish ... + double bearVolume = GetSum(bearVolumes); + double bearVolumeMax = GetMax(bearVolumes); + double bearVolumeMin = GetMin(bearVolumes); + + // + // Creating Result Conditions ... + + // + bool isBullishPassed = + isBullish && + bullScore >= (scorePassMultiplier * bearScore) && + bullVolume >= (scorePassMultiplier * bearVolume); + + // + bool isBearishPassed = + isBearish && + bearScore >= (scorePassMultiplier * bullScore) && + bearVolume >= (scorePassMultiplier * bullVolume); + + // + result = isBullishPassed || + isBearishPassed; + if (!result) + { + // + iBar.Clean(); + Clean(bullScores); + Clean(bearScores); + Clean(bullVolumes); + Clean(bearVolumes); + iConditions.Clean(); + + // + return result; + } + + // + // Validating Box to Find a Rejection ... + + // + // Validating Box to Has a Gap ... + + // + // Validating Box to Has a Block ... + + // + bool isPassed = + isBullishPassed || + isBearishPassed; + if (isPassed) + { + // + // Preparing TP and SL ... + + // + sl = isBullishPassed + ? box.lower + : box.upper; + + // + tp = 0; + } + + // + // Summarizing ... + + // + bool canTriggerLong = + isBullishPassed; + + // + bool canTriggerShort = + isBearishPassed; + + // + result = canTriggerLong || + canTriggerShort; + if (result) + { + // + dir = canTriggerLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + Print("Triggered ..."); + } + + // + // Cleanup Resources ... + + // + iBar.Clean(); + Clean(bullScores); + Clean(bearScores); + Clean(bullVolumes); + Clean(bearVolumes); + iConditions.Clean(); + + // + return result; +} + // // Detect Trigger Based On Decision Zone's // Fake Breaked out ... @@ -1258,7 +1551,8 @@ bool CanTriggerCond1( // // Validate Decision Box ... - result = box.IsValid(); + result = box.IsValid() && + helper != NULL; if (!result) { return result; @@ -1373,7 +1667,8 @@ bool CanTriggerCond2( // // Validate Decision Box ... - result = box.IsValid(); + result = box.IsValid() && + helper != NULL; if (!result) { return result; diff --git a/XCAEA/Signals/xcaea.signaller.class.mq5 b/XCAEA/Signals/xcaea.signaller.class.mq5 index 0d535359..b7d41ea0 100644 --- a/XCAEA/Signals/xcaea.signaller.class.mq5 +++ b/XCAEA/Signals/xcaea.signaller.class.mq5 @@ -139,8 +139,8 @@ class XCXCAEASignaller : XCBase inputs.caInputs.showPeaksAndVales = true; // - inputs.caInputs.showKI = false; - inputs.caInputs.showTKI = false; + inputs.caInputs.showKI = true; + inputs.caInputs.showTKI = true; inputs.caInputs.showVidya = true; inputs.caInputs.showTrend = true; inputs.caInputs.showPeakAndValeGolden = false; @@ -159,7 +159,7 @@ class XCXCAEASignaller : XCBase // // Oscillators Views ... - inputs.showRSI = false; + inputs.showRSI = true; inputs.showCCI = false; inputs.showMFI = false; inputs.showRVI = false; @@ -602,29 +602,42 @@ class XCXCAEASignaller : XCBase // Checking Trigger Conditions ... double sl = 0; double tp = 0; - ENUM_X_DIRECTION triggerDir; + ENUM_X_DIRECTION triggerDir = X_DIRECTION_NONE; + + // + // Checking Trigger Cond 0 ... + bool canTriggerCond0 = CanTriggerCond0( + helper, + conditions.decisionZone, + triggerDir, + sl, + tp, + barIndex // + ); // // Checking Trigger Cond 1 ... - bool canTriggerCond1 = CanTriggerCond1( - helper, - conditions.decisionZone, - triggerDir, - sl, - tp, - barIndex // - ); + bool canTriggerCond1 = false; + // CanTriggerCond1( + // helper, + // conditions.decisionZone, + // triggerDir, + // sl, + // tp, + // barIndex // + // ); // // Checking Trigger Cond 2 ... - bool canTriggerCond2 = CanTriggerCond2( - helper, - conditions.decisionZone, - triggerDir, - sl, - tp, - barIndex // - ); + bool canTriggerCond2 = false; + // CanTriggerCond2( + // helper, + // conditions.decisionZone, + // triggerDir, + // sl, + // tp, + // barIndex // + // ); // // Update Signal Box To ... @@ -645,6 +658,7 @@ class XCXCAEASignaller : XCBase // // Summarizing Result ... result = + canTriggerCond0 || canTriggerCond1 || canTriggerCond2; @@ -655,6 +669,7 @@ class XCXCAEASignaller : XCBase IsBearish(triggerDir); // + // Configure Conditions for Preparing Signal ... if (result) { // @@ -697,6 +712,22 @@ class XCXCAEASignaller : XCBase conditions.targets // ); + // + rfReward = risk * 2.85; + rfPrice = + isBullish + ? entry + rfReward + : entry - rfReward; + Add( + rfPrice, + conditions.targets // + ); + + // + // Handling Partial Close ... + conditions.partialCloseOnTPLevel = 1; + conditions.partialCloseMultiplier = 0.5; + // conditions.sl = sl; conditions.tp = tp;