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?
CodePudding user response:
Consider using the following:
import numpy as np
first_half = np.random.random(size=20)*0.04 0.005
second_half = 0.05-first_half
This is the right range, uniformly distributed, all random, however, the 2nd half is (anti)correlated with the 1st half. You can merge the two halves:
tot40elems = np.concatenate((first_half,second_half))
CodePudding user response:
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