Portfolio construction: the frontier meets the real constraints

On this page
  1. A forecast becomes a weight through a rule
  2. The benchmark decides what counts as a bet
  3. Correlation turns ten positions into one
  4. Constraints cut the ideal down to the holdable
  5. The inputs are estimates, so the weights must be dull
  6. Traps
  7. The code
  8. Summary
  9. References

The portfolio optimisation post in the first series drew the efficient frontier, the set of mixes with the least risk for each level of return, and ended on a warning: an optimiser takes its inputs literally, and a five-point change in one expected return moved an eighth of the portfolio. This post is about what happens after the forecast and before the trade. The alphas post produced a number per asset that says which way; construction turns those numbers into positions, measures the result against a benchmark, and applies the limits a real mandate imposes. The worked example is the blog’s five tickers (SPY, NVDA, GS, XOM, GLD, 2020 to 2025) with a set of made-up forecasts, and every number in it is arithmetic: no optimiser runs anywhere in it.

A forecast becomes a weight through a rule

A forecast is a return you expect above the benchmark, one per asset. The sizing rule maps it to a weight, the share of the money in that asset. Three rules are common, and they disagree on what the size of the forecast means:

  • Linear: the weight is a constant times the forecast. A 2% forecast gets twice the position of a 1% forecast, and a zero forecast gets nothing. The constant sets the overall scale and changes every size but no sign.
  • Sign: every positive forecast gets the same long weight, every negative one the same short weight. The rule throws away the magnitude on purpose, so one extreme score cannot dominate.
  • Risk-adjusted: the weight is the forecast divided by the asset’s variance. Two assets with the same forecast get different weights, and the calmer one gets more.

Table 1 has the three on the same forecasts, SPY +2%, NVDA +5%, GS +1%, XOM −1% and GLD 0%, with the linear constant set to 4 (a 1% forecast becomes a 4% weight) and the risk-adjusted weights scaled to the same gross size as the linear ones so the shapes can be compared.

Table 1. Three sizing rules on the same forecasts, with gross and net
RuleSPYNVDAGSXOMGLDGrossNet
Linear, 4×4 \times forecast8%20%4%−4%0%36%28%
Sign, 10% each way10%10%10%−10%0%40%20%
Risk-adjusted, forecast ÷\div variance20.2%7.7%4.1%−4.0%0%36%28%

The linear rule gives NVDA two and a half times SPY’s weight (Figure 1), because its forecast is two and a half times bigger. The risk-adjusted rule gives NVDA 0.38\key{0.38} times SPY’s weight, because NVDA’s variance is 6.546.54 times SPY’s and dividing by it more than cancels the bigger forecast. Which rule is right depends on whether you believe the magnitudes of your forecasts; the sign rule is the honest choice when you only trust their direction. The last two columns are the ones a risk manager reads first. Gross exposure is the sum of the absolute weights, how much can go wrong; net is the plain sum, how much of the market you own. A fund that is 130% long and 30% short has a gross of 160% and a net of 100%, which Romero and Balch describe in What Hedge Funds Really Do as the “130/30” strategy: the extra 30% long is borrowed, and the short is the hedge.

2026-10-31T01:55:45.351826 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ SPY NVDA GS XOM GLD Ticker (forecasts +2, +5, +1, −1, 0 percent a year) −10 −5 0 5 10 15 20 Weight (% of the portfolio) 1. The same five forecasts, sized by three rules linear: 4 × forecast sign: 10% each way risk-adjusted: forecast ÷ variance SPY NVDA GS XOM GLD Ticker in the 40/20/20/10/10 portfolio 0 5 10 15 20 25 30 35 40 Share (% of the total) 2. Where the money is and where the risk is weight, % of money share of the portfolio's risk
Figure 1. Weights by sizing rule; money share against risk share, 40/20/20/10/10

The benchmark decides what counts as a bet

A manager hired to beat an index is judged against it, so a position only counts as a bet where it differs from the index. The active weight is the portfolio’s weight minus the benchmark’s. Holding 8% where the index holds 5% is a +3% bet; holding nothing where the index holds 4% is a −4% bet, an underweight, which is how a long-only fund expresses a negative view. Take a hand-chosen long-only portfolio, 40% SPY, 20% NVDA, 20% GS, 10% XOM, 10% GLD, and treat SPY itself as the benchmark. Against SPY the active weights are −60% SPY and +20, +20, +10, +10 in the other four; the active share, half the sum of the absolute active weights, is 60%, the share of the money that is placed differently from the index. Active share measures how different you are, not how good: the deviations can win or lose.

