more typos
This commit is contained in:
@@ -33,11 +33,11 @@ Notebook numbering: **01** Data & market stats · **02** Factor diagnostics · *
|
|||||||
| Term | Linear-algebra meaning | Notebooks |
|
| Term | Linear-algebra meaning | Notebooks |
|
||||||
|------|------------------------|:---------:|
|
|------|------------------------|:---------:|
|
||||||
| **Return** | Fractional price change: $r_{t} = p_t / p_{t-1} - 1$ | 01 |
|
| **Return** | Fractional price change: $r_{t} = p_t / p_{t-1} - 1$ | 01 |
|
||||||
| **Return panel** $\mathbf{R}$ | Matrix $\mathbf{R}\in\mathbb{R}^{T\times N}$: months (rows) × stocks (columns); sparse (NaN where a stock didn't trade yet) | 01–06 |
|
| **Return panel** $\mathbf{R}$ | Matrix $\mathbf{R}\in\mathbb{R}^{T\times N}$: months (rows) $\times$ stocks (columns); sparse (NaN where a stock didn't trade yet) | 01–06 |
|
||||||
| **Cross-section** | A row $r_t \in \mathbb{R}^{N_t}$ — all stock returns at one date $t$ | 01, 02, 03 |
|
| **Cross-section** | A row $r_t \in \mathbb{R}^{N_t}$ — all stock returns at one date $t$ | 01, 02, 03 |
|
||||||
| **One stock's history** | A single column of $\mathbf{R}$ | 01 |
|
| **One stock's history** | A single column of $\mathbf{R}$ | 01 |
|
||||||
| **Universe** | The set of columns we're allowed to hold — here the S&P 500 large-caps | 01 |
|
| **Universe** | The set of columns we're allowed to hold — here the S&P 500 large-caps | 01 |
|
||||||
| **Sector** | A categorical partition of the column index set (Technology, Financials, …); one-hot form → indicator matrix $\mathbf{D}$ | 01, 03 |
|
| **Sector** | A categorical partition of the column index set (Technology, Financials, …); one-hot form $\rightarrow$ indicator matrix $\mathbf{D}$ | 01, 03 |
|
||||||
| **Dispersion** | Cross-sectional std dev — the spread of returns across a row of $\mathbf{R}$ | 01, 06 |
|
| **Dispersion** | Cross-sectional std dev — the spread of returns across a row of $\mathbf{R}$ | 01, 06 |
|
||||||
| **Equal-weight index** | Mean of a row: $\bar{r}_t = \tfrac{1}{N_t}\mathbf{1}^\top r_t$ (portfolio with $w_i = 1/N_t$) | 01, 04 |
|
| **Equal-weight index** | Mean of a row: $\bar{r}_t = \tfrac{1}{N_t}\mathbf{1}^\top r_t$ (portfolio with $w_i = 1/N_t$) | 01, 04 |
|
||||||
| **Survivorship bias** | Columns are a *non-random* sample: delisted/bankrupt names are missing, biasing returns upward | 01, 04 |
|
| **Survivorship bias** | Columns are a *non-random* sample: delisted/bankrupt names are missing, biasing returns upward | 01, 04 |
|
||||||
@@ -49,11 +49,11 @@ Notebook numbering: **01** Data & market stats · **02** Factor diagnostics · *
|
|||||||
| **Factor / signal** | Vector $f_t \in \mathbb{R}^{N_t}$ — one score per stock; we ask whether $f_t$ predicts $r_{t+1}$ | 02, 03, 04 |
|
| **Factor / signal** | Vector $f_t \in \mathbb{R}^{N_t}$ — one score per stock; we ask whether $f_t$ predicts $r_{t+1}$ | 02, 03, 04 |
|
||||||
| **Momentum (12-1)** | Trailing 12-month return skipping the last month — the headline signal; persistent drift | 02, 03, 04 |
|
| **Momentum (12-1)** | Trailing 12-month return skipping the last month — the headline signal; persistent drift | 02, 03, 04 |
|
||||||
| **Value / Quality / Low-vol** | Other candidate factor vectors (proxied by price data here) | 02, 03 |
|
| **Value / Quality / Low-vol** | Other candidate factor vectors (proxied by price data here) | 02, 03 |
|
||||||
| **Information coefficient (IC)** | Cosine similarity $\cos\theta = \dfrac{f_t^\top r_{t+1}}{\|f_t\|\,\|r_{t+1}\|}$ (ranks → Spearman IC) | 02, 03 |
|
| **Information coefficient (IC)** | Cosine similarity $\cos\theta = \dfrac{f_t^\top r_{t+1}}{\|f_t\|\ \|r_{t+1}\|}$ (ranks $\rightarrow$ Spearman IC) | 02, 03 |
|
||||||
| **Information ratio (IR)** | Mean IC / std(IC) — a signal-to-noise ratio for the factor | 02, 04 |
|
| **Information ratio (IR)** | Mean IC / std(IC) — a signal-to-noise ratio for the factor | 02, 04 |
|
||||||
| **Rank** | A permutation of $\{1,\dots,N\}$; makes factors comparable and robust to outliers | 02 |
|
| **Rank** | A permutation of $\{1,\dots,N\}$; makes factors comparable and robust to outliers | 02 |
|
||||||
| **Walk-forward validation** | Split the sample into sub-windows and test stability of IC / performance across regimes | 02, 04 |
|
| **Walk-forward validation** | Split the sample into sub-windows and test stability of IC / performance across regimes | 02, 04 |
|
||||||
| **Winsorize** | Clip extreme entries of $f$ at ±3σ to tame outliers | 03 |
|
| **Winsorize** | Clip extreme entries of $f$ at $\pm 3\sigma$ to tame outliers | 03 |
|
||||||
| **Z-score** | Center each cross-section to mean 0, std 1 | 03 |
|
| **Z-score** | Center each cross-section to mean 0, std 1 | 03 |
|
||||||
| **Sector neutralization** | Orthogonal projection $f_\perp = (I - P)f$ with $P = \mathbf{D}(\mathbf{D}^\top\mathbf{D})^{-1}\mathbf{D}^\top$ onto sector dummies | 03, 04 |
|
| **Sector neutralization** | Orthogonal projection $f_\perp = (I - P)f$ with $P = \mathbf{D}(\mathbf{D}^\top\mathbf{D})^{-1}\mathbf{D}^\top$ onto sector dummies | 03, 04 |
|
||||||
| **Composite signal** | A linear combination $c_t = \sum_k w_k f_{k,\perp}$ of neutralized factor vectors | 03 |
|
| **Composite signal** | A linear combination $c_t = \sum_k w_k f_{k,\perp}$ of neutralized factor vectors | 03 |
|
||||||
@@ -182,7 +182,7 @@ We pull the current S&P 500 constituents and download adjusted close prices. Thi
|
|||||||
Key findings:
|
Key findings:
|
||||||
* **Universe breadth** rises from ~385 to ~501 stocks over the sample — but the column set is fixed to *today's* constituents, so this counts how many of today's survivors had price data in month $t$. The matrix isn't truly "getting wider"; its survivor-only columns fill in over time.
|
* **Universe breadth** rises from ~385 to ~501 stocks over the sample — but the column set is fixed to *today's* constituents, so this counts how many of today's survivors had price data in month $t$. The matrix isn't truly "getting wider"; its survivor-only columns fill in over time.
|
||||||
* Average monthly cross-sectional return dispersion ~7.5% (the spread across a row of $\mathbf{R}$).
|
* Average monthly cross-sectional return dispersion ~7.5% (the spread across a row of $\mathbf{R}$).
|
||||||
* Equal-weight universe Sharpe (rf=0) ≈ 0.98 over the full period.
|
* Equal-weight universe Sharpe (rf=0) $\approx$ 0.98 over the full period.
|
||||||
* Sector composition spans 11 GICS sectors, dominated by Technology, Financials, and Healthcare.
|
* Sector composition spans 11 GICS sectors, dominated by Technology, Financials, and Healthcare.
|
||||||
|
|
||||||
### 2. Factor Analysis and Diagnostics
|
### 2. Factor Analysis and Diagnostics
|
||||||
@@ -214,9 +214,9 @@ Notebook 02 established momentum as the only factor with positive IC. This noteb
|
|||||||
3. **Sector-neutralizes** via orthogonal projection: $f_\perp = (\mathbf{I} - \mathbf{P})f$ with $\mathbf{P} = \mathbf{D}(\mathbf{D}^\top\mathbf{D})^{-1}\mathbf{D}^\top$
|
3. **Sector-neutralizes** via orthogonal projection: $f_\perp = (\mathbf{I} - \mathbf{P})f$ with $\mathbf{P} = \mathbf{D}(\mathbf{D}^\top\mathbf{D})^{-1}\mathbf{D}^\top$
|
||||||
4. **Compares** momentum-only vs. a 4-factor equal-weight composite
|
4. **Compares** momentum-only vs. a 4-factor equal-weight composite
|
||||||
|
|
||||||
Sector neutralization slightly improves momentum (IR 0.11 raw → 0.15 neutralized). Combining momentum with two negative-IC factors (value, lowvol) and one near-zero factor (quality) **dilutes** the signal — the 4-factor composite has negative IC. This is the linear-algebra intuition made empirical: adding vectors that point in the wrong direction moves the sum away from the target.
|
Sector neutralization slightly improves momentum (IR 0.11 raw $\rightarrow$ 0.15 neutralized). Combining momentum with two negative-IC factors (value, lowvol) and one near-zero factor (quality) **dilutes** the signal — the 4-factor composite has negative IC. This is the linear-algebra intuition made empirical: adding vectors that point in the wrong direction moves the sum away from the target.
|
||||||
|
|
||||||
**The headline signal is momentum-only, sector-neutralized** → saved as `momentum_signal.csv`. This is what the backtest trades.
|
**The headline signal is momentum-only, sector-neutralized** $\rightarrow$ saved as `momentum_signal.csv`. This is what the backtest trades.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@ A portfolio is a weight vector $w$. We form a top-decile long-only portfolio at
|
|||||||
| EW Universe | 15.9% | 0.95 | -47% | 1.27 |
|
| EW Universe | 15.9% | 0.95 | -47% | 1.27 |
|
||||||
| Long-Short (net) | -0.7% | -0.04 | -70% | — |
|
| Long-Short (net) | -0.7% | -0.04 | -70% | — |
|
||||||
|
|
||||||
| Portfolio | FF 4-factor alpha (ann.) | t-stat | MKT β | MOM β |
|
| Portfolio | FF 4-factor alpha (ann.) | t-stat | MKT $\beta$ | MOM $\beta$ |
|
||||||
|-----------|-------------------------:|-------:|------:|------:|
|
|-----------|-------------------------:|-------:|------:|------:|
|
||||||
| **Long-Only** | **+5.95%** | **3.95** | 1.19 | 0.25 |
|
| **Long-Only** | **+5.95%** | **3.95** | 1.19 | 0.25 |
|
||||||
| Long-Short | -2.95% | -1.41 | 0.15 | 0.91 |
|
| Long-Short | -2.95% | -1.41 | 0.15 | 0.91 |
|
||||||
@@ -295,7 +295,6 @@ The momentum long-only portfolio's risk is **~90.7% systematic** and **~9.3% idi
|
|||||||
* **No intraday execution modeling.** Transaction costs are a flat 5 bps. Real slippage depends on order size, liquidity, and volatility.
|
* **No intraday execution modeling.** Transaction costs are a flat 5 bps. Real slippage depends on order size, liquidity, and volatility.
|
||||||
* **Monthly rebalance only.** Daily/weekly rebalancing might capture different signals but would dramatically increase turnover.
|
* **Monthly rebalance only.** Daily/weekly rebalancing might capture different signals but would dramatically increase turnover.
|
||||||
* **Momentum crash risk.** The 2006–2011 walk-forward window shows negative active return, driven by the 2008–09 momentum crash. A crash-protection overlay (e.g. volatility scaling) would improve robustness.
|
* **Momentum crash risk.** The 2006–2011 walk-forward window shows negative active return, driven by the 2008–09 momentum crash. A crash-protection overlay (e.g. volatility scaling) would improve robustness.
|
||||||
* **Sector neutralization only.** A full Barra-style risk model would neutralize against more risk factors (size, beta, liquidity).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"| Term | Meaning |\n",
|
"| Term | Meaning |\n",
|
||||||
"|------|---------|\n",
|
"|------|---------|\n",
|
||||||
"| **Return** | Fractional price change: $r_{t} = p_t / p_{t-1} - 1$ |\n",
|
"| **Return** | Fractional price change: $r_{t} = p_t / p_{t-1} - 1$ |\n",
|
||||||
"| **Return panel** $\\mathbf{R}$ | The $T \\times N$ matrix of monthly returns — months (rows) × stocks (columns); the project's central object |\n",
|
"| **Return panel** $\\mathbf{R}$ | The $T \\times N$ matrix of monthly returns — months (rows) $\\times$ stocks (columns); the project's central object |\n",
|
||||||
"| **Cross-section** | A row of $\\mathbf{R}$ — all stocks at one date |\n",
|
"| **Cross-section** | A row of $\\mathbf{R}$ — all stocks at one date |\n",
|
||||||
"| **One stock's history** | A column of $\\mathbf{R}$ |\n",
|
"| **One stock's history** | A column of $\\mathbf{R}$ |\n",
|
||||||
"| **Universe** | The set of stocks (columns) we're allowed to hold — here the S&P 500 |\n",
|
"| **Universe** | The set of stocks (columns) we're allowed to hold — here the S&P 500 |\n",
|
||||||
|
|||||||
@@ -372,7 +372,7 @@
|
|||||||
"id": "5659b941",
|
"id": "5659b941",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Note that we added a sample size filter with `mask.sum() < 20`. The `mask` identifies stocks that have both a valid factor score and a valid forward return in a given month, and `mask.sum()` counts how many usable pairs you actually have. The `< 20` threshold prevents the code from computing a correlation on a tiny sample, which is statistically meaningless and numerically unstable (e.g., Spearman correlation on 2 stocks is always exactly ±1). If you don't gate this, early-history months, mass delistings, or data gaps inject garbage ±1.0 values into your IC time series, which then contaminate every downstream statistic like the mean IC, Information Ratio, and decay curves. Setting a floor of 20 filters out those degenerate months while retaining enough valid data to produce a reliable signal.\n",
|
"Note that we added a sample size filter with `mask.sum() < 20`. The `mask` identifies stocks that have both a valid factor score and a valid forward return in a given month, and `mask.sum()` counts how many usable pairs you actually have. The `< 20` threshold prevents the code from computing a correlation on a tiny sample, which is statistically meaningless and numerically unstable (e.g., Spearman correlation on 2 stocks is always exactly $\\pm$1). If you don't gate this, early-history months, mass delistings, or data gaps inject garbage $\\pm 1.0$ values into your IC time series, which then contaminate every downstream statistic like the mean IC, Information Ratio, and decay curves. Setting a floor of 20 filters out those degenerate months while retaining enough valid data to produce a reliable signal.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"We do this sort of masking throughout."
|
"We do this sort of masking throughout."
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"| Term | Meaning |\n",
|
"| Term | Meaning |\n",
|
||||||
"|------|---------|\n",
|
"|------|---------|\n",
|
||||||
"| **Winsorization** | Clipping extreme values at ±$k$ standard deviations — a soft truncation to limit outlier influence |\n",
|
"| **Winsorization** | Clipping extreme values at $\\pm k$ standard deviations — a soft truncation to limit outlier influence |\n",
|
||||||
"| **Z-scoring** | Centering to mean 0 and scaling to std 1, so each factor vector lives on the same scale |\n",
|
"| **Z-scoring** | Centering to mean 0 and scaling to std 1, so each factor vector lives on the same scale |\n",
|
||||||
"| **Neutralization** | Projecting out unwanted components (sector) — an orthogonal projection onto a complement subspace |\n",
|
"| **Neutralization** | Projecting out unwanted components (sector) — an orthogonal projection onto a complement subspace |\n",
|
||||||
"| **Composite signal** | A linear combination $c_t = \\sum_k w_k f_{k,\\perp}$ of neutralized factor vectors |\n",
|
"| **Composite signal** | A linear combination $c_t = \\sum_k w_k f_{k,\\perp}$ of neutralized factor vectors |\n",
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"## Winsorization and Z-Scoring\n",
|
"## Winsorization and Z-Scoring\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Winsorization** is a statistical technique for limiting the influence of extreme outliers in a dataset by capping them at a specified threshold rather than removing them entirely. Raw factor exposures can have extreme outliers — a stock that returned 500% in the trailing year, for instance. We **Winsorize** at ±3 standard deviations, so that we don't have to drop them.\n",
|
"**Winsorization** is a statistical technique for limiting the influence of extreme outliers in a dataset by capping them at a specified threshold rather than removing them entirely. Raw factor exposures can have extreme outliers — a stock that returned 500% in the trailing year, for instance. We **Winsorize** at $\\pm 3$ standard deviations, so that we don't have to drop them.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"After winsorization we **z-score** cross-sectionally: for each date $t$, the factor vector $f_t$ is transformed to\n",
|
"After winsorization we **z-score** cross-sectionally: for each date $t$, the factor vector $f_t$ is transformed to\n",
|
||||||
"$$\\tilde{f}_t = (f_t - \\bar{f}_t) / \\text{std}(f_t),$$\n",
|
"$$\\tilde{f}_t = (f_t - \\bar{f}_t) / \\text{std}(f_t),$$\n",
|
||||||
@@ -268,7 +268,7 @@
|
|||||||
"id": "9740141a",
|
"id": "9740141a",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Much like in Notebook 02, we note that we added a sample size filter with `mask.sum() < 30`. The `mask` identifies stocks that have both a valid factor score and a valid forward return in a given month, and `mask.sum()` counts how many usable pairs you actually have. The `< 30` threshold prevents the code from computing a correlation on a tiny sample, which is statistically meaningless and numerically unstable (e.g., Spearman correlation on 2 stocks is always exactly ±1). If you don't gate this, early-history months, mass delistings, or data gaps inject garbage ±1.0 values into your IC time series, which then contaminate every downstream statistic like the mean IC, Information Ratio, and decay curves. Setting a floor of 30 filters out those degenerate months while retaining enough valid data to produce a reliable signal.\n",
|
"Much like in Notebook 02, we note that we added a sample size filter with `mask.sum() < 30`. The `mask` identifies stocks that have both a valid factor score and a valid forward return in a given month, and `mask.sum()` counts how many usable pairs you actually have. The `< 30` threshold prevents the code from computing a correlation on a tiny sample, which is statistically meaningless and numerically unstable (e.g., Spearman correlation on 2 stocks is always exactly $\\pm$1). If you don't gate this, early-history months, mass delistings, or data gaps inject garbage $\\pm 1.0$ values into your IC time series, which then contaminate every downstream statistic like the mean IC, Information Ratio, and decay curves. Setting a floor of 30 filters out those degenerate months while retaining enough valid data to produce a reliable signal.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"We do this sort of masking throughout."
|
"We do this sort of masking throughout."
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -787,7 +787,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"### When Sortino > Sharpe\n",
|
"### When Sortino > Sharpe\n",
|
||||||
"\n",
|
"\n",
|
||||||
"A strategy with occasional large positive surprises will have Sortino noticeably higher than Sharpe. A strategy with symmetric volatility (gains and losses of similar magnitude) will have Sortino ≈ Sharpe. Big gap between them tells you the return distribution is positively skewed.\n",
|
"A strategy with occasional large positive surprises will have Sortino noticeably higher than Sharpe. A strategy with symmetric volatility (gains and losses of similar magnitude) will have Sortino $\\approx$ Sharpe. Big gap between them tells you the return distribution is positively skewed.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"---\n",
|
"---\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -808,8 +808,8 @@
|
|||||||
"$$V_t = \\prod_{s=1}^{t}(1 + r_{p,s}) = (1+r_1)(1+r_2)\\cdots(1+r_t)$$\n",
|
"$$V_t = \\prod_{s=1}^{t}(1 + r_{p,s}) = (1+r_1)(1+r_2)\\cdots(1+r_t)$$\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This is **compounding**. Start with $\\$1$. Each month, multiply by $(1 + r_s)$:\n",
|
"This is **compounding**. Start with $\\$1$. Each month, multiply by $(1 + r_s)$:\n",
|
||||||
"- Return $+5\\%$ → multiply by $1.05$\n",
|
"- Return $+5\\%$ $\\rightarrow$ multiply by $1.05$\n",
|
||||||
"- Return $-3\\%$ → multiply by $0.97$\n",
|
"- Return $-3\\%$ $\\rightarrow$ multiply by $0.97$\n",
|
||||||
"\n",
|
"\n",
|
||||||
"$V_t$ is the value of your $\\$1$ at the end of month $t$. If $V_t = 1.50$, your $\\$1$ has grown to $\\$1.50$.\n",
|
"$V_t$ is the value of your $\\$1$ at the end of month $t$. If $V_t = 1.50$, your $\\$1$ has grown to $\\$1.50$.\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|||||||
Reference in New Issue
Block a user