VIZANIXTrading Software Development
Market mechanicsMarket making8 min read

Market making: inventory, skew, and being on the wrong side of every trade

A market maker earns the spread and pays for information. Every fill you get is a fill somebody wanted, and the whole discipline is about surviving that asymmetry.

Vizanix engineering · about the author

ARTICLE
8 minreading time
SECTION
Market mechanics
PUBLISHED
2026-08-28
CHAPTERS
6
READ NEXT
3
LANGUAGE
written in English
An engineering breakdown, not a rewrite of the docs.
QUOTINGINVENTORY SKEWADVERSE SELECTIONCANCELS

Market making sounds like a fee arbitrage: quote both sides, capture the spread, repeat. The reason it is difficult is contained in one observation — you do not choose which side gets filled. The market does, and it chooses the side that is about to be right.

Adverse selection is the business

Your bid gets hit when someone wants to sell. Sometimes that is a person needing liquidity, and you have earned half a spread. Sometimes it is a person who knows something, and you have just bought the top of a move.

You cannot tell which at the moment of the fill. Over many fills the mix determines whether the strategy works. Everything below is machinery for tilting that mix, or for surviving when it tilts against you.

Inventory is the state variable

A market maker's position is not a view — it is an accident of who traded with you. Left alone it accumulates: a falling market fills your bids repeatedly and you end up long into weakness.

The standard correction is skew. As inventory grows long, move both quotes down: the bid becomes less attractive to sellers, the ask becomes more attractive to buyers, and the order flow itself pushes you back toward flat.

python
def quotes(mid, spread, inventory, max_inventory, skew_k):
    # ratio in [-1, 1]: how far inventory is from flat
    r = max(-1.0, min(1.0, inventory / max_inventory))
    centre = mid - skew_k * r * spread     # long inventory -> shift both quotes down
    return centre - spread / 2, centre + spread / 2

# Near the limit, stop adding to the wrong side entirely.
def sizes(inventory, max_inventory, base):
    r = inventory / max_inventory
    bid = base * max(0.0, 1.0 - max(0.0, r))
    ask = base * max(0.0, 1.0 + min(0.0, r))
    return bid, ask

The second function matters as much as the first. Skewing the price helps; refusing to add size on the side that is already too big is what actually stops the accumulation.

Widen when you are uninformed

The spread is the price of your uncertainty. It should not be constant:

  • Volatility up, spread up. More movement per unit time means more chance the mid moves against you before you can re-quote.
  • Thin book, spread up. Less depth means a larger price impact when you have to exit inventory.
  • Around a scheduled event, spread up or quotes off. Being tight into a print is volunteering to be adversely selected.
  • Stale data, quotes off entirely. If your market state is older than a threshold, you are quoting against a book that may no longer exist.

Cancels are the bottleneck

A quoting engine spends most of its request budget on amends and cancels, and it needs them most in exactly the moment it has least budget — when the market moves and forty quotes are wrong at once.

Three things make this survivable, and all three are covered in Bybit rate limits:

  1. Batch. Where the venue supports batched cancel and amend, use it. It turns the worst moment from forty requests into a handful.
  2. Prioritise. Cancels outrank quote refreshes, always. A stale quote that cannot be cancelled is a liability; a quote that was not refreshed is only a missed opportunity.
  3. Quote fewer levels. The cheapest way to reduce cancel load is to have fewer resting orders. Most engines quote more depth than their edge justifies.

The risk band has to be hard

Skew is a soft mechanism — it makes the wrong side less likely, not impossible. Behind it there must be limits the quoting loop cannot argue with:

  • An absolute inventory ceiling, beyond which one side stops quoting entirely.
  • A loss limit on the session that pulls all quotes when breached.
  • An adverse-selection stop: if realised P&L per fill deteriorates past a threshold over a window, stop and let a human look.
  • A kill switch that cancels everything and flattens, tested and reachable in one command.

The third one deserves attention because it catches the failure mode that inventory limits do not: a market maker that is flat, within limits, and losing money on every round trip because the flow has become informed.

What to measure

MetricTells you
Fill ratio by sideWhether skew is working
Time in inventory bandHow often you are near the limit
Mark-out after fill (1s, 10s, 60s)Adverse selection, directly measured
Realised spread capture per round tripWhether the spread covers the selection cost
Cancel latency, p99Whether you can get out of the way
Quote uptimeHow much of the session you were actually in the market

Mark-out is the honest one. If the price consistently moves against you in the seconds after your fills, you are being selected, and no amount of spread widening fixes a structural information disadvantage — it only tells you how much to charge for it, or whether to be in that market at all.

This article describes engineering practice. It is not investment advice. Vizanix develops software and does not promise trading returns.

Blog

Read next

Want this running for you?

We write about what we build. If you need it built, get in touch — scoping is free.

Brief

Get a project estimate

Four questions and your contact. No deposit required to talk — if the job is not a fit, we say so straight away.

01What do you need
02Exchange
03Market
04Strategy
05Contacts

Prefer to write directly? Telegram @vx_ceo

Discuss a system