HangukQuant Research

HangukQuant Research

Quantitative Trading Strategies - How I went from 10k to 100k to 1M (part 2: trading in factor space)

factor-trading in crypto, with code

HangukQuant's avatar
HangukQuant
Jul 18, 2026
∙ Paid

PSA: we have an ongoing, 1-week 50% discount on all subs.

Quantitative Trading Strategies - How I went from 10k to 100k to 1M (new series intro)

Quantitative Trading Strategies - How I went from 10k to 100k to 1M (new series intro)

HangukQuant
·
Jul 13
Read full story

A factor model is motivated by the observation that market movements are primarily driven by a relatively small number of common sources of risk. Assets may have thousands of individual return streams, but much of their variation is shared: broad market movements, industries, economic characteristics, liquidity conditions, or latent statistical relationships. The purpose of a factor model is to separate these common movements from asset-specific noise.

There are three broad approaches: Fama-style (time-series) portfolio factors, statistical factor models such as PCA, and Barra-style (cross-sectional) exposure models. They differ not merely in interpretation, but in the direction of estimation, the information supplied to the model, and the quantity being estimated.

Getting timely exposure to desirable factors — and hedging undesirable ones — is a primary concern of smart-beta funds and are a TRILLION dollar industry.

Factor analysis in crypto is still nascent. This article focuses on Barra-style models and how I actively trade them to enhance my pnl.

The full implementation is included at the bottom.

We will touch lightly on the first two, and then detail a Barra-style analysis with code.

Fama-style

A Fama-style factor is defined as the return of a portfolio. For example, a simplified value factor might be

\(f_{\mathrm{value},t} = R_{\mathrm{high\ value},t} - R_{\mathrm{low\ value},t}.\)

More generally, if (pk,t) contains the asset weights of factor portfolio (k), then

