OrderCalcProfit used to calculate prices for TakeProfit and StopLoss gives wrong values

 

Hi everyone,

I've read some topics on this function, but I'm really stuck with this situation. I wrote two functions to get the takeprofit price and the stoploss price for a position that is already opened manually. 
Takeprofit and Stoploss prices are calculated knowing the details of the opened position (opening price, volume), the desired profit and loss in the account currency and a closed price that is 500 points distant from the opening price of the position.

The problem is that the function for calculating the SL is working perfectly, the function calculating the TP is giving values that are distant from the desired target (the value in account currency).

The calculation is done with the intention to "revert" the OrderCalcSize function: calculating a profit having a certain closing price (in my case I use 500 ticks) and then rescaling this value based on the ratio between desired profit and profit obtained via the OrderCalcProfit function (like suggested from @Fernando Carreiro for calculating the size of a position knowing the risk).

I know that the conversion from the position enum to the order enum in order to make it work with the OrderCalcProfit function is not nice, but in my opinion it makes sense and it was the only idea to get it working. 

Let me know if you have suggestions for this problem or any better method to obtain the desiderd TP or SL price based on the desired risk of a position


PS. I'm evaluating the correctness of the calculations after the prices of TP and SL from these two functions are sent and placed on the market as TP and SL for the opened position and I hover with the mouse on the placed TP and SL lines and I see the expected profit and expected loss when the price will trigger those prices 

//| m_sym                : Symbol name                       
//| m_risk_money     : Desired money amount         
//| m_pos_price       : Position opening price                                    
//| m_pos_vol          : Position volume                                           
//| m_pos_type        : Position type                                             
//| m_price              : TP price, already rounded                                 
bool TPPriceCalc(const string m_sym, const double m_risk_money, const double m_pos_price, const double m_pos_vol, ENUM_POSITION_TYPE m_pos_type, double &m_price)
{
   string m_symbol = StringLen(m_sym) > 0 ? m_sym : Symbol();   
   int m_mult = (m_pos_type == POSITION_TYPE_BUY) ? 1 : -1;
   
   double m_tick_size = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_SIZE);
   if(m_tick_size == 0)
      return false;
   
   double m_max_price = m_pos_price + 500 * m_mult * m_tick_size;
   double m_max_money = 0;
   if( OrderCalcProfit( (m_pos_type == POSITION_TYPE_BUY ? ORDER_TYPE_BUY : ORDER_TYPE_SELL), m_symbol, m_pos_vol, m_pos_price, m_max_price, m_max_money) && m_max_money > 0)
   {
      double tp_points = m_risk_money * 500 / MathAbs(m_max_money);  // tp_points : 500 = risk_money : max_money (profit obtained with a price movement of 500 ticks) 
      m_price = m_pos_price + m_mult * tp_points * m_tick_size;
      m_price = MathRound(m_price / m_tick_size) * m_tick_size;   
  
      return true;
   }   
      
   return false;
}


//| m_sym            : Symbol name                                               
//| m_risk_money     : Desired money amount                                      
//| m_pos_price      : Position opening price                                    
//| m_pos_vol        : Position volume                                           
//| m_pos_type       : Position type                                             
//| m_price          : SL price, already rounded                                 
bool SLPriceCalc(const string m_sym, const double m_risk_money, const double m_pos_price, const double m_pos_vol, ENUM_POSITION_TYPE m_pos_type, double &m_price)
{
   string m_symbol = StringLen(m_sym) > 0 ? m_sym : Symbol();   
   int m_mult = (m_pos_type == POSITION_TYPE_BUY) ? 1 : -1;
   
   double m_tick_size = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_SIZE);
   if(m_tick_size == 0)
      return false;
         
   double m_max_price = m_pos_price - 500 * m_mult * m_tick_size;
   double m_max_money = 0;
   if( OrderCalcProfit( (m_pos_type == POSITION_TYPE_BUY ? ORDER_TYPE_BUY : ORDER_TYPE_SELL), m_symbol, m_pos_vol, m_pos_price, m_max_price, m_max_money) && m_max_money < 0)
   {   
      double sl_points = m_risk_money * 500 / MathAbs(m_max_money);  // tp_points : 500 = risk_money : max_money (profit obtained with a price movement of 500 ticks) 
      m_price = m_pos_price - m_mult * sl_points * m_tick_size;   
      m_price = MathRound(m_price / m_tick_size) * m_tick_size;
   
      return true;
   }
   
   return false;
}


 

 
Luigi Rossi:

The idea makes sense and is actually pretty clever. Using a 500-tick reference to estimate TP based on a money amount is a practical approach.

It's a bit strange that it works well for SL but not for TP. That might come from small differences due to rounding, spread, or how OrderCalcProfit calculates profit exactly.

