DEV Community

Cover image for Two Weeks of Live Tick Data vs Polymarket's Crypto Books: What Actually Warns a Market Maker
Andrew Rodn for FollowSM

Posted on Edited on

Two Weeks of Live Tick Data vs Polymarket's Crypto Books: What Actually Warns a Market Maker

πŸ“š The Quantitative Microstructure & Cross-Market Series by FollowSM

Part 2 ended with a promise. VPIN rebuilt from public 1-minute bars added nothing to a hedger, but 1-minute bars can't see what moved first in Part 1's 22 August sweep: one-sided taker flow inside the minute and the bid side thinning within 1% of mid. The next experiment, we wrote, was to log tick-level trades and books live and replay them through the same harness.

This is that experiment. For two weeks we recorded FollowSM's Enterprise streams next to Binance's own tick data and every quote and trade on Polymarket's rolling crypto "Up or Down" books. Then we asked the questions from Parts 1 and 4 again, on data that can actually answer them:

  1. Do the live book and flow signals warn of Binance moves, or of Polymarket repricing, better than chance?
  2. Does a circuit breaker built on them save a Polymarket market maker money, against a placebo that fires the same breaker at random times?
  3. Part 4 made money quoting Polymarket's equity books around a fair value computed from a Binance perp from January to September, then lost it in the two weeks after the study ended. Does the same idea work on the crypto books?

The capture covers 343 hours (30 September – 14 October 2026), 4 symbols (BTC, ETH, SOL, XRP), 22,576 Polymarket Up/Down markets, 5.3 million simulated fills on BTC alone, and 73 minutes of logged gaps, all excluded.

TL;DR

  • Whale sweeps lead Polymarket; the book signal mostly doesn't. After a β‰₯ $100k Binance taker sweep, the matching Up/Down markets repriced with a median lag of 44–227 ms on our clock, and 53–64% of them within a second. At random times the median was 2.5–3.7 s and 15–22% within a second. After a lopsided Β±1% book, the median was 1.2–2.2 s, barely better than random.
  • A lopsided book flags volatility, not direction. On BTC, ob_toxicity_1pct > 2 raised the chance of a β‰₯ 10 bps drop within 30 s 3.0Γ—, and of a β‰₯ 10 bps rise 4.5Γ—. On ETH it didn't raise drops at all. A walk-forward split left almost no out-of-sample events to set a threshold on.
  • Book confirmation adds nothing to a sweep. Sweeps with a same-direction book spike repriced Polymarket no faster than sweeps without one (61% vs 64% within 5 s on BTC).
  • The fair-value quoter that worked on equities loses on crypto. Quoting around a Binance-implied P(Up) lost money on all four symbols at every horizon: βˆ’$543k on BTC at settlement over two weeks, against βˆ’$72k for simply joining Polymarket's best bid and ask. The crypto books already reprice within a quarter of a second; a quote 250 ms behind Binance is the slow one.
  • The sweep breaker is the one trigger that clearly beat its placebo, on BTC only. Pulling the fair-value quoter's quotes for 5 s after each sweep saved $52.9k, more than 98% of placebos. On ETH and SOL it didn't beat them. VPIN percentile beat 93–95% of placebos on BTC and SOL, and hurt BTC's join-best quoter.
  • Check your settlement source. Our first run showed the fair-value quoter making +$4.05M on BTC. The simulator settled fills on Binance's price; Polymarket settles on a Chainlink TWAP. They disagree on 9–13% of windows, and that alone produced the profit.

Code: tick-microstructure-research (tmr collect, tmr analyze). The venue data is public; the FollowSM streams need an Enterprise key.


Part 1. The capture

What was recorded

stream source why
/ws/v1/toxicity, /ws/v1/confluence FollowSM Enterprise the signals: VPIN percentile, Β±1% book toxicity and imbalance percentile, confluence
aggTrade, bookTicker Binance spot the outcomes: per-trade sweeps, sub-second price paths
market WebSocket: best bid/ask + trades Polymarket CLOB every rolling BTC/ETH/SOL/XRP Up/Down market, 5- and 15-minute

