N°03 / Build

Venue adapters

A Venue is anywhere your strategy can place orders. Banger ships official adapters for the venues we support, each as a separate Python package so you only install what you use.

Polymarket

uv pip install banger-adapter-polymarket

# For live trading (paper works without this extra):
uv pip install "banger-adapter-polymarket[live]"
from banger.venues.polymarket import Polymarket

class MyStrategy(Strategy):
    venues = [Polymarket()]
    universe = signals.polymarket_markets(
        category="crypto",
        min_volume_usd=10_000,
        time_to_resolution_lt="7d",
    )
    ...

Required env (live mode only)

VariablePurpose
POLYMARKET_PRIVATE_KEYEthereum private key for EIP-712 order signing
POLYMARKET_FUNDERFunder/proxy wallet address (your USDC-holding address)
POLYMARKET_SIG_TYPE0=EOA, 1=POLY_PROXY, 2=POLY_GNOSIS_SAFE (default), 3=POLY_1271
POLYMARKET_CHAIN_IDDefaults to 137 (Polygon mainnet)

Save these in Settings → Venue credentials and they’ll be encrypted at rest and injected into your deployment env at runtime.

Universe filters

  • category: case-insensitive substring match against the market’s category
  • min_volume_usd: exclude markets with cumulative volume below this
  • time_to_resolution_lt: "24h", "7d", etc. — resolves later than this is excluded
  • limit: cap result count (default 200)

Tick payload

Polymarket sends events on the public market WebSocket (no auth needed). Each event normalizes to a banger.Tick:

  • book snapshot → tick.yes_price / tick.no_price from best bid
  • price_change → updated best_bid
  • last_trade_pricetick.last_price

Kalshi

uv pip install banger-adapter-kalshi
from banger.venues.kalshi import Kalshi

class MyStrategy(Strategy):
    venues = [Kalshi()]
    universe = signals.kalshi_markets(
        category="NFL",
        time_to_resolution_lt="24h",
    )
    ...

Required env

VariablePurpose
KALSHI_API_KEY_IDAPI key UUID from your Kalshi account
KALSHI_PRIVATE_KEYRSA private key (PEM). \n-escaped multiline works.

Kalshi requires authentication for all websocket subscriptions, even public market data — so set both env vars to enable tick streams. REST market discovery works without auth.

Signing

Banger signs every authenticated Kalshi request with RSA-PSS-SHA256 over {timestamp}{METHOD}{path}, per Kalshi’s spec. You don’t need to do this yourself — set the env vars and the adapter handles it.

Building your own adapter

Every adapter implements a small ABC:

from banger.venue import Venue

class MyVenue(Venue):
    name = "my_venue"

    async def list_markets(self, **filters):
        ...  # discover

    async def subscribe_ticks(self, markets):
        ...  # async generator yielding Tick

    async def place_order(self, order):
        ...  # paper: stamp filled; live: hit your venue

    async def cancel_order(self, order_id):
        ...

    async def get_positions(self):
        ...

See packages/adapters/polymarket/ in the repo for a worked example that handles WebSocket reconnects, paper-vs-live branching, and graceful auth fallback.

See also