M

How To Build a Quant Portfolio From Scratch (2026 Edition)

16 min readView source ↗

Cover image

Not a stock-picking guide. The actual mathematics behind capital allocation from covariance estimation to when you cut a strategy entirely.

Ask ten people how to build a portfolio and nine of them will tell you to diversify.

Almost none of them can show you the equation that proves it works, or the equation that tells you exactly how much it helps given the specific things you're combining. "Don't put all your eggs in one basket" is advice. It is not engineering. A portfolio built on advice instead of engineering tends to fall apart in exactly the moment it was supposed to protect you.

Bookmark This!

I’m Ruuj a backend developer, researcher, and working on quant systems. DMs are open for thoughtful discussions and collaborations.

This article is the engineering version, start to finish. Not a survey of portfolio theory. The actual sequence of decisions and formulas I would use, in order, building a portfolio from scratch today. Starting with the equation that proves diversification works, through the specific reason the textbook covariance matrix will quietly wreck your allocation if you use it directly, through the allocation method that survives that problem, and ending with the precise operational rule for when you cut a strategy entirely versus when you just trim a position.

By the end of this article you will understand the actual mathematics of why combining things reduces risk and how to measure that benefit precisely, why the sample covariance matrix is dangerous to use directly in any optimizer and what the fix is, why classical mean-variance optimization tends to produce fragile, unstable portfolios and what serious allocators use instead, how to blend your own genuine market views into an allocation without a shaky forecast taking it over, and the exact rules for rebalancing and for shutting down a strategy before it costs you the whole drawdown.

Note: This article is deliberately thorough. Every Chapter builds on the one before it. Read it in order.

Chapter 1: The Actual Mathematics of Diversification

Start with the formula, because everything else in this article depends on understanding it precisely.