FollowSM is never scored against FollowSM: signals come from the stream, outcomes from the venues. Every record carries two clocks, our receive time and the venue's, and signals are evaluated at receive time, when a client here could have acted on them. Binance trade IDs are consecutive, so any hole is back-filled from REST; every reconnect or cadence break on the other streams is logged and any window touching one is dropped.

The backend switched to a full local order book on 30 September, which changed what the Β±1% depth metrics mean (Part 1 has the details). The analysis uses only data after that switch.

BTC ETH SOL XRP
ob_toxicity_1pct p50 / p99 1.32 / 2.02 1.03 / 1.38 0.95 / 1.97 0.80 / 1.23
share of frames > 2 1.2% 0.3% 0.8% 0.0%
FollowSM arrival lag p50 / p99 63 / 121 ms 63 / 121 ms 65 / 120 ms 65 / 120 ms

The latency a stream adds is about a tenth of a second. That matters below, because Polymarket's books move on the same scale.

A trap worth describing

Our first full run reported the fair-value quoter making +$4,051,866 at settlement on BTC over two weeks. An edge that size on Polymarket's busiest crypto books would not survive a week of bots, so we checked the settlement before believing it.

The simulator marked each fill against the market's outcome, and took the outcome from Binance: last trade at the window's end against the last trade at its start. Polymarket's crypto Up/Down markets don't resolve on Binance. They resolve on a Chainlink BTC/USD 60-second TWAP against the window's opening price. We fetched Polymarket's own resolution for every one of the 22,576 markets and compared:

BTC ETH SOL XRP
windows where Binance disagrees with the resolution 12.7% 10.1% 9.2% 9.2%

A disagreement in one window in eight would be noise for most strategies. For this one it was the whole result. The fair-value quoter prices off exactly the Binance comparison the proxy used, so on the windows where Binance and Chainlink disagree, the proxy paid it for being wrong. Settled on the real outcomes, the same fills lost βˆ’$542,844.

The fix is in the repo: fills now settle on Polymarket's own resolution, fetched from its public API and cached, and the report prints the disagreement table above on every run. The fair-value model itself is unchanged. We fixed it before the capture started, and re-fitting it to the TWAP after seeing this result would be choosing a model by its outcome.

Part 4's lesson was to check your timestamps before you celebrate a lead. This one is the same lesson for P&L: settle on what the contract settles on.


Part 2. Who moves first

For every Binance event we found every Polymarket Up/Down market of the same coin open at that moment, and measured the time until its Up-token mid first moved at least one cent in the event's direction. The placebo runs the same measurement from random gap-free times with a random direction.

Lead-lag CDF

Fig 1. BTCUSDT: share of event–market pairs repriced, by time after the Binance event (our clock, log scale). Green: Binance sweeps and fast moves. Purple: FollowSM book-toxicity spikes. Dashed: random times.

after… BTC ETH SOL XRP
β‰₯ $100k taker sweep: median lag 227 ms 116 ms 60 ms 44 ms
… repriced within 1 s 53% 56% 63% 64%
ob_toxicity_1pct > 2 spike: median lag 1,546 ms 1,200 ms 1,408 ms 2,192 ms
… repriced within 1 s 26% 33% 32% 23%
random time (placebo): median lag 3,741 ms 2,859 ms 2,468 ms 2,676 ms
… repriced within 1 s 15% 20% 22% 21%
sweeps (pairs) 17,805 (34,962) 8,018 (15,853) 1,725 (3,408) 597 (1,179)

A sweep here is a set of same-side taker fills sharing one Binance matching event and totalling at least $100k. It is the clearest signal in the capture. When one prints, someone on Polymarket reprices within a quarter of a second. On BTC, about 5% of the time Polymarket moved before the sweep reached us. For scale, delivering a FollowSM frame from the server to us took 63 ms at the median, a quarter of BTC's median reaction window.

A lopsided book is a much weaker clock. Its curve sits between the sweep and the placebo: informative, but late.

Does the book confirm the sweep?

