【问题标题】:Error somewhere in my RNG for Monte-Carlo Simulation?用于蒙特卡洛模拟的 RNG 中某处出错?
【发布时间】:2018-07-21 13:38:39
【问题描述】:

因此,对于 Monte-Carlo 类,我创建了一个统一的随机数生成器来模拟正态分布并将其用于 MC 期权定价,但我在某处出现了严重错误。它使用一个简单的线性同余生成器 (lcg),它生成一个随机向量,该向量被输入到一个逆正态分布的数值近似中(beasley-springer-morrow 算法)生成标准正态分布值(具体过程详解见here)。

这是我目前的代码。

Rng:

def lcrm_generator(num, a, seed, c):

    mod = 4294967296 # 2^32
    val = int(seed)  #int() is to ensure seeds with a leading zero still get accepted by the program
    rng = []
    for i in range(num):
        val = (a * val + c) % mod
        rng.append(val/(mod-1))

    return rng

逆正态逼近器:

def bsm_algorithm(u):

    # These are my necessary initial constants
    a0 = 2.50662823884; a1 = -18.61500062529; a2 = 41.39119773534; a3 = -25.44106049637;

    b0 = -8.47351093090; b1 = 23.08336743743; b2 = -21.06224101826; b3 = 3.13082909833;

    c0 = 0.3374754822726147; c1 = 0.9761690190917186; c2 = 0.1607979714918209; c3 = 0.0276438810333863;
    c4 = 0.0038405729373609; c5 = 0.0003951896511919; c6 = 0.0000321767881768; c7 = 0.0000002888167364;
    c8 = 0.0000003960315187;

    x = [0]*len(u)
    for i in range(len(u)):
        y = u[i] - 0.5
        if abs(y) < 0.42:
            r = y**2
            x[i] = y*(((a3*r+a2)*r+a1)*r+a0)/((((b3*r+b2)*r+b1)*r+b0)*r+1)
        else:
            r = u[i]
            if y > 0:
                r = 1 - u[i]
            r = log(-log(r))
            x[i] = c0+r*(c1+r*(c2+r*(c3+r*(c4+r*(c5+r*(c6+r*(c7+r*c8)))))))
            if y < 0:
                x[i] = -x[i]

    return x

将这两者与以下结合并绘制直方图显示数据看起来正确正常,

a=lcrm_generator(100000,301,"0",21)
b = bsm_algorithm(a)
plt.hist(b, bins=100)
plt.show()

及期权定价函数:

def LookbackOP(S,K,r,sigma,intervals,sims,Call_Put=1):

    ## My objects that will determine the option prices.
    path = [0]*intervals
    values = [0]*sims

    ## Objects to hold the random nums used for simulation.
    randuni = [0]*sims
    randnorm = [0]*sims
    for i in range(sims):
        randuni[i] = lcrm_generator(intervals,301,i,21)
        randnorm[i] = bsm_algorithm(randuni[i]) 

    # Generating the simulation one by one.
    for i in range(sims):
        path[0] = 1

        ## Below is to generate one whole simulated path.

        ################## MY INCORRECT WAY ##################
        for j in range(1,intervals):
            path[j] = path[j-1]*exp((r - .5*sigma**2)*(1/intervals) + sqrt(1/intervals)*randnorm[i][j])

        ################## CORRECT BUILT-IN WAY ##################
            # path[j] = path[j-1]*exp((r - .5*sigma**2)*(1/intervals) + sqrt(1/intervals)*np.random.normal(0,1))

        ## For each separate simulation, price the option either as a call or a put.    
        if Call_Put == 1:
            values[i] = max(S*max(path)-K,0)
        elif Call_Put == 0:
            values[i] = max(K-S*min(path),0)
        else:
            print("Error: You inputted something other than '1 = Call', or '0 = Put'")
    plt.hist(values,bins=30)
    plt.show()

    ## To get expected return of option by takeing their avg.
    option_value = np.mean(values)
    print(option_value)
    return option_value

在最后一段代码中,指出了我的错误,这似乎可以通过简单地使用 numpy's 普通 rng 来修复。使用一个与另一个产生截然不同的答案,我很想相信 numpy 而不是自己,但我的代码看起来很正常,所以我哪里出错了。

【问题讨论】:

  • 我在您的伪随机分布和numpy.randon.normal 之间进行了一些视觉比较,而后者似乎有点尖锐。也许他们并不完全平等?我还尝试使用numpy.random.rand 生成数字,然后使用您的bsm_algorithm 获得正态分布。它看起来更像numpy.random.normal 一个,这让我怀疑你的 rng 没有正确、均匀的分布。由于我对 MC 期权定价一无所知,因此我无法说出最终结果。
  • 这就是我所害怕的,不知何故数据有点不正常。我想我必须阅读更多关于为 lcg rng 选择正确常数的数学知识,因为我听说您需要选择正确的常数才能使其工作,但从不相信它会产生糊状影响。

标签: python numpy random montecarlo quantitative-finance


【解决方案1】:

首先,

a=lcrm_generator(100000,301,"0",21)

这看起来很奇怪 - 为什么你需要一个角色作为种子?无论如何,好的参数都在这里的表格中:https://en.wikipedia.org/wiki/Linear_congruential_generator。但我相信问题不在于 LCG,但您的高斯可能存在系统性差异。

我跑了代码

from scipy.stats import norm
q = lcrm_generator(100000, 301, "0", 21)
g = bsm(q)

param = norm.fit(g)
print(param)

对于 100 000、1 000 000 和 10 000 000 个样本,我的输出是

(0.0009370998731855792, 0.9982155665317061)
(-0.0006429485100838258, 0.9996875045073682)
(-0.0007464875819397183, 1.0002711142625116)

在 1 000 000 和 10 000 000 个样本之间没有任何改进。基本上,你对高斯反函数使用了一些近似,这些只是近似的产物,没有什么可做的。

我相信 Numpy 正在使用一种精确的正态采样方法(我认为是 Box-Muller)

【讨论】:

  • 我只是重新进行了与您相同的测试,除了使用np.random.normal(0,1),并且随着样本的增加,参数变得可以预见地更加精确,所以这一定是 BSM 算法的问题。这让我有些焦虑,感谢您向我展示了我应该如何测试我的代码以找出问题所在。
  • @Coolio2654 不客气。 SciPy 和 Statsmodels 中有更多测试(Komogorov-Smirnov 等)
猜你喜欢
  • 2021-01-06
  • 1970-01-01
  • 1970-01-01
  • 2018-09-24
  • 2018-04-03
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 2014-12-09
相关资源
最近更新 更多