![Article image](https://pbs.twimg.com/media/HNIng5taIAAHoLk.jpg — "Visualizes how Mean-Variance Optimization and Risk Parity (ERC)

For a portfolio of two assets with weights w₁ and w₂, individual volatilities σ₁ and σ₂, and correlation ρ between them, the portfolio's variance is:

σ_p² = w₁²σ₁² + w₂²σ₂² + 2w₁w₂σ₁σ₂ρ

Look closely at that third term. It is the only place correlation enters the formula, and it is doing all the work that "diversification" actually refers to.

If ρ = 1, the two assets move in perfect lockstep, and the formula reduces to σ_p = w₁σ₁ + w₂σ₂. Portfolio volatility is just the weighted average of the individual volatilities. Combining them bought you nothing. You have one risk, expressed through two tickers.

If ρ = 0, the two assets are genuinely uncorrelated, and that third term vanishes entirely. Portfolio variance becomes w₁²σ₁² + w₂²σ₂²,strictly less than the weighted average would suggest. This is the mathematical fact underneath every piece of diversification advice you've ever heard: combining genuinely uncorrelated things reduces total risk below what either one carries alone, purely as a consequence of the algebra, with no change to expected return required.

If ρ is negative, the benefit is larger still. That third term becomes a subtraction, and portfolio variance can fall below either individual asset's variance.

For N assets this generalizes directly using the full covariance matrix Σ:

σ_p² = w'Σw

The numerator is the weighted average of individual asset volatilities: what your total risk would be if everything were perfectly correlated. The denominator is your actual portfolio volatility, computed from the full covariance matrix. A portfolio concentrated in one asset has a diversification ratio of exactly 1, no benefit at all. Anything above 1 means the correlation structure is doing real work for you.

This is the number I would actually track when deciding whether a new strategy or asset belongs in the portfolio. Adding something that raises the diversification ratio is adding real diversification. Adding something that leaves it roughly flat, even if it looks attractive on its own, is not diversifying anything. It's just more exposure to a risk you already have.

The catch, and it is the catch that defines the rest of this article: every quantity in these formulas has to be estimated from historical data. That estimation is far less reliable than the elegance of the formula suggests.

![Article image](https://pbs.twimg.com/media/HNInskSbgAA4yPm.jpg — "Simulation showing the trade-off between the shrinking marginal benefit of adding more assets to a portfolio (1/√N)

Chapter 2: The Covariance Matrix Problem That Breaks Everything Downstream

Every method in this article depends on one input: an accurate estimate of Σ, the covariance matrix. Get this wrong and the elegant math from Part 1 actively works against you.

Here is the problem almost nobody addresses before reaching for an optimizer. Estimating a covariance matrix accurately requires a lot of data relative to how many things you're estimating, and in practice you almost never have enough.

For N assets or strategies, Σ contains N(N+1)/2 unique numbers that all need to be estimated from history, not N numbers. Ten return sources means 55 separate covariance terms estimated from a finite, noisy sample. Twenty means 210. The estimation error compounds badly as this grows relative to your available history.

The naive approach, computing the sample covariance matrix directly from historical returns, is badly behaved in exactly this setting. It systematically overstates the reliability of whatever combination happened to perform best in your specific historical window, and understates the risk of whatever performed worst. Feed that noisy matrix into any optimizer and it treats estimation noise as if it were real signal, producing extreme, unstable weights that swing wildly with small changes to the input data. This is exactly why the diversification ratio from Part 1 can mislead you badly if Σ itself is unreliable. You can compute a ratio of 1.8 on a portfolio with no real diversification benefit at all, purely because your covariance estimate is noise dressed up as structure.

Shrinkage estimation is the standard fix, and has been for two decades.

Ledoit and Wolf published the original solution in 2003. Instead of trusting the noisy sample covariance matrix completely, shrink it toward a simpler, more stable structure:

Σ_shrunk = δ × F + (1 - δ) × S

Where S is the sample covariance matrix, F is a stable structured target such as a constant-correlation matrix, and δ is the shrinkage intensity, derived mathematically rather than guessed.

The thing to check after running this is the condition number of the matrix, np.linalg.cond(cov_matrix). A high condition number means the matrix is close to singular: small changes in input data produce large, erratic changes in the matrix inverse, which is exactly the operation the allocation methods in Chapter 3 need to perform. Shrinkage improves this conditioning substantially. This is not a cosmetic adjustment. It is the difference between an optimizer that produces stable weights and one that produces weights that look impressive on the exact window you fed it and fall apart the moment conditions shift. Research through 2025 continues refining this further with nonlinear and quadratic shrinkage variants, but the core linear Ledoit-Wolf estimator remains the well-tested practical default.

I would never compute a diversification ratio, and I would never run any allocation method, on a raw sample covariance matrix. Shrinkage first, always.

![Article image](https://pbs.twimg.com/media/HNIoE7xaYAAHFeQ.jpg — "Shows annualized portfolio volatility as the weight in Asset 1 varies from 0% to 100%, under perfect positive correlation (ρ=+1)

Chapter 3: Choosing the Allocation Method

With a properly estimated covariance matrix, the next decision is how to turn it into actual portfolio weights. Three real candidates are worth understanding precisely.

Mean-variance optimization is the original Markowitz framework from 1952, still the academic starting point, and still fragile in its naive form. Given expected returns and a covariance matrix, it finds the weights that maximize return for a given level of risk. The deeper problem isn't the covariance matrix anymore, Part 2 addressed that. It's that mean-variance optimization also needs an estimate of expected returns for every return source, and those estimates are far noisier than covariance estimates. A small difference in forecast, 8% expected return instead of 7.5%, can swing the optimal allocation from 5% of the portfolio to 60%. This is why naive mean-variance portfolios are almost never run without heavy additional constraints just to make the output usable.

Risk parity removes expected returns from the equation almost entirely. Instead of maximizing return for a given risk level, it asks a more robust question: what allocation makes every return source contribute an equal share of total portfolio risk. This is the framework Bridgewater built the All Weather fund on starting in 1996, and it remains one of the most widely used institutional approaches today, with Bridgewater and AQR running real capital on variants of it right now. The total risk contribution of asset i is:

TRC_i = w_i × (Σw)_i

The objective finds weights where every contribution is equal, TRC_i = TRC_j for all i, j.

Hierarchical Risk Parity (HRP), introduced by Marcos Lopez de Prado in 2016, fixes a structural weakness both prior methods share: they require inverting the covariance matrix, and matrix inversion is exactly the operation that amplifies small estimation errors most violently. HRP sidesteps this completely. It groups your return sources into a hierarchical tree based on how similarly they actually behave, using clustering rather than matrix inversion, then allocates risk down that tree recursively. Because it never inverts Σ, HRP is structurally more robust to the exact estimation noise Chapter 2 was about. Formal theoretical work published in 2024 confirmed this directly, showing HRP provably addresses the Markowitz instability problem, and the method continues to be actively validated in research published through 2025.

The two helper functions, get_quasi_diag for extracting the leaf order from the cluster tree, and recursive_bisection for splitting the risk budget top-down, are standard and available in most portfolio libraries such as riskfolio-lib or PyPortfolioOpt, so I'd pull them from there rather than reimplementing the tree logic by hand.

The call I would actually make: HRP as the base allocation, not mean-variance and not plain risk parity. Empirical results comparing these methods are genuinely mixed, some studies find HRP beats simple equal-weighting out of sample, others find equal-weighting is surprisingly hard to beat under any method. What's consistent across the research is that HRP is structurally protected against the estimation noise problem established in Chapter 2, while mean-variance and standard risk parity are structurally exposed to it. I would rather run the protected method, even when a backtest occasionally favors the fragile one on a specific historical window.

Part 4: Blending In Your Own Views Without Breaking the Portfolio

A pure risk-based allocation deliberately ignores what you actually believe about future returns. That's correct when your beliefs are noisy, but it's a real limitation when you have a genuinely well-calibrated view that deserves to move the allocation.

![Article image](https://pbs.twimg.com/media/HNImYjhaUAAesn6.jpg — "Tracks the deviation of actual SPY portfolio weight from its target allocation over time, treating the ±5% band like statistical control limits. Green circles mark the points where drift crosses the threshold and triggers a rebalance.")

This is the exact problem the Black-Litterman model was built to solve. Developed by Fischer Black and Robert Litterman at Goldman Sachs and published in 1992, it remains, as of 2026, one of the most widely used portfolio construction frameworks among institutional allocators. Pension funds, sovereign wealth funds, and central bank reserve managers all use variants of it, and Goldman Sachs Asset Management has run it as the foundation of their quantitative allocation process since it was introduced.

The core idea is a Bayesian blend. Start from an equilibrium baseline, what your HRP weights from Part 3 imply about expected returns, working backward from the allocation rather than forward from a forecast:

π = λΣw_market

Then blend in your specific views, weighted by confidence:

Here P encodes which strategies each view refers to, Q is the return you expect for each view, and omega is how uncertain you are in each view, higher values meaning lower confidence. A high-confidence view pulls the posterior meaningfully toward it. A low-confidence view barely moves it. If you have no view on a strategy at all, that strategy's weight in P is zero and the model reverts exactly to the risk-based weight, so absence of information never gets treated as a strong opinion.

In practice I would use this the way institutions do: HRP produces the disciplined baseline, and Black-Litterman is the mechanism for tilting it when there's a specific, calibrated reason to, new information that the purely backward-looking risk-based method structurally can't see. The omega parameter is what keeps this honest. A vague hunch gets high omega, low confidence, and barely moves the allocation. A well-evidenced view gets low omega, high confidence, and moves it meaningfully.

Part 5: Rebalancing, and Knowing When To Cut Rather Than Trim

The last layer is operational: once you have target weights, when do you actually trade toward them, and when do you decide a return source no longer belongs in the portfolio at all.

Calendar versus threshold rebalancing. This has been studied extensively, and the evidence is consistent, including Vanguard's own research on target-date fund rebalancing, that threshold-based rebalancing outperforms fixed calendar rebalancing at maintaining alignment with target risk, at similar or lower transaction cost. A monthly calendar rebalance let a standard portfolio drift as much as 7% from target during the March 2020 volatility spike, purely because the fixed date fell at the wrong moment. A threshold-based approach monitored daily never let the same portfolio drift more than 2% over the same period, at comparable trading cost.

The threshold itself is a genuine tradeoff. A tight 2 to 3 percent band keeps the portfolio closely aligned with target but increases trading frequency and cost. A wider 8 to 10 percent band reduces turnover but allows more drift. Research comparing calendar, threshold, and hybrid approaches over multi-decade periods finds the long-run differences are often modest. What matters more than the exact threshold is having an explicit written policy and sticking to it, particularly during the exact market extremes when the temptation to deviate is highest.

Cutting a return source versus trimming a position. This distinction matters more than every other rule in this article combined, and almost no portfolio content addresses it directly.

![Article image](https://pbs.twimg.com/media/HNInTxIaMAAo_XH.jpg — "Compares a 63-day rolling out-of-sample R² (proxy for model confidence)

A losing period within a strategy is normal, every genuine return-generating process has expected drawdown built into its normal operation. That alone is not evidence something has gone wrong. What actually signals a problem is different: the strategy's own internal measure of confidence in its own model degrading persistently, independent of whether it's currently winning or losing. A strategy whose forecast errors are growing or whose underlying statistical relationship is weakening is broken even while still nominally profitable. A strategy having a rough month while its internal diagnostics stay healthy is not broken at all.

The discipline this enforces: separate "is this strategy currently losing money" from "has this strategy's reason for working stopped being true." Those are different questions with different answers most of the time. Conflating them is how portfolios either panic out of a temporarily unlucky strategy that's fundamentally sound, or ride a genuinely broken strategy all the way down because the losses hadn't caught up with the underlying deterioration yet.

The Summary

Here is the complete architecture, assembled from the ground up.

Start from the actual mathematics of why diversification works, the portfolio variance formula, and the diversification ratio that turns "is this diversified" from a feeling into a number you can compute and optimize for directly. Estimate the covariance matrix that formula depends on using shrinkage, because the raw sample estimate is too noisy to trust with any method built on top of it, including the diversification ratio itself. Use Hierarchical Risk Parity as the base allocation, because it is structurally protected against exactly the estimation noise that damages mean-variance optimization and standard risk parity. Layer genuine, calibrated views on top using a Black-Litterman blend, so a low-confidence hunch never moves the portfolio as much as a well-evidenced view. Rebalance on a threshold basis rather than a fixed calendar. And separate, explicitly and always, the decision to trim a losing position from the decision to cut an entire return source.

None of the individual pieces here are exotic. The portfolio variance formula is over seventy years old and has never needed revision. Ledoit-Wolf shrinkage is over two decades old and remains the practical default. Black-Litterman is over three decades old and still runs inside Goldman Sachs's allocation process in 2026. Hierarchical Risk Parity is a decade old and continues to be actively validated in research published this year. What most portfolio content gets wrong isn't any single piece of math, it's skipping straight to an optimizer without addressing why the inputs to that optimizer are unreliable in the first place.

This is the architecture I would actually run. Every layer exists because the layer beneath it has a specific, documented weakness that the next layer is built to address.

Here is the question worth sitting with.

Of the five layers here, the diversification math, covariance shrinkage, HRP allocation, Black-Litterman view blending, and the operational rebalancing rules, which one would you trust with your own capital, and what would you build differently to compensate for it?

![Article image](https://pbs.twimg.com/media/HNIn4_obYAAqJyw.jpg — "Compares the empirical eigenvalues of a sample correlation matrix to the theoretical Marchenko-Pastur density. Eigenvalues within the shaded bound (λ₋ = 0.634 to λ₊ = 1.587)

Prompts

from scipy.cluster.hierarchy import linkage
from scipy.spatial.distance import squareform
 
def hrp_weights(returns_df):
    corr = returns_df.corr()
    cov = returns_df.cov()
    dist = np.sqrt(0.5 * (1 - corr))
    link = linkage(squareform(dist.values, checks=False), method='single')
 
    # order assets by cluster structure, then recursively split
    # risk budget top-down between each pair of sub-clusters
    order = get_quasi_diag(link)
    weights = recursive_bisection(cov, corr.index[order].tolist())
    return weights.sort_index()
def strategy_status(confidence_history, lookback=60,
                    cut_below=0.30, trend_below=-0.005):
    recent = confidence_history[-lookback:]
    avg = np.mean(recent)
    trend = np.polyfit(range(len(recent)), recent, 1)[0]
 
    if avg < cut_below:
        return 'CUT'
    elif trend < trend_below:
        return 'REDUCE'
    return 'NORMAL'
def bl_posterior(cov, pi, P, Q, omega, tau=0.05):
    tau_cov = tau * cov
    A = np.linalg.inv(np.linalg.inv(tau_cov) + P.T @ np.linalg.inv(omega) @ P)
    b = np.linalg.inv(tau_cov) @ pi + P.T @ np.linalg.inv(omega) @ Q
    return A @ b
def rebalance_needed(current_w, target_w, threshold=0.05):
    drift = (current_w - target_w).abs()
    return drift[drift > threshold]
from sklearn.covariance import LedoitWolf
 
def shrunk_covariance(returns_df):
    lw = LedoitWolf().fit(returns_df.values)
    return pd.DataFrame(lw.covariance_,
                         index=returns_df.columns,
                         columns=returns_df.columns), lw.shrinkage_
def diversification_ratio(weights, cov_matrix):
    w = np.array(weights)
    vols = np.sqrt(np.diag(cov_matrix))
    port_vol = np.sqrt(w @ cov_matrix @ w)
    return (w @ vols) / port_vol

Related articles