Guide July 27, 2026

polyflux-client: stream Polymarket trades in Python and name every market

The official Polyflux Python library: typed real-time trades with auto-reconnect, plus a MarketCatalog that resolves any asset_id to its market in O(1).

polyflux-client is the official Python library for the Polyflux feed: pip install polyflux-client gives you every Polymarket trade as a typed object the millisecond it happens, and a local catalog that turns any trade’s asset_id into a market you can actually name. It’s the five-line raw client with the production plumbing — parsing, reconnection, market resolution — already done.

Source is on GitHub, package on PyPI. Here’s the tour.

Streaming: typed trades, zero plumbing

import asyncio
from polyflux import Client

async def main():
    client = Client("YOUR_API_KEY")          # get one at /auth
    async for trade in client.trades():
        print(trade.side, trade.size, trade.price, trade.wallet_address)

asyncio.run(main())

client.trades() yields only trade events (redeems, splits, and merges are filtered out), parsed into a Trade dataclass:

  • asset_id — the clob token id of the outcome traded
  • wallet_address — who traded
  • size, price — position size and odds (0.00–1.00), as floats
  • side / operation_typebuy or sell, with an is_buy shortcut
  • timestamp — epoch time, plus .time for a UTC datetime
  • .notionalsize × price, the trade’s USDC value
  • .raw — the full original message, so nothing the feed sends is ever out of reach

Two behaviors matter for anything that runs unattended. Drops reconnect automatically with exponential backoff — your async for just keeps going. A bad key fails fast: rejected keys raise AuthError immediately instead of retrying forever, so you find out at startup, not in the logs a day later. (Want the unfiltered feed, redeems and all? client.events() yields every raw event dict.)

The catalog: from asset_id to a market you can name

A trade tells you what happened — but its market arrives as an asset_id like 98022490269…, which is precise and completely unreadable. Calling an API to resolve every trade would put a network round-trip in your hot path, with all the latency you came here to avoid.

MarketCatalog solves it locally:

from polyflux import Client, MarketCatalog

catalog = MarketCatalog(
    event_fields=["slug", "title", "tags"],
    market_fields=["question", "outcomes"],
)
await catalog.start()     # warms from ./data, downloads if stale

record = catalog.get(trade.asset_id)       # O(1) dict read — no network call
if record:
    print(record["market"]["question"])    # "Will …?"

It builds an asset_id → market map from Polymarket’s Gamma API, and the design is worth understanding:

  • On disk: everything. The catalog keeps a raw dump of every active Polymarket event — about 500 MB, the complete payload the API returns. Disk is cheap, and the dump means a restart warms up from file instead of re-downloading.
  • In memory: only what you ask for. event_fields / market_fields act as a mask — only those fields are projected from the dump into RAM. The default tags-only projection holds every active market in ~67 MB; a rich trading projection (ids, questions, volumes, dates) runs ~160 MB. Wildcards work too ("volume*"), and a fields={...} dict lets you compute custom values per market.
  • It stays current. The catalog re-downloads in the background (hourly by default) and swaps the mapping atomically — lookups never block on a refresh. Set refresh_interval=None for offline analysis against the dump you have.
  • New markets resolve on demand. A trade in a market created minutes ago won’t be in the dump yet. With on_miss="background", unknown ids are fetched in batches as they appear; await catalog.resolve(asset_id) fetches one immediately when you need the answer now.
  • It can shrink further. A keep predicate decides which markets enter memory at all — e.g. only events tagged crypto — so a focused bot pays for exactly its universe.

Putting both together: a whale alert with names

The two pieces compose into the classic first bot — whale watching, but with human-readable output:

import asyncio
from polyflux import Client, MarketCatalog

BIG = 5_000  # shares

async def main():
    catalog = MarketCatalog(market_fields=["question"], on_miss="background")
    await catalog.start()

    client = Client("YOUR_API_KEY")
    async for trade in client.trades():
        if (trade.size or 0) < BIG:
            continue
        record = catalog.get(trade.asset_id)
        name = record["market"]["question"] if record else trade.asset_id
        print(f"🐳 {trade.side} {trade.size:,.0f} @ {trade.price}{name}")

asyncio.run(main())

🐳 buy 18,400 @ 0.63 — Will X happen by March? beats a wall of token ids — and everything after the async for is your logic, not plumbing.

When to use the library vs. raw WebSockets

Use polyflux-client when you’re building something that runs — bots, alerts, position trackers — and reconnection, typing, and market resolution are problems you’d rather not own. Drop to a raw WebSocket when you want to see the feed with zero abstraction, or you’re in a language other than Python. Same feed, same events, either way.

pip install polyflux-client, grab a key, and the whale alert above is running in the time it takes the catalog to warm up.

Frequently asked questions

Is there a Python library for Polyflux?
Yes — polyflux-client on PyPI (pip install polyflux-client, source at github.com/polyflux-io/polyflux-python). It provides a streaming Client that yields typed Trade objects with automatic reconnection, and a MarketCatalog for resolving asset ids to market details.
Does polyflux-client reconnect automatically?
Yes. The Client reconnects with exponential backoff on drops and keeps your async-for loop running. The exception is a rejected API key — that raises AuthError immediately instead of retrying, so a bad key fails fast.
How do I find which market a Polymarket trade belongs to?
Each trade carries an asset_id — the clob token id of the outcome traded. MarketCatalog maps asset_id to the market and event it belongs to as an O(1) in-memory lookup, built from Polymarket's Gamma API.
How much memory does the MarketCatalog use?
You decide. The raw dump of all active events lives on disk (~500 MB), and only the fields you select are projected into memory: the default tags-only projection is about 67 MB, and a rich trading projection (questions, volumes, dates) is about 160 MB.
What happens when a trade is in a brand-new market the catalog doesn't know?
get() returns None for unknown ids. With on_miss='background' the catalog fetches unknown ids from the API in batches and fills itself so subsequent lookups hit; await catalog.resolve(asset_id) does a blocking fetch and returns the record right away.
← All articles