From a1c0a364af76a0007799b8503e1262b1f062912b Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Tue, 17 Sep 2024 16:49:45 +0330 Subject: [PATCH] last works on Position Protector ... --- .vscode/vscode-kanban.json | 28 +- .../x-saherelm.x121.xtrade.handler.class.mq5 | 550 +++++++++++++++++- Experts/x-saherelm.x121.ea.mq5 | 1 + Libraries/x-saherelm.xtrade.lib.mq5 | 62 +- 4 files changed, 619 insertions(+), 22 deletions(-) diff --git a/.vscode/vscode-kanban.json b/.vscode/vscode-kanban.json index 2bcf309d..81cfaeaa 100644 --- a/.vscode/vscode-kanban.json +++ b/.vscode/vscode-kanban.json @@ -7,18 +7,15 @@ }, "creation_time": "2024-09-16T10:58:36.122Z", "description": { - "content": "Complete Position Protector Tasks\n", - "mime": "text/markdown" - }, - "details": { - "content": "- [] Hedge;\n- [] Protector Start;\n", + "content": "Complete Position Protector Tasks\n\n- [] Hedge;\n- [x] Position Profit in Point;\n- [x] Protector Start;\n- [x] Same Signals Delay;\n- [] Signal Protecting;", "mime": "text/markdown" }, "id": "89", "references": [ "90", "91", - "92" + "92", + "93" ], "title": "Complete Position Protector" }, @@ -39,10 +36,14 @@ "assignedTo": { "name": "Hadi Khazaee Asl" }, - "creation_time": "2024-09-16T13:08:56.494Z", - "id": "92", + "creation_time": "2024-09-16T23:16:09.221Z", + "description": { + "content": "- [] Conditions for In Profit;\n- [] Conditions for In DrawDown;", + "mime": "text/markdown" + }, + "id": "93", "references": [], - "title": "Implement Protector Start Point" + "title": "Implement Signal Protecting Mechanism" } ], "testing": [ @@ -58,6 +59,15 @@ "id": "90", "references": [], "title": "Implement HE Hedge mechanism" + }, + { + "assignedTo": { + "name": "Hadi Khazaee Asl" + }, + "creation_time": "2024-09-16T13:08:56.494Z", + "id": "92", + "references": [], + "title": "Implement Protector Start Point" } ], "done": [ diff --git a/Classes/x-saherelm.x121.xtrade.handler.class.mq5 b/Classes/x-saherelm.x121.xtrade.handler.class.mq5 index 6629f4da..ae8cb8f8 100644 --- a/Classes/x-saherelm.x121.xtrade.handler.class.mq5 +++ b/Classes/x-saherelm.x121.xtrade.handler.class.mq5 @@ -53,6 +53,10 @@ struct X121TradeData int pushers; // Signal Pushers string conditions; // Signal Conditions + // + int trailStep; // Trail Step + bool partiallyClosed; // Partially Closed or not + // // Constructor ... void XTradeInfo() @@ -189,6 +193,10 @@ struct X121TradeData commission = 0; maxDrawdown = 0; + // + trailStep = 0; + partiallyClosed = false; + // signal.Clean(); } @@ -1049,7 +1057,7 @@ class X121SCTradeHandler : public XSCBaseAlert // double ProtectorStartDistanceInPoint() { - return mProtectorStartDistanceInPointl + return mProtectorStartDistanceInPoint; } // @@ -1065,6 +1073,116 @@ class X121SCTradeHandler : public XSCBaseAlert mProtectorStartDistanceInPoint = value; } + // + int DelayBarBetweenTwoSameSignal() + { + return mDelayBarBetweenTwoSameSignal; + } + + // + void DelayBarBetweenTwoSameSignal(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mDelayBarBetweenTwoSameSignal = value; + } + + // + // In Profit Position Protecting ... + + // + bool AllowTrailStopInProfits() + { + return mAllowTrailStopInProfits; + } + + // + void AllowTrailStopInProfits(bool value) + { + mAllowTrailStopInProfits = value; + } + + // + double TrailStopStepsInPoint() + { + return mTrailStopStepsInPoint; + } + + // + void TrailStopStepsInPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mTrailStopStepsInPoint = value; + } + + // + int RmoveTPOnTrailStep() + { + return mRmoveTPOnTrailStep; + } + + // + void RmoveTPOnTrailStep(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mRmoveTPOnTrailStep = value; + } + + // + double PartialCloseOnSpecificPoint() + { + return mPartialCloseOnSpecificPoint; + } + + // + void PartialCloseOnSpecificPoint(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPartialCloseOnSpecificPoint = value; + } + + // + double PartialCloseVolume() + { + return mPartialCloseVolume; + } + + // + void PartialCloseVolume(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + mPartialCloseVolume = value; + } + // // Hedge Props ... @@ -1776,6 +1894,50 @@ class X121SCTradeHandler : public XSCBaseAlert state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } + + // + // Check Position Delays ... + if (result && mDelayBarBetweenTwoSameSignal > 0) + { + // + int youngestAge = 0; + XPosition youngestPosition; + + // + // Long Positions when there are Longs ... + if (isLong && longsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + longs // + ); + } + // + // Short Positions when there are Shorts ... + else if (!isLong && shortsCount > 0) + { + // + youngestAge = GetYoungest( + youngestPosition, + shorts // + ); + } + + // + // Only Check when there is must to check and conditions happens ... + if (youngestAge > 0 && youngestPosition.IsValid()) + { + // + result = youngestAge >= mDelayBarBetweenTwoSameSignal; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + } + } } // @@ -1886,7 +2048,7 @@ class X121SCTradeHandler : public XSCBaseAlert { // // Check Position is Protectable or not ... - XPosition iProtected = pPositions[i]; + XProtectedPosition iProtected = pPositions[i]; // XPosition iPosition = iProtected.main; @@ -2138,7 +2300,380 @@ class X121SCTradeHandler : public XSCBaseAlert bool result = false; // - // Here we Make Sure this Position has ... + // Find Position's Item Data ... + int iDX = -1; + result = HasItem( + position.ticket, + iDX // + ); + if (!result) + { + return result; + } + + // + // Here we Make Sure this Position has reached Proper distance ... + + // + bool isLong = IsLong(position.type); + bool isInProfit = position.profit > 0; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + // Last Bar ... + XOHCL cBar; + result = cBar.Init( + position.symbol, + position.period, + cIndex // + ); + if (!result) + { + return result; + } + + // + // Previous Bar of Last Bar ... + XOHCL pBar; + result = cBar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Last Swing Low Bar ... + XOHCL lastSwingLow; + result = cBar.FindLastSwingLow(lastSwingLow); + if (!result) + { + return result; + } + + // + // Last Swing High Bar ... + XOHCL lastSwingHigh; + result = cBar.FindLastSwingHigh(lastSwingHigh); + if (!result) + { + return result; + } + + // + // Common Conditions For Bullish and Bearish Powers ... + + // + // For Trend ... + XOHCL tmpHSW[]; + XOHCL tmpLSW[]; + + // + // Detect Bullish/Bearish Patterns and Trends ... + + // + // Bullish ... + bool hasBullishPower = cBar.HasBullishPower(); + bool hasBullishPattern = HasBullishPattern(cBar); + bool hasBullishPressure = cBar.HasBullishPressure(); + bool isBullishTrend = cBar.HasBullishTrend( + tmpHSW, + tmpLSW, + true // + ); + bool isBullishTrend1 = cBar.HasBullishTrend( + tmpHSW, + tmpLSW, + false // + ); + + // + // Bearish ... + bool hasBearishPower = cBar.HasBearishPower(); + bool hasBearishPattern = HasBearishPattern(cBar); + bool hasBearishPressure = cBar.HasBearishPressure(); + bool isBearishTrend = cBar.HasBearishTrend( + tmpHSW, + tmpLSW, + true // + ); + bool isBearishTrend1 = cBar.HasBearishTrend( + tmpHSW, + tmpLSW, + false // + ); + + // + // Define Conditions ... + MqlTick ticks[]; + int ticksCount = CopyTicks( + position.symbol, + ticks, + COPY_TICKS_ALL, + 0, + 5 // + ); + + // + // TODO: Check Volume if Required ... + + // + bool isTicksBullish = + ( + // + ticks[0].last > ticks[1].last && + ticks[1].last > ticks[2].last && + ticks[2].last > ticks[3].last && + ticks[3].last > ticks[4].last + // + ); + + // + bool isTicksBearish = + ( + // + ticks[0].last < ticks[1].last && + ticks[1].last < ticks[2].last && + ticks[2].last < ticks[3].last && + ticks[3].last < ticks[4].last + // + ); + + // + bool hasBearishDecision = + // + cBar.IsBearishDecision() + // + || + // + pBar.IsBearishDecision() + // + ; + + // + bool hasBullishDecision = + // + cBar.IsBullishDecision() + // + || + // + pBar.IsBullishDecision() + // + ; + + // + bool hasBullishConditions = + // + isTicksBullish && + (isBullishTrend || + isBullishTrend1) && + (hasBullishPower || + hasBullishPattern || + hasBullishPressure) + // + ; + + // + bool hasBearishConditions = + // + isTicksBearish && + (isBearishTrend || + isBearishTrend1) && + (hasBearishPower || + hasBearishPattern || + hasBearishPressure) + // + ; + + // + // In Profit ... + // When a Position running in Profit, we have to look pressures by Same Direction + // of Main Position. for eaxmple if it is long, we look for Bullish Pressures and + // if it is short we look for Bearish Pressures. + // when pressure happens we must Trail position Stop ... + if (isInProfit) + { + // + // Do In Profit Protection Mechanism ... + + // + // - [] Partial Close; + // - [] Specified Point of Profits; + + // + // Trail Stops ... + // Remove Trailed Positions TP ... + bool allowTrailStop = AllowTrailStopInProfits(); + double trailStep = TrailStopStepsInPoint(); + if (allowTrailStop && trailStep > 0) + { + // + // Temp Vaiables ... + bool canTrailStop = false; + + // + if (isLong) + { + // + // Check Conditions ... + canTrailStop = isTicksBullish && + (hasBullishDecision || + hasBullishConditions); + } + else + { + // + // Check Conditions ... + canTrailStop = isTicksBearish && + (hasBearishDecision || + hasBearishConditions); + } + + // + // Do Stop Trailling ... + if (canTrailStop) + { + // + int lastTrailedStep = mData[iDX].trailStep; + + // + double entry = position.entry; + double pointValue = position.GetPointsValue(); + double profitInPoint = position.GetProfitInPoint(); + + // + double requiredProfit = + lastTrailedStep == 0 + ? ProtectorStartDistanceInPoint() + : lastTrailedStep * trailStep; + + // + bool isProfitsPassed = profitInPoint > requiredProfit; + if (isProfitsPassed) + { + // + double delta = (requiredProfit * pointValue); + + // + double sl = + isLong + ? entry + delta + : entry - delta; + + // + string comment = "EQM Trail Stop ..."; + + // + // Try to Modify Position ... + result = mTrader.Modify( + position.ticket, + sl, + position.tp, + comment // + ); + if (result) + { + // + mData[iDX].trailStep++; + + // + string message = "EQM Trail (" + ToString(position.ticket) + ") Stop ..."; + Alert(message); + + // + XPosition trailedPosition; + bool hasPosition = mTrader.GetPosition( + position.ticket, + trailedPosition // + ); + + // + // Check Remove Trailed Positions TP Conditions ... + int removeTPOnTrailStep = RmoveTPOnTrailStep(); + if (removeTPOnTrailStep > 0 && mData[iDX].trailStep == removeTPOnTrailStep && trailedPosition.tp != 0) + { + // + string comment = "EQM Removes TP ..."; + + // + // Remove Position's TP ... + result = mTrader.Modify( + trailedPosition.ticket, + trailedPosition.sl, + 0, + comment // + ); + if (result) + { + // + string message = "EQM Removes (" + ToString(trailedPosition.ticket) + ") TP ..."; + Alert(message); + } + } + } + } + } + + // + if (result) + { + return result; + } + } + + // + // Check Points of Profit and Do Partial Closing ... + double partialCloseVolume = PartialCloseVolume(); + double partialCloseProfitPoint = PartialCloseOnSpecificPoint(); + if (partialCloseVolume > 0 && partialCloseProfitPoint > 0) + { + // + double profitPoints = position.GetProfitInPoint(); + if (profitPoints >= partialCloseProfitPoint && !mData[iDX].partiallyClosed) + { + // + string comment = "EQM Partial Close ..."; + + // + // Do Partial Closing ... + result = mTrader.ClosePartial( + position.ticket, + partialCloseVolume, + comment // + ); + if (result) + { + // + mData[iDX].partiallyClosed = true; + + // + string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ")"; + Alert(message); + } + } + } + } + // + // In Drawdown ... + // When a Position running in Drawdown, we have to look for pressures by Indirection + // of Main Position. for example if it is long, we Look For Bearish Pressures and if + // it is short we Look for Bullish Pressure. + // when indirectional pressure found we must Open a Recovery Position. + // also if Same Direction Pressure Found we try to Recover Same Direction using Grid ... + else + { + // + if (isLong) + { + } + else + { + } + } // return result; @@ -2171,8 +2706,17 @@ class X121SCTradeHandler : public XSCBaseAlert double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades // + int mDelayBarBetweenTwoSameSignal; // Delay Bars Between Two Same Type Signal double mProtectorStartDistanceInPoint; // Protector Start Distance in Point + // + // In Profit Positions Protecting ... + bool mAllowTrailStopInProfits; // Allow Trail Stops for In Profit Positions + double mTrailStopStepsInPoint; // Trail Stop Steps in Point + int mRmoveTPOnTrailStep; // Remove Position TP if Trailed specific times + double mPartialCloseOnSpecificPoint; // Partial Close Position on Specific Points of Profit + double mPartialCloseVolume; // Partial Close Volume + // // Hedging Properties ... bool mAllowHedge; // Allow Protector to Hedge Positions diff --git a/Experts/x-saherelm.x121.ea.mq5 b/Experts/x-saherelm.x121.ea.mq5 index fda73c05..2f5c2321 100644 --- a/Experts/x-saherelm.x121.ea.mq5 +++ b/Experts/x-saherelm.x121.ea.mq5 @@ -443,6 +443,7 @@ bool InitialEA() // TODO: Configure it using Inputs ... // + eaTradeHandler.DelayBarBetweenTwoSameSignal(5); eaTradeHandler.ProtectorStartDistanceInPoint(35); // diff --git a/Libraries/x-saherelm.xtrade.lib.mq5 b/Libraries/x-saherelm.xtrade.lib.mq5 index d6708c1e..1f2d9d17 100644 --- a/Libraries/x-saherelm.xtrade.lib.mq5 +++ b/Libraries/x-saherelm.xtrade.lib.mq5 @@ -21,9 +21,9 @@ // // Imports ... -#include -#include "../Libraries/x-saherelm.draw.lib.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include // // Definitions ... @@ -130,14 +130,15 @@ enum ENUM_X_POSITION_SELECT_METHODS enum ENUM_X_SIGNAL_EXECUTION_RESULT { // - X_SIGNAL_EXECUTION_UNKNOWN, // Unknown - X_SIGNAL_EXECUTION_SUCCEED, // Succed - X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed - X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type - X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade - X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error - X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached - X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params + X_SIGNAL_EXECUTION_UNKNOWN, // Unknown + X_SIGNAL_EXECUTION_SUCCEED, // Succed + X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed + X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type + X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade + X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error + X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached + X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED, // Same Positions Delay Not Passed + X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params }; // @@ -546,6 +547,47 @@ struct XPosition return result; } + // + double GetPointsValue() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetPoints(symbol); + + // + return result; + } + + // + double GetProfitInPoint() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + double point = GetPoints(symbol); + + // + result = profit / point; + + // + return result; + } + // // Find Reward ... double GetReward()