//+------------------------------------------------------------------+ //| MartingaleEA_XAUUSD.mq5 | //| Copyright 2025, Your Name | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Your Name" #property link "https://www.mql5.com" #property version "1.00" #include // Include Trade library //--- Input parameters input double InitialVolume = 0.01; // Initial Volume (x) for XAUUSD input double VolumeMultiplier = 1.5; // Volume Multiplier input double TakeProfitPips = 50; // Take Profit (pips) for XAUUSD input double PriceStepPips = 20; // Price Step for new orders (pips) input double MaxSpreadPips = 5; // Maximum allowable spread (pips) //--- Global variables double PipValue; // Value of 1 pip in points CTrade trade; // Trade object for order operations double initialBuyTP = 0; // Store TP of initial Buy order double initialBuyPrice = 0; // Store price of initial Buy order double initialSellPrice =0; double initialSellTP = 0; int priceDigits; // Digits for price normalization ulong lastDealTicket = 0; // Track last processed deal ticket //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Calculate pip value based on symbol's point PipValue = SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 10; // 1 pip = 10 points for XAUUSD priceDigits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); // Get symbol digits for normalization trade.SetExpertMagicNumber(123456); // Set unique magic number return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Normalize volume to comply with broker's requirements | //+------------------------------------------------------------------+ double NormalizeVolume(double volume) { double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); // Normalize volume to the nearest step double normalized = MathRound(volume / volumeStep) * volumeStep; // Ensure volume is within min/max limits normalized = MathMax(minVolume, MathMin(maxVolume, normalized)); // Round to correct precision int digits = (int)MathCeil(-MathLog10(volumeStep)); return NormalizeDouble(normalized, digits); } //+------------------------------------------------------------------+ //| Normalize price to comply with broker's tick size | //+------------------------------------------------------------------+ double NormalizePrice(double price) { double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); return NormalizeDouble(price, priceDigits); } //+------------------------------------------------------------------+ //| Check if a pending order already exists at a specific price | //+------------------------------------------------------------------+ bool PendingOrderExists(double price, ENUM_ORDER_TYPE orderType) { for(int i = OrdersTotal() - 1; i >= 0; i--) { ulong ticket = OrderGetTicket(i); if(OrderSelect(ticket)) { if(OrderGetString(ORDER_SYMBOL) == _Symbol && OrderGetInteger(ORDER_TYPE) == orderType) { if(MathAbs(OrderGetDouble(ORDER_PRICE_OPEN) - price) < PipValue) return true; } } } return false; } //+------------------------------------------------------------------+ //| Cancel all pending Sell Stop orders | //+------------------------------------------------------------------+ void CancelPendingStops() { for(int i = OrdersTotal() - 1; i >= 0; i--) { ulong ticket = OrderGetTicket(i); if(OrderSelect(ticket)) { if(OrderGetString(ORDER_SYMBOL) == _Symbol) { trade.OrderDelete(ticket); } } } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Check spread double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) / 10; // Convert to pips if(spread > MaxSpreadPips) return; // Skip if spread is too high // Check if there are no open positions if(PositionsTotal() == 0) { // Cancel any remaining Sell Stop orders CancelPendingStops(); // Open initial Buy order if no pending orders if(OrdersTotal() == 0) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double tp = NormalizePrice(ask + TakeProfitPips * PipValue); double normalizedVolume = NormalizeVolume(InitialVolume); // Place Sell Stop order immediately double sellStopPrice = NormalizePrice(bid - PriceStepPips * PipValue); double sellTP = NormalizePrice(sellStopPrice - TakeProfitPips * PipValue); double sellVolume = NormalizeVolume(InitialVolume * VolumeMultiplier); if(trade.Buy(normalizedVolume, _Symbol, ask, sellTP, tp, "Initial Buy")) { initialBuyTP = tp; // Store normalized TP of initial Buy order initialBuyPrice = ask; // Store initial Buy price trade.SellStop(sellVolume, sellStopPrice, _Symbol, tp, sellTP, 0, 0, "Sell Stop Hedge"); initialSellPrice = sellStopPrice; initialSellTP = sellTP; } } } else { // Process open positions and pending orders ManagePositions(); } } //+------------------------------------------------------------------+ //| Expert trade event function | //+------------------------------------------------------------------+ void OnTrade() { // Select history for the current symbol HistorySelect(0, TimeCurrent()); // Loop through deals to find the latest one for(int i = HistoryDealsTotal() - 1; i >= 0; i--) { ulong dealTicket = HistoryDealGetTicket(i); if(dealTicket > lastDealTicket && HistoryDealSelect(dealTicket)) { if(HistoryDealGetString(dealTicket, DEAL_SYMBOL) == _Symbol) { // Check if deal was closed by TP if(HistoryDealGetInteger(dealTicket, DEAL_REASON) == DEAL_REASON_TP) { // Close all remaining positions CloseAllPositions(); // Cancel all pending orders CancelPendingStops(); // Update last processed deal ticket lastDealTicket = dealTicket; break; } } } } } //+------------------------------------------------------------------+ //| Close all open positions | //+------------------------------------------------------------------+ void CloseAllPositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol) { trade.PositionClose(ticket); } } } } //+------------------------------------------------------------------+ //| Manage open positions and pending orders | //+------------------------------------------------------------------+ void ManagePositions() { double lastVolume = InitialVolume; int buyCount = 0; int sellCount = 0; bool sellStopTriggered = false; // Loop through all open positions for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol) { if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { buyCount++; if(buyCount == 1) // First Buy order { initialBuyPrice = PositionGetDouble(POSITION_PRICE_OPEN); initialBuyTP = PositionGetDouble(POSITION_TP); } lastVolume = MathMax(lastVolume, PositionGetDouble(POSITION_VOLUME)); } else // Sell position { sellCount++; lastVolume = MathMax(lastVolume, PositionGetDouble(POSITION_VOLUME)); } } } } double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Place Buy Stop order if Sell Stop was triggered and no Buy Stop exists at initialBuyPrice if(initialBuyPrice > 0 && !PendingOrderExists(initialBuyPrice, ORDER_TYPE_BUY_STOP) && buyCount == sellCount) { double newVolume = NormalizeVolume(lastVolume * VolumeMultiplier); trade.BuyStop(newVolume, initialBuyPrice, _Symbol, initialSellTP, initialBuyTP, 0, 0, "Additional Buy Stop"); } // Place new Sell Stop orders after a Buy Stop is triggered if(buyCount > 1 && !PendingOrderExists(initialSellPrice, ORDER_TYPE_SELL_STOP) && (buyCount - sellCount) == 1) { double sellVolume = NormalizeVolume(lastVolume * VolumeMultiplier); trade.SellStop(sellVolume, initialSellPrice, _Symbol, initialBuyTP, initialSellTP, 0, 0, "Sell Stop Hedge"); } } //+------------------------------------------------------------------+ //| Get first Buy order ticket | //+------------------------------------------------------------------+ ulong GetFirstBuyTicket() { for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { return ticket; } } } return 0; } //+------------------------------------------------------------------+