Skip to content

fluidity-money/arbitrage.9lives.so

Repository files navigation

9lives Arbitrage

Real-time arbitrage dashboard that compares prediction market prices between Polymarket and Kalshi for BTC price markets. Displays live bid/ask spreads, asset price charts from both platforms overlaid, and an arbitrage difference chart — all updating in real time via WebSockets and polling.

What It Does

The app finds the current active BTC 15-minute prediction market on both Polymarket and Kalshi, then:

  • Best Bids Table — Shows side-by-side Yes/No bid, ask, and spread for both markets along with the price-to-beat and current BTC price.
  • Asset Price Chart — Overlays real-time BTC prices as reported by Polymarket (via Chainlink data streams) and Kalshi, with base price reference lines for each platform.
  • Arbitrage Diff Chart — Tracks the absolute difference in Yes bids, No bids, and spreads between the two markets over time, highlighting exploitable gaps.
  • Countdown Timer — Shows time remaining until the current market window closes, then automatically fetches the next market.

Architecture

src/
├── providers/
│   ├── polymarket.tsx      # WebSocket connections to Polymarket (market bids + Chainlink prices)
│   └── kalshi.tsx          # HTTP polling for Kalshi order book + price data (1s intervals)
├── components/
│   ├── BestBids.tsx        # Best bid/ask/spread table for both markets
│   ├── Chart.tsx           # Overlaid Polymarket vs Kalshi asset price chart (Recharts)
│   ├── ArbChart.tsx        # Yes/No/Spread difference chart between platforms
│   ├── Countdown.tsx       # Market expiry countdown timer
│   ├── Header.tsx          # Navigation header with branding
│   ├── Footer.tsx          # Footer
│   └── ThemeToggle.tsx     # Light/Dark/Auto theme switcher
├── hooks/
│   ├── useMarketSelector.tsx   # Fetches + selects the active market for a given platform/asset/period
│   ├── usePolymarketPrice.tsx  # Fetches historical BTC start price via Chainlink (Superposition GraphQL)
│   └── useBinancePrice.tsx     # Fetches historical BTC start price from Binance API
├── utils/
│   ├── findMarket.ts           # Constructs market slugs from timestamps, fetches active markets via proxy workers
│   ├── formatPolymarketBids.ts # Normalizes Polymarket best_bid_ask WebSocket messages into Orderbook format
│   ├── formatKalshiBids.ts     # Normalizes Kalshi order book responses into Orderbook format
│   ├── getPriceFromChainlink.ts # Fetches historical BTC/USD price from Superposition's Chainlink GraphQL endpoint
│   └── getPriceFromBinance.ts   # Fetches historical BTC/USDT kline close price from Binance
├── config.ts               # Platform-specific WebSocket URLs and market data selectors
├── types.ts                # TypeScript types (Orderbook, BidAsk, PricePoint, ArbDiff, market types)
├── routes/
│   ├── __root.tsx          # Root layout with Header, Footer, QueryClientProvider, theme init
│   └── index.tsx           # Main page composing all providers and chart components
└── styles.css              # Tailwind CSS styles
websocket/
└── index.mjs               # Kalshi WebSocket proxy server (Fastify + ws) with RSA-PSS auth signing

Data Flow

  1. Market DiscoveryfindMarket.ts calculates the current 15-minute window timestamp and constructs platform-specific slugs (btc-updown-15m-{ts} for Polymarket, KXBTC15M-{ts} for Kalshi). These are fetched via Cloudflare Workers proxies (*.9livesso.workers.dev).

  2. Polymarket (WebSocket) — Two persistent WebSocket connections:

    • ws-subscriptions-clob.polymarket.com — Streams best_bid_ask events for the active market. On each message, updates the Polymarket orderbook in the React Query cache and computes the arbitrage diff against the latest Kalshi data.
    • ws-live-data.polymarket.com — Streams real-time BTC/USD prices via Chainlink's crypto_prices_chainlink topic.
  3. Kalshi (Polling) — Two polling loops at 1-second intervals:

    • Order book fetched from kalshi-orderbook.9livesso.workers.dev.
    • Price fetched from klashi-price.9livesso.workers.dev.
  4. State Management — All data flows through TanStack React Query. Providers write directly to the query cache via setQueriesData, and chart components read from the cache using passive queries (enabled: false) — a pub/sub pattern over React Query.

Tech Stack

  • React 19 + TanStack Start (SSR framework with file-based routing)
  • TanStack React Query — State management and data fetching
  • TanStack Router — File-based routing
  • Recharts — Charting (ComposedChart, LineChart with animated reference dots)
  • Tailwind CSS v4 — Styling
  • Vite 7 — Build tool
  • Cloudflare Workers — Deployment target (via Wrangler) + API proxy workers
  • Biome — Linting and formatting
  • Vitest — Testing

Getting Started

Prerequisites

  • Node.js
  • pnpm

Install and Run

pnpm install
pnpm dev

The dev server starts on http://localhost:3000.

Build and Deploy

pnpm run deploy

This builds the app and deploys to Cloudflare Workers via Wrangler.

Kalshi WebSocket Proxy (Optional)

The websocket/ directory contains a standalone Fastify server that proxies authenticated WebSocket connections to the Kalshi trade API. It uses RSA-PSS signing with a private key file.

cd websocket
pnpm install
KALSHI_API_KEY=your_key node index.mjs

Runs on port 3001.

Other Commands

pnpm test        # Run tests with Vitest
pnpm lint        # Lint with Biome
pnpm format      # Format with Biome
pnpm check       # Biome check (lint + format)

License

© 9lives. All rights reserved.

About

A helpful arbitrage dashboard for Kalshi and Polymarket.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors