Slippage and Fill Quality: Market Orders vs Limit Orders

🌐 한국어

The backtest curve slopes up and to the right, but the live account goes nowhere. Anyone who has run an automated strategy knows the feeling. Most of the time the culprit isn't the strategy—it's execution. The gap between the price on your screen and the price your order actually filled at: that's slippage.

⚠️ This article is for educational and informational purposes. It does not guarantee returns from any particular technique, and you alone are responsible for any losses.

1. Where Slippage Comes From

Backtests generally assume "filled at the close." In live trading, a market order eats through the order book from the top down. If the size resting at the best ask is smaller than your order, the remainder walks up to the second and third levels and your average fill price slips.

Send a market buy for 500 shares:

  Ask level 1  10,000 × 300 shares  → 300 filled

  Ask level 2  10,005 × 200 shares  → 200 filled

Average fill = (10,000×300 + 10,005×200) / 500 = 10,002

→ 2 (0.02%) of slippage versus the 10,000 on screen

The wider the spread, the thinner the book, and the larger the order, the bigger this loss. On a round trip (entry plus exit) you pay slippage twice.

2. Market vs Limit — What Are You Giving Up?

Brokerage APIs usually distinguish order types by code. Real bot code handles it like this.

OrderType string // "00" limit, "01" market
  • Market ("01"): the fill is all but guaranteed, but you surrender the price. Right for urgent exits and stop-losses—at the cost of accepting slippage.
  • Limit ("00"): you control the price but may surrender the fill. If the market never comes to your number, the order just sits there unfilled.

The question is which hurts more. For strategies where the entry price is the edge—arbitrage, pairs—limit orders are the rule. Conversely, when a trend has broken and you must get out, a market order is the safe choice.

3. Order Size Against Book Depth

Subscribe to real-time depth and you can calculate in advance how many levels your order will consume before you send it. A bot holds quote data like this.

type RealtimeQuote struct {

    AskPrice float64 // best ask

    BidPrice float64 // best bid

    AskQty   int64   // size resting at the best ask

    BidQty   int64   // size resting at the best bid

}

// Warn about slippage if the order exceeds the size at the best level

func checkDepth(orderQty, askQty int64) bool {

    if orderQty > askQty {

        // Can't be absorbed at level 1 → consider splitting or a limit order

        return false

    }

    return true

}

If your order fits inside the size at the best level, slippage is effectively zero. If it doesn't, you're better off splitting the order into several tranches, or switching to a limit order and letting the market come to you.

4. Unfilled Orders — Sending Isn't the End

Use limit orders and managing unfilled orders comes with them, unavoidably. A resting order left unattended can fill long after the market has moved on, handing you a position you no longer want.

  • Timeout cancel: if it isn't filled within N seconds, cancel and re-evaluate. A mechanism for admitting "this price is no longer valid."
  • Chase: cancel, then re-post one tick along with the current quote. Limit the number of attempts—chasing forever invites the very slippage you were avoiding.
  • Partial fills: track precisely that 300 of 500 shares filled. Leave the remaining 200 out of your math and your position accounting drifts.
if !filled && elapsed > orderTimeout {

    cancelOrder(orderID)         // cancel the unfilled order

    if retries < maxChase {

        placeLimit(currentBid)   // re-post at the current quote

        retries++

    } else {

        placeMarket()            // give up on price, take the certain fill

    }

}

Summary

  • The gap between backtest and reality is mostly slippage — "filled at the close" is a lie
  • Market orders buy the fill; limit orders buy the price. If your edge is the price, use limits
  • Compare resting size against order size before sending, to predict and split around slippage
  • Limit orders come as a set with timeouts, chasing, and partial-fill handling

What separates live returns isn't a flashy entry signal—it's the craft of turning that signal into a fill without leaking. Slippage of 0.1% looks trivial, but for a bot doing dozens of round trips a day it's enough to flip an entire strategy into the red.

댓글

이 블로그의 인기 게시물

한국투자증권 KIS API로 실시간 시세 받기 (WebSocket 실전)

파이썬으로 업비트 API 연동하기 — 시세 조회부터 주문까지 기초

Go로 자동매매 신호봇 프레임워크 설계하기