//+------------------------------------------------------------------+ //| ADR_BASED_TRADE_PANEL.mq4 | //| | //+------------------------------------------------------------------+ #property copyright "ADR BASED TRADE PANEL WITH BASKET" #property link "" #property version "2.84" #property strict //--- Input Parameters //--- Diagnostics input bool ShowDiagnostics = false; // Show diagnostic messages in log //--- Panel Display Settings input string panel_sep1 = "==============================================="; input string panel_title = "==== Panel Display Settings ===="; input string panel_sep2 = "==============================================="; input int Panel_X = 20; // Panel X position input int Panel_Y = 50; // Panel Y position input color Panel_BgColor = clrNavy; // Panel background color input color Button_Color = clrGreen; // Button color //--- ADR and Trading Settings input string adr_sep1 = "==============================================="; input string adr_title = "==== ADR and Trading Settings ===="; input string adr_sep2 = "==============================================="; input int ADR_Period = 20; // Number of days for ADR calculation input double SL_Percent = 200.0; // Stop Loss as % of ADR input double TP_Percent = 100.0; // Take Profit as % of ADR //--- Stop Loss Type and Order Management input string order_sep1 = "==============================================="; input string order_title = "==== Stop Loss Type & Order Management ===="; input string order_sep2 = "==============================================="; enum ENUM_SL_TYPE { SL_TYPE_NORMAL = 1, SL_TYPE_STOP_ORDER = 2, SL_TYPE_AUTO_HEDGE = 3, SL_TYPE_NONE = 4 }; input ENUM_SL_TYPE Stop_Loss_Type = SL_TYPE_AUTO_HEDGE; // 1=SL, 2=Stop Order, 3=Auto Hedge, 4=No SL input double AutoHedge_SL_Pips = 20; // Auto Hedge SL distance (pips) - only for Type 3 input int Magic_Number = 12345; // Magic number for panel orders input bool Manage_Only_Panel_Orders = false; // Manage only panel's own trades input bool Close_Trades_By_Order_CloseBy = false; // Use OrderCloseBy for CLOSE ALL //--- Risk-Based Lot Calculation input string risk_sep1 = "==============================================="; input string risk_title = "==== Risk-Based Lot Calculation ===="; input string risk_sep2 = "==============================================="; input double Trade0Lot = 0.01; // Fixed lot size (if RiskPercent = 0) input double Trade0RiskPercent = 1.0; // Risk % per trade (0 = use fixed lot) input bool Trade0UseBalance = false; // Use account balance for calculation input bool Trade0UseEquity = true; // Use account equity for calculation //--- Trailing Stop & Breakeven Settings input string trail_sep1 = "==============================================="; input string trail_title = "==== Trailing Stop & Breakeven ===="; input string trail_sep2 = "==============================================="; enum ENUM_TRAIL_METHOD { TRAIL_METHOD_A = 0, TRAIL_METHOD_B = 1, TRAIL_METHOD_C = 2 }; input bool UseJumpingTrail = true; // Enable trailing stop input int Distance_to_BE = 50; // Distance to breakeven (pips) input int BE_Min_Pips = 2; // Breakeven cushion (pips) input ENUM_TRAIL_METHOD Trail_Method = TRAIL_METHOD_B; // Trail method (A=Fixed, B=Swing, C=ADR%) input int TrailStartPips = 60; // Start trailing at profit (pips) input int TrailJumpPips = 15; // Trail distance for Method A (pips) input int Swing_Lookback = 10; // Swing lookback for Method B (bars) input int Trail_Buffer_Pips = 5; // Trail buffer for Method B (pips) input int ADR_H1_Period = 20; // ADR H1 period for Method C input double ADR_H1_TrailPct = 50.0; // Trail as % of ADR H1 for Method C //--- Symbol Basket Trading 5 Settings input string bas5_sep1 = "==============================================="; input string bas5_title = "==== Symbol Basket Trading 5 ===="; input string bas5_sep2 = "==============================================="; input bool SymbolTradesBelongToBasket5 = false; // Enable basket trading input bool BasketClosesByOrderCloseBy5 = true; // Use OrderCloseBy for basket closure input string bas5_sep3 = "--- Partial Close Percentages ---"; input double Percentage5OfTrade1ToClose = 25; // % of trade 1 to close input double Percentage5OfTrade2ToClose = 50; // % of trade 2 to close input double Percentage5OfTrade3ToClose = 50; // % of trade 3 to close input double Percentage5OfTrade4ToClose = 50; // % of trade 4 to close input double Percentage5OfTrade5ToClose = 50; // % of trade 5 to close input double Percentage5OfTrade6ToClose = 50; // % of trade 6 to close input double Percentage5OfTrade7ToClose = 50; // % of trade 7 to close input double Percentage5OfTrade8ToClose = 50; // % of trade 8 to close input double Percentage5OfTrade9ToClose = 50; // % of trade 9 to close input double Percentage5OfTrade10ToClose = 50; // % of trade 10 to close input double Percentage5OfTrade11ToClose = 50; // % of trade 11 to close input double Percentage5OfTrade12ToClose = 50; // % of trade 12 to close input string bas5_sep4 = "--- Basket Criteria ---"; input int SymbolMinTradesOpenForBasket5 = 11; // Min trades for basket input int SymbolMaxTradesOpenForBasket5 = 100; // Max trades for basket input string bas5_sep5 = "--- Basket Targets ---"; input double SymbolBasketCashTakeProfit5 = 2; // Fixed cash target ($) input double BasketProfitPercentTarget5 = 1.0; // Positive Profit Target (% of Equity) input double BasketLossPercentTarget5 = -0.1; // Negative Profit Target (% of Equity) input bool SymbolTargetOnPips5 = false; // Use pips target instead input int SymbolBasketPips5 = 10; // Pips target input bool Use_Swap_in_TP5 = true; // Include swap in profit calc //--- Global Variables datetime lastCheckTime = 0; int checkIntervalSeconds = 600; // 10 minutes = 600 seconds datetime lastH1BarTime = 0; double cachedADR_H1_Pips = 0; int magic_shift = 0; // For auto-hedging mode // Current panel position (can be modified) int CurrentPanelX = 0; int CurrentPanelY = 0; // Magic number system for linking market orders to stop orders // Stop order comment format: "Stop:#12345" where 12345 is parent ticket //--- Panel Objects string panelName = "ADR_Panel"; string buttonName = "ADR_Button"; string labelName = "ADR_Label"; string adrValueLabel = "ADR_Value_Label"; string spreadLabel = "Spread_Label"; string slValueLabel = "SL_Value_Label"; string tpValueLabel = "TP_Value_Label"; string lotSizeLabel = "LotSize_Label"; string netPosLabel = "NetPos_Label"; string magicLabel = "Magic_Label"; // NEW: Display magic number //--- Trading Button Names string applySLButton = "ApplySL_Button"; string hedgeAllButton = "HedgeAll_Button"; string buyButton = "Buy_Button"; string sellButton = "Sell_Button"; string buyPendButton = "BuyPend_Button"; string sellPendButton = "SellPend_Button"; string closeBuyButton = "CloseBuy_Button"; string closeSellButton = "CloseSell_Button"; string closeAllButton = "CloseAll_Button"; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("========================================"); Print("=== ADR BASED TRADE PANEL v2.84 ==="); Print("========================================"); Print("ADR Period: ", ADR_Period, " days"); Print("SL Percent: ", SL_Percent, "%"); Print("TP Percent: ", TP_Percent, "%"); Print("Check Interval: Every 10 minutes"); // Display Stop Loss Type string slTypeStr = ""; if(Stop_Loss_Type == SL_TYPE_NORMAL) slTypeStr = "NORMAL SL"; else if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) slTypeStr = "STOP ORDERS"; else if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) slTypeStr = "AUTO HEDGE"; else if(Stop_Loss_Type == SL_TYPE_NONE) slTypeStr = "NO SL"; Print("Stop Loss Type: ", slTypeStr); if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) Print(" Auto Hedge SL Distance: ", AutoHedge_SL_Pips, " pips"); Print("Risk Percent: ", Trade0RiskPercent, "%"); // Trailing stop info Print("Trailing Stop: ", (UseJumpingTrail ? "ENABLED" : "DISABLED")); if(UseJumpingTrail) { Print(" - Distance to BE: ", Distance_to_BE, " pips"); Print(" - BE Cushion: ", BE_Min_Pips, " pips"); Print(" - Trail Start: ", TrailStartPips, " pips"); Print(" - Trail Method: ", (Trail_Method == TRAIL_METHOD_A ? "A (Fixed)" : (Trail_Method == TRAIL_METHOD_B ? "B (Swing)" : "C (ADR H1%)"))); if(Trail_Method == TRAIL_METHOD_A) Print(" Method A: Fixed ", TrailJumpPips, " pips"); else if(Trail_Method == TRAIL_METHOD_B) Print(" Method B: Swing lookback ", Swing_Lookback, " bars, buffer ", Trail_Buffer_Pips, " pips"); else if(Trail_Method == TRAIL_METHOD_C) Print(" Method C: ", ADR_H1_TrailPct, "% of ADR H1 (", ADR_H1_Period, " periods)"); Print(" - Hedged orders: EXCLUDED from trailing"); } // Check OrderCloseBy availability if(Close_Trades_By_Order_CloseBy) { Print("OrderCloseBy enabled for CLOSE ALL button"); Print("NOTE: OrderCloseBy requires hedging account and may not work on all brokers"); Print(" If errors occur, set Close_Trades_By_Order_CloseBy = false"); } Print("========================================"); Print("V2.84: Added 4-option Stop Loss Type"); Print(" - Option 1: Normal SL"); Print(" - Option 2: Stop Orders"); Print(" - Option 3: Auto Hedge (with magic_shift)"); Print(" - Option 4: No SL"); Print("========================================"); lastCheckTime = TimeCurrent(); // Initialize magic_shift for auto-hedging magic_shift = (int)GlobalVariableGet("ADR_magic_shift"); // Initialize global variables for panel position if(!GlobalVariableCheck("ADR_PanelX")) GlobalVariableSet("ADR_PanelX", Panel_X); if(!GlobalVariableCheck("ADR_PanelY")) GlobalVariableSet("ADR_PanelY", Panel_Y); // Load saved position or use input parameters int savedX = (int)GlobalVariableGet("ADR_PanelX"); int savedY = (int)GlobalVariableGet("ADR_PanelY"); CurrentPanelX = (savedX > 0) ? savedX : Panel_X; CurrentPanelY = (savedY > 0) ? savedY : Panel_Y; // Create the panel and buttons CreatePanel(); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("ADR SL/TP Manager EA stopped"); // Remove panel objects DeleteAllPanelObjects(); ChartRedraw(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Manage trailing stops and breakeven if(UseJumpingTrail) ManageTrail(); // Check if 10 minutes have passed if(TimeCurrent() - lastCheckTime >= checkIntervalSeconds) { Print("--- Starting 10-minute check for open orders ---"); ProcessOpenOrders(); lastCheckTime = TimeCurrent(); } // Update panel display UpdatePanelInfo(); // Check symbol basket targets if(SymbolTradesBelongToBasket5) CheckSymbolBasket5(); // Manage stop orders if enabled (Type 2) if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) { ManageStopOrders(); } // Manage auto-hedging if enabled (Type 3) if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) { ManageAutoHedging(); } } //+------------------------------------------------------------------+ //| Manage Auto-Hedging (Type 3) | //+------------------------------------------------------------------+ void ManageAutoHedging() { double point = MarketInfo(Symbol(), MODE_POINT); double pipValue = point; // For 5-digit forex, 1 pip = 10 points if(Digits == 5) pipValue = point * 10; // For 2-digit or 3-digit symbols (gold, JPY), 1 pip = 100 points else if(Digits == 2 || Digits == 3) pipValue = point * 100; // Find the last opened trade (most recent) datetime opentime = 0; int ticket1 = -1; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS)) continue; if(OrderSymbol() != Symbol()) continue; if(OrderType() >= 2) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != (Magic_Number + magic_shift)) continue; if(OrderOpenTime() > opentime) { opentime = OrderOpenTime(); ticket1 = OrderTicket(); } } if(ticket1 < 0) return; // Select the last trade if(!OrderSelect(ticket1, SELECT_BY_TICKET)) return; int orderType = OrderType(); double openPrice = OrderOpenPrice(); double currentPrice = (orderType == OP_BUY) ? Bid : Ask; // Calculate distance in pips int mdir = -2 * orderType + 1; // +1 for buy, -1 for sell double distance = mdir * (currentPrice - openPrice) / pipValue; // If distance reaches negative threshold, hedge if(distance <= -AutoHedge_SL_Pips) { Print("Auto-Hedge triggered for order #", ticket1, " at distance ", DoubleToStr(distance, 1), " pips"); // Remove TP from the order being hedged bool modifyResult = OrderModify(ticket1, openPrice, OrderStopLoss(), 0, 0); if(!modifyResult) Print("Warning: Failed to remove TP from order #", ticket1, " - Error: ", GetLastError()); // Place the hedge order double netPos = GetNetPosition(Symbol()); if(netPos != 0) { int hedgeType = (netPos > 0) ? OP_SELL : OP_BUY; double hedgePrice = (hedgeType == OP_BUY) ? Ask : Bid; double hedgeLots = MathAbs(netPos); int hedgeTicket = OrderSend(Symbol(), hedgeType, hedgeLots, hedgePrice, 3, 0, 0, "Auto-Hedge", Magic_Number + magic_shift, 0, clrOrange); if(hedgeTicket > 0) Print("Auto-Hedge order placed: #", hedgeTicket, " | ", hedgeLots, " lots"); else Print("Failed to place auto-hedge order - Error: ", GetLastError()); } // Increment magic shift magic_shift++; GlobalVariableSet("ADR_magic_shift", magic_shift); Print("Magic shift incremented to: ", magic_shift, " | New magic: ", Magic_Number + magic_shift); } } //+------------------------------------------------------------------+ //| Chart Event function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // Handle drag button movement if(id == CHARTEVENT_OBJECT_DRAG && sparam == "ADR_DragHandle") { // Get new position of drag handle int newX = (int)ObjectGetInteger(0, "ADR_DragHandle", OBJPROP_XDISTANCE); int newY = (int)ObjectGetInteger(0, "ADR_DragHandle", OBJPROP_YDISTANCE); // Calculate panel position (drag handle is at top-right, -18px from right edge, +2px from top) int panelX = newX - 182; // 200 - 18 int panelY = newY - 2; // Save to global variables GlobalVariableSet("ADR_PanelX", panelX); GlobalVariableSet("ADR_PanelY", panelY); // Delete and recreate all panel elements at new position DeleteAllPanelObjects(); CurrentPanelX = panelX; CurrentPanelY = panelY; CreatePanel(); return; } // Check if button was clicked if(id == CHARTEVENT_OBJECT_CLICK) { if(sparam == applySLButton) { Print("APPLY SL or SO button pressed - applying SL/TP to all orders"); ProcessOpenOrders(); ObjectSetInteger(0, applySLButton, OBJPROP_STATE, false); } else if(sparam == hedgeAllButton) { Print("HEDGE ALL button pressed"); HedgeAllTrades(); ObjectSetInteger(0, hedgeAllButton, OBJPROP_STATE, false); } else if(sparam == buyButton) { Print("BUY button pressed"); ExecuteBuyOrder(); ObjectSetInteger(0, buyButton, OBJPROP_STATE, false); } else if(sparam == sellButton) { Print("SELL button pressed"); ExecuteSellOrder(); ObjectSetInteger(0, sellButton, OBJPROP_STATE, false); } else if(sparam == buyPendButton) { Print("BUY PEND button pressed"); ExecuteBuyPendingOrder(); ObjectSetInteger(0, buyPendButton, OBJPROP_STATE, false); } else if(sparam == sellPendButton) { Print("SELL PEND button pressed"); ExecuteSellPendingOrder(); ObjectSetInteger(0, sellPendButton, OBJPROP_STATE, false); } else if(sparam == closeBuyButton) { Print("CLOSE BUY button pressed"); CloseAllBuyTrades(); ObjectSetInteger(0, closeBuyButton, OBJPROP_STATE, false); } else if(sparam == closeSellButton) { Print("CLOSE SELL button pressed"); CloseAllSellTrades(); ObjectSetInteger(0, closeSellButton, OBJPROP_STATE, false); } else if(sparam == closeAllButton) { Print("CLOSE ALL button pressed"); CloseAllTrades(); ObjectSetInteger(0, closeAllButton, OBJPROP_STATE, false); } ChartRedraw(); } } //+------------------------------------------------------------------+ //| Delete All Panel Objects | //+------------------------------------------------------------------+ void DeleteAllPanelObjects() { ObjectDelete(0, panelName); ObjectDelete(0, "ADR_DragHandle"); ObjectDelete(0, labelName); ObjectDelete(0, adrValueLabel); ObjectDelete(0, spreadLabel); ObjectDelete(0, slValueLabel); ObjectDelete(0, tpValueLabel); ObjectDelete(0, lotSizeLabel); ObjectDelete(0, netPosLabel); ObjectDelete(0, magicLabel); ObjectDelete(0, applySLButton); ObjectDelete(0, hedgeAllButton); ObjectDelete(0, buyButton); ObjectDelete(0, sellButton); ObjectDelete(0, buyPendButton); ObjectDelete(0, sellPendButton); ObjectDelete(0, closeBuyButton); ObjectDelete(0, closeSellButton); ObjectDelete(0, closeAllButton); } //+------------------------------------------------------------------+ //| Calculate Lot Size Based on Risk (TF0 Method) | //+------------------------------------------------------------------+ double CalculateLotSize(string symbol, double slPips) { if(Trade0RiskPercent == 0) { Print("Using fixed lot size: ", Trade0Lot); return Trade0Lot; } double accountValue = Trade0UseEquity ? AccountBalance() : AccountEquity(); double riskAmount = accountValue * Trade0RiskPercent / 100.0; if(slPips <= 0) slPips = 50; // Default fallback double tickSize = MarketInfo(symbol, MODE_TICKSIZE); double tickValue = MarketInfo(symbol, MODE_TICKVALUE); double point = MarketInfo(symbol, MODE_POINT); double pipValue = 0; if(point > 0 && tickSize > 0) { pipValue = (tickValue / tickSize) * point * 10; } double lots = 0; if(pipValue > 0 && slPips > 0) { lots = riskAmount / (slPips * pipValue); } double minLot = MarketInfo(symbol, MODE_MINLOT); double maxLot = MarketInfo(symbol, MODE_MAXLOT); double lotStep = MarketInfo(symbol, MODE_LOTSTEP); lots = MathMax(lots, minLot); lots = MathMin(lots, maxLot); lots = MathFloor(lots / lotStep) * lotStep; lots = NormalizeDouble(lots, 2); return lots; } //+------------------------------------------------------------------+ //| Get Net Open Position (Buy lots - Sell lots) | //+------------------------------------------------------------------+ double GetNetPosition(string symbol) { double buyLots = 0; double sellLots = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != symbol) continue; if(OrderType() == OP_BUY) buyLots += OrderLots(); else if(OrderType() == OP_SELL) sellLots += OrderLots(); } return buyLots - sellLots; } //+------------------------------------------------------------------+ //| Update Panel Information | //+------------------------------------------------------------------+ void UpdatePanelInfo() { // Calculate current ADR double adr = CalculateADR(Symbol(), ADR_Period); // Convert ADR to pips - FIXED for gold double point = MarketInfo(Symbol(), MODE_POINT); double pipValue = point; // For 5-digit forex (EURUSD), 1 pip = 10 points if(Digits == 5) pipValue = point * 10; // For 2-digit or 3-digit symbols (XAUUSD, USDJPY), 1 pip = 100 points else if(Digits == 2 || Digits == 3) pipValue = point * 100; double adrPips = 0; double slPips = 0; double tpPips = 0; double lotSize = 0; if(adr > 0) { adrPips = adr / pipValue; slPips = adrPips * (SL_Percent / 100.0); tpPips = adrPips * (TP_Percent / 100.0); // Calculate lot size lotSize = CalculateLotSize(Symbol(), slPips); } else { // If ADR calculation fails, use fallback values lotSize = Trade0Lot; } // Get net position double netPos = GetNetPosition(Symbol()); // Get current spread (convert to pips) double spread = MarketInfo(Symbol(), MODE_SPREAD); // For all multi-digit symbols (2, 3, 5 digits), divide by 10 if(Digits == 2 || Digits == 3 || Digits == 5) spread = spread / 10.0; // Update ADR value label string adrText = (adr > 0) ? StringFormat("ADR (%d): %.0f pips", ADR_Period, adrPips) : StringFormat("ADR (%d): N/A", ADR_Period); ObjectSetString(0, adrValueLabel, OBJPROP_TEXT, adrText); // Update spread label string spreadText = StringFormat("Spread: %.1f", spread); ObjectSetString(0, spreadLabel, OBJPROP_TEXT, spreadText); // Update SL value label string slText = (adr > 0) ? StringFormat("SL(%.0f%%): %.0f pips", SL_Percent, slPips) : StringFormat("SL(%.0f%%): N/A", SL_Percent); ObjectSetString(0, slValueLabel, OBJPROP_TEXT, slText); // Update TP value label string tpText = (adr > 0) ? StringFormat("TP(%.0f%%): %.0f pips", TP_Percent, tpPips) : StringFormat("TP(%.0f%%): N/A", TP_Percent); ObjectSetString(0, tpValueLabel, OBJPROP_TEXT, tpText); // Update lot size label string lotText = StringFormat("Lot: %.2f", lotSize); ObjectSetString(0, lotSizeLabel, OBJPROP_TEXT, lotText); // Update net position label string netPosText = StringFormat("Pos: %.2f", netPos); color netPosColor = netPos > 0 ? clrLime : (netPos < 0 ? clrTomato : clrYellow); ObjectSetString(0, netPosLabel, OBJPROP_TEXT, netPosText); ObjectSetInteger(0, netPosLabel, OBJPROP_COLOR, netPosColor); // Update magic number label int currentMagic = Magic_Number + magic_shift; string magicText = StringFormat("Magic No: %d", currentMagic); ObjectSetString(0, magicLabel, OBJPROP_TEXT, magicText); } //+------------------------------------------------------------------+ //| Process all open orders and apply ADR-based SL/TP | //+------------------------------------------------------------------+ void ProcessOpenOrders() { int totalOrders = OrdersTotal(); if(totalOrders == 0) { if(ShowDiagnostics) Print("No open orders found"); return; } if(ShowDiagnostics) Print("Found ", totalOrders, " open order(s)"); for(int i = totalOrders - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != (Magic_Number + magic_shift)) continue; // Only process market orders (Buy or Sell) if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue; // CRITICAL: Store ALL order data BEFORE calling IsOrderHedged (which does OrderSelect internally) int currentTicket = OrderTicket(); string currentSymbol = OrderSymbol(); int currentType = OrderType(); double currentStopLoss = OrderStopLoss(); double currentTakeProfit = OrderTakeProfit(); // Skip hedged orders - don't apply SL/TP to hedged trades if(IsOrderHedged(currentTicket)) { if(ShowDiagnostics) Print("Order #", currentTicket, " is hedged - skipping SL/TP application"); continue; } // For Type 1 (Normal SL): Check if order already has SL and TP set if(Stop_Loss_Type == SL_TYPE_NORMAL && currentStopLoss != 0 && currentTakeProfit != 0) { if(ShowDiagnostics) Print("Order #", currentTicket, " (", currentSymbol, ") already has SL/TP - skipping"); continue; } // Calculate ADR for this symbol double adr = CalculateADR(currentSymbol, ADR_Period); if(adr <= 0) { if(ShowDiagnostics) Print("Failed to calculate ADR for ", currentSymbol); continue; } if(ShowDiagnostics) Print("ADR for ", currentSymbol, ": ", DoubleToStr(adr, Digits), " pips"); // Get current market price for this symbol double currentPrice = currentType == OP_BUY ? Bid : Ask; if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) { // Place stop order instead of SL PlaceStopOrderInsteadOfSL(currentTicket, currentSymbol, currentType, currentPrice, adr); } else if(Stop_Loss_Type == SL_TYPE_NORMAL) { // Calculate SL and TP levels based on current price double sl = CalculateStopLoss(currentSymbol, currentType, currentPrice, adr); double tp = CalculateTakeProfit(currentSymbol, currentType, currentPrice, adr); // Re-select the order before modifying (in case OrderSelect was called elsewhere) if(!OrderSelect(currentTicket, SELECT_BY_TICKET)) continue; // Apply SL and TP bool result = OrderModify(currentTicket, OrderOpenPrice(), sl, tp, 0, clrNONE); if(result) { if(ShowDiagnostics) { Print("Successfully applied SL/TP to order #", currentTicket, " (", currentSymbol, ")"); Print(" Current Price: ", DoubleToStr(currentPrice, Digits)); Print(" SL: ", DoubleToStr(sl, Digits), " | TP: ", DoubleToStr(tp, Digits)); } } else { if(ShowDiagnostics) Print("Failed to modify order #", currentTicket, " - Error: ", GetLastError()); } } // Type 3 (Auto Hedge): Don't apply SL/TP, hedging handled in ManageAutoHedging() } } //+------------------------------------------------------------------+ //| Place Stop Order Instead of SL | //+------------------------------------------------------------------+ void PlaceStopOrderInsteadOfSL(int ticket, string symbol, int orderType, double currentPrice, double adr) { // CRITICAL: Re-select the specific order to get its ACTUAL lot size if(!OrderSelect(ticket, SELECT_BY_TICKET)) { if(ShowDiagnostics) Print("ERROR: Cannot select order #", ticket, " to place stop order"); return; } // Get the ACTUAL lot size of THIS specific order double lotSize = OrderLots(); if(ShowDiagnostics) Print("DEBUG: Order #", ticket, " has lot size: ", DoubleToStr(lotSize, 2)); double slDistance = adr * (SL_Percent / 100.0); double stopPrice = 0; int stopOrderType = -1; // Determine stop order type and price if(orderType == OP_BUY) { // For buy order, place sell stop below stopPrice = currentPrice - slDistance; stopOrderType = OP_SELLSTOP; } else if(orderType == OP_SELL) { // For sell order, place buy stop above stopPrice = currentPrice + slDistance; stopOrderType = OP_BUYSTOP; } stopPrice = NormalizeDouble(stopPrice, (int)MarketInfo(symbol, MODE_DIGITS)); // Check if stop order already exists for this trade by checking comment bool stopExists = false; string searchComment = "Stop:#" + IntegerToString(ticket); for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != symbol) continue; // Check if this is a stop order for our market order if(StringFind(OrderComment(), searchComment) >= 0) { stopExists = true; if(ShowDiagnostics) Print("Stop order already exists for #", ticket); return; } } // CRITICAL: Re-select the original order again because the loop above changed selection if(!OrderSelect(ticket, SELECT_BY_TICKET)) { if(ShowDiagnostics) Print("ERROR: Cannot re-select order #", ticket, " after checking for existing stops"); return; } // Get the lot size again to ensure we have the correct value lotSize = OrderLots(); if(ShowDiagnostics) Print("DEBUG: Placing stop order for #", ticket, " with lot size: ", DoubleToStr(lotSize, 2)); // Place the stop order with comment linking to parent string comment = "Stop:#" + IntegerToString(ticket); int newTicket = OrderSend(symbol, stopOrderType, lotSize, stopPrice, 3, 0, 0, comment, 0, 0, clrRed); if(newTicket > 0) { if(ShowDiagnostics) Print("Placed ", (stopOrderType == OP_BUYSTOP ? "BUY STOP" : "SELL STOP"), " order #", newTicket, " (", DoubleToStr(lotSize, 2), " lots) at ", DoubleToStr(stopPrice, Digits), " as protection for order #", ticket); } else { if(ShowDiagnostics) Print("Failed to place stop order for #", ticket, " - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Execute Market Buy Order | //+------------------------------------------------------------------+ void ExecuteBuyOrder() { string symbol = Symbol(); double adr = CalculateADR(symbol, ADR_Period); if(adr <= 0) { Print("Cannot execute buy - failed to calculate ADR"); return; } // Convert ADR to pips double point = MarketInfo(symbol, MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; double adrPips = adr / pipValue; double slPips = adrPips * (SL_Percent / 100.0); // Calculate lot size double lotSize = CalculateLotSize(symbol, slPips); // Calculate SL and TP based on Stop Loss Type double sl = 0; double tp = 0; if(Stop_Loss_Type == SL_TYPE_NORMAL) { sl = CalculateStopLoss(symbol, OP_BUY, Ask, adr); tp = CalculateTakeProfit(symbol, OP_BUY, Ask, adr); } else if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) { // No SL in order, stop order will be created sl = 0; tp = CalculateTakeProfit(symbol, OP_BUY, Ask, adr); } else if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) { // No SL or TP, auto-hedging will manage sl = 0; tp = 0; } else if(Stop_Loss_Type == SL_TYPE_NONE) { // No SL, but TP is set sl = 0; tp = CalculateTakeProfit(symbol, OP_BUY, Ask, adr); } int currentMagic = Magic_Number + magic_shift; int ticket = OrderSend(symbol, OP_BUY, lotSize, Ask, 3, sl, tp, "HTP Buy " + symbol, currentMagic, 0, clrGreen); if(ticket > 0) { Print("BUY order placed successfully #", ticket, " with magic ", currentMagic); Print(" Price: ", DoubleToStr(Ask, Digits)); Print(" Lot: ", lotSize); Print(" SL: ", DoubleToStr(sl, Digits)); Print(" TP: ", DoubleToStr(tp, Digits)); // Stop order will be created automatically on next tick by ManageStopOrders() if Type 2 } else { Print("Failed to place BUY order - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Execute Market Sell Order | //+------------------------------------------------------------------+ void ExecuteSellOrder() { string symbol = Symbol(); double adr = CalculateADR(symbol, ADR_Period); if(adr <= 0) { Print("Cannot execute sell - failed to calculate ADR"); return; } // Convert ADR to pips double point = MarketInfo(symbol, MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; double adrPips = adr / pipValue; double slPips = adrPips * (SL_Percent / 100.0); // Calculate lot size double lotSize = CalculateLotSize(symbol, slPips); // Calculate SL and TP based on Stop Loss Type double sl = 0; double tp = 0; if(Stop_Loss_Type == SL_TYPE_NORMAL) { sl = CalculateStopLoss(symbol, OP_SELL, Bid, adr); tp = CalculateTakeProfit(symbol, OP_SELL, Bid, adr); } else if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) { // No SL in order, stop order will be created sl = 0; tp = CalculateTakeProfit(symbol, OP_SELL, Bid, adr); } else if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) { // No SL or TP, auto-hedging will manage sl = 0; tp = 0; } else if(Stop_Loss_Type == SL_TYPE_NONE) { // No SL, but TP is set sl = 0; tp = CalculateTakeProfit(symbol, OP_SELL, Bid, adr); } int currentMagic = Magic_Number + magic_shift; int ticket = OrderSend(symbol, OP_SELL, lotSize, Bid, 3, sl, tp, "HTP Sell " + symbol, currentMagic, 0, clrRed); if(ticket > 0) { Print("SELL order placed successfully #", ticket, " with magic ", currentMagic); Print(" Price: ", DoubleToStr(Bid, Digits)); Print(" Lot: ", lotSize); Print(" SL: ", DoubleToStr(sl, Digits)); Print(" TP: ", DoubleToStr(tp, Digits)); // Stop order will be created automatically on next tick by ManageStopOrders() if Type 2 } else { Print("Failed to place SELL order - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Execute Buy Pending Order (Buy Limit at ADR distance below) | //+------------------------------------------------------------------+ void ExecuteBuyPendingOrder() { string symbol = Symbol(); double adr = CalculateADR(symbol, ADR_Period); if(adr <= 0) { Print("Cannot execute buy pending - failed to calculate ADR"); return; } // Convert ADR to pips double point = MarketInfo(symbol, MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; double adrPips = adr / pipValue; double slPips = adrPips * (SL_Percent / 100.0); // Calculate lot size double lotSize = CalculateLotSize(symbol, slPips); // Place buy limit at ADR distance below current price double entryPrice = NormalizeDouble(Bid - adr, Digits); // Calculate SL and TP based on Stop Loss Type double sl = 0; double tp = 0; if(Stop_Loss_Type == SL_TYPE_NORMAL) { sl = CalculateStopLoss(symbol, OP_BUY, entryPrice, adr); tp = CalculateTakeProfit(symbol, OP_BUY, entryPrice, adr); } else if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) { sl = 0; tp = CalculateTakeProfit(symbol, OP_BUY, entryPrice, adr); } else if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) { sl = 0; tp = 0; } else if(Stop_Loss_Type == SL_TYPE_NONE) { sl = 0; tp = CalculateTakeProfit(symbol, OP_BUY, entryPrice, adr); } int currentMagic = Magic_Number + magic_shift; int ticket = OrderSend(symbol, OP_BUYLIMIT, lotSize, entryPrice, 3, sl, tp, "HTP Buy Limit " + symbol, currentMagic, 0, clrGreen); if(ticket > 0) { Print("BUY LIMIT order placed successfully #", ticket); Print(" Entry Price: ", DoubleToStr(entryPrice, Digits)); Print(" Current Bid: ", DoubleToStr(Bid, Digits)); Print(" Distance: ", DoubleToStr(adr / pipValue, 1), " pips"); Print(" Lot: ", lotSize); } else { Print("Failed to place BUY LIMIT order - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Execute Sell Pending Order (Sell Limit at ADR distance above) | //+------------------------------------------------------------------+ void ExecuteSellPendingOrder() { string symbol = Symbol(); double adr = CalculateADR(symbol, ADR_Period); if(adr <= 0) { Print("Cannot execute sell pending - failed to calculate ADR"); return; } // Convert ADR to pips double point = MarketInfo(symbol, MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; double adrPips = adr / pipValue; double slPips = adrPips * (SL_Percent / 100.0); // Calculate lot size double lotSize = CalculateLotSize(symbol, slPips); // Place sell limit at ADR distance above current price double entryPrice = NormalizeDouble(Ask + adr, Digits); // Calculate SL and TP based on Stop Loss Type double sl = 0; double tp = 0; if(Stop_Loss_Type == SL_TYPE_NORMAL) { sl = CalculateStopLoss(symbol, OP_SELL, entryPrice, adr); tp = CalculateTakeProfit(symbol, OP_SELL, entryPrice, adr); } else if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) { sl = 0; tp = CalculateTakeProfit(symbol, OP_SELL, entryPrice, adr); } else if(Stop_Loss_Type == SL_TYPE_AUTO_HEDGE) { sl = 0; tp = 0; } else if(Stop_Loss_Type == SL_TYPE_NONE) { sl = 0; tp = CalculateTakeProfit(symbol, OP_SELL, entryPrice, adr); } int currentMagic = Magic_Number + magic_shift; int ticket = OrderSend(symbol, OP_SELLLIMIT, lotSize, entryPrice, 3, sl, tp, "HTP Sell Limit " + symbol, currentMagic, 0, clrRed); if(ticket > 0) { Print("SELL LIMIT order placed successfully #", ticket); Print(" Entry Price: ", DoubleToStr(entryPrice, Digits)); Print(" Current Ask: ", DoubleToStr(Ask, Digits)); Print(" Distance: ", DoubleToStr(adr / pipValue, 1), " pips"); Print(" Lot: ", lotSize); } else { Print("Failed to place SELL LIMIT order - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Close All Buy Trades | //+------------------------------------------------------------------+ void CloseAllBuyTrades() { int closed = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != (Magic_Number + magic_shift)) continue; // Only close market BUY orders if(OrderType() == OP_BUY) { bool result = OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed); if(result) closed++; } // Close BUY LIMIT pending orders else if(OrderType() == OP_BUYLIMIT) { bool result = OrderDelete(OrderTicket()); if(result) closed++; } } Print("Closed ", closed, " buy trade(s)"); } //+------------------------------------------------------------------+ //| Close All Sell Trades | //+------------------------------------------------------------------+ void CloseAllSellTrades() { int closed = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != (Magic_Number + magic_shift)) continue; // Only close market SELL orders if(OrderType() == OP_SELL) { bool result = OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrGreen); if(result) closed++; } // Close SELL LIMIT pending orders else if(OrderType() == OP_SELLLIMIT) { bool result = OrderDelete(OrderTicket()); if(result) closed++; } } Print("Closed ", closed, " sell trade(s)"); } //+------------------------------------------------------------------+ //| Close All Trades | //+------------------------------------------------------------------+ void CloseAllTrades() { int closed = 0; int currentMagic = Magic_Number + magic_shift; if(Close_Trades_By_Order_CloseBy) { // Use OrderCloseBy method - hedges opposite orders before closing Print("Closing all trades using OrderCloseBy (hedge first method)"); // Collect all buy and sell tickets int buyTickets[]; double buyLots[]; int sellTickets[]; double sellLots[]; int buyCount = 0; int sellCount = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; if(OrderType() == OP_BUY) { buyCount++; ArrayResize(buyTickets, buyCount); ArrayResize(buyLots, buyCount); buyTickets[buyCount-1] = OrderTicket(); buyLots[buyCount-1] = OrderLots(); } else if(OrderType() == OP_SELL) { sellCount++; ArrayResize(sellTickets, sellCount); ArrayResize(sellLots, sellCount); sellTickets[sellCount-1] = OrderTicket(); sellLots[sellCount-1] = OrderLots(); } } // Close opposite orders using OrderCloseBy (hedges positions) int minCount = MathMin(buyCount, sellCount); for(int i = 0; i < minCount; i++) { // Verify both orders still exist before attempting OrderCloseBy bool buyExists = false; bool sellExists = false; for(int j = OrdersTotal() - 1; j >= 0; j--) { if(OrderSelect(j, SELECT_BY_POS, MODE_TRADES)) { if(OrderTicket() == buyTickets[i]) buyExists = true; if(OrderTicket() == sellTickets[i]) sellExists = true; } } if(buyExists && sellExists) { if(OrderCloseBy(buyTickets[i], sellTickets[i], clrGreen)) { closed += 2; Print("Closed by hedge: BUY #", buyTickets[i], " with SELL #", sellTickets[i]); } else { int error = GetLastError(); Print("OrderCloseBy failed for BUY #", buyTickets[i], " and SELL #", sellTickets[i], " - Error: ", error); } } } // Close remaining buy orders (those not hedged or partially remaining) for(int i = 0; i < buyCount; i++) { if(OrderSelect(buyTickets[i], SELECT_BY_TICKET) && OrderCloseTime() == 0) { if(OrderClose(buyTickets[i], OrderLots(), Bid, 3, clrRed)) { closed++; Print("Closed remaining BUY #", buyTickets[i]); } } } // Close remaining sell orders (those not hedged or partially remaining) for(int i = 0; i < sellCount; i++) { if(OrderSelect(sellTickets[i], SELECT_BY_TICKET) && OrderCloseTime() == 0) { if(OrderClose(sellTickets[i], OrderLots(), Ask, 3, clrGreen)) { closed++; Print("Closed remaining SELL #", sellTickets[i]); } } } // Close pending orders for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; if(OrderType() > OP_SELL) { if(OrderDelete(OrderTicket())) closed++; } } } else { // Standard close method - close orders normally for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; bool result = false; if(OrderType() == OP_BUY) result = OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed); else if(OrderType() == OP_SELL) result = OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrGreen); else result = OrderDelete(OrderTicket()); if(result) closed++; } } Print("Closed ", closed, " trade(s)"); } //+------------------------------------------------------------------+ //| Check if Order is Hedged | //+------------------------------------------------------------------+ bool IsOrderHedged(int ticket) { // Check if this order's comment indicates it's a hedge if(!OrderSelect(ticket, SELECT_BY_TICKET)) return false; string comment = OrderComment(); // If this order IS a hedge (comment starts with "Hedge:#") if(StringFind(comment, "Hedge:#") >= 0) return true; // Check if another order exists that hedges THIS order string searchComment = "Hedge:#" + IntegerToString(ticket); for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; string orderComment = OrderComment(); // Check if this is a hedge for our order if(StringFind(orderComment, searchComment) >= 0) return true; } return false; } //+------------------------------------------------------------------+ //| Hedge All Open Trades | //+------------------------------------------------------------------+ void HedgeAllTrades() { int hedged = 0; int currentMagic = Magic_Number + magic_shift; // Collect all market orders to hedge int tickets[]; double lots[]; int types[]; int count = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; // Only hedge market orders (not pending) if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue; // CRITICAL: Store order data FIRST before any function calls int currentTicket = OrderTicket(); string currentComment = OrderComment(); double currentLots = OrderLots(); int currentType = OrderType(); // CRITICAL: Skip if this order IS ITSELF a hedge order if(StringFind(currentComment, "Hedge:#") >= 0) continue; // Skip if already hedged (another order exists that hedges this one) if(IsOrderHedged(currentTicket)) continue; count++; ArrayResize(tickets, count); ArrayResize(lots, count); ArrayResize(types, count); tickets[count-1] = currentTicket; lots[count-1] = currentLots; types[count-1] = currentType; } if(count == 0) return; // Now place opposite orders for each for(int i = 0; i < count; i++) { int originalTicket = tickets[i]; double lotSize = lots[i]; int originalType = types[i]; // Delete any existing stop orders for this trade BEFORE hedging (only if Type 2) if(Stop_Loss_Type == SL_TYPE_STOP_ORDER) DeleteStopOrdersForTicket(originalTicket); // Place opposite order string comment = "Hedge:#" + IntegerToString(originalTicket); int hedgeType = (originalType == OP_BUY) ? OP_SELL : OP_BUY; double price = (hedgeType == OP_BUY) ? Ask : Bid; int newTicket = OrderSend(Symbol(), hedgeType, lotSize, price, 3, 0, 0, comment, currentMagic, 0, clrOrange); if(newTicket > 0) hedged++; } Print("Hedged ", hedged, " trade(s)"); } //+------------------------------------------------------------------+ //| Delete Stop Orders for Specific Ticket | //+------------------------------------------------------------------+ void DeleteStopOrdersForTicket(int ticket) { string searchComment = "Stop:#" + IntegerToString(ticket); for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Only check pending stop orders if(OrderType() != OP_BUYSTOP && OrderType() != OP_SELLSTOP) continue; // Check if this is a stop order for the specified ticket if(StringFind(OrderComment(), searchComment) >= 0) { bool result = OrderDelete(OrderTicket(), clrNONE); if(!result) Print("Failed to delete stop order #", OrderTicket(), " - Error: ", GetLastError()); } } } //+------------------------------------------------------------------+ //| Get ADR H1 in Pips | //+------------------------------------------------------------------+ double GetADR_H1_Pips() { double sum = 0; int count = 0; double point = MarketInfo(Symbol(), MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; for(int i = 1; i <= ADR_H1_Period; i++) { double h = iHigh(Symbol(), PERIOD_H1, i); double l = iLow(Symbol(), PERIOD_H1, i); if(h > 0 && l > 0) { sum += (h - l); count++; } } if(count < (int)(ADR_H1_Period * 0.8)) return 0; return (sum / count) / pipValue; } //+------------------------------------------------------------------+ //| Find Higher Low (for swing-based trailing) | //+------------------------------------------------------------------+ double FindHigherLow(int lookback) { double lows[]; ArraySetAsSeries(lows, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 1, lookback + 2, lows) < lookback + 2) return 0; // Look for swing low for(int i = 1; i < lookback; i++) { if(lows[i] < lows[i-1] && lows[i] < lows[i+1]) return lows[i]; } // If no swing found, return highest low double highestLow = 0; for(int i = 0; i < lookback; i++) { if(lows[i] > highestLow) highestLow = lows[i]; } return highestLow; } //+------------------------------------------------------------------+ //| Find Lower High (for swing-based trailing) | //+------------------------------------------------------------------+ double FindLowerHigh(int lookback) { double highs[]; ArraySetAsSeries(highs, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 1, lookback + 2, highs) < lookback + 2) return 0; // Look for swing high for(int i = 1; i < lookback; i++) { if(highs[i] > highs[i-1] && highs[i] > highs[i+1]) return highs[i]; } // If no swing found, return lowest high double lowestHigh = 999999; for(int i = 0; i < lookback; i++) { if(highs[i] < lowestHigh) lowestHigh = highs[i]; } return (lowestHigh == 999999) ? 0 : lowestHigh; } //+------------------------------------------------------------------+ //| Manage Trailing Stop and Breakeven | //+------------------------------------------------------------------+ void ManageTrail() { if(!UseJumpingTrail) return; // Cache ADR H1 for Method C if(Trail_Method == TRAIL_METHOD_C) { datetime h1Time = iTime(Symbol(), PERIOD_H1, 0); if(h1Time != lastH1BarTime) { cachedADR_H1_Pips = GetADR_H1_Pips(); lastH1BarTime = h1Time; } } double point = MarketInfo(Symbol(), MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; int currentMagic = Magic_Number + magic_shift; int totalOrders = OrdersTotal(); for(int i = totalOrders - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; // Only process market orders if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue; int ticket = OrderTicket(); // CRITICAL: Skip hedged orders - they should not be trailed if(IsOrderHedged(ticket)) continue; int orderType = OrderType(); double openPrice = OrderOpenPrice(); double currentSL = OrderStopLoss(); double tp = OrderTakeProfit(); double bid = MarketInfo(Symbol(), MODE_BID); double ask = MarketInfo(Symbol(), MODE_ASK); double profitPips = (orderType == OP_BUY) ? (bid - openPrice) / pipValue : (openPrice - ask) / pipValue; // Breakeven logic (only before trailing starts - Option 2) if(profitPips >= Distance_to_BE && profitPips < TrailStartPips) { double beSL = (orderType == OP_BUY) ? NormalizeDouble(openPrice + (BE_Min_Pips * pipValue), Digits) : NormalizeDouble(openPrice - (BE_Min_Pips * pipValue), Digits); bool needsBE = (orderType == OP_BUY && currentSL < beSL) || (orderType == OP_SELL && (currentSL == 0 || beSL < currentSL)); if(needsBE) { if(OrderModify(ticket, openPrice, beSL, tp, 0, clrNONE)) { Print("[TRAIL] Breakeven set for order #", ticket, " at ", beSL); currentSL = beSL; } } } // Trailing logic (starts at TrailStartPips) if(profitPips >= TrailStartPips) { double newSL = 0; if(Trail_Method == TRAIL_METHOD_A) { // Fixed pip trailing newSL = (orderType == OP_BUY) ? NormalizeDouble(bid - (TrailJumpPips * pipValue), Digits) : NormalizeDouble(ask + (TrailJumpPips * pipValue), Digits); } else if(Trail_Method == TRAIL_METHOD_B) { // Swing-based trailing if(orderType == OP_BUY) { double higherLow = FindHigherLow(Swing_Lookback); if(higherLow > 0) newSL = NormalizeDouble(higherLow - (Trail_Buffer_Pips * pipValue), Digits); } else { double lowerHigh = FindLowerHigh(Swing_Lookback); if(lowerHigh > 0) newSL = NormalizeDouble(lowerHigh + (Trail_Buffer_Pips * pipValue), Digits); } } else if(Trail_Method == TRAIL_METHOD_C) { // ADR H1 percentage trailing double trailDist = cachedADR_H1_Pips * (ADR_H1_TrailPct / 100.0); newSL = (orderType == OP_BUY) ? NormalizeDouble(bid - (trailDist * pipValue), Digits) : NormalizeDouble(ask + (trailDist * pipValue), Digits); } if(newSL > 0) { bool shouldUpdate = false; if(orderType == OP_BUY) { shouldUpdate = (newSL > currentSL + (2 * point) && newSL > openPrice); } else { shouldUpdate = ((currentSL == 0 || newSL < currentSL - (2 * point)) && newSL < openPrice); } if(shouldUpdate) { if(OrderModify(ticket, openPrice, newSL, tp, 0, clrNONE)) { Print("[TRAIL] Updated order #", ticket, " | Method: ", (Trail_Method == TRAIL_METHOD_A ? "A" : (Trail_Method == TRAIL_METHOD_B ? "B" : "C")), " | New SL: ", newSL, " | Profit: ", DoubleToString(profitPips, 1), " pips"); } } } } } } //+------------------------------------------------------------------+ //| Manage Stop Orders - Automatically sync with market orders | //+------------------------------------------------------------------+ void ManageStopOrders() { int currentMagic = Magic_Number + magic_shift; // Loop through all market orders and ensure they have matching stop orders for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Filter by magic number if enabled if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; // Only process market orders (Buy or Sell) if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue; // CRITICAL: Capture ALL order data BEFORE calling IsOrderHedged (which does OrderSelect internally) int marketTicket = OrderTicket(); double marketLots = OrderLots(); int orderType = OrderType(); // Skip hedged orders - don't create stop orders for hedged trades if(IsOrderHedged(marketTicket)) continue; // Check if matching stop order exists bool stopExists = false; double existingStopLots = 0; int existingStopTicket = 0; string searchComment = "Stop:#" + IntegerToString(marketTicket); for(int j = OrdersTotal() - 1; j >= 0; j--) { if(!OrderSelect(j, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; // Check if this is a stop order for our market order if(StringFind(OrderComment(), searchComment) >= 0) { stopExists = true; existingStopLots = OrderLots(); existingStopTicket = OrderTicket(); break; } } // If stop order doesn't exist, create it if(!stopExists) { if(ShowDiagnostics) Print("DEBUG: Creating stop for #", marketTicket, " with ", DoubleToStr(marketLots, 2), " lots"); CreateProtectiveStopOrder(marketTicket, orderType, marketLots); } // If stop order exists but lot size doesn't match (partial close), update it else if(MathAbs(existingStopLots - marketLots) > 0.001) { if(ShowDiagnostics) Print("Market order #", marketTicket, " partially closed. Old lots: ", existingStopLots, ", New lots: ", marketLots); // Delete old stop order if(OrderSelect(existingStopTicket, SELECT_BY_TICKET)) { bool deleteResult = OrderDelete(existingStopTicket); if(!deleteResult && ShowDiagnostics) Print("Failed to delete stop order #", existingStopTicket, " - Error: ", GetLastError()); else if(ShowDiagnostics) Print("Deleted old stop order #", existingStopTicket); } // Create new stop order with correct lot size if(ShowDiagnostics) Print("DEBUG: Creating updated stop for #", marketTicket, " with ", DoubleToStr(marketLots, 2), " lots"); CreateProtectiveStopOrder(marketTicket, orderType, marketLots); } } // Clean up orphaned stop orders (market order was fully closed) CleanUpOrphanedStopOrders(); } //+------------------------------------------------------------------+ //| Create Protective Stop Order | //+------------------------------------------------------------------+ void CreateProtectiveStopOrder(int marketTicket, int orderType, double lots) { if(!OrderSelect(marketTicket, SELECT_BY_TICKET)) return; string symbol = OrderSymbol(); double adr = CalculateADR(symbol, ADR_Period); if(adr <= 0) return; double slDistance = adr * (SL_Percent / 100.0); double currentPrice = (orderType == OP_BUY) ? MarketInfo(symbol, MODE_BID) : MarketInfo(symbol, MODE_ASK); double stopPrice = 0; int stopOrderType = -1; // Determine stop order type and price if(orderType == OP_BUY) { // For buy order, place sell stop below stopPrice = currentPrice - slDistance; stopOrderType = OP_SELLSTOP; } else if(orderType == OP_SELL) { // For sell order, place buy stop above stopPrice = currentPrice + slDistance; stopOrderType = OP_BUYSTOP; } stopPrice = NormalizeDouble(stopPrice, Digits); // Create comment with parent ticket string comment = "Stop:#" + IntegerToString(marketTicket); // Place the stop order int ticket = OrderSend(symbol, stopOrderType, lots, stopPrice, 3, 0, 0, comment, 0, 0, clrRed); if(ticket > 0) { Print("Created protective ", (stopOrderType == OP_BUYSTOP ? "BUY STOP" : "SELL STOP"), " order #", ticket, " (", DoubleToStr(lots, 2), " lots) at ", DoubleToStr(stopPrice, Digits), " for market order #", marketTicket); } else { Print("Failed to create protective stop order for #", marketTicket, " - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Clean Up Orphaned Stop Orders | //+------------------------------------------------------------------+ void CleanUpOrphanedStopOrders() { int currentMagic = Magic_Number + magic_shift; // Build list of active market order tickets int activeMarketTickets[]; int count = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(OrderType() == OP_BUY || OrderType() == OP_SELL) { // Skip stop orders themselves if(StringFind(OrderComment(), "Stop:#") < 0) { count++; ArrayResize(activeMarketTickets, count); activeMarketTickets[count-1] = OrderTicket(); } } } // Check all stop orders and delete orphans for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; string comment = OrderComment(); // Check if this is a protective stop order if(StringFind(comment, "Stop:#") >= 0) { // Extract the parent market order ticket from comment int startPos = StringFind(comment, "Stop:#") + 6; string ticketStr = StringSubstr(comment, startPos); int parentTicket = (int)StringToInteger(ticketStr); // Check if parent market order still exists bool parentExists = false; for(int j = 0; j < count; j++) { if(activeMarketTickets[j] == parentTicket) { parentExists = true; break; } } // If parent doesn't exist, delete this orphaned stop order if(!parentExists) { int stopTicket = OrderTicket(); if(OrderDelete(stopTicket)) { Print("Deleted orphaned stop order #", stopTicket, " (parent order #", parentTicket, " no longer exists)"); } } } } } //+------------------------------------------------------------------+ //| Calculate Average Daily Range | //+------------------------------------------------------------------+ double CalculateADR(string symbol, int period) { double totalRange = 0; int validDays = 0; // CHANGED: Start from bar 1 instead of bar 0 to avoid incomplete current day for(int i = 1; i <= period; i++) { double high = iHigh(symbol, PERIOD_D1, i); double low = iLow(symbol, PERIOD_D1, i); if(high > 0 && low > 0) { totalRange += (high - low); validDays++; } } if(validDays == 0) return 0; return totalRange / validDays; } //+------------------------------------------------------------------+ //| Calculate Stop Loss level | //+------------------------------------------------------------------+ double CalculateStopLoss(string symbol, int orderType, double currentPrice, double adr) { double slDistance = adr * (SL_Percent / 100.0); double sl = 0; if(orderType == OP_BUY || orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP) sl = currentPrice - slDistance; else if(orderType == OP_SELL || orderType == OP_SELLLIMIT || orderType == OP_SELLSTOP) sl = currentPrice + slDistance; // Normalize to symbol's digits return NormalizeDouble(sl, (int)MarketInfo(symbol, MODE_DIGITS)); } //+------------------------------------------------------------------+ //| Calculate Take Profit level | //+------------------------------------------------------------------+ double CalculateTakeProfit(string symbol, int orderType, double currentPrice, double adr) { double tpDistance = adr * (TP_Percent / 100.0); double tp = 0; if(orderType == OP_BUY || orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP) tp = currentPrice + tpDistance; else if(orderType == OP_SELL || orderType == OP_SELLLIMIT || orderType == OP_SELLSTOP) tp = currentPrice - tpDistance; // Normalize to symbol's digits return NormalizeDouble(tp, (int)MarketInfo(symbol, MODE_DIGITS)); } //========== CONTINUE WITH BASKET FUNCTIONS BELOW ========== //========== PART 3 OF 3 - FINAL (BASKET & PANEL) ========== // // PASTE THIS AFTER PART 2 // This completes the EA file // //========================================================== //+------------------------------------------------------------------+ //| Create Panel with Buttons | //+------------------------------------------------------------------+ void CreatePanel() { int panelWidth = 180; int panelHeight = 263; // Increased by 18px for new magic label int buttonWidth = 150; int buttonHeight = 28; int yOffset = CurrentPanelY; // Create background panel - FIXED (not moveable) ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, CurrentPanelX); ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, CurrentPanelY); ObjectSetInteger(0, panelName, OBJPROP_XSIZE, panelWidth); ObjectSetInteger(0, panelName, OBJPROP_YSIZE, panelHeight); ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR, Panel_BgColor); ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, panelName, OBJPROP_BACK, false); ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, panelName, OBJPROP_SELECTED, false); ObjectSetInteger(0, panelName, OBJPROP_HIDDEN, false); // Create drag handle button "≡" at top right string dragHandle = "ADR_DragHandle"; ObjectCreate(0, dragHandle, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, dragHandle, OBJPROP_XDISTANCE, CurrentPanelX + panelWidth - 20); ObjectSetInteger(0, dragHandle, OBJPROP_YDISTANCE, CurrentPanelY + 2); ObjectSetInteger(0, dragHandle, OBJPROP_XSIZE, 18); ObjectSetInteger(0, dragHandle, OBJPROP_YSIZE, 16); ObjectSetInteger(0, dragHandle, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, dragHandle, OBJPROP_BGCOLOR, clrDarkSlateGray); ObjectSetInteger(0, dragHandle, OBJPROP_COLOR, clrYellow); ObjectSetInteger(0, dragHandle, OBJPROP_FONTSIZE, 10); ObjectSetString(0, dragHandle, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, dragHandle, OBJPROP_TEXT, "≡"); ObjectSetInteger(0, dragHandle, OBJPROP_SELECTABLE, true); ObjectSetInteger(0, dragHandle, OBJPROP_SELECTED, false); ObjectSetInteger(0, dragHandle, OBJPROP_HIDDEN, false); // Create title label - CHANGED to "AUTO SL TRADE PANEL" yOffset += 8; ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 9); ObjectSetString(0, labelName, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, labelName, OBJPROP_TEXT, "AUTO SL TRADE PANEL"); ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, false); // Create ADR value label - positioned on left yOffset += 22; ObjectCreate(0, adrValueLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, adrValueLabel, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, adrValueLabel, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, adrValueLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, adrValueLabel, OBJPROP_COLOR, clrYellow); ObjectSetInteger(0, adrValueLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, adrValueLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, adrValueLabel, OBJPROP_TEXT, "ADR (20): N/A"); ObjectSetInteger(0, adrValueLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, adrValueLabel, OBJPROP_HIDDEN, false); // Create Spread label - NEW, positioned on right side of same row ObjectCreate(0, spreadLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, spreadLabel, OBJPROP_XDISTANCE, CurrentPanelX + 110); ObjectSetInteger(0, spreadLabel, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, spreadLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, spreadLabel, OBJPROP_COLOR, clrAqua); ObjectSetInteger(0, spreadLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, spreadLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, spreadLabel, OBJPROP_TEXT, "Spread: 0"); ObjectSetInteger(0, spreadLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, spreadLabel, OBJPROP_HIDDEN, false); // Create SL value label (left column) yOffset += 18; int slYOffset = yOffset; ObjectCreate(0, slValueLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, slValueLabel, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, slValueLabel, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, slValueLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, slValueLabel, OBJPROP_COLOR, clrTomato); ObjectSetInteger(0, slValueLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, slValueLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, slValueLabel, OBJPROP_TEXT, "SL (200%): N/A"); ObjectSetInteger(0, slValueLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, slValueLabel, OBJPROP_HIDDEN, false); // Create Lot Size label (right column, same row as SL) ObjectCreate(0, lotSizeLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, lotSizeLabel, OBJPROP_XDISTANCE, CurrentPanelX + 110); ObjectSetInteger(0, lotSizeLabel, OBJPROP_YDISTANCE, slYOffset); ObjectSetInteger(0, lotSizeLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, lotSizeLabel, OBJPROP_COLOR, clrAqua); ObjectSetInteger(0, lotSizeLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, lotSizeLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, lotSizeLabel, OBJPROP_TEXT, "Lot: 0.00"); ObjectSetInteger(0, lotSizeLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, lotSizeLabel, OBJPROP_HIDDEN, false); // Create TP value label (left column) yOffset += 18; int tpYOffset = yOffset; ObjectCreate(0, tpValueLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, tpValueLabel, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, tpValueLabel, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, tpValueLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, tpValueLabel, OBJPROP_COLOR, clrLimeGreen); ObjectSetInteger(0, tpValueLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, tpValueLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, tpValueLabel, OBJPROP_TEXT, "TP (100%): N/A"); ObjectSetInteger(0, tpValueLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, tpValueLabel, OBJPROP_HIDDEN, false); // Create Net Position label (right column, same row as TP) ObjectCreate(0, netPosLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, netPosLabel, OBJPROP_XDISTANCE, CurrentPanelX + 110); ObjectSetInteger(0, netPosLabel, OBJPROP_YDISTANCE, tpYOffset); ObjectSetInteger(0, netPosLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, netPosLabel, OBJPROP_COLOR, clrYellow); ObjectSetInteger(0, netPosLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, netPosLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, netPosLabel, OBJPROP_TEXT, "Pos: 0.00"); ObjectSetInteger(0, netPosLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, netPosLabel, OBJPROP_HIDDEN, false); // NEW: Create Magic Number label (centered below Net Position) yOffset += 18; ObjectCreate(0, magicLabel, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, magicLabel, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, magicLabel, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, magicLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, magicLabel, OBJPROP_COLOR, clrOrange); ObjectSetInteger(0, magicLabel, OBJPROP_FONTSIZE, 8); ObjectSetString(0, magicLabel, OBJPROP_FONT, "Arial"); ObjectSetString(0, magicLabel, OBJPROP_TEXT, "Magic No: 12345"); ObjectSetInteger(0, magicLabel, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, magicLabel, OBJPROP_HIDDEN, false); // Create "APPLY SL or SO" button (left side, same size as BUY button) yOffset += 20; ObjectCreate(0, applySLButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, applySLButton, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, applySLButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, applySLButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, applySLButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, applySLButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, applySLButton, OBJPROP_BGCOLOR, Button_Color); ObjectSetInteger(0, applySLButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, applySLButton, OBJPROP_FONTSIZE, 7); ObjectSetString(0, applySLButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, applySLButton, OBJPROP_TEXT, "APPLY SL/SO"); ObjectSetInteger(0, applySLButton, OBJPROP_HIDDEN, false); // Create "HEDGE ALL" button (right side, same size as SELL button) ObjectCreate(0, hedgeAllButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, hedgeAllButton, OBJPROP_XDISTANCE, CurrentPanelX + 95); ObjectSetInteger(0, hedgeAllButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, hedgeAllButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, hedgeAllButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, hedgeAllButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, hedgeAllButton, OBJPROP_BGCOLOR, clrDarkOrange); ObjectSetInteger(0, hedgeAllButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, hedgeAllButton, OBJPROP_FONTSIZE, 8); ObjectSetString(0, hedgeAllButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, hedgeAllButton, OBJPROP_TEXT, "HEDGE ALL"); ObjectSetInteger(0, hedgeAllButton, OBJPROP_HIDDEN, false); // Trading buttons - BUY yOffset += 31; ObjectCreate(0, buyButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, buyButton, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, buyButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, buyButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, buyButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, buyButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, buyButton, OBJPROP_BGCOLOR, clrGreen); ObjectSetInteger(0, buyButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, buyButton, OBJPROP_FONTSIZE, 9); ObjectSetString(0, buyButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, buyButton, OBJPROP_TEXT, "BUY"); ObjectSetInteger(0, buyButton, OBJPROP_HIDDEN, false); // Trading buttons - SELL ObjectCreate(0, sellButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, sellButton, OBJPROP_XDISTANCE, CurrentPanelX + 95); ObjectSetInteger(0, sellButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, sellButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, sellButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, sellButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, sellButton, OBJPROP_BGCOLOR, clrRed); ObjectSetInteger(0, sellButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, sellButton, OBJPROP_FONTSIZE, 9); ObjectSetString(0, sellButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, sellButton, OBJPROP_TEXT, "SELL"); ObjectSetInteger(0, sellButton, OBJPROP_HIDDEN, false); // Trading buttons - BUY PEND yOffset += 31; ObjectCreate(0, buyPendButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, buyPendButton, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, buyPendButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, buyPendButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, buyPendButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, buyPendButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, buyPendButton, OBJPROP_BGCOLOR, clrDarkGreen); ObjectSetInteger(0, buyPendButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, buyPendButton, OBJPROP_FONTSIZE, 8); ObjectSetString(0, buyPendButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, buyPendButton, OBJPROP_TEXT, "BUY PEND"); ObjectSetInteger(0, buyPendButton, OBJPROP_HIDDEN, false); // Trading buttons - SELL PEND ObjectCreate(0, sellPendButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, sellPendButton, OBJPROP_XDISTANCE, CurrentPanelX + 95); ObjectSetInteger(0, sellPendButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, sellPendButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, sellPendButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, sellPendButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, sellPendButton, OBJPROP_BGCOLOR, clrMaroon); ObjectSetInteger(0, sellPendButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, sellPendButton, OBJPROP_FONTSIZE, 8); ObjectSetString(0, sellPendButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, sellPendButton, OBJPROP_TEXT, "SELL PEND"); ObjectSetInteger(0, sellPendButton, OBJPROP_HIDDEN, false); // Trading buttons - CLOSE BUY yOffset += 31; ObjectCreate(0, closeBuyButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, closeBuyButton, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, closeBuyButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, closeBuyButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, closeBuyButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, closeBuyButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, closeBuyButton, OBJPROP_BGCOLOR, clrOrangeRed); ObjectSetInteger(0, closeBuyButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, closeBuyButton, OBJPROP_FONTSIZE, 8); ObjectSetString(0, closeBuyButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, closeBuyButton, OBJPROP_TEXT, "CLOSE BUY"); ObjectSetInteger(0, closeBuyButton, OBJPROP_HIDDEN, false); // Trading buttons - CLOSE SELL ObjectCreate(0, closeSellButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, closeSellButton, OBJPROP_XDISTANCE, CurrentPanelX + 95); ObjectSetInteger(0, closeSellButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, closeSellButton, OBJPROP_XSIZE, 75); ObjectSetInteger(0, closeSellButton, OBJPROP_YSIZE, 26); ObjectSetInteger(0, closeSellButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, closeSellButton, OBJPROP_BGCOLOR, clrOrangeRed); ObjectSetInteger(0, closeSellButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, closeSellButton, OBJPROP_FONTSIZE, 8); ObjectSetString(0, closeSellButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, closeSellButton, OBJPROP_TEXT, "CLOSE SELL"); ObjectSetInteger(0, closeSellButton, OBJPROP_HIDDEN, false); // Trading buttons - CLOSE ALL (wider to match BUY+SELL combined) yOffset += 31; ObjectCreate(0, closeAllButton, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, closeAllButton, OBJPROP_XDISTANCE, CurrentPanelX + 10); ObjectSetInteger(0, closeAllButton, OBJPROP_YDISTANCE, yOffset); ObjectSetInteger(0, closeAllButton, OBJPROP_XSIZE, 160); ObjectSetInteger(0, closeAllButton, OBJPROP_YSIZE, buttonHeight); ObjectSetInteger(0, closeAllButton, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, closeAllButton, OBJPROP_BGCOLOR, clrDarkRed); ObjectSetInteger(0, closeAllButton, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, closeAllButton, OBJPROP_FONTSIZE, 9); ObjectSetString(0, closeAllButton, OBJPROP_FONT, "Arial Bold"); ObjectSetString(0, closeAllButton, OBJPROP_TEXT, "CLOSE ALL"); ObjectSetInteger(0, closeAllButton, OBJPROP_HIDDEN, false); ChartRedraw(); } //+------------------------------------------------------------------+ //| Check Symbol Basket 5 and Close if Target Reached | //+------------------------------------------------------------------+ void CheckSymbolBasket5() { if(!SymbolTradesBelongToBasket5) return; double cashUpl = 0; double pipsUpl = 0; int tradeCount = 0; double point = MarketInfo(Symbol(), MODE_POINT); double pipValue = point; if(Digits == 3 || Digits == 5) pipValue = point * 10; // Calculate total profit and pips for all symbol trades for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != (Magic_Number + magic_shift)) continue; if(OrderType() >= 2) continue; // Only market orders tradeCount++; // Calculate cash profit double profit = OrderProfit() + OrderCommission(); if(Use_Swap_in_TP5) profit += OrderSwap(); cashUpl += profit; // Calculate pips profit double pipProfit = 0; if(OrderType() == OP_BUY) pipProfit = (Bid - OrderOpenPrice()) / pipValue; else if(OrderType() == OP_SELL) pipProfit = (OrderOpenPrice() - Ask) / pipValue; pipsUpl += pipProfit; } // Check if basket criteria are met if(tradeCount < SymbolMinTradesOpenForBasket5) return; if(tradeCount > SymbolMaxTradesOpenForBasket5) return; bool targetReached = false; // Check pips target if(SymbolTargetOnPips5 && pipsUpl >= SymbolBasketPips5) targetReached = true; // Check cash targets double cashTarget = SymbolBasketCashTakeProfit5; // Positive percentage target (profit target) if(BasketProfitPercentTarget5 > 0) { cashTarget = AccountEquity() * BasketProfitPercentTarget5 / 100.0; if(cashUpl >= cashTarget) targetReached = true; } // Negative percentage target (loss limit / stop-loss for basket) if(BasketLossPercentTarget5 < 0) { double lossLimit = AccountEquity() * BasketLossPercentTarget5 / 100.0; if(cashUpl <= lossLimit) targetReached = true; } // Fixed cash target (only if no percentage targets are active) if(BasketProfitPercentTarget5 == 0 && BasketLossPercentTarget5 >= 0) { if(cashUpl >= cashTarget) targetReached = true; } // Close trades if target reached if(targetReached) CloseSymbolBasket5Trades(); } //+------------------------------------------------------------------+ //| Close Symbol Basket 5 Trades with Partial Closure | //+------------------------------------------------------------------+ void CloseSymbolBasket5Trades() { // If OrderCloseBy is enabled, use hedging method if(BasketClosesByOrderCloseBy5) { CreateHedgeOrderForBasket(); ReconcileHedgeOrdersForBasket(); return; } // Otherwise, use partial closure method // Percentages for each trade double percentages[12]; percentages[0] = Percentage5OfTrade1ToClose; percentages[1] = Percentage5OfTrade2ToClose; percentages[2] = Percentage5OfTrade3ToClose; percentages[3] = Percentage5OfTrade4ToClose; percentages[4] = Percentage5OfTrade5ToClose; percentages[5] = Percentage5OfTrade6ToClose; percentages[6] = Percentage5OfTrade7ToClose; percentages[7] = Percentage5OfTrade8ToClose; percentages[8] = Percentage5OfTrade9ToClose; percentages[9] = Percentage5OfTrade10ToClose; percentages[10] = Percentage5OfTrade11ToClose; percentages[11] = Percentage5OfTrade12ToClose; // Collect all trades sorted by open time int tickets[]; datetime times[]; int count = 0; for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != (Magic_Number + magic_shift)) continue; if(OrderType() >= 2) continue; count++; ArrayResize(tickets, count); ArrayResize(times, count); tickets[count-1] = OrderTicket(); times[count-1] = OrderOpenTime(); } // Sort by open time (earliest first) for(int i = 0; i < count - 1; i++) { for(int j = i + 1; j < count; j++) { if(times[j] < times[i]) { int tempTicket = tickets[i]; datetime tempTime = times[i]; tickets[i] = tickets[j]; times[i] = times[j]; tickets[j] = tempTicket; times[j] = tempTime; } } } // Close trades with respective percentages for(int i = 0; i < count; i++) { if(!OrderSelect(tickets[i], SELECT_BY_TICKET)) continue; double percentage = (i < 12) ? percentages[i] : 100.0; double lotsToClose = OrderLots() * percentage / 100.0; // Normalize lot size double minLot = MarketInfo(Symbol(), MODE_MINLOT); double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP); lotsToClose = MathMax(lotsToClose, minLot); lotsToClose = NormalizeDouble(lotsToClose / lotStep, 0) * lotStep; // Close the trade bool result = OrderClose(OrderTicket(), lotsToClose, OrderClosePrice(), 3, clrNONE); if(result) Print("Basket5: Closed ", percentage, "% of trade #", OrderTicket()); } } //+------------------------------------------------------------------+ //| Create Hedge Order for Basket (Net Position) | //+------------------------------------------------------------------+ void CreateHedgeOrderForBasket() { double netBuyLots = 0; double netSellLots = 0; int currentMagic = Magic_Number + magic_shift; // Calculate net position for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; if(OrderType() >= 2) continue; if(OrderType() == OP_BUY) netBuyLots += OrderLots(); else if(OrderType() == OP_SELL) netSellLots += OrderLots(); } double netPosition = netBuyLots - netSellLots; // Create hedge order for net position if(netPosition > 0) { // Net long position - create sell hedge int ticket = OrderSend(Symbol(), OP_SELL, netPosition, Bid, 3, 0, 0, "BASKET-HEDGE", currentMagic, 0, clrOrange); if(ticket < 0) Print("Failed to create basket hedge SELL order - Error: ", GetLastError()); } else if(netPosition < 0) { // Net short position - create buy hedge int ticket = OrderSend(Symbol(), OP_BUY, MathAbs(netPosition), Ask, 3, 0, 0, "BASKET-HEDGE", currentMagic, 0, clrOrange); if(ticket < 0) Print("Failed to create basket hedge BUY order - Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Reconcile Hedge Orders for Basket (Close Opposing Pairs) | //+------------------------------------------------------------------+ void ReconcileHedgeOrdersForBasket() { int currentMagic = Magic_Number + magic_shift; for(int i = OrdersTotal() - 1; i > 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; if(OrderType() >= 2) continue; int type = OrderType(); int ticket = OrderTicket(); // Find opposing order to close by for(int j = i - 1; j >= 0; j--) { if(!OrderSelect(j, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderSymbol() != Symbol()) continue; if(Manage_Only_Panel_Orders && OrderMagicNumber() != currentMagic) continue; if(OrderType() >= 2) continue; if(OrderType() == type) continue; // Same direction // Close by opposing order if(OrderCloseBy(OrderTicket(), ticket)) { Print("Basket5: Closed orders #", OrderTicket(), " and #", ticket, " by OrderCloseBy"); i = OrdersTotal(); // Restart loop break; } } } } //+------------------------------------------------------------------+