MQL5: How to Set Take Profit in Your Trading Strategy?

Introduction to Take Profit in MQL5

What is Take Profit (TP) and Why is it Important?

Take Profit (TP) is a crucial order parameter that specifies the price level at which an open position will be automatically closed for a profit. It is, alongside Stop Loss, a fundamental risk management tool. Setting an appropriate Take Profit level is vital for:

  • Profit Locking: Securing profits when the price reaches a pre-defined favorable level.
  • Risk Management: Defining the maximum potential profit, contributing to a consistent risk-reward ratio.
  • Trading Automation: Enabling Expert Advisors (EAs) to execute trades automatically based on predefined rules, including profit targets.

Basic Concepts of Order Management in MQL5

MQL5 offers a robust order management system. Understanding the core concepts is essential before implementing Take Profit strategies. Key elements include:

  • Order Ticket: A unique identifier for each order.
  • Order Type: Specifies the type of order (e.g., Buy, Sell).
  • Order Open Price: The price at which the order was executed.
  • Stop Loss (SL): The price level at which the order will be closed to limit losses.
  • Take Profit (TP): The price level at which the order will be closed to secure profits.
  • OrderSend() Function: Used to submit a new order to the trading server.
  • OrderModify() Function: Used to modify the parameters of an existing order (e.g., SL, TP).

Setting Take Profit Using MQL5 Functions

Using OrderSend() Function to Set Initial Take Profit

The OrderSend() function is the primary means of opening a new position. The Take Profit level is specified as one of its parameters. The price must be provided in normalized format (MarketInfo(Symbol, MODEPOINT)).

MqlTradeRequest request;
MqlTradeResult  result;

double symbol_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double symbol_bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

// Example: Place a buy order with a Take Profit 50 points above the ask price
double takeProfit = symbol_ask + 50 * point;

request.action   = TRADE_ACTION_DEAL;
request.symbol   = _Symbol;
request.type     = ORDER_TYPE_BUY;
request.volume   = 0.01; // Example volume
request.price    = symbol_ask;
request.sl       = 0;     // No Stop Loss for now
request.tp       = NormalizeDouble(takeProfit, digits); // Take Profit price
request.deviation= 10;    // Allowable price deviation
request.magic    = 12345; // Magic number for the EA
request.comment  = "Buy Order with TP";

if(!OrderSend(request, result))
  PrintFormat("OrderSend failed with error %d",result.retcode);

Modifying Take Profit Levels with OrderModify()

To adjust the Take Profit of an existing order, use the OrderModify() function. You’ll need the order’s ticket number. The function requires the new SL and TP values. The key point is that the OrderModify function requires the ticket of the order, rather than its position. In MQL4 you have OrderModify and you iterate through all orders in the loop and use OrderSymbol()==Symbol() to check the order. But in MQL5 you must use PositionSelect(_Symbol) and PositionGetTicket() to find out a ticket and use this ticket in the OrderModify function.

// Example: Modify the Take Profit of an existing order
long ticket = PositionGetTicket(0);
if(ticket != 0)
{
   double newTakeProfit = symbol_ask + 100 * point; // New TP 100 points above ask
   double currentStopLoss = PositionGetDouble(POSITION_SL);

   request.action = TRADE_ACTION_MODIFY;
   request.ticket = ticket;
   request.sl     = currentStopLoss;  // Keep the existing Stop Loss
   request.tp     = NormalizeDouble(newTakeProfit, digits); // New Take Profit price
   request.price = symbol_ask; //Price is required for modify

   if(!OrderSend(request, result))
     PrintFormat("OrderModify failed with error %d",result.retcode);
}
else
   Print("No open position found!");

Understanding Take Profit in Points vs. Price

It’s crucial to understand the difference between specifying Take Profit in points versus price. When using points, you’re defining the distance from the order’s open price. This needs to be converted to an actual price based on the current market price and point size. Always use NormalizeDouble() function to adjust the TP price according to the SYMBOL_DIGITS to avoid invalid stops errors.

Dynamic Take Profit Strategies

Trailing Take Profit Based on Price Action

A trailing Take Profit adjusts automatically as the price moves in a favorable direction. This allows you to capture more profit if the trend continues. Implement this by periodically checking the current price and modifying the TP if it meets your criteria.

Calculating Take Profit Based on Risk-Reward Ratio

Determine the Take Profit level based on a predefined risk-reward ratio. For instance, if your risk (Stop Loss distance) is 50 points, and you aim for a 1:2 risk-reward ratio, set the Take Profit 100 points away from the entry price in the anticipated direction.

Implementing Take Profit Based on Technical Indicators

Use technical indicators like Moving Averages, RSI, or Fibonacci levels to determine dynamic Take Profit levels. For example, you could set the TP at a key Fibonacci retracement level or when the price crosses a Moving Average.

Advanced Take Profit Techniques and Considerations

Using Take Profit with Virtual Trades and Backtesting

When backtesting, ensure your Take Profit logic is robust and considers historical data. Use virtual trades (without actually executing them) to test different Take Profit strategies. Proper backtesting and forward testing are vital for verifying a Take Profit strategy’s effectiveness.

Optimizing Take Profit Levels for Different Market Conditions

