Skip to content
C.W.K.
Stream
Lesson 02 of 05 · published

Three Years, Forty-One Years, a Century and a Half

~12 min · licensing, data-availability, comparability, gauges

Level 0Raw Ore
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
The windows on this dashboard differ by a factor of fifty, and the differences come from three different places — only one of which is under your control, and you cannot tell which from the number.

Where the unequal windows come from

It would be reasonable to assume a spread of window lengths reflects decisions someone made. Mostly it does not — most of these are imposed from outside, by different mechanisms worth knowing because they recur in every data product. But not all of them, and the exception is the one that matters, because it is invisible from the surface and it is yours.

Licensing. The high-yield credit spread series is trimmed to roughly three trailing years — the index behind it is licensed, and the public distribution carries only a window. This was verified live rather than assumed: the series starts where it starts even in the public download. No amount of engineering extends it, and no reasonable person would guess it from looking at the chart.

Your own default, wearing an external limit's costume. The policy-rate window is about four decades, and the obvious story — that is how far back the series goes — is false. The public source publishes that rate daily from 1954, seventy-plus years. The window is forty-one because this engine's FRED helper takes a start parameter defaulting to 1985-01-01 and no caller overrides it. The same default silently truncates two currency series that are published from the 1970s and 1981.

That one is worth sitting with, because it is the inverse of the licence case and indistinguishable from it at the surface. Both present as "this series carries N years." One is imposed by a rights holder and no engineering can extend it. The other is a line in your own ingest layer that nobody has revisited since it was written. You cannot tell them apart from the number. Which means the discipline is not just "disclose the window" — it is know, for each series, whether the window is the world's answer or yours.

Scholarly reconstruction. The CAPE inputs reach back to the 1880s because an academic assembled the long series and published it — a genuinely unusual artifact, and the reason one gauge on this dashboard can make a statement about a century and a half at all.

Know which of your windows you chose. Every system that aggregates external sources inherits their unequal histories, and the design question is never "how do we make these comparable" — it is "how do we stop the interface implying they already are." But before you can disclose a window honestly you have to know where it came from, and a default in your own ingest layer looks exactly like a limit imposed by the world. Audit them by asking the source what it publishes, not by reading what you stored.

Why not normalize them?

The instinctive engineering fix is to trim everything to the shortest common window so that all percentiles are computed over the same span. It is a clean idea and it is wrong here, for a reason worth internalizing.

Trimming a century of history down to three years to match its shortest neighbor does not make the two comparable. It destroys the most valuable thing in the entire dataset — a genuinely long series is rare, expensive, and irreplaceable — in exchange for a cosmetic consistency. The reader gains nothing: they now have two percentiles that agree in span and both say very little.

The alternative is to keep each series' full history and carry the window as data, so the interface can show it and any consumer can reason about it. Disclosure preserves information; normalization destroys it. When those are the two options, disclosure wins every time.

The short windows are not the useless ones. It would be easy to conclude that a three-year percentile is not worth computing. But that series is measuring something that genuinely moves on a multi-year cycle, and three years of it is real information about where the current reading sits in the recent regime. The mistake is never the short window itself — it is putting the short-window number and the long-window number side by side in the same type with no annotation.

Code

The window computed once, on the row, with its reasoning attached·python
def span_years(first: str | None, last: str | None) -> float | None:
    """How much history stands behind a percentile, in years.

    Not decoration. These windows are wildly unequal -- HY OAS
    carries ~3 years (FRED trims the ICE BofA licence), CAPE 155,
    fed funds 41 -- and a percentile says nothing without the ruler
    it was measured against. p12 over three years and p12 over a
    century are different claims, and a surface that prints them
    identically is asserting a commensurability it does not have.
    """
    ...


# Quoted verbatim, INCLUDING its error: the live read model reports
# CAPE at 145.6 years, not 155. The stored series starts 1881 --
# CAPE needs ten years of earnings before its first point, so the
# ~1871 dataset yields a ~145-year window. The docstring is off by
# a decade, in a docstring whose entire subject is stating your
# window accurately. Left as-is here rather than silently corrected,
# because tidying a quote is how a source error becomes yours.


# Attached to every read-model row, next to the percentile itself:
#   row["first_date"]   = first[key]
#   row["window_years"] = span_years(first[key], row["data_date"])
#
# Two extra fields. They are the difference between publishing a
# measurement and publishing a number that looks like one.

External links

Exercise

Take three metrics your team compares against each other on a dashboard and find, for each, the earliest data point you actually hold. If the spans differ by more than a factor of two, your comparisons have been implicitly weighting the longest-history metric as the most trustworthy — or, worse, treating them as equals. Write the spans onto the dashboard and see whether anyone's interpretation changes.
Hint
The most common real-world version of this is a metric that was instrumented later than its neighbors. Nothing marks it, the chart starts where the data starts, and it silently reads as 'this metric has been flat and then started moving' when the truth is 'we started measuring'.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.