← Projects

Crypto QuantLab

11 min read

Motivation

Around my junior year of highschool, I started getting big into "internet money". By this, I mean various different ways to get rich online. This started off with daytrading, then it went to NFTs, then finally it just landed on crypto. Ever since then, the technology and applications of Crypto/Web3 have been super interesting to me. Fast forward a few years and I'm a sophomore at JHU who's getting more and more into programming and finance-y applications of software.

After creating my first project, this blend of interesting between software and cryptocurrency would start my next project, a comprehensive data platform and suite of tools that would amplify my ability to make money in the market. Well, I sort of just never finished that version. There was never anything too interesting in it and eventually I wanted to take the project in a completely different route. Instead of just being a boilerplate dashboard with redundant data you could find anywhere else, the other path became clear: a quantitative research system for crypto currency.

With that, the goal was clear, use this as a reason to learn some cool things about quant research and how the practice actually works.

Design Decisions

By the virtue of the fact that this project was meant to be less technical from a programming sense, the design is not noteworthy. A simple HTTP server that routes the frontend to backend calculation functions is the entire scope of the project. With that being said, the lack of nuance in the code is made up with some neat mathematical tricks that are, or at least have been, used by quantitative researchers.

Mathematical Deep-Dive

There are four main categories of theory and math we focused on. Lets go through categories one by one and understand its theory and its usecase in the system.

Part I: Portfolio Theory

portfolio theory is a massive part with investing today. Managers conducting research on different types of action abide by contemporary portfolio theory. While some may consider this a little old-school, the results don't lie. In this project's usecase, we're just running one model: Mean-Variance Optimization. Curated by American economist Harry Markowitz, this model attempts to maximize return per unit of risk. If you know your stuff, you'll realize that this is just saying to maximize the sharpe ratio. We can find this given expected returns μ\mu and covariance matrix ∑\sum, to calculate the portfolio weights/allocation that maximize the risk-to-reward ratio. The optimal portfolio is found on the curve of possible portfolio weights, known as the efficient frontier, where you find the tangency portfolio when considering these constraints:

max⁡wμ⊤ww⊤Σws.t.∑iwi=1wi≥0 \begin{aligned} \max_{w} \quad & \frac{\mu^\top w}{\sqrt{w^\top \Sigma w}} \\ \text{s.t.} \quad & \sum_i w_i = 1 \\ & w_i \geq 0 \end{aligned}

Then, you will find the optimal portfolio. Of course, this is not a flawless money-making machine. Some drawbacks are:

  • Inputs (μ\mu, ∑\sum) are estimated from historical data and are therefore not 100% accurate
  • There is a long-only position constraint, eliminating short-selling entirely. That is not realistic

Part II: Cointegration & Pairs Trading

Some of the most lucrative strategies in history have leveraged a powerful statistical property known as cointegration. Before getting into what it is, here's the intuition: most asset prices are random walks, meaning they wander endlessly with no stable mean, no tendency to revert, just noise on top of noise. Cointegration is the rare case where two of these wandering series are tethered together. They can each drift forever, but they can never permanently drift apart.

Here's a concrete example. Imagine $BTC and $ETH tend to move together over the long run. Not necessarily perfectly, and not always, but there's an underlying relationship that keeps them from diverging indefinitely. Modern systems detect this relationship statistically, then watch for moments when it breaks down. When $ETH gets cheap relative to $BTC beyond what the historical relationship would predict, that's a signal: long ETH, short \BTC, and wait for the spread to converge back. The math guarantees it has toEventually, that is. That guarantee is what makes this interesting. It's not just a pattern someone eyeballed in a chart. It's a provable statistical property, and the trade is the exploitation of a temporary violation of it.

The formal framework that makes this rigorous is known as the Vector Error Correction Model, or VECM for short. Given a vector of log prices XtX_t,

ΔXt=ΠXt−1+Γ1ΔXt−1+εt\Delta X_t = \Pi X_{t-1} + \Gamma_1 \Delta X_{t-1} + \varepsilon_t