What they did from 2020 to 2025 is measured the way the Sharpe, Sortino and information ratio post set up:

IR, the information ratioactive, the return above the benchmarktracking error, the standard deviation of that difference

IR=active returntracking error\key{\text{IR}} = \frac{\good{\text{active return}}}{\risk{\text{tracking error}}}

The portfolio returned 30.9%30.9\% a year against SPY’s 16.4%16.4\%, an active return of +14.5%\good{+14.5\%} a year. The day-to-day difference between the two had a yearly standard deviation of 8.3%\risk{8.3\%}, the tracking error: how far the portfolio strayed from the index. The ratio, 1.74\key{1.74}, is the information ratio, the number Grinold’s fundamental law predicts from skill and breadth. A ratio that high is the window, not skill: NVDA’s 2023 to 2024 run sat in a 20% slot of a hand-picked portfolio, and no forecast earned it. Note what the tracking error is not: the portfolio’s own standard deviation was 24.2%\risk{24.2\%} against SPY’s 20.9%\risk{20.9\%}, and neither number, nor their difference, is the 8.3%\risk{8.3\%}; the tracking error is the spread of the daily gap. The risk the mandate cares about is the 8.3%\risk{8.3\%} of straying, because that is the part the manager chose.

Against a benchmark, risk means straying from it, not moving at all. A portfolio can be as volatile as its index and still carry little active risk, or be calm and carry a lot.

Correlation turns ten positions into one

The covariance and correlation post showed that a portfolio’s variance is a double sum over every pair of assets, weights times volatilities times their correlation, so a portfolio’s volatility is not the average of its parts. The same sum says where the risk comes from. Each asset’s risk contribution is its weight times how much the portfolio’s standard deviation would rise if that weight grew a little, and the contributions add up to the portfolio’s standard deviation exactly. On the 40/20/20/10/10 mix (Table 2):

Table 2. Risk contribution by ticker for the 40/20/20/10/10 portfolio
TickerWeightRisk contributionShare of the risk
SPY40%7.9%33%
NVDA20%8.9%37%
GS20%5.2%22%
XOM10%1.8%7%
GLD10%0.3%1%
Total100%24.2%100%

Gold holds a tenth of the money and a hundredth of the risk (the second panel of Figure 1), because its correlation with the four stocks averages 0.080.08. The four stocks hold 90% of the money and 99% of the risk, because their correlations with each other average 0.520.52: SPY and NVDA move together at 0.700.70, SPY and GS at 0.750.75. Romero and Balch’s chapter 10 makes the point with three made-up stocks, two of which move in tandem at a correlation of 0.9: buying both “does not really diversify your portfolio”. On real data the same thing shows up as a count that lies. Four stocks at equal weight have a standard deviation of 27.5%\risk{27.5\%} against an average of 35.2%\risk{35.2\%} for the four on their own; adding gold as a fifth equal slice takes it to 22.6%\risk{22.6\%}. Five positions here are closer to two bets, the stock market and gold, than to five. The chapter’s other warning is that the correlations are not fixed: in a crisis “nothing rises except correlations”, and the diversification that was measured in calm years is the first thing to go.

Constraints cut the ideal down to the holdable

