MQL4 Trailing Stop: How to Code It?

This article delves into implementing trailing stops in MQL4, the programming language for MetaTrader 4 Expert Advisors (EAs). We’ll cover the core concepts, essential code, and advanced techniques for creating effective trailing stop strategies.

Understanding Trailing Stops in MQL4

What is a Trailing Stop?

A trailing stop is a dynamic stop-loss order that adjusts automatically as the price of the asset moves in a favorable direction. It aims to protect profits while allowing the trade to continue benefiting from further price movements. Unlike a fixed stop-loss, a trailing stop follows the price, tightening the stop as the trade becomes more profitable.

Benefits of Using Trailing Stops

  • Profit Protection: Locks in profits as the price moves favorably.
  • Risk Management: Limits potential losses by dynamically adjusting the stop-loss level.
  • Flexibility: Adapts to changing market conditions and price volatility.
  • Automation: Once implemented in an EA, the trailing stop adjusts automatically, freeing up manual monitoring.

Limitations of Trailing Stops in Automated Trading

  • Whipsaws: Susceptible to being triggered prematurely by short-term price fluctuations (‘whipsaws’) especially in volatile markets.
  • Parameter Optimization: Requires careful optimization of the trailing stop distance to avoid premature exits or insufficient protection.
  • Broker Limitations: Some brokers might have limitations on the minimum trailing stop distance allowed.

Basic MQL4 Code Structure for a Trailing Stop

Essential MQL4 Functions for Trailing Stops (OrderSelect, OrderModify)

The two fundamental functions are:

  • OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES): Selects a specific order based on its ticket number.
  • OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color): Modifies an existing order’s parameters, including the stop-loss level. Important: price, takeprofit, expiration, and arrow_color are still required even when only modifying the stoploss.

Key Variables for Trailing Stop Implementation (Pip Value, Stop Loss Level)

  • Point: Represents the smallest price increment for the currency pair. This is critical for calculating stop-loss levels in pips.
  • MarketInfo(Symbol(), MODE_TICKVALUE): Returns the tick value of the current symbol.
  • StopLoss: The current stop-loss level of the order.
  • TrailingStop: The desired trailing stop distance in pips.
  • OrderType(): Returns the order type. Used to determine if it’s a buy or sell order.

Initial Setup and Order Selection

Before implementing the trailing stop logic, you need to select the relevant order. This is typically done within the OnTick() function of your EA. Here’s an example:

int totalOrders = OrdersTotal();
for (int i = 0; i < totalOrders; i++) {
  if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
    if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {
      // Trailing stop logic will go here
    }
  }
}

Replace MagicNumber with your EA’s unique identifier. This ensures that the EA only modifies its own orders.

Implementing a Simple Trailing Stop Algorithm

Calculating the New Stop Loss Level

The core of the trailing stop algorithm involves calculating the new stop-loss level based on the current price and the specified trailing stop distance. The calculation differs slightly for buy and sell orders.

For Buy orders:

double newStopLoss = Ask - TrailingStop * Point;

For Sell orders:

double newStopLoss = Bid + TrailingStop * Point;

Modifying the Stop Loss Using OrderModify()

Once the new stop-loss level is calculated, use OrderModify() to update the order. However, check that the new stop loss is more favorable than current one before updating.

Handling Different Order Types (Buy/Sell)

int ticket = OrderTicket();
double currentPrice = (OrderType() == OP_BUY) ? Ask : Bid;
double currentStopLoss = OrderStopLoss();
double newStopLoss;

if (OrderType() == OP_BUY) {
  newStopLoss = Ask - TrailingStop * Point;
  if (newStopLoss > currentStopLoss && Ask - OrderOpenPrice() > TrailingStop * Point) {
    OrderModify(ticket, OrderOpenPrice(), newStopLoss, OrderTakeProfit(), OrderExpiration(), White);
  }
} else if (OrderType() == OP_SELL) {
  newStopLoss = Bid + TrailingStop * Point;
  if (newStopLoss < currentStopLoss && OrderOpenPrice() - Bid > TrailingStop * Point) {
    OrderModify(ticket, OrderOpenPrice(), newStopLoss, OrderTakeProfit(), OrderExpiration(), White);
  }
}

This code snippet demonstrates the complete process of calculating and modifying the stop-loss level based on the order type. The check Ask - OrderOpenPrice() > TrailingStop * Point (and its counterpart for SELL orders) ensures the trailing stop is activated only after the price has moved a certain distance in profit.

Advanced Trailing Stop Techniques

Trailing Stop Based on Price Action (e.g., Moving Averages, High/Low)

Instead of using a fixed pip value, the trailing stop can be based on dynamic price action indicators. For instance:

  • Moving Average: Set the stop-loss a certain distance below a moving average for buy orders or above for sell orders.
  • High/Low: Use the high or low of a previous period to determine the stop-loss level. This can be implemented using the iHigh() and iLow() functions.

Trailing Stop with Breakeven

A breakeven trailing stop moves the stop-loss to the order’s open price once the price reaches a certain profit level. This guarantees a risk-free trade.

if (OrderType() == OP_BUY && Ask - OrderOpenPrice() > BreakevenPips * Point) {
  OrderModify(ticket, OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), OrderExpiration(), White);
}

if (OrderType() == OP_SELL && OrderOpenPrice() - Bid > BreakevenPips * Point) {
  OrderModify(ticket, OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), OrderExpiration(), White);
}

Dynamic Trailing Stop (ATR-Based)

Using the Average True Range (ATR) indicator to dynamically adjust the trailing stop distance based on market volatility can be more effective than a fixed value. iATR() is used to calculate the average true range over a specified period.

Testing and Optimizing Your MQL4 Trailing Stop

Backtesting with the Strategy Tester

The MetaTrader 4 Strategy Tester is crucial for evaluating the performance of your trailing stop strategy. Backtest your EA over different time periods and currency pairs to assess its effectiveness.

Optimizing Parameters for Different Market Conditions

Experiment with different trailing stop distances, breakeven levels, and ATR periods to find the optimal settings for various market conditions. The Strategy Tester’s optimization feature can automate this process.

Common Errors and Debugging Tips

  • Invalid Stop Loss: Ensure that the calculated stop-loss level is valid (i.e., not too close to the current price and within the broker’s limitations).
  • Order Modification Errors: Check the return value of OrderModify() for errors. Use GetLastError() to identify the specific error code. Common errors include ERR_INVALID_PRICE, ERR_TRADE_NOT_ALLOWED, and ERR_TOO_MANY_REQUESTS.
  • Magic Number Conflicts: Make sure your EA’s magic number is unique to prevent conflicts with other EAs. If EAs have the same magic number, there will be conflicting modifications that can result in unexpected behavior.

By understanding these concepts and implementing these techniques, you can effectively code trailing stops in MQL4 to enhance your trading strategies.


Leave a Reply