Python中的蒙特卡罗

Python中的蒙特卡罗,python,finance,montecarlo,Python,Finance,Montecarlo,编辑以包含用于比较的VBA代码 此外,我们知道分析值,即8.021,蒙特卡罗应向该值收敛,这使得比较更容易。 Excel VBA基于平均5次蒙特卡罗模拟(7.989、8.187、8.045、8.034、8.075)得出8.067分 Python基于5个MCs(7.913、7.915、8.203、7.739、8.095)和更大的差异给出了7.973 VBA代码甚至没有“那么好”,它使用了一种相当糟糕的方法从标准法线生成样本 我正在用Python运行一个超级简单的代码,通过Monte Carlo为欧

编辑以包含用于比较的VBA代码

此外,我们知道分析值,即8.021,蒙特卡罗应向该值收敛,这使得比较更容易。

Excel VBA基于平均5次蒙特卡罗模拟(7.989、8.187、8.045、8.034、8.075)得出8.067分

Python基于5个MCs(7.913、7.915、8.203、7.739、8.095)和更大的差异给出了7.973

VBA代码甚至没有“那么好”,它使用了一种相当糟糕的方法从标准法线生成样本

我正在用Python运行一个超级简单的代码,通过Monte Carlo为欧洲看涨期权定价,我惊讶于10000条“模拟路径”的收敛是多么“糟糕”。通常,在C++中,或者在VBA中运行这个简单的问题时,蒙特卡洛的收敛性更好。 我展示了下面的代码(代码取自教科书“Python for Finance”,我在Visual Studio代码中以Python 3.7.7,64位版本运行):我得到以下结果,例如:运行1=7.913,运行2=7.915,运行3=8.203,运行4=7.739,运行5=8.095

上述结果相差如此之大,将是不可接受的。如何改进收敛性???(显然,通过运行更多路径,但正如我所说:对于10000条路径,结果应该已经收敛得更好了):

我还包括了VBA代码,它产生了稍好的结果(在我看来):使用下面的VBA代码,我得到了7.989、8.187、8.045、8.034、8.075

Option Explicit

Sub monteCarlo()

    ' variable declaration
    ' stock initial & final values, option pay-off at maturity
    Dim stockInitial, stockFinal, optionFinal As Double

    ' r = rate, sigma = volatility, strike = strike price
    Dim r, sigma, strike As Double

    'maturity of the option
    Dim maturity As Double

    ' instatiate variables
    stockInitial = 100#

    r = 0.05
    maturity = 1#
    sigma = 0.2
    strike = 105#

    ' normal is Standard Normal
    Dim normal As Double

    ' randomNr is randomly generated nr via "rnd()" function, between 0 & 1
    Dim randomNr As Double

    ' variable for storing the final result value
    Dim result As Double

    Dim i, j As Long, monteCarlo As Long
    monteCarlo = 10000

    For j = 1 To 5
        result = 0#
        For i = 1 To monteCarlo

            ' get random nr between 0 and 1
            randomNr = Rnd()
            'max(Rnd(), 0.000000001)

            ' standard Normal
            normal = Application.WorksheetFunction.Norm_S_Inv(randomNr)

            stockFinal = stockInitial * Exp((r - (0.5 * (sigma ^ 2))) + (sigma * Sqr(maturity) * normal))

            optionFinal = max((stockFinal - strike), 0)

            result = result + optionFinal

        Next i

        result = result / monteCarlo
        result = result * Exp(-r * maturity)
        Worksheets("sheet1").Cells(j, 1) = result

    Next j


    MsgBox "Done"

End Sub

Function max(ByVal number1 As Double, ByVal number2 As Double)

    If number1 > number2 Then
        max = number1
    Else
        max = number2
    End If

End Function

我不认为Python或numpy内部有任何问题,无论您使用的是什么工具,收敛性肯定应该是相同的。我用不同的样本大小和不同的西格玛值进行了一些模拟。毫不奇怪,结果表明,收敛速度在很大程度上受西格玛值的控制,见下图。请注意,x轴在对数刻度上!较大的振荡消失后,在稳定之前会有更多较小的波动。西格玛=0.5时最容易看到的。