Romero and Balch list constraints as one of the four parts of any optimisation problem, the limits you impose on the set the optimiser may consider, with these examples: a minimum or maximum weight on an element, “no more than 5 percent in any single issue”, and for a long-only portfolio the rule that the weights sum to at most 100%. The chapter before it reports the advice behind the 5%: diversification mutes the risk specific to one company, the benefit decelerates after 20 to 40 names, and some advisers cap any single position at 5% of the portfolio. The others a mandate commonly adds:

  • Leverage. Gross above 100% means borrowed money. Romero and Balch note that leverage “magnifies both gains and losses”, which is why high leverage is usually paired with a hedged book rather than a plain long one.
  • Short selling. A short is a borrowed share sold now and bought back later. It pays a borrowing fee and any dividends to the lender, and its loss is unbounded, since a price has no ceiling. A long-only mandate removes the whole tool, and a negative view becomes an underweight.
  • Position size. A cap on any one name. On the linear weights above a 15% cap cuts NVDA from 20% to 15% and displaces 5% of the money, which has to go somewhere else under the other limits. The cap lowers the model’s expected return and limits the damage one wrong forecast can do; that is the trade.
  • Liquidity. The order has to fit the market. The execution chapter of the CFA Institute’s Handbook of Artificial Intelligence and Big Data Applications in Investments frames the problem as a block of shares to trade within a time frame, where a higher trading volume “allows larger trades to be executed for the same amount of price impact”. An order that is too large for the day’s volume is traded slower or cut smaller; slicing it into pieces within the same day does not change the day’s share.
  • Turnover. Every change of weights is a trade with a cost, the subject of the what a trade costs post. A target weight says nothing about how far the current holdings are from it, and a small improvement in expected return can be smaller than the cost of reaching it.

None of these raise the expected return the model computes. They can only lower it, in exchange for a portfolio that exists.

The inputs are estimates, so the weights must be dull

The portfolio optimisation post’s experiment was a five-point cut to NVDA’s expected return moving an eighth of the portfolio. The sizing rules make the mechanism plain. Under the linear rule a forecast that moves from 1% to 2% doubles the position, from 4% to 8%, on a change no forecaster can defend. Under the risk-adjusted rule, forecasts of 5% for NVDA and 2% for SPY give NVDA 0.38\key{0.38} times SPY’s weight; move each by half a point towards the other, 4.5% and 2.5%, and the ratio is 0.28\key{0.28}. A quarter of the relative position went on a change smaller than the error bar of either forecast. Romero and Balch’s “No Panacea” section says why this matters: outputs are only as good as inputs, forecasts “can be noisy and erroneous”, and a quantitative output “can appear overly rigorous” when it is built on them. The optimiser transforms the inputs; it never validates them.

The construction step’s defences are all ways of admitting the noise. Shrinkage pulls every forecast part of the way towards a neutral value: halve the five forecasts towards zero and the linear weights halve with them, gross 36% to 18%, same ranking, calmer book. A cap bounds what any one estimate can do, as above. A no-trade buffer ignores a forecast change too small to be worth a trade, so a sign that flickers between +0.1% and −0.1% does not flip a position every day. And a perturbation test, nudging each input and watching the weights, is the cheapest check there is: a portfolio that changes a lot on a small nudge is a portfolio built on that nudge. Equal weight is the extreme of this school, a rule that uses no forecast at all and so cannot be wrong about one; it gives up the optimum in exchange for stability, and whether the optimum was real is something only later data can say.

The construction step’s job is not to find the best portfolio but to refuse a fragile one. Every weight is downstream of a number with an error bar; size positions so that the error bar, not the point estimate, decides how much you can lose.

Notation in other books

Grinold and Kahn, whose book Romero and Balch paraphrase, define the information ratio as the active return over the tracking error, the form used above. Romero and Balch (chapter 10) keep to the four-part description of an optimisation problem, decision variables, objective, constraints and a search procedure, and point to a public optimiser rather than writing the algebra out. The information ratio appears in both books under the same name; chapter 9 of Romero and Balch measures it on alpha, the return left after the market’s share is removed, which equals the active return when the portfolio’s beta to the benchmark is 1.

Traps

Table 3 has the beliefs this post set out to correct.

Table 3. Eight beliefs about portfolio construction and what is actually true
People thinkActually
A positive holding is an overweightonly if it is above the benchmark’s weight; 1% held against 3% in the index is a −2% bet
High active share means high expected returnit measures how different you are, not how right
Net zero means hedgedgross exposure, sector and factor risk all remain; 130/30 is net 100% and gross 160%
Portfolio volatility is the average of the assets’ volatilitiesit is lower whenever correlations are below 1: 27.5% here against an average of 35.2%
More positions means less riskit depends on sizes and correlations; four correlated stocks are closer to one bet
Constraints never cost anythingthey lower the model’s expected return; the gain is a portfolio that can be held
Splitting an order within the day satisfies a volume capthe day’s share is unchanged; trade slower or smaller
A good optimiser fixes bad forecastsit transforms inputs and never validates them

