σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoadmapsSkills
Ctrl K
AO
+1.2k Learners
LoginJoin ↗
RoadmapsSkills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoadmapsSkills
Ctrl K
AO
+1.2k Learners
LoginJoin ↗
RoadmapsSkills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Optimization skill›Module 5 · Optimization in practice›Topic 5.2·~1 hr 40 minAdvanced

Capstone: constrained portfolio optimization with turnover and cost limits

Skill positionModule 5 of 5 · Topic 2 of 2
5.2 Capstone: constrained portfolio optimization with turnover and cost limits
—Lab score— / 100Total XP—Streak—

From the pieces to a working optimizer

A minimum-variance portfolio on paper has no rules. A real mandate is long-only, fully invested and pays to trade, and the only way to see what those rules do is to build the optimizer yourself and test it on days it never saw. This capstone uses three ideas from the skill: gradient descent for the loop, a projection for the long-only budget rule and an L1 limit on the trades. Only NumPy is needed, and no library solver is allowed.

wₖ₊₁=Π(wₖ-η·2Σwₖ), η=1/(2λₘₐₓ(Σ))

Projected gradient descent takes an ordinary gradient step on the variance wᵀΣw, whose gradient is 2Σw, and then maps the result back to the nearest long-only, fully invested portfolio with the projection Π. The step 1/L, with L=2λₘₐₓ(Σ) the largest Hessian eigenvalue, is always stable. The projection onto {w≥0, Σw=1} has an exact answer: sort the vector in decreasing order, take cumulative sums minus one, find the last position ρ where the sorted value still exceeds its cumulative sum divided by k, set θ to that cumulative sum over ρ+1, and return max(v-θ,0). Every weight is shifted by the same amount and the ones that would go negative are cut at zero.

w=w₀+α(wₜ-w₀), α=min(1, τ/(‖wₜ-w₀‖₁)), c ‖w-w₀‖₁

Turnover is the L1 norm of the trade, ‖w-w₀‖₁. To keep it below a limit τ while staying feasible, move only the fraction α of the way from the current portfolio w₀ to the optimizer's target wₜ. A point on the straight line between two long-only, fully invested portfolios is again long-only and fully invested, and the L1 norm grows linearly along the line, so the trade is exactly min(gap,τ). Each rebalance then costs c times its turnover, which the backtest subtracts from the first day of the holding block. Weights for a block may use only the days before it, and the result to report is the volatility and return of the joined, net, out-of-sample days.

What the real data saysFor twelve large US stocks since 2010, with a 126-day window re-estimated every 42 days, a cost of 10 basis points and 4,058 out-of-sample days, the long-only minimum-variance portfolio has a volatility of about 13.4% a year, a return of about 13.8% and a turnover of about 0.36 per rebalance. Limiting the turnover to 0.2 gives a volatility of about 13.6%, a return of about 14.0% and a turnover of 0.20: slightly more risk, but fewer trades and no loss in net return. Equal weights have a volatility of about 18.4%, a return of about 21.4% and no trading. They earn more only because these twelve survivors, above all Apple, Amazon and Nvidia, did so well.
  • Projected gradient descent: gradient step 2Σw with step 1/L, then the projection onto the simplex.
  • Turnover limit: move the fraction α=min(1,τ/gap) along the line to the target; the portfolio stays feasible.
  • Honest backtest: estimate on the last window days, hold for step days, subtract the costs and report the joined out-of-sample numbers.
Two simplifications to rememberThe backtest ignores weight drift inside a block (the weights are held fixed) and charges a flat cost per unit of turnover, whereas real impact grows with the size traded and with illiquidity. Both make the numbers a little too friendly. Treat the exercise as a clean model of the trade-off between risk, turnover and cost, not as a forecast of live performance.

Lab · what's graded

  • Projection onto the simplex20 pts
  • Projected gradient descent25 pts
  • A turnover limit15 pts
  • A rolling backtest with costs25 pts
  • Comparing the policies15 pts
Explorer · lab-op-11
▾ lab-op-11
▾ data
…
bash · in-browser
learner@quantcraft:~/lab-op-11$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-op-11 goes back to the starter files and the terminal is cleared. Your current solution will be lost — this can't be undone.

Will be reset
  • main.py → starter code
  • Terminal history and test output
  • Unsubmitted changes
Will be kept
  • Best lab score
  • Your XP and streak
  • Lecture progress and notes

Log in to run your code.

Every lecture is free to read. Create an account or log in to run code, run tests and submit this lab.

  • In-browser IDE with a bash terminal — nothing to install
  • Instant grading, XP and your place on the skill
Create an accountLog in
OR
Continue with GitHub