σμ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ᵀμ = μ*∫Σ∂∞λ
σμ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 AcademySkills
Ctrl K
AO
+1.2k Learners
LoginJoin ↗
Skills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python skill›Module 3 · Probability & Monte Carlo simulation›Topic 3.5·~55 minIntermediate

Linear regression (OLS)

Skill positionModule 3 of 11 · Topic 5 of 12
3.5 Linear regression (OLS)
—Lab score— / 100Total XP—Streak—

Explaining one return with another

A stock rarely moves alone: when the market rises it usually rises too. Linear regression quantifies that link by fitting a straight line y = alpha + beta * x through the pairs of returns (x: the market, y: the stock). Ordinary least squares (OLS) chooses the line that makes the sum of the squared vertical gaps, the residuals, as small as possible. The result has a closed form: the slope beta is the covariance of x and y divided by the variance of x, and the intercept alpha makes the line pass through the point of means.

beta = sum((x - mean_x) * (y - mean_y)) / sum((x - mean_x)^2) alpha = mean_y - beta * mean_x
import numpy as np

market = np.array([0.010, -0.005, 0.004, 0.012, -0.008, 0.003, -0.002, 0.007, 0.001, -0.004])
asset  = np.array([0.013, -0.004, 0.007, 0.016, -0.011, 0.004, -0.001, 0.011, 0.002, -0.007])

dx = market - market.mean()                      # deviations of x from its mean
beta = (dx * (asset - asset.mean())).sum() / (dx ** 2).sum()
alpha = asset.mean() - beta * market.mean()
print(round(beta, 4), round(alpha, 5))           # 1.3271 0.00061   the asset moves 1.33 times as much as the market

Residuals and R squared

A residual is what the line fails to explain for one observation: y - (alpha + beta * x). OLS residuals always add up to zero and are uncorrelated with x, which is a handy check on your own code. R squared says how much of the variation of y the line explains: 1 - sum(residuals²) / sum((y - mean_y)²). It runs from 0 (the line is no better than the average) to 1 (all the points lie on the line), and in a simple regression it equals the squared correlation of x and y.

residuals = asset - (alpha + beta * market)
print(abs(residuals.sum()) < 1e-12, abs((residuals * market).sum()) < 1e-12)   # True True   the OLS fingerprints

ss_res = (residuals ** 2).sum()
ss_tot = ((asset - asset.mean()) ** 2).sum()
print(round(1 - ss_res / ss_tot, 4))                  # 0.9785
print(round(np.corrcoef(market, asset)[0, 1] ** 2, 4))   # 0.9785   the squared correlation

CAPM: beta and alpha

In finance the regression has a name. Beta is the sensitivity to the market: a beta of 1.3 means the stock tends to move 30% more than the market, up or down. Alpha is the average return left over once that market exposure is accounted for, and it is what a manager claims as skill. To keep the risk-free rate out of the picture, the CAPM regression uses excess returns: the return minus the risk-free rate, for both the asset and the market. A strategy with alpha near zero is just market exposure in disguise.

risk_free = 0.0001                                 # risk-free return of one day
x = market - risk_free                             # excess returns of the market
y = asset - risk_free                              # excess returns of the asset

beta = ((x - x.mean()) * (y - y.mean())).sum() / ((x - x.mean()) ** 2).sum()
alpha = y.mean() - beta * x.mean()
print(round(beta, 4), round(alpha, 6))             # 1.3271 0.000644   a daily alpha of 0.064%, on 10 days of data
# Points exactly on y = 1 + 2x: the fit recovers the line
x = np.array([1.0, 2.0, 3.0, 4.0])
y = 1 + 2 * x
dx = x - x.mean()
slope = (dx * (y - y.mean())).sum() / (dx ** 2).sum()
print(y.mean() - slope * x.mean(), slope)      # 1.0 2.0
A line is not a causeA regression describes how two series moved together in the sample; it does not prove one drives the other, and the numbers are estimates with their own uncertainty. With 10 days the beta is rough and the alpha is lost in noise. Beta also changes with time and with the market's regime, so re-estimate it on a rolling window rather than trusting one number forever.
  • OLS minimises the squared residuals: beta = cov(x, y) / var(x) (sums of centred products) and alpha = mean_y - beta * mean_x.
  • Residuals y - (alpha + beta * x) add up to zero; R squared 1 - ss_res / ss_tot is the share of variance explained.
  • CAPM: regress the asset's excess returns on the market's excess returns; beta is market exposure, alpha what is left.

Next up: volatility, measuring and forecasting how much returns fluctuate.

Lab · what's graded

  • Fit the line through the points with ols_fit25 pts
  • Measure what the line misses with residuals25 pts
  • Score the fit with r_squared25 pts
  • Split an asset into market exposure and skill with capm_alpha_beta25 pts
Explorer · lab-58-1
▾ lab-58-1
…
bash · in-browser
learner@quantcraft:~/lab-58-1$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-58-1 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