ConvexPi

Arena lesson

Market making

Most strategies bet on direction. A market maker doesn't — it quotes both sides of the book and earns the spreadas others trade against it. It's the perfect first agent for the Arena: you'll feel spread capture, the maker rebate, and the two risks that make it hard — inventory and adverse selection — all measurable on a real recorded order book.

The idea

Post a bid a little below the mid and an aska little above it. If a seller hits your bid and, later, a buyer lifts your ask, you've bought low and sold high — pocketing the spread without ever predicting the price. Do this thousands of times and the edge compounds. On exchanges with a maker rebate(you get paid for providing liquidity), you earn that on top. The Arena's real-book season uses a maker rebate and a taker fee, so providing liquidity is rewarded and crossing the spread costs you — exactly like a real venue.

Why it's hard: two risks

  • Inventory risk. Every fill leaves you holding a position. If your bid keeps getting hit, you accumulate a long inventory right as the price may be falling — your spread profits get swamped by a directional loss. You must lean against inventory.
  • Adverse selection.Your quote gets filled precisely when someone knows something you don't — the market is about to move through your price. Makers are systematically picked off by informed flow; the spread you earn has to compensate for it.
  • Queue position. At a given price, fills go first-in-first-out. Re-quoting every tick is simple but sends you to the back of the line; quoting patiently keeps your place. (See how matching works.)

The starter agent

Here's the core of a working market maker (full file on GitHub). It cancels its old quotes, recomputes a bid and ask around the mid, and skews both quotes against its current inventory so fills naturally pull it back toward flat:

from convexpi.arena.client import RemoteAgent, MarketState

class MarketMaker(RemoteAgent):
    half_spread_bps = 8.0   # how far each quote sits from the mid
    size = 5                # quote size per side
    max_pos = 40            # hard inventory cap
    max_skew_bps = 8.0      # max quote shift at full inventory

    def on_tick(self, state: MarketState) -> list[dict]:
        if state.mid is None:
            return []
        orders = [self.cancel(o["order_id"]) for o in state.my_open_orders]

        mid  = state.mid
        half = mid * self.half_spread_bps / 1e4
        # lean against inventory: long -> shift quotes down (sell more, buy less)
        skew = (state.position / self.max_pos) * (mid * self.max_skew_bps / 1e4)

        if state.position < self.max_pos:
            orders.append(self.limit("buy",  round(mid - half - skew), self.size))
        if state.position > -self.max_pos:
            orders.append(self.limit("sell", round(mid + half - skew), self.size))
        return orders

That's the whole strategy. When flat, the quotes are symmetric around the mid; as inventory grows, the skew shifts both quotes to unload it, and the position cap stops either side from running away.

Run it

Install the SDK, then point the agent at the real-order-book competition:

pip install convexpi-arena

python examples/market_maker.py my-handle \
    --server wss://arena-production-e3f1.up.railway.app

Watch your fills print, and your PnL and maker % climb the board on /compete/arena-book— where you can also see the live depth ladder you're quoting into.

Now make it better

The starter is deliberately naive. Ideas that move the needle:

  • Keep queue priority: only re-quote when the mid moves enough to matter, instead of cancelling every tick.
  • Widen in fast markets: scale your half-spread with recent volatility so you're not picked off during moves.
  • Smarter skew: make the inventory penalty non-linear, or quote different sizes on each side.
  • Respect the fees: your spread must clear the round-trip cost after the maker rebate — quote too tight and you pay to trade.
  • Read the tape: back off when recent trades show one-sided, informed flow.

Go quote the book

Clone the starter, run it against the live book, and tune it. The spread is there to be earned — if your quotes are smart enough to survive the inventory and the informed flow.