σμ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
  • 日本語
  • 中文
Hidden Markov Models skill›Module 3 · Regimes in markets›Topic 3.4·~1 hr 40 minAdvanced

Capstone: a bull bear and crisis regime detector on index data

Skill positionModule 3 of 3 · Topic 4 of 4
3.4 Capstone: a bull bear and crisis regime detector on index data
—Lab score— / 100Total XP—Streak—

A regime detector you build yourself

In this capstone you build a hidden Markov model from nothing but NumPy and run it on twenty years of SPY. The model says that each day the market is in one of three hidden regimes, calm, normal or stormy, that you never see. Each regime has its own typical return and volatility, and tomorrow's regime depends only on today's through a transition matrix A. The forward pass turns the returns into a chance for each regime on every day. A backward pass adds what the later days say. Viterbi finds the single most likely path. Baum-Welch repeats these steps to learn the regime numbers from the data.

αₜ=((αₜ₋₁A)·Bₜ)/cₜ, βₜ=(A (Bₜ₊₁·βₜ₊₁))/(cₜ₊₁), γₜ=(αₜ·βₜ)/(Σ(αₜ·βₜ)), log L=Σₜlog cₜ

Everything is scaled. Dividing each day's forward numbers by their sum cₜ keeps them from shrinking to zero over thousands of days, and the sum of the log cₜ is exactly the log-likelihood. Viterbi works with logs for the same reason. In the Baum-Welch step, the smoothed chances γ act as weights: each regime's mean and volatility are the weighted mean and weighted spread of the returns, and the transition counts come from the chance of moving from i to j on every day. Each round can only raise the log-likelihood, which is a good test of your code. In the last function you use the fitted regimes to trade: one signal predicts the crisis chance from the day before (honest), the other reads it from the smoothed chances (look-ahead).

What the real data saysOn the 5,404 SPY returns since 2005, forty rounds from a rough start find three regimes with annual volatilities of about 8%, 19% and 51%. Their annual means are about +30%, -1% and -73%, and each regime is very sticky: it stays put on about 96% to 97% of days. The log-likelihood climbs from about 17,544 to 17,803. Along the Viterbi path the market spends about 52% of days in the calm regime, 41% in the normal one and 6% in the crisis one. Staying invested only while the crisis chance is below one half gives an annual Sharpe ratio of 0.52 for buy and hold, 0.66 for the honest filtered signal and 1.12 for the smoothed one. That last gap is the look-ahead trap in action.
  • Scale every step: divide by the day's sum and add up the logs, or thousands of days underflow to zero.
  • Check with brute force: on a few days you can list every state path and compare. The log-likelihood must never fall from one round to the next.
  • Honest signals only: predict tomorrow from today's filtered chances. Smoothed chances flatter the back-test.
Simplifications to rememberReturns inside a regime are treated as normal and independent, which ignores fat tails. The number of regimes is fixed at three. The model is fitted once on the whole sample, so even the honest filtered signal uses numbers that were learned from the future. A strict test refits on past data only, and adds trading costs. The thresholds of one half are not tuned.

Lab · what's graded

  • Emission probabilities10 pts
  • The forward algorithm20 pts
  • The backward algorithm10 pts
  • Smoothing5 pts
  • Viterbi decoding15 pts
  • Baum-Welch fitting25 pts
  • The regime study15 pts
Explorer · lab-hm-10
▾ lab-hm-10
▾ data
…
bash · in-browser
learner@quantcraft:~/lab-hm-10$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-hm-10 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