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 担心播种。
如果此自相关不能解释错误,则问题在于您未显示的代码,因此您需要包含该代码。
我构建的 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 担心播种。
如果此自相关不能解释错误,则问题在于您未显示的代码,因此您需要包含该代码。