Calculating Pip Size and and Questions about Tick/Lot Size Values

 

Hi All,

I am currently new to MT4 and I want to compute for the pips with minimal hard coding. When coding for currency AUDCHF, I get the following info from MarketInfo():


1. Lot Size = 100000

2. Tick Value = 1.089...

3. Tick Size = 1e-05


What I want to do is that I have an integer pip value that I want to add to the existing Bid/Ask. Say this value is 20. I have this formula:


 double getPipsFromDistance(double distance) {
   double dblTickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
   double pipValue =  distance * dblTickSize;
   
   return pipValue;
  }

From the tick size info, it computes for the pippette, and I have to multiply by 10 (hard-coded) in order to get it correct, which I want to avoid to have some flexibility for other currencies. Is there any method that I can use to calculate the pips instead of manually multiplying by 10?


Another questions that I have:

  • what is tick value? Is this something that I can use for calculating risk management? It is advisable to do this or just stick with manual computation of standard lot then multiple by $10, mini lot then multiply by $1 and so on. Is there anything that I can use programatically to get the amount based on the lot size? 


My questions would seem to be very mundane but bear with me since I am still starting. Thanks.

 
Topics concerning MT4 and MQL4 have their own section.
In future please post in the correct section.
I have moved your topic to the MQL4 and Metatrader 4 section.
 
Doy Roberto:

Hi All,

I am currently new to MT4 and I want to compute for the pips with minimal hard coding. When coding for currency AUDCHF, I get the following info from MarketInfo():


1. Lot Size = 100000

2. Tick Value = 1.089...

3. Tick Size = 1e-05


What I want to do is that I have an integer pip value that I want to add to the existing Bid/Ask. Say this value is 20. I have this formula:


From the tick size info, it computes for the pippette, and I have to multiply by 10 (hard-coded) in order to get it correct, which I want to avoid to have some flexibility for other currencies. Is there any method that I can use to calculate the pips instead of manually multiplying by 10?


Another questions that I have:

  • what is tick value? Is this something that I can use for calculating risk management? It is advisable to do this or just stick with manual computation of standard lot then multiple by $10, mini lot then multiply by $1 and so on. Is there anything that I can use programatically to get the amount based on the lot size? 


My questions would seem to be very mundane but bear with me since I am still starting. Thanks.


I know what you want. You know correctly what you want and what you are asking for. 

This topic (with the answers we need) are extremely important and this is a VERY complex topic,. for the answer to be simple.. Lol.. 


My best answer, is to put here some other threads about this topic. Learning how this relations works are NOT EASY, because they are somehow confusing when learning.

But you must learn and know it 100%.


Take a read on the thread below


https://www.mql5.com/en/forum/365781



365781

TickValue with EURUSD includes exchange rate?
TickValue with EURUSD includes exchange rate?
  • 2021.03.26
  • www.mql5.com
Hi, The specifications in general are as shown in the picture. The focus should be on Profit-currency, which is USD...
 
rrocchi:


I know what you want. You know correctly what you want and what you are asking for. 

This topic (with the answers we need) are extremely important and this is a VERY complex topic,. for the answer to be simple.. Lol.. 


My best answer, is to put here some other threads about this topic. Learning how this relations works are NOT EASY, because they are somehow confusing when learning.

But you must learn and know it 100%.


Take a read on the thread below


https://www.mql5.com/en/forum/365781



365781

Looks like I might be jumping the gun here with regards to the tick values and all. So maybe I'll stick to the first part of the question first. 


1. Lot Size = 100000

2. Tick Value = 1.089...

3. Tick Size = 1e-05


What I want to do is that I have an integer pip value that I want to add to the existing Bid/Ask. Say this value is 20. I have this formula:


 double getPipsFromDistance(double distance) {
   double dblTickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
   double pipValue =  distance * dblTickSize;
   
   return pipValue;
  }

From the tick size info, it computes for the pippette, and I have to multiply by 10 (hard-coded) in order to get it correct, which I want to avoid to have some flexibility for other currencies. Is there any method that I can use to calculate the pips instead of manually multiplying by 10?

Are there any values that I can use to get the 10 multiplier? Or I really dont have a choice?

To further clarify, what I am trying to do is something like IntToPipsValue(), where say, 20 can be converted to 0.002

 

Forum on trading, automated trading systems and testing trading strategies

any suggestions for getting the required lot size for certain risk percentage ?

William Roeder, 2021.03.18 15:26