Part 1 suggested combining the two: act on a sweep only when the book agrees. We split the sweeps by whether a same-direction book spike followed within 5 s:

BTC, reprice within 5 s rate median lag
sweep, book confirmed (n = 5,156 pairs) 61.1% [59.8–62.5] 235 ms
sweep, not confirmed (n = 27,906) 63.5% [62.9–64.0] 228 ms
random time (n = 41,721) 37.1% [36.6–37.6] 3,711 ms

Confirmation adds nothing, and waiting for it costs time. ETH, SOL and XRP show the same.


Part 3. Do the signals predict Binance moves?

H1: depth depletion

Does ob_toxicity_1pct > 2 (at least twice as much resting sell as buy notional within Β±1% of mid) predict a Binance drop of at least 10 bps? Each signal is compared with random frames where the condition was false, and up-moves are reported too, so a volatility effect can't pass as a directional one.

30 s horizon P(drop) signal P(drop) control P(rise) signal P(rise) control
BTC (n = 520) 2.7% [1.6–4.5] 0.9% 5.0% [3.4–7.2] 1.1%
ETH (n = 769) 2.2% [1.4–3.5] 2.0% 3.3% [2.2–4.8] 1.5%
SOL (n = 701) 7.7% [6.0–9.9] 3.4% 4.7% [3.4–6.5] 3.5%
XRP (n = 163) 14.1% [9.6–20.3] 4.5% 14.7% [10.1–21.0] 3.5%

On BTC and XRP a lopsided book comes before bigger moves in both directions. It is a volatility warning, not a sell signal. Only SOL tilts down. A walk-forward test chose a threshold on the first week (3.0 for BTC, ETH and SOL, 2.0 for XRP); the second week had no events above it on three of the four symbols and three on ETH, so we recommend no threshold.

H3: which trigger is on when a move starts?

We took every Binance move of at least 10 bps within 2 s and asked which triggers were already active, and how much of the time each trigger is on (its cost to a quoter). The placebo shifts each trigger's intervals to random times.

BTC, 118 moves time active active at the move active 1 s before placebo, 1 s before
sweep 6.2% 75.4% 42.4% 6.1%
ob_toxicity_1pct > 2 6.5% 20.3% 19.5% 5.3%
VPIN percentile β‰₯ 0.95 3.9% 11.9% 11.9% 3.1%
all three 15.5% 83.9% 55.9% 14.3%

On BTC every trigger beats its placebo. On the other coins only the sweep does consistently. One second before a move, VPIN's coverage on ETH (2.2%) and SOL (4.7%) was no better than random intervals (4.4% and 5.5%), although on every coin a VPIN onset was followed by a move far more often than a placebo onset (5.6–15.3% vs 0.3–1.7%). VPIN fires rarely and is sometimes right; it does not cover most moves.


Part 4. The quote-cancel simulation

Two quoters

Part 4 found that a breaker scored only on a bad quoter looks useful because the quoter is bad. So two makers quote every tracked Up/Down token, filled by the same recorded Polymarket trades:

  • Join best (the naive control): one 100-share quote at Polymarket's best bid and best ask.
  • Fair value: a Binance-implied P(Up) Β± 2Β’, computed 250 ms before each print and never crossing the book. P(Up) = Ξ¦((ln(S/K) βˆ’ σ²/2)/Οƒ), with S the last Binance trade, K Binance at the window start and Οƒ from the trailing 30 minutes of 1-second returns. This is the crypto version of Part 4's quoter, fixed before the capture.

A trade at or through our price fills us, ignoring queue position, so fills are an upper bound. Each fill is marked out 5, 30 and 60 s later and at settlement, on Polymarket's own resolution.

