Transaction Costs & Market Impact: Models & Analysis › Types of Transaction Costs

Michael BrenndoerferJanuary 8, 202610 min read
Quantitative FinanceAll chapters
Part 14 of 15Strategy Development and Backtesting
Chapter 74Transaction Costs & Market Impact: Models & Analysis › Types of Transaction Costs
Reading section 2 of 16 · Types of Transaction Costs · 10 minSection 2 of 16 · 10 min

Book contents

Section 2 of 16 · 10 min read

Transaction Costs & Market Impact: Models & Analysis › Types of Transaction CostsOne section · Sections in this chapter2 / 16 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Transaction costs can be decomposed into several distinct components, each with different characteristics and magnitudes depending on the market, instrument, and trading style. Understanding this decomposition is essential for accurate cost modeling. Each component behaves differently: some are fixed and predictable, others scale with trade size, and still others depend on market conditions at the moment of execution. By carefully separating these components, we can build more accurate models and identify which costs dominate in different trading scenarios.

Explicit Costs

Explicit costs are directly observable and contractually specified. They include:

  • Commissions: Fees paid to brokers for executing trades. While commissions on US equities have largely been eliminated for retail investors, you still pay per-share or per-value fees as an institutional trader. In futures and options markets, commissions remain significant.

  • Exchange fees: Charges from exchanges for order routing, execution, and clearing. These vary by venue and order type; some exchanges offer rebates for providing liquidity while charging fees for taking liquidity.

  • Regulatory fees: In the US, these include SEC fees (based on dollar volume of sales) and FINRA Trading Activity Fees. While individually small, they accumulate for high-frequency traders.

  • Taxes: Stamp duties, financial transaction taxes, and capital gains taxes. The UK charges 0.5% stamp duty on equity purchases; France and Italy have financial transaction taxes on certain instruments. These can dramatically affect the viability of high-turnover strategies in affected markets.

In[2]:
Code
# Example: Explicit cost calculation for institutional equity trade
trade_value = 1_000_000  # $1 million trade

# Commission structure (per share)
shares = 10_000
commission_per_share = 0.005  # $0.005 per share
commission_total = shares * commission_per_share

# Exchange fees (maker-taker model)
exchange_fee_rate = 0.0003  # 3 bps for taking liquidity
exchange_fee = trade_value * exchange_fee_rate

# SEC fee (on sales only, approximately $23.10 per million)
sec_fee_rate = 23.10 / 1_000_000
sec_fee = trade_value * sec_fee_rate  # Only applies to sells

# Total explicit costs (assuming a round-trip buy and sell)
explicit_cost_buy = commission_total + exchange_fee
explicit_cost_sell = commission_total + exchange_fee + sec_fee
total_explicit = explicit_cost_buy + explicit_cost_sell
total_explicit_pct = 100 * total_explicit / trade_value
Out[3]:
Console
Trade Value: $1,000,000

Explicit Costs Breakdown:
  Commission (buy): $50.00
  Exchange fee (buy): $300.00
  Commission (sell): $50.00
  Exchange fee (sell): $300.00
  SEC fee (sell): $23.10

Total Round-Trip Explicit Cost: $723.10
As percentage of trade value: 0.072%

For this institutional trade, explicit costs amount to roughly 7-8 basis points round-trip. While seemingly small, a strategy with 100% daily turnover would pay this cost every day, amounting to roughly 18% annually in explicit costs alone.

The Bid-Ask Spread

The bid-ask spread represents the difference between the best available price to buy (ask) and sell (bid) a security. It is the most fundamental implicit trading cost and reflects the compensation that market makers demand for providing immediacy and bearing inventory risk. To understand why this spread exists, consider the role of market makers: they stand ready to buy from sellers and sell to buyers at any moment. This service of providing liquidity on demand exposes them to adverse selection risk, as informed traders may know something about the security's value that the market maker does not. The spread compensates for this risk, along with the cost of holding inventory and the operational expenses of market making.

Bid-Ask Spread

The bid-ask spread is the difference between the lowest price at which sellers are willing to sell (ask) and the highest price at which buyers are willing to buy (bid). Crossing the spread to execute immediately incurs a cost of approximately half the spread for a single trade, or the full spread for a round-trip transaction.

If you need immediate execution, buying at the ask and later selling at the bid means paying the full spread as a transaction cost. This fundamental relationship is captured by a simple formula that quantifies the cost of demanding immediacy from the market:

Spread Cost=Ask Price−Bid Price=Sask−Sbid\text{Spread Cost} = \text{Ask Price} - \text{Bid Price} = S_{\text{ask}} - S_{\text{bid}}

where:

  • Spread Cost\text{Spread Cost}: cost of immediate execution
  • SaskS_{\text{ask}}: ask price of the security
  • SbidS_{\text{bid}}: bid price of the security

The formula shows that every round-trip trade that demands immediate execution pays exactly this difference as an implicit fee to liquidity providers. If you are patient and can wait to provide liquidity rather than demand it, you may avoid this cost entirely, or even earn a portion of the spread by being on the other side of the transaction.

To compare spreads across securities with different price levels, we express the spread as a percentage of the price. This normalization allows meaningful comparisons between a $5 stock and a $500 stock since a 1-cent spread means very different things at these price levels. The percentage spread, often expressed in basis points, is:

Spread (%)=Sask−Sbid12(Sask+Sbid)×100\text{Spread (\%)} = \frac{S_{\text{ask}} - S_{\text{bid}}}{\frac{1}{2}(S_{\text{ask}} + S_{\text{bid}})} \times 100

