title: Monte Carlo simulations in Python using quasi random standard normal numbers using sobol sequences gives erroneous values
body: <p>I'm trying to perform Monte Carlo Simulations using quasi-random standard normal numbers. I understand that we can use Sobol sequences to generate uniform numbers, and then use probability integral transform to convert them to standard normal numbers. My code gives unrealistic values of the simulated asset path:</p>
  
  <pre class="lang-py prettyprint-override"><code>import sobol_seq
  import numpy as np
  from scipy.stats import norm
  
  def i4_sobol_generate_std_normal(dim_num, n, skip=1):
      """
      Generates multivariate standard normal quasi-random variables.
      Parameters:
        Input, integer dim_num, the spatial dimension.
        Input, integer n, the number of points to generate.
        Input, integer SKIP, the number of initial points to skip.
        Output, real np array of shape (n, dim_num).
      """
  
      sobols = sobol_seq.i4_sobol_generate(dim_num, n, skip)
  
      normals = norm.ppf(sobols)
  
      return normals
  
  def GBM(Ttm, TradingDaysInAYear, NoOfPaths, UnderlyingPrice, RiskFreeRate, Volatility):
      dt = float(Ttm) / TradingDaysInAYear
      paths = np.zeros((TradingDaysInAYear + 1, NoOfPaths), np.float64)
      paths[0] = UnderlyingPrice
      for t in range(1, TradingDaysInAYear + 1):
          rand = i4_sobol_generate_std_normal(1, NoOfPaths)
          lRand = []
          for i in range(len(rand)):
              a = rand[i][0]
              lRand.append(a)
          rand = np.array(lRand)
  
          paths[t] = paths[t - 1] * np.exp((RiskFreeRate - 0.5 * Volatility ** 2) * dt + Volatility * np.sqrt(dt) * rand)
      return paths
  
  GBM(1, 252, 8, 100., 0.05, 0.5)
  
  array([[1.00000000e+02, 1.00000000e+02, 1.00000000e+02, ...,
          1.00000000e+02, 1.00000000e+02, 1.00000000e+02],
         [9.99702425e+01, 1.02116774e+02, 9.78688323e+01, ...,
          1.00978615e+02, 9.64128959e+01, 9.72154915e+01],
         [9.99404939e+01, 1.04278354e+02, 9.57830834e+01, ...,
          1.01966807e+02, 9.29544649e+01, 9.45085180e+01],
         ...,
         [9.28295879e+01, 1.88049044e+04, 4.58249200e-01, ...,
          1.14117599e+03, 1.08089096e-02, 8.58754653e-02],
         [9.28019642e+01, 1.92029616e+04, 4.48483141e-01, ...,
          1.15234371e+03, 1.04211828e-02, 8.34842557e-02],
         [9.27743486e+01, 1.96094448e+04, 4.38925214e-01, ...,
          1.16362072e+03, 1.00473641e-02, 8.11596295e-02]])
  
  </code></pre>
  
  <p>Values like 8.11596295e-02 should not be generated, hence I think there is something wrong in the code. If I use standard normal draws from the <code>numpy</code> library <code>rand = np.random.standard_normal(NoOfPaths)</code> then the price matches with the Black Scholes price. Hence I think the problem is with the random number generator. The value <code>8.11596295e-02</code> refers to a price in a path, and it's very unlikely that the price would come down from 100 (initial price) to <code>8.11596295e-02</code>.</p>
  
  <p>References: <a href="https://stats.stackexchange.com/questions/27450/best-method-for-transforming-low-discrepancy-sequence-into-normal-distribution">1</a>, <a href="https://stackoverflow.com/questions/9412339/recommendations-for-low-discrepancy-e-g-sobol-quasi-random-sequences-in-pytho">2</a>, <a href="https://github.com/naught101/sobol_seq" rel="nofollow noreferrer">3</a>.</p>