Моделирование методом Монте-Карло в VBA постоянно недооценивает истинную ценность

У меня странная проблема с созданной мной имитацией Монте-Карло. Это вложенный цикл для расчета ожидаемой стоимости инвестиций (на самом деле турниров по покеру). Для демонстрации предположим, что мы говорим о покерных турнирах один на один, которые равносильны подбрасыванию монеты. Предположим, что у нас есть 25% ROI на подбрасывание монеты, а бай-ин равен единице, поэтому EV после 100 (500, 1000) подбрасываний монеты составляет 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), поэтому он не может ничего прочитать. Я проверил, что все результаты являются целыми числами (что касается подбрасывания монеты, вы можете выиграть или проиграть только единицу), я сильно подозреваю, что генератор случайных чисел как-то смещен.

Я объявил почти все в коде как вариант и исключил второй случайный выбор без изменения смещения. Итак, ребята, что здесь происходит?


person IschaIschratioh    schedule 09.12.2016    source источник


Ответы (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 (ожидаемое значение составляет 4999,5, если последовательные вызовы Rnd соответствуют независимым случайным величинам - следовательно, существует явное отсутствие независимости при повторном пересеве).

Мораль истории: вызовите Randomize всего один раз в симуляции, скажем, в первой строке основной подпрограммы. Или используйте Application.WorksheetFunction.RandBetween(0,1) и позвольте Excel позаботиться о заполнении.

Если эта автокорреляция не объясняет ошибку, проблема заключается в коде, который вы не показали, поэтому вам нужно будет включить этот код.

person John Coleman    schedule 09.12.2016