我肯定不是专家,但我认为最明显的解决方案是增加样本量,正如你提到的。看到C++和VBA的结果和代码会很好,因为我不知道你对NoMPY和Python函数有多熟悉。也许有些东西没有做你认为它在做的事情

生成绘图的代码(不要谈论效率,这很可怕):

将numpy导入为np
将matplotlib.pyplot作为plt导入
S_0=100初始值
K=105.#罢工
T=1.0#到期时间
r=0.05#短期利率(常数)
图=plt.图()
ax=图添加_子批次()
plt.xscale('log')
samplesize=np.geomspace(100020000064)
sigmas=np.arange(0,0.7,0.1)
对于sigmas中的s:
arr=[]
对于样本中的n:
n=n.aType(int)
z=np.随机.标准_-正态(n)
S_T=S_0*np.exp((r-0.5*S**2)+np.sqrt(T)*S*z)
C_T=np.最大值((S_T-K),0)
C_0=np.exp(-r*T)*np.average(C_T)
arr.append(C_0)
散点(样本大小,arr,label=f'sigma={s:.2f})
plt.紧_布局()
plt.xlabel(“样本量”)
plt.ylabel('值')
plt.grid()
句柄,标签=ax.get\u legend\u handles\u labels()
plt.legend(句柄[::-1],标签[::-1],loc='左上角')
plt.show()
补充:


这一次,您使用VBA获得了更接近实际值的结果。但有时你不会。随机性的影响在这里太大了。事实是,从低样本数模拟中平均出5个结果是没有意义的。例如,在Python中平均出50个不同的模拟(只有n=10000,即使你不应该这样做,如果你想得到正确的答案),结果是8.025167(±0.039717,95%置信水平),这非常接近真实的解决方案。

有趣!我得到的值和你差不多。你能把你的结果从C++或VBA上传到比较吗?谢谢,彼得,谢谢你的回答。我想说的是,在一家金融机构,你可能经常被要求快速计算出报价或相关风险,而没有时间真正运行50种不同的模拟。对于这个简单的例子,NuMpy的性能不如VBA,这让我很惊讶,NuMpy是为这类计算而优化的。
Option Explicit

Sub monteCarlo()

    ' variable declaration
    ' stock initial & final values, option pay-off at maturity
    Dim stockInitial, stockFinal, optionFinal As Double

    ' r = rate, sigma = volatility, strike = strike price
    Dim r, sigma, strike As Double

    'maturity of the option
    Dim maturity As Double

    ' instatiate variables
    stockInitial = 100#

    r = 0.05
    maturity = 1#
    sigma = 0.2
    strike = 105#

    ' normal is Standard Normal
    Dim normal As Double

    ' randomNr is randomly generated nr via "rnd()" function, between 0 & 1
    Dim randomNr As Double

    ' variable for storing the final result value
    Dim result As Double

    Dim i, j As Long, monteCarlo As Long
    monteCarlo = 10000

    For j = 1 To 5
        result = 0#
        For i = 1 To monteCarlo

            ' get random nr between 0 and 1
            randomNr = Rnd()
            'max(Rnd(), 0.000000001)

            ' standard Normal
            normal = Application.WorksheetFunction.Norm_S_Inv(randomNr)

            stockFinal = stockInitial * Exp((r - (0.5 * (sigma ^ 2))) + (sigma * Sqr(maturity) * normal))

            optionFinal = max((stockFinal - strike), 0)

            result = result + optionFinal

        Next i

        result = result / monteCarlo
        result = result * Exp(-r * maturity)
        Worksheets("sheet1").Cells(j, 1) = result

    Next j


    MsgBox "Done"

End Sub

Function max(ByVal number1 As Double, ByVal number2 As Double)

    If number1 > number2 Then
        max = number1
    Else
        max = number2
    End If

End Function