VBA中的蒙特卡罗模拟始终低估了真实价值

时间:2016-12-09 11:03:24

标签: vba montecarlo

我建立的蒙特卡罗模拟有一个奇怪的问题。它是一个嵌套循环来计算投资的预期价值(实际上是扑克锦标赛)。为了演示,假设我们正在谈论单挑扑克锦标赛,这相当于硬币翻转。假设每个硬币翻转的投资回报率为25%,买入费为1,因此100(500,1000)次硬币翻转后的EV为25(125,250)个单位。然而,模拟分别返回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而不改变偏差。那么伙计们,这是怎么回事?

1 个答案:

答案 0 :(得分:1)

看起来你反复打电话给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担心播种。

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