static P&L, two weeks 5 s 30 s 60 s settlement
BTC join best (5.3M fills) +$76,358 +$45,239 βˆ’$51,349 βˆ’$71,714
BTC fair value (2.4M fills) βˆ’$448,370 βˆ’$483,784 βˆ’$544,301 βˆ’$542,844
ETH join best / fair value +$8,149 / βˆ’$59,979 +$3,708 / βˆ’$53,164 +$5,348 / βˆ’$33,536 +$5,238 / βˆ’$27,900
SOL join best / fair value +$13,062 / βˆ’$41,550 +$10,054 / βˆ’$38,054 +$5,589 / βˆ’$29,838 +$11,990 / βˆ’$41,192
XRP join best / fair value +$4,820 / βˆ’$21,799 +$1,020 / βˆ’$19,322 +$482 / βˆ’$13,249 +$7,032 / βˆ’$11,279

The fair-value quoter loses within 5 seconds of being filled, on every coin. That is the signature of being picked off, not of a mis-specified probability. On equities the Polymarket books were thin and slow, and a perp-based quote was ahead of them. On crypto, someone already reprices Polymarket within a quarter of a second of a Binance sweep (Part 2). A quote computed 250 ms behind Binance is the stale quote in that market, and the fills it gets are the ones it shouldn't want.

Joining the best bid and offer did better simply because it moves with everyone else's quotes. Its small edge is not robust either: BTC's settlement P&L is βˆ’$72k, and fills are an upper bound.

The breaker on top

Each trigger pulls both quoters' quotes while it is active, shifted by the measured stream lag plus a 100 ms cancel. Net value is the losing fills avoided minus the winning fills missed, at the 30 s markout; placebo β‰₯ actual is the share of 100 randomly shifted copies of the same trigger that did at least as well.

trigger (time active on BTC) BTC fair value BTC join best ETH fair value SOL fair value XRP fair value
sweep, 5 s hold (6.2%) +$52,857 (2%) +$5,894 (6%) +$1,809 (41%) +$371 (31%) +$153 (6%)
VPIN percentile β‰₯ 0.95 (3.9%) +$36,669 (7%) βˆ’$19,167 (99%) +$2,251 (48%) +$3,254 (5%) +$829 (56%)
ob_toxicity_1pct > 2 (6.5%) +$23,383 (77%) +$8,944 (9%) +$6,339 (22%) +$1,006 (57%) βˆ’$55 (94%)
any of the three (15.5%) +$96,939 (19%) βˆ’$6,061 (44%) +$9,737 (23%) +$4,703 (5%) +$853 (67%)

In brackets: the share of placebos at least as good. Bold: 5% or less.

  • Sweep: real on BTC. It saved $52.9k on the fair-value quoter (more than 98% of placebos) and $5.9k on join-best (94%). On ETH and SOL it did no better than random timing.
  • VPIN percentile: mixed. It helped the fair-value quoter on BTC and SOL, and was the worst trigger for BTC's join-best quoter (βˆ’$19.2k, 99% of placebos did better).
  • The book trigger never beat its placebos.
  • Every breaker is small next to the quoter. The best one recovered $53k of a $484k loss. A breaker can't rescue a quoter that is structurally slow.
  • Cancel latency barely mattered between 0 ms and 60 s for the composite breaker on the fair-value quoter (+$98k at 0 ms, +$77k at 5 s, +$87k at 60 s), consistent with it acting on regimes rather than single events.

Part 5. What changed in FollowSM

The capture changed what we ship, in both directions.

Added: per-event sweep fields on both streams. The clearest signal in two weeks was a single Binance taker sweep. Until now the stream's sweep detection was candle-level: a 15-minute volume z-score next to NATR, the "liquidity sweep" of Parts 2 and 3, which can't mark the second a sweep prints. Now SymbolToxicityMetrics and the confluence snapshot's binance_microstructure also publish the event itself:

field
last_sweep_side 1 buy, -1 sell, 0 none yet: the last Binance taker sweep (same-side fills in one matching event, β‰₯ $100k)
last_sweep_notional_usd its notional
last_sweep_ts its Binance trade time
sweep_active true for a few seconds after it
import asyncio
import os

from followsm_sdk import FollowSMClient  # pip install "followsm-sdk>=1.7.0"


