简体   繁体   中英

Creating a monte carlo simulation from a loop python

I am attempting to calculate the probablility of a for loop returning a value lower than 10% of the initial value input using a monte-carlo simulation.

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)

This is the for-loop that I wish to run a large number of times (200000 as a rough number) and calculate the probability that:

stock < stock_initial * .9

I've found examples that define their initial loop as a function and then will use that function in the loop, so I have tried to define a function from my loop:

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)

This produces values for 'stock' that don't seem to fit the same range as before being defined as a function.

using this code I tried to run a monte-carlo simulation:

# 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)

but this returns no results outside the 10% range even when looped 200000 times, it seems the range/spread of results gets hugely reduced in my defined function somehow.

Can anyone see a problem in my defined function 'stock_value' or can see a way of implementing a monte-carlo simulation in a way I've not come across?

My full code for reference:

#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)

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

Posting an answer as I don't have the points to comment. Some queries about your code - going through these might help you find an answer:

  1. Why have you defined rtn_annual as an array, np.repeat(np.arange(0.00,0.15,0.05), 31) ? Since it just repeats the values [0.0, 0.05, 0.1] , why not define it as a function?:

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

    Likewise for sig_annual , rtn_daily , and sig_daily - the contents of these are all straightforward functions of the index, so I'm not sure what the advantage could be of making them arrays.

  2. What does D actually represent? As you've defined it, it's a random variable with mean of 0.0 , and standard deviation 1.0 . So around 95% of the values in D will be in the range (-2.0, +2.0) - is that what you expect?

  3. Have you tested your stock_value() function even on small periods (eg from 0 to a few days) to ensure it's doing what you think it should? It's not clear from your question whether you've verified that it's ever doing the right thing, for any input, and your comment " ...(possibly?) " doesn't sound very confident.

  4. Spoiler alert - it almost certainly doesn't. In the function stock_value , your return statement is within the for loop. It will get executed the first time round, when i = 0 , and the loop will never get any further than that. This would be the chief reason why the function is giving different results to the loop.

  5. Also, where you say "returning a value lower than 10% of...", I assume you mean "returning a value at least 10% lower than...", since that's what your probability stock < stock_initial * .9 is calculating.

I hope this helps. You may want to step through your code with a debugger in your preferred IDE ( idle , or thonny , or eclipse , whatever it may be) to see what your code is actually doing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM