为什么用于毛坯模拟的几何布朗运动 (GBM) 函数会产生不同的结果?

Why do my Geometric Brownian Motion (GBM) functions for stock simulation produce different results?

提问人:Pavel 提问时间:11/11/2023 最后编辑:Pavel 更新时间:11/12/2023 访问量:49

问:

我使用GBM运行了一些股票模拟。我写了两个函数,一个是使用 for 循环,计算成本更高。在那之后,我写了另一个矢量化,因此效率更高。但是,在显示结果后,函数似乎显示的行为略有不同。尽管这些图看起来非常相似,但它们的均值不同——第一个函数的平均值约为 105,另一个函数的平均值约为 102。我不认为这种差异仅仅是由于随机性(尤其是在使用 1,000 次模拟运行时)

import  numpy as np
import matplotlib.pyplot as plt
import time 
np.random.seed(123)

def MC_gbm1(S0, mu, sigma, T, M, n):
    start_time2 = time.time()
    dt = float(T) / n
    paths = np.zeros((n+1,M), np.float64)
    paths[0] = S0
    for t in range(1, n + 1):
        rand = np.random.normal(0,np.sqrt(dt), M)
        paths[t] = paths[t-1] * np.exp((mu- 0.5 * sigma ** 2) * dt +
                                         sigma * rand)
    comp_time2 = round(time.time() - start_time2,4)
    print("Computation time:", comp_time2)
    return paths

def MC_gbm2(S0, mu, sigma, T, M, n):
    #timesteps = np.linspace(0, T, n+1)[:,None]
    dt = T / n

    dW = np.random.normal(0, np.sqrt(dt), size=(n, M))
    dW_cumsum = np.cumsum(dW, axis=0)

    paths = S0 * np.exp((mu - 0.5 * sigma**2) * dt + sigma * dW_cumsum)
    result = np.concatenate((np.full((1,M), S0), paths), axis=0)
    return result

# Parameters
mu = 0.1
n = 100 # number of steps
T = 1 # time in years
M = 1000 #no of sims
S0 = 100 
sigma = 0.3

# GBM Simulation 1
St = MC_gbm1(S0, mu, sigma, T, M, n)

# GBM Simulation 2
St3 = MC_gbm2(S0, mu, sigma, T, M, n)

# Plot the results
sequence = np.linspace(0, T, n+1)
tt = np.full(shape = (M,n+1), fill_value=sequence).T

plt.plot(tt,St)
plt.title("GBM simulation 1")
plt.ylabel("Stock price")
plt.xlabel("Years")
plt.show()     

plt.plot(tt,St2)
plt.title("GBM simulation 2")
plt.ylabel("Stock price")
plt.xlabel("Years")
plt.show()

在此处输入图像描述 在此处输入图像描述

我尝试以多种方式修改功能,但没有任何真正改变。理想情况下,我希望看到两种非常手段和图(当然考虑到随机性给出的轻微随机性)

Python 模拟 金融 股票 蒙特卡洛

评论


答:

1赞 JustLearning 11/12/2023 #1

为了理解其中的区别,请注意,在以下两个操作之间重置种子会导致完全相同的噪声矩阵:

n = 10                                                                                                                
M = 1000                                                                                                              
dt = 1 / 10                                                                                                           
                                                                                                                      
rands = np.empty((n, M))                                                                                              
# Operation 1                                                                                                         
np.random.seed(123)                                                                                                   
for i in range(n):                                                                                                    
    rands[i] = np.random.normal(0, np.sqrt(dt), M)                                                                    
                                                                                                                                                                                                                                            
# Operation 2                                                                                                         
np.random.seed(123)                                                                                                   
dW = np.random.normal(0, np.sqrt(dt), size=(n, M))                                                                    
                                                                                                                      
print("Equal matrices?", np.allclose(rands, dW)) # True

因此,差异必须来自每个函数中操作的顺序和数量。事实上,如果你通过以下方式关闭每个功能中的随机噪声

paths[t] = paths[t-1] * np.exp((mu- 0.5 * sigma ** 2) * dt + sigma * np.zeros_like(rand))

paths = S0 * np.exp((mu - 0.5 * sigma**2) * dt + sigma * np.zeros_like(dW_cumsum))

这两个函数生成不同的矩阵:

# GBM Simulation 1                                                                                                    
np.random.seed(123)                                                                                                   
St = MC_gbm1(S0, mu, sigma, T, M, n)                                                                                  
                                                                                                                      
# GBM Simulation 2                                                                                                    
np.random.seed(123)                                                                                                   
St2 = MC_gbm2(S0, mu, sigma, T, M, n)                                                                                 
                                                                                                                                                                                                                                
print("Equal matrices?", np.allclose(St, St2)) # False

在本例中,差异在于方法 1 中生成迭代的方式:使用上一个值来计算下一个值。将对应的行更改为t

paths[t] = S0 * np.exp((mu- 0.5 * sigma ** 2) * dt + sigma * np.zeros_like(rand))

当噪音关闭时,这两个功能都会给出相同的结果。

最后,当您打开噪音时,差异的来源是方法 2 中的额外步骤:破坏结果。如果你只是这样做cumsum

paths = S0 * np.exp((mu - 0.5 * sigma**2) * dt + sigma * dW)

除了已经讨论过的

paths[t] = S0 * np.exp((mu- 0.5 * sigma ** 2) * dt + sigma * rand)

你会得到相同的结果:

# GBM Simulation 1                                                                                                    
np.random.seed(123)                                                                                                   
St = MC_gbm1(S0, mu, sigma, T, M, n)                                                                                  

# GBM Simulation 2                                                                                                    
np.random.seed(123)                                                                                                   
St2 = MC_gbm2(S0, mu, sigma, T, M, n)                                                                                 

print("Equal matrices?", np.allclose(St, St2)) # True

评论

0赞 Pavel 11/12/2023
谢谢你的回答。我刚刚替换了您建议的两行代码。即使它正在工作并且我得到了相同的矩阵,我认为这在 GBM 理论上是不正确的。在绘制结果后,我得到了非常奇怪的绘图,看起来像白噪声。我的理解是,在第一个函数中,需要依赖于 t-1,因为股票路径必须不断前进。同样,出于同样的原因,第二个函数具有 cumsum。但也许应该有cumprod。
0赞 JustLearning 11/12/2023
该问题试图理解为什么这些函数会给出不同的结果。这就是我提供的。虽然我理解你对这个理论的担忧,但我的建议是将这个问题标记为已解决,并提出一个关于如何使用矢量化操作实现你想要的东西的新问题。