The governed definitions this build depends on. Read them first if a term is unfamiliar.
- PrimaryConstituent ConcentrationConstituent Concentration describes how unevenly index weight or another declared exposure is distributed across constituents.
- PrerequisiteBase ValueBase value is the chosen numerical level assigned to an index at its base date.
- PrerequisiteHerfindahl-Hirschman IndexHerfindahl-Hirschman Index is the sum of squared shares across the members of a defined population.
- PrerequisiteIndex ConstituentAn index constituent is an instrument included in an index for a specified effective interval.
- ImportantConcentration MeasureConcentration Measure quantifies how much a total is dominated by relatively few members of a population.
- ImportantDominant ConstituentDominant Constituent is the constituent with the largest value under a declared weight, exposure, or contribution basis.
The operational question
Market breadth is not one idea. A headline move can be driven by a few constituents, a weight vector can be concentrated before any return occurs, and a signal can spread across sectors or factor sleeves without those components being independent. Herfindahl Constituent Concentration owns one precise question: how concentrated are index weights before any constituent return is observed?
Two indices can each hold 24 names while one behaves like a much more concentrated portfolio. HHI exposes that hidden weight imbalance before returns arrive. That is a diagnostic and governance outcome, not a forecast, recommendation, legal classification, or promise of diversification.
Intuition before notation
Squaring makes large weights count disproportionately, so two rosters with the same constituent count can have very different concentration. Top-N weight is local to a chosen cutoff; HHI uses the full distribution. Antitrust thresholds are not imported as index-risk labels.
The family map prevents a category error. Contribution combines beginning weight and realized return. HHI and effective N inspect the weight vector before returns. Diffusion scores direction across a fixed component panel. Choosing the wrong branch may produce valid arithmetic that answers the wrong question.
Freeze the series identity
The selected formula is:
Square every normalized constituent weight and sum the squares; publish both the 0-1 value and 0-10,000 points. Weights must be nonnegative, unique by security, point-in-time, and sum to one within tolerance. The relevant primary source establishes the underlying convention; the exact diagnostic, translated universe, and parameters remain package choices where stated.
The snapshot needs unique identifiers, finite values, complete coverage, and one point-in-time methodology. as_of is not enough in production: retain observation, availability, and knowledge times plus source owner, revision, and finality. A later corrected roster or classification must not overwrite what was knowable at the earlier cutoff.
Required input
| Field | Type | Unit and rule |
|---|---|---|
as_of | ISO date | effective weight snapshot; retain availability and knowledge time separately |
security_id | string | nonempty and unique after the declared share-class aggregation policy |
weight | finite number | nonnegative fraction from one methodology; complete vector sums to 1 within 1e-9 |
ready | boolean | false means the weight vector is not publishable |
Output and refusal behavior
Return unit-scale hhi and hhi_points = 10,000 * hhi. For M positive or zero normalized weights, 1/M <= hhi <= 1; zero-weight constituents may remain only if the declared roster policy retains them.
The reference API raises on incomplete or malformed vectors. The playground renders a withheld state for the deliberately incomplete scenario so learners can see why renormalizing the survivors would answer a different question.
Read the mathematics, not only the score
Squaring makes a large weight contribute disproportionately. An equal-weight M-name roster has H=1/M; a single-name roster has H=1. Scaling by 10,000 changes presentation, not information.
sum(weight_i) == 1and every weight is nonnegative.1/M <= H <= 1; equality at1/Moccurs under equal weights.- Moving mass from a smaller weight to a larger weight increases concentration.
- DOJ's percentage-share scale explains HHI mathematics; its legal thresholds are outside this tutorial's investment interpretation.
The output must travel with its series identity and diagnostic trace. A bare number strips away the universe, methodology, horizon, tolerance, and evidence status needed to interpret it.
Work the synthetic example
The following is labelled synthetic and all arithmetic is author-derived:
| Security | Weight | Squared weight |
|---|---|---|
| S01 | 0.178218 | 0.03176159 |
| S02 | 0.138614 | 0.01921380 |
| S03 | 0.108911 | 0.01186158 |
| S04 | 0.089109 | 0.00794040 |
| S05 | 0.069307 | 0.00480345 |
| S06 | 0.059406 | 0.00352907 |
| S07 | 0.049505 | 0.00245074 |
| S08 | 0.044554 | 0.00198510 |
| … 16 more | — | included in total |
The exact expected result is:
{
"status": "resolved",
"hhi": 0.0898088422703657,
"hhi_points": 898.088422703657
}
The visual keeps the distribution beside the aggregate. That matters because two identical aggregate values can conceal different component states. The values are synthetic teaching inputs; the displayed result is author-derived arithmetic.
Compare nearby methods
| Variant | Definition | Best use | Main limitation |
|---|---|---|---|
| Full-distribution HHI (selected) | sum(w_i^2) | compare concentration of complete normalized rosters | comparison is invalid across different universes or weight bases |
| HHI points | 10,000 H | human-readable reporting on percentage-share scale | legal merger thresholds are not index-risk bands |
| Top-N weight | sum of the largest N weights | communicate a simple cutoff | ignores every weight below N |
| Effective N | 1/H | translate HHI into an equal-weight equivalent | adds intuition, not new information |
The comparison is part of the contract. A different numerator, denominator, component universe, weighting rule, tolerance, or signal horizon is not a cosmetic option—it defines a different series.
Implementation walkthrough
The reference algorithm validates before aggregating:
validate one complete point-in-time normalized weight vector
for each constituent: squared_weight = weight * weight
hhi = sum(squared_weight)
assert 1 / roster_size <= hhi <= 1
return hhi, 10000 * hhi, and squared-weight trace
Reject negative or non-normalized weights, retain the squared-weight trace, and never apply antitrust threshold labels to an investment index.
Python and TypeScript consume the same JSON fixture and return the same resolved fields. Invalid or incomplete input raises rather than being repaired. The playground deliberately translates its failure fixture into a visible withheld state because its job is to teach the refusal boundary.
Guided lab
Open the guided playground. Start from the informative canonical state, switch to Comparison, then Failure / boundary. Use Back and Step to inspect how each component enters the result. Compare the canonical distribution with equal weights and an invalid non-normalized roster. Reset restores the exact canonical state, and reduced-motion Play advances one deterministic observation without starting a timer.
The calculation flow shows why point-in-time validation precedes aggregation.
Put the diagnostic into an operating workflow
Use HHI for governance snapshots, concentration monitoring, and before/after rebalance comparisons only after freezing the same roster rules, share-class treatment, and weighting methodology.
A robust dashboard retains the input snapshot, formula version, parameters, component trace, and refusal reason. It should make methodology or taxonomy changes visible as breaks in series identity rather than quietly splicing them into history.
Edge cases and misuse boundaries
Do not treat legal merger thresholds as investment guidance or compare HHI values built from different weight bases and universes. Missing components are neither zero nor unchanged. A different roster, taxonomy, factor provider, share-class policy, currency, return basis, horizon, or tolerance defines a different series.
Main takeaway: HHI uses the entire weight distribution; constituent count alone cannot reveal this concentration.
Passing implementation tests proves that the code matches the selected definition. It does not prove association with future returns, usefulness after costs, causation, or suitability for an investment decision.
Evidence and historical boundary
The source records in REFERENCES.md establish only the claims mapped to them. They do not establish the synthetic numbers or silently define this package's translated universe and parameters.
A named historical case is deferred until a licensed complete point-in-time normalized weight vector, exact weighting methodology, share-class aggregation policy, revision state, and redistribution permission. Deferral is a publication boundary, not a missing-data invitation: the public tutorial uses a transparent synthetic case rather than an irreproducible observed value.
Summary and handoff
You can now calculate H=\sum_{i=1}^{M}w_i^2,\qquad H_{\mathrm{points}}=10{,}000H, identify the series-defining choices, interpret its edge regimes, preserve the audit trace, and reject incomplete snapshots. Continue with Effective Number of Constituents.
Primary sources and exact limitations are recorded in REFERENCES.md.
Rendered from the canonical Mermaid sources linked by this article.
Calculation Flow — Herfindahl Constituent Concentration
Purpose: validate series identity before producing the diagnostic.
Takeaway: Missing evidence is a state, never a zero contribution or neutral component.
ReferencesPrimary sources and evidence notesExpand the source trail, evidence role, and limitations behind the engineering choices.
Expand the source trail, evidence role, and limitations behind the engineering choices.
Claim-to-source map
| Material claim | Evidence | Classification |
|---|---|---|
| HHI squares and sums normalized shares | DOJ-HHI | sourced mathematical definition |
| Index weights depend on the declared index methodology | SPDJI-MATH | sourced provider convention |
| Unit-scale HHI and refusal to import legal thresholds | definition contract | package scaling and interpretation choice |
| Canonical values | datasets/canonical-fixture.json | synthetic input and author-derived calculation |
Every external source ID mapped above is expanded below. Provider or institutional conventions are not presented as universal laws; package translations and parameters remain labelled as implementation choices.
DOJ-HHI — Herfindahl-Hirschman Index
- Organization or authors: U.S. Department of Justice, Antitrust Division
- Source type: Official government methodology explanation
- Publication or effective date: 2023
- Version: 2023 Merger Guidelines reference
- URL or DOI: https://www.justice.gov/atr/herfindahl-hirschman-index
- Accessed: 2026-07-26
- Jurisdiction: Global methodology unless the limitation states otherwise
- Supports: HHI as the sum of squared shares and the 0-10,000 percentage-share scale.
- Limitations: Antitrust thresholds describe market concentration, not investment-index risk labels; this package transfers only the mathematics.
SPDJI-MATH — S&P Dow Jones Indices: Index Mathematics Methodology
- Organization or authors: S&P Dow Jones Indices
- Source type: Official index methodology
- Publication or effective date: 2026
- Version: Current methodology retrieved 2026-07-26
- URL or DOI: https://www.spglobal.com/spdji/en/documents/methodologies/methodology-index-math.pdf
- Accessed: 2026-07-26
- Jurisdiction: Global methodology unless the limitation states otherwise
- Supports: Index weights, weighted component returns, index calculation, capping, and the importance of methodology-specific weights.
- Limitations: Defines S&P DJI conventions; it does not define this package's Top-N diagnostic, HHI, or diffusion thresholds.
Full dependency-light reference implementations in both supported languages.
type Row = Record<string, unknown>;
const numberValue = (value: unknown, name: string): number => {
if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${name} must be a finite number`);
return value;
};
const validateRows = (rows: Row[], weighted: boolean): void => {
if (!rows.length) throw new Error("rows must not be empty");
const seen = new Set<string>();
for (const row of rows) {
const key = row[weighted ? "security_id" : "component_id"];
if (typeof key !== "string" || !key || seen.has(key)) throw new Error("component identifiers must be nonempty and unique");
seen.add(key);
if (row.ready === false) throw new Error("incomplete_component");
}
};
export function calculate(rows: Row[]) {
validateRows(rows, true);
const weights = rows.map(row => numberValue(row.weight, "weight"));
if (weights.some(w => w < 0) || Math.abs(weights.reduce((a,b)=>a+b,0)-1) > 1e-9) throw new Error("weights must be nonnegative and sum to one");
const hhi = weights.reduce((sum,w)=>sum+w*w,0);
return {status:"resolved", hhi, hhi_points:10000*hhi};
}
The embedded lab now expands to its full document height, keeping the article as the only scroll surface.