Breaking this down, ΔXt\Delta X_t is just the vector of daily returns, not too interesting. What is interesting is Π\Pi, which attempts to encode all long-run relationships between the assets. Diving deeper,

Π=αβ⊤\Pi = \alpha \beta^\top

Here, β\beta holds the cointegrating vectors. When we transpose beta, β⊤Xt\beta^\top X_t becomes the stationary spread(s). Essentially, this is what captures the invariant relationship between the two assets. On the other hand, α\alpha represents the adjustment speeds, or how aggressively each asset corrects back towards the equilibrium spread. Finally, the rank of Π\Pi is the number of independent long-run relationships. If rank(Π)=r>0\text{rank}(\Pi) = r > 0, there are rr cointegrating relationships to exploit.

The natural follow-up question is, "How can we determine the rank?". Let's intuit this first. Trivially, we know that rank is zero if Π\Pi is a zero matrix. Now, assume that we know Π≠0\Pi \neq 0, the next step is to break it down further with our second equation αβ⊤\alpha \beta^\top. The rank is determined now by the number of nonzero columns in β⊤\beta^\top, at least in theory. The real problem lies in the fact that if you naively estimated Π\Pi from data, the noise in the data would trump the actual signals and you would find a full-rank matrix every time.

To solve this problem, Søren Johansen created the aptly named Johansen test. Instead of directly estimating Π\Pi from data, the test finds the rank of Π\Pi indirectly through a cleaner procedure. Given the complexity of the original VECM model, the first step of the Johansen test is to strip out the short-run dynamics. This is done by regressing ΔXt\Delta X_t on the lagged differences ΔXt−1,...,ΔXt−k\Delta X_{t-1}, ..., \Delta X_{t-k} and saving the residuals R0tR_{0t}. Then, we simply repeat the process for Xt−1X_{t-1} with the same lags and saving the residuals as R1tR_{1t}. At this point, both series filter for only the long-term information by removing everything that short-run autocorrelation can explain. R0tR_{0t} and R1tR_{1t} consist solely of the long-run co-movement signal, where R0tR_{0t} represents filtered price changes and R1tR_{1t} represents filtered price levels.

The next step is to solve a generalized eigenvalue problem. Given our residuals from step one, we construct the cross-product matrices S00S_{00}, S11S_{11}, and S01S_{01}. Here is what each conceptually represents:

  1. S00=1T∑t=1TR0tR0t⊤S_{00} = \frac{1}{T}\sum_{t=1}^T R_{0t}R_{0t}^\top: how price changes co-vary with each other
  2. S11=1T∑t=1TR1tR1t⊤S_{11} = \frac{1}{T}\sum_{t=1}^T R_{1t}R_{1t}^\top: how price levels co-vary with each other
  3. S01=1T∑t=1TR0tR1t⊤S_{01} = \frac{1}{T}\sum_{t=1}^T R_{0t}R_{1t}^\top: how price changes co-vary with price levels

Once these matrices are calculated, we solve:

∣S01⊤S00−1S01−λS11∣=0|S_{01}^\top S_{00}^{-1} S_{01} - \lambda S_{11}| = 0

Each eigenvalue λ^i\hat{\lambda}_i measures the canonical correlation between R0tR_{0t} and R1tR_{1t} in a particular direction. Larger eigenvalues indicate that the linear combination of prices strongly predicts tomorrow's correction, highlighting a mean-reverting, cointegrating relationship. Eigenvalues close to zero indicate that direction has no predictive power and is a random walk.

Rather than drawing an arbitrary cutoff for significance on eigenvalues, Johansen formalizes the counting with:

λtrace(r)=−T∑i=r+1nln⁡(1−λ^i)\lambda_{\text{trace}}(r) = -T \sum_{i=r+1}^{n} \ln(1 - \hat{\lambda}_i)

This tests the null hypothesis where rank≤r\text{rank} \leq r by asking whether the remaining eigenvalues are all statistically indistinguishable from zeroThat is, whether that linear combination of prices has no mean-reverting pull and behaves like a random walk. If they are, ln⁡(1−λ^i)≈0\ln(1 - \hat{\lambda}_i) \approx 0 for each and the sum is small, and you fail to reject rank rr. Conversely, if any eigenvalue is significant, the sum grows large, rejecting the null and concluding that the rank is at least r+1r + 1. This process repeats starting from r=0r = 0, incrementing until you fail to reject.

