Canonical data model
Seven entities. One identity, three hourly snapshots on a shared key, one daily series entity, and two market-wide feeds that are not keyed to an asset at all.
Entity relationships
Asset (1) ──< MarketSnapshot hourly, assetId + observedAt
(1) ──< SocialSnapshot hourly, assetId + observedAt
(1) ──< SentimentSnapshot hourly, assetId + observedAt
(1) ──< EcosystemSnapshot daily, assetId + asOf + series
(1) ──< NewsItem m:n, confident mappings only
Narrative hourly, not keyed to an asset
# The three hourly snapshots share a key. They are separate entities
# because they have separate nullability and separate meaning, not
# because they arrive separately.Asset
The registry entry. Mutable — display fields and pointers change — but the id never does. Everything else in the model references it. 7,461 records.
MarketSnapshot
One immutable row per asset per hour. Written once, never updated.
SocialSnapshot
Shares the key and the timestamp of the market snapshot, so market and social values for an asset at an hour are exactly aligned rather than approximately so.
SentimentSnapshot
Carries the sentiment measure and the composite score computed at write time. The score is stored with its inputs so a historical value can be audited against what produced it.
EcosystemSnapshot
Daily grain, and deliberately a separate entity with a separate time field. An asOf date next to an observedAt timestamp is a visible reminder that these are different measurements on different clocks. 69 assets.
NewsItem
Market-wide. Asset links are present only where entity mapping was unambiguous — an empty assetIds is a deliberate outcome, not a missing value.
Narrative
Not keyed to an asset at all. A narrative is an event cluster; attributing one to a specific asset is a downstream analysis with its own error rate.
Modelling decisions worth knowing
- Three hourly entities rather than one wide row. Market, social and sentiment have different nullability and different reasons to be absent. Splitting them keeps "no social data" distinguishable from "no observation".
- Daily and hourly never share a timestamp field. The naming difference is the guard rail.
- Scores are stored, not recomputed. A stored score is a historical fact about what the system said at the time.
- Provider identifiers live on the asset, not on the observation. An observation references the canonical asset; provider mapping is a property of identity.
- Nullability is part of the contract. Every
?in the tables above is real and occurs in production data.
What is not in the model
- Network and contract address — planned, see asset metadata.
- Venue-level market data — the layer receives aggregated figures.
- On-chain state — not indexed by this layer.
- Post-level or article-level content — aggregates and summaries only.
- Order book, depth or execution data.
Field-level definitions and coverage per entity are on the individual data pages. Figures measured 2026-08-31.
Related
- Asset metadata — the registry in detail.
- Normalization — how provider payloads reach this shape.
- Data API — the interface that will serve it.