async def main() -> None:
    client = FollowSMClient(api_key=os.environ["FOLLOWSM_API_KEY"])  # ENTERPRISE key
    async for m in client.stream_toxicity():
        if m.sweep_active:
            side = "buy" if m.last_sweep_side > 0 else "sell"
            print(f"{m.symbol}: {side} sweep ${m.last_sweep_notional_usd:,.0f}, pull quotes on its Up/Down books")


asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

Mind the race. Polymarket's median reaction to a sweep on BTC was 227 ms, and every step between Binance's matching engine and your cancel reaching Polymarket comes out of that budget. Measure your own path end to end, from last_sweep_ts to the cancel acknowledgement; if it is longer than the venue's reaction, you are the stale quote.

Not added: a fair-value field. Before the capture we had planned to stream a Binance-implied P(Up) for each Up/Down market. On crypto, quoting around it lost money on every coin, so we are not shipping a number that invites people to quote around it.

Unchanged: is_toxic_alert. The sweep breaker beat its placebos on BTC but not on ETH or SOL, which is not enough to change the alert everyone's thresholds are tuned to. The sweep fields sit next to it for you to combine.


Caveats

  • Two weeks, four coins. 343 hours is enough for the lead-lag tables (tens of thousands of pairs) and thin for P&L: a few volatile hours drive much of BTC's breaker result.
  • Fills are an upper bound. Any trade at or through our price fills us, ignoring queue position. Joining the best bid and ask in particular would sit behind other makers.
  • The fair-value quoter is one design. A quoter pricing the Chainlink TWAP itself, updating faster than 250 ms, or quoting wider might do better. We fixed this one before the capture and report it as it is.
  • One clock. Lags are measured on our receive clock, from one server. A colocated client sees everything sooner, Polymarket's reactions included.
  • Settlement outcomes come from Polymarket's API. We trust its resolutions; we did not re-derive the Chainlink TWAP.

Reproduce

git clone https://github.com/Follow-SM/tick-microstructure-research
cd tick-microstructure-research && pip install -e ".[parquet]"
cp .env.example .env          # FOLLOWSM_API_KEY (ENTERPRISE) for the FollowSM streams
tmr collect                   # run for two weeks; ~10 GB of RAM to analyse that much
tmr analyze                   # results/results.json, outreach/REPORT.md, charts
Enter fullscreen mode Exit fullscreen mode

tmr collect --venues-only records the Binance and Polymarket side without a key; the sweep lead-lag in Part 2 needs only that.


The Shield and the Sword, after five parts

  • The Sword didn't survive contact with faster quoters. A fair value from a Binance perp beat Polymarket's equity books in sample Part 4, faded after June and lost out of sample. On the crypto books, where others already react within a quarter of a second, it lost from the start. Before you quote around a better price, measure how fast the venue already moves to it.
  • The best Shield is the fastest event, not the cleverest statistic. A single large taker sweep warned of Polymarket repricing better than VPIN or book imbalance did, and was the only breaker trigger that clearly beat random timing. Ratios and percentiles describe a regime; sweeps mark the moment.
  • Settle on what the contract settles on. A proxy that disagrees with the real settlement one time in eight turned a βˆ’$543k strategy into +$4.05M. Timestamps (Part 4) and settlement sources (Part 5) are where backtests lie.

Get started

FollowSM streams VPIN, Β±1% book toxicity and imbalance percentiles, per-event Binance taker sweeps and Polymarket confluence for crypto pairs. ENTERPRISE ($499/mo) includes the /ws/v1/toxicity and /ws/v1/confluence streams used in this capture.

πŸ‘‰ Get your API key at follow-sm.com/pricing


References: Easley, LΓ³pez de Prado & O'Hara (2012), "Flow Toxicity and Liquidity in a High-Frequency World", Review of Financial Studies. Glosten & Milgrom (1985), "Bid, Ask and Transaction Prices in a Specialist Market with Heterogeneously Informed Traders", Journal of Financial Economics. Budish, Cramton & Shim (2015), "The High-Frequency Trading Arms Race: Frequent Batch Auctions as a Market Design Response", Quarterly Journal of Economics.

Not financial advice. Prediction markets and crypto carry substantial risk of loss.

Top comments (0)