\(f_{k,t}=p_{k,t}'R_t.\)

Once these factor-return histories have been constructed, the exposure of an individual asset is estimated through time:

\(\underbrace{r_i}_{T\times1} = \alpha_i\mathbf 1 + \underbrace{F}_{T\times K} \underbrace{\beta_i}_{K\times1} + \epsilon_i.\)

The factor-return matrix (F) is known. The regression estimates (βi):

\(\widehat{\beta}_i = (F'F)^{-1}F'r_i.\)

For a single, demeaned factor,

\(\widehat{\beta}_i = \frac{\operatorname{Cov}(r_i,f)} {\operatorname{Var}(f)}.\)

Fama-style models are motivated by economic hypotheses about expected returns. Is a manager’s apparent alpha simply compensation for exposure to known factor strategies? Is our portfolio (statistically) significantly just some beta against a factor portfolio?

For a portfolio with estimated factor betas (βp),

\(\operatorname{Var}(r_p) = \beta_p'\Sigma_F\beta_p + \sigma_{\epsilon,p}^2.\)

Statistical-style

A statistical factor model begins with the complete return matrix:

\(R\in\mathbb R^{T\times N},\)

where rows are dates and columns are assets. It seeks a lower-dimensional approximation:

\(R\approx FL'+E,\)

where F ∈ ℝT×K contains the statistical factor returns and L ∈ ℝN×K contains the asset loadings. In principal components analysis, first estimate the asset covariance matrix:

\(\Sigma_R = \frac{1}{T-1}R'R,\)

of demeaned returns. Decompose it as

\(\Sigma_R=V\Lambda V'.\)

The first (K) eigenvectors define the principal directions:

\(V_K= \begin{bmatrix} v_1 & \cdots & v_K \end{bmatrix},\)

and the corresponding factor scores are

\(F=RV_K.\)

The resulting rank-(K) reconstruction is

\(R\approx FV_K'.\)

Unlike the Fama regression, however, neither the factors nor the loadings are specified economically.

These are motivated mainly by dimensionality reduction. If hundreds of assets share a few dominant covariance patterns, the researcher may want to discover those patterns without imposing characteristic taxonomy.

Here is a seminal paper on enhanced portfolio optimization using principal components by AQR’s Pedersen et al.

Barra-style

The focus of our post, is the Barra-style model. We will first discover it’s mathematical basis, and then use them to identify sector performance.

We begin by specifying each asset’s exposures. On date (t),

\(B_t\in\mathbb R^{N\times K}\)

contains exposures to K factors, such as categories, industries, countries, or continuous styles such as size and momentum.

The model then examines the cross-section of asset returns on that date:

\(\underbrace{R_t}_{N\times1} = \underbrace{B_t}_{N\times K} \underbrace{f_t}_{K\times1} + \epsilon_t.\)

The exposures (Bt) are known. The factor returns (ft) are estimated using the (N) assets observed on that date.

This regression is repeated for every date, therefore produces a time series of factor returns from a sequence of cross-sectional regressions.

Barra-style models are motivated by the need to describe the current economic composition of a portfolio. Rather than waiting for a long return history to reveal a portfolio’s betas, the manager declares or measures the underlying asset exposures directly.

Repeating the cross-sectional regression each day produces a synthetic return series for every factor. By extension, if sector inclusion is defined as a factor, we obtain the synthetic return of the sector performance.

They are useful to:

  • portfolio managers performing return attribution;

  • risk managers estimating common and specific risk;

  • traders neutralising unwanted industry or style bets;

  • isolating sector performance for smart beta plays.

The factor return has a different meaning from a Fama-style factor. It is the return attributed to one unit of exposure after controlling for the other exposures in the cross-sectional regression.

Example'; crypto Barra model

We will demonstrate the categorical Barra analysis here using a reduced four-asset problem with two categories. The full regression code can be found at the bottom.

Let’s begin.

Suppose our universe contains four assets:

  • BTC — L1; daily return 4%; liquidity score 4.

  • ETH — L1; daily return 2%; liquidity score 2.

  • DOGE — Meme; daily return 8%; liquidity score 1.

  • PEPE — Meme; daily return 6%; liquidity score 1.

The objective is to estimate three returns:

\(f_t= \begin{bmatrix} f_{\mathrm{market},t}\\ f_{\mathrm{L1},t}\\ f_{\mathrm{Meme},t} \end{bmatrix}.\)

The market factor represents the weighted return of the crypto universe. The category factors represent L1 and Meme performance relative to that market.

1. Construct the return vector

For each asset, the daily close-to-close return is

\(r_{i,t} = \frac{P_{i,t}}{P_{i,t-1}}-1.\)

Collect the four asset returns into the vector

\(y_t= \begin{bmatrix} r_{\mathrm{BTC},t}\\ r_{\mathrm{ETH},t}\\ r_{\mathrm{DOGE},t}\\ r_{\mathrm{PEPE},t} \end{bmatrix}.\)

This is the dependent variable in the daily cross-sectional regression.

2. Construct the regression weights

For each day, determine asset’s regression weight. Reasonably, we may choose the square root of its preceding 30-day dollar volume:

\(q_{i,t} = \sqrt{ \sum_{\tau=t-30}^{t-1} P_{i,\tau}V_{i,\tau} }.\)

The weights are then normalised:

\(w_{i,t} = \frac{q_{i,t}}{\sum_jq_{j,t}}.\)

Our simplified liquidity scores are

\(q= \begin{bmatrix} 4\\ 2\\ 1\\ 1 \end{bmatrix}.\)

Since they sum to eight, the normalised weights are

\(w= \begin{bmatrix} 0.50\\ 0.25\\ 0.125\\ 0.125 \end{bmatrix}.\)

The WLS weighting matrix is simply diag(w).

\(W= \begin{bmatrix} 0.50&0&0&0\\ 0&0.25&0&0\\ 0&0&0.125&0\\ 0&0&0&0.125 \end{bmatrix}.\)

BTC contributes half of the regression weight, ETH contributes one quarter, and DOGE and PEPE each contribute one eighth.

3. Construct the exposure matrix

Every asset has market exposure equal to one. It also has exposure equal to one to its assigned category.

The exposure matrix is

\(X= \begin{bmatrix} 1&1&0\\ 1&1&0\\ 1&0&1\\ 1&0&1 \end{bmatrix}.\)

for columns [market, L1, Meme] and rows [BTC, ETH, DOGE, PEPE].

Each day, the regression equation is given by (solve for f)

\(y=Xf+\epsilon.\)

For instance,

\(r_{\mathrm{BTC}} = f_{\mathrm{market}} + f_{\mathrm{L1}} + \epsilon_{\mathrm{BTC}},\)
\(r_{\mathrm{PEPE}} = f_{\mathrm{market}} + f_{\mathrm{Meme}} + \epsilon_{\mathrm{PEPE}}.\)

The model assigns the same fitted common return to assets in the same category. Differences between the individual asset returns in a fitted category return remain in the residuals.

4. Remove collinearity problem

The market column is equal to the sum of the two category columns:

\(X_{\mathrm{market}} = X_{\mathrm{L1}} + X_{\mathrm{Meme}}.\)

Consequently, the exposure matrix does not have full column rank.

For a particular solution

\(\left( f_{\mathrm{market}}, f_{\mathrm{L1}}, f_{\mathrm{Meme}} \right)\)

and any constant a,

\(\left( f_{\mathrm{market}}+a, f_{\mathrm{L1}}-a, f_{\mathrm{Meme}}-a \right)\)

produces exactly the same fitted asset returns.

We may solve this by requiring the liquidity-weighted average category return to equal zero.

5. Reduction of Degree of Freedom

Let the aggregate weight of category c be

\(s_c = \sum_{i\in c}w_i.\)

In our example,

\(s_{\mathrm{L1}} = 0.50+0.25 = 0.75\)
\(s_{\mathrm{Meme}} = 0.125+0.125 = 0.25.\)

We impose

\(s_{\mathrm{L1}}f_{\mathrm{L1}} + s_{\mathrm{Meme}}f_{\mathrm{Meme}} = 0.\)

Substituting the category weights,

\(0.75f_{\mathrm{L1}} + 0.25f_{\mathrm{Meme}} = 0.\)

The constraint vector is therefore

\(c= \begin{bmatrix} 0\\ 0.75\\ 0.25 \end{bmatrix},\)

and the constraint is

\(c'f=0.\)

The leading zero means that the market coefficient is not directly constrained.

6. Solving the constrained WLS

We minimise the weighted squared residuals:

\(\widehat f = \arg\min_f \frac{1}{2} (y-Xf)'W(y-Xf)\)

subject to

\(c'f=0.\)

Introduce a Lagrange multiplier λ:

\(\mathcal L(f,\lambda) = \frac{1}{2} (y-Xf)'W(y-Xf) + \lambda c'f.\)

The first-order condition with respect to f is

\(-X'W(y-Xf)+c\lambda=0.\)

Rearranging,

\(X'WXf+c\lambda=X'Wy.\)

The first-order condition with respect to λ is

\(c'f=0.\)

Combining the two equations produces the KKT system:

\(\begin{bmatrix} X'WX&c\\ c'&0 \end{bmatrix} \begin{bmatrix} \widehat f\\ \lambda \end{bmatrix} = \begin{bmatrix} X'Wy\\ 0 \end{bmatrix}.\)

For our example,

\(X'WX = \begin{bmatrix} 1&0.75&0.25\\ 0.75&0.75&0\\ 0.25&0&0.25 \end{bmatrix}.\)

The weighted return vector is

\(X'Wy = \begin{bmatrix} 0.0425\\ 0.0250\\ 0.0175 \end{bmatrix}.\)

The first element is the weighted return contribution of the whole market:

\(0.50(0.04) + 0.25(0.02) + 0.125(0.08) + 0.125(0.06) = 0.0425.\)

The second is the weighted contribution from L1 assets:

\(0.50(0.04)+0.25(0.02)=0.0250.\)

The third is the weighted contribution from Meme assets:

\(0.125(0.08)+0.125(0.06)=0.0175.\)

The complete system is

\(\begin{bmatrix} 1&0.75&0.25&0\\ 0.75&0.75&0&0.75\\ 0.25&0&0.25&0.25\\ 0&0.75&0.25&0 \end{bmatrix} \begin{bmatrix} f_{\mathrm{market}}\\ f_{\mathrm{L1}}\\ f_{\mathrm{Meme}}\\ \lambda \end{bmatrix} = \begin{bmatrix} 0.0425\\ 0.0250\\ 0.0175\\ 0 \end{bmatrix}.\)

Solving gives

\(f_{\mathrm{market}} = 0.0425,\)
\(f_{\mathrm{L1}} = -0.0091667,\)
\(f_{\mathrm{Meme}} = 0.0275.\)

The constraint is satisfied:

\(0.75(-0.9167\%) + 0.25(2.75\%) = 0.\)

7. Interpretations

The weighted return of the L1 category is

\(\overline r_{\mathrm{L1}} = \frac{ 0.50(4\%) + 0.25(2\%) }{ 0.75 } = 3.3333\%.\)

The weighted return of the Meme category is

\(\overline r_{\mathrm{Meme}} = \frac{ 0.125(8\%) + 0.125(6\%) }{ 0.25 } = 7\%.\)

The category coefficients are the differences between these category returns and the weighted market return:

\(f_{\mathrm{L1}} = 3.3333\%-4.25\% = -0.9167\%,\)
\(f_{\mathrm{Meme}} = 7\%-4.25\% = 2.75\%.\)

The fitted common return for an L1 asset is

\(f_{\mathrm{market}}+f_{\mathrm{L1}} = 4.25\%-0.9167\% = 3.3333\%.\)

The regression therefore tells us:

  • the weighted market returned 4.25%;

  • L1 underperformed the market by 0.9167%;

And the same exercise applies to the Memes category.

The residuals describe the returns not explained by category membership.

For BTC,

\(\epsilon_{\mathrm{BTC}} = 4\%-3.3333\% = 0.6667\%.\)

8. Repeat the analysis through time

The same cross-sectional regression is repeated for every date t. Each regression produces one market return and one relative return for every represented category:

\(\widehat f_t = \begin{bmatrix} \widehat f_{\mathrm{market},t}\\ \widehat f_{\mathrm{L1},t}\\ \widehat f_{\mathrm{Meme},t}\\ \vdots \end{bmatrix}.\)

Stacking the daily estimates produces a synthetic return history for every category/sector.

For example,

\(\left\{ f_{\mathrm{Meme},1}, f_{\mathrm{Meme},2}, \ldots, f_{\mathrm{Meme},T} \right\}\)

is the estimated history of the crypto meme-sector relative to the weighted crypto market. If we take these as ‘sector returns’ and compound them from 1, we essentially have a synthetic sector index. This is (theoretically) tradable with a factor-mimicking portfolio.

9. Recover the factor-mimicking weights

The estimated coefficients are linear combinations of the asset returns. We may therefore recover asset weights that reproduce them exactly.

For the market factor, the mimicking weights are the normalised regression weights:

\(p_{\mathrm{market}} = \begin{bmatrix} 0.50\\ 0.25\\ 0.125\\ 0.125 \end{bmatrix}.\)

For category c, the mimicking weights are

\(p_{c,i} = \mathbf 1\{i\in c\} \frac{w_i}{s_c} - w_i.\)

For L1, this gives

\(p_{\mathrm{L1}} = \begin{bmatrix} 0.50/0.75-0.50\\ 0.25/0.75-0.25\\ -0.125\\ -0.125 \end{bmatrix} = \begin{bmatrix} 0.1667\\ 0.0833\\ -0.125\\ -0.125 \end{bmatrix}.\)

These weights sum to zero:

\(0.1667+0.0833-0.125-0.125=0.\)

Their realised return is

\(p_{\mathrm{L1}}'y = 0.1667(4\%) + 0.0833(2\%) - 0.125(8\%) - 0.125(6\%) = -0.9167\%.\)

For Meme,

\(p_{\mathrm{Meme}} = \begin{bmatrix} -0.50\\ -0.25\\ 0.125/0.25-0.125\\ 0.125/0.25-0.125 \end{bmatrix} = \begin{bmatrix} -0.50\\ -0.25\\ 0.375\\ 0.375 \end{bmatrix}.\)

Its return is

\(p_{\mathrm{Meme}}'y = -0.50(4\%) - 0.25(2\%) + 0.375(8\%) + 0.375(6\%) = 2.75\%.\)

This exactly reproduces the L1 factor return.

The category factor can therefore be interpreted as a long position in the weighted category basket and a short position in the weighted market basket.

The factor-mimicking portfolio exists exactly in the mathematics. Essentially, what we have done is to transform quantitative analysis from price space to factor space, using statistical categorical analysis. In the process, we might

  • better appreciate crypto asset returns as a mixture of factors/sectors

  • construct a more informed portfolio by reducing noise in our samples

For instance, using “theoretical” factor-mimicking portfolios, we may look to construct a long-short delta neutral portfolio for “bullish sectors” against “bearish sectors”. Or we may look to “enhance” our trend construction from the previous post to trading in the factor space, subject to same considerations of portfolio construction that were discussed.

Code:

Let’s take a look an example construction of the above test to a universe of hundred tickers from Binance and Python code.

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2026 QUANTA GLOBAL PTE. LTD. 202328387H. · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture