Friday 10 June 2016

mini-Meucci : Applying The Checklist - Steps 3-5

"In the future, instead of striving to be right at a high cost, it will be more appropriate to be flexible and plural at a lower cost. If you cannot accurately predict the future then you must flexibly be prepared to deal with various possible futures."
Edward de Bono, author and thinker extraordinaire (born 1933)


In this third leg of The Checklist tour, we will take 3 more steps, Projection, Pricing and Aggregation.

Quick Recap

Goal: Apply Meucci's The Checklist to create a toy example low volatility equity portfolio using DJIA stocks, with an investment horizon of 21 days.

Risk drivers: log of stock prices (values): $X_t = \ln V_t$, where $X$ is risk driver, $V$ is stock price (value).

Invariants: modelled using a simple random walk: $X_{t+1} = X_t + \epsilon_{t+1}$, where $\epsilon$ is invariant.

Estimation: Historical (simulation) with Flexible Probabilities approach (HFP)

Projection to the Horizon

The goal of this step is to create various possible scenarios (i.e. de Bono's "various possible futures") of the risk drivers at the investment horizon.

"Ultimately we are interested in the value of our positions at the investment horizon. In order to determine the distribution of our positions, we must first determine the distribution of the risk drivers at the investment horizon. This distribution, in turn, is obtained by projecting to the horizon the invariants distribution, obtained in the Estimation Step 2."
The Prayer (former Checklist)

So 2 sub-steps are involved - first project the invariants, then recover the risk drivers.

In our toy example, we can take a 'short-cut' and set the estimation interval equal to the investment horizon i.e. 21 days (in the previous 2 posts the estimation interval was 1 day). In this case, the estimation step also performs projection of the invariants.

To recover the future risk driver, simply apply the right-hand side of our random walk model i.e. risk driver at horizon = risk driver today plus invariant at horizon.

In general though, if you have an estimation interval shorter than your investment horizon (e.g. 5-day estimation interval and 20-day horizon, you'll need to apply the 2-step recipe of 'project then recover' recursively (e.g. 4 times one after the other).

Read The Prayer (former Checklist) and see slide #33 Projection to the Horizon (general case) and slide #8 (2-stock example).

Like to know more? Go to the ARPM Bootcamp!

Python Code Example

In [1]:
%matplotlib inline
from pandas_datareader import data
import numpy as np
import datetime
import math
import matplotlib.pyplot as plt
import seaborn

# Get Yahoo data on 30 DJIA stocks and a few ETFs
tickers = ['MMM','AXP','AAPL','BA','CAT','CVX','CSCO','KO','DD','XOM','GE','GS',
           'HD','INTC','IBM','JNJ','JPM','MCD','MRK','MSFT','NKE','PFE','PG',
           'TRV','UNH','UTX','VZ','V','WMT','DIS','SPY','DIA','TLT','SHY']
start = datetime.datetime(2008, 4, 1)
end = datetime.datetime(2016, 5, 31)
rawdata = data.DataReader(tickers, 'yahoo', start, end) 
prices = rawdata.to_frame().unstack(level=1)['Adj Close']

# Quest for Invariance (random walk model) and Estimation (historical approach)
risk_drivers = np.log(prices)
# Set estimation interval = investment horizon (tau)
tau = 21 # investment horizon in days
invariants = risk_drivers.diff(tau).drop(risk_drivers.index[0:tau])

# Projection to the Investment Horizon
# Using the historical simulation approach and setting estimation interval = 
# investment horizon, means that projected invariants = invariants.
# Recover the projected scenarios for the risk drivers at the tau-day horizon
risk_drivers_prjn = risk_drivers.loc[end,:] + invariants

Pricing at the Horizon

We now have the projected distribution of the risk drivers and the goal of this step is calculate the projected profit and loss (P&L in currency terms not percentage returns) per unit of each asset.

First sub-step is to derive the projected prices from the projected risk drivers. Recall that in our case the risk drivers were log prices, so we can just exponentiate them to get back the prices.

Second sub-step of calculating the $P&L per unit of each asset is simply subtract today's price from the projected price.

Do this for all tickers/scenarios and you get the joint distribution of the ex-ante $P&L's.

Here is the code to do it - a bit different from the formulas in the slides but equivalent...

Python Code Example

In [2]:
# Compute the projected $ P&L per unit of each stock for all scenarios
prices_prjn = np.exp(risk_drivers_prjn)
pnl = prices_prjn - prices.loc[end,:]

Aggregation

In this step we take the ex-ante $P&L's per unit of each stock and multiply by the quantity of each stock held in the portfolio, and add them up to get the portfolio (aggregated) P&L. Do this for all scenarios and we get the distribution of the projected portfolio P&L at the horizon.

Two examples are shown below for an equally weighted portfolio of the 30 DJIA stocks. The first shows the distribution of the portfolio P&L using equal probabilities for the scenarios, while the second uses time-conditioned flexible probabilities...

Python Code Example

In [8]:
# Aggregation at the Investment Horizon
# Aggregate the individual stock P&Ls into projected portfolio P&L for all scenarios
# Assume equally weighted protfolio at beginning of investment period
capital = 1e6
n_asset = 30
asset_tickers = tickers[0:30]
asset_weights = np.ones(n_asset) / n_asset
# initial holdings ie number of shares
h0 = capital * asset_weights / prices.loc[end, asset_tickers]
pnl_portfolio = np.dot(pnl.loc[:, asset_tickers], h0)

# Apply flexible probabilities to portfolio P&L scenarios
n_scenarios = len(pnl_portfolio)

# Equal probs
equal_probs = np.ones(n_scenarios) / n_scenarios

# Time-conditioned flexible probs with exponential decay
half_life = 252 * 2 # half life of 2 years
es_lambda = math.log(2) / half_life
exp_probs = np.exp(-es_lambda * (np.arange(0, n_scenarios)[::-1]))
exp_probs = exp_probs / sum(exp_probs)
# effective number of scenarios
ens_exp_probs = np.exp(sum(-exp_probs * np.log(exp_probs))) 

# Projected Distribution of Portfolio P&L at Horizon  with flexible probabilities
import rnr_meucci_functions as rnr
mu_port, sigma2_port = rnr.fp_mean_cov(pnl_portfolio.T, equal_probs)  
mu_port_e, sigma2_port_e = rnr.fp_mean_cov(pnl_portfolio.T, exp_probs)  

print('Ex-ante portfolio $P&L mean over horizon (equal probs) : {:,.0f}'\
      .format(mu_port))
print('Ex-ante portfolio $P&L volatility over horizon (equal probs) : {:,.0f}'\
      .format(np.sqrt(sigma2_port)))
print('')
print('Ex-ante portfolio $P&L mean over horizon (flex probs) : {:,.0f}'\
      .format(mu_port_e))
print('Ex-ante portfolio $P&L volatility over horizon (flex probs) : {:,.0f}'\
      .format(np.sqrt(sigma2_port_e)))

fig = plt.figure(figsize=(9, 8))
ax = fig.add_subplot(111)
ax.hist(pnl_portfolio, 50, weights=exp_probs) 
ax.set_title('Ex-ante Distribution of Portfolio P&L \
             (flexbile probabilities with exponential decay)') 
plt.show()
Ex-ante portfolio $P&L mean over horizon (equal probs) : 10,431
Ex-ante portfolio $P&L volatility over horizon (equal probs) : 49,829

Ex-ante portfolio $P&L mean over horizon (flex probs) : 10,395
Ex-ante portfolio $P&L volatility over horizon (flex probs) : 39,750

No comments:

Post a Comment