Posts Portfolio Optimisation: Monte Carlo method
Post
Cancel

Portfolio Optimisation: Monte Carlo method

Jupyter notebook here

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.

nnamepricemusigma
00jumanji inc100.1010
11evolution ltd200.2020
22the incredibles inc300.3030
33men in black & co200.0840
44goldmember gmbh500.0515
55dantes peak100.2520
66deep impact200.025

png

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.

nnamepricemusigmavaluesharesp
03men in black & co200.0840201.35336810.0676680
16deep impact200.02519.9069060.9953450

Balanced Portfolio

We also create A balanced portfolio. This provides a usefull benchamrk and represents the strategy of investing in each stock equally.

nnamepricemusigmavaluesharesp
00jumanji inc100.1010333.3333.3330balanced
11evolution ltd200.2020333.3316.6665balanced
22the incredibles inc300.3030333.3311.1110balanced
33men in black & co200.0840333.3316.6665balanced
44goldmember gmbh500.0515333.336.6666balanced
55dantes peak100.2520333.3333.3330balanced
66deep impact200.025333.3316.6665balanced

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.

png

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()]
nnamepricemusigmavaluesharespresultvar
91646deep impact200.025187.6029829.3801492037-18.59292525
91650jumanji inc100.1010812.39701881.23970220371747.558702100

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/
This post is licensed under CC BY 4.0 by the author.