This post will investigate the idea of reducing leverage when drawdowns are small, and increasing leverage as losses accumulate. It’s based on the idea that whatever goes up must come down, and whatever comes down generally goes back up.
I originally came across this idea from this blog post.
So, first off, let’s write an easy function that allows replication of this idea. Essentially, we have several arguments:
One: the default leverage (that is, when your drawdown is zero, what’s your exposure)? For reference, in the original post, it’s 10%.
Next: the various leverage levels. In the original post, the leverage levels are 25%, 50%, and 100%.
And lastly, we need the corresponding thresholds at which to apply those leverage levels. In the original post, those levels are 20%, 40%, and 55%.
So, now we can create a function to implement that in R. The idea being that we have R compute the drawdowns, and then use that information to determine leverage levels as precisely and frequently as possible.
Here’s a quick piece of code to do so:
require(xts) require(PerformanceAnalytics) drawdownLev <- function(rets, defaultLev = .1, levs = c(.25, .5, 1), ddthresh = c(-.2, -.4, -.55)) { # compute drawdowns dds <- PerformanceAnalytics:::Drawdowns(rets) # initialize leverage to the default level dds$lev <- defaultLev # change the leverage for every threshold for(i in 1:length(ddthresh)) { # as drawdowns go through thresholds, adjust leverage dds$lev[dds$Close < ddthresh[i]] <- levs[i] } # compute the new strategy returns -- apply leverage at tomorrow's close out <- rets * lag(dds$lev, 2) # return the leverage and the new returns leverage <- dds$lev colnames(leverage) <- c("DDLev_leverage") return(list(leverage, out)) }
So, let’s replicate some results.
require(downloader) require(xts) require(PerformanceAnalytics) download("https://dl.dropboxusercontent.com/s/jk6der1s5lxtcfy/XIVlong.TXT", destfile="longXIV.txt") xiv <- xts(read.zoo("longXIV.txt", format="%Y-%m-%d", sep=",", header=TRUE)) xivRets <- Return.calculate(Cl(xiv)) xivDDlev <- drawdownLev(xivRets, defaultLev = .1, levs = c(.25, .5, 1), ddthresh = c(-.2, -.4, -.55)) compare <- na.omit(cbind(xivDDlev[[2]], xivRets)) colnames(compare) <- c("XIV_DD_leverage", "XIV") charts.PerformanceSummary(compare['2011::2016'])
And our results look something like this:
XIV_DD_leverage XIV Annualized Return 0.2828000 0.2556000 Annualized Std Dev 0.3191000 0.6498000 Annualized Sharpe (Rf=0%) 0.8862000 0.3934000 Worst Drawdown 0.4870604 0.7438706 Calmar Ratio 0.5805443 0.3436668
That said, what would happen if one were to extend the data for all available XIV data?
> rbind(table.AnnualizedReturns(compare), maxDrawdown(compare), CalmarRatio(compare)) XIV_DD_leverage XIV Annualized Return 0.1615000 0.3319000 Annualized Std Dev 0.3691000 0.5796000 Annualized Sharpe (Rf=0%) 0.4375000 0.5727000 Worst Drawdown 0.8293650 0.9215784 Calmar Ratio 0.1947428 0.3601385
A different story.
In this case, I think the takeaway is that such a mechanism does well when the drawdowns for the benchmark in question occur sharply, so that the lower exposure protects from those sharp drawdowns, and then the benchmark spends much of the time in a recovery mode, so that the increased exposure has time to earn outsized returns, and then draws down again. When the benchmark continues to see drawdowns after maximum leverage is reached, or continues to perform well when not in drawdown, such a mechanism falls behind quickly.
As always, there is no free lunch when it comes to drawdowns, as trying to lower exposure in preparation for a correction will necessarily mean forfeiting a painful amount of upside in the good times, at least as presented in the original post.
Thanks for reading.
NOTE: I am currently looking for my next full-time opportunity, preferably in New York City or Philadelphia relating to the skills I have demonstrated on this blog. My LinkedIn profile can be found here. If you know of such opportunities, do not hesitate to reach out to me.
Pingback: Leverage Up When You’re Down? – Mubashir Qasim
This assumes that your returns are a mean reverting process, although you are trading VIX which as a proxy for volatility should be mean reverting. Couldn’t we test at assumption by doing a ADF test? Seems to me that what this strategy does is remove the tails of your return distribution, making it seem smoother. But as you mentioned in your article the cost is that, given you may have positive skewed return distribution and are missing out on a significant portion of your expected value from outsized positive winners. I think there are a few things that could be clarified, what are the effects of this if you are trading an underlying that is not mean reverting and what happens if you use this process on return distributions that have positive or negative skew (assuming that they have fat tails).
Pingback: Quantocracy's Daily Wrap for 09/05/2017 | Quantocracy
Pingback: Leverage Up When You’re Down? | A bunch of data
Pingback: Mundo Quant #1 – Stratsphera