Cross-Platform Spread
Pull the YES price for the same real-world question from every venue that lists it, in one API call.
This recipe replaces the old "build your own correlation index" approach in cross-platform arbitrage. Recent versions ships the correlation built-in — no manual matching required.
Walkthrough
- Find a multi-provider event
bash
TOKEN="art_live_..." curl 'https://api.artery.questflow.ai/v1/events?underlying=BTC&min_providers=2&limit=5' \ -H "Authorization: Bearer $TOKEN"min_providers=2filters to events where ≥2 providers list the same canonical question. Without it, you also see single-provider events. - Fetch the live spread
bash
EVENT_ID=evt_94c9a200-8152-43b1-8b10-46214bea101a curl "https://api.artery.questflow.ai/v1/events/$EVENT_ID/spread" \ -H "Authorization: Bearer $TOKEN"Response:
json
{ "universalId": "evt_94c9a200-...", "fetchedAt": "2026-05-09T04:01:30.123Z", "legs": [ { "provider": "polymarket", "providerMarketId": "0xa8aceb...", "yesBid": 0.999, "yesAsk": 1.0, "yesMid": 0.9995 }, { "provider": "kalshi", "providerMarketId": "KXBTCD-26MAY0917-T69999.99", "yesBid": 0.99, "yesAsk": null, "noBid": null, "noAsk": 0.01, "yesMid": null } ] }YES prices are normalised to dollars (0–1). Each leg's
yesBid/yesAsk/yesMidis computed from that provider's native orderbook in parallel; one leg failing doesn't block the others. - Detect edges
ts
type Leg = { provider: string; yesBid?: number; yesAsk?: number; yesMid?: number }; function detectEdge(legs: Leg[]) { const valid = legs.filter((l) => l.yesMid !== undefined); if (valid.length < 2) return null; const sorted = [...valid].sort((a, b) => a.yesMid! - b.yesMid!); const cheapest = sorted[0]; const richest = sorted[sorted.length - 1]; const grossEdge = richest.yesMid! - cheapest.yesMid!; // Subtract conservative round-trip fees (0.3% Polymarket, 0.7% Kalshi // per side — figures in /providers/* docs). const netEdge = grossEdge - 0.01; return netEdge > 0 ? { buy: cheapest.provider, sell: richest.provider, netEdge } : null; } - Subscribe to live mids
Recent versions add
artery:stream:event:<universalId>channels that push spread snapshots every time any leg's mid moves. Until then, poll/v1/events/:id/spreadat the cadence your strategy needs (typically 1-5 Hz for daily-resolution price binaries).
Per-provider price semantics
| Provider | What yesAsk represents |
|---|---|
| Polymarket | CLOB best SELL-side price for the YES token, in dollars (Polymarket quotes 0–1 directly) |
| Kalshi | Implied: 1 - best NO bid (from orderbook_fp.no_dollars). Direct YES ask isn't quoted by Kalshi — only YES bid is |
| Hyperliquid HIP-4 | levels[1][0].px from info/l2-book?coin=<asset_id> — best ask in dollars |
Settlement risk — Polymarket settles via UMA Optimistic Oracle, Kalshi
via CFTC-regulated DCM rules, HL HIP-4 via on-chain price oracle. The same
canonical event can settle differently across venues if the underlying
data sources diverge near the strike. A future release will add a
settlement_consensus_score per universal event.
Why prices may not align
Even when canonical match is exact, observed mids can differ for legitimate reasons — these are not Artery bugs:
| Reason | Example |
|---|---|
| Different settlement times | Polymarket "by May 9" = midnight ET; Kalshi 26MAY0917 = 17:00 ET; the implied ≥-strike probability differs slightly because there are extra hours of price action |
| Liquidity-driven spread | Polymarket's BTC-binary book is deeper than Kalshi's by ~10x; Kalshi quotes wider |
| Settlement-source risk pricing | UMA disputes have settled some Polymarket markets opposite the consensus; arbitrageurs bake that risk into the price |
| Stale book on one side | One leg may have last traded minutes ago while the other is fresh |
Real arbitrage opportunities are typically the small, persistent gaps after fees. Use the snapshot data to make decisions; route execution through official SDKs — Artery does not wrap trade endpoints today (trade endpoints are on the roadmap).
See also
- Event correlation concept — the canonical key model
- Streaming — Future versions will add spread streams