Your data pipeline broke again — not because of the feed, but because vendor A calls it
adjusted_close, vendor B calls it close_adj, and your intern called it
price. This is not a naming problem. It is an ontology problem — and the
difference matters, because a naming problem is fixed once and an ontology problem compounds until you
fix the architecture.
The global financial data services market reached $29.5 billion in 2024 and is on track to exceed $63 billion by 2032. Yet a significant portion of every quant team's working time is consumed not by alpha generation, but by identifier mapping, schema reconciliation, and corporate-action normalisation. A pricing quant developer once put it bluntly: data retrieval, storage, cleaning, and normalisation was "about 80% of my job." The alpha model — the intellectual product the firm actually pays for — was the remaining 20%.
Not a talent problem. A structural one.
This is not a resource problem, and it is not a talent problem. It is a structural problem rooted in the absence of a shared semantic layer. Financial data exists in parallel semantic universes that were never designed to converge. Each failure mode is well understood in isolation; together they compound into a productivity catastrophe. The solution has existed in computer science for decades — the financial industry has simply failed to adopt it at infrastructure scale.
Bloomberg's own survey of more than 150 quants and data scientists confirmed that progress with AI in quantitative research "is increasingly shaped by data readiness rather than experimentation alone." The firms with clean, semantically consistent data are pulling ahead. The rest are running faster on a treadmill.
Five failure modes, none of which throws an error.
An instrument exists simultaneously under five or more identifiers with no formal cross-reference standard, and that is only the first of five compounding failures. The defining property of all five is that they are silent: none produces a runtime error, all produce plausible-looking data.
| Mode | The failure | Why it is invisible |
|---|---|---|
| 01 · Identity | No universal instrument schema — Bloomberg, RIC, FIGI, CUSIP, ISIN, internal IDs coexist. | A join that silently drops 3% of instruments is indistinguishable from a correct one without ground truth. G-Research calls "symbology" one of its hardest problems. |
| 02 · Corporate actions | Split factors, dividends, spin-offs normalised differently by every vendor. | The same split produces three adjusted price series; a 0.1% discrepancy moves Sharpe by tenths over a 10-year backtest. |
| 03 · Event taxonomy | "Earnings date" has at least six legitimate answers (press release, 8-K, call, prelim, final, vendor stamp). | For PEAD and earnings momentum this is not data quality — it is the strategy. A one-day window error backtests a non-tradeable signal. |
| 04 · Cross-asset joins | No common entity model across equities, rates, credit, FX, commodities. | Each join is bespoke; teams accumulate one-off scripts with undocumented assumptions that break on schema change. |
| 05 · Temporal semantics | Point-in-time, as-of, as-reported routinely conflated into a single timestamp. | A 2015 backtest using 2018-revised earnings tests a strategy that did not exist in 2015. The subtlest and most expensive mode. |
Consider a quant PM at a mid-size macro fund backtesting a cross-asset equity–rates strategy. In week one the equity universe join fails because one feed uses FIGI and another internal RIC codes; split factors are applied inconsistently between two equity vendors; earnings dates diverge by 1–3 days on pre-market vs after-hours conventions; the macro indicator uses final-revised figures rather than real-time release vintage, injecting look-ahead bias; and rates data joins on identifiers with no formal link to the equity issuer model.
Five independent semantic failures. None produced a runtime error. All produced plausible-looking data. The strategy that "works" in this backtest environment is not a trading strategy — it is an artefact of data-engineering inconsistency.
A class definition, not an object instance.
An ontology, in the W3C technical sense, is a formal specification of the concepts, relationships, and constraints within a domain, expressed in a machine-interpretable language. The substrate is RDF (Resource Description Framework) — a graph model of subject–predicate–object triples — and the vocabulary layered on top is OWL (Web Ontology Language), which defines classes, properties, restrictions, and axioms, enabling automated reasoning.
Crucially, an ontology is not a database schema (structure, not meaning), a data dictionary (human-readable, not machine-inferrable), a taxonomy (hierarchy without axioms), or a knowledge graph. A knowledge graph is the populated instance of an ontology — the distinction is precisely that between a class definition and an object instance in OOP. Bloomberg runs one of the most sophisticated financial KGs in production; the KG holds the instances, the ontology defines what those instances mean.
The three working parts are classes (fin:Instrument, fin:Equity,
fin:CorporateAction, fin:PriceObservation, fin:LegalEntity),
properties — object properties like fin:issuedBy and fin:listedOn,
datatype properties like fin:hasISIN and fin:closePrice — and axioms,
the constraints instances must satisfy: cardinality (an Equity has at most one ISIN per jurisdiction),
domain/range (fin:adjustedBy requires a fin:CorporateAction), and temporal
validity. A database schema can encode classes and properties. Only an ontology encodes the
axioms.
# Minimal Equity definition in Turtle / OWL 2
fin:Equity a owl:Class ; rdfs:subClassOf fin:Instrument .
fin:hasISIN a owl:DatatypeProperty ;
rdfs:domain fin:Instrument ; rdfs:range xsd:string ;
owl:cardinality 1 . # exactly one ISIN per jurisdiction
fin:adjustedBy a owl:ObjectProperty ;
rdfs:domain fin:PriceTimeSeries ;
rdfs:range fin:CorporateAction . # adjusted series ↔ triggering CA
fin:AAPL a fin:Equity ;
fin:hasISIN "US0378331005" ; fin:hasFIGI "BBG000B9XRY4" ;
fin:hasRIC "AAPL.O" ; fin:hasPriceSeries fin:AAPL_AdjClose_USD .
fin:AAPL_AdjClose_USD a fin:PriceTimeSeries ;
fin:priceType fin:AdjustedClose ; fin:currency "USD" ;
fin:adjustedBy fin:AAPL_SplitEvent_2020_08 .
What that encodes is class hierarchy plus identifier carriers plus adjustment provenance plus cardinality constraints. A relational schema covers the first two slots. The third and fourth are what make it an ontology, not a table.
Each solves one slice. Nothing links them.
The industry has not been idle. Multiple standards address fragments of this problem. The honest assessment is that each solves its assigned problem well and fails to integrate with any of the others.
| Standard | Owner | Coverage | Core limitation |
|---|---|---|---|
| FIBO v3.0 | EDM Council | Broad financial concepts: instruments, entities, contracts, processes | Conceptually rich; operationally immature. OWL 2 DL reasoning over the full corpus times out in standard reasoners. Wide gap between firms that reference FIBO and those that deploy it. |
| FIX 5.0 SP2 | FIX Trading Community | Trade and order message semantics, execution reporting | Messaging protocol only — wire format and field tags, not a persistent data model. No temporal semantics, no instrument model beyond order routing. |
| ACTUS v1.0 | ACTUS Research Foundation | Algorithmic representation of contract cash flows (PAM, ANN, LAM) | Narrow by design. No market-data layer, no cross-asset identity, no event taxonomy. Excellent for cash-flow simulation; irrelevant to data wrangling. |
| FIGI / OpenFIGI | OMG · Bloomberg | Instrument identification | Identifier only — no properties, relationships, or temporal validity. Mapping to ISIN/CUSIP/RIC needs external tooling and is not always current. |
| LEI / GLEIF | GLEIF | Legal entity identity | Entity-level only. No linkage to instruments, no issuer→instrument graph, no counterparty model. Required for MiFID II / EMIR; insufficient for quant infrastructure. |
The critical observation is structural. FIGI identifies instruments. LEI identifies entities. ACTUS models cash flows. FIX transmits orders. FIBO conceptualises everything. Nothing links them. The gap between "we use FIBO as our data dictionary" — which many large banks genuinely do — and "our quant data stack is semantically consistent across vendors" is not a small implementation gap. It is an architectural chasm. FIBO grew out of the 2008 crisis into a comprehensive but operationally difficult artefact whose full OWL corpus times out basic consistency checking in standard DL reasoners.
No existing standard is the answer. What exists is a collection of useful building blocks — and the engineering task is to assemble them into a coherent operational layer, made the foundation of the data infrastructure rather than a retrospective mapping exercise.
Five layers, bottom-up.
A production-grade implementation does not require deploying full OWL 2 DL reasoning over a tick database. The architecture that eliminates 80–90% of wrangling is a layered semantic model with clear separation of concerns — built from canonical identity up to point-in-time semantics.
The foundation everything rests on. Build this first or build nothing.
A bidirectional cross-reference graph — ISIN ↔ FIGI ↔ RIC ↔ CUSIP ↔ LEI ↔ internal_id — resolving every vendor identifier to a single canonical node. Not a spreadsheet lookup: a typed property graph with versioning and temporal validity. Property graph DBs (Neo4j, Memgraph) give constant-time traversal where relational JOINs degrade with depth.
Canonical normalisation. Queryable by historical knowledge.
CorporateAction · EarningsEvent · IndexRebalance normalised into as_released (first published) and as_revised (corrected) variants, each carrying valid_time and transaction_time. A backtest can query the event as it was known on any specific historical date — not as it appears today.
Methodology as type, not name. Eliminates silent discrepancies.
AdjustedClose is a class, not a string — with properties recording which corporate actions, which methodology, which vendor. AAPL_AdjClose_BloombergMethod and AAPL_AdjClose_RefinitivMethod are distinct objects sharing a supertype, so a query specifies the methodology it wants and records it in the output.
The cross-asset graph. Multi-asset strategies become path queries.
Issuer → Instrument → Listing → Index → Portfolio as typed edges (issuedBy, listedOn, memberOf, includedIn). "All S&P 500 instruments as of 2020-01-01 whose issuer was rated BB or above" is a three-hop traversal — not a custom join pipeline with manual date alignment.
Not optional. The difference between backtesting and fiction.
Two independent axes per record: valid_time (when the fact was true) and transaction_time (when it was recorded). A figure valid in 2019 but entered in March 2020 is a restatement; AS OF TRANSACTION_TIME 2019-06-01 never sees it. Without this, a 2021 backtest treats it as known in 2019 — look-ahead bias.
A worked sketch makes the identity layer concrete. Two vendor dataframes — one keyed on FIGI, one on RIC — each map their identifiers to a canonical internal node by walking the connected component of an identity graph, then join on the canonical ID. Vendor schemas become irrelevant, and a semantic validation step flags any instrument where the two vendor prices diverge by more than five basis points.
import networkx as nx, pandas as pd
def resolve_canonical(identifier, graph):
"""Walk the connected component; return the 'internal' node."""
if identifier not in graph:
return None
for node in nx.node_connected_component(graph, identifier):
if graph.nodes[node].get("id_type") == "internal":
return node
return None
prices_bbg["canonical"] = prices_bbg["figi"].map(lambda x: resolve_canonical(x, id_graph))
prices_ref["canonical"] = prices_ref["ric"].map(lambda x: resolve_canonical(x, id_graph))
# Join on canonical ID — vendor schemas are now irrelevant
merged = prices_bbg.dropna(subset=["canonical"]).merge(
prices_ref.dropna(subset=["canonical"]),
on=["canonical", "date"], how="inner")
# Semantic validation: flag divergence > 5 bps before it reaches the model
merged["price_divergence_bps"] = (
(merged["close_adj"] - merged["adjusted_close"]).abs()
/ merged["adjusted_close"] * 10_000).round(1)
In a naive pd.merge() the price discrepancy is invisible. In an ontology-aware pipeline the
mismatch surfaces before it reaches the model. A production implementation would swap
networkx for a property graph database or an rdflib RDF store, and the columnar price store
retrieves history for the resolved canonical ID.
What actually gets fixed.
The most direct consequence of missing temporal semantics is look-ahead bias — a backtest using information that was not available at the simulated decision. It is the most common mistake in quantitative backtesting and the hardest to detect, because it throws no error, only inflated results. It enters through restated fundamentals, backdated index additions, and vendor timestamp errors. Survivorship bias alone inflates annual S&P 500 backtest returns by 1.5–2.0%, and using final-revised GDP figures instead of real-time vintages produces systematic Sharpe inflation. A point-in-time layer makes this class of error structurally impossible: a query at a given transaction_time cannot return records added afterwards.
Reliability improves the same way. With semantic validation at the identity layer, a price observation without a typed methodology is invalid by schema, and an instrument without a canonical ID cannot enter the pipeline. The failure mode shifts from "silently wrong output" to "loud, early rejection." In production systems ingesting from 10+ vendors daily, silent errors compound faster than loud ones — loud failures are fixed once; silent errors are discovered during performance review.
Cross-asset development and regulatory reporting come along for free. When equities, rates, and FX share one ontological identity and a traversable graph, multi-asset joins become path queries — the same architecture Bloomberg built to "link data across different domains," and that JPMorgan has referenced for counterparty networks. MiFID II and EMIR already mandate LEI-linked transaction reporting; firms that maintain a proper LEI → instrument → counterparty graph generate those reports as a by-product of normal operations. The semantic layer converts compliance from periodic firefighting into a standing query.
What ontologies cannot easily fix.
The technical implementation is tractable — rdflib handles OWL 2 RL reasoning, Apache Jena
serves SPARQL, Neo4j deploys the property graph. The hard problem is organisational.
Converging four teams with four vendor contracts, four naming conventions, and four existing pipelines on
a shared schema is a political challenge, not a technical one: the transition cost is immediate and
certain, the benefit deferred and shared. The successful implementations start small — one asset class,
one vendor pair, one pain point. Prove value, expand incrementally.
The performance answer is separation of concerns. Full SPARQL over an RDF triplestore is expressive but not fast over tick-level data — a SPARQL query over 100 billion price observations is the wrong architecture. The resolution is hybrid: the graph layer for identity resolution, relationship traversal, and event normalisation; a columnar time-series store (ClickHouse, ArcticDB, kdb+) for price history. The two communicate through the canonical identity system. Equally, full OWL 2 DL reasoning is overkill: OWL 2 RL, designed for data-intensive Horn-clause reasoning over large triple stores, is the correct profile for enforcing cardinality, validating temporal consistency, and inferring cross-identifier equivalence.
An ontology is a living specification, not a one-time artefact. Every new asset class, corporate-action type, and data vendor adds maintenance obligations. The discipline is software versioning — semantic versions, explicit migration paths, a changelog, backward-compatibility guarantees. Break it deliberately and communicate the break, or maintain compatibility.
The pragmatic 80% that eliminates 90% of the wrangling.
In building Nyquist's data layer we confronted every one of these problems in sequence and in combination. Our approach was to build an identity resolution graph at the core of the API layer — so that regardless of which vendor feed a user queries, instruments, events, and prices resolve to a consistent semantic model.
It is not a full OWL ontology; a full OWL 2 DL deployment would be over-engineered for the use cases we currently serve. What we built is a typed identity graph with bidirectional cross-reference resolution, normalised corporate actions with point-in-time flags, and price observations typed by methodology rather than column name. Semantic consistency is enforced at ingestion — not at query time, and certainly not at analysis time.
The identity layer is the primitive everything else depends on. Build it first; build it well. The event layer, the relationship graph, and the temporal model are incrementally valuable on top of a solid identity foundation. They are expensive noise without one.
Key takeaways.
- Build the identity layer first — everything else depends on it. A bidirectional cross-reference graph (ISIN ↔ FIGI ↔ RIC ↔ CUSIP ↔ internal) to canonical nodes eliminates the majority of join failures. A property graph or maintained mapping table — never a hardcoded join key in a notebook.
- Type price observations as semantic classes, not column names.
AdjustedClose,VWAP,SettlementPriceare different objects with explicit properties. Trusting thatclose_adjandadjusted_closemean the same thing is a bet you will eventually lose. - Implement bi-temporality for fundamentals first. Earnings fundamentals and index constituents are where restated-figure and backdating bias is most severe. The rule: never overwrite a historical record — always insert new versions with new transaction timestamps.
- Use FIGI for instrument identity and LEI for entity identity — but own the bridge. Neither links to the other;
instrument hasIssuer entityis the join key for every cross-asset, regulatory, and counterparty analysis. It is your infrastructure moat. - Choose your stack by use case, not by standard. Property graph for identity resolution, columnar time-series for price history, RDF/SPARQL for relationship and constraint validation, OWL 2 RL — not DL — for inference. A composed architecture, not a single technology.
The relevant question for quant practitioners in 2026 is not whether to invest in a semantic data layer — the firms with clean, ontology-aware data are already pulling ahead. The question is whether the investment is disciplined: is the identity layer first or bolted on; are price observations typed by methodology or by column name; is bi-temporality enforced for fundamentals or treated as a nice-to-have; is the ontology versioned like an API or maintained by tribal knowledge. A naming problem is fixed once. An ontology problem compounds until you fix the architecture.