Maybe adding a small final adjustment (like a quick iteration) could help get the TP closer to the expected result.

 
Luigi Rossi:

Hi everyone,

I've read some topics on this function, but I'm really stuck with this situation. I wrote two functions to get the takeprofit price and the stoploss price for a position that is already opened manually. 
Takeprofit and Stoploss prices are calculated knowing the details of the opened position (opening price, volume), the desired profit and loss in the account currency and a closed price that is 500 points distant from the opening price of the position.

The problem is that the function for calculating the SL is working perfectly, the function calculating the TP is giving values that are distant from the desired target (the value in account currency).

The calculation is done with the intention to "revert" the OrderCalcSize function: calculating a profit having a certain closing price (in my case I use 500 ticks) and then rescaling this value based on the ratio between desired profit and profit obtained via the OrderCalcProfit function (like suggested from @Fernando Carreiro for calculating the size of a position knowing the risk).

I know that the conversion from the position enum to the order enum in order to make it work with the OrderCalcProfit function is not nice, but in my opinion it makes sense and it was the only idea to get it working. 

Let me know if you have suggestions for this problem or any better method to obtain the desiderd TP or SL price based on the desired risk of a position


PS. I'm evaluating the correctness of the calculations after the prices of TP and SL from these two functions are sent and placed on the market as TP and SL for the opened position and I hover with the mouse on the placed TP and SL lines and I see the expected profit and expected loss when the price will trigger those prices 


 

There has been discussions about this phenomenon.

Take a look at this link. It is actually a rabbithole, and requires you to build your own functions with proper calculations/namings.

https://www.mql5.com/en/forum/441959/45091676#comment_45091676

Next challenge you will come across is poor broker configurations, like missing ticksize and tick value.

Then you will find out about margin calculations and the mess around that.

But, mql supports all you need to make it work, it just takes "some" effort.
 
Luigi Rossi:

Hi everyone,

I've read some topics on this function, but I'm really stuck with this situation. I wrote two functions to get the takeprofit price and the stoploss price for a position that is already opened manually. 
Takeprofit and Stoploss prices are calculated knowing the details of the opened position (opening price, volume), the desired profit and loss in the account currency and a closed price that is 500 points distant from the opening price of the position.

The problem is that the function for calculating the SL is working perfectly, the function calculating the TP is giving values that are distant from the desired target (the value in account currency).

The calculation is done with the intention to "revert" the OrderCalcSize function: calculating a profit having a certain closing price (in my case I use 500 ticks) and then rescaling this value based on the ratio between desired profit and profit obtained via the OrderCalcProfit function (like suggested from @Fernando Carreiro for calculating the size of a position knowing the risk).

I know that the conversion from the position enum to the order enum in order to make it work with the OrderCalcProfit function is not nice, but in my opinion it makes sense and it was the only idea to get it working. 

Let me know if you have suggestions for this problem or any better method to obtain the desiderd TP or SL price based on the desired risk of a position


PS. I'm evaluating the correctness of the calculations after the prices of TP and SL from these two functions are sent and placed on the market as TP and SL for the opened position and I hover with the mouse on the placed TP and SL lines and I see the expected profit and expected loss when the price will trigger those prices 


 

You should provide data and logs to demonstrate your problem.
 

Here's the code that I use to convert points to account currency (for swaps). Obviously, you're not calculating swaps but the general principle might be helpful if you edit it and input your TP in points.

swap_long = swap_value_currency(symbol.SwapLong(), symbol.TickValueProfit(), symbol.TickValueLoss());
swap_short = swap_value_currency(symbol.SwapShort(), symbol.TickValueProfit(), symbol.TickValueLoss());

The complete code with the #include and NormailizeDouble() are at:

Code Base

Swaps Monitor for a Single Symbol

Ryan L Johnson, 2025.05.14 01:27

A simple utility for monitoring long and short swaps of a single symbol. If your broker-dealer's swaps are specified in points instead of account currency, this utility automatically converts points into account currency. Swaps are tripled on Wednesday. Horizontal and vertical alignment can be adjusted in the inputs.

 
Miguel Angel Vico Alba #:

The idea makes sense and is actually pretty clever. Using a 500-tick reference to estimate TP based on a money amount is a practical approach.

It's a bit strange that it works well for SL but not for TP. That might come from small differences due to rounding, spread, or how OrderCalcProfit calculates profit exactly.

Maybe adding a small final adjustment (like a quick iteration) could help get the TP closer to the expected result.

Thanks! I tought about using a quick iteration too (increasing/decreasing by one tick at time till I get to the desired value), and it works flawlessly, but it's adding a bit of computational time and logic to the code. If there's no other way I will use it for sure 
 
Alain Verleyen #:
You should provide data and logs to demonstrate your problem.
You're right sorry, I'm working on them, I'll post them soon