Index and ETF Arbitrage

Index and ETF arbitrage is the set of trades that keep an ETF's price glued to the value of the securities it holds, and keep index futures glued to the underlying basket. Unlike most "arbitrage," this one has a genuine enforcement mechanism — the ETF creation/redemption process — that lets a privileged set of players convert between the wrapper and its contents. That mechanism is what makes the law of one price hold here, and understanding it is the difference between seeing a tradeable dislocation and chasing a phantom one. It is the most structurally sound member of the classical arbitrage family, but its edges are tiny, latency-bound, and capital-intensive.

The creation-redemption mechanism

An ETF share is a claim on a basket of underlying securities. The price of the ETF on the exchange can drift away from the value of that basket, but Authorized Participants (APs) — large broker-dealers with a contract with the ETF issuer — can force convergence:

  • Creation: if the ETF trades at a premium to its basket, an AP buys the

underlying basket in the market, delivers it to the issuer in kind, and receives newly created ETF shares (in large blocks called creation units, e.g. 50,000 shares). It sells those ETF shares on the exchange at the premium. This buying of the basket and selling of the ETF pushes them together.

  • Redemption: if the ETF trades at a discount, the AP buys ETF shares cheap on

the exchange, delivers a creation unit to the issuer, and receives the underlying basket in kind, which it sells. Buying the ETF and selling the basket closes the gap.

The in-kind mechanism is the elegant part: it transfers the securities without forcing the fund to trade (so it is tax-efficient and does not move the underlying through the fund itself), and the threat of creation/redemption keeps the price in line even when no AP actually transacts. The arbitrage is the AP capturing the premium/discount minus its costs.

def etf_arb_signal(etf_price, basket_value, create_fee, redeem_fee,
                   basket_trade_cost, etf_trade_cost):
    premium = etf_price - basket_value
    # Net edge after the round-trip frictions of the mechanism
    if premium > 0:   # ETF rich -> buy basket, create, sell ETF
        net = premium - create_fee - basket_trade_cost - etf_trade_cost
        return ("create", net)
    else:             # ETF cheap -> buy ETF, redeem, sell basket
        net = -premium - redeem_fee - basket_trade_cost - etf_trade_cost
        return ("redeem", net)

NAV vs price: premium and discount

The ETF's NAV (net asset value) is the per-share value of its holdings, struck once a day at the close. Intraday, vendors publish an iNAV (indicative NAV) on a delayed, approximate basis. The ETF's traded price can sit at a premium or discount to either. The crucial professional distinction is why a premium exists:

  • Mechanical/transient premium: order flow temporarily pushes the ETF above its

basket; APs arbitrage it away within seconds to minutes. This is the tradeable kind.

  • Structural/fair premium: the ETF holds assets that are stale or hard to trade

— international equities whose home market is closed, illiquid bonds, anything where the "NAV" is itself an estimate. Here the ETF price is often the better price discovery and the "premium to NAV" is not an arbitrage at all; trading it gets you run over when the underlying reprices. Bond ETFs in March 2020 traded at large "discounts" that were really the ETF telling the truth while stale bond marks lagged.

ETF typeNAV reliability intradayPremium meaningArbable?
Large-cap domestic equityhigh (basket trades live)mostly mechanicalyes, tiny edge
International equity (closed market)low (stale prices)price discoverymostly no
Illiquid fixed incomelow (matrix-priced)liquidity signaldangerous
Leveraged / derivatives-basedmodel-dependentpath/cost artifactsrarely

Reading every premium as free money is the canonical beginner error; half of them are the market correctly disagreeing with a stale NAV.

Basket replication and tracking

To run the trade you must hold or trade the exact basket the issuer will accept for creation/redemption — the published creation basket, which is not always the full index (issuers may use a representative sample, and the basket changes on reconstitution and corporate actions). Replication choices:

  • Full replication: hold every name at index weight. Lowest tracking error,

highest transaction and rebalancing cost; only feasible for liquid indices.

  • Sampling/optimization: hold a subset that minimizes tracking error against the

index using a factor-risk model. Lower cost, residual basis risk — the source of the ETF's tracking error and your arb's slippage.

The arb's profitability hinges on executing the whole basket at prices close to the ones implied by the ETF quote, simultaneously. Any leg you cannot fill at the modeled price is basis risk that eats the spread. This is why execution quality — TWAP/VWAP and impact-aware algos — is not a footnote but the core competency: you are trading dozens to hundreds of names against one ETF on a few basis points of edge.

The futures-index basis

The cousin trade is index arbitrage between an index future and its cash basket. Fair value of the future is the cost-of-carry relationship:

F_fair = S * exp((r - q) * T)
       ≈ S + S*(r - q)*T        (for small T)
basis  = F_market - F_fair

