Monte Carlo VBA 中的模拟始终低估真实值

Monte Carlo Simulation in VBA consistently underestimates the true value

我构建的 Monte Carlo 模拟有一个奇怪的问题。这是一个计算投资预期价值的嵌套循环(实际上是扑克锦标赛)。为了演示,假设我们正在谈论单挑扑克锦标赛,这等同于掷硬币。假设每次抛硬币我们有 25% 的投资回报率并且买入是 1,那么抛硬币 100 (500, 1000) 次后的 EV 为 25 (125, 250) 个单位。然而,模拟,returns分别为24,6、123,6和246。 代码中的关键行在这里:

Randomize
randomnumber = Rnd()
If randomnumber > adjustedITM Then
MC_array(m, n) = -tournamentvariables(k, 6)
Else:
Randomize
MC_array(m, n) = CDec(tournamentstructures(Int(Rnd() * (tournamentvariables(k, 7)) + 1), k) * tournamentvariables(k, 6) * (1 - tournamentvariables(k, 5)) * tournamentvariables(k, 2) - tournamentvariables(k, 6))
End If

第二个MC_array(m, n)是关键的代码行。如果玩家获胜,它会给出净利润。在抛硬币的情况下,这是一个单位。如果我将第二行更改为

 Randomize
    If Rnd() > adjustedITM Then
    MC_array(m, n) = -tournamentvariables(k, 6)
    Else:
    Randomize
    MC_array(m, n) = 1
    End If

结果正确。第二个 MCarray 之后的代码将抛硬币简化为:

CDec(tournamentstructures(Int(Rnd() * (tournamentvariables(k, 7)) + 1), k) * tournamentvariables(k, 6) * (1 - tournamentvariables(k, 5)) * tournamentvariables(k, 2) - tournamentvariables(k, 6))

=
CDec(tournamentstructures(1,1) * 1 * (1 - 0%) * 2 - 1)

所以和一个一模一样。数组 tournamentstructures() 的大小为 (1,1),所以它无法读取任何内容。我验证了所有结果都是整数(至于抛硬币你只能赢或输一个单位),我强烈怀疑随机数生成器存在某种偏差。

我将代码中的几乎所有内容都声明为变体,并在不改变偏差的情况下排除了第二个 Randomize。伙计们,这是怎么回事?

您似乎在重复调用 Randomize,大概是紧密循环的一部分。每次调用它时,它都会从系统时钟重新播种随机数生成器。每次通过循环都这样做会引入自相关(尽管具体如何还不是很清楚)。

考虑以下实验:

Sub Test()
    Dim i As Long, A As Variant
    Dim count1 As Long, count2 As Long
    ReDim A(1 To 10000)

    For i = 1 To 10000
        Randomize
        A(i) = IIf(Rnd() < 0.5, 0, 1)
    Next i

    'count how often A(i) = A(i+1)
    For i = 1 To 9999
        If A(i) = A(i + 1) Then count1 = count1 + 1
    Next i

    For i = 1 To 10000
        A(i) = IIf(Rnd() < 0.5, 0, 1)
    Next i

    'count how often A(i) = A(i+1)
    For i = 1 To 9999
        If A(i) = A(i + 1) Then count2 = count2 + 1
    Next i

   Debug.Print "First Loop: " & count1
   Debug.Print "Second Loop: " & count2 & vbCrLf

End Sub

典型输出:

First Loop: 5452
Second Loop: 4996

我已经运行好几次了。第一个循环几乎总是产生一个与 5000 相差很大的数字,而第二个循环几乎总是产生一个非常接近 5000 的数字(如果对 Rnd 的连续调用对应于独立随机变量,则预期值为 4999.5 - - 因此在重复重新播种时明显缺乏独立性。

故事的寓意:在模拟中只调用 Randomize 一次 一次 ,比如主子的第一行。或者,使用 Application.WorksheetFunction.RandBetween(0,1) 让 Excel 担心播种。

如果此自相关不能解释错误,则问题在于您未显示的代码,因此您需要包含该代码。