Measuring data quality with completeness and accuracy metrics
At 7:15 AM, a fixed-income portfolio manager (PM) opens her risk dashboard and sees that 4 of her 320 corporate bonds show no price from the prior close. Those 4 positions represent 2.8% of the book by market value. Should she trade at 8:00 AM? That single decision hinges on data quality (DQ) metrics: coverage, staleness, and tolerance breaks. This lesson turns those vague worries into numbers you can put in a service level agreementservice level agreementA formal commitment defining the service level a provider guarantees to a customer, with measurable targets and consequences if they are missed.View full definition → (SLA).
Why fixed income is the hard case
Equities trade on lit exchanges with continuous prices. A large-cap stock has a clean, timestamped last trade every second.
Bonds do not. Most corporate and municipal bonds trade over the counter (OTC), meaning dealer to dealer, not on an exchange. A given bond might not trade for days. Prices are often "evaluated prices": model based estimates produced by pricing vendors such as Bloomberg (BVAL), ICE Data Services, or Refinitiv, rather than actual transactions.
That makes DQDQThe degree to which data is fit for purpose: accurate, complete, consistent, timely, valid and unique. Poor quality data undermines analytics, reporting and AI.View full definition → measurement essential. You are not asking "is the price right?" You are asking "how confident am I, and by how much could it be wrong?"
The four metrics that matter
1. Coverage ratio (completeness)
Coverage ratio = positions with a valid attribute / total positions. Measure it per attribute, not just overall.
A fixed-income book needs coverage tracked separately for: price, yield, duration, rating, and sector classification. A bond can have a price but no credit rating, which breaks your risk aggregation.
Worked example, as of a hypothetical close:
- Book: 320 bonds
- Bonds with a valid vendor price: 316
- Price coverage = 316 / 320 = 98.75%
But weight by market value, because 4 missing tiny positions matter less than 1 missing large one.
- Market-value-weighted price coverage = (total MV priced) / (total MV) = 97.2% in our opening scene
Always report both count-based and value-weighted coverage. PMs care about the value-weighted number.
2. Staleness threshold (timeliness)
A stale price is one that has not changed or refreshed within an acceptable window. For an actively traded on-the-run US Treasury, a price older than a few minutes intraday is stale. For an illiquid high-yield bond, a 2 day old evaluated price may be perfectly normal.
So staleness thresholds must be tiered by asset liquidity:
| Instrument class | Staleness threshold (illustrative) |
|---|---|
| On-the-run US Treasuries | 15 minutes intraday |
| Investment-grade corporates | 1 business day |
| High-yield corporates | 2 business days |
| Private / illiquid credit | 5 business days, then escalate |
These are illustrative operating choices, not regulatory standards. Each firm calibrates them.
Staleness rate = positions breaching the threshold / total positions. If 12 of 320 bonds exceed their tier threshold, staleness rate = 3.75%.
3. Tolerance breaks (accuracy)
You cannot check a bond price against "the true price" because there often is no trade. So you check for internal consistency and cross-source agreement.
A tolerance break is a difference between two sources (or between today and yesterday) that exceeds a preset threshold.
Two common checks:
- Day-over-day price move check. Flag any bond whose price moved more than, say, 2 points (2% of par) with no corresponding market event. A fat-fingered price of 98 entered as 89 gets caught here.
- Cross-vendor check. Compare Bloomberg BVAL against ICE. Flag differences greater than a tolerance, often expressed in basis points (bps) of yield. One basis point = 0.01%. A common corporate-bond tolerance is 10 to 25 bps of yield spread.
Tolerance break rate = flagged positions / total positions.
4. Exception rate and resolution
An exception is any DQ flag that requires human review: a missing price, a stale price, or a tolerance break. The exception rate is the total exceptions divided by total data points checked.
The metric PMs and operations teams actually negotiate is not just how many exceptions, but how fast they clear.
- Exception resolution time: median and 95th percentile time to close an exception.
- Aged exceptions: count open beyond the SLA window (for example, unresolved after 2 hours on pricing day).
Turning metrics into SLAs
An SLA is a written promise, usually between the data operations team and the front office, specifying targets and consequences. A fixed-income pricing SLA typically states:
- Priced book ready by a cutoff time (for example, 6:30 AM local for an 8:00 AM trading desk).
- Value-weighted price coverage >= 99.5% at cutoff.
- Staleness rate <= 2% at cutoff.
- All tolerance breaks above threshold reviewed and dispositioned before cutoff.
- Critical exceptions (large positions, benchmark constituents) resolved with a named escalation path.
The word "dispositioned" matters: a break does not have to be fixed, it has to be reviewed and a decision recorded (accept, override, or hold). A recorded override with a reason is good governance. A silently changed price is not.
For the regulatory backdrop, valuation governance in Europe sits under the AIFMD (Alternative Investment Fund Managers Directive) and UCITS (Undertakings for Collective Investment in Transferable Securities) frameworks, both overseen by ESMA (European Securities and Markets Authority). In the US, fund valuation is governed by Rule 2a-5 under the Investment Company Act of 1940, enforced by the SEC (Securities and Exchange Commission). Rule 2a-5 explicitly requires boards to oversee fair-value processes and to monitor pricing-service quality, which is exactly what these metrics evidence. You can read the SEC's adopting release on the SEC's Rule 2a-5 page.
A minimal DQ check in code
Here is the day-over-day tolerance check in plain Python, the kind an operations analyst runs before cutoff.
import pandas as pd
# prices: columns = cusip, price_today, price_prior, market_value
df = pd.read_csv("book_prices.csv")
# tolerance: flag moves larger than 2 points of par (par = 100)
df["move"] = (df["price_today"] - df["price_prior"]).abs()
df["break_flag"] = df["move"] > 2.0
# missing price = completeness gap
df["missing"] = df["price_today"].isna()
# value-weighted coverage
priced_mv = df.loc[~df["missing"], "market_value"].sum()
total_mv = df["market_value"].sum()
coverage_vw = priced_mv / total_mv
print(f"VW price coverage: {coverage_vw:.2%}")
print(f"Tolerance breaks: {df['break_flag'].sum()}")
print(f"Missing prices: {df['missing'].sum()}")The output is your morning SLA scorecard: three numbers that decide whether the book is fit to trade.
Knowledge check
1. Why is data quality measurement considered more essential for fixed income than for equities?
2. A PM finds that 4 of 320 bonds are missing prices, but those positions represent only a small fraction of the book by market value. What does this illustrate about coverage metrics?
3. Why should coverage ratio be tracked per attribute (price, yield, duration, rating, sector) rather than only overall?
4. Select ALL correct answers about why data quality metrics like coverage, staleness, and tolerance breaks are valuable in a fixed-income context.
Select all the correct answers.
5. Select ALL correct answers describing appropriate uses of count-based versus value-weighted coverage.
Select all the correct answers.
Reading the numbers like a PM
Metrics without context mislead. Three habits separate a useful DQ report from a noisy one.
Segment by liquidity. A 96% coverage ratio might be excellent for a distressed-debt book and alarming for a Treasury fund. Report coverage by rating bucket and by liquidity tier, never as one blended figure.
Weight by risk, not just value. A missing price on a long-duration 30 year bond distorts portfolio duration far more than a missing price on a 3 month bill of the same market value. Sophisticated shops weight coverage by contribution to interest rate risk (DV01, the dollar change in value per 1 bp move), not just market value.
Watch the trend, not the snapshot. A staleness rate creeping from 1.5% to 3% over a month often signals a decaying vendor feed or a mapping error, well before any single day breaches the SLA.
A note on benchmark and reference data
Pricing is only half the book. Fixed-income analytics also depend on reference data: coupon, maturity, day-count convention, call schedules, and issuer hierarchy. A wrong call date silently corrupts every yield-to-worst calculation downstream.
Coverage and accuracy metrics apply here too. Track "reference completeness" (percent of bonds with a full, validated static-data record) as its own SLA, often targeted above 99.9% because these fields change rarely and errors persist quietly.
Key Takeaways
- Measure per attribute, not per book. Track coverage, staleness, and tolerance breaks separately for price, yield, rating, and reference data. A blended number hides the gaps that hurt.
- Report coverage two ways: count-based and value-weighted, and ideally risk-weighted (DV01). PMs act on the risk-weighted figure.
- Tier every threshold by liquidity. A 2 day old evaluated price is stale for a Treasury and normal for a high-yield bond. One threshold for all instruments is a broken metric.
- SLAs are promises with cutoffs and escalation. Typical targets (illustrative, not regulatory): value-weighted coverage >= 99.5%, staleness <= 2%, all tolerance breaks dispositioned before the trading desk opens.
- Governance means recorded decisions. Rule 2a-5 in the US and AIFMD/UCITS in Europe expect documented oversight of pricing quality. An override with a logged reason is defensible; a silent price change is not.