where S is the index level, r the financing rate, q the dividend yield, T the time to expiry. If the future trades above F_fair net of costs, you sell the future and buy the basket (cash-and-carry); below, the reverse. The futures basics cover the carry model; the arb adds the requirement to actually replicate S with a tradeable basket.

import numpy as np

def futures_fair_value(index_level, r, div_yield, days, day_count=365):
    T = days / day_count
    return index_level * np.exp((r - div_yield) * T)

def index_basis_signal(fut_price, index_level, r, div_yield, days, cost):
    fair = futures_fair_value(index_level, r, div_yield, days)
    edge = fut_price - fair
    if abs(edge) <= cost:
        return ("no-trade", edge)
    return ("sell_fut_buy_cash" if edge > 0 else "buy_fut_sell_cash", edge)

The hard inputs are not the formula but r and q: the right financing rate is your actual marginal funding (repo, not a textbook rate), and the dividend forecast over T is uncertain — dividend surprises and the term repo rate are where the basis "mispricing" usually lives, and they are real risks, not free money. Around expiry the basis converges mechanically, and the roll between contracts is its own crowded, predictable flow.

Latency, cost, and capacity limits

Why isn't this infinite free money? Because the enforcers compete on speed and capital, and the spread is exactly the marginal enforcer's cost:

  • Latency. Mechanical ETF/futures dislocations live for milliseconds to seconds.

Capturing them is a low-latency game — co-location, fast basket pricing, simultaneous multi-leg execution. If you are not fast, the edge is gone before your basket order acknowledges, and you are left with one leg filled and directional risk.

  • Cost floor. Every round trip pays creation/redemption fees, the spread on every

basket name, ETF spread, financing, and slippage. The observed premium/discount band is bounded by these costs — the market sits inside the no-arbitrage band defined by the cheapest AP's frictions, so the spread you see is usually already smaller than your costs unless you are the low-cost operator.

  • Capacity and balance sheet. Creation units are large and APs warehouse inventory

and post margin; the trade consumes balance sheet and is gated by how much basket you can move without impact. Scale beyond the liquidity of the underlying and your own market impact erases the premium you were capturing.

Intraday fair value and corporate-action bookkeeping

The premium/discount signal is only as good as your real-time basket valuation, and this is harder than the formula suggests. The published iNAV updates on a delay and uses last-trade prices that may be stale for thinly traded constituents; a serious operation recomputes basket fair value continuously from live bid/ask midpoints of every name, not from the vendor iNAV. The gap between your basket mark and the lagged iNAV is itself a signal — and a trap, because trading against a stale iNAV that your own faster mark already disagrees with is how you end up buying a "discount" that does not exist.

def live_basket_value(weights, mids, fx=None):
    # Mark the creation basket off live midpoints; convert any ADR/foreign legs
    val = 0.0
    for name, w in weights.items():
        px = mids[name]
        if fx is not None and name in fx:
            px *= fx[name]      # foreign-listed legs need live FX
        val += w * px
    return val

Corporate actions are where the bookkeeping breaks down for the unprepared. Dividends (the ETF accrues them between distribution dates, so its fair value includes accrued income the basket of shares no longer reflects after they go ex), splits, spinoffs, index reconstitutions, and cash-in-lieu components of the creation basket all shift the relationship between the ETF and a naive basket mark. Around index reconstitution dates the creation basket changes and flows are enormous and predictable, which both creates opportunity and crowds it. The accrued-dividend adjustment alone explains a chunk of the "persistent small premium" on dividend-paying equity ETFs that looks like free money and is not.

AdjustmentEffect on fair valueFrequency
Accrued dividendsETF richer than ex-div basketcontinuous
Reconstitutionbasket composition jumpsscheduled
Cash-in-lieubasket includes cash legper creation
Foreign FXbasket needs live FX markscontinuous

Honest limits and where it fails live

This is the most genuine arbitrage on the list and therefore the least profitable for anyone without infrastructure: the convergence is real and enforced, which means the easy edge is competed to the cost floor. The dangerous failures are the structural premia masquerading as mechanical ones — illiquid or closed-market underlyings where the NAV is stale and the "arbitrage" is you taking the wrong side of price discovery. The 2020 bond-ETF episode is the cautionary tale: APs stopped arbitraging discounts because the in-kind basket had become untradeable, so the mechanism that "guarantees" convergence simply switched off when liquidity vanished — exactly when you would have wanted it most. The lesson for systematic traders: model the creation/redemption frictions and the AP's incentive, not just the price gap, treat every premium as guilty until proven mechanical, and never assume the convergence engine runs in a crisis. The edge that survives is operational — speed, low financing, clean multi-leg execution — not the formula.

#index arbitrage #ETF arbitrage #creation redemption #basket #NAV