Market Data Requirement
Table of Contents
Summary
A market data requirement is a logical, symbolic description of a piece of market data that a valuation needs, stated independently of any particular physical instance that might eventually satisfy it. "The EUR discount curve" is a requirement; a specific bootstrapped curve object built from a specific set of quotes on a specific morning is not — that is what the requirement resolves to, a distinct concept covered in Market Data Identifier. This document defines what a requirement is, what identity means for one, and the three-level structure by which requirement sets are generated in practice: a static requirement set derived once from a trade's type; an instance requirement set refined per trade instance by binding the type's structural slots (currency, index, credit name, …) to that instance's actual attributes, independent of any date; and a dynamic requirement set refined further per valuation date by localising each curve-level requirement to the specific points a trade's cashflows actually touch. Each level narrows the one before it — \(\mathrm{static}(\tau(t)) \supseteq \mathrm{instance}(t) \supseteq \mathrm{dynamic}(t, d)\) — so the requirement set only ever gets smaller as more is known about the trade and the moment it is being valued.
Layperson's mental model
A market data requirement is a specification, not a selection. When a procurement team writes "400g unsalted butter, AA grade" on a purchase requisition, they are stating what is needed — a quality standard, a quantity, a type — without naming a particular supplier, batch, or delivery date. The requirement is complete as written; the choice of which supplier's butter satisfies it on any given day is a separate decision made by whoever fills the order. A market data requirement works the same way: "the EUR discount curve, for a valuation on 2026-07-23" is a statement of what is needed, written in the vocabulary a trader, a risk report, or a pricing engine naturally uses, without specifying which concrete curve object, built from which instrument quotes, by which bootstrapping methodology, provides the answer. The specification is stable; what satisfies it is not.
This analogy extends naturally to the three-level narrowing structure this document defines. A static requirement is like a category in the procurement catalogue — "unsalted butter" — true for every purchase of that product type regardless of quantity or occasion. The instance requirement binds the category to a specific transaction's actual needs: "400g of it, for the July delivery" — determined the moment the order is placed, without yet knowing the day's prices. The dynamic requirement is the final step: "these 400g, at today's price, from this storage location" — a fully-specified claim that can only be resolved into a concrete fulfilment by knowing today's information.
Aside: for readers who know DNS
The DNS system makes this same logical/physical distinction at network
scale. A domain name — www.example.com — is a requirement: a logical,
human-legible claim about what is needed ("the web server responsible for
example.com"), without specifying which physical machine answers for it.
DNS resolution turns that requirement into a physical identifier (an IP
address such as 93.184.216.34), and it is only that address a network
packet can actually be routed to. The same domain name can resolve to
different addresses over time — when a hosting provider changes — without
the requirement itself changing at all. "The EUR discount curve" behaves
exactly the same way: a requirement whose resolution can change while the
requirement remains fixed.
The three-level structure has a DNS parallel, though a thinner one. A resolver does not re-derive "what record type does this request need" on every query — the record type is fixed by the client's protocol, the analogue of the static level. But a name is resolved as a whole, not decomposed into a curve-then-point the way the instance/dynamic distinction is. The computational-cost argument for separating instance from dynamic (see Discussion) is therefore this document's own, not a consequence of the DNS analogy.
Aside: for readers who know CIDR
The static/instance/dynamic narrowing has a direct parallel in CIDR
addressing: static is like a broad address block reserved for a category
(10.0.0.0/8 for "yield curves"), instance is like a subnet carved out
for one specific trade's currency (10.1.0.0/16 for "the EUR curve"),
and dynamic is like one host address within it (10.1.3.1/32 for "the
EUR curve's 3M point"). Each step is a longer prefix, and a longer prefix
always covers fewer addresses than a shorter one — which is exactly why
\(\mathrm{dynamic}(t,d) \subseteq \mathrm{instance}(t) \subseteq
\mathrm{static}(\tau(t))\) holds without needing a separate argument.
State of the art
The three-level structure this document defines is not invented here. OpenGamma Strata provides two independent confirmations, from opposite sides of the resolution boundary, that it reflects a genuine structural necessity of building a pricing system at scale.
The first confirmation is
com.opengamma.strata.calc.runner.CalculationFunction, whose
requirements method returns "the market data requirements for performing
the calculation," keyed on the target's type, not on any resolved
value. This is the static structure made concrete: a function from trade
type to requirement set, evaluated once per type rather than once per
trade, independent of any specific instance, currency, or date. The
method signature's type parameter enforces this — the same method applies
uniformly to every instance of a given calculation target type, not to
any particular one.
The second confirmation is
com.opengamma.strata.calc.marketdata.MarketDataFunction, method
requirements(I id, MarketDataConfig marketDataConfig), which produces,
for one specific market data identifier, the further data needed to build
that identifier. This is the instance-specific and date-dependent
character of the dynamic level, expressed from the identifier's side
rather than the trade's: not "what does this trade type need" but "what
does building this one already-identified item further require."
Together, the two interfaces reproduce the per-type and per-instance levels from opposite sides of the resolution boundary. Neither had access to the other's starting point; both arrived at the same structural split. That two independently engineered production systems converge on the same decomposition — one from the trade side, one from the identifier side — is the strongest available evidence that the static/instance/dynamic distinction reflects something irreducible in the problem, not a design preference.
The three-level structure
The three levels — static, instance, dynamic — each answer a different question about what a trade needs, using a different amount of information. What changes between levels is not the concept of a requirement but how much is known: first the trade's type, then its specific attributes, then the valuation date. The levels are nested — each is a subset of the one above it — because knowing more can only narrow, never expand, what is needed.
Requirement identity
A requirement is only useful if two independently-written requirements can be compared and recognised as the same need — otherwise nothing could deduplicate work, cache a resolution, or reason about which requirements a trade population collectively generates. The attributes that compose a market data requirement's identity are:
| Attribute | Role | Worked example |
|---|---|---|
| Asset class / curve family | The broad category of market data being asked for | Yield, FX, SWAPTION |
| What is being quoted | Distinguishes a rate from a price from a volatility, within the same family | RATE, RATE_LNVOL, PRICE |
| Qualifier | The instance within the family: a currency, a currency pair, an index name, a credit name | EUR, EUR/USD, USD-LIBOR-3M |
| Curve role (where applicable) | Discounting vs projection — the same currency can require two structurally different curves for the same valuation | discount vs projection |
| Point (optional) | A specific tenor, strike, or surface coordinate, when the requirement is for a single point rather than the whole term structure | 5Y, 2Y/ATM |
| As-of / valuation date | When the requirement is being evaluated, since a requirement's resolution can and does change over time | 2026-07-23 |
Two requirements are the same requirement precisely when every one of these attributes is equal. Whether the point and as-of attributes belong to the requirement's identity itself, or are better modelled as parameters passed alongside a coarser, curve-level requirement, is a design decision this document does not settle in the abstract — it is precisely the distinction drawn below between the static requirement set (which does not yet know the as-of date, or often even the specific point) and the dynamic requirement set (which does).
Static: what a trade type needs
The static requirement set for a trade type is the set of market data requirements that every instance of that type needs, purely as a consequence of what kind of trade it is — before any specific trade, any specific currency pair, or any specific valuation date has been named. "Every FX Forward requires two interest rate curves, one for each currency in its pair" is a static requirement: it is true of the FX Forward product type as a category, derivable from the product's definition alone, and it does not change from one FX Forward to the next or from one day to the next.
Formally, if \(\mathcal{T}\) is the space of possible trade types, the static requirement set is a function
\[\mathrm{static}: \mathcal{T} \to \mathcal{P}(\mathrm{Requirements})\]
mapping each trade type to a set of requirements (using \(\mathcal{P}(\cdot)\) for "power set of") — deliberately a function of the type alone, with no dependence on any particular trade instance, currency, or date. Re-evaluating \(\mathrm{static}(\text{FxForward})\) tomorrow yields the same set as today, because nothing about the FX Forward product definition itself changed overnight.
Instance: what a trade instance needs
The static set says an FX Forward needs "two interest rate curves, one for each currency in its pair" — but it cannot say which two currencies, because it is a function of the type alone, and every FX Forward shares the same type regardless of whether it is EUR/USD or JPY/GBP. The instance requirement set closes that gap: it binds the static set's structural slots (currency, currency pair, index name, credit name, curve role) to one specific trade's actual attributes. "This trade is a EUR/USD forward, so it needs the EUR and USD discount curves, specifically" is an instance-level statement.
Formally, given a specific trade \(t\) of type \(\tau(t) \in \mathcal{T}\),
\[\mathrm{instance}(t) \subseteq \mathrm{static}(\tau(t))\]
Two properties make this level worth naming separately rather than folding it into either its neighbours. First, it needs no valuation date and no analytics to compute: which curves a EUR/USD forward touches is fixed the moment the trade is booked, by simply reading its currency pair and index fields — no cashflow generation, no schedule, no model. Second, it is stable over the trade's life in a way the level below it is not: the set of curves a trade instance touches does not change from one valuation date to the next, only which points within those curves it touches does. A EUR/USD forward booked today will still need "the EUR and USD discount curves" a year from now, even though the specific tenor points it needs will have shifted as it rolls towards maturity.
Dynamic: what a trade instance at a date needs
The dynamic requirement set refines the instance set for a specific valuation date. Where the instance set can only say "this forward needs the EUR and USD discount curves," the dynamic set can say "this forward, maturing in 87 days, needs those two curves' 3-month tenor points specifically" — a statement that depends on a fact the instance set has no access to: what today's date is.
Unlike the instance/type binding above, this step is not a lookup — for anything beyond the simplest linear products it requires running the same cashflow-generation and, where applicable, model machinery the valuation itself will eventually use (exercise dates for an option, reset and payment schedules for a swap, barrier monitoring dates for an exotic), just far enough to know which points on a curve or surface those cashflows will read from. This is why the dynamic set, not the instance set, is where most of the genuine complexity in requirement derivation lives.
Formally, given a specific trade \(t\) of type \(\tau(t) \in \mathcal{T}\) and a valuation date \(d\),
\[\mathrm{dynamic}(t, d) \subseteq \mathrm{instance}(t) \subseteq \mathrm{static}(\tau(t))\]
— the dynamic requirement set is a refinement of the instance set: it narrows any curve-level requirement down to the specific points that trade instance's cashflows actually touch on date \(d\). In practice a dynamic set is usually a proper subset — an instance requirement for "the whole EUR discount curve" narrows to "the EUR discount curve's 3M and 6M points" for one particular short-dated forward — though nothing in the definition forbids equality when a trade genuinely needs every point a term structure offers, such as a full-curve sensitivity calculation.
Discussion
Why the split matters in practice
Separating static, instance, and dynamic requirement derivation is not merely a taxonomic nicety — it is what makes large-scale requirement generation computationally tractable at all, because the three levels have sharply different costs. A trading book with ten thousand FX Forwards does not need its static requirement set computed ten thousand times; \(\mathrm{static}(\text{FxForward})\) is computed once for the type, and every instance of that type shares it. The instance refinement — binding "the two currencies' curves" to "the EUR and USD curves, specifically" — is cheap: it runs once per trade, but is pure attribute lookup, no analytics involved, and stays valid across every valuation date until the trade itself changes. The dynamic refinement — narrowing "the EUR discount curve" down to "these specific points, for this specific maturity, as of this date" — is where the real cost sits: it runs once per trade per valuation date, and for anything beyond a linear product it means re-running enough of the pricing model's own cashflow logic to know which points it will read. Knowing a book needs EUR and USD curves at all is nearly free; knowing exactly which points on those curves a thousand American swaptions and barrier options need today is not.
Why "dynamic," not "behavioural"
The distinction earns its own name specifically because behavioural would have been the natural word to pair against static — "static configuration vs. runtime behaviour" is a familiar contrast in software engineering generally — but that pairing was deliberately rejected. "Behavioural" suggests the requirement set changes as a side effect of how the system runs (caching, retries, feature flags); what actually varies between the static and dynamic requirement sets is not runtime behaviour but the arguments available at each stage — a trade's type is known before the trade itself is booked, and a trade's specific maturities and the day's date are known only once. "Static" and "dynamic" name that temporal and informational distinction directly, without implying anything about system behaviour that is not actually there.
See also
- Market Data Requirements and Resolution — the hub; a reading-order guide for the full cluster.
- Market Data Identifier — what a requirement resolves to.
- Market Data Configuration — the mechanism that performs the resolution from requirement to identifier.
- Market Data Universe — the space every resolved identifier is drawn from.
- External market data identifiers — RIC, Bloomberg, and ORE quote key compared, a worked instance of the identity attributes discussed above.
- ORE market data catalogue — ORE's own concrete quote-key scheme, a second worked instance.