Risk depends on your initial stop loss, lot size, and the value of the symbol. It does not depend on margin and leverage. No SL means you have infinite risk. Never risk more than a small percentage of your trading funds, certainly less than 2% per trade, 6% total.

  1. You place the stop where it needs to be — where the reason for the trade is no longer valid. E.g. trading a support bounce the stop goes below the support.

  2. AccountBalance * percent/100 = RISK = OrderLots * (|OrderOpenPrice - OrderStopLoss| * DeltaPerLot + CommissionPerLot) (Note OOP-OSL includes the spread, and DeltaPerLot is usually around $10/pip but it takes account of the exchange rates of the pair vs. your account currency.)

  3. Do NOT use TickValue by itself - DeltaPerLot and verify that MODE_TICKVALUE is returning a value in your deposit currency, as promised by the documentation, or whether it is returning a value in the instrument's base currency.
              MODE_TICKVALUE is not reliable on non-fx instruments with many brokers - MQL4 programming forum 2017.10.10
              Is there an universal solution for Tick value? - Currency Pairs - General - MQL5 programming forum 2018.02.11
              Lot value calculation off by a factor of 100 - MQL5 programming forum 2019.07.19

  4. You must normalize lots properly and check against min and max.

  5. You must also check FreeMargin to avoid stop out

Most pairs are worth about $10 per PIP. A $5 risk with a (very small) 5 PIP SL is $5/$10/5 or 0.1 Lots maximum.

 

Forum on trading, automated trading systems and testing trading strategies

Formula to get the right lot size to recover my open losing trade

Fernando Carreiro, 2021.07.21 05:16

I know that! And I have already said that the calculation for Risk and S/L, is the same as for Reward and T/P. Just invert the direction. It is the same thing!

Volume in lots = ( [Reward] * [Tick Size] ) / ( [T/P Size] * [Tick Value] )

If the Symbol is EURUSD, then [Tick Value] = $1.00, [Tick Size] = 0.00001 and [T/P Size] = 80 pips = 0.00800, [Reward] = $500.00

Volume = ($500 * 0.00001) / (0.00800 * $1) = 0.005 / 0.008 = 0.625 Lots = 0.63 Lots

 

This code will calculate the proper tickvalue for Forex, Crypto, Gold, CFD and indices.

//+------------------------------------------------------------------+
//| TickValuePerLot in account currency.                             |
//+------------------------------------------------------------------+
double mTickValue(string symbol = NULL)
  {
   if(symbol == NULL) symbol = _Symbol;

//--- Some brokers return incorrect values for TICK_VALUE.
   long CalcMode = SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
   if((CalcMode == SYMBOL_CALC_MODE_CFD) || (CalcMode == SYMBOL_CALC_MODE_CFDINDEX) || (CalcMode == SYMBOL_CALC_MODE_CFDLEVERAGE))
     {
      double TickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
      double LotSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
      double TickValue = TickSize * LotSize;
      const string prof = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
      const string acc  = AccountInfoString(ACCOUNT_CURRENCY);
      //--- converting into deposit currency.
      if(prof != acc)
        {
         TickValue *= GetCrossRate(prof, acc);
        }

      return TickValue;
     }

   return (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE));
  }
//+------------------------------------------------------------------+
//| PointValuePerLot in account currency.                            |
//+------------------------------------------------------------------+
double mPointValue(string symbol = NULL)
  {
   if(symbol == NULL) symbol = _Symbol;

   double TickSize  = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
   double PointSize = SymbolInfoDouble(symbol, SYMBOL_POINT);
   return mTickValue(symbol) / TickSize * PointSize;
  }
//+------------------------------------------------------------------+
//| Get the cross-rate for the profit/account symbol                 |
//+------------------------------------------------------------------+
double GetCrossRate(string curr_prof, string curr_acc)
  {
//--- compare case-insensitive
   if(StringCompare(curr_prof, curr_acc, false) == 0)
     {
      return (1.0);
     }
//---
   string symbol = curr_prof + curr_acc;
   if(CheckMarketWatch(symbol))
     {
      double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
      if(bid != 0.0) return (bid);
     }
//--- Try the inverse symbol
   symbol = curr_acc + curr_prof;
   if(CheckMarketWatch(symbol))
     {
      double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
      if(ask != 0.0) return (1 / ask);
     }
//---
   Print(__FUNCTION__, ": Error, cannot get cross rate for ", curr_prof + curr_acc);
   return (0.0);
  }
