This post is a token of appreciation for Faisal Habib who taught us structured products this summer.

As commonly known among people who are familiar with leveraged ETFs, the tracking error of those products tend to be larger than what we intuitively expected. This phenomenon has been explored and explained by Avellaneda and Zhang (2009). More information can also be found here. In a nutshell, the discrepancy resides in the borrowing cost incurred in a replication portfolio and extra realized variance in a continuous model. The resources linked above have more details, here I think it’ll be interesting just to model it out and take a look at the simulated results.

To do this I simulated four time-series.

- An underlying that follows GBM.
- An imaginary product that provides perfect leverage simply by multiplying the underlying return by the leverage ratio.
- A leveraged product that achieves leveraged return by constructing a static replication portfolio with risk-free rate r.
- A leveraged ETF modeled in continuous time, i.e., drift term adjusted using Ito’s lemma.

Here we have the results after running it once with 2x leverage and daily frequency (delta_t = 1/252). I know it strikingly resembles the shape of S&P500 but I swear this is pure coincidence (I thought it’s cool, too).

And annualized returns:

underlying_process | simple_multiplication | static_replication | leveraged_etf |

12.0% | 25.4% | 23.6% | 22.3% |

A quick note. The annualized return of the simple multiplication process (# 2) is way above 2 times of the underlying because of the compounding effect in a raging bull market we just created. The static replication (# 3) underperforms # 2 roughly by the same amount of the annual risk-free rate. The leveraged ETF (# 4) underperforms # 3 by the annual variance of the underlying. These results are consistent with previous studies.

There are a lot of ways to play with this so I’ll post the source code here for anyone who’s interested in trying it out (or let me know if I made any mistakes).

LETF <- function(S_0 = 100, r_f = 0.015, borrow_cost = 0.01, mu = 0.05, sigma = 0.1, end_t = 5, delta_t = 1/252, leverage = 2) { # create a vector of the undelrying process n <- end_t / delta_t underlying_process <- zoo(0, 1:n) underlying_process[1] <- S_0 if (leverage > 1) {borrow_cost <- 0} # create vectors of simple_multiplication, static replication # and leveraged ETF without expense ratio simple_multiplication <- underlying_process static_replication <- underlying_process leveraged_etf <- underlying_process for (i in 2:n) { # the random component of the GBM model rdn <- rnorm(1) # model the underlying with GBM underlying_process[i] <- coredata(underlying_process[i - 1]) * exp((mu - sigma ^ 2 / 2) * delta_t + sigma * sqrt(delta_t) * rdn) underlying_log_return <- log(coredata(underlying_process[i]) / coredata(underlying_process[i - 1])) # model a leveraged process by simplely multiplying underlying returns simple_multiplication_log_return <- leverage * underlying_log_return simple_multiplication[i] <- simple_multiplication[i - 1] * exp(simple_multiplication_log_return) # model static replication return with equation (1) and (2) in # Avellaneda and Zhang (2009) static_replication_log_return <- underlying_log_return * leverage - ((leverage - 1) * r_f - borrow_cost * leverage) * delta_t static_replication[i] <- coredata(static_replication[i - 1]) * exp(static_replication_log_return) # model leveraged etf return with equation (10) in # Avellaneda and Zhang (2009) leveraged_etf[i] <- coredata(leveraged_etf[i - 1]) * exp(underlying_log_return) ^ leverage * exp(-((leverage - 1) * r_f + sigma ^ 2 * leverage * (leverage - 1) / 2) * delta_t) } return(merge(underlying_process, simple_multiplication, static_replication, leveraged_etf)) }

Roy