Maker-economics dossier — is (toxic-flow-filtered) market-making OOS-profitable net?
Verdict: NO (net, out-of-sample, tail-robust). The maker's earned spread is REAL but tiny (+1.3% gross per fill, OOS — the exact mirror of the taker's −1.3%), and it lives entirely in the cheap-token fat right tail. By the project's own tail-robust standard (equal-notional, capped [−1,1]) the naive maker is −13.5% per fill OOS, and a TRAIN-derived toxic-flow filter halves the bleed (−13.5% → −7.8%) but does not reach profitability. The adverse-selection *mechanism* the filter targets is clean and confirmed — the maker bleeds monotonically more as flow gets more one-sided — but mitigating it is not enough to make passive making +EV in this dataset.
Ticket: T-0016. Script: research/05_maker.py. Date: 2026-07-24. Reproduce: uv run --extra backtest python research/05_maker.py · uv run pytest -q → green.
> Honest > profitable. The whole SCORECARD showed every intrinsic signal is > real but smaller than the ~3–4% *taker* cost, pointing at the *maker* side as > the natural next question (post limit orders, pay ~0 fee, capture the bias as > spread). We tested it directly. The answer: the maker *does* earn the spread > (the fee asymmetry is real and large), but it is ~1.3% gross, tail-dependent, > eaten by adverse selection, and it does not survive as a robust per-bet > positive. This is a clean negative on the naive maker and a clean negative > on the toxic-flow fix — with the adverse-selection mechanism nonetheless > confirmed as the reason a live maker must skew/pull quotes.
---
THE MODELING CAVEAT (read first)
This is an upper bound on maker economics, not a live P&L. We assume we win every passive fill at the observed price. That ignores:
- Queue position / fill probability — a real resting quote is not guaranteed to be hit; you get filled *selectively*, and disproportionately by the informed side (that is adverse selection).
- Book impact — our own quote would change the book and the counterparty's behavior; the historical fill would not have occurred unchanged.
So every maker number here is the most optimistic case. That the *most optimistic* case is still net-negative on the tail-robust measure is the finding.
---
Method
- Universe:
dataset.build_resolved_bets_full(use_cache=True)→ 29,651,775 resolved-sports fills, 83,019 markets, span 2026-04-18 → 06-11. Split by calendar date (splits.calendar_split): TRAIN = Apr18→May26 (19,696,250), TEST = a genuine ~15-day June OOS (May27→Jun11, 9,955,525). - The naive maker = the passive counterparty of every taker fill. Verified on the raw chain (
../_repos/poly_data/processed/trades.csv):maker_directionis the exact opposite oftaker_directionon the samenonusdc_sidetoken in 100% of a 600k-row head+deep sample. The maker therefore enters the same token at the same fillpricein the opposite direction, held to resolution, so per $1 of notional
`` maker_realized_return = -( taker_realized_return ) [EXACT] ``
and the cache's taker realized_return already contains everything — negate it. The maker's fill price sits on the favorable side of mid (the taker crossed the spread to reach it), so the "earned spread" is already embedded in this gross number; no extra credit is added (conservative).
- Maker fee (documented). Polymarket charges takers a category fee (
fee_rate=0.05sports in the repo cost model); makers pay $0. Under Fee Structure V2 (effective 2026-03-30, which covers the entire Apr–Jun window) makers additionally earn a daily rebate of ~20–25% of the taker fee their counterparty paid (100% of taker fees are redistributed to makers). We use the conservativemaker_fee = 0and ignore the rebate — any rebate only improves the maker. (V2 also lowered the *sports taker* rate to 0.03; the control keeps the repo/SCORECARD0.05for continuity — see caveats.) - Sizing / tails: equal-notional $1/fill; the verdict measure caps |return| to [−1, +1]; the uncapped mean is reported alongside every figure so the tail is visible, never hidden.
- Toxic-flow filter (Q2): reuse the Edge-3 causal per-market signed-flow feature —
one_sidedness = w_signed / w_abs ∈ [−1,1]over the prior 30-min window, computed in market-batches (a single groupby.rolling over ~30M rows OOM-segfaults on this box). A toxic window =|one_sidedness| ≥ τ; the filter skips those fills. τ is derived on TRAIN only.
---
Q1 — naive maker: does the earned spread beat adverse selection?
Answer: only in gross/uncapped terms (+1.3%), and it is a cheap-token tail artifact. NO on the tail-robust measure (−13.5%).
price band | N_train mkr_net_tr uncap_tr | N_test mkr_net_te uncap_te med_te win_te
[0.0,0.1) | 1,154,807 -0.6480 +0.1631 | 582,121 -0.6194 +0.2542 -1.0000 0.190
[0.1,0.2) | 1,191,358 -0.4947 -0.0274 | 608,468 -0.4843 -0.0058 -1.0000 0.258
[0.2,0.3) | 1,592,229 -0.3776 -0.0147 | 831,154 -0.4075 -0.0762 -1.0000 0.296
[0.3,0.4) | 2,314,103 -0.2143 +0.0143 | 1,135,850 -0.1922 +0.0497 -1.0000 0.404
[0.4,0.5) | 2,891,054 -0.0914 -0.0125 | 1,539,053 -0.0673 +0.0129 -1.0000 0.466
[0.5,0.6) | 3,043,568 +0.0103 +0.0103 | 1,639,200 -0.0118 -0.0118 +0.6949 0.526
[0.6,0.7) | 2,266,973 -0.0109 -0.0109 | 1,116,850 -0.0263 -0.0263 +0.4706 0.591
[0.7,0.8) | 1,646,652 +0.0066 +0.0066 | 855,851 +0.0265 +0.0265 +0.2987 0.698
[0.8,0.9) | 1,267,482 +0.0029 +0.0029 | 613,952 +0.0032 +0.0032 +0.1628 0.736
[0.9,1.0) | 2,328,024 +0.0007 +0.0007 | 1,033,026 -0.0014 -0.0014 +0.0010 0.683
OVERALL | 19,696,250 -0.1359 +0.0077 | 9,955,525 -0.1347 +0.0132 -0.0010 0.499
- The gross edge is real but thin. Uncapped OVERALL TEST = +0.0132 — the exact mirror of the taker's gross −0.0132. The maker collects the ~1.3% the taker pays to cross. That is the earned spread, confirmed.
- The cap kills it, and the cap is the honest measure here. Capped OVERALL TEST = −0.1347. The gap is not a losing maker — it is the cheap-token fat right tail: a maker *buying* a 0.05 token that wins earns +19 uncapped but only +1 capped, while its −1 losses are unchanged. In bands
[0.0,0.4)the uncapped mean is ~0 but the capped mean is deeply negative purely because the legitimate large upside is chopped. The +1.3% uncapped lives entirely in that tail — exactly the kind of non-robust, high-variance edge the project's capped/equal-notional methodology exists to discount. - Where the cap does *not* distort (mid/favorite bands
[0.4,0.9), returns naturally within [−1,1]), the maker is roughly flat to razor-thin positive: best is[0.7,0.8)at +0.0265 TEST;[0.9,1.0)is −0.0014. No band is a robust, sizeable positive. Median TEST = −0.0010, win rate 0.499 — per fill it is a coin flip with a tail-dependent mean.
Q1 verdict: naive making is NOT robustly profitable OOS. The maker earns the spread (+1.3% gross), but adverse selection plus the cheap-token tail leave it at −13.5% on the tail-robust measure, flat in the clean mid-price region, and median ~0.
---
Q2 — the polymm fix: does a toxic-flow filter cure adverse selection?
Answer: it confirms and halves the adverse-selection bleed, but does NOT reach profitability. FALSIFIED as a profitability fix.
Adverse-selection scan (maker NET by |one-sidedness|, TRAIN only) — the maker is the counterparty of the flow, so informed one-sided flow should hurt it. It does, cleanly and monotonically:
|osid| band N maker_net win_rate
[0.0,0.1) 5,249,591 -0.0725 0.506
[0.1,0.2) 4,031,132 -0.1028 0.498
[0.2,0.3) 3,207,602 -0.1288 0.497
[0.3,0.4) 2,263,085 -0.1616 0.498
[0.4,0.5) 1,559,235 -0.1952 0.500
[0.5,0.6) 1,097,293 -0.2238 0.500
[0.6,0.7) 674,702 -0.2433 0.503
[0.7,0.8) 417,752 -0.2629 0.512
[0.8,0.9) 244,581 -0.2719 0.518
[0.9,1.0) 681,792 -0.2115 0.552
no prior flow 244,305 -0.2678 0.438
This monotone gradient (−0.07 at balanced flow → −0.27 at one-sided flow) is the strongest, cleanest result in the study: it is the adverse-selection signature made explicit. A maker who quotes into one-sided flow is being picked off, in direct proportion to how one-sided the flow is.
But every bucket is already net-negative (capped), so the TRAIN-derived threshold falls to the least-toxic cut — τ = 0.10 (skip |osid| ≥ 0.10; keep the near-balanced and no-prior-flow fills):
strategy split N mean_net uncapped median sharpe top1%|PnL|
naive maker train 19,696,250 -0.1359 +0.0077 +0.0010 -0.1641 0.013
naive maker test 9,955,525 -0.1347 +0.0132 -0.0010 -0.1610 0.013
filtered (tau=0.10) train 5,493,896 -0.0812 +0.0086 +0.0010 -0.0923 0.012
filtered (tau=0.10) test 2,870,437 -0.0778 +0.0091 -0.0010 -0.0873 0.012
- Capped, the filter halves the loss (naive −0.1347 → filtered −0.0778 OOS) — a real, OOS-consistent improvement that confirms the filter engages the adverse-selection mechanism. But it is still net-negative: it does not clear 0, and it throws away ~71% of volume to do it.
- Uncapped, the filter slightly *reduces* the edge (+0.0132 → +0.0091), because the discarded high-
|osid|bands contain some of the cheap-token winners the uncapped mean depends on. - Verdict rule (filtered TEST net > naive TEST net and > 0): the filter beats naive but is < 0, so FALSIFIED as a profitability fix.
vbt.pro (gate L1.2) — filtered-maker hourly equal-weight TEST book: total_return −100.0%, sharpe(1h-ann) −89.4, max_drawdown −100.0% over 379 bars — consistent with the negative capped per-fill net.
---
Control — the fee-asymmetry sanity (is the fee the driver?)
Confirmed. The maker and taker hold the exact opposite positions (maker_gross = −taker_gross), so the only thing separating who profits is the cost, all of which the taker pays:
role split N mean_net uncapped sharpe
MAKER (fee 0) train 19,696,250 -0.1359 +0.0077 -0.1641
MAKER (fee 0) test 9,955,525 -0.1347 +0.0132 -0.1610
TAKER (fee .05/.02) train 19,696,250 -0.2975 -0.0077 -0.1430
TAKER (fee .05/.02) test 9,955,525 -0.1973 -0.0132 -0.1073
MAKER *paying taker cost* test 9,955,525 -0.3940 +0.0132 -0.2455
- The uncapped rows are an exact mirror: maker +0.0132 = −(taker −0.0132). The gross game is zero-sum between the two sides; the fee is what breaks the symmetry.
- Fee-asymmetry wedge = MAKER(fee 0) − MAKER(paying the taker cost), TEST = +0.2593 — the mean per-fill cost the taker eats and the maker does not (fee + half-spread, inflated at cheap prices by the
spread/2 / pterm). - On the like-for-like capped measure, maker −0.1347 beats taker −0.1973 by ~0.063 — same opposite positions, the fee is the entire difference. The fee asymmetry is real and large; it is simply not large enough to lift the maker above 0 once the cheap-token tail and adverse selection are accounted for.
---
Tail honesty
top-1% |PnL| share = 0.013(naive, capped, TEST): the −13.5% is not driven by a handful of bets — after capping it is a broad phenomenon (the cap chopping the cheap-token bands across millions of fills). The positive uncapped +1.3%, by contrast, *is* the tail (cheap tokens winning big).- Median TEST −0.0010, win rate 0.499: the naive maker is a coin flip per fill; its sign lives in the mean's tails, not the body.
- The [−1, +1] cap is asymmetric against the maker here (it truncates large legitimate cheap-token *gains* more than losses → capped is *more* negative than uncapped) — the opposite direction from the Edge-3 taker case, where the cap removed a fake positive. Both the capped and uncapped means are reported at every level so the reader can see which way the tail cuts.
---
Verdict
Naive market-making is NOT profitable net OOS by the project's tail-robust standard (−13.5%/fill capped, median ~0, flat in the clean mid-price region); its only positive is a +1.3% gross earned-spread that is a cheap-token fat-tail artifact. The toxic-flow filter does NOT fix it — it confirms and *halves* the adverse-selection bleed (−13.5% → −7.8% OOS, a clean monotone mechanism) but never clears 0, and slightly reduces the uncapped edge. The fee asymmetry is real and large (wedge +0.26/fill; maker beats taker by the whole cost) — just not large enough to overcome adverse selection under honest, tail-robust sizing.
Every intrinsic signal being real-but-sub-taker-cost pointed at the maker side; the maker side turns out to earn the spread but bleed it back to adverse selection and the cheap-token tail. Under the *upper-bound* fill assumption. A real maker, filled *selectively* by the informed side, would do worse than this ceiling.
---
Caveats
- Upper-bound fills (the big one). Every number assumes we win every passive fill at that price — no queue, no fill-probability, no book impact. Real selective fills skew toward the informed side, so live making is worse than this ceiling. This is a *ceiling test*, and the ceiling is already net-negative (capped).
- The [−1,1] cap mis-measures cheap-token maker positions. A $1-notional buy of a 0.05 token can legitimately pay +$19; capping to +$1 understates it. The capped verdict (−13.5%) is therefore partly a cap artifact of cheap-token holdings — but the uncapped +1.3% is itself a fat-tail artifact of the same positions, and by the project's stated methodology (equal-notional, capped, to prevent tail-fabricated means) the capped read governs the verdict. Both are reported.
- Taker-control fee schedule. The control uses the repo/SCORECARD sports taker rate
0.05(+spread 0.02) for continuity with the edge dossiers. Under Fee Structure V2 (eff. 2026-03-30) the sports taker rate is actually0.03; a lower taker fee would *shrink* the fee-asymmetry wedge, i.e. the maker's cost advantage is somewhat smaller than the control's0.05implies. It does not change the maker's own (fee-0) economics, which drive the verdict. - Maker rebate ignored. V2 pays makers a ~20–25% daily rebate of the counterparty's taker fee; we set it to 0 (conservative). Including it would add a small positive to the maker but cannot bridge a −7.8%…−13.5% gap.
- Fill-clustering / weighting. The all-fills view weights high-volume markets by fill count (as in the edge dossiers). Event-level weighting is the stricter unit (deferred); the monotone adverse-selection gradient is unlikely to reverse under it.
Reproduce
uv run --extra backtest python research/05_maker.py
# tunables: ODDS_FLOW_WINDOW=30min ODDS_MAKER_FEE=0.0
# first run computes + caches the 30-min one_sidedness (runs/data/maker_flow_osid.parquet);
# subsequent runs reload it.
uv run pytest -q → green (includes tests/test_maker.py, the maker-identity proof).