Tick size vs Point(), can be a little tricky in Multicurrency EA - page 2

 
Dima Diall #: Another question, in the meantime -- why is the tick value for profitable positions differ from losing ones? I haven't had time yet to delve deeper into this, but any answers or pointers appreciated.

Well, this may be controversial and there will be users contesting what I state, but in my opinion MetaQuotes has made a mess of it and it should not be about loss or profit, but about current ask and bid prices. These two “tick values” should be renamed as “ask”/“bid” tick values and not “profit”/“loss” which would also require knowing the direction of the trade.

The “correct” risk calculation being promoted on the forum by the more experienced users, including myself, is technically wrong (and that includes my code). This is because we calculate the risk based on some assumptions which are technically incorrect. I accept this “calculation error” because I understand what is wrong with it and know that I am only working with an approximation of the risk value, even though it can often be slightly off.

The fundamental assumption is that the tick value at the stop-loss price (or the take-profit price) will remain the same compared to the opening price, which is often not the case. Unless you are trading “xxx/USD” currency pairs (or the like) with a deposit account currency of USD, then the tick value will change with the quote price, both bid and ask prices.

If one really wants to create a technically correct and precise calculation of a risk or a reward, one would need to code a custom function that does all the cross currency calculations to get the tick value at the closing price at the stopless (or take profit) and in reference to the tick value at the opening (considering ask or bid prices and direction of the trade).

This, however, can be a considerable task and not worth it when the approximate value of the risk (or the reward) suffices for calculating the volume of an order, which is very granular anyway.

If one really wants to improve the current method of risk calculation, one could take the average of the two tick values (“profit” and “loss”) and use that instead, or use one or the depending on if it is a buy or sell position, but the difference would be minor.

 

Hi Farnando,

I am not sure if it is okay for me to post here because this is my first post on this forum. I have a problem the i need to solve but I could not figure out how to do that.

      1. I have Open Price e.g. 1704.00 for XAU/USD

      2. I have Stop Loss Price e.g. 1688.00 XAU/USD

      3. I want to open 10 trades at 150 points interval from open price to stop loss price

      4. i want to risk 0.5% of account balance for all 10 Trades

      5. I want to calculate lot size for each trade

So, I wrote the following code and I am getting lot size 0.14 per trade, but my total loss is:-1137.5, where as it should be -125.

//+------------------------------------------------------------------+
//|                                               TickExperiment.mq5 |
//|                                      Copyright 2022,Shomon Robie |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

/*
What I am trying to achieve:
Get the lot size to open trades

      1. I have Open Price e.g. 1704.00 for XAU/USD
      2. I have Stop Loss Price e.g. 1688.00 XAU/USD
      3. I want to open 10 trades at 150 points interval from open price to stop loss price
      4. i want to risk 0.5% of account balance for all 10 Trades
      5. I want to calculate lot size for each trade

*/

#property copyright "Copyright 2022,Shomon Robie"
#property link      "http://www.mql5.com"
#property version   "1.00"

