Given a fixed amount of avliable resources, optimise allocation to maximise returns across a set of products with variable returns.
Following the Modern Portfolio Theory model (Markowitz 1957) we can formulate this problem as:
Given a fixed quantity of money (say $1000), how much should we invest in a series of stocks so as to (a) have a one month expected return of at least a given threshold, and (b) minimize the risk (variance) of the portfolio return.
Solution using Monte Carlo
Monte Carlo (MC) based solutions encompass a wide array of algorithms that exploit repeat random sampling and uncertainty to solve large, complex and generally intractable mathematical problems. MC is akin to exhaustive search type solutions. However in MC framed problems, the input model parameters, initial, boundary and environmental conditions are unknown and or subject to a degree of uncertainty. Therefore a true exahuastive search is not possible. The aim of MC is to conduct repeat random sampling of the input space to generate large numbers (e.g. $n$ = 100,000) of “plausible realities” from which metrics, risk analyses, and further assessments are drawn. Thus one of the most challenging aspects of the monte carlo method is in determining accuracte covariances and probability distributions of the input parameter space.
Lets make some simplifying assumptions:
- We have \$1000 to invest $V$.
- The risk-free rate is 0.03 (3 %). This is the return we can garuntee by instead putting our money in a savings account.
- Stocks have a known and fixed starting price.
- The monthly returns of a stock follow a standard normal distribution.
Stocks
First let’s define some stocks that are avaliable to invest in. For simplicity the stocks are heuristically assignined with a range of average daily return $mu$ and volatility $sigma$ values. For a more realistic simulation, one could derive these values from actual investment instruments. The average return and volatility of each stock is summarised in the table and figure 1.
n | name | price | mu | sigma | |
---|---|---|---|---|---|
0 | 0 | jumanji inc | 10 | 0.10 | 10 |
1 | 1 | evolution ltd | 20 | 0.20 | 20 |
2 | 2 | the incredibles inc | 30 | 0.30 | 30 |
3 | 3 | men in black & co | 20 | 0.08 | 40 |
4 | 4 | goldmember gmbh | 50 | 0.05 | 15 |
5 | 5 | dantes peak | 10 | 0.25 | 20 |
6 | 6 | deep impact | 20 | 0.02 | 5 |
Random Portfolio’s
The second step is to generate random portfolios of value upto a maximum value of \(V\), the total funds avaliable to invest. The method applied is adapted from this SO answer but is not optimal in terms of performance.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# total number of stocks in universe
N = len(stocks)
# V = total to invest
investment = 10**3
print(f'Investment: ${investment:.2f}')
mc_portfolio_runs = list()
pmax=5000
for p in range(pmax):
print(f'{p}/{pmax}',end='\r')
# random portfolio size
portfolio_size = np.random.randint(2, N+1)
# create a df portfolio of them
df = stocks_df.iloc[np.random.choice(N, portfolio_size, replace=False)].copy()
# sum numbers
while True:
df['value'] = np.random.random(portfolio_size)
T = df['value'].sum()
if T != 0: break
# calculate normalised value and number of shares
df['value'] *= investment/T
df['shares'] = df['value']/df['price']
df['p'] = p
mc_portfolio_runs.append(df)
Here we can see the investments in portfolio 0.
n | name | price | mu | sigma | value | shares | p | |
---|---|---|---|---|---|---|---|---|
0 | 3 | men in black & co | 20 | 0.08 | 40 | 201.353368 | 10.067668 | 0 |
1 | 6 | deep impact | 20 | 0.02 | 5 | 19.906906 | 0.995345 | 0 |
Balanced Portfolio
We also create A balanced portfolio. This provides a usefull benchamrk and represents the strategy of investing in each stock equally.
n | name | price | mu | sigma | value | shares | p | |
---|---|---|---|---|---|---|---|---|
0 | 0 | jumanji inc | 10 | 0.10 | 10 | 333.33 | 33.3330 | balanced |
1 | 1 | evolution ltd | 20 | 0.20 | 20 | 333.33 | 16.6665 | balanced |
2 | 2 | the incredibles inc | 30 | 0.30 | 30 | 333.33 | 11.1110 | balanced |
3 | 3 | men in black & co | 20 | 0.08 | 40 | 333.33 | 16.6665 | balanced |
4 | 4 | goldmember gmbh | 50 | 0.05 | 15 | 333.33 | 6.6666 | balanced |
5 | 5 | dantes peak | 10 | 0.25 | 20 | 333.33 | 33.3330 | balanced |
6 | 6 | deep impact | 20 | 0.02 | 5 | 333.33 | 16.6665 | balanced |
Calculate Portfolio Risk & Return
Third, we define and execute a function to calculate the return, risk, and Sharpe ratio of each random portfolio and the balance portfolio. The Sharpe ratio is defined as the return earned in excess of the risk free rate (e.g. fixed rate saving account).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def portfolio_returns(portfolio,risk_free_rate=0.03):
"""
Calculates portfolio returns, risk and summary
"""
#calculate returns
portfolio['result'] = np.random.normal(loc=portfolio['mu'],scale=portfolio['sigma'])*portfolio['shares']
# calculate risk
# https://math.stackexchange.com/questions/3381762/how-to-combine-standard-deviations-using-variance
# sqrt((sum(var1^2+var2^2)))
portfolio['var'] = portfolio['sigma'].apply(lambda x: x**2)
# portfolio summary
portfolio_summary = portfolio.groupby('p').agg({'value':sum,'var':sum,'result':sum})
portfolio_summary['return']= ((portfolio_summary['value']+portfolio_summary['result'])/portfolio_summary['value'])*100.0
portfolio_summary['risk'] = portfolio_summary['var'].apply(lambda x: np.sqrt(x)/100.)
portfolio_summary['sharpe']=(portfolio_summary['return']-risk_free_rate)/portfolio_summary['risk']
portfolio_summary.drop(labels=['var'],axis=1,inplace=True)
return portfolio_summary,portfolio
1
2
3
summary = dict()
summary['MonteCarlo'],mc = portfolio_returns(mc_portfolios)
summary['Balanced'],_ = portfolio_returns(balanced_portfolio)
Results
Figure 2 below illustrates the results and relationship between each randomised portfolios (grey dots) risk and investment return (%). The orange dot is the balance portfolio.
The green dot is the portfolio with the greatest Sharpe ratio, that is the portfolio with lowest risk in relation to the level of return in excess of the risk free rate. We see that this portfolio has a blend of investments in “Deep Impact” 9% and “Jumanji Inc” 81 %.
1
2
# Max Sharpe portfolio
mc.loc[mc['p']==summary['MonteCarlo'].sharpe.idxmax()]
n | name | price | mu | sigma | value | shares | p | result | var | |
---|---|---|---|---|---|---|---|---|---|---|
9164 | 6 | deep impact | 20 | 0.02 | 5 | 187.602982 | 9.380149 | 2037 | -18.592925 | 25 |
9165 | 0 | jumanji inc | 10 | 0.10 | 10 | 812.397018 | 81.239702 | 2037 | 1747.558702 | 100 |
Conclusion
- This method applies monte carlo (i.e. exhaustive search) to calculate a large number of randomised investment portfolios.
- Risk, Return, and Sharpe measures are calculated for each of the random portfolios, and for a balanced portfolio (i.e. equal allocation portfolio assuming no knowledge of where to invest).
- An optimal portfolio is identified using the maximum Sharpe ratio that maximises returns whilst minimising risk.
- Increasing the number of randomised portfolios increases the chances of identifying an optimal portfolio.
- However, finding the optimal portfolio is not garunteed. The likelihood of identifying the most optimal portfolio decreases with increasing number of investment options, and higher degrees of uncertainty of the investment returns and variances.
Thank you for reading. Next time I will run through a more sophisticated optimisation technique using Machine Learning. You can find the code to replicate the above analysis on my Github account here
References
- https://towardsdatascience.com/optimization-with-python-how-to-make-the-most-amount-of-money-with-the-least-amount-of-risk-1ebebf5b2f29
- https://colab.research.google.com/github/cvxgrp/cvx_short_course/blob/master/applications/portfolio_optimization.ipynb
- https://insightr.wordpress.com/2017/08/27/pricing-optimization-how-to-find-the-price-that-maximizes-your-profit/
- http://riskdatascience.net/usecases-auswahl/automated-portfolio-optimization-by-combining-ai-and-risk-methods/
- https://towardsdatascience.com/automating-portfolio-optimization-using-python-9f344b9380b9
- https://towardsdatascience.com/best-investment-portfolio-via-monte-carlo-simulation-in-python-53286f3fe93
- https://www.dummies.com/business/accounting/auditing/how-to-optimize-portfolio-risk/