Создание симуляции Монте-Карло из петли питона

Я пытаюсь вычислить вероятность цикла for, возвращающего значение ниже 10% от начального значения, используя симуляцию Монте-Карло.

for i in range(0, period):
    if i < 1:
        r=(rtn_daily[i]+sig_daily[i]*D[i])
        stock = stock_initial * (1+r)
    elif i >=1:
        r=(rtn_daily[i]+sig_daily[i]*D[i])
        stock = stock * (1+r)
print(stock)

Это цикл for, который я хочу выполнить большое количество раз (200000 как грубое число) и рассчитать вероятность того, что:

stock < stock_initial * .9

Я нашел примеры, которые определяют их начальный цикл как функцию, а затем будут использовать эту функцию в цикле, поэтому я попытался определить функцию из моего цикла:

def stock_value(period):
    for i in range(0, period):
        if i < 1:
            r=(rtn_daily[i]+sig_daily[i]*D[i])
            stock = stock_initial * (1+r)
        elif i >=1:
            r=(rtn_daily[i]+sig_daily[i]*D[i])
            stock = stock * (1+r)
    return(stock)

Это дает значения для "акции", которые, кажется, не соответствуют тому же диапазону, что и раньше, будучи определенными как функция.

используя этот код, я попытался запустить симуляцию Монте-Карло:

# code to implement monte-carlo simulation
number_of_loops = 200 # lower number to run quicker 

for stock_calc in range(1,period+1):
    moneyneeded = 0
    for i in range(number_of_loops):
        stock=stock_value(stock_calc)
        if stock < stock_initial * 0.90:
            moneyneeded += 1
    #print(stock) this is to check the value of stock being produced.
stock_percentage = float(moneyneeded) / number_of_loops
print(stock_percentage)

но это не дает результатов за пределами 10% -ного диапазона, даже когда оно повторяется 200000 раз, кажется, что диапазон / разброс результатов каким-то образом сильно уменьшается в моей определенной функции.

Может кто-нибудь увидеть проблему в моей определенной функции stock_value или может найти способ реализации симуляции Монте-Карло способом, с которым я не сталкивался?

Мой полный код для справки:

#import all modules required
import numpy as np # using different notation for easier writting
import scipy as sp 
import matplotlib.pyplot as plt

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


#collect variables provided by the user
stock_initial = float(12000) # can be input for variable price of stock initially.
period = int(63) # can be edited to an input() command for variable periods.
mrgn_dec = .10 # decimal value of 10%, can be manipulated to produce a 10% increase/decrease
addmoremoney = stock_initial*(1-mrgn_dec)

rtn_annual = np.repeat(np.arange(0.00,0.15,0.05), 31) 
sig_annual = np.repeat(np.arange(0.01,0.31,0.01), 3) #use .31 as python doesn't include the upper range value.

#functions for variables of daily return and risk.
rtn_daily = float((1/252))*rtn_annual
sig_daily = float((1/(np.sqrt(252))))*sig_annual
D=np.random.normal(size=period) # unsure of range to use for standard distribution


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# returns the final value of stock after 63rd day(possibly?)
def stock_value(period):
    for i in range(0, period):
        if i < 1:
            r=(rtn_daily[i]+sig_daily[i]*D[i])
            stock = stock_initial * (1+r)
        elif i >=1:
            r=(rtn_daily[i]+sig_daily[i]*D[i])
            stock = stock * (1+r)
        return(stock)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# code to implement monte-carlo simulation
number_of_loops = 20000

for stock_calc in range(1,period+1):
    moneyneeded = 0
    for i in range(number_of_loops):
        stock=stock_value(stock_calc)
        if stock < stock_initial * 0.90:
            moneyneeded += 1
    print(stock)
stock_percentage = float(moneyneeded) / number_of_loops
print(stock_percentage)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 ответ

Публикация ответа, так как у меня нет точек для комментариев. Некоторые вопросы о вашем коде - прохождение этих может помочь вам найти ответ:

  1. Почему вы определили rtn_annual как массив, np.repeat(np.arange(0.00,0.15,0.05), 31)? Так как он просто повторяет значения [0.0, 0.05, 0.1]почему бы не определить его как функцию?

    def rtn_annual(i):
      vals = [0.0,  0.05,  0.1]
      return vals[i % 3]
    

    Аналогично для sig_annual, rtn_daily, а также sig_daily - все это - прямые функции индекса, поэтому я не уверен, какое преимущество может дать их создание массивов.

  2. Что значит D на самом деле представляют? Как вы уже определили, это случайная величина со средним 0.0и стандартное отклонение 1.0, Таким образом, около 95% значений в D будет в диапазоне (-2,0, +2,0) - это то, что вы ожидаете?

  3. Вы проверили свой stock_value() работать даже в небольшие периоды (например, от 0 до нескольких дней), чтобы убедиться, что он делает то, что, как вы думаете, должен? Из вашего вопроса неясно, подтвердили ли вы, что когда-либо поступали правильно, для любого ввода и вашего комментария "...(possibly?)"звучит не очень уверенно.

  4. Оповещение спойлера - это почти наверняка нет. В функции stock_valueВаше заявление о возврате находится в пределах for петля. Это будет выполнено в первый раз, когда i = 0и цикл никогда не будет дальше. Это будет основной причиной, по которой функция дает разные результаты в цикле.

  5. Кроме того, когда вы говорите, "возвращая значение меньше, чем 10% от...", я предполагаю, что вы имеете в виду "возвращать значение, по крайней мере, на 10% ниже, чем...", так как это ваша вероятность stock < stock_initial * .9 рассчитывает.

Надеюсь, это поможет. Возможно, вы захотите пройтись по своему коду с помощью отладчика в предпочитаемой вами IDE (idle, или же thonny, или же eclipse(что бы это ни было), чтобы увидеть, что на самом деле делает ваш код.

Другие вопросы по тегам