double RiskPercent = 0.5;
double PipStep = 150;  // in point
double OpenPrice = 1704.00;
double StopLossPrice = 1688.00;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
 
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   Print("Total Loss : ", lossCalculation());
  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double lossCalculation()
  {
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double digits = _Digits;
   double digitAdjust = 0.0;
   if(_Digits == 3 || _Digits == 5)
     {
      digitAdjust = 10 * tickSize;
     }
   else
     {
      digitAdjust = tickSize;
     }
   double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100;
   double pipDistancefromOPToSL = OpenPrice - StopLossPrice;
   double howManyTicksInPipDistance = pipDistancefromOPToSL / tickSize;
   double totalAmountInPipDistance = howManyTicksInPipDistance * tickValue;
   double averageOpenPrice = getAverageOpenPrice(OpenPrice, StopLossPrice, PipStep * digitAdjust);
   double pipDistanceToSlPriceFromAverageOpenPrice = averageOpenPrice - StopLossPrice;
   double howManyTicksToSlPriceFromAvgOpenPrice  = pipDistanceToSlPriceFromAverageOpenPrice / tickSize;
   double lotSize = NormalizeDouble(riskAmount / howManyTicksToSlPriceFromAvgOpenPrice * tickValue, _Digits);
   double totalLoss = calTotalLoss(OpenPrice, StopLossPrice, PipStep * digitAdjust, lotSize);
   return (totalLoss);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double calTotalLoss(double openPrice, double slPrice, double pipStep, double lotSize)
  {
   double pipDistanceToStopLossPrice = OpenPrice - StopLossPrice;
   int totalPositions = (int)MathFloor(pipDistanceToStopLossPrice / pipStep);
   double prevPrice = openPrice, nextPrice = 0.0;
   double averageOpenPrice = openPrice;
   double totalLoss = 0.0, thisLoss = 0.0;
   for(int i  = 0; i < totalPositions; i++)
     {
      double thisPrice = prevPrice - pipStep * i;
      thisLoss = (thisPrice - StopLossPrice) / _Point * lotSize;
      totalLoss = totalLoss + thisLoss;
      prevPrice = thisPrice;
     }
   return(totalLoss);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double getAverageOpenPrice(double openPrice, double slPrice, double pipStep)
  {
   double pipDistanceToStopLossPrice = openPrice - slPrice;
   int totalPositions = (int) MathFloor(pipDistanceToStopLossPrice / pipStep);
   double prevPrice = 0.0;
   double sumOfAllOpenPrice = 0.0;
   for(int i  = 0; i < totalPositions; i++)
     {
      double thisPrice = openPrice - pipStep * i;
      sumOfAllOpenPrice = sumOfAllOpenPrice + thisPrice;
      prevPrice = thisPrice;
     }
   if(sumOfAllOpenPrice > 0 && totalPositions > 0)
     {
      double averageOpenPrice = sumOfAllOpenPrice / totalPositions;
      return(averageOpenPrice);
     }
   else
     {
      Print(__FUNCTION__, "Either sumOfAllOpenPrice or total Positions is zero");
      return(0);
     }
  }
//+------------------------------------------------------------------+
 
shomonrobie #:Hi Farnando, I am not sure if it is okay for me to post here because this is my first post on this forum. I have a problem the i need to solve but I could not figure out how to do that.

      1. I have Open Price e.g. 1704.00 for XAU/USD
      2. I have Stop Loss Price e.g. 1688.00 XAU/USD
      3. I want to open 10 trades at 150 points interval from open price to stop loss price
      4. i want to risk 0.5% of account balance for all 10 Trades
      5. I want to calculate lot size for each trade

So, I wrote the following code and I am getting lot size 0.14 per trade, but my total loss is:-1137.5, where as it should be -125.

Assuming that each point is worth $1.00 for 1 Lot, then for 0.14 lots, 1 point is worth $0.14.

Given a full S/L is 1600 points, then ...

Order 1, S/L = 1600, Value = 1600 * $0.14 = $224.00 loss
Order 2, S/L = 1450, Value = 1450 * $0.14 = $203.00 loss

etc., where the total loss will be $1295.00


 
shomonrobie #: Hi Farnando,I am not sure if it is okay for me to post here because this is my first post on this forum. I have a problem the i need to solve but I could not figure out how to do that.

      1. I have Open Price e.g. 1704.00 for XAU/USD
      2. I have Stop Loss Price e.g. 1688.00 XAU/USD
      3. I want to open 10 trades at 150 points interval from open price to stop loss price
      4. i want to risk 0.5% of account balance for all 10 Trades
      5. I want to calculate lot size for each trade

So, I wrote the following code and I am getting lot size 0.14 per trade, but my total loss is:-1137.5, where as it should be -125.

Forum on trading, automated trading systems and testing trading strategies

How to calculate current equity when back testing in Forex?

Fernando Carreiro, 2022.09.01 00:26

Correct, but it is important to take into account the spread when converting from one currency into another. I'm not sure at the moment when to use bid or ask when doing this (I need to refresh my memory on this), but if I am not mistaken in this case you would have to use the Ask price to convert USD into AUD, since you are selling USD ad buying AUD for the conversion.

If you are adding to the position during the life of the original position, you need to analyse each added position separately and then sum the profits and losses.

How to Calculate the Net Resulting Equivalent Order

The math is self explanatory, but here are the variables anyway:

  • vi = volume of individual position
  • oi = open price of individual position
  • ci = close price of individual position
  • Vn = total volume for a basket of positions
  • On = net mean open price for a basket of positions
  • Cn = net mean close price for a basket of positions
  • PLn = profit/loss for a basket of positions
The rest is in the math calculations.

In the example above your loss was $19 USD (not in AUD), so you would convert USD into GBP at the time the position was closed. However, in MetaTrader that conversion is done automatically for you. You would only need to do this for your spreadsheet paper trading.

Incorrect! Leverage has no effect on the gain, be it loss or gain. In the example above, the only thing that would affect the gain would be the volume (lots) of the position. Leverage only affects the required margin when you place the trade, which is then returned to you when you close the trade. It does not affect the profit or loss of the trade, only the required margin.


 
Fernando Carreiro #:

Thank you for your response. It did help me narrow down the issue.

I guess I got it right in the following way:

with the following code, I am getting total volume from formula Risk = (netClosingPrice - netOpeningPrice )/totalVolume. Therefore, totalVolume must be divided by totalPostions to get the lotSize for individual trades:

double totalVolume =  riskAmount/ (pipDistanceToSlPriceFromAverageOpenPrice*DeltaValuePerLot()); 
double lotSize = NormalizeDouble(totalVolume/ totalPositions, _Digits);
//+------------------------------------------------------------------+
//|                                               TickExperiment.mq5 |
//|                                      Copyright 2022,Shomon Robie |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

/*
What I am trying to achieve:
Get the lot size to open trades

      1. I have Open Price e.g. 1704.00 for XAU/USD
      2. I have Stop Loss Price e.g. 1688.00 XAU/USD
      3. I want to open 10 trades at 150 points interval from open price to stop loss price
      4. i want to risk 0.5% of account balance for all 10 Trades
      5. I want to calculate lot size for each trade

*/

#property copyright "Copyright 2022,Shomon Robie"
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Trade\Trade.mqh>

double RiskPercent = .2;
double PipStep = 150;  // in point
double OpenPrice = 1704.00;
double StopLossPrice = 1688.00;

CTrade trade;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
 
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   Print("Total Loss : ", lossCalculation());
  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double lossCalculation()
  {
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double digits = _Digits;
   double digitAdjust = 0.0;
   if(_Digits == 3 || _Digits == 5)
     {
      digitAdjust = 10 * tickSize;
     }
   else
     {
      digitAdjust = tickSize;
     }
   double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100;
   double pipDistancefromOPToSL = OpenPrice - StopLossPrice;
   double howManyTicksInPipDistance = pipDistancefromOPToSL / tickSize;
   double totalAmountInPipDistance = howManyTicksInPipDistance * tickValue;
   double averageOpenPrice = getAverageOpenPrice(OpenPrice, StopLossPrice, PipStep * digitAdjust);  //On
   double pipDistanceToSlPriceFromAverageOpenPrice = averageOpenPrice - StopLossPrice;
   double howManyTicksToSlPriceFromAvgOpenPrice  = pipDistanceToSlPriceFromAverageOpenPrice / tickSize;
   //double totalVolume =  pipDistanceToSlPriceFromAverageOpenPrice/riskAmount*_Point;
   double totalVolume =  riskAmount/ (pipDistanceToSlPriceFromAverageOpenPrice*DeltaValuePerLot()); // This is Total Volume which much be divided by totalPositions to get individual lotSize
   double totalLoss = calTotalLoss(OpenPrice, StopLossPrice, PipStep * digitAdjust, totalVolume);
   return (totalLoss);
   Print("");
   
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double calTotalLoss(double openPrice, double slPrice, double pipStep, double totalVolume)
  {
   
   double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   
   double pipDistanceToStopLossPrice = OpenPrice - StopLossPrice;
   int totalPositions = (int)MathFloor(pipDistanceToStopLossPrice / pipStep);
   double lotSize = NormalizeDouble(totalVolume/ totalPositions, _Digits);
   if (lotSize < minLot ) {
      lotSize = minLot;
   } else if (lotSize > maxLot) {
      lotSize = maxLot;
   }
   
   
   double prevPrice = openPrice, nextPrice = 0.0;
   double averageOpenPrice = openPrice;
   double totalLoss = 0.0, thisLoss = 0.0;
   for(int i  = 0; i < totalPositions; i++)
     {
      double thisPrice = prevPrice - pipStep * i;
      thisLoss = (thisPrice - StopLossPrice) / _Point * lotSize;
      totalLoss = totalLoss + thisLoss;
      prevPrice = thisPrice;
     }
   return(totalLoss);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double getAverageOpenPrice(double openPrice, double slPrice, double pipStep)
  {
   double pipDistanceToStopLossPrice = openPrice - slPrice;
   int totalPositions = (int) MathFloor(pipDistanceToStopLossPrice / pipStep);
   double prevPrice = 0.0;
   double sumOfAllOpenPrice = 0.0;
   for(int i  = 0; i < totalPositions; i++)
     {
      double thisPrice = openPrice - pipStep * i;
      sumOfAllOpenPrice = sumOfAllOpenPrice + thisPrice;
      prevPrice = thisPrice;
     }
   if(sumOfAllOpenPrice > 0 && totalPositions > 0)
     {
      double averageOpenPrice = sumOfAllOpenPrice / totalPositions;
      return(averageOpenPrice);
     }
   else
     {
      Print(__FUNCTION__, "Either sumOfAllOpenPrice or total Positions is zero");
      return(0);
     }
  }
//+------------------------------------------------------------------+



double  DeltaValuePerLot(){
   
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
    return(  tickValue / tickSize); 
}

Reason: