Little Wolf's Blog

Back

Pendulum data on Oak

What the Pendulum mirror on Sherlock/Oak contains, and what it is missing
Last updated

A mirror of the Pendulum Flow archive ↗’s Polymarket order-book data, stored on Stanford Oak and reachable from Sherlock.

Location#

/oak/stanford/projects/ruizhe-share/ganluo/pendulum-flow/
├── manifests/
├── mirror/
│   ├── contrib/devpyle/      # daily dirs, README.md
│   ├── pmxt/
│   │   ├── v1/               # 2026-02-21 .. 2026-04-16, hourly parquet
│   │   └── v2/               # 2026-04-13 .. 2026-08-10, hourly parquet
│   ├── third-party/ag6/      # 2026-08, hourly parquet, not contiguous
│   └── v3/<date>/<hour>/     # 2026-08-18 .. , parquet + manifest.json
├── mirror-state/
└── objects/
plaintext

What a parquet row is#

Every source stores the Polymarket CLOB market-channel WebSocket feed as one wide table: one row per message, typed by event_type. Columns not relevant to a type are null.

SourceNotes
pmxtv1 and v2. Millisecond times, bids and asks as JSON strings, asset_id as a decimal string.
ag6Same schema as pmxt.
v3Typed columns (list<struct> book, binary ids), microsecond timestamp_received, sequence. Five collectors merged and deduplicated; witness_set, source_witness, arrival_skew record which. About 2 GB and 180M rows per hour.

v3 event types#

Counts are from 2026-10-11 hour 00.

event_typeRowsOwn columns
price_change160Masset_id, price, size, side, best_bid, best_ask
best_bid_ask16Masset_id, best_bid, best_ask, spread
book3.9Masset_id, bids, asks
last_trade_price58Kasset_id, price, size, side, fee_rate_bps, transaction_hash
market_resolved16Kid, assets_ids, winning_asset_id, winning_outcome
new_market3.9Kid, assets_ids, outcomes, question, slug
tick_size_change9Kasset_id, old_tick_size, new_tick_size

Every row also carries timestamp, timestamp_received, sequence, market. Each row group holds a single event_type, so filtering on it skips whole row groups: reading trades only touches one row group instead of the full file.

What is missing, and how to recover it#

Most gaps can be filled from the Polymarket API ↗ (gamma, CLOB, data-api).

MissingSourceRecoverable?
Wallets behind a tradedata-api /v2/trades?taker_only=false, join on transaction_hashYes, but market feeds only page backward from now; start/end work only with user=. About 1000 rows per page.
Holders/v2/holdersCurrent snapshot only
Market and event metadatagamma /markets, /eventsYes, current state only
Resolution and dispute detail/v2/resolutionsYes
Per-minute priceCLOB /prices-history?fidelity=1Yes
On-chain splits, merges, redeems/v2/activity, Goldsky, DuneYes
Order-book book and price_changenoneNo. The WebSocket stream is the only source.

Trades themselves are in v3. The API is needed only to add the wallet.

Caveats#

  • One transaction_hash is one v3 row but several REST rows (taker plus makers, often with complementary prices summing to 1).
  • A v3 trade price can differ slightly from the REST taker average (0.7500 vs 0.7503 in one sample).
  • Leftovers from interrupted syncs: pmxt/v2/...2026-08-10T00.parquet.part (0 bytes) and contrib/devpyle/README.md.part.bad-20261013T084254Z.
  • Newest v3 day was 2026-10-11 when checked on 2026-10-16.
  • gamma and holders return current values, not point-in-time snapshots.