How it works...

As mentioned in the introduction, we continued the example from the previous recipe. That is why we had to run Step 1 to Step 4 from the previous recipe, Finding the Efficient Frontier using Monte Carlo simulations (not shown here for brevity), to have all the required data. As an extra prerequisite, we had to import the optimization module from scipy.

In Step 2, we defined two functions, which returned the expected portfolio return and volatility, given historical data and the portfolio weights. We had to define these functions instead of calculating these metrics directly, as we used them in the optimization procedure. The algorithm iteratively tries different weights and needs to be able to use the current values of the target variables (weights) to arrive at the metric it tries to optimize.

In Step 3, we defined a function called get_efficient_frontier. Its goal is to return a list containing the efficient portfolios, given historical metrics and the considered range of returns. This was the most important step of the recipe and contained a lot of nuances.

We describe the logic of the function sequentially:

  • The outline of the function is that it runs the optimization procedure for each expected return in the considered range, and stores the resulting optimal portfolio in a list.
  • Outside of the for loop, we define a couple of objects that we pass into the optimizer:
    • The arguments that are passed to the objective function. In this case, these are the historical average returns and the covariance matrix. The function that we optimize must accept the arguments as inputs. That is why we pass the returns to the get_portfolio_volatility function, even though they are not necessary for calculations.
    • Bounds (a nested tuple)—for each target variable (weight), a tuple containing the boundaries—minimum and maximum allowable values. In this case, the values span the range from 0 to 1 (no negative weights, as per the MPT). 
    • initial_guess, which is the initial guess of the target variables. The goal of using the initial guess is to make the optimization run faster and more efficiently. In this case, the guess is the 1/n allocation.
  • Inside the for loop, we define the last element used for the optimization—the constraints. We define two constraints:
    • The expected portfolio return must be equal to the provided value.
    • The sum of the weights must be equal to 1.
  • The first constraint is the reason why the constraint's tuple is defined within the loop—as the loop passes over the considered range of expected portfolio returns, and for each value, we find the optimal risk level.
  • We run the optimizer with the Sequential Least-Squares Programming (SLSQP) algorithm, which is frequently used for generic minimization problems. For the function to be minimized, we pass the specially prepared get_portfolio_volatility function.
The optimizer sets the equality (eq) constraint to 0. That is why the intended constraint, np.sum(weights) == 1, is expressed as np.sum(weights) - 1 == 0.

In Steps 4 and 5, we defined the range of expected portfolio returns (based on the range we empirically observed in the previous recipe) and ran the optimization function.

In Step 6, we iterated over the list of efficient portfolios and extracted the optimal volatilities. We extracted the volatility from the scipy.optimize.OptimizeResult object by accessing the fun element. This stands for the optimized objective function—in this case, the portfolio volatility.

In Step 7, we added the calculated Efficient Frontier on top of the plot from the previous recipe, Finding the Efficient Frontier using Monte Carlo simulations. All the simulated portfolios lie on or below the Efficient Frontier, which is what we expected to happen.

In Steps 8 and 9, we identified the minimum volatility portfolio, printed the performance metrics, and showed the portfolio's weights (extracted from the Efficient Frontier).

We can now compare the two minimum volatility portfolios: the one obtained using Monte Carlo simulations, and the one we received from optimization. The prevailing pattern in the allocation is the same—allocate the majority of the available resources to Facebook and Microsoft. We can also see that the volatility of the optimized strategy is slightly lower. This means that among the 100,000 portfolios, we have not simulated the actual minimum volatility portfolio.

..................Content has been hidden....................

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