Market volatility and trading ranges influence the optimal Take Profit levels. Consider using Average True Range (ATR) or other volatility indicators to adapt your TP strategy to changing market dynamics. What is optimum for ranging market, might not work for trending one.

Handling Take Profit in Expert Advisors (EAs)

In EAs, carefully handle Take Profit updates and potential errors. Implement error checking and logging to ensure your TP logic functions correctly, and properly handles situations like insufficient free margin or invalid stops.

Common Mistakes to Avoid When Setting Take Profit

  • Not using NormalizeDouble(): This will likely lead to invalid stops errors from the trade server.
  • Ignoring slippage: Account for potential slippage when setting the TP, especially during volatile periods.
  • Using excessively tight Take Profit: Might result in prematurely closing positions due to minor price fluctuations.
  • Failing to adjust TP based on market conditions: A static TP strategy can perform poorly in changing markets.
  • Incorrectly calculating TP based on points: Ensure correct conversion from points to price.

Practical Examples and Code Snippets

Example 1: Simple Fixed Take Profit Implementation

This example sets a fixed Take Profit of 100 points for buy orders:

void OnTick()
{
   double symbol_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   if (/* Your entry condition here */)
   {
      double takeProfit = symbol_ask + 100 * point;  // Fixed 100 points TP

      MqlTradeRequest request;
      MqlTradeResult  result;

      request.action   = TRADE_ACTION_DEAL;
      request.symbol   = _Symbol;
      request.type     = ORDER_TYPE_BUY;
      request.volume   = 0.01;
      request.price    = symbol_ask;
      request.sl       = 0;
      request.tp       = NormalizeDouble(takeProfit, digits);
      request.deviation= 10;
      request.magic    = 12345;
      request.comment  = "Fixed TP Buy Order";

      if(!OrderSend(request, result))
         PrintFormat("OrderSend failed with error %d",result.retcode);
   }
}

Example 2: Dynamic Take Profit Based on ATR Indicator

This example calculates the Take Profit based on the Average True Range (ATR) indicator:

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  Red

input int ATRPeriod = 14;  // ATR Period

double ATRBuffer[];

int OnInit()
{
   SetIndexBuffer(0, ATRBuffer, INDICATOR_DATA);
   IndicatorSetInteger(INDICATOR_DIGITS, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
   return(INIT_SUCCEEDED);
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   int start = prev_calculated - 1;
   if (start < 0)
      start = 0;

   for (int i = start; i < rates_total; i++)
   {
      ATRBuffer[i] = iATR(_Symbol, 0, ATRPeriod, i);
   }

   return(rates_total);
}

void OnTick()
{
   double symbol_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   double atrValue = iATR(_Symbol, 0, ATRPeriod, 0); // Current ATR value

   if (/* Your entry condition here */)
   {
      double takeProfit = symbol_ask + 2 * atrValue;  // TP is 2 times the ATR

      MqlTradeRequest request;
      MqlTradeResult  result;

      request.action   = TRADE_ACTION_DEAL;
      request.symbol   = _Symbol;
      request.type     = ORDER_TYPE_BUY;
      request.volume   = 0.01;
      request.price    = symbol_ask;
      request.sl       = 0;
      request.tp       = NormalizeDouble(takeProfit, digits);
      request.deviation= 10;
      request.magic    = 12345;
      request.comment  = "ATR-based TP Buy Order";

      if(!OrderSend(request, result))
         PrintFormat("OrderSend failed with error %d",result.retcode);
   }
}

Example 3: Take Profit Adjustment in a Trading Robot

This example demonstrates adjusting the Take Profit based on price movement:

void OnTick()
{
   static long ticket = 0;
   double symbol_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double symbol_bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   static double initialAsk = 0.0;

   if (/* Your entry condition here and no position is open */ && ticket == 0)
   {
      MqlTradeRequest request;
      MqlTradeResult  result;

      request.action   = TRADE_ACTION_DEAL;
      request.symbol   = _Symbol;
      request.type     = ORDER_TYPE_BUY;
      request.volume   = 0.01;
      request.price    = symbol_ask;
      request.sl       = 0;
      request.tp       = NormalizeDouble(symbol_ask + 50 * point, digits);
      request.deviation= 10;
      request.magic    = 12345;
      request.comment  = "Initial TP Buy Order";

      if(OrderSend(request, result))
      {
         PrintFormat("OrderSend successful");
         ticket = result.deal;
         initialAsk = symbol_ask;
      }
      else
      {
         PrintFormat("OrderSend failed with error %d",result.retcode);
      }
   }

   if(ticket != 0)
   {
      double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      if(currentAsk > initialAsk + 20 * point)
      {
         // Adjust TP if price moved favorably by 20 points
         MqlTradeRequest request;
         MqlTradeResult  result;

         double newTakeProfit = currentAsk + 50 * point; // Move TP higher
         double currentStopLoss = PositionGetDouble(POSITION_SL);

         request.action = TRADE_ACTION_MODIFY;
         request.ticket = ticket;
         request.sl     = currentStopLoss;
         request.tp     = NormalizeDouble(newTakeProfit, digits);
         request.price = symbol_ask;

         if(!OrderSend(request, result))
         {
           PrintFormat("OrderModify failed with error %d",result.retcode);
         }
         else
         {
           PrintFormat("Take profit updated");
         }
      }
   }
}

Leave a Reply