σμ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
  • 日本語
  • 中文
SciPy skill›Module 1 · Fitting and finding›Topic 1.5·~50 minIntermediate

Constrained portfolios with minimize

Skill positionModule 1 of 3 · Topic 5 of 8
1.5 Constrained portfolios with minimize
—Lab score— / 100Total XP—Streak—

An optimiser is a function plus rules

scipy.optimize.minimize(fun, x0, method='SLSQP', bounds=..., constraints=...) finds the vector that makes fun smallest. You give it three kinds of information. The objective fun(w) returns a number to minimise: for a minimum-variance portfolio it is w @ cov @ w, and to maximise something you minimise its negative. The bounds are a list of (low, high) pairs, one per weight: (0, cap) means no shorting and no position above the cap. The constraints are dictionaries: {'type': 'eq', 'fun': lambda w: w.sum() - 1} forces the weights to add up to one, because an eq function must equal zero, while an ineq function must stay at or above zero. The starting point x0 matters too: equal weights is a sensible, feasible start.

Two details decide whether the answer is right. First, scale: daily variances are numbers like 0.0001, and SLSQP stops when the objective changes by less than its tolerance ftol (default 1e-6), so with raw daily numbers it can stop at the starting point without moving. Annualise the inputs (times 252) and pass options={'ftol': 1e-12, 'maxiter': 500}, and always check result.success and that the weights obey the rules. Second, the formulation: maximising the Sharpe ratio is a ratio, so minimise -(w @ mu) / sqrt(w @ cov @ w); risk parity asks for equal risk shares wᵢ(Σw)ᵢ/ wᵀΣw, so minimise the squared gaps to 1/n; and an efficient frontier is one minimum-variance problem per target return, with a second eq constraint w @ mu - target.

What the real data saysTake ten stocks, the utility DUK and the gold ETF GLD over the last 2,500 days, with at most 25% in any asset. Equal weights have a volatility of 14.6%. The minimum-variance portfolio brings it to 11.9% by holding 25% gold, 18% JNJ and 14% KO, and none of AAPL or HD. The maximum-Sharpe portfolio earns 21.3% a year at 14.3% volatility, a Sharpe ratio of 1.48, by leaning on gold, WMT and CAT: a number that reflects the past ten years, not the next ten. Risk parity holds between 5.8% and 19.6% in each asset, with gold the largest, and every asset carries 8.3% of the risk.
  • Scale and tolerance: annualise the inputs and tighten ftol, or SLSQP may stop where it started.
  • Check the answer: the weights must add up to one and obey the bounds; look at result.success.
  • Same tool, four problems: minimum variance, a negative Sharpe ratio, equal risk shares and one problem per target return are all minimize calls with different objectives and constraints.

Lab · what's graded

  • Annual inputs8 pts
  • Return and risk of a portfolio8 pts
  • Minimum variance with a cap18 pts
  • Maximum Sharpe ratio18 pts
  • Risk contributions10 pts
  • Risk parity16 pts
  • A frontier point by point10 pts
  • Three portfolios12 pts
Explorer · lab-sp-14
▾ lab-sp-14
▾ data
…
bash · in-browser
learner@quantcraft:~/lab-sp-14$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-sp-14 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