//+------------------------------------------------------------------+
//| Checks if symbol is selected in the MarketWatch                  |
//| and adds symbol to the MarketWatch, if necessary                 |
//+------------------------------------------------------------------+
bool CheckMarketWatch(string symbol)
  {
   ResetLastError();
//--- check if symbol is selected in the MarketWatch
   if(!SymbolInfoInteger(symbol,SYMBOL_SELECT))
     {
      if(GetLastError()==ERR_MARKET_UNKNOWN_SYMBOL)
        {
         //printf(__FUNCTION__+": Unknown symbol '%s'",symbol);
         return(false);
        }
      if(!SymbolSelect(symbol,true))
        {
         printf(__FUNCTION__+": Error adding symbol %d",GetLastError());
         return(false);
        }
      printf(__FUNCTION__+": Symbol '%s' is added in the MarketWatch.",symbol);
     }
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
 

Here is another shorter code to calculate the tickvalue.

//+------------------------------------------------------------------+
//| TickValuePerLot in account currency.                             |
//+------------------------------------------------------------------+
double mTickValue(string symbol = NULL)
  {
   if(symbol == NULL) symbol = _Symbol;

//--- Some brokers return incorrect values for TICK_VALUE.
   long CalcMode = SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
   if((CalcMode == SYMBOL_CALC_MODE_CFD) || (CalcMode == SYMBOL_CALC_MODE_CFDINDEX) || (CalcMode == SYMBOL_CALC_MODE_CFDLEVERAGE))
     {
      double MaxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
      double Price = SymbolInfoDouble(symbol, SYMBOL_ASK);
      double TickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
      double Profit = 0;
      if(OrderCalcProfit(ORDER_TYPE_BUY, symbol, 100 * MaxLot, Price, Price + TickSize, Profit) && Profit > 0)
        {
         return Profit / (100 * MaxLot);
        }
     }

   return (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE));
  }


Edit: I'm sorry, I didn't notice the OP wants code for MT4

 
amrali:

Here is another shorter code to calculate the tickvalue.


Edit: I'm sorry, I didn't notice the OP wants code for MT4

I do have a similar functionset in my library. SInce your code shows to be valid only for certain types of calculation modes, I was wondering if my code takes this into respect or if I need to adjust it maybe to have it generalized.

May I ask to take a look at this code and share improvements to it, please.

//+------------------------------------------------------------------+
//| AccountCurrencySymbolProfit()                                    |
//+------------------------------------------------------------------+
double AccountCurrencySymbolProfit(const string symbol, const double open_price, const double close_price, const double vol = 1.00)
{
    // Local cache
    
        static  double  c_tick_value    = NULL;
        static  int     c_digit_factor  = NULL;
        static  string  c_symbol        = NULL;


    // Init or update cache
    
        if(symbol != c_symbol)
        {
            c_symbol        = symbol;
            c_tick_value    = AccountCurrencySymbolTickValue(symbol, vol);
            c_digit_factor  = MathPow(10, SymbolInfoInteger(symbol, SYMBOL_DIGITS));
        }


    // Calculate profit
    return(fabs(open_price - close_price) * c_digit_factor * c_tick_value);
}


//+------------------------------------------------------------------+
//| AccountCurrencySymbolTickValue()                                 |
//+------------------------------------------------------------------+
double AccountCurrencySymbolTickValue(const string symbol, const double vol = 1.00)
{
    // Const static
    
        const static bool   _is_indicator       = MQLInfoInteger(MQL_PROGRAM_TYPE) == PROGRAM_INDICATOR;
    
    
    // Local cache
    
        static  double  c_digit_factor      = NULL;
        static  double  c_contract_size     = NULL;
        static  double  c_tick_multiply     = NULL;
        static  double  _vol_min            = NULL;
        static  double  _vol_max            = NULL;
        static  bool    m_hidden_currency   = false;
        static  bool    m_hidden_rev_quote  = false;
        static  bool    rev_quote           = false;
        static  string  c_symbol            = NULL;
        static  string  a_currency              = NULL;
        static  string  m_currency                  = NULL;
        static  string  m_hidden_symbol     = NULL;
        

    // Cache update function

        if(c_symbol != symbol)
        {
            // Temporals                        

                const   double  c_factor    = MathPow(10, MathDigits(SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE)));
                        double  m_vol_min   = NULL;
                        double  m_vol_max   = DBL_MAX;


            // Globals

                c_symbol                = symbol;
                c_tick_multiply         = SymbolInfoDouble(c_symbol, SYMBOL_TRADE_TICK_SIZE) * c_factor;
                c_digit_factor          = 1.0 / c_factor;
                c_contract_size         = SymbolInfoDouble(c_symbol, SYMBOL_TRADE_CONTRACT_SIZE);
                        m_currency                      = SymbolInfoString(c_symbol, SYMBOL_CURRENCY_MARGIN);
                        rev_quote               = (m_currency == SymbolInfoString(c_symbol, SYMBOL_CURRENCY_PROFIT)) ;
                        a_currency              = AccountInfoString(ACCOUNT_CURRENCY);


            // Margin currency is not account currency

                        if(m_currency != a_currency)
                        {
                                m_hidden_symbol     = SymbolFind(a_currency, m_currency, m_hidden_rev_quote);
    
                                m_hidden_currency   = true;
                                m_vol_min           = SymbolInfoDouble(m_hidden_symbol, SYMBOL_VOLUME_MIN);
                                m_vol_max           = SymbolInfoDouble(m_hidden_symbol, SYMBOL_VOLUME_MAX);
                                
                                // Preload hidden symbol
                                if( (c_symbol != m_hidden_symbol)
                                 && (!SymbolInfoInteger(m_hidden_symbol, SYMBOL_SELECT))
                                 && (SymbolSelect(m_hidden_symbol, true))
                                 && (!_is_indicator) )
                                { 
                                    Sleep(TerminalInfoInteger(TERMINAL_PING_LAST) / 500);
                                    if(!SymbolIsSynchronized(m_hidden_symbol))
                                    { return(NULL); }
                                }
                }


            // Globals

                _vol_min                = MathMax(SymbolInfoDouble(c_symbol, SYMBOL_VOLUME_MIN), m_vol_min);
                _vol_max                = MathMin(SymbolInfoDouble(c_symbol, SYMBOL_VOLUME_MAX), m_vol_max);
        }


    // Local init

                MqlTick _tick   = {};
                MqlTick m_tick  = {};
        double  factor  = NULL;
        double  _vol    = MathRange(vol, _vol_min, _vol_max);


    // Update tick data

                SymbolInfoTick(c_symbol, _tick);


    // Default to account currency is margin currency

        factor      = (rev_quote) ? ((m_hidden_currency) ? _tick.bid : 1.0) : (1.0 / _tick.bid);


    // Currency factor

        if(m_hidden_currency)
        {
                SymbolInfoTick(m_hidden_symbol, m_tick);
            factor *= (m_tick.bid > NULL) ? ( ((1.0 / m_tick.bid) * ((m_hidden_rev_quote) && (!rev_quote)) )
                                                + (m_tick.bid * ((!m_hidden_rev_quote) || (rev_quote))) ) : NULL;
        }

    // Return
    return(c_contract_size * c_digit_factor * factor * _vol * c_tick_multiply);
}


