From 1da3496ce96ced5de04593aee1623da005be1871 Mon Sep 17 00:00:00 2001 From: EarnForex <48102957+EarnForex@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:55:35 +0200 Subject: [PATCH] 1.01 1. Added an MT5 version of the script. 2. Added an option to apply stop-loss and take-profit based on the current price rather than open price. 3. Added an option to work with pending orders as well. 4. Added an option to set SL and TP not only for the current trading symbol. 5. Added an option to skip either SL or TP by setting the respective input parameter to zero. 6. Added a filter based on trade's direction. 7. Changed the script to work based on points rather than pips. 8. Removed the Slippage input parameter (wasn't used). 9. Refactored the MQL4 code. --- MQL4/Files/EF-Icon-64x64px.ico | Bin 0 -> 2686 bytes MQL4/Scripts/SetFixedSLandTP.mq4 | 160 +++++++++++++++++++ MQL5/Files/EF-Icon-64x64px.ico | Bin 0 -> 2686 bytes MQL5/Scripts/SetFixedSLandTP.mq5 | 255 +++++++++++++++++++++++++++++++ 4 files changed, 415 insertions(+) create mode 100644 MQL4/Files/EF-Icon-64x64px.ico create mode 100644 MQL4/Scripts/SetFixedSLandTP.mq4 create mode 100644 MQL5/Files/EF-Icon-64x64px.ico create mode 100644 MQL5/Scripts/SetFixedSLandTP.mq5 diff --git a/MQL4/Files/EF-Icon-64x64px.ico b/MQL4/Files/EF-Icon-64x64px.ico new file mode 100644 index 0000000000000000000000000000000000000000..07237533063096da1cc8f2d43dbe4fbfd0f431d1 GIT binary patch literal 2686 zcmZQzU<5)32LT|-!jQqmz#zuJz@P!d4nW)h#2|58z^Ryl!Q^ljF6mM6Aru0FSOBu~ zu}BM!$|FL6((pl;#J~VE3t0@AJt_|g0pu`2W|J2_FkJ{5*-S*NjLO48fV$y>Fb%u; Tqw=s281CT%^XDi%yh8v0Xl5}> literal 0 HcmV?d00001 diff --git a/MQL4/Scripts/SetFixedSLandTP.mq4 b/MQL4/Scripts/SetFixedSLandTP.mq4 new file mode 100644 index 0000000..561d68e --- /dev/null +++ b/MQL4/Scripts/SetFixedSLandTP.mq4 @@ -0,0 +1,160 @@ +#property link "https://www.earnforex.com/metatrader-scripts/set-fixed-sl-tp/" +#property version "1.01" +#property strict +#property copyright "EarnForex.com - 2023" +#property description "This script sets a stop-loss and, if required a take-profit, to all open orders based on filters." +#property description "SL and TP values are in POINTS (not pips)." +#property description "" +#property description "DISCLAIMER: This script comes with no guarantee. Use it at your own risk." +#property description "It is best to test it on a demo account first." +#property icon "\\Files\\EF-Icon-64x64px.ico" +#property show_inputs + +enum ENUM_PRICE_TYPE +{ + ENUM_PRICE_TYPE_OPEN, // Trade's open price + ENUM_PRICE_TYPE_CURRENT // Current price +}; + +enum ENUM_ORDER_TYPES +{ + ALL_ORDERS = 1, // ALL TRADES + ONLY_BUY = 2, // BUY ONLY + ONLY_SELL = 3 // SELL ONLY +}; + +input int StopLoss = 200; // Stop-Loss in points +input int TakeProfit = 400; // Take-Profit in points +input bool CurrentSymbolOnly = true; // Current symbol only? +input ENUM_ORDER_TYPES OrderTypeFilter = ALL_ORDERS; // Type of trades to apply to +input bool OnlyMagicNumber = false; // Modify only trades matching the magic number +input int MagicNumber = 0; // Matching magic number +input bool OnlyWithComment = false; // Modify only trades with the following comment +input string MatchingComment = ""; // Matching comment +input int Delay = 0; // Delay to wait between modifying trades (in milliseconds) +input ENUM_PRICE_TYPE PriceType = ENUM_PRICE_TYPE_OPEN; // Price to use for SL/TP setting +input bool ApplyToPending = false; // Apply to pending orders too? + +void OnStart() +{ + if (!TerminalInfoInteger(TERMINAL_CONNECTED)) + { + Print("Not connected to the trading server. Exiting."); + return; + } + + if ((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) || (!MQLInfoInteger(MQL_TRADE_ALLOWED))) + { + Print("Autotrading is disable. Please enable. Exiting."); + return; + } + + if ((StopLoss == 0) && (TakeProfit == 0)) + { + Print("Both StopLoss and TakeProfit are set to zero. Exiting."); + return; + } + + int TotalModified = 0; + + // Scan the orders backwards: + for (int i = OrdersTotal() - 1; i >= 0; i--) + { + // Select the order. If not selected print the error and continue with the next index. + if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) + { + Print("ERROR - Unable to select the order - ", GetLastError()); + continue; + } + + // Check if the order can be modified matching the criteria. If criteria not matched skip to the next. + if ((CurrentSymbolOnly) && (OrderSymbol() != Symbol())) continue; + if ((OnlyMagicNumber) && (OrderMagicNumber() != MagicNumber)) continue; + if ((OnlyWithComment) && (StringCompare(OrderComment(), MatchingComment) != 0)) continue; + if ((!ApplyToPending) && (OrderType() != OP_BUY) && (OrderType() != OP_SELL)) continue; + if ((OrderTypeFilter == ONLY_SELL) && ((OrderType() == OP_BUY) || (OrderType() == OP_BUYLIMIT) || (OrderType() == OP_BUYSTOP))) continue; + if ((OrderTypeFilter == ONLY_BUY) && ((OrderType() == OP_SELL) || (OrderType() == OP_SELLLIMIT) || (OrderType() == OP_SELLSTOP))) continue; + + // Prepare everything. + string symbol = OrderSymbol(); + double TakeProfitPrice = 0; + double StopLossPrice = 0; + double Price; + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + + if (SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) + { + Print("Trading is disabled for ", symbol, ". Skipping."); + continue; + } + + double tick_size = MarketInfo(OrderSymbol(), MODE_TICKSIZE); + if (tick_size == 0) + { + Print("Zero tick size for ", symbol, ". Skipping."); + continue; + } + + if ((OrderType() == OP_BUY) || (OrderType() == OP_BUYLIMIT) || (OrderType() == OP_BUYSTOP)) + { + if (PriceType == ENUM_PRICE_TYPE_CURRENT) + { + RefreshRates(); + // Should be Bid for Buy orders: + Price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else Price = OrderOpenPrice(); + if (TakeProfit > 0) + { + TakeProfitPrice = NormalizeDouble(Price + TakeProfit * point, digits); + TakeProfitPrice = NormalizeDouble(MathRound(TakeProfitPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else TakeProfitPrice = OrderTakeProfit(); + if (StopLoss > 0) + { + StopLossPrice = NormalizeDouble(Price - StopLoss * point, digits); + StopLossPrice = NormalizeDouble(MathRound(StopLossPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else StopLossPrice = OrderStopLoss(); + } + else if ((OrderType() == OP_SELL) || (OrderType() == OP_SELLLIMIT) || (OrderType() == OP_SELLSTOP)) + { + if (PriceType == ENUM_PRICE_TYPE_CURRENT) + { + RefreshRates(); + // Should be Ask for Sell orders: + Price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + else Price = OrderOpenPrice(); + if (TakeProfit > 0) + { + TakeProfitPrice = NormalizeDouble(Price - TakeProfit * point, digits); + TakeProfitPrice = NormalizeDouble(MathRound(TakeProfitPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else TakeProfitPrice = OrderTakeProfit(); + if (StopLoss > 0) + { + StopLossPrice = NormalizeDouble(Price + StopLoss * point, digits); + StopLossPrice = NormalizeDouble(MathRound(StopLossPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else StopLossPrice = OrderStopLoss(); + } + + // Try to modify the order: + if (OrderModify(OrderTicket(), OrderOpenPrice(), StopLossPrice, TakeProfitPrice, OrderExpiration())) + { + TotalModified++; + } + else + { + Print("Order failed to update with error - ", GetLastError()); + } + + // Wait if necessary. + Sleep(Delay); + } + + Print("Total orders modified = ", TotalModified); +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/MQL5/Files/EF-Icon-64x64px.ico b/MQL5/Files/EF-Icon-64x64px.ico new file mode 100644 index 0000000000000000000000000000000000000000..07237533063096da1cc8f2d43dbe4fbfd0f431d1 GIT binary patch literal 2686 zcmZQzU<5)32LT|-!jQqmz#zuJz@P!d4nW)h#2|58z^Ryl!Q^ljF6mM6Aru0FSOBu~ zu}BM!$|FL6((pl;#J~VE3t0@AJt_|g0pu`2W|J2_FkJ{5*-S*NjLO48fV$y>Fb%u; Tqw=s281CT%^XDi%yh8v0Xl5}> literal 0 HcmV?d00001 diff --git a/MQL5/Scripts/SetFixedSLandTP.mq5 b/MQL5/Scripts/SetFixedSLandTP.mq5 new file mode 100644 index 0000000..0918543 --- /dev/null +++ b/MQL5/Scripts/SetFixedSLandTP.mq5 @@ -0,0 +1,255 @@ +#property link "https://www.earnforex.com/metatrader-scripts/set-fixed-sl-tp/" +#property version "1.01" +#property strict +#property copyright "EarnForex.com - 2023" +#property description "This script sets a stop-loss and, if required a take-profit, to all open trades based on filters." +#property description "SL and TP values are in POINTS (not pips)." +#property description "" +#property description "DISCLAIMER: This script comes with no guarantee. Use it at your own risk." +#property description "It is best to test it on a demo account first." +#property icon "\\Files\\EF-Icon-64x64px.ico" +#property script_show_inputs + +#include + +enum ENUM_PRICE_TYPE +{ + ENUM_PRICE_TYPE_OPEN, // Trade's open price + ENUM_PRICE_TYPE_CURRENT // Current price +}; + +enum ENUM_ORDER_TYPES +{ + ALL_ORDERS = 1, // ALL TRADES + ONLY_BUY = 2, // BUY ONLY + ONLY_SELL = 3 // SELL ONLY +}; + +input int StopLoss = 200; // Stop-Loss in points +input int TakeProfit = 400; // Take-Profit in points +input bool CurrentSymbolOnly = true; // Current symbol only? +input ENUM_ORDER_TYPES OrderTypeFilter = ALL_ORDERS; // Type of trades to apply to +input bool OnlyMagicNumber = false; // Modify only orders matching the magic number +input int MagicNumber = 0; // Matching magic number +input bool OnlyWithComment = false; // Modify only trades with the following comment +input string MatchingComment = ""; // Matching comment +input int Delay = 0; // Delay to wait between modifying trades (in milliseconds) +input ENUM_PRICE_TYPE PriceType = ENUM_PRICE_TYPE_OPEN; // Price to use for SL/TP setting +input bool ApplyToPending = false; // Apply to pending orders too? + +void OnStart() +{ + if (!TerminalInfoInteger(TERMINAL_CONNECTED)) + { + Print("Not connected to the trading server. Exiting."); + return; + } + + if ((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) || (!MQLInfoInteger(MQL_TRADE_ALLOWED))) + { + Print("Autotrading is disable. Please enable. Exiting."); + return; + } + + if ((StopLoss == 0) && (TakeProfit == 0)) + { + Print("Both StopLoss and TakeProfit are set to zero. Exiting."); + return; + } + + int TotalModifiedPositions = 0; + int TotalModifiedOrders = 0; + CTrade *Trade; + Trade = new CTrade; + + int positions_total = PositionsTotal(); + for (int i = positions_total - 1; i >= 0; i--) // Going backwards in case one or more positions are closed during the cycle. + { + ulong ticket = PositionGetTicket(i); + if (ticket <= 0) + { + Print("ERROR - Unable to select the position - ", GetLastError()); + continue; + } + + // Check if the position matches the filter and if not, skip the position and move to the next one. + if ((OrderTypeFilter == ONLY_SELL) && (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)) continue; + if ((OrderTypeFilter == ONLY_BUY) && (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)) continue; + if ((CurrentSymbolOnly) && (PositionGetString(POSITION_SYMBOL) != Symbol())) continue; + if ((OnlyMagicNumber) && (PositionGetInteger(POSITION_MAGIC) != MagicNumber)) continue; + if ((OnlyWithComment) && (StringCompare(PositionGetString(POSITION_COMMENT), MatchingComment) != 0)) continue; + + string symbol = PositionGetString(POSITION_SYMBOL); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + if (SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) + { + Print("Trading is disabled for ", symbol, ". Skipping."); + continue; + } + + double Price; + double TakeProfitPrice = 0; + double StopLossPrice = 0; + int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + if (tick_size == 0) + { + Print("Zero tick size for ", symbol, ". Skipping."); + continue; + } + + if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + if (PriceType == ENUM_PRICE_TYPE_CURRENT) + { + // Should be Bid for Buy orders: + Price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else Price = PositionGetDouble(POSITION_PRICE_OPEN); + + if (TakeProfit > 0) + { + TakeProfitPrice = NormalizeDouble(Price + TakeProfit * point, digits); + TakeProfitPrice = NormalizeDouble(MathRound(TakeProfitPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else TakeProfitPrice = PositionGetDouble(POSITION_TP); + if (StopLoss > 0) + { + StopLossPrice = NormalizeDouble(Price - StopLoss * point, digits); + StopLossPrice = NormalizeDouble(MathRound(StopLossPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else StopLossPrice = PositionGetDouble(POSITION_SL); + } + else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) + { + if (PriceType == ENUM_PRICE_TYPE_CURRENT) + { + // Should be Ask for Sell orders: + Price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + else Price = PositionGetDouble(POSITION_PRICE_OPEN); + + if (TakeProfit > 0) + { + TakeProfitPrice = NormalizeDouble(Price - TakeProfit * point, digits); + TakeProfitPrice = NormalizeDouble(MathRound(TakeProfitPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else TakeProfitPrice = PositionGetDouble(POSITION_TP); + if (StopLoss > 0) + { + StopLossPrice = NormalizeDouble(Price + StopLoss * point, digits); + StopLossPrice = NormalizeDouble(MathRound(StopLossPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else StopLossPrice = PositionGetDouble(POSITION_SL); + } + + // Write BE price to the SL field. + if (!Trade.PositionModify(ticket, StopLossPrice, TakeProfitPrice)) + Print("PositionModify failed ", GetLastError(), " for ", symbol, ", position #", ticket); + else + { + TotalModifiedPositions++; + } + } + Print("Total positions modified = ", TotalModifiedPositions); + + if (ApplyToPending) + { + int orders_total = OrdersTotal(); + for (int i = orders_total - 1; i >= 0; i--) // Going backwards in case one or more orders are deleted during the cycle. + { + ulong ticket = OrderGetTicket(i); + if (ticket <= 0) + { + Print("ERROR - Unable to select the position - ", GetLastError()); + continue; + } + + // Check if the position matches the filter and if not, skip the position and move to the next one. + if ((OrderTypeFilter == ONLY_SELL) && (OrderGetInteger(ORDER_TYPE) != ORDER_TYPE_SELL_STOP) && (OrderGetInteger(ORDER_TYPE) != ORDER_TYPE_SELL_LIMIT) && (OrderGetInteger(ORDER_TYPE) != ORDER_TYPE_SELL_STOP_LIMIT)) continue; + if ((OrderTypeFilter == ONLY_BUY) && (OrderGetInteger(ORDER_TYPE) != ORDER_TYPE_BUY_STOP) && (OrderGetInteger(ORDER_TYPE) != ORDER_TYPE_BUY_LIMIT) && (OrderGetInteger(ORDER_TYPE) != ORDER_TYPE_BUY_STOP_LIMIT)) continue; + if ((CurrentSymbolOnly) && (OrderGetString(ORDER_SYMBOL) != Symbol())) continue; + if ((OnlyMagicNumber) && (OrderGetInteger(ORDER_MAGIC) != MagicNumber)) continue; + if ((OnlyWithComment) && (StringCompare(OrderGetString(ORDER_COMMENT), MatchingComment) != 0)) continue; + + string symbol = OrderGetString(ORDER_SYMBOL); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + if (SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) + { + Print("Trading is disabled for ", symbol, ". Skipping."); + continue; + } + + double Price; + double TakeProfitPrice = 0; + double StopLossPrice = 0; + int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + if (tick_size == 0) + { + Print("Zero tick size for ", symbol, ". Skipping."); + continue; + } + + if ((OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) || (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT) || (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP_LIMIT)) + { + if (PriceType == ENUM_PRICE_TYPE_CURRENT) + { + // Should be Bid for Buy orders: + Price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else Price = OrderGetDouble(ORDER_PRICE_OPEN); + + if (TakeProfit > 0) + { + TakeProfitPrice = NormalizeDouble(Price + TakeProfit * point, digits); + TakeProfitPrice = NormalizeDouble(MathRound(TakeProfitPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else TakeProfitPrice = PositionGetDouble(POSITION_TP); + if (StopLoss > 0) + { + StopLossPrice = NormalizeDouble(Price - StopLoss * point, digits); + StopLossPrice = NormalizeDouble(MathRound(StopLossPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else StopLossPrice = PositionGetDouble(POSITION_SL); + } + else if ((OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) || (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT) || (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP_LIMIT)) + { + if (PriceType == ENUM_PRICE_TYPE_CURRENT) + { + // Should be Ask for Sell orders: + Price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + else Price = OrderGetDouble(ORDER_PRICE_OPEN); + + if (TakeProfit > 0) + { + TakeProfitPrice = NormalizeDouble(Price - TakeProfit * point, digits); + TakeProfitPrice = NormalizeDouble(MathRound(TakeProfitPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else TakeProfitPrice = PositionGetDouble(POSITION_TP); + if (StopLoss > 0) + { + StopLossPrice = NormalizeDouble(Price + StopLoss * point, digits); + StopLossPrice = NormalizeDouble(MathRound(StopLossPrice / tick_size) * tick_size, digits); // Adjusting for tick size granularity. + } + else StopLossPrice = PositionGetDouble(POSITION_SL); + } + + // Write BE price to the SL field. + + if (!Trade.OrderModify(ticket, OrderGetDouble(ORDER_PRICE_OPEN), StopLossPrice, TakeProfitPrice, (ENUM_ORDER_TYPE_TIME)OrderGetInteger(ORDER_TYPE_TIME), OrderGetInteger(ORDER_TIME_EXPIRATION))) + Print("OrderModify failed ", GetLastError(), " for ", symbol, ", order #", ticket); + else + { + TotalModifiedOrders++; + } + } + Print("Total orders modified = ", TotalModifiedOrders); + } + + delete Trade; +} +//+------------------------------------------------------------------+ \ No newline at end of file