Obscura

Forex Orderbook

OANDA's order book and position book by currency pair: where retail traders' open orders and positions sit relative to price.

forex_orderbook — the dataset name to pass to the Obscura API.

Category Markets Columns 11 Refresh Every 30 minutes Entity key pair Point-in-time available_date

What one row means

One price bucket within one OANDA order-book or position-book snapshot for one instrument at one 20-minute grid time: the percent of pending orders (`book_type = 'order'`) or open positions (`book_type = 'position'`) sitting at that price level, expressed as long/short shares of the book. This preserves OANDA's rich structure; the net long/short it implies is also written to `forex_positions` for cross-source aggregation.

One row per (source, pair, event_time, book_type, price_bucket).

Point-in-time availability

Every Obscura dataset carries available_date: the calendar day the publisher made the row available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the same thing on every dataset in the catalog.

For forex_orderbook: snapshot: available_date = captured_date, a STORED GENERATED column (migration 000205). WHY THAT IS THE DAY IT BECAME AVAILABLE: OANDA exposes only its CURRENT 20-minute grid bucket and offers no archive endpoint, so a past book cannot be fetched — every row exists because we polled, and the day we polled is the day the book was obtainable. There is nothing the vendor disseminates for this to lag behind. captured_date replaced a generated `(event_time AT TIME ZONE 'UTC')::date`; same day, but a poll instant cannot NAME itself a capture day, which is how one label came to cover six expressions. Existing rows were backfilled from exactly that expression, so no stored value moved.

Refresh cadence

Obscura refreshes forex_orderbook every 30 minutes — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.

Schema — 11 columns

The full public column list for forex_orderbook, with the meaning of every field. The same schema is served unauthenticated at https://api.obscura.trade/v1/catalog/forex_orderbook.

ColumnTypeDescription
sourcetext · not nullVendor discriminator for this shared forex-positioning table family; always `oanda` for now. Part of the composite primary key so other vendors could share the table without colliding.
pairtext · not nullCurrency pair (or metal), underscore form normalized to a pair, e.g. `EUR_USD` -> `EURUSD`.
event_timetimestamp with time zone · not nullThe book's own snapshot instant (aligns to OANDA's fixed 20-minute grid); `available_date` derives from it.
book_typetext · not null`order` (pending-order book) or `position` (open-position book).
price_buckettext · not nullBucket lower-edge price, kept as OANDA delivers it (string keeps float PKs exact).
captured_datedate · not nullThe UTC calendar day the collector POLLED the book — the date-part of the grid instant on a live run, the bronze object's capture day on a replay. available_date is generated directly from it.
available_datedatePUBLIC-availability date = captured_date. STORED generated column, read-only; not settable directly. For this source the poll instant IS the only instant the book was obtainable — there is no archive and no embargo.
long_count_percentdouble precisionPercent of the book's order/position count at this bucket that are long; nullable when OANDA omits it.
short_count_percentdouble precisionPercent of the book's order/position count at this bucket that are short.
snapshot_pricedouble precisionMid price + bucket width for the whole snapshot (repeated per row).
bucket_widthdouble precisionWidth in price units of each bucket in this book snapshot, repeated on every row.

Access forex_orderbook

Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.

import obscura

client = obscura.Client("obs_live_…")

df = client.query(
    dataset="forex_orderbook",
    symbols=["NVDA", "AAPL"],
    start="2024-01-01",
)

Create a free account Browse all 95 datasets

Frequently asked questions

What is in the forex_orderbook dataset?

OANDA's order book and position book by currency pair: where retail traders' open orders and positions sit relative to price. One price bucket within one OANDA order-book or position-book snapshot for one instrument at one 20-minute grid time: the percent of pending orders (`book_type = 'order'`) or open positions (`book_type = 'position'`) sitting at that price level, expressed as long/short shares of the book. This preserves OANDA's rich structure; the net long/short it implies is also written to `forex_positions` for cross-source aggregation.

How do I avoid look-ahead bias with forex_orderbook?

Filter on forex_orderbook.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — snapshot: available_date = captured_date, a STORED GENERATED column (migration 000205). WHY THAT IS THE DAY IT BECAME AVAILABLE: OANDA exposes only its CURRENT 20-minute grid bucket and offers no archive endpoint, so a past book cannot be fetched — every row exists because we polled, and the day we polled is the day the book was obtainable. There is nothing the vendor disseminates for this to lag behind. captured_date replaced a generated `(event_time AT TIME ZONE 'UTC')::date`; same day, but a poll instant cannot NAME itself a capture day, which is how one label came to cover six expressions. Existing rows were backfilled from exactly that expression, so no stored value moved. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.

In what formats can I get forex_orderbook?

As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="forex_orderbook". The column schema is public at https://api.obscura.trade/v1/catalog/forex_orderbook.

Can I filter forex_orderbook by company or symbol?

Yes. forex_orderbook carries pair, the column the API's symbols filter resolves against.

How often is forex_orderbook updated?

Obscura refreshes forex_orderbook on a every 30 minutes schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.

Related datasets

Cboe IndicesDaily history of Cboe's volatility indices, including VIX, sourced directly from Cboe. Crypto MarketsPer-coin market data from CoinGecko: price, market cap and volume across thousands of cryptocurrencies. DeFiLlama ProtocolsTotal value locked in each DeFi protocol, tracked by DeFiLlama. DeFiLlama StablecoinsCirculating supply of each stablecoin over time, from DeFiLlama. DeFiLlama TVLTotal value locked on each blockchain, from DeFiLlama. Flow MetricsTrade-flow metrics per symbol in fixed time windows: taker (aggressor) buy versus sell volume and trade counts, broken o… Forex PositionsRetail forex positioning by pair (share of traders long versus short), collected from several broker sentiment feeds. Forex Positions AggregateA consensus long/short reading per currency pair, blending the individual broker sentiment feeds.