How it works...

In Step 2, we defined parameters used for this recipe, such as the considered timeframe, the risky assets we wanted to use for building the portfolio, and the number of simulations. An important thing to note here is that we also ran RISKY_ASSETS.sort(), to sort the list alphabetically. This matters when interpreting the results as when downloading data from Yahoo Finance using the yfinance library, the obtained prices are ordered alphabetically, not as specified in the provided list. Having downloaded the stock prices, we calculated simple returns using the pct_change method of a pandas DataFrame, and dropped the first row containing NaNs.

For evaluating the potential portfolios, we needed the average (expected) annual return and the corresponding covariance matrix. We obtained them by using the mean() and cov() methods of the DataFrame. We also annualized both metrics by multiplying them by 252 (the average number of trading days in a year).

We needed the covariance matrix, as for calculating the portfolio volatility, we also needed to account for the correlation between the assets. To benefit from significant diversification, the assets should have low positive or negative correlations.

In Step 5, we calculated the random portfolio weights. Following the assumptions of the MPT (refer to the chapter introduction for reference), the weights needed to be positive and sum up to 1. To achieve this, we first generated a matrix of random numbers (between 0 and 1), using np.random.random. The matrix was of size N_SIMULATIONS x N_ASSETS. To make sure the weights totaled 1, we divided each row of the matrix by its sum.

In Step 6, we calculated the portfolio metrics—returns and standard deviation. To calculate the expected annual portfolio returns, we had to multiply the weights by the previously calculated annual averages. For the standard deviations, we had to use the following formula: , where  is the vector of weights and  is the historical covariance matrix. To calculate the standard deviation, we iterated over all the simulated portfolios, using a for loop.

The for loop implementation is actually faster than the vectorized matrix equivalent: np.diag(np.sqrt(np.dot(weights, np.dot(cov_mat, weights.T)))). The reason for that is the quickly increasing number of off-diagonal elements to be calculated, which, in the end, does not matter for the metrics of interest. This approach is faster than the for loop for only a relatively small number of simulations (~100).

For this example, we assumed that the risk-free rate was 0%, so the Sharpe ratio of the portfolio could be calculated as portfolio returns/portfolio volatility. Another possible approach would be to calculate the average annual risk-free rate over 2018, and to use the portfolio excess returns for calculating the ratio.

The last three steps led to visualizing the results. First, we put all the relevant metrics into a pandas DataFrame. Second, we created an array of expected returns from the sample. To do so, we used np.linspace, with the min and max values from the calculated portfolio returns. We rounded the numbers to two decimals, to make the calculations smoother. For each expected return, we found the minimum observable volatility. In cases where there was no match, as can happen with equally spread points on the linear space, we skipped that point.

In the very last step, we plotted the simulated portfolios, the individual assets, and the approximated Efficient Frontier in one plot. The shape of the frontier was a bit jagged, which can be expected when using only simulated values that are not that frequent in some extreme areas. Additionally, we colored the dots representing the simulated portfolios by the value of the Sharpe ratio.

You can find the available colormaps here: https://matplotlib.org/examples/color/colormaps_reference.html. Depending on the problem at hand, a different colormap might be more suitable (sequential, diverging, qualitative, and so on).
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.2.212