Modeling slippage and transaction costs

The direct answer to "how much does live execution differ from backtest numbers" — the single biggest gap between a good-looking backtest and a disappointing live strategy is usually here, not in the signal logic.

Every real cost component for Indian equity/F&O

STT was hiked effective April 1, 2026 (this is now in effect, not a future change): futures STT rose from 0.02% to 0.05% (a 150% increase), options STT from 0.10% to 0.15% on premium (and 0.125% to 0.15% on exercise) — part of a deliberate push to curb retail F&O speculation. This directly cuts into thin-edge intraday/options strategies more than it did before — re-run chapter 82's backtests with these updated rates before trusting any pre-2026 performance number.

def compute_transaction_costs(turnover: float, segment: str, is_buy: bool) -> dict:
    """Rates as of April 2026 (post-hike) — verify current values before relying on this long-term,
    these are exactly the numbers that just changed once and will change again."""
    brokerage = min(20, turnover * 0.0003)   # many discount brokers: flat fee or 0.03%, whichever lower
    stt_rates = {
        "equity_delivery": 0.001,     # unchanged in the 2026 hike — delivery STT applies on both buy and sell
        "equity_intraday": 0.00025,    # sell side only, unchanged
        "futures": 0.0005,              # hiked from 0.0002 (0.02% -> 0.05%), effective April 1, 2026
        "options_premium": 0.0015,       # hiked from 0.0010 (0.10% -> 0.15%), effective April 1, 2026
    }
    stt = turnover * stt_rates.get(segment, 0.0005)
    exchange_txn_charge = turnover * 0.0000345   # NSE, approx
    gst = (brokerage + exchange_txn_charge) * 0.18
    sebi_charges = turnover * 0.0000010
    stamp_duty = turnover * 0.00003 if is_buy else 0   # stamp duty only on buy side

    total = brokerage + stt + exchange_txn_charge + gst + sebi_charges + stamp_duty
    return {"brokerage": brokerage, "stt": stt, "gst": gst, "total": total}

These exact rates change (STT rates, exchange charges, GST are all subject to regulatory revision) — treat this function as a template to keep updated from your broker's current charges page, not a permanent constant.

Slippage — the harder, more important cost to model honestly

Unlike fixed statutory charges, slippage depends on your order type, instrument liquidity, and order size relative to depth (chapter 26).

def model_slippage(order_type: str, depth: dict, qty: int) -> float:
    """Returns estimated slippage in price terms (not percentage)."""
    if order_type == "LIMIT":
        return 0.0   # assumes limit fully fills at your price — optimistic if size > depth
    # MARKET order: walk the book (chapter 26's estimate_market_buy_cost pattern)
    best_price = depth["sell"][0]["price"]
    avg_fill_price = estimate_market_buy_cost(depth, qty)
    return avg_fill_price - best_price

Backtest slippage assumption should come from real data, not a guess

def calibrate_slippage_from_live_trades(order_log: list[dict]) -> float:
    """order_log: your own recorded {intended_price, filled_price} pairs from actual live/paper trades."""
    slippages = [abs(o["filled_price"] - o["intended_price"]) / o["intended_price"] for o in order_log]
    return sum(slippages) / len(slippages) if slippages else 0.001   # fallback default

Run the strategy in paper mode (chapter 87) or with small real size first, log actual slippage experienced, and feed that measured number back into your backtest assumptions — don't backtest with a slippage assumption pulled from nowhere.

Why this single modeling choice can flip a strategy from profitable to not

A high-frequency mean-reversion strategy with a small per-trade edge (say, 0.3% expected gain per trade) can be entirely consumed by realistic costs (0.1-0.2% round-trip in fees plus slippage) — a backtest run with zero-cost assumptions will look robustly profitable while the live version barely breaks even or loses. Always re-run your backtest with realistic costs (chapter 82's fees= and slippage= parameters) before trusting any performance number.

Next: 087 — Paper trading mode