Diagnose active risk when stocks lag a benchmark
A stock portfolio can move closely with its benchmark and still have meaningful active risk or persistent underperformance. Construct the aligned portfolio-minus-benchmark return series, measure its variability and examine the periods with large differences. Then trace those observations to beginning active weights rather than explaining the entire record with one correlation coefficient.
This guide produces an active-return table, a realized tracking-error calculation and one holding-contribution card. The standard-library example uses invented returns and weights, not real market performance. It is an external analysis; CoTrading and reference long-only risk tools are not assumed to provide this benchmark-relative model.
Define the benchmark and return basis
Choose one benchmark in the same currency and document its identity, version, total-return convention and covered sessions. Match the portfolio’s valuation and cost treatment. A price-only benchmark and a dividend-inclusive portfolio do not provide a clean comparison unless that mismatch is deliberately explained.
Prepare returns with external cash flows already handled under the account’s declared policy. Do not interpret a deposit as portfolio outperformance. Obtain beginning weights and security returns for the diagnostic periods, along with any fee or cash residual needed to reconcile the observed active return.
Keep benchmark choice fixed before diagnosing the result. Selecting a weaker benchmark after viewing a lagging portfolio changes the question. Preserve the original comparison and explain any later benchmark revision as a separate research context.
Align observations without filling gaps
Join by actual session keys and verify that both series cover the intended calendar. The sample requires matching key sets and rejects a benchmark with a missing second session. It does not silently intersect the data and pretend no observation was lost.
Even equal key sets do not prove a complete calendar if both sources omitted the same day. Our four-session fixture is declared consecutive; a real workflow must verify expected coverage and sampling interval separately. Do not convert a two-session change into a daily return by dropping the missing mark.
Check finite values and consistent decimal units before statistics. A return of 0.01 means one percent here. Mixing percentage points, percent strings and fractions can create dramatic but entirely artificial tracking error. Retain source rows and transformation rules so the vector can be rebuilt.
Distinguish active return from active risk
For each session, active return is portfolio return minus benchmark return. The CFA Institute multifactor-model reading defines active risk as the standard deviation of active returns, also called tracking error. Our calculation is a realized sample statistic, not a forecast factor-risk model.
Use the sample standard deviation described in Python statistics. The example multiplies per-session deviation by sqrt(252) under an explicit synthetic business-session annualization convention. Replace that factor with the verified frequency appropriate to the actual input; four observations alone cannot establish a year’s market calendar.
The mean measures systematic average lag or lead, while tracking error measures variation around that mean. They answer different questions. A low tracking error does not certify that the portfolio achieved the benchmark return, and a large value does not by itself tell whether active decisions helped.
Work through four synthetic sessions
The benchmark holds A and B equally. Portfolio A weights are 0.4, 0.6, 0.7 and 0.45 at the beginning of four sessions; B receives the remainder. Each weight is a declared observation for this analysis, not a claim that a real rebalancing engine executed it without costs.
| Session | A/B security returns | Portfolio return | Benchmark return | Active return |
|---|---|---|---|---|
| 1 | 2% / 0% | 0.8% | 1.0% | −0.2 pp |
| 2 | 1% / 0% | 0.6% | 0.5% | +0.1 pp |
| 3 | −2% / 1.5% | −0.95% | −0.25% | −0.7 pp |
| 4 | 2% / 0% | 0.9% | 1.0% | −0.1 pp |
Active returns are [-0.002,0.001,-0.007,-0.001]. Their mean is −0.225% per session, and annualized sample tracking error is 5.402777% under the stated factor. The code checks the latter against the independent analytic value sqrt(0.002919).
These are deliberately tiny invented data. Annualization makes the units comparable under a convention; it does not make four observations a credible estimate of long-run active risk or prove that the portfolio manager lacks skill.
Identify large deviations and sustained lag
Freeze a high-deviation rule before selecting examples. Here an absolute active return at least 0.005 flags a session. Only session three qualifies, and it happens to be negative. A positive outlier would also qualify under this absolute-value rule.
Track consecutive negative active observations separately. Session one is an isolated lag, while sessions three and four form a two-session lag streak. Do not confuse a streak length with the tracking-error estimate; one describes temporal ordering, the other aggregate dispersion.
Store each window’s beginning and end keys, available observations and missing-data status. A gap should not be filled with zero to break an unfavorable streak. If the expected calendar is incomplete, report the duration as unresolved or apply an explicitly justified policy.
Trace the flagged session to active holdings
At session three, portfolio A weight exceeds benchmark by 0.2 and B is below by 0.2. A’s −2% return contributes −0.4 percentage points; B’s +1.5% return contributes −0.3 points because the portfolio held less of the rising stock. They sum to the observed −0.7-point active result.
active_contribution[s] = (portfolio_weight[s] - benchmark_weight[s]) * security_return[s]
Keep costs, cash or unexplained differences separate if they exist. The fixture assumes zero costs and two fully mapped securities. It does not implement a general Brinson decomposition, a covariance forecast or a causal explanation of why a stock moved.
Active weights can be negative even when both portfolios are long-only. That simply indicates an underweight relative to the benchmark. Do not run them through a long-only normalization routine that deletes negative entries or rescales them to one; doing so changes the diagnostic quantity.
Test correlation and constant-lag counterexamples
The first counterexample sets portfolio returns to 0.9 times a varying benchmark. Correlation is one, yet the active-return sequence varies and tracking error is positive. High correlation therefore does not imply absence of active risk.
The second subtracts a constant 0.001 from every benchmark return. Active returns have constant negative mean and zero dispersion, up to floating roundoff. Tracking error is effectively zero while the portfolio persistently lags. This is not a missing statistic: zero tracking error is a valid dispersion result here.
A ratio dividing mean active return by zero risk would need its own undefined status; the example does not report such a ratio. Finite-value validation precedes the sample-size decision. Even a single NaN or infinite return is rejected; only valid aligned data with fewer than two observations return insufficient information. Missing keys or nonfinite values are never converted to convenient zero returns.
When reconciling another report, check whether its statistic is demeaned standard deviation or root mean squared active return. The latter includes the average bias and is a different quantity. A constant negative gap can have zero deviation but positive root mean square. Under this guide’s definition, replacing one with the other would change the diagnostic question. Preserve the formula name and intermediate mean so a disagreement can be explained rather than forcing two differently defined measures to match by changing annualization.
Execute and accept the diagnostic
Download the complete example. Use Python 3.12 or later and run python R634.py. Standard-library assertions verify the active vector, mean, annual risk, flagged session, −0.4/−0.3 contribution bridge, lag streak, correlation-one example and missing-session rejection.
Archive benchmark definition, aligned source series, frequency, mean/deviation convention, flagged windows and beginning active weights. Explain residuals and missing classification rather than forcing all differences into known stocks. Retain both persistent bias and variable active risk in the final assessment.
Recalculate after benchmark, returns, fees, period or holdings change. This synthetic diagnosis does not validate a product risk module, actual historical performance or the suitability of any benchmark for a real investor.
FAQ
Can correlation one still imply active risk?
Yes. Different return magnitudes can generate varying active returns even with perfect correlation.
Does tracking error zero mean no underperformance?
No. A constant negative active return can have zero variability and still lag every period.