# Data Quality and Carried-Forward Rates

> Read dense history correctly: carried-forward weekends, absent pre-listing dates, UTC dates, and the difference between a calendar row and a fresh fixing.

Canonical: https://currency-core.com/docs/guides/data-quality/
Updated: 2026-11-12
Published: 2026-11-11

---
A daily history response is dense, not a list of fixes. It has one entry per calendar day in the window, with weekends and holidays carrying the last published trading day forward. Charting is easy; analysis is not: a row can be a fresh fixing, a repeat, or absent because the currency had no quote yet.

| Date (UTC) | Rate | Change | What the row is |
|---|---:|---:|---|
| 2026-11-06 (Fri) | 1.0842 | | Fresh fixing |
| 2026-11-07 (Sat) | 1.0842 | 0 | Carried forward |
| 2026-11-08 (Sun) | 1.0842 | 0 | Carried forward |
| 2026-11-09 (Mon) | 1.0861 | +0.0019 | Fresh fixing |

Dates before a currency's first quote are absent, not zero. Annual parity starts in 1949 for GBP/USD and USD/INR; most majors have daily data from 1971, USD/INR from 1973, EUR pairs from 1999, and many Asian pairs from 1981. A missing early date is a coverage boundary, not a data gap.

## Detect and record carried-forward values

`/v1/rates`, `/v1/rates/{base}`, and `/v1/convert` separate the requested day (`requestedDate`) from the day actually used (`date`). When present, `asOf` maps a currency to the earlier date its value came from. History has no `asOf`, so detect carry-forward by comparing consecutive values and skipping weekends and holidays. An unchanged value is evidence, not proof; a genuinely unchanged fixing looks identical.

Store the effective `rate_date`, your fetch's `observed_at`, and `source_as_of` when supplied. Include observation time in the primary key so a refetch does not overwrite history. All dates are UTC; convert for display only.

Do not treat every calendar row as a fresh fixing. Averaging a dense series overweights weekends, and volatility over calendar days treats a three-day carry as three observations. Filter to changed values or business days, and document the convention.

A fixing is not versioned. There is no revision feed or revision number. If a refetch returns a different value for the same date, keep both observations, flag the later one, and recompute dependents. The website annual dataset is separate: FRED H.10 annual series plus documented parities, while API history uses the Frankfurter-seeded history store. Do not compare them without checking units and definitions.

## Detect repeats in code

The API does not mark a repeat, so detect it by comparing consecutive values.
This function returns every calendar row with a `repeat` flag. A repeat is
evidence of a carried-forward value, not proof: a genuinely unchanged fixing
looks identical.

```ts
type RateRow = {
  date: string;
  rate: number;
  repeat: boolean;
};

export function markRepeats(rates: Record<string, number>): RateRow[] {
  let previous: number | undefined;

  return Object.entries(rates).map(([date, rate]) => {
    const repeat = previous !== undefined && rate === previous;
    previous = rate;
    return { date, rate, repeat };
  });
}

export function observedOnly(rows: RateRow[]): RateRow[] {
  return rows.filter((row) => !row.repeat);
}
```

Use `observedOnly` before averaging or computing volatility over observed
fixings. Keep the full array for a dense chart that shows weekends and holidays.
Document which convention each dashboard or report uses.

## Related

- [API reference](/docs/api/)
- [Authentication](/docs/authentication/)
- [Errors](/docs/errors/)
- [Rate limits](/docs/rate-limits/)
- [Guides](/docs/guides/)
- [History coverage](/docs/guides/history-coverage/)
- [Caching reference rates](/docs/guides/caching/)
- [Backtesting](/docs/guides/backtesting/)