This completely sidesteps the noise problem because it never estimates Π\Pi directly. Instead, it finds the directions in price space that maximally explain mean reversion, and those directions are the cointegrating vectors themselves, the spreads you ultimately trade.

Part III: Systematic Strategies

Modern trading systems rely heavily on computer programs that run curated algorithms, entering and exiting the market based on various conditions. These programs fall under the category of systematic investing. The art of systematic investing lies in finding certain configurations of parameters modeling volume, price change, volatility, and many other metrics that together maximize returns. In this project I've implemented a few of the more popular strategies in systematic investing. The strategies are quick and digestibleThe simplicity of these algorithms is actually a feature when you consider a fascinating tradeoff. Systematic investing requires programs to be blazingly fast and to beat out their competition. The nuance lies in the tradeoff between program logic and speed. The more complicated an algorithm or trading decision is, the slower it runs, but the algorithm must also have enough nuance to be profitable. I digress

The first strategy focuses solely on momentum. The core belief is that recent winners are more likely to keep winning and recent losers are more likely to keep losing. It turns out that this is one of the most empirically robust anomalies in the markets, showing up across asset classes, geographies, and time periods going back over a century.

From an implementation perspective, the specific flavor here is cross-sectional momentumCross-sectional momentum is market neutral and typically produces a stronger, less noisy signal than absolute momentum since broad market moves affect all assets equally and cancel out. The distinction is that we aren't looking at whether an asset goes up in absolute terms, but whether it is winning or losing relative to the other assets in the basket. The process is as follows:

  1. For each day tt, compute the 21-day cumulative return for each asset
  2. Rank all assets by that return as a percentile in [0,1][0, 1]
  3. Assign positions: +1+1 if percentile >0.6> 0.6, −1-1 if percentile <0.4< 0.4, 00 otherwise
  4. Portfolio return: rt=∑iwi,t−1⋅ri,tr_t = \sum_i w_{i,t-1} \cdot r_{i,t}

The second strategy is mean reversion. Instead of betting on winners and losers continuing to diverge, this strategy assumes that outlier prices return back to their recent mean. If $BTC has been trading around $80K over the last 20 days but is now sitting at $60K, the strategy bets that BTC will revert back toward \80K and enters a long position. To put it simply, it trades the move back to the mean.

In a technical sense, all we need here is basic statistics. Leveraging z-scores relative to a 20-day rolling window:

zt=pt−μ20σ20z_t = \frac{p_t - \mu_{20}}{\sigma_{20}}
  1. For each day tt, compute the z-score for each asset relative to its 20-day rolling mean
  2. Assign positions: +1+1 if zt<−2z_t < -2, −1-1 if zt>2z_t > 2, 00 otherwise
  3. Portfolio return: rt=∑iwi,t−1⋅ri,tr_t = \sum_i w_{i,t-1} \cdot r_{i,t}

The threshold of ∣zt∣>2|z_t| > 2 corresponds roughly to the 95th percentile of a normal distribution, meaning the strategy only trades genuinely unusual moves rather than everyday noise.

It also turns out that I didn't select these two strategies arbitrarily. Momentum thrives in trending markets where assets keep moving in one direction; as the price of Ethereum surges, the market supports and hypes the asset further. On the other hand, there are certainly markets that lack these traits and are instead much more choppy with immense price oscillations. These rougher conditions are the bread and butter for mean reversion, which captures random oscillatory movements and turns them into profit. So when one strategy is underperforming, the other tends to be better positioned, and the combined strategy ends up with a smoother return profile than either one alone.

Part IV: Backtesting

The system includes a backtesting engine that replays each strategy over historical price data and returns a performance report consisting of: sharpe ratio, win/loss ratio, max drawdown, and total return. Nothing novel here, just a clean implementation to close the loop on strategy evaluation.