Files
Factor-Risk-Decomposition/notebooks/03_factor_construction_and_composite_signal.ipynb
T
2026-07-31 08:33:52 -04:00

675 lines
62 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "d273a5e0",
"metadata": {},
"source": [
"# Factor Construction and Composite Signal\n",
"\n",
"## Purpose\n",
"\n",
"Notebook 02 suggested that momentum is the only price-based signal worth carrying forward. This notebook turns that raw momentum rank into the traded signal used by the backtest.\n",
"\n",
"The goals are:\n",
"1. Winsorize and z-score each factor cross-section so outliers do not dominate.\n",
"2. Neutralize the signal against sector membership by projecting out sector effects.\n",
"3. Compare momentum-only against a simple four-factor composite.\n",
"4. Save the sector-neutralized momentum signal for notebook 04.\n",
"\n",
"### Terms used in this notebook\n",
"\n",
"| Term | Meaning |\n",
"|------|---------|\n",
"| **Winsorization** | Clip extreme values at a threshold instead of dropping them |\n",
"| **Z-scoring** | Center to mean 0 and scale to standard deviation 1 |\n",
"| **Neutralization** | Regress a signal on unwanted exposures and keep the residual |\n",
"| **Composite signal** | A linear combination $c_t = \\sum_k w_k f_{k,\\perp}$ |\n",
"| **Sector matrix** | $D \\in \\{0,1\\}^{N \\times K}$, a one-hot sector-membership matrix |\n",
"| **Projection** | The linear algebra operation behind neutralization |\n",
"| **Information coefficient (IC)** ↻ | Spearman rank correlation used to compare candidate signals |\n",
"| **Return panel** $R$ ↻ | The monthly return matrix from notebook 01 |\n",
"\n",
"## Outputs\n",
"\n",
"- `momentum_signal.csv`: sector-neutralized momentum, the signal used in the backtest\n",
"- `composite_4factor.csv`: a simple four-factor composite kept for comparison\n",
"- `factor_*_neutralized.csv`: neutralized versions of the individual factors\n",
"\n",
"## Notebook Structure\n",
"1. [Setup and Imports](#setup-and-imports)\n",
"2. [Winsorization and Z-Scoring](#winsorization-and-z-scoring)\n",
"3. [Sector Neutralization](#sector-neutralization)\n",
"4. [Composite Assembly and Comparison](#composite-assembly-and-comparison)\n",
"5. [IC Comparison: Momentum vs. Composite](#ic-comparison-momentum-vs-composite)\n",
"6. [Conclusion](#conclusion)"
]
},
{
"cell_type": "markdown",
"id": "75cbb165",
"metadata": {},
"source": [
"\n",
"## Setup and Imports"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c72adc67",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:52.187310Z",
"iopub.status.busy": "2026-07-31T11:08:52.186272Z",
"iopub.status.idle": "2026-07-31T11:08:53.251453Z",
"shell.execute_reply": "2026-07-31T11:08:53.250854Z"
}
},
"outputs": [],
"source": [
"\"\"\"\n",
"==================================\n",
"Setup and imports\n",
"==================================\n",
"\"\"\"\n",
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"import os\n",
"from scipy.stats import spearmanr\n",
"\n",
"pd.set_option('display.max_columns', None)\n",
"pd.set_option('display.max_rows', 100)\n",
"\n",
"palette = ['steelblue', 'coral', 'seagreen']\n",
"\n",
"os.makedirs('../data/processed', exist_ok=True)\n",
"os.makedirs('../images/03_factor_construction', exist_ok=True)\n",
"\n",
"RANDOM_STATE = 3"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "0090dab7",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:53.253326Z",
"iopub.status.busy": "2026-07-31T11:08:53.253053Z",
"iopub.status.idle": "2026-07-31T11:08:53.408971Z",
"shell.execute_reply": "2026-07-31T11:08:53.408532Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loaded 4 factors\n",
"Returns: (251, 501)\n"
]
}
],
"source": [
"\"\"\"\n",
"==================================\n",
"Load factor exposures, returns, sectors\n",
"==================================\n",
"\"\"\"\n",
"factor_names = ['momentum', 'value', 'quality', 'lowvol']\n",
"factor_dict = {n: pd.read_csv(f'../data/processed/factor_{n}.csv', index_col=0, parse_dates=True) for n in factor_names}\n",
"df_returns = pd.read_csv('../data/processed/returns_monthly.csv', index_col=0, parse_dates=True)\n",
"df_sector = pd.read_csv('../data/processed/sector_mapping.csv')\n",
"\n",
"# Build sector lookup\n",
"sector_map = dict(zip(df_sector['ticker'], df_sector['sector']))\n",
"\n",
"print(f\"Loaded {len(factor_names)} factors\")\n",
"print(f\"Returns: {df_returns.shape}\")"
]
},
{
"cell_type": "markdown",
"id": "46a37025",
"metadata": {},
"source": [
"## Winsorization and Z-Scoring\n",
"\n",
"Raw factor values can contain large outliers. Winsorization clips those extremes rather than dropping the stock entirely. Here we cap each monthly cross-section at $\\pm 3$ standard deviations around its mean.\n",
"\n",
"After clipping, we z-score within each date:\n",
"\n",
"$$\\tilde f_{t,i}=\\frac{f_{t,i}-\\bar f_t}{\\mathrm{std}(f_t)}.$$\n",
"\n",
"This gives each factor row mean 0 and standard deviation 1, so later comparisons are not driven by arbitrary units."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "83a54dbc",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:53.410714Z",
"iopub.status.busy": "2026-07-31T11:08:53.410441Z",
"iopub.status.idle": "2026-07-31T11:08:54.165454Z",
"shell.execute_reply": "2026-07-31T11:08:54.164580Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"momentum: z-scores, shape=(251, 501)\n",
"value: z-scores, shape=(251, 501)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"quality: z-scores, shape=(251, 501)\n",
"lowvol: z-scores, shape=(251, 501)\n"
]
}
],
"source": [
"\"\"\"\n",
"==================================\n",
"Winsorize and z-score\n",
"==================================\n",
"\"\"\"\n",
"def winsorize(series, sigma=3):\n",
" \"\"\"Clip at ±sigma standard deviations around the mean.\"\"\"\n",
" mu = series.mean()\n",
" s = series.std()\n",
" if s == 0 or pd.isna(s):\n",
" return series\n",
" return series.clip(lower=mu - sigma*s, upper=mu + sigma * s)\n",
"\n",
"def zscore(series):\n",
" \"\"\"Cross-sectional z-score.\"\"\"\n",
" mu = series.mean()\n",
" s = series.std()\n",
" if s == 0 or pd.isna(s):\n",
" return series * 0\n",
" return (series - mu)/s\n",
"\n",
"factor_z = {}\n",
"for name, df_f in factor_dict.items():\n",
" df_w = df_f.apply(winsorize, axis=1)\n",
" df_z = df_w.apply(zscore, axis=1)\n",
" factor_z[name] = df_z\n",
" print(f\"{name}: z-scores, shape={df_z.shape}\")"
]
},
{
"cell_type": "markdown",
"id": "112a7744",
"metadata": {},
"source": [
"## Sector Neutralization\n",
"\n",
"A raw momentum score may contain sector bets. For example, if Technology had a strong year, a momentum portfolio might become mostly a Technology portfolio. That may be a valid trade, but it is not a clean test of stock selection within sectors.\n",
"\n",
"To neutralize sectors, create a sector dummy matrix\n",
"\n",
"$$D \\in \\{0,1\\}^{N \\times K}.$$\n",
"\n",
"For one factor vector $f \\in \\mathbb{R}^N$, the projection onto the sector span is\n",
"\n",
"$$P_D f = D(D^\\top D)^{-1}D^\\top f.$$\n",
"\n",
"The sector-neutralized signal is the residual:\n",
"\n",
"$$f_\\perp = (I-P_D)f.$$\n",
"\n",
"This is the same as running a cross-sectional OLS regression of the factor on sector dummies and keeping the residuals. The residual has zero linear exposure to the sector dummy columns used in the regression.\n",
"\n",
"The code also mentions size, but with this dataset we only have a weak price-based size proxy. I would not interpret it as a true market-cap neutralization without real shares-outstanding data."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "b7ce2018",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:54.167456Z",
"iopub.status.busy": "2026-07-31T11:08:54.167259Z",
"iopub.status.idle": "2026-07-31T11:08:56.142616Z",
"shell.execute_reply": "2026-07-31T11:08:56.141776Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Neutralizing momentum...\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Neutralizing value...\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Neutralizing quality...\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Neutralizing lowvol...\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sector neutralization complete.\n"
]
}
],
"source": [
"\"\"\"\n",
"==================================\n",
"Sector neutralization via cross-sectional regression on dummies\n",
"==================================\n",
"\"\"\"\n",
"def neutralize_against_sector(factor_row, sector_map):\n",
" \"\"\"Regress factor on sector dummies, return residuals.\"\"\"\n",
" tickers = factor_row.index\n",
" sectors = pd.Series([sector_map.get(t, 'Unknown') for t in tickers], index=tickers)\n",
"\n",
" # One-hot encode\n",
" indicators = pd.get_dummies(sectors, drop_first=True).astype(float)\n",
" indicators['intercept'] = 1.0\n",
"\n",
" # Mask valid\n",
" mask = factor_row.notna()\n",
" if mask.sum() < 30:\n",
" return factor_row\n",
"\n",
" y = factor_row[mask].values\n",
" X = indicators.loc[mask].values\n",
"\n",
" # OLS via least squares\n",
" beta, _, _, _ = np.linalg.lstsq(X,y)\n",
" resid = y - X @ beta\n",
"\n",
" out = pd.Series(np.nan, index=factor_row.index)\n",
" out[mask] = resid\n",
" return out\n",
"\n",
"factor_neut = {}\n",
"for name, df_z in factor_z.items():\n",
" print(f\"Neutralizing {name}...\")\n",
" df_neut = df_z.apply(lambda row: neutralize_against_sector(row, sector_map), axis=1)\n",
" # Re-z-score the residuals so they're back on a common scale\n",
" df_neut = df_neut.apply(zscore, axis=1)\n",
" factor_neut[name] = df_neut\n",
"\n",
"print(\"Sector neutralization complete.\")"
]
},
{
"cell_type": "markdown",
"id": "9740141a",
"metadata": {},
"source": [
"As in notebook 02, we use a sample-size guardrail. If fewer than 30 stocks have valid data in a month, we skip neutralization for that row rather than fit a noisy cross-sectional regression. This mostly affects early or sparse parts of the panel."
]
},
{
"cell_type": "markdown",
"id": "b4204816",
"metadata": {},
"source": [
"## Composite Assembly and Comparison\n",
"\n",
"We compare two candidate signals:\n",
"\n",
"1. **Momentum-only:** the sector-neutralized momentum residual $f_{m,\\perp}$, re-z-scored. This is the signal passed to the backtest.\n",
"2. **Four-factor composite:** an equal-weight average of the neutralized factor vectors,\n",
"\n",
"$$c_t = \\frac{1}{4}\\sum_{k=1}^4 f_{k,\\perp}(t).$$\n",
"\n",
"This is a useful sanity check. If the composite improves IC, the extra factors are helping. If it gets worse, the added factors are diluting momentum rather than diversifying it."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "792e547e",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:56.144507Z",
"iopub.status.busy": "2026-07-31T11:08:56.144304Z",
"iopub.status.idle": "2026-07-31T11:08:56.350858Z",
"shell.execute_reply": "2026-07-31T11:08:56.350129Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Momentum-only signal: (251, 501)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"4-factor composite: (251, 501)\n",
"\n",
"Our main signal will be momentum-only. The 4-factor composite is kept for comparison.\n"
]
}
],
"source": [
"\"\"\"\n",
"==================================\n",
"Build momentum-only signal and 4-factor composite\n",
"==================================\n",
"\"\"\"\n",
"# Momentum only\n",
"df_momentum_signal = factor_neut['momentum'].apply(zscore, axis=1)\n",
"print(f\"Momentum-only signal: {df_momentum_signal.shape}\")\n",
"\n",
"# 4-factor equal-weight composite\n",
"common_dates = factor_neut['momentum'].index\n",
"common_tickers = factor_neut['momentum'].columns\n",
"\n",
"for name in factor_names:\n",
" common_dates = common_dates.intersection(factor_neut[name].index)\n",
" common_tickers = common_tickers.intersection(factor_neut[name].columns)\n",
"\n",
"df_composite_4f = pd.DataFrame(0.0, index=common_dates, columns=common_tickers)\n",
"count_df = pd.DataFrame(0, index=common_dates, columns=common_tickers)\n",
"\n",
"for name in factor_names:\n",
" df_f = factor_neut[name].loc[common_dates, common_tickers]\n",
" df_composite_4f = df_composite_4f.add(df_f.fillna(0))\n",
" count_df = count_df.add(df_f.notna().astype(int))\n",
"\n",
"df_composite_4f = df_composite_4f / count_df.replace(0, np.nan)\n",
"df_composite_4f[count_df < 3] = np.nan\n",
"df_composite_4f = df_composite_4f.apply(zscore, axis=1)\n",
"\n",
"print(f\"4-factor composite: {df_composite_4f.shape}\")\n",
"print(f\"\\nOur main signal will be momentum-only. The 4-factor composite is kept for comparison.\")"
]
},
{
"cell_type": "markdown",
"id": "f8809b2e",
"metadata": {},
"source": [
"## Composite vs. Single Factors"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "25e7a046",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:56.353026Z",
"iopub.status.busy": "2026-07-31T11:08:56.352756Z",
"iopub.status.idle": "2026-07-31T11:08:58.700588Z",
"shell.execute_reply": "2026-07-31T11:08:58.699933Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"IC Comparison: Neutralized Factors, Momentum-Only, and 4-Factor Composite\n",
"\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>mean</th>\n",
" <th>std</th>\n",
" <th>ic_ir</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>momentum</th>\n",
" <td>0.0068</td>\n",
" <td>0.1576</td>\n",
" <td>0.1505</td>\n",
" </tr>\n",
" <tr>\n",
" <th>value</th>\n",
" <td>-0.0198</td>\n",
" <td>0.1344</td>\n",
" <td>-0.5111</td>\n",
" </tr>\n",
" <tr>\n",
" <th>quality</th>\n",
" <td>0.0013</td>\n",
" <td>0.1597</td>\n",
" <td>0.0282</td>\n",
" </tr>\n",
" <tr>\n",
" <th>lowvol</th>\n",
" <td>-0.0169</td>\n",
" <td>0.1772</td>\n",
" <td>-0.3298</td>\n",
" </tr>\n",
" <tr>\n",
" <th>momentum_only</th>\n",
" <td>0.0068</td>\n",
" <td>0.1576</td>\n",
" <td>0.1505</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4factor_composite</th>\n",
" <td>-0.0078</td>\n",
" <td>0.1688</td>\n",
" <td>-0.1593</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" mean std ic_ir\n",
"momentum 0.0068 0.1576 0.1505\n",
"value -0.0198 0.1344 -0.5111\n",
"quality 0.0013 0.1597 0.0282\n",
"lowvol -0.0169 0.1772 -0.3298\n",
"momentum_only 0.0068 0.1576 0.1505\n",
"4factor_composite -0.0078 0.1688 -0.1593"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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mN58880MH/Paw8tPnDghHx8fvfzyy27jfvnlFzkcDr333nvSDQ7nnj59usqUKeN8j2fOnOn2WJnd9/fff3c77Wfjxo3q3LmzihYt6tzePProozp48KDH71tWnDhxQv369VP58uWVJ08ehYWFqXHjxvrhhx/cxl6+fFmjRo1SuXLl5OfnpwIFCqhRo0Zas2aN9Pf36/z585oxY4bzM3ntURg7duzQQw89pHz58snPz09VqlRx+/lKf68+/fRTDR48WIUKFZKvr6/27dunCxcu6Nlnn1WxYsWcP081atRw+V0AuJtRugFkq+DgYLVv396laMyZM0deXl4ZFpi0tDQ99NBDGjt2rLp06aKvv/5aY8eO1bJly9SwYUNdvHjROXbv3r1q0aKFpkyZovj4eA0YMECff/65Wrdu7fa4KSkpatOmjR544AEtXLhQvXr10ttvv61x48Zl+TUtXbpUkrJ0SF7RokWzdN6gl5eXevTooZkzZyo1NdX5vH/++ad69uzpNt4wDD388MN68803FRsbq6+//lqDBg3SjBkz1LhxY7c/LmzdulVDhw7VCy+8oC+++EIhISFq166dhg8frsmTJ+v111/XrFmzlJSUpFatWrm87ytXrtT999+vs2fPatKkSVq4cKGqVKmiTp06ZXhedp8+feTt7a3Zs2dr/PjxWrVqlbp27epcv2DBAhUvXlxVq1bV2rVrtXbt2lveK5qYmKiePXuqT58+WrhwoSpWrKhevXpp1KhRGjp0qJ5//nnNnz9fefLk0cMPP5xpeb3WypUrdfXq1Rt+v9PXLVu2zGX51q1bNXjwYA0cOFALFy5UpUqV1Lt3b33//feZPlanTp0UERHhVrquXr2qjz76SG3btlVUVFSG923VqpXCwsKcf2i41vTp01WtWjVVqlRJktSiRQtt2rRJ48eP17Jly/Thhx+qatWqbn+k8cTSpUsVHh7u8d65MWPGqHfv3qpQoYK++OILvfvuu9q2bZvq1KmjvXv3uoxNSUlRu3bt1LJlSy1cuFDNmzfX0KFDNWzYMHXv3l29evXSggULVKZMGfXo0UObNm1ye77evXvLy8tLs2fP1jvvvKOffvpJDRs2dHmtnmbK6vsWGRnp/ANP7969nZ/x9PK4a9cu3XfffdqxY4feeustffXVV2rZsqXi4uKch6RnpmfPnlq9erXbe7Z06VIdOXLEua2YO3eu+vXrpwYNGmjBggX68ssvNXDgQLc/UN6ur7/+WhMnTtSoUaM0f/585x8urv0Dx/Lly/XQQw8pKChIc+fO1RtvvKHPP/88w8/stUJDQ9WqVSvNmDFDaWlpLuumTZsmHx8fPfbYY5nef/r06erZs6fKlSun+fPn66WXXtLo0aO1YsWKW369v//+u8qUKaN33nlHS5Ys0bhx43T06FHdd999Onny5C0/blpamq5everyJUmnT5+WJA0fPlxff/21pk2bpuLFi6thw4YufyS4evWqmjdvrtGjR6tVq1ZasGCBpk+frrp16+rQoUOSpLVr18rf318tWrRwfibTT4vYs2eP6tatq507d+q9997TF198ofLly6tHjx4aP368W96hQ4fq0KFDmjRpkhYvXqywsDANGjRIH374oeLi4hQfH69PP/1UHTp0uK35L4AcxQCAbDBt2jRDkrFhwwZj5cqVhiRjx44dhmEYxn333Wf06NHDMAzDqFChgtGgQQPn/ebMmWNIMubPn+/yeBs2bDAkGR988EGGz5eWlmakpKQYCQkJhiRj69atznXdu3c3JBmff/65y31atGhhlClT5qavpUGDBkaFChWct/v27WtIMn755ReP348SJUoYJUqUuOm49Pfqv//9r7F//37D4XAYX331lWEYhtGhQwejYcOGhmEYRsuWLY3o6Gjn/eLj4w1Jxvjx410eb968eYYk4+OPP3Yui46ONvz9/Y0///zTuWzLli2GJCMyMtI4f/68c/mXX35pSDIWLVrkXFa2bFmjatWqRkpKistztWrVyoiMjDRSU1MN45rPQL9+/VzGjR8/3pBkHD161Lns+s9BuvTHOHDgQIbv08qVK53LGjRoYEgyNm7c6Fx26tQpI1euXIa/v79x+PBht9f73nvvuT3n9caOHWtIMuLj4zMdc/HiRUOS0bx5c+ey6Ohow8/Pzzh48KDLuPz58xtPPPHEDV/L8OHDDR8fH+PYsWPOZenfy4SEhBvmHTRokOHv72+cPXvWuWzXrl2GJOP99983DMMwTp48aUgy3nnnnZu+fk/4+fkZtWvX9mjsmTNnDH9/f6NFixYuyw8dOmT4+voaXbp0cS5L/9m9dnuQkpJihIaGGpKMn3/+2bk8/Xs9aNAg57L0z0/btm1dnuvHH380JBmvvvpqljJ5+r41aNDA5fN8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z5491a9fP+3evVv79+/X0aNH3eYCiI6O1pQpUyRJv/76qz7//HONGDFCV65c0aRJk7KUNSYmRu+//77WrVt30/O604vZ0aNH3dYdOXLE+RnLTomJiRkuK1myZJYzZef7li9fPuXKlUuxsbF66qmnMhxTrFixGz5GTEyMoqKiNG3aNMXExGjatGmqVauW2wzqPXv2VM+ePXX+/Hl9//33Gj58uFq1aqVff/1V0dHRWcp9q/LlyyeHw5Hp98MTPXv21BtvvOG8ksCiRYs0YMCAG141IP3768nzerrNSUpK0ldffaXhw4dryJAhzuWXL192nnud3T777DM1bNhQH374ocvy6//gExoaqtWrVystLe2WineBAgUy/VnQNf8PpLv+CB9JCgwM1MiRIzVy5EgdO3bMude7devW+uWXX7KcCchp2NMNwBSFChXSc889p9atW6t79+6ZjmvVqpVOnTql1NRUt7/016hRw1mE0v+TT99rmu6jjz4y+ZX8/2vANm/eXFOmTMl0Ep6NGzc6J6y5Hf7+/nrllVfUunVr5yHHGXnggQekv38pu9b8+fN1/vx55/rbVaZMGZUqVUpbt27N8PtTo0aNW7r2emZ7f9Mnn0ufcTvdokWLbuNVuPPx8cn0dURERKhXr15asmSJyyHb6X799VeNGzdOFSpUyNbr3VavXl1169bVuHHjNGvWLPXo0UOBgYEe3ffRRx+Vn5+fpk+frunTp6tQoUJq2rRppuNLly6tl156SRUrVtTPP/+c5awDBw5UYGCg+vXrp6SkJLf1hmE4J8erU6eO/P393T6rf/75p/Ow1uw2a9Ysl9tr1qzRwYMHnbM132omT9+3zI7uCAgIUKNGjbR582ZVqlQpw5+nm12fOb20f/nll/rhhx+0cePGGx5WHBgYqObNm+vFF1/UlStXtHPnzhs+fnZKvyLCF1984XJEwrlz57R48WKPHqNcuXKqVauWpk2bptmzZ+vy5csZTi55rTJlyigyMlJz5sxxOW3k4MGDztm803m6zXE4HDIMw+3/oMmTJzsnv8xuDofD7fm2bdvmdrh38+bNdenSpQwntrxWZtvdBx54wPmH7WvNnDlTAQEBWb6cWXh4uHr06KFHH31Ue/bs0YULF7J0fyAnYk83ANOkX+bnRjp37qxZs2apRYsWeuaZZ1SzZk15e3vrzz//1MqVK/XQQw+pbdu2qlu3rvLly6e+fftq+PDh8vb21qxZs7R169Z/5LXMnDlTzZo1U/PmzdWrVy81b95c+fLl09GjR7V48WLNmTNHmzZtch6anL5HLavndUvSoEGDNGjQoBuOadKkiWJiYvTCCy8oOTlZ999/v7Zt26bhw4eratWqio2NvcVX6u6jjz5S8+bNFRMTox49eqhQoUI6ffq0du/erZ9//ln//e9/s/yYFStW1Ny5czVv3jwVL15cfn5+qlixou677z6VKVNGzz77rK5evap8+fJpwYIFWr16dba9Hk9MmDBBe/bsUdeuXfX999+rdevW8vX11bp16/Tmm28qKChI8+fPz/ZrdD/zzDPq1KmTHA6H8/B9T+TNm1dt27bV9OnTdfbsWT377LMue7y2bdum/v37q0OHDipVqpR8fHy0YsUKbdu2zWWvXe/evTVjxgz99ttvN9wbWqxYMeeexypVqqh///7O86137dqlqVOnyjAMtW3bVnnz5tXLL7+sYcOGqVu3bnr00Ud16tQpjRw5Un5+fho+fPgtv1+Z2bhxo/r06aMOHTrojz/+0IsvvqhChQo531NPM3n6vl0vKChI0dHRWrhwoR544AHlz59fBQsWVNGiRfXuu+/qX//6l+rVq6cnn3xSRYsW1blz57Rv3z4tXrzYo9m1e/XqpXHjxqlLly7y9/d3uzJE+lEy999/vyIjI5WYmKgxY8YoJCTEeRTMwYMHVaJECXXv3t25J98Mo0ePVrNmzdSkSRMNHjxYqampGjdunAIDAz3eQ9yrVy898cQTOnLkiOrWrXvTo2u8vLw0evRo9enTR23bttXjjz+us2fPasSIEW6Hl0dEROjBBx/UmDFjlC9fPkVHR2v58uXOU5fSBQcHq379+nrjjTec38uEhARNmTJFefPmvYV35uZatWql0aNHa/jw4WrQoIH27NmjUaNGqVixYs4ZzvX3H92mTZumvn37as+ePWrUqJHS0tK0fv16lStXTp07d5b+3u6uWrVKixcvVmRkpIKCglSmTBkNHz5cX331lRo1aqRXXnlF+fPn16xZs/T1119r/PjxGV4W8Hq1atVSq1atVKlSJeXLl0+7d+/Wp59+qjp16rjMGwLctayeyQ1AznDt7OU3ktGs1SkpKcabb75pVK5c2fDz8zPy5MljlC1b1njiiSdcZnBds2aNUadOHSMg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wa9AFasj2EKY1QFsovkytk+eOPzTYasj2EahmoWsjoAcpHnz962OYA9//mp1Anu4p7TVCVxcvXrVo3G2aX8FCxZUrly53PYuHz9+3G0vdLqIiIgMx+fOnVsFChS44Zj0x7yV55WkoUOHatCgQc7bycnJKly4sObPn39nndMNZKN9c0tZHcEWSnb+1oNRALLTaO/RVkewjZe/fdnqCMDdZ1R7qxPYwyv/szqBi+TkZOXLl++m42xTun18fFS9enUtW7ZMbdv+3+Rfy5Yt00MPPZThferUqaPFixe7LFu6dKlq1Kghb29v55hly5Zp4MCBLmPq1q17y88rSb6+vvL19XVb7uXlJS8v25xKD2SJQxxC5gm2AYAF2Dx5jG0UYAVOV/DIHbZ98nR7aZvSLUmDBg1SbGysatSooTp16ujjjz/WoUOH1LdvX+nvvcuHDx/WzJkzpb9nKp84caIGDRqkxx9/XGvXrtWUKVOcs5JL0jPPPKP69etr3Lhxeuihh7Rw4UJ99913Wr16tcfPCwAAAABARmxVujt16qRTp05p1KhROnr0qO6991598803io6OliQdPXrU5drZxYoV0zfffKOBAwfqP//5j6KiovTee+/pkUcecY6pW7eu5s6dq5deekkvv/yySpQooXnz5qlWrVoePy8AAAAAABmx1XW67eyOvU43kI32zi5mdQRbKNXlgNURgLvOSIf75KbI2HBjuNURgLvPiLYeDIJGLLA6gYscd51uAAAAAADshtINAAAAAIBJKN0AAAAAAJiE0g0AAAAAgEko3QAAAAAAmITSDQAAAACASSjdAAAAAACYhNINAAAAAIBJKN0AAAAAAJiE0g0AAAAAgEko3QAAAAAAmITSDQAAAACASSjdAAAAAACYhNINAAAAAIBJKN0AAAAAAJiE0g0AAAAAgEko3QAAAAAAmITSDQAAAACASSjdAAAAAACYhNINAAAAAIBJKN0AAAAAAJiE0g0AAAAAgEko3QAAAAAAmITSDQAAAACASSjdAAAAAACYhNINAAAAAIBJKN0AAAAAAJiE0g0AAAAAgEk8Lt2pqanatm2bLl686LbuwoUL2rZtm9LS0rI7HwAAAAAAtuVx6f7000/Vq1cv+fj4uK3z9fVVr169NHv27OzOBwAAAACAbXlcuqdMmaJnn31WuXLlcluXK1cuPf/88/r444+zOx8AAAAAALblcenes2ePateunen6++67T7t3786uXAAAAAAA2J7Hpfv8+fNKTk7OdP25c+d04cKF7MoFAAAAAIDteVy6S5UqpTVr1mS6fvXq1SpVqlR25QIAAAAAwPY8Lt1dunTRSy+9pG3btrmt27p1q1555RV16dIlu/MBAAAAAGBbuT0dOHDgQH377beqXr26HnzwQZUtW1YOh0O7d+/Wd999p/vvv18DBw40Ny0AAAAAADbicen29vbW0qVL9fbbb2v27Nn6/vvvZRiGSpcurddee00DBgyQt7e3uWkBAAAAALARj0u3/i7ezz//vJ5//nnzEgEAAAAAkEN4fE43AAAAAADIGo/3dOfLl08Oh+Om406fPn27mQAAAAAAyBE8Lt3vvPOOuUkAAAAAAMhhPC7d3bt3NzcJAAAAAAA5DOd0AwAAAABgEko3AAAAAAAmoXQDAAAAAGASSjcAAAAAACbJculetWqVOUkAAAAAAMhhsly6mzVrphIlSujVV1/VH3/8YU4qAAAAAABygCyX7iNHjuiZZ57RF198oWLFiikmJkaff/65rly5Yk5CAAAAAABsKsulO3/+/IqLi9PPP/+sjRs3qkyZMnrqqacUGRmpuLg4bd261ZykAAAAAADYzG1NpFalShUNGTJETz31lM6fP6+pU6eqevXqqlevnnbu3Jl9KQEAAAAAsKFbKt0pKSn63//+pxYtWig6OlpLlizRxIkTdezYMR04cECFCxdWhw4dsj8tAAAAAAA2kjurd3j66ac1Z84cSVLXrl01fvx43Xvvvc71gYGBGjt2rIoWLZq9SQEAAAAAsJksl+5du3bp/fff1yOPPCIfH58Mx0RFRWnlypXZkQ8AAAAAANvKculevnz5zR80d241aNDgVjMBAAAAAJAjeFS6Fy1a5PEDtmnT5nbyAAAAAACQY3hUuh9++GGPHszhcCg1NfV2MwEAAAAAkCN4VLrT0tLMTwIAAAAAQA5zW9fpBgAAAAAAmbul0r18+XINGzZMffr0Ua9evVy+zHLmzBnFxsYqJCREISEhio2N1dmzZ294H8MwNGLECEVFRcnf318NGzbUzp07XcZcvnxZTz/9tAoWLKjAwEC1adNGf/75p8uYokWLyuFwuHwNGTLElNcJAAAAAMg5sly6R44cqaZNm2r58uU6efKkzpw54/Jlli5dumjL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AAAAAACwvSyX7sKFC2v58uVuy5cvX67ChQtnVy4AAAAAAGwvy4eXDx48WHFxcdqyZYvq1q0rh8Oh1atXa/r06Xr33XfNSQkAAAAAgA1luXQ/+eSTioiI0FtvvaXPP/9cklSuXDnNmzdPDz30kBkZAQAAAACwpSyXbklq27at2rZtm/1pAAAAAADIQW7pOt0AAAAAAODmPN7TXbx4cY/G7d+//3byAAAAAACQY3hcun///XdFR0erS5cuCgsLMzcVAAAAAAA5gMele+7cuZo2bZomTJig5s2bq1evXmrRooW8vDhCHQAAAACAjHjcmDt27Khvv/1W+/btU/Xq1TVw4EDdc889GjJkiPbu3WtuSgAAAAAAbCjLu6kLFSqkF198UXv37tWcOXO0fv16lS1bVmfOnDEnIQAAAAAANnVLlwy7dOmS/ve//2nq1Klav369OnTooICAgOxPBwAAAACAjWWpdK9fv15TpkzRvHnzVKJECfXq1Uvz589Xvnz5zEsIAAAAAIBNeVy6K1SooOPHj6tLly764YcfVKlSJXOTAQAAAABgcx6X7t27dyswMFAzZ87Up59+mum406dPZ1c2AAAAAABszePSPW3aNHOTAAAAAACQw3hcurt3725uEgAAAAAAcpgsXzIMAAAAAAB45pYuGQYAAAAAyCYjFlidACZiTzcAAAAAACahdAMAAAAAYBJKNwAAAAAAJsnyOd2pqamaPn26li9fruPHjystLc1l/YoVK7IzHwAAAAAAtpXl0v3MM89o+vTpatmype699145HA5zkgEAAAAAYHNZLt1z587V559/rhYtWpiTCAAAAACAHCLL53T7+PioZMmS5qQBAAAAACAHyXLpHjx4sN59910ZhmFOIgAAAAAAcogsH16+evVqrVy5Ut9++60qVKggb29vl/VffPFFduYDAAAAAMC2sly68+bNq7Zt25qTBgAAAACAHCTLpXvatGnmJAEAAAAAIIfJ8jndAAAAAADAM1ne0y1J//vf//T555/r0KFDunLlisu6n3/+ObuyAQAAAABga1ne0/3ee++pZ8+eCgsL0+bNm1WzZk0VKFBA+/fvV/Pmzc1JCQAAAACADWW5dH/wwQf6+OOPNXHiRPn4+Oj555/XsmXLFBcXp6SkJHNSAgAAAABgQ1ku3YcOHVLdunUlSf7+/jp37pwkKTY2VnPm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U/v27TVu3DgVKFAgw/sMHTpUgwYNct5OTk5W4cKFFRoaquBg/uNHzpScutvqCLaQ0R8RAZgreVOy1RFsg20UAHjGz8/Po3GWlu7+/furc+fONxxTtGhRbdu2TceOHXNbd+LECbc92enSz79OTExUZGSkc/nx48czvY+nateuLUnat29fpqXb19dXvr6+bsu9vLzk5cUxbsiZHOKQRE+wDQAswObJY2yjAMAznm4vLS3dBQsWVMGCBW86rk6dOkpKStJPP/2kmjVrSpLWr1+vpKQk1a1bN8P7FCtWTBEREVq2bJmqVq0qSbpy5YoSEhI0bty428q9efNmSXIp8wAAAAAAXM8W53SXK1dOzZo10+OPP66PPvpIkvTvf/9brVq1cplErWzZshozZozatm0rh8OhAQMG6PXXX1epUqVUqlQpvf766woICFCXLl2c90lMTFRiYqL27dsnSdq+fbuCgoJUpEgR5c+fX2vXrtW6devUqFEjhYSEaMOGDRo4cKDatGmjIkWKWPBuAAAAAADswhalW5JmzZqluLg452zkbdq00cSJE13G7NmzR0lJSc7bzz//vC5evKh+/frpzJkzqlWrlpYuXaqgoCDnmEmTJrmcV16/fn1J0rRp09SjRw/5+vpq3rx5GjlypC5fvqzo6Gg9/vjjev755/+BVw0AAAAAsDOHYRiG1SHuBsnJyQoJCVFSUhITqSHH2ju7mNURbKFUlwNWRwDuOiMdN564Ff9nuDHc6ggAYAuedjxmygAAAAAAwCSUbgAAAAAATELpBgAAAADAJJRuAAAAAABMQukGAAAAAMAklG4AAAAAAExC6QYAAAAAwCSUbgAAAAAATELpBgAAAADAJJRuAAAAAABMQukGAAAAAMAklG4AAAAAAExC6QYAAAAAwCSUbgAAAAAATELpBgAAAADAJJRuAAAAAABMQukGAAAAAMAklG4AAAAAAExC6QYAAAAAwCSUbgAAAAAATJLb6gAAAABmG24MtzoCAOAuxZ5uAAAAAABMQukGAAAAAMAklG4AAAAAAExC6QYAAAAAwCSUbgAAAAAATELpBgAAAADAJJRuAAAAAABMQukGAAAAAMAklG4AAAAAAExC6QYAAAAAwCSUbgAAAAAATELpBgAAAADAJJRuAAAAAABMQukGAAAAAMAklG4AAAAAAExC6QYAAAAAwCSUbgAA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Tp486bbO4XAoNTXVklywp4iICC1ZskSVK1dWUFCQtm7dquLFi+vAgQOqWLGi/vrrL6sjwoauXr2qxYsXa/r06fr2229VqlQp9e7dW7GxsQoNDbU6Hu5wXl5ecjgcNxxjGAb/5yHLTp8+rc8++0zTp0/Xtm3b9MADD6h37956+OGH5ePjY3U82Ex0dLTmzZun2rVru/wOtW/fPlWrVo0/DN4GSjcsV7JkScXExOiVV15ReHi41XFgc0FBQfr5559VqlQpl/8wNmzYoGbNmunUqVNWR4SNXb58WR988IGGDh2qK1euyNvbW506ddK4ceMUGRlpdTzcoRISEjwe26BBA1OzIOfasmWLpk6dqjlz5igtLU2PPfaYevfurcqVK1sdDTYREBCgHTt2qHjx4i6/Q23dulX169dXUlKS1RFti9INywUHB2vz5s0qUaKE1VGQA7Rs2VLVqlXT6NGjFRQUpG3btik6OlqdO3dWWlqa/ve//1kdETa0ceNGTZ06VXPnzlVgYKC6d++u3r1768iRI3rllVd07tw5DjsHYLkjR47o448/1tixY5U7d25dunRJderU0aRJk1ShQgWr4+EO16BBA7Vv315PP/2083eoYsWKqX///tq3bx+n6d2G3FYHANq3b69Vq1ZRupEt3njjDTVs2FAbN27UlStX9Pzzz2vnzp06ffq0fvzxR6vjwWYmTJigadOmac+ePWrRooVmzpypFi1ayMvr/0+JUqxYMX300UcqW7as1VFhI2fPntWUKVO0e/duORwOlS9fXr169VJISIjV0WBDKSkpWrhwoaZOnaply5apRo0amjhxoh599FGdPn1aL7zwgjp06KBdu3ZZHRV3uDFjxqhZs2batWuXrl69qnfffVc7d+7U2rVrs3TEDtyxpxuWu3Dhgjp06KDQ0FBVrFhR3t7eLuvj4uIsywZ7SkxM1IcffqhNmzYpLS1N1apV01NPPcXhv8iyUqVKqVevXurZs6ciIiIyHHPlyhXNmTNH3bt3/8fzwX42btyomJgY+fv7q2bNmjIMQxs3btTFixe1dOlSVatWzeqIsJGnn35ac+bMkSR17dpVffr00b333usy5tChQypatKjS0tIsSgk72b59u958802X36FeeOEFVaxY0epotkbphuUmT56svn37yt/fXwUKFHCZbMbhcGj//v2W5gNw9/r9999V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",
"text/plain": [
"<Figure size 1000x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\"\"\"\n",
"==================================\n",
"Compare IC: momentum-only vs. 4-factor composite vs. individual factors\n",
"==================================\n",
"\"\"\"\n",
"def compute_monthly_ic(factor_df, return_df):\n",
" common_dates = factor_df.index.intersection(return_df.index)\n",
" common_tickers = factor_df.columns.intersection(return_df.columns)\n",
" ic_series = []\n",
" for date in common_dates:\n",
" f = factor_df.loc[date, common_tickers]\n",
" r = return_df.loc[date, common_tickers]\n",
" mask = f.notna() & r.notna()\n",
" if mask.sum() < 20:\n",
" ic_series.append(np.nan)\n",
" continue\n",
" ic, _ = spearmanr(f[mask], r[mask])\n",
" ic_series.append(ic)\n",
" return pd.Series(ic_series, index=common_dates)\n",
"\n",
"# Compute IC for all signals\n",
"ic_compare = {}\n",
"for name in factor_names:\n",
" ic_compare[name] = compute_monthly_ic(factor_neut[name], df_returns)\n",
"ic_compare['momentum_only'] = compute_monthly_ic(df_momentum_signal, df_returns)\n",
"ic_compare['4factor_composite'] = compute_monthly_ic(df_composite_4f, df_returns)\n",
"\n",
"df_ic_compare = pd.DataFrame(ic_compare)\n",
"\n",
"summary = df_ic_compare.describe().T[['mean', 'std']]\n",
"summary['ic_ir'] = summary['mean'] / summary['std'] * np.sqrt(12)\n",
"summary = summary.round(4)\n",
"\n",
"print(\"IC Comparison: Neutralized Factors, Momentum-Only, and 4-Factor Composite\\n\")\n",
"display(summary)\n",
"\n",
"fig, ax = plt.subplots(figsize=(10, 6))\n",
"colors = ['coral', 'goldenrod', 'seagreen', 'purple', 'steelblue', 'coral']\n",
"summary['mean'].plot(kind='bar', ax=ax, color=['coral', 'goldenrod', 'seagreen', 'purple', 'steelblue', 'coral'])\n",
"ax.set_ylabel('Mean Monthly IC')\n",
"ax.set_title('Mean IC: Momentum-Only vs. Composite vs. Individual Factors')\n",
"ax.axhline(y=0, color='black', linewidth=0.5)\n",
"ax.grid(alpha=0.3, axis='y')\n",
"\n",
"plt.tight_layout()\n",
"plt.savefig('../images/03_factor_construction/composite_vs_single_ic.png', dpi=150, bbox_inches='tight')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "9c9cc628",
"metadata": {
"execution": {
"iopub.execute_input": "2026-07-31T11:08:58.702363Z",
"iopub.status.busy": "2026-07-31T11:08:58.702180Z",
"iopub.status.idle": "2026-07-31T11:08:59.630835Z",
"shell.execute_reply": "2026-07-31T11:08:59.630226Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Saved:\n",
" - momentum_signal.csv (momentum-only, sector-neutralized)\n",
" - composite_4factor.csv (4-factor equal-weight — comparison only)\n",
" - factor_momentum_neutralized.csv\n",
" - factor_value_neutralized.csv\n",
" - factor_quality_neutralized.csv\n",
" - factor_lowvol_neutralized.csv\n"
]
}
],
"source": [
"\"\"\"\n",
"==================================\n",
"Save signals and neutralized factors\n",
"==================================\n",
"\"\"\"\n",
"# The headline signal: momentum-only, sector-neutralized\n",
"df_momentum_signal.to_csv('../data/processed/momentum_signal.csv')\n",
"\n",
"# The 4-factor composite: kept for comparison\n",
"df_composite_4f.to_csv('../data/processed/composite_4factor.csv')\n",
"\n",
"# Individual neutralized factors\n",
"for name in factor_names:\n",
" factor_neut[name].to_csv(f'../data/processed/factor_{name}_neutralized.csv')\n",
"\n",
"print(\"Saved:\")\n",
"print(\" - momentum_signal.csv (momentum-only, sector-neutralized)\")\n",
"print(\" - composite_4factor.csv (4-factor equal-weight — comparison only)\")\n",
"for name in factor_names:\n",
" print(f\" - factor_{name}_neutralized.csv\")"
]
},
{
"cell_type": "markdown",
"id": "daab87e7",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"The comparison supports a simple choice: use **momentum-only, sector-neutralized** as the headline signal.\n",
"\n",
"- Sector neutralization slightly improves the momentum IC.\n",
"- The equal-weight four-factor composite is worse, because it mixes momentum with weak or negative proxy signals.\n",
"- The result is also easier to explain: rank stocks by momentum within a sector-neutral framework, then trade the top decile.\n",
"\n",
"Notebook 04 turns this signal into portfolio weights and asks whether it produces returns net of transaction costs."
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}