Price reconciliation stream

Four price sources reconciled, with the premium computed in basis points.

RobinhoodRPC nativerhrpc.v1.EquitiesStream/StreamPrices

What it carries

Four prices exist for every stock token and they disagree by construction: Robinhood's raw underlying REST price, Chainlink's multiplier-adjusted oracle, Chainlink Data Streams, and observed DEX spot. This stream carries all four with their observation times and staleness, plus the premium between the onchain price and the underlying — the number no other provider on this chain publishes.

Key fields

FieldTypeDescription
underlying_middecimal stringFrom Robinhood REST.RAW underlying. Multiply by the multiplier before comparing to anything onchain.
oracle_pricedecimal stringChainlink feed.ALREADY multiplier-adjusted. Applying uiMultiplier() to this squares the multiplier.
dex_middecimal stringConsolidated onchain mid.
multiplierdecimal stringUsed for every conversion in the record.
premium_bpsdecimal string(dex_mid − underlying_mid × multiplier) ÷ (underlying_mid × multiplier) × 10000.
flags[]enumSTALE_ORACLE, TRADING_HALTED, SESSION_CLOSED, WIDE_SPREAD, CONTRACT_PAUSED, THIN_LIQUIDITY, MULTIPLIER_PENDING.
oracle_staleness_msuint64How old the oracle round is.

Delivery semantics

Sources have different cadences — a 15-second REST cache, an oracle heartbeat, sub-second Data Streams, and per-block DEX observation. Each input is stamped with its own observation time and staleness rather than being treated as simultaneous.

Volume: Emitted on change, per instrument. Every record carries a dedup_key and a monotonic sequence, so at-least-once delivery is deterministic to deduplicate.

Server-side filters

  • token_symbols
  • min_premium_change_bps

Filters are evaluated before bytes leave us, so a narrow subscription costs you nothing in bandwidth or parse time.

Subscribe

import { RobinhoodRPC } from "@robinhoodrpc/sdk"; const client = new RobinhoodRPC({ apiKey: process.env.RHRPC_KEY! }); // Backfill then live: omit toBlock to tail indefinitely.for await (const msg of client.prices.stream({  fromBlock: 4_200_000,})) {  handle(msg);}

Sample message

{  "token_symbol": "TSLA",  "session": "SESSION_OVERNIGHT",  "underlying_market_open": false,  "underlying_mid": "402.1800",  "oracle_price": "402.6100",  "oracle_staleness_ms": 42180,  "dex_mid": "405.9200",  "multiplier": "1.000000",  "premium_bps": "92.9",  "flags": ["DIVERGENCE_FLAG_SESSION_CLOSED"]}

Correctness notes

Prices in this stream are already multiplier-adjusted where the field says so. Robinhood’s own REST endpoint returns raw underlying values and Chainlink’s feed returns multiplier-adjusted ones; mixing them without applying the multiplier — or applying it twice — is the most common source of silent error on this chain.

The full set of rules is published at /docs/equities/correctness-rules.

Related streams