//+------------------------------------------------------------------+
//| SymbolFind()                                                     |
//+------------------------------------------------------------------+
string SymbolFind(const string margin_currency, const string profit_currency, bool& rev_quote)
{
        // Local init

                bool    custom_symbol   = false;
                string  symbolname              = NULL;
                string  m_cur                   = NULL;
                string  p_cur                   = NULL;
                string  c_symbol        = NULL;


        // Initially try guess a symbol

                if( (SymbolExist(margin_currency + profit_currency, custom_symbol))
                 && (!custom_symbol))
                { c_symbol = margin_currency + profit_currency; rev_quote = true; return(c_symbol); }

                if( (SymbolExist(profit_currency + margin_currency, custom_symbol))
                 && (!custom_symbol))
                { c_symbol = profit_currency + margin_currency; rev_quote = false; return(c_symbol); }


        // Search all available symbols for a match

                for(int cnt = 0; (cnt < SymbolsTotal(false)) && !IsStopped(); cnt++)
                {
                        // Get symbol name
                        symbolname = SymbolName(cnt, false);

                        // Get margin currency
                        m_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_MARGIN);

                        // Get profit currency (profit on price change)
                        p_cur = SymbolInfoString(symbolname, SYMBOL_CURRENCY_PROFIT);

                        // Check if found
                        if(      ( (m_cur == margin_currency)
                                && (p_cur == profit_currency))
                         ||      ( (p_cur == margin_currency)
                                && (m_cur == profit_currency)) )
                         {
                                c_symbol = symbolname;
                                if(SymbolExist(c_symbol, custom_symbol) && (!custom_symbol))
                                {
                                        rev_quote = (m_cur == margin_currency);
                                        return(c_symbol);
                                }
                         }
                }


        // Return failure
        return(NULL);
}


template <typename T, typename U, typename V>
T MathRange(const T value, const U min, const V max)
{ return((value * (T)(((U)value >= min) && ((V)value <= max))) + (T)(min * (U)((U)value < min)) + (T)(max * (V)((V)value > max))); }

template <typename T>
int MathDigits(const T value)
{ return((int)MathRound(fabs(MathLog10((double)value)))); }

 
Dominik Egert:

I do have a similar functionset in my library. SInce your code shows to be valid only for certain types of calculation modes, I was wondering if my code takes this into respect or if I need to adjust it maybe to have it generalized.

May I ask to take a look at this code and share improvements to it, please.

Your code calculates wrong tick_value for all symbols.

To calculate the proper tick_value:

tick_value (in profit currency) = volume in units * ticksize (price change)

tick_value (converted to account currency) = tick_value (in profit currency) * profit currency/account currency exchange rate


The margin currency has no role in calculating the tick_value

 
Thank you very much, I will repair the function.
Reason: