---
name: Kalshi market making — the edge is ONLY in a market's first ~30% of volume, and it decays monotonically
description: 2026-07-25. Maker P&L by position in each event's volume, 209 events / $16.9M notional: 0-10% +25.8%, 10-20% +17.7%, 20-30% +13.1%, then -0.2% to -4.2% for the rest. Mature market making LOSES. Makers pay $0 fees (takers pay 4.4% of stake). Aggregate maker edge shrank +7.9% -> +2.3% as n went 40 -> 205, so only the decile structure is trustworthy. Run research/mm_feasibility.py then mm_analyse.py.
metadata:
  type: project
---

Opened after [[project_xlow_spread_verdict]] established that the money in these
markets is the spread and that **makers pay zero fees** while takers pay
`0.07*P*(1-P)` (4.39% of stake across 100 real fills). Making is the structurally
correct side; the question was whether the spread survives adverse selection.

## THE ROBUST FINDING

Maker P&L by position in each event's cumulative volume (pre-kickoff, 5c-95c,
209 events, $16.9M notional):

| share of event volume | maker ROI |
|---|---|
| **0–10%** | **+25.8%** |
| **10–20%** | **+17.7%** |
| **20–30%** | **+13.1%** |
| 30–40% | −2.5% |
| 40–100% | −0.2% to −4.2% |

**Monotone across ten deciles, then flat-negative.** Mechanism: a newly listed
market has no established price and a wide spread, so whoever quotes first
collects from early impatient buyers. Once price discovery happens and
competitors arrive, the spread compresses to the 1c tick and making stops paying.

This explains why every earlier attempt failed — xlow was always trading in the
*mature* part of the market, where the edge is already gone.

## WHAT IS NOT ESTABLISHED

- **Aggregate maker ROI is shrinking with sample.** +7.88% at 40 events →
  **+2.27%** at 205. Median event is still **negative** (−0.80%) and only 48% of
  events are profitable in the 15–85c band. Only the DECILE STRUCTURE looks real;
  the headline aggregate is probably heading to ~0.
- **Capture is the unanswered question.** All numbers assume you win every passive
  fill. You would win a queue-dependent slice, plausibly the worse slice (you fill
  when better-informed makers pull). Treat every figure as a CEILING.
- **Conditioning on Pinnacle fair — UNTESTED, not disproven.** The natural next
  step (post asks at pin_fair + margin while Kalshi has no price yet) produced
  incoherent, non-monotone output. Cause is a broken analysis, not a refuted idea:
  only 102/641 events join to live_data, the join is cross-source name matching,
  and pin_fair has to be reconstructed per-trade from 15-minute snapshots. Rebuild
  it carefully on the full pull.

## Errors made while building this — check for them on any rerun

1. **`taker_book_side` is the TAKER's own side.** `'bid'` = taker BOUGHT = MAKER
   SOLD. Getting this backwards produced a confident "-5%, market making loses"
   result. Sanity check: takers must come out net BUYERS (~3:1); retail backs
   teams, it rarely lays them.
2. **ROI on notional is distorted by price level** — a 3c longshot that loses
   returns +100% on tiny notional. Use **cents per contract** for anything
   conditioned on price.
3. **Leg identification**: ticker suffix is the team code, but codes are 2–4 chars
   (KC, SJ, LAFC), so `suffix[:3]` fails on 24/1060 legs. Strip the 7-char date
   prefix from the middle segment and use `startswith(suffix)`.

## Mechanics, for whenever this is picked up

Sell YES = Kalshi v2 `side: "ask"` (economically identical to buying NO; fully
collateralised, max loss known, no borrow). `kalshi_trader.place_limit_order`
currently hardcodes `side: "bid"` and `time_in_force: "immediate_or_cancel"` —
both must change, plus an order manager that cancels/replaces as fair value moves.
Capital is modest because quoting all three legs self-hedges: **~$1,500–2,500** at
0.5–1% capture across ten concurrent matches, sized on the p90 event.

Related: [[project_xlow_spread_verdict]], [[project_no_subask_limits]],
[[project_edge_mine_exhausted]].
