typos
This commit is contained in:
@@ -256,7 +256,7 @@ The long-only portfolio beats the EW universe by **3.6% per year**, though that
|
|||||||
|
|
||||||
Portfolio risk is the quadratic form $w^\top \Sigma w$. This notebook decomposes it using the eigendecomposition of $\Sigma$.
|
Portfolio risk is the quadratic form $w^\top \Sigma w$. This notebook decomposes it using the eigendecomposition of $\Sigma$.
|
||||||
|
|
||||||
* **PCA from scratch** as eigendecomposition of the sample covariance, computed via SVD of the centered return matrix (a balanced panel of 394 stocks over 240 months).
|
* **PCA via scikit-learn** (`PCA` from `sklearn.decomposition`), fit on the centered return matrix (a balanced panel of 394 stocks over 240 months). The linear-algebra content is the same eigendecomposition $\Sigma = V\Lambda V^\top$ — we now delegate the SVD-based solve to sklearn rather than rolling it by hand.
|
||||||
* **Marchenko–Pastur cutoff** (random matrix theory): eigenvalues of a random covariance matrix fall inside $[\lambda_-, \lambda_+]$; eigenvalues above $\lambda_+$ are statistically significant factors. Here **9 eigenvalues** exceed the cutoff. PC1 explains 34% of variance and is essentially the market factor (correlation 0.96 with MKT-RF); PC2 loads on value (HML, 0.65).
|
* **Marchenko–Pastur cutoff** (random matrix theory): eigenvalues of a random covariance matrix fall inside $[\lambda_-, \lambda_+]$; eigenvalues above $\lambda_+$ are statistically significant factors. Here **9 eigenvalues** exceed the cutoff. PC1 explains 34% of variance and is essentially the market factor (correlation 0.96 with MKT-RF); PC2 loads on value (HML, 0.65).
|
||||||
* **Ledoit–Wolf shrinkage** ($\hat\Sigma = \delta F + (1-\delta)S$) regularizes the noisy sample covariance; out-of-sample it lowers the Frobenius estimation error by ~5%.
|
* **Ledoit–Wolf shrinkage** ($\hat\Sigma = \delta F + (1-\delta)S$) regularizes the noisy sample covariance; out-of-sample it lowers the Frobenius estimation error by ~5%.
|
||||||
* **Variance decomposition:** splitting $\Sigma$ into the top-$k$ factor subspace and its orthogonal complement,
|
* **Variance decomposition:** splitting $\Sigma$ into the top-$k$ factor subspace and its orthogonal complement,
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"## Outputs\n",
|
"## Outputs\n",
|
||||||
"\n",
|
"\n",
|
||||||
"We produce a cleaned monthy return panel ($R$), a sector mapping table, and exploratory plots that motivate later notebooks. Topics include:\n",
|
"We produce a cleaned monthly return panel ($R$), a sector mapping table, and exploratory plots that motivate later notebooks. Topics include:\n",
|
||||||
"- single-factor diagnostics (vecotrs $f_t$ that predict rows of $R$),\n",
|
"- single-factor diagnostics (vectors $f_t$ that predict rows of $R$),\n",
|
||||||
"- composite signal construction (linear combinations of orthogonalized factor vectors),\n",
|
"- composite signal construction (linear combinations of orthogonalized factor vectors),\n",
|
||||||
"- backtesting (weight vectors $w$ and portfolio returns $w^Tr)$,\n",
|
"- backtesting (weight vectors $w$ and portfolio returns $w^Tr)$,\n",
|
||||||
"- risk decomposition (eigendecomposition of the covariance matrix $\\Sigma$). \n",
|
"- risk decomposition (eigendecomposition of the covariance matrix $\\Sigma$). \n",
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"## Steup and Imports"
|
"## Setup and Imports"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -361,7 +361,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"We resample daily prices to month-end and compute simple monthly return \n",
|
"We resample daily prices to month-end and compute simple monthly return \n",
|
||||||
"$$ r_{t,i} = p_{t,i}/p_{t-1,i} - 1. $$\n",
|
"$$ r_{t,i} = p_{t,i}/p_{t-1,i} - 1. $$\n",
|
||||||
"Here $t$ is the time index, $i$ is the stock index, and $p_{t,i}$ is the closing date. The ration $p_{t,i}/p_{t-1,i}$ tells us what \\$1 invested ends up as, so we subtract 1 in order get the simple net return. \n",
|
"Here $t$ is the time index, $i$ is the stock index, and $p_{t,i}$ is the closing date. The ratio $p_{t,i}/p_{t-1,i}$ tells us what \\$1 invested ends up as, so we subtract 1 in order to get the simple net return. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"The result is the return matrix $R \\in M_{T \\times N}(\\mathbb{R})$ with months as rows and stocks as columns. \n",
|
"The result is the return matrix $R \\in M_{T \\times N}(\\mathbb{R})$ with months as rows and stocks as columns. \n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -715,9 +715,9 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"## Sector Composition\n",
|
"## Sector Composition\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Sectors are a categorial partition of the column index — each stock belongs to exactly one of the ~11 sectors (Technology, Financials, Healthcare, etc.). A binary encoding of sector membership gives a $\\{0,1\\}$-matrix $N \\times K$ matrix that will reappear in later notebooks. \n",
|
"Sectors are a categorical partition of the column index — each stock belongs to exactly one of the ~11 sectors (Technology, Financials, Healthcare, etc.). A binary encoding of sector membership gives a $\\{0,1\\}$ $N \\times K$ matrix that will reappear in later notebooks. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Sectors matter for two reasons. First, many factors (value, quality) have strong sector tilts that need to be projected out if we want a clean understanding of what is happening. Second, sector concentration in the unviverse drives how much idiosyncratic risk (stock-specific variance) a long-short portfolio will carry."
|
"Sectors matter for two reasons. First, many factors (value, quality) have strong sector tilts that need to be projected out if we want a clean understanding of what is happening. Second, sector concentration in the universe drives how much idiosyncratic risk (stock-specific variance) a long-short portfolio will carry."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,11 +21,11 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"In linear-algebraic terms, this is a question about the **angle** between two vectors. If $f_t$ and $r_{t+1}$ point in similar directions (small angle, high cosine similarity), the factor has predictive power. If they're nearly orthogonal, it doesn't. \n",
|
"In linear-algebraic terms, this is a question about the **angle** between two vectors. If $f_t$ and $r_{t+1}$ point in similar directions (small angle, high cosine similarity), the factor has predictive power. If they're nearly orthogonal, it doesn't. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"We test four standard cross-sectional factors, most of which we compute as priced-based proxies since we are using pretty basic data. They are momentum, value, quality, and low volatility.\n",
|
"We test four standard cross-sectional factors, most of which we compute as price-based proxies since we are using pretty basic data. They are momentum, value, quality, and low volatility.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"> **Spoiler**: Momentum wins, and the rest have negative or insignificant information coefficients over this period. The methodology for diagnosing a factor is the same whether it works or not, and showing *why* the proxies fail is more instructive than silently dropping them.\n",
|
"> **Spoiler**: Momentum wins, and the rest have negative or insignificant information coefficients over this period. The methodology for diagnosing a factor is the same whether it works or not, and showing *why* the proxies fail is more instructive than silently dropping them.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The main goals of this notebook are.\n",
|
"The main goals of this notebook are:\n",
|
||||||
"1. To define and compute four cross-sectional factors (momentum, value, quality, low-vol) as vectors $f_t$.\n",
|
"1. To define and compute four cross-sectional factors (momentum, value, quality, low-vol) as vectors $f_t$.\n",
|
||||||
"2. To measure each factor's information coefficient (**IC**) — the cosine similarity between $f_t$ and $r_{t+1}$.\n",
|
"2. To measure each factor's information coefficient (**IC**) — the cosine similarity between $f_t$ and $r_{t+1}$.\n",
|
||||||
"3. To examine **IC stability** across subperiods (walk-forward: is the factor consistent, or just lucky in one period?).\n",
|
"3. To examine **IC stability** across subperiods (walk-forward: is the factor consistent, or just lucky in one period?).\n",
|
||||||
@@ -141,9 +141,9 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Factor definitions\n",
|
"## Factor definitions\n",
|
||||||
"We'll now compute are four standard factors. All are cross-sectional ranks (permutations) at each month-end, so they live on the same scale and can be combined later without further normalization.\n",
|
"We'll now compute our four standard factors. All are cross-sectional ranks (permutations) at each month-end, so they live on the same scale and can be combined later without further normalization.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- **Momemtum**: Trailing 12-month return skipping the most recent month ($t - 12$ to $t - 2$). The intuition behind is that stocks that went up over the past year tend to keep going up for another month or two\n",
|
"- **Momentum**: Trailing 12-month return skipping the most recent month ($t - 12$ to $t - 2$). The intuition behind it is that stocks that went up over the past year tend to keep going up for another month or two\n",
|
||||||
"- **Values**: we use price-based inverse momentum as a value proxy: 60-month trailing return, inverted. The intuition is that stocks that went down over 5 years are \"cheap\" and may mean-revert.\n",
|
"- **Values**: we use price-based inverse momentum as a value proxy: 60-month trailing return, inverted. The intuition is that stocks that went down over 5 years are \"cheap\" and may mean-revert.\n",
|
||||||
"- **Quality**: 12-month Sharpe-like ratio of monthly returns (mean / std). The intuition is that stocks with smooth positive returns are \"higher quality\".\n",
|
"- **Quality**: 12-month Sharpe-like ratio of monthly returns (mean / std). The intuition is that stocks with smooth positive returns are \"higher quality\".\n",
|
||||||
"- **Low-volatility**: Inverse of 60-month trailing volatility, ranked. Intuition is that low-risk stocks tend to outperform on a risk-adjusted basis.\n",
|
"- **Low-volatility**: Inverse of 60-month trailing volatility, ranked. Intuition is that low-risk stocks tend to outperform on a risk-adjusted basis.\n",
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"The **information ratio (IR)** is the mean IC divided by the standard deviation of IC across dates: \n",
|
"The **information ratio (IR)** is the mean IC divided by the standard deviation of IC across dates: \n",
|
||||||
"$$ \\text{IR} = \\frac{\\text{Mean IC}}{\\text{Std IC}} \\times \\sqrt{12}. $$\n",
|
"$$ \\text{IR} = \\frac{\\text{Mean IC}}{\\text{Std IC}} \\times \\sqrt{12}. $$\n",
|
||||||
"This is a ration of signal and noise, which tells us whether the factor reliably predicts returns or is just noise."
|
"This is a ratio of signal and noise, which tells us whether the factor reliably predicts returns or is just noise."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -372,7 +372,7 @@
|
|||||||
"id": "5659b941",
|
"id": "5659b941",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Note that 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 ±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",
|
||||||
"\n",
|
"\n",
|
||||||
"We do this sort of masking throughout."
|
"We do this sort of masking throughout."
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"## Purpose\n",
|
"## Purpose\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Notebook 02 established that momentum was the only factor with positive, persistant IC. The other three have negative or insignicant IC with our price-based proxies.\n",
|
"Notebook 02 established that momentum was the only factor with positive, persistent IC. The other three have negative or insignificant IC with our price-based proxies.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In this notebook, our goals are the following.\n",
|
"In this notebook, our goals are the following.\n",
|
||||||
"1. **Build the headline signal**: sector-neutralized momentum. We winsoirze, z-score, and project orthogonal to the sector subspace. The same pipeline that would apply to any factor, but applied to the one that works. \n",
|
"1. **Build the headline signal**: sector-neutralized momentum. We winsorize, z-score, and project orthogonal to the sector subspace. The same pipeline that would apply to any factor, but applied to the one that works. \n",
|
||||||
"2. **Tests whether combining helps**: we build a 4-factor equal-weight composite and compare its IC to momentum alone. If the composite IC is worse (it is), that confirms the decision to trade based on momentum alone is the right one. \n",
|
"2. **Tests whether combining helps**: we build a 4-factor equal-weight composite and compare its IC to momentum alone. If the composite IC is worse (it is), that confirms the decision to trade based on momentum alone is the right one. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"### Terms uesd in this notebook. \n",
|
"### Terms used in this notebook \n",
|
||||||
"\n",
|
"\n",
|
||||||
"| Term | Meaning |\n",
|
"| Term | Meaning |\n",
|
||||||
"|------|---------|\n",
|
"|------|---------|\n",
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"## Outputs\n",
|
"## Outputs\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- `momentum_signal.csv` — the **momentum-only** sector-neutralized signal (this is what will backtest trades)\n",
|
"- `momentum_signal.csv` — the **momentum-only** sector-neutralized signal (this is what the backtest trades)\n",
|
||||||
"- `composite_4factor.csv` — the 4-factor equal weight composite (kept for comparison)\n",
|
"- `composite_4factor.csv` — the 4-factor equal weight composite (kept for comparison)\n",
|
||||||
"- Per-factor neutralized exposures\n",
|
"- Per-factor neutralized exposures\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"## Winsorization and Z-Scoring\n",
|
"## Winsorization and Z-Scoring\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Winsorization** is a statiscal technique for limiting the influence of extreme outlies 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 ±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",
|
||||||
@@ -194,13 +194,13 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"From the linear algebraists' perspective, the sector matrix $D \\in \\{0,1\\}^{N \\times K}$ spans a subspace $S \\subseteq \\mathbb{R}^N$. The orthogonal projection onto $S$ is:\n",
|
"From the linear algebraists' perspective, the sector matrix $D \\in \\{0,1\\}^{N \\times K}$ spans a subspace $S \\subseteq \\mathbb{R}^N$. The orthogonal projection onto $S$ is:\n",
|
||||||
"$$ P = D(D^TD)^{-1}D^T. $$\n",
|
"$$ P = D(D^TD)^{-1}D^T. $$\n",
|
||||||
"This is the familiar ordinary least-squares projection matrix, which is symmetric and idempotent. Applying to to a factor vector $f$ gives the component of $f$ which lies in the sector subspace:\n",
|
"This is the familiar ordinary least-squares projection matrix, which is symmetric and idempotent. Applying it to a factor vector $f$ gives the component of $f$ which lies in the sector subspace:\n",
|
||||||
"$$ \\hat{f} = Pf. $$\n",
|
"$$ \\hat{f} = Pf. $$\n",
|
||||||
"The **neutralized factor** is the residual, i.e., the component orthogonal to $S$:\n",
|
"The **neutralized factor** is the residual, i.e., the component orthogonal to $S$:\n",
|
||||||
"$$ f_\\perp = (I - P)f = f - \\hat{f}. $$\n",
|
"$$ f_\\perp = (I - P)f = f - \\hat{f}. $$\n",
|
||||||
"This is exactly linear squares regression of $f$ on sectors, returning the residuals. The residual is orthogonal to the sector subspace by construction: $\\langle f_\\perp, \\hat{f} \\rangle = 0$. \n",
|
"This is exactly linear least squares regression of $f$ on sectors, returning the residuals. The residual is orthogonal to the sector subspace by construction: $\\langle f_\\perp, \\hat{f} \\rangle = 0$. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"For size, we use the log of tralining market cap proxied by price $\\times 1$ (best we could do with out data). This is a weak proxy — a real implementation would use actual market cap."
|
"For size, we use the log of trailing market cap proxied by price $\\times 1$ (best we could do with our data). This is a weak proxy — a real implementation would use actual market cap."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -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 20 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 ±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",
|
||||||
"\n",
|
"\n",
|
||||||
"We do this sort of masking throughout."
|
"We do this sort of masking throughout."
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The main goals in this notebook are:\n",
|
"The main goals in this notebook are:\n",
|
||||||
"1. To construct top-decile long and long-short portfolions (spare weight vectors) from the momentum signal.\n",
|
"1. To construct top-decile long and long-short portfolios (sparse weight vectors) from the momentum signal.\n",
|
||||||
"2. To track **turnover** explicitly: $\\|w_t - w_{t-1}|\\|_1$ (the $\\ell^1$ distance between consecutive weights).\n",
|
"2. To track **turnover** explicitly: $\\|w_t - w_{t-1}\\|_1$ (the $\\ell^1$ distance between consecutive weights).\n",
|
||||||
"3. To apply realistic transaction costs: $c \\cdot \\|w_t - w_{t-1}\\|_1$.\n",
|
"3. To apply realistic transaction costs: $c \\cdot \\|w_t - w_{t-1}\\|_1$.\n",
|
||||||
"4. To compute performance metrics: Sharpe, Sortino, max drawdown, Calmar.\n",
|
"4. To compute performance metrics: Sharpe, Sortino, max drawdown, Calmar.\n",
|
||||||
"5. To run walk-forward analysis: split into 5-year windows and verify performance is consistent across subperiods (not just one lucky stretch).\n",
|
"5. To run walk-forward analysis: split into 5-year windows and verify performance is consistent across subperiods (not just one lucky stretch).\n",
|
||||||
"6. To regress portfolio returns on Fama-French benchmark factors (OLS projection) to extract alpha (the orthogonal residual).\n",
|
"6. To regress portfolio returns on Fama-French benchmark factors (OLS projection) to extract alpha (the orthogonal residual).\n",
|
||||||
"7. To test survivorship bias sensitivity: how much return drag from missing/delisted stocks would it take to erate the alpha?\n",
|
"7. To test survivorship bias sensitivity: how much return drag from missing/delisted stocks would it take to erase the alpha?\n",
|
||||||
"\n",
|
"\n",
|
||||||
"### Terms used in this notebook\n",
|
"### Terms used in this notebook\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -320,8 +320,8 @@
|
|||||||
"## Portfolio Formation\n",
|
"## Portfolio Formation\n",
|
||||||
"\n",
|
"\n",
|
||||||
"At each rebalance date, we rank stocks by the momentum signal (the vector $c_t$) and form two portfolios:\n",
|
"At each rebalance date, we rank stocks by the momentum signal (the vector $c_t$) and form two portfolios:\n",
|
||||||
"- **Long-only**: equal-weight the top declide (top 10% of stocks by momentum score). This is a sparse weight vector with $w_i = 1/k$ for the top $k$ stocks and $w_i = 0$ for the rest.\n",
|
"- **Long-only**: equal-weight the top decile (top 10% of stocks by momentum score). This is a sparse weight vector with $w_i = 1/k$ for the top $k$ stocks and $w_i = 0$ for the rest.\n",
|
||||||
"- **Long-short (comparison)**: long the top declide, short the bottom decile, equal-weighted on each side with $\\sum w_i = 0$ (dollar-neutral).\n",
|
"- **Long-short (comparison)**: long the top decile, short the bottom decile, equal-weighted on each side with $\\sum w_i = 0$ (dollar-neutral).\n",
|
||||||
"\n"
|
"\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -1089,7 +1089,7 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"## Walk-Forward Analysis\n",
|
"## Walk-Forward Analysis\n",
|
||||||
"\n",
|
"\n",
|
||||||
"A single full-sample Sharpe ration doesn't quite tell us whether we have a robust strategy. Walk-forward analysis plits the sample into non-overlapping 5-year windows and computes performance metric in each. A strategy that's positive in *every window* is far more convincing than one that earned all its returns in one lucky period.\n",
|
"A single full-sample Sharpe ratio doesn't quite tell us whether we have a robust strategy. Walk-forward analysis splits the sample into non-overlapping 5-year windows and computes performance metrics in each. A strategy that's positive in *every window* is far more convincing than one that earned all its returns in one lucky period.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This is pure consistency checking; we're not optimizing any parameters or anything."
|
"This is pure consistency checking; we're not optimizing any parameters or anything."
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"1. To compute the sample covariance matrix $\\Sigma = \\frac{1}{T-1}X_c^T X_c$.\n",
|
"1. To compute the sample covariance matrix $\\Sigma = \\frac{1}{T-1}X_c^T X_c$.\n",
|
||||||
"2. To use PCA on $\\Sigma$ using `sklearn.decomposition.PCA` (which is really an eigendecomposition $\\Sigma = V\\Lambda V^T$ under the hood).\n",
|
"2. To use PCA on $\\Sigma$ using `sklearn.decomposition.PCA` (which is really an eigendecomposition $\\Sigma = V\\Lambda V^T$ under the hood).\n",
|
||||||
"3. To apply the Marchenko-Pastur cutoff from random matrix theory to separate signal eigenvalues from noise.\n",
|
"3. To apply the Marchenko-Pastur cutoff from random matrix theory to separate signal eigenvalues from noise.\n",
|
||||||
"4. To implement Ledoit-Wolf shrinkage (a convex combination of sample and stuctured covariance) and show it improves out-of-sample estimation.\n",
|
"4. To implement Ledoit-Wolf shrinkage (a convex combination of sample and structured covariance) and show it improves out-of-sample estimation.\n",
|
||||||
"5. To decompose the portfolio's variance $\\langle \\Sigma w, w \\rangle$ into the factor subspace and its orthogonal complement. \n",
|
"5. To decompose the portfolio's variance $\\langle \\Sigma w, w \\rangle$ into the factor subspace and its orthogonal complement. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"### Terms used in this notebook\n",
|
"### Terms used in this notebook\n",
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
"## Notebook Structure\n",
|
"## Notebook Structure\n",
|
||||||
"1. [Setup and Imports](#setup-and-imports)\n",
|
"1. [Setup and Imports](#setup-and-imports)\n",
|
||||||
"2. [Load Data](#load-data)\n",
|
"2. [Load Data](#load-data)\n",
|
||||||
"3. [Sample Covariance and PCA from Scratch](#sample-covariance-and-pca-from-scratch)\n",
|
"3. [Sample Covariance and PCA](#sample-covariance-and-pca)\n",
|
||||||
"4. [Marchenko–Pastur Noise Separation](#marchenkopastur-noise-separation)\n",
|
"4. [Marchenko–Pastur Noise Separation](#marchenkopastur-noise-separation)\n",
|
||||||
"5. [Ledoit–Wolf Shrinkage](#ledoitwolf-shrinkage)\n",
|
"5. [Ledoit–Wolf Shrinkage](#ledoitwolf-shrinkage)\n",
|
||||||
"6. [Portfolio Variance Decomposition](#portfolio-variance-decomposition)\n",
|
"6. [Portfolio Variance Decomposition](#portfolio-variance-decomposition)\n",
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"id": "08545070",
|
"id": "08545070",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Setups and Imports"
|
"## Setup and Imports"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user