Project: Build the Single-Period Optimizer
Nothing new to learn today. This is the assembly lesson: Lessons 0001–0018 become one working optimizer in ≈40 lines of CVXPY, written by you, on your machine. The twist that makes it a real lesson: you don't need an answer key. KKT is a test suite — this page includes a checker that certifies your solution from the optimality conditions alone.
The One-Step Skill
Translate a full institutional problem statement — objective with alpha, factor risk, and trading costs; budget, box, and exposure constraints — into running solver code, and verify your own output by checking primal feasibility, dual signs, complementary slackness, and stationarity. This is the skill every “implement the optimizer from the paper” task reduces to.
The Spec
Everything below is a lesson you've had. The margin notes say which.
maximize αᵀw - γ( eᵀΣ_F e + Σ d_i²w_i² ) - κ‖w - w_prev‖₁
| | |
0001 0017 (e = Fᵀw) 0012/0015
subject to 1ᵀw = 1 budget (0003)
0 ≤ w ≤ 0.40 long-only + caps (0003/0008)
βᵀw ≤ 0.80 exposure wall (0016)
Stage-1 data (four names; the checker below is wired to these exact numbers):
alpha = [0.09, 0.06, 0.04, 0.03] γ = 5 beta = [1.5, 1.0, 0.5, 0.0 ] σ_f = 0.20 (so Σ_F = 0.04, k = 1) idio vol = [0.10, 0.08, 0.06, 0.02] w_prev = [0.25, 0.25, 0.25, 0.25] Σ = 0.04·ββᵀ + diag(idio vol²) κ = 0 in stage 1
The build, in stages
stage 1 core QP: alpha + factor risk + all three constraints, κ = 0
→ solve, print w*, print every constraint's .dual_value
stage 2 turnover: add κ = 0.002, then κ = 0.02
→ use cp.norm(w - w_prev, 1); watch the no-trade behavior appear
stage 3 duals: check the wall's λ against the after-toll ranking (0016);
verify slack constraints report ≈0 (0004)
stage 4 stress: sweep the wall 0.5 → 1.1, plot λ(wall) — you built
Lesson 0016's lab for real; sweep κ and find each name's parking zone
Skeleton (the holes are the project)
import cvxpy as cp
import numpy as np
alpha = np.array([0.09, 0.06, 0.04, 0.03])
beta = np.array([1.5, 1.0, 0.5, 0.0])
d = np.array([0.10, 0.08, 0.06, 0.02])
w_prev = np.full(4, 0.25)
gamma, sf2, kappa = 5.0, 0.04, 0.0
w = cp.Variable(4)
e = beta @ w # exposure (k = 1)
risk = sf2 * cp.square(e) + ... # TODO: idio term (0017)
cost = ... # TODO: kappa * L1 turnover (0015)
budget = ... # TODO
box = [...] # TODO: floors and caps
wall = ... # TODO: beta exposure ≤ 0.80
prob = cp.Problem(cp.Maximize(alpha @ w - gamma * risk - cost),
[budget, *box, wall])
prob.solve()
print(w.value, wall.dual_value, budget.dual_value)
Lab: The KKT Test Suite
Why trust the checker more than an answer key? Because it's the same certificate the solver itself uses (Lesson 0004): any point passing all four families of checks is provably the optimum of this convex problem — local is global. Solve stage 1, then paste w.value and every .dual_value below (duals of slack constraints are 0). A FAIL names the exact constraint or asset to debug — read it like a failing unit test. If stationarity fails on every asset by the same amount, your budget dual's sign convention differs from mine; the checker tries both and tells you.
Definition of Done
You're finished when you can say yes to all five: (1) stage 1 passes the full KKT suite above; (2) with κ = 0.02, at least one name sits exactly at its w_prev — and you can say which and why from the push-vs-fee rule (0012); (3) your wall-dual sweep (stage 4) is a step function, and you can name the active-set change at each step (0010); (4) the wall's dual_value matches the after-toll-alpha breakeven within tolerance (0016); (5) you tried to Maximize a book with +κ‖·‖₁ once, got the DCP error, and smiled (0015).
Retrieval Practice
Your stage-1 solution has
Why does passing all KKT checks prove optimality here, with no answer key?
With κ = 0.02, a name sits exactly at w_prev,i = 0.25. What does stationarity look like there?
Primary Source
The CVXPY quadratic program example and the dual variables guide are the two pages open while you build. The MOSEK Portfolio Cookbook's Markowitz chapter is the same build with production seasoning. Cheat sheet: project spec card — print it, build against it.
Questions?
Ask your agent anything unclear — good prompts: “my stationarity residual is off by exactly the same 0.011 on all four assets — what did I do,” “why is my wall dual zero at κ = 0.02 when it was 0.04 at κ = 0,” or “generate three more stress datasets with known active sets for my stage 4.”