Here in Australia, we’re right in the depths of the silly season. We indulge in long lunches, take days off work, and generally let our hair down.
In that spirit, I thought I might have some fun punting shitcoins.
(Maybe my definition of fun differs from yours, but let’s run with it).
For the uninitiated, the technical definition of a shitcoin is a recently launched cryptocurrency of dubious economic value and marginal liquidity.
These things have historically shown a noisy tendency to trend, which means that if you can be bothered trading them (marginal liquidity and all that) and don’t mind taking on the very real risk of total capital incineration, you can potentially make some money with simple trend-following rules.
A while back we looked at a simple trend-following strategy where we get long anything within 5 days of its 20-day high:
As part of my homage to the silly season, I intend to throw a small amount of capital at this strategy, turn it up to full noise, and see how we go.
But I’d like to do it at least somewhat sensibly and systematically.
To that end, I’ll manage the strategy to a drawdown target by reducing the leverage as a function of drawdown from all time equity highs. I’ll be turbo long (5x leverage) when I’m at all time highs, and I’ll be at 0 leverage when I’m drawn down 90% from all time highs. I’ll reduce my leverage linearly between these two extremes as a function of drawdown.
But these are illiquid shitcoins that are flying around all over the place. I don’t want to be constantly rebalancing – that’d be a full time job. My silly season would quickly turn into boring season.
So how often should I rebalance things? What are the implications of rebalancing more or less frequently?
One way to answer that is through simulation – we can generate a statistically significant number of random outcomes and see how our decisions about leverage played out. Our results are only as good as our assumptions that go into the simulator, but even if those assumptions are off, we can still gain some important intuition.
In this case, I’ll set up a Geometric Brownian Motion (GBM) simulator and generate a ton of different random price series that look like shitcoin prices.
A while back, I shared some code for generating GBM price series using vectorisation. You can check it out here.
But this time, I want to add some proper shitcoin dynamics:
- These things tend to show some autocorrelation (hence why trend following has worked on these in the past)
- They tend to be quite jumpy
I’ll add some autocorrelation using an autorgressive process. And I’ll add some random jumps via a jump diffusion process.
These things make the vectorised approach impossible, since subsequent values depend on previous ones.
But to speed things up, we’ll outsource the autoregressive and jump diffusion components to a C++ function and call that from our R session.
Let’s get to it.
cppFunction("
NumericMatrix generateAR1WithJumps(int nsim, int t, double phi, double lambda, double mu_j, double sigma_j) {
NumericMatrix epsilon(t-1, nsim);
NumericVector eta(nsim);
NumericVector jumpSize(nsim);
// Initial values from normal distribution
for(int j = 0; j < nsim; ++j) {
epsilon(0, j) = R::rnorm(0, 1);
}
// AR(1) process with jumps
for(int i = 1; i < t-1; ++i) {
for(int j = 0; j < nsim; ++j) {
eta[j] = R::rnorm(0, 1);
epsilon(i, j) = phi * epsilon(i-1, j) + eta[j];
// Generate jumps
if(R::runif(0, 1) < lambda) {
jumpSize[j] = R::rnorm(mu_j, sigma_j);
epsilon(i, j) += jumpSize[j];
}
}
}
return epsilon;
}
")
gbm_autocor_jumps <- function(nsim = 100, t = 25, mu = 0, sigma = 0.1, S0 = 100, dt = 1./(365*24), phi = 0.5, lambda = 0.01, mu_j = 0, sigma_j = 0.1) {
epsilon <- generateAR1WithJumps(nsim, t, phi, lambda, mu_j, sigma_j)
gbm <- exp((mu - sigma * sigma / 2) * dt + sigma * epsilon * sqrt(dt))
gbm <- apply(rbind(rep(S0, nsim), gbm), 2, cumprod)
return(gbm)
}
The next part is the tricky and fairly slow bit.
We simulate the returns to the ape new highs strategy being managed to a drawdown target.
It’s a time-consuming operation because our target leverage depends on our current drawdown, and so we must do it all in a big for
loop.
Ideally I’d like to generate multiple universes of simulated shitcoins and then run this ape strategy simulation for each universe. That would generate a histogram of outcomes, rather than the single outcome we see here, enabling us to make probabilistic conclusions and extract further insight.
I’ll leave to you. For the purposes of this post, I’ll just run it on the universe we generated previously. I’ll simulate a rebalance period of 24 hours (or when a position changes).
Summary
In this post, we shared an efficient way to generate Geometric Brownian Motion (GBM) price series that include autocorrelation and jumps.
One can use such a tool to gain intuition into various noisy, random processes, such as turbo-punting shitcoins to a drawdown target.
In this example, we used the GBM simulator to get a feel for how often we might need to rebalance an overly leveraged shitcoin trend-following strategy. We can run the simulator with various parameterisations and get a feel for how often we destroy our capital under different conditions, or how often we should think about rebalancing back to our target leverage.
I hope you have as much fun as I intend to this silly season.