Lesson 0012

The Turnover Penalty and the No-Trade Zone

Add a per-unit trading fee to the objective and something remarkable happens: the optimizer develops patience. A whole band of holdings becomes “good enough to keep” — and the width of that band is exactly the fee divided by the conviction.

The One-Step Skill

Given a frictionless target, a previous holding, and a proportional trading cost κ, predict whether the optimizer trades at all — and if it trades, where it stops (spoiler: short of the frictionless target).

This is the first lesson where the portfolio remembers yesterday. Until now every problem was solved from scratch; w_prev is the hinge on which all multiperiod optimization — your long-term target — will turn.

The Setup

Take the running two-asset objective from Lesson 0007 and add a proportional cost on the trade |w - w_prev|:

frictionless:  f0(w) = 0.15 w² - 0.30 w + 0.08
               f0'(w) = 0.30 w - 0.30
               frictionless target: w = 1.00

with costs:    minimize  f0(w) + κ |w - w_prev|

Lesson 0011 licensed this: f0 is convex, κ|w - w_prev| is the convex kink, and their sum is convex. One global optimum, no traps — but the kink at w_prev changes where that optimum sits.

The Picture First: A Kink Can Hold a Ball

Picture the total cost curve. Away from w_prev it is the old bowl, tilted up by the fee. At w_prev there is a crease — a V pressed into the bowl.

Now roll the ball. On a smooth curve, the ball only rests where the slope is exactly zero. But a crease is different: a crease can hold a ball on a sloping hillside, the way a gutter holds a marble on a tilted driveway. As long as the hillside doesn't push harder than the crease is deep, the ball stays put.

Memory hook: smooth optima need zero slope; kinked optima only need the push to be smaller than the fee. Small edge, no trade.

The Theory: Optimality at a Kink

At the kink, the penalty has no single slope. Just left of w_prev it slopes , just right it slopes — and the honest statement is that the kink carries the whole range of slopes in between. That range is called the subdifferential, and the optimality condition generalizes from “slope equals zero” to “zero is inside the slope range”:

smooth optimality:   f'(w) = 0

kinked optimality:   0  ∈  f0'(w_prev) + κ · [-1, +1]

equivalently:        hold  ⇔  |f0'(w_prev)| <= κ
                     (the kink absorbs any push up to the fee)

When the push is too strong for the kink, the optimizer trades — but only until the remaining push equals the fee. Trading further would cost more in fees than it gains in objective:

if f0'(w_prev) < -κ  (strong pull upward):
    trade to where  f0'(w) = -κ
    0.30 w - 0.30 = -κ
    w* = 1 - κ/0.30        ← stops SHORT of the target 1.00

no-trade zone:  every w_prev with |f0'(w_prev)| <= κ
             =  [ 1 - κ/0.30 ,  1 + κ/0.30 ]

Two facts fall out, both worth saying in an interview. First, proportional costs shrink trades toward zero: you never quite reach the frictionless target. Second, the no-trade zone widens with the fee κ and narrows with conviction (the curvature 0.30): expensive trading plus a shallow objective means wide patience.

Lab: Watch the No-Trade Zone Breathe

The dashed grey curve is the frictionless bowl; the solid curve is with the fee, creased at w_prev. Two experiments: (1) fix κ and slide w_prev across the shaded zone boundary — watch the decision snap from trade to hold; (2) fix w_prev at 40% and raise κ from zero — watch the solution walk back from 100% toward w_prev, and the zone widen until it swallows the holding.

w_prev-
Fee κ-
Solution-
Trade size-
Decision-
No-trade zone-

Check the formula live: with κ = 0.06 the zone should start at 1 - 0.06/0.30 = 80%. Slide w_prev to 79% (trade) and 81% (hold) to feel the boundary.

Why Real Portfolios Love This

Turnover control for free

Nobody writes “do not fidget” as a constraint. The L1 penalty produces calm, sparse trading automatically — small alpha changes inside the zone cause zero trades.

Noise immunity

Return forecasts are noisy. A frictionless optimizer chases every forecast wiggle; the no-trade zone acts as a filter that only lets conviction-sized signals through.

Why L1, not L2

A quadratic (L2) trade penalty is smooth — no kink, so every wiggle still causes a small trade. Only the kink produces exact zeros. Same reason lasso gives sparse regressions.

The multiperiod door

Once trades cost money, when you trade matters, and today's position constrains tomorrow's. That coupling across time is precisely what Boyd et al.'s multiperiod paper optimizes.

Retrieval Practice

With κ = 0.06, the pull at w_prev is |f0'(w_prev)| = 0.03. The optimal action is?

The fee κ doubles. The no-trade zone does what?

When the optimizer does trade, where does it stop?

Portfolio Reading

In papers, this term appears as κ'|w - w_prev| or ||Λ(w - w_prev)||_1 inside the objective, usually named transaction cost or trading aversion. When you see it, you now know three things without reading further: trades will be sparse (many exact zeros), executed trades will fall short of frictionless targets, and there is an implicit no-trade region even though no constraint says so. If the paper uses a quadratic trade penalty instead, expect dense small trades and no exact zeros — that is a modeling choice about market impact, not a typo.

Primary Source

Sections 2.3 and 4.2 of Boyd et al., “Multi-Period Trading via Convex Optimization” give the professional version of this cost model. The MOSEK cookbook's transaction cost chapter shows the same idea in several solver-ready variants. Keep the turnover penalty reference at hand, and revisit the convexity cheat sheet for why the kink is legal.

Questions?

Ask your agent anything unclear — good prompts: “derive the no-trade zone for a general quadratic,” “show me the 2-asset version where only one asset is in its zone,” or “what changes with different buy and sell fees?”