# How to make markets in horizon contracts: quoting strikes, not cents

Market making on a strike book: quote percentiles of your distribution, earn when the number lands inside your spread, manage net exposure. With code.

Source: https://rizon.markets/learn/how-to-make-markets-in-horizon-contracts (updated 2026-11-02)

> **Short answer:** A market maker in a [horizon contract](https://rizon.markets/horizon-contracts) book rests Higher orders (bids) at strikes below the median and Lower orders (asks) at strikes above it. Every contract pays 2×, so a quote is fair when the taker wins half the time, and each fill is worth twice the amount by which the taker's chance falls short of 50%. Quote the 46th and 54th percentiles of your distribution and each fill expects 8¢ per $1 of size. Filled on both sides, you make twice your size if the number finishes inside your spread and nothing if it finishes outside. Your risk is being wrong about the distribution, and being slow.

This guide is the quoting logic of Rizon's [open-source market maker](https://github.com/PlathsOven/prediction-market-maker), which quotes every book on the exchange through the public API. Accounts are paper money, so it's a safe place to build one.

## Quoting strikes instead of cents

| | Cents market | Horizon book |
|---|---|---|
| You quote | A price at a fixed strike | A strike at a fixed price |
| A bid | "I'll pay 48¢ for Yes" | "I'll hold Higher at 191.5" |
| An ask | "I'll sell Yes at 52¢" | "I'll hold Lower at 194.5" |
| Better for the taker | A higher bid, a lower ask | A higher bid strike, a lower ask strike |
| The spread | Cents | The number's own units |
| Number of books | One per strike | One |
| Fair value | The chance at that strike | The median |

A taker who sells into your bid at k holds Lower at k, and wins if the number ends below k. So the taker's chance at your bid is P(X < k), and the highest strike you can bid is where that chance is as much as you're willing to give.

## The touch: percentiles of a distribution

Give a taker at most 50% − m to win on either side:

- **Best bid:** the highest strike where P(X < k) ≤ 50% − m.
- **Best ask:** the lowest strike where P(X > k) ≤ 50% − m.

With m = 4%, that's about the 46th and 54th percentiles. Each fill is worth 2m to you, 8% of size, if your distribution is right. Here's Polymarket's distribution of Republican House seats on Oct 29, 2026 (worked through in [how to price a horizon contract](https://rizon.markets/learn/how-to-price-a-horizon-contract)), on half-seat strikes:

| Quote | Percentile | Exact level (seats) | On the grid (seats) | Taker's win chance (%) |
|---|---|---|---|---|
| Best bid | 46th | 194.71 | 194.5 | 45.43 |
| Median | 50th | 196.17 | | |
| Best ask | 54th | 197.63 | 198.5 | 43.62 |

Each quote moves outward to the next strike, so the taker never gets more than 46%. The live bot blends Polymarket and Kalshi, so its numbers differ a little: its log for this market reads `median 196.09 · bid 194.5 · ask 197.5`. Its deeper levels step out by another 4% each, to about the 18th and 82nd percentiles. The margin is your choice: a tighter quote earns less per fill and takes more of the flow, and there's no fee on either side.

## What a round trip pays

Say you're filled on both sides at the same size: Higher at bid B, Lower at ask A, with B below A.

| The number finishes | Your Higher | Your Lower | Total PnL |
|---|---|---|---|
| Above A | +s | −s | 0 |
| Between B and A | +s | +s | +2s |
| Below B | −s | +s | 0 |

So a filled round trip has no risk: at worst you're flat, and if the number lands in your spread, you collect twice your size. That's the same 8% a fill in another form: if 8% of the distribution sits between the 46th and 54th percentiles, a round trip expects 16% of size across its two fills. It's also why a spread is a cost for a taker who crosses both sides: their strikes are the other way round, and they lose twice their size in the same gap.

## Net exposure is the real risk

Real fills don't come in pairs. If takers only buy, you're short one side at a stack of strikes, and you're exposed to the whole move.

| Control | What it does | The bot's default |
|---|---|---|
| Size per level | Caps what one sweep through the book can take | $2 a level, set by `SIZE` |
| Levels a side | How deep the ladder runs | 8, or 10 on price feeds |
| Maximum net position | On long-dated markets, stop adding to a side once you hold this much net | 20 × size |
| Wider quotes on thin sources | m = 7% where the source's own spread is over 5¢, 6% on uptime | On |
| Wider quotes on disagreement | When two sources, or a source and its last trades, disagree | 3 points wider |

On a rolling market, net exposure clears itself: every fill has its own expiry, so a position lasts a horizon at most. On a fixed market it stays until the result, so the cap on net position does most of the work.

## Speed on live feeds

On a live price, your risk is a stale quote. If Bitcoin jumps $20 and your ask still sits at the old level, the next taker buys a contract that's already well in the money: a $10 stale strike on a 1-minute book is worth about 37¢ per $1 of size to them ([the numbers](https://rizon.markets/learn/how-to-price-a-horizon-contract)). So a feed book re-quotes on every tick.

The exchange allows 20 orders a second per account, so quote changes are the budget to spend:

- **Move the near side first.** A price move makes the side it moved toward less safe and the other side more safe. The far side can lag slightly, so a wiggle costs no orders.
- **Batch.** One batch (`POST /orders/batch` over the WebSocket) cancels only the quotes whose strike moved and places their replacements.
- **Best levels first.** Every book gets its best bid and ask before any book gets its depth.
- **One process per set of markets.** To run more books at full speed, give each process its own key.

## Run it

You need [Bun](https://bun.sh) 1.2 or later:

```sh
git clone https://github.com/PlathsOven/prediction-market-maker && cd prediction-market-maker
bun src/read.ts                 # read every source and print the ladders it would quote (no orders)
bun src/audit.ts --latency 30   # every fair value beside an independent reference; how fast feed books follow
RIZON_KEY=rz_… bun src/main.ts  # quote every market, as you
```

Get a key at [rizon.markets/docs#keys](https://rizon.markets/docs#keys). With no key, the bot creates a fresh $1,000 paper account. [Build a Bitcoin trading bot](https://rizon.markets/learn/build-a-bitcoin-trading-bot-with-the-rizon-api) goes through the API from scratch if you'd rather write your own.

## FAQ

### How does a market maker make money on a horizon contract?

By resting orders at strikes where the taker wins less than half the time. Quoting the 46th and 54th percentiles means a taker wins at most 46%, so each fill is worth about 8% of size to the maker, if the distribution is right.

### Do makers pay fees on horizon contracts?

Rizon has no fees on either side. The maker's income is the spread, and the taker's cost is the same spread.

### What's the risk of making markets in horizon contracts?

Being wrong about the distribution, and being slow. A quote at the wrong strike hands the edge to whoever trades against it, and on a live feed a stale quote is picked off in moments. Holding a large net position on one side adds the risk of the number itself.

### Who makes markets on Rizon now?

Open-source bots run by Rizon, through the same public API as everyone else, on three accounts that rank like any other. There's no house. Anyone can quote tighter and take the flow.

### Can I run the market maker with real money?

Not on Rizon: it's paper only, so the bots trade practice money. The code is MIT-licensed, and its pricing could read any venue, but it's written for Rizon's strike books.
