Search code examples
pythonlistnumpyrandomportfolio

Python - Generate a list of 40 random numbers summing to 1, with min and max weight


I have a portfolio of 40 stocks and I'm trying to calculate the standard deviation for the total portfolio while changing the weight per stock every time I calculate this standard deviation. I know how to create a list of random numbers summing to 1, but how can I add max and min weights per stock..

The maximum I'm using is 4.5% and the minimum 0.5%.

The code I use for creating a list of random numbers summing to 1 is:

import numpy as np, numpy.random

random = np.random.dirichlet(np.ones(10), size=1)

But how can I make this list with only values between 0.005 and 0.045?


Solution

  • Perhaps using np.random.normal would give better results. You could scale down the distribution to the 0.005-0.045 range using the proportion of 80% that is variable (above 0.005). Because normal distributions can still have outliers, it will be necessary to "retry" the calculation if the values go out of bounds (but that shouldn't happen too frequently unless you give a large standard deviation):

    import numpy as np

    def randStock(count=40,minR=0.005,maxR=0.045,sd=3):
        iterations = 0
        while True:
            iterations += 1
            r = np.random.normal(1,sd,count) #normal distribution
            r -= min(r) # offset to zero
            r /= max(r) # scale to 0..1
            r = minR + r/sum(r)*(maxR-minR)/(maxR+minR) # scale to range
            if min(r)>=minR and max(r)<=maxR: return r, iterations
    

    Output:

    for _ in range(10):
        s,i = randStock()
        print(*map("{:6.4f}".format,(sum(s),min(s),max(s))),i,"iterations")
    
    [sum]  [min]  [max]  [mean] 
    1.0000 0.0050 0.0404 0.0250 1 iterations
    1.0000 0.0050 0.0409 0.0250 2 iterations
    1.0000 0.0050 0.0395 0.0250 1 iterations
    1.0000 0.0050 0.0411 0.0250 4 iterations
    1.0000 0.0050 0.0410 0.0250 2 iterations
    1.0000 0.0050 0.0428 0.0250 1 iterations
    1.0000 0.0050 0.0433 0.0250 1 iterations
    1.0000 0.0050 0.0424 0.0250 1 iterations
    1.0000 0.0050 0.0371 0.0250 1 iterations
    1.0000 0.0050 0.0446 0.0250 1 iterations
    

    Note that this could be improved to randomize the lower bound a bit more and you can chose a different standard deviations