The code

The snippet reproduces the active return, tracking error and information ratio of the 40/20/20/10/10 portfolio against SPY; Table 4 names its variables.

Table 4. Variables in the information ratio snippet
VariableHolds
rdaily returns, one column per ticker, 2020 to 2025
wthe five weights of the hand-chosen portfolio
activeeach day’s portfolio return minus SPY’s return
import numpy as np
import pandas as pd

url = "https://raw.githubusercontent.com/ankurtrapasiya/examples/main/data/prices.csv"
px = pd.read_csv(url, index_col="date", parse_dates=True)[["SPY", "NVDA", "GS", "XOM", "GLD"]]
r = (px / px.shift(1) - 1).dropna()
w = np.array([0.40, 0.20, 0.20, 0.10, 0.10])

active = r @ w - r["SPY"]                 # the portfolio's daily return minus the benchmark's
active_return = 252 * active.mean()       # average daily gap, scaled to a year
tracking_error = np.sqrt(252) * active.std()   # standard deviation of the gap, scaled to a year
print(f"active return {100 * active_return:+.1f}% a year")
print(f"tracking error {100 * tracking_error:.1f}% a year")
print(f"information ratio {active_return / tracking_error:.2f}")

It prints an active return of +14.5% a year, a tracking error of 8.3% a year and an information ratio of 1.74. r @ w is NumPy’s matrix product: each day’s five returns weighted and summed, one portfolio return per day.

The script behind the real numbers

The tables and the chart come from examples/portfolio-construction-real-constraints/construction.py, which runs on the blog’s five tickers. To run it yourself, clone the examples repo: its README has a three-command Docker setup, or run uv run portfolio-construction-real-constraints/construction.py.

Summary

Table 5 collects the ideas, with the five-ticker number behind each.

Table 5. Seven ideas in portfolio construction, with the five-ticker numbers
IdeaIn one lineOn the five tickers
Sizing rulelinear trusts the forecast’s size, sign trusts only its direction, risk-adjusted divides by varianceNVDA gets 2.5×2.5 \times SPY linearly, 0.38×0.38 \times risk-adjusted
Gross and netsum of absolute weights versus plain sum130/30 is gross 160%, net 100%
Active weightportfolio weight minus benchmark weight; an underweight is a negative view40/20/20/10/10 against SPY has an active share of 60%
Information ratioactive return per unit of tracking error+14.5% a year over 8.3% gives 1.74
Risk contributionweight times the portfolio’s sensitivity to it; the contributions sum to the totalGLD: 10% of the money, 1% of the risk
Constraintsleverage, shorting, position size, liquidity, turnover; they lower the model’s optimuma 15% cap displaces 5% of the money
Estimation errora half-point input change moves a weight by a quarter; shrink, cap, buffer, perturb5% and 2% give a 0.38 ratio, 4.5% and 2.5% give 0.28

References

  • Philip J. Romero and Tucker Balch, What Hedge Funds Really Do: An Introduction to Portfolio Management (Business Expert Press, 2014). Chapter 10 for the four parts of an optimisation problem and its examples of constraints (minimum and maximum weights, no more than 5 percent in one issue, long-only weights summing to 100 percent), “Why Low Correlation Is Prized”, “A Dynamic Process” and “No Panacea”; chapter 9 for the information ratio, systematic against specific risk, the 5 percent position advice and the 20 to 40 names after which diversification adds little; chapter 2 for the 130/30 strategy and leverage; chapter 4 for the mechanics of selling short; chapter 7 for leverage magnifying gains and losses.
  • Richard C. Grinold and Ronald N. Kahn, Active Portfolio Management, 2nd edition (McGraw-Hill, 2000). The information ratio as active return over tracking error, and the fundamental law that chapter 9 of Romero and Balch paraphrases.
  • CFA Institute Research Foundation, Handbook of Artificial Intelligence and Big Data Applications in Investments (2023). Chapter 8 for the execution problem as a block of shares within a time frame, slippage, and trading volume allowing larger trades for the same price impact.
  • Richard O. Michaud, “The Markowitz Optimization Enigma: Is ‘Optimized’ Optimal?”, Financial Analysts Journal 45(1), 1989. Optimisers as “error maximizers”, the problem the shrinkage and perturbation habits above answer.