There's more...

We can also plot the two Efficient Frontiers for comparison—the one calculated by minimizing the volatility per expected level of return, and the other one using the convex optimization and maximizing the risk-adjusted return.

The code is as follows:

x_lim = [0.25, 0.6]
y_lim = [0.125, 0.325]

fig, ax = plt.subplots(1, 2)
ax[0].plot(vols_range, rtns_range, 'g-', linewidth=3)
ax[0].set(title='Efficient Frontier - Minimized Volatility',
xlabel='Volatility',
ylabel='Expected Returns',
xlim=x_lim,
ylim=y_lim)

ax[1].plot(portf_vol_cvx_ef, portf_rtn_cvx_ef, 'g-', linewidth=3)
ax[1].set(title='Efficient Frontier - Maximized Risk-Adjusted Return',
xlabel='Volatility',
ylabel='Expected Returns',
xlim=x_lim,
ylim=y_lim)

The only thing to note is that the one obtained using minimization is smoother, as we used more points to calculate the frontier:

Another interesting concept we can incorporate into the analysis is the maximum allowable leverage. We replace the non-negativity constraints on the weights with a max leverage constraint, using the norm of a vector.

In the following code, we only show what was added to the previous code block:

max_leverage = cp.Parameter()
problem_with_leverage = cp.Problem(objective_function,
[cp.sum(weights) == 1,
cp.norm(weights, 1) <= max_leverage])

In the following code block, we modify the code, this time to include two loops—one over potential values of the risk-aversion parameter, and the other one indicating the maximum allowable leverage. Max leverage equal to 1 (meaning no leverage) results in a case similar to the previous optimization problem (only this time, there is no non-negativity constraint).

We also redefine the objects, storing the results to be either larger 2D matrices (np.ndarrays) or including a third dimension, in the case of weights.

The code is as follows:

LEVERAGE_RANGE = [1, 2, 5]
len_leverage = len(LEVERAGE_RANGE)
N_POINTS = 25

portf_vol_l_ef = np.zeros((N_POINTS, len_leverage))
portf_rtn_l_ef = np.zeros(( N_POINTS, len_leverage))
weights_ef = np.zeros((len_leverage, N_POINTS, n_assets))

for lev_ind, leverage in enumerate(LEVERAGE_RANGE):
for gamma_ind in range(N_POINTS):
max_leverage.value = leverage
gamma.value = gamma_range[gamma_ind]
problem_with_leverage.solve()
portf_vol_l_ef[gamma_ind, lev_ind] = cp.sqrt(portf_vol_cvx).value
portf_rtn_l_ef[gamma_ind, lev_ind] = portf_rtn_cvx.value
weights_ef[lev_ind, gamma_ind, :] = weights.value

In the following code block, we plot the Efficient Frontiers for different maximum leverages. We can clearly see that higher leverage increases returns and, at the same time, allows for greater volatility:

fig, ax = plt.subplots()

for leverage_index, leverage in enumerate(LEVERAGE_RANGE):
plt.plot(portf_vol_l_ef[:, leverage_index],
portf_rtn_l_ef[:, leverage_index],
label=f'{leverage}')

ax.set(title='Efficient Frontier for different max leverage',
xlabel='Volatility',
ylabel='Expected Returns')
ax.legend(title='Max leverage');

Executing the preceding code generates the following plot:

Lastly, we also recreate the plot showing weight allocation per varying risk-aversion levels. With a maximum leverage of 1, there is no short-selling. 

The code is as follows:

fig, ax = plt.subplots(len_leverage, 1, sharex=True)

for ax_index in range(len_leverage):
weights_df = pd.DataFrame(weights_ef[ax_index],
columns=RISKY_ASSETS,
index=np.round(gamma_range, 3))
weights_df.plot(kind='bar',
stacked=True,
ax=ax[ax_index],
legend=None)
ax[ax_index].set(ylabel=(f'max_leverage = {LEVERAGE_RANGE[ax_index]}'
' weight'))


ax[len_leverage - 1].set(xlabel=r'$gamma$')
ax[0].legend(bbox_to_anchor=(1,1))
ax[0].set_title('Weights allocation per risk-aversion level',
fontsize=16)

Executing the preceding code generates the following plot:

We can spot a pattern where, with an increase in risk aversion, investors stop using leverage altogether, and converge to a similar allocation for all levels of maximum permitted leverage.

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

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