where:

  • Spread (%)\text{Spread (\%)}: spread as a percentage of the midpoint
  • SaskS_{\text{ask}}: ask price
  • SbidS_{\text{bid}}: bid price
  • 12(Sask+Sbid)\frac{1}{2}(S_{\text{ask}} + S_{\text{bid}}): midpoint price used as reference

The choice to use the midpoint as the denominator rather than either the bid or ask price gives a symmetric measure that does not favor one side of the market over the other. This midpoint also is our best estimate of the "true" or "efficient" price of the security at any given moment.

In[4]:
Code
import pandas as pd

# Spread characteristics for different asset classes
spread_data = {
    "Asset": [
        "Apple (AAPL)",
        "Small-cap stock",
        "S&P 500 E-mini futures",
        "EUR/USD spot",
        "Corporate bond (IG)",
        "Corporate bond (HY)",
    ],
    "Typical Bid": [150.00, 25.00, 4500.00, 1.0850, 98.50, 95.00],
    "Typical Ask": [150.01, 25.05, 4500.25, 1.0851, 99.00, 96.00],
}

spread_df = pd.DataFrame(spread_data)
spread_df["Spread"] = spread_df["Typical Ask"] - spread_df["Typical Bid"]
spread_df["Spread (bps)"] = (
    10000
    * spread_df["Spread"]
    / ((spread_df["Typical Ask"] + spread_df["Typical Bid"]) / 2)
)
Out[5]:
Console
Bid-Ask Spreads Across Asset Classes:
-----------------------------------------------------------------
Apple (AAPL)              Spread: 0.0100  (0.7 bps)
Small-cap stock           Spread: 0.0500  (20.0 bps)
S&P 500 E-mini futures    Spread: 0.2500  (0.6 bps)
EUR/USD spot              Spread: 0.0001  (0.9 bps)
Corporate bond (IG)       Spread: 0.5000  (50.6 bps)
Corporate bond (HY)       Spread: 1.0000  (104.7 bps)
Out[6]:
Visualization
Horizontal bar chart comparing bid-ask spreads in basis points across six asset classes, from liquid large-cap equities to high-yield corporate bonds.
Bid-ask spreads across different asset classes expressed in basis points. Liquid equities and FX pairs have much tighter spreads compared to corporate bonds.

The variation across asset classes is substantial. In this illustration, Apple, EUR/USD, and the E-mini future have spreads below 1 basis point, while the small-cap stock is near 20 basis points and the corporate bonds are near 50-100+ basis points. This difference has major implications for strategy design: a high-turnover strategy might be profitable in SPY but disastrous in small-cap or corporate bond markets.

Slippage and Price Impact

Slippage refers to the difference between the expected execution price (such as the price at the time of order submission) and the actual execution price. This concept captures the reality that markets move between the moment you decide to trade and the moment your order is filled. Slippage arises from two sources:

  • Time-based slippage: Prices move between when you decide to trade and when your order is executed. This is particularly relevant for strategies with execution delays.

  • Market impact slippage: Your order itself moves the market price against you because you consume available liquidity at the best prices and must execute deeper into the order book.

For small orders that can be filled at the best bid or ask, slippage is minimal. But as order size increases relative to available liquidity, market impact becomes the dominant transaction cost component. This transition from "small order, minimal impact" to "large order, significant impact" determines how execution costs should be managed.

In[7]:
Code
# Simulated order book and market impact
# Assume a stock trading at $100 with the following order book on the ask side
initial_price = 100.00
order_book_ask = {
    "price": [initial_price, 100.01, 100.02, 100.05, 100.10, 100.15],
    "size": [500, 1000, 2000, 3000, 5000, 10000],  # shares at each level
}


def calculate_execution_price(order_size, order_book):
    """Calculate volume-weighted average execution price"""
    prices = order_book["price"]
    sizes = order_book["size"]

    remaining = order_size
    total_cost = 0
    filled = 0

    execution_details = []

    for price, size in zip(prices, sizes):
        if remaining <= 0:
            break
        fill_at_level = min(remaining, size)
        total_cost += fill_at_level * price
        filled += fill_at_level
        remaining -= fill_at_level
        execution_details.append((price, fill_at_level))

    if filled < order_size:
        return None, execution_details  # Insufficient liquidity

    vwap = total_cost / filled
    return vwap, execution_details


# Calculate execution prices for different order sizes
order_sizes = [100, 500, 1000, 2500, 5000, 10000]
results = []

for size in order_sizes:
    vwap, details = calculate_execution_price(size, order_book_ask)
    slippage_bps = (
        10000 * (vwap - initial_price) / initial_price if vwap else np.nan
    )
    results.append(
        {"Order Size": size, "VWAP": vwap, "Slippage (bps)": slippage_bps}
    )

results_df = pd.DataFrame(results)
Out[8]:
Console
Market Impact: Execution Price vs Order Size
--------------------------------------------------
  Order Size       VWAP  Slippage (bps)
--------------------------------------------------
       100.0 $ 100.0000             0.0
       500.0 $ 100.0000             0.0
     1,000.0 $ 100.0050             0.5
     2,500.0 $ 100.0120             1.2
     5,000.0 $ 100.0250             2.5
    10,000.0 $ 100.0550             5.5
Out[9]:
Visualization
Line chart showing slippage in basis points rising nonlinearly as order size increases from 100 to 10,000 shares against a simulated order book.
Slippage vs. Order Size. As order size increases, the execution price deviates further from the initial price, illustrating the nonlinearity of market impact when liquidity is consumed.

This example illustrates how slippage grows nonlinearly with order size. A 100-share order executes at the best ask price with zero slippage, while a 10,000-share order must consume multiple price levels, resulting in significant slippage. This nonlinearity is a fundamental feature of market impact that we will model more rigorously in the next section.