1658 lines
111 KiB
Plaintext
1658 lines
111 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "4ed31fb1",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002903,
|
|
"end_time": "2026-06-13T03:12:14.622921+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:14.620018+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"# Case Study Overview: Cross-Strategy Summary\n",
|
|
"\n",
|
|
"**ML4T Third Edition - Chapter 6: Strategy Definition**\n",
|
|
"\n",
|
|
"**Docker image**: `ml4t`\n",
|
|
"\n",
|
|
"This notebook provides a unified view of all 9 case studies used throughout this book.\n",
|
|
"It consolidates key information that readers need to understand:\n",
|
|
"\n",
|
|
"- **What datasets we cover**: Asset classes, universes, and time periods\n",
|
|
"- **Trading setup constraints**: Cost models, horizons, and feasibility analysis\n",
|
|
"- **Evaluation protocols**: Walk-forward configurations and holdout policies\n",
|
|
"- **Prediction coverage**: Calendar-year spans for training, validation, and holdout\n",
|
|
"\n",
|
|
"**Book Reference**: Chapter 6, Sections 6.3 and 6.5\n",
|
|
"\n",
|
|
"**Prerequisites**: Each case study must have a `config/setup.yaml` defining\n",
|
|
"the trading setup, universe, evaluation protocol, and cost model."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "e51bdb19",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:14.629102Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:14.628931Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.595991Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.595533Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 2.971566,
|
|
"end_time": "2026-06-13T03:12:17.596868+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:14.625302+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"\"\"\"Case Study Overview: Cross-strategy summary for Chapter 6.\"\"\"\n",
|
|
"\n",
|
|
"import warnings\n",
|
|
"from typing import Any\n",
|
|
"\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"import polars as pl\n",
|
|
"import yaml\n",
|
|
"from matplotlib.patches import Patch\n",
|
|
"\n",
|
|
"from utils.paths import REPO_ROOT\n",
|
|
"\n",
|
|
"warnings.filterwarnings(\"ignore\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "412d139c",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.603806Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.603661Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.605592Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.605186Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.005542,
|
|
"end_time": "2026-06-13T03:12:17.606000+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.600458+00:00",
|
|
"status": "completed"
|
|
},
|
|
"tags": [
|
|
"parameters"
|
|
]
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Production defaults — Papermill injects overrides for CI\n",
|
|
"MAX_SYMBOLS = 0 # 0 = all"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "e8ecf592",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.611282Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.610969Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.613405Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.613074Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.00549,
|
|
"end_time": "2026-06-13T03:12:17.613673+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.608183+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"CASE_STUDIES_DIR = REPO_ROOT / \"case_studies\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6a31e2b5",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002192,
|
|
"end_time": "2026-06-13T03:12:17.618211+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.616019+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"## Load Results\n",
|
|
"\n",
|
|
"Each case study's `config/setup.yaml` defines the trading setup, universe,\n",
|
|
"evaluation protocol, and cost model. We load all available configs and build\n",
|
|
"comparative tables from them."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "34028805",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.623269Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.623116Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.625721Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.625186Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.005937,
|
|
"end_time": "2026-06-13T03:12:17.626044+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.620107+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Display names and chapter tracks — book-structural metadata, not per-run data\n",
|
|
"DISPLAY_NAMES = {\n",
|
|
" \"etfs\": \"ETFs\",\n",
|
|
" \"crypto_perps_funding\": \"Crypto Perps Funding\",\n",
|
|
" \"nasdaq100_microstructure\": \"NASDAQ-100 Microstructure\",\n",
|
|
" \"sp500_equity_option_analytics\": \"S&P 500 Equity+Options\",\n",
|
|
" \"us_firm_characteristics\": \"US Firm Characteristics\",\n",
|
|
" \"fx_pairs\": \"FX Pairs\",\n",
|
|
" \"cme_futures\": \"CME Futures\",\n",
|
|
" \"sp500_options\": \"S&P 500 Options\",\n",
|
|
" \"us_equities_panel\": \"US Equities Panel\",\n",
|
|
"}\n",
|
|
"\n",
|
|
"CHAPTER_TRACKS = {\n",
|
|
" \"etfs\": \"Ch6 to Ch21\",\n",
|
|
" \"crypto_perps_funding\": \"Ch6 to Ch12\",\n",
|
|
" \"nasdaq100_microstructure\": \"Ch6 to Ch12\",\n",
|
|
" \"sp500_equity_option_analytics\": \"Ch6 to Ch21\",\n",
|
|
" \"us_firm_characteristics\": \"Ch6 to Ch14\",\n",
|
|
" \"fx_pairs\": \"Ch6 to Ch17\",\n",
|
|
" \"cme_futures\": \"Ch6 to Ch17\",\n",
|
|
" \"sp500_options\": \"Ch6 to Ch21\",\n",
|
|
" \"us_equities_panel\": \"Ch6 to Ch14\",\n",
|
|
"}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "d7dd0dae",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.631744Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.631521Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.635229Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.634831Z"
|
|
},
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.007072,
|
|
"end_time": "2026-06-13T03:12:17.635579+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.628507+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def _normalize_setup_yaml(case_id: str, cfg: dict) -> dict:\n",
|
|
" \"\"\"Convert setup.yaml structure to the summary/diagnostics format the notebook expects.\"\"\"\n",
|
|
" universe = cfg.get(\"universe\", {})\n",
|
|
" decision = cfg.get(\"decision\", {})\n",
|
|
" costs = cfg.get(\"costs\", {})\n",
|
|
" ev = cfg.get(\"evaluation\", {})\n",
|
|
" mapping = cfg.get(\"mapping\", {})\n",
|
|
"\n",
|
|
" n_assets = universe.get(\"n_assets\", 0) or universe.get(\"n_products\", 0)\n",
|
|
" if not n_assets:\n",
|
|
" n_assets = len(universe.get(\"assets\", universe.get(\"symbols\", [])))\n",
|
|
"\n",
|
|
" # Decision cadence — case studies use different keys: `cadence`,\n",
|
|
" # `entry_cadence` (sp500_options), or `bar_frequency` (microstructure).\n",
|
|
" cadence = (\n",
|
|
" decision.get(\"cadence\")\n",
|
|
" or decision.get(\"entry_cadence\")\n",
|
|
" or decision.get(\"bar_frequency\")\n",
|
|
" or \"\"\n",
|
|
" )\n",
|
|
" freq_map = {\n",
|
|
" \"monthly_month_end\": \"Daily\",\n",
|
|
" \"8_hour_funding_aligned\": \"8-hourly\",\n",
|
|
" \"daily_close\": \"Daily\",\n",
|
|
" \"daily_ny_close\": \"Daily\",\n",
|
|
" \"weekly_friday_close\": \"Weekly\",\n",
|
|
" \"weekly_friday\": \"Weekly\",\n",
|
|
" \"15_minute\": \"15-min\",\n",
|
|
" \"15_min\": \"15-min\",\n",
|
|
" }\n",
|
|
" data_freq = freq_map.get(cadence, cadence)\n",
|
|
"\n",
|
|
" holdout_start = ev.get(\"holdout_start\", \"\")\n",
|
|
" holdout_end = ev.get(\"holdout_end\", \"\")\n",
|
|
"\n",
|
|
" return {\n",
|
|
" \"summary\": {\n",
|
|
" \"asset_class\": _infer_asset_class(case_id),\n",
|
|
" \"universe_size\": n_assets,\n",
|
|
" \"data_frequency\": data_freq,\n",
|
|
" \"decision_cadence\": cadence.replace(\"_\", \" \"),\n",
|
|
" \"cost_model\": costs.get(\"class\", \"\"),\n",
|
|
" },\n",
|
|
" \"diagnostics\": {\n",
|
|
" \"train_size\": ev.get(\"train_size\", \"N/A\"),\n",
|
|
" \"test_size\": ev.get(\"val_size\", \"N/A\"),\n",
|
|
" \"n_splits\": ev.get(\"n_splits\", 0),\n",
|
|
" \"holdout_start\": holdout_start,\n",
|
|
" \"holdout_end\": holdout_end,\n",
|
|
" },\n",
|
|
" \"techniques\": {\n",
|
|
" \"setup_type\": mapping.get(\"class\", \"\"),\n",
|
|
" \"position_mapping\": mapping.get(\"entry_logic\", \"\"),\n",
|
|
" },\n",
|
|
" }"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9bd34cc2",
|
|
"metadata": {
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.002362,
|
|
"end_time": "2026-06-13T03:12:17.640182+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.637820+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Infer Asset Class"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "c7f38a01",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.646442Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.646306Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.649213Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.648450Z"
|
|
},
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.006814,
|
|
"end_time": "2026-06-13T03:12:17.649624+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.642810+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def _infer_asset_class(case_id: str) -> str:\n",
|
|
" \"\"\"Infer asset class from case study ID.\"\"\"\n",
|
|
" mapping = {\n",
|
|
" \"etfs\": \"Multi-Asset\",\n",
|
|
" \"crypto_perps_funding\": \"Crypto\",\n",
|
|
" \"nasdaq100_microstructure\": \"Equities\",\n",
|
|
" \"sp500_equity_option_analytics\": \"Equities+Options\",\n",
|
|
" \"us_firm_characteristics\": \"Equities\",\n",
|
|
" \"fx_pairs\": \"FX\",\n",
|
|
" \"cme_futures\": \"Futures\",\n",
|
|
" \"sp500_options\": \"Options\",\n",
|
|
" \"us_equities_panel\": \"Equities\",\n",
|
|
" }\n",
|
|
" return mapping.get(case_id, \"Unknown\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2a59b4d0",
|
|
"metadata": {
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.002559,
|
|
"end_time": "2026-06-13T03:12:17.655131+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.652572+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Load All Case Study Configs"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "43226501",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.660939Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.660796Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.663535Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.663094Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.006454,
|
|
"end_time": "2026-06-13T03:12:17.664096+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.657642+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def load_setup_results() -> dict[str, dict]:\n",
|
|
" \"\"\"Load config/setup.yaml from all case studies.\"\"\"\n",
|
|
" results = {}\n",
|
|
" for case_dir in sorted(CASE_STUDIES_DIR.iterdir()):\n",
|
|
" if case_dir.name.startswith(\"_\") or not case_dir.is_dir():\n",
|
|
" continue\n",
|
|
" setup_path = case_dir / \"config\" / \"setup.yaml\"\n",
|
|
" if not setup_path.exists():\n",
|
|
" continue\n",
|
|
" cfg = yaml.safe_load(setup_path.read_text())\n",
|
|
" results[case_dir.name] = _normalize_setup_yaml(case_dir.name, cfg)\n",
|
|
" return results"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "eb39e9f8",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.670237Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.670033Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.728031Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.727370Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.061904,
|
|
"end_time": "2026-06-13T03:12:17.728547+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.666643+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Loaded results for 9/9 case studies\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"all_results = load_setup_results()\n",
|
|
"print(f\"Loaded results for {len(all_results)}/{len(DISPLAY_NAMES)} case studies\")\n",
|
|
"\n",
|
|
"if len(all_results) < len(DISPLAY_NAMES):\n",
|
|
" missing = set(DISPLAY_NAMES) - set(all_results)\n",
|
|
" print(f\"Missing: {', '.join(sorted(missing))}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b5b7b704",
|
|
"metadata": {
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.002199,
|
|
"end_time": "2026-06-13T03:12:17.733259+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.731060+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"## Helper: Window Conversion"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "6bc6a289",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.738786Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.738535Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.741942Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.741476Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.006722,
|
|
"end_time": "2026-06-13T03:12:17.742255+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.735533+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def _window_to_years(value: Any) -> float | None:\n",
|
|
" \"\"\"Convert window spec to years.\n",
|
|
"\n",
|
|
" Supports numeric trading days or strings like 6M, 2Q, 10D, 26W, 1Y.\n",
|
|
" \"\"\"\n",
|
|
" if value is None:\n",
|
|
" return None\n",
|
|
" if isinstance(value, (int, float)):\n",
|
|
" return float(value) / 252.0\n",
|
|
" if isinstance(value, str):\n",
|
|
" s = value.strip().upper()\n",
|
|
" if s.startswith(\"P\"): # ISO 8601 duration prefix used by some configs\n",
|
|
" s = s[1:]\n",
|
|
" try:\n",
|
|
" if s.endswith(\"Y\"):\n",
|
|
" return float(s[:-1])\n",
|
|
" if s.endswith(\"Q\"):\n",
|
|
" return float(s[:-1]) * 0.25\n",
|
|
" if s.endswith(\"M\"):\n",
|
|
" return float(s[:-1]) / 12.0\n",
|
|
" if s.endswith(\"W\"):\n",
|
|
" return float(s[:-1]) / 52.0\n",
|
|
" if s.endswith(\"D\"):\n",
|
|
" return float(s[:-1]) / 252.0\n",
|
|
" except ValueError:\n",
|
|
" return None\n",
|
|
" return None"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9e3f6ecf",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001817,
|
|
"end_time": "2026-06-13T03:12:17.746515+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.744698+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## 1. Case Study Inventory\n",
|
|
"\n",
|
|
"The book uses 9 case studies that span different asset classes, frequencies,\n",
|
|
"and time horizons. This diversity demonstrates how the same ML4T workflow\n",
|
|
"adapts to different trading contexts."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "e549b613",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.751073Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.750937Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.756867Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.756537Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.008978,
|
|
"end_time": "2026-06-13T03:12:17.757296+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.748318+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div><style>\n",
|
|
".dataframe > thead > tr,\n",
|
|
".dataframe > tbody > tr {\n",
|
|
" text-align: right;\n",
|
|
" white-space: pre-wrap;\n",
|
|
"}\n",
|
|
"</style>\n",
|
|
"<small>shape: (9, 6)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Case Study</th><th>Asset Class</th><th>Universe</th><th>Data Freq</th><th>Decision</th><th>Cost Model</th></tr><tr><td>str</td><td>str</td><td>i64</td><td>str</td><td>str</td><td>str</td></tr></thead><tbody><tr><td>"CME Futures"</td><td>"Futures"</td><td>30</td><td>"Weekly"</td><td>"weekly friday close"</td><td>"material"</td></tr><tr><td>"Crypto Perps Funding"</td><td>"Crypto"</td><td>19</td><td>"8-hourly"</td><td>"8 hour funding aligned"</td><td>"material"</td></tr><tr><td>"ETFs"</td><td>"Multi-Asset"</td><td>100</td><td>"Daily"</td><td>"monthly month end"</td><td>"material"</td></tr><tr><td>"FX Pairs"</td><td>"FX"</td><td>20</td><td>"Daily"</td><td>"daily ny close"</td><td>"material"</td></tr><tr><td>"NASDAQ-100 Microstructure"</td><td>"Equities"</td><td>114</td><td>"15-min"</td><td>"15 minute"</td><td>"dominant"</td></tr><tr><td>"S&P 500 Equity+Options"</td><td>"Equities+Options"</td><td>633</td><td>"Weekly"</td><td>"weekly friday close"</td><td>"material"</td></tr><tr><td>"S&P 500 Options"</td><td>"Options"</td><td>0</td><td>"Weekly"</td><td>"weekly friday"</td><td>"dominant"</td></tr><tr><td>"US Equities Panel"</td><td>"Equities"</td><td>3199</td><td>"Daily"</td><td>"daily close"</td><td>"material"</td></tr><tr><td>"US Firm Characteristics"</td><td>"Equities"</td><td>0</td><td>"Daily"</td><td>"monthly month end"</td><td>"material"</td></tr></tbody></table></div>"
|
|
],
|
|
"text/plain": [
|
|
"shape: (9, 6)\n",
|
|
"┌─────────────────────┬──────────────────┬──────────┬───────────┬─────────────────────┬────────────┐\n",
|
|
"│ Case Study ┆ Asset Class ┆ Universe ┆ Data Freq ┆ Decision ┆ Cost Model │\n",
|
|
"│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n",
|
|
"│ str ┆ str ┆ i64 ┆ str ┆ str ┆ str │\n",
|
|
"╞═════════════════════╪══════════════════╪══════════╪═══════════╪═════════════════════╪════════════╡\n",
|
|
"│ CME Futures ┆ Futures ┆ 30 ┆ Weekly ┆ weekly friday close ┆ material │\n",
|
|
"│ Crypto Perps ┆ Crypto ┆ 19 ┆ 8-hourly ┆ 8 hour funding ┆ material │\n",
|
|
"│ Funding ┆ ┆ ┆ ┆ aligned ┆ │\n",
|
|
"│ ETFs ┆ Multi-Asset ┆ 100 ┆ Daily ┆ monthly month end ┆ material │\n",
|
|
"│ FX Pairs ┆ FX ┆ 20 ┆ Daily ┆ daily ny close ┆ material │\n",
|
|
"│ NASDAQ-100 ┆ Equities ┆ 114 ┆ 15-min ┆ 15 minute ┆ dominant │\n",
|
|
"│ Microstructure ┆ ┆ ┆ ┆ ┆ │\n",
|
|
"│ S&P 500 ┆ Equities+Options ┆ 633 ┆ Weekly ┆ weekly friday close ┆ material │\n",
|
|
"│ Equity+Options ┆ ┆ ┆ ┆ ┆ │\n",
|
|
"│ S&P 500 Options ┆ Options ┆ 0 ┆ Weekly ┆ weekly friday ┆ dominant │\n",
|
|
"│ US Equities Panel ┆ Equities ┆ 3199 ┆ Daily ┆ daily close ┆ material │\n",
|
|
"│ US Firm ┆ Equities ┆ 0 ┆ Daily ┆ monthly month end ┆ material │\n",
|
|
"│ Characteristics ┆ ┆ ┆ ┆ ┆ │\n",
|
|
"└─────────────────────┴──────────────────┴──────────┴───────────┴─────────────────────┴────────────┘"
|
|
]
|
|
},
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"overview_rows = []\n",
|
|
"for case_id, r in all_results.items():\n",
|
|
" s = r.get(\"summary\", {})\n",
|
|
" overview_rows.append(\n",
|
|
" {\n",
|
|
" \"Case Study\": DISPLAY_NAMES.get(case_id, case_id),\n",
|
|
" \"Asset Class\": s.get(\"asset_class\", \"\"),\n",
|
|
" \"Universe\": s.get(\"universe_size\", 0),\n",
|
|
" \"Data Freq\": s.get(\"data_frequency\", \"\"),\n",
|
|
" \"Decision\": s.get(\"decision_cadence\", \"\"),\n",
|
|
" \"Cost Model\": s.get(\"cost_model\", \"\"),\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
"overview_df = pl.DataFrame(overview_rows)\n",
|
|
"overview_df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cdf98396",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001838,
|
|
"end_time": "2026-06-13T03:12:17.761078+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.759240+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"**What to notice**:\n",
|
|
"- Universe sizes range widely: from 19 (Crypto) and 20 (FX) to 100 (ETFs) and\n",
|
|
" 633 (S&P 500 Equity+Options), affecting cross-sectional signal construction\n",
|
|
"- Data frequencies span 15-minute bars (NASDAQ-100) to weekly (CME Futures, S&P 500)\n",
|
|
"- Cost models are either \"Material\" (7 case studies) or \"Dominant\" (2),\n",
|
|
" where dominant costs require exceptionally strong signals"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b10d3648",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001825,
|
|
"end_time": "2026-06-13T03:12:17.764629+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.762804+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Asset Class Distribution"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "d1f4413c",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.769589Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.769451Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.773443Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.773017Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.00784,
|
|
"end_time": "2026-06-13T03:12:17.774295+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.766455+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div><style>\n",
|
|
".dataframe > thead > tr,\n",
|
|
".dataframe > tbody > tr {\n",
|
|
" text-align: right;\n",
|
|
" white-space: pre-wrap;\n",
|
|
"}\n",
|
|
"</style>\n",
|
|
"<small>shape: (7, 2)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Asset Class</th><th>Count</th></tr><tr><td>str</td><td>i64</td></tr></thead><tbody><tr><td>"Equities"</td><td>3</td></tr><tr><td>"Futures"</td><td>1</td></tr><tr><td>"Crypto"</td><td>1</td></tr><tr><td>"Multi-Asset"</td><td>1</td></tr><tr><td>"FX"</td><td>1</td></tr><tr><td>"Equities+Options"</td><td>1</td></tr><tr><td>"Options"</td><td>1</td></tr></tbody></table></div>"
|
|
],
|
|
"text/plain": [
|
|
"shape: (7, 2)\n",
|
|
"┌──────────────────┬───────┐\n",
|
|
"│ Asset Class ┆ Count │\n",
|
|
"│ --- ┆ --- │\n",
|
|
"│ str ┆ i64 │\n",
|
|
"╞══════════════════╪═══════╡\n",
|
|
"│ Equities ┆ 3 │\n",
|
|
"│ Futures ┆ 1 │\n",
|
|
"│ Crypto ┆ 1 │\n",
|
|
"│ Multi-Asset ┆ 1 │\n",
|
|
"│ FX ┆ 1 │\n",
|
|
"│ Equities+Options ┆ 1 │\n",
|
|
"│ Options ┆ 1 │\n",
|
|
"└──────────────────┴───────┘"
|
|
]
|
|
},
|
|
"execution_count": 11,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"asset_counts: dict[str, int] = {}\n",
|
|
"for r in all_results.values():\n",
|
|
" ac = r.get(\"summary\", {}).get(\"asset_class\", \"Unknown\")\n",
|
|
" asset_counts[ac] = asset_counts.get(ac, 0) + 1\n",
|
|
"\n",
|
|
"asset_df = pl.DataFrame(\n",
|
|
" [\n",
|
|
" {\"Asset Class\": ac, \"Count\": count}\n",
|
|
" for ac, count in sorted(asset_counts.items(), key=lambda x: -x[1])\n",
|
|
" ]\n",
|
|
")\n",
|
|
"asset_df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6005f036",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001956,
|
|
"end_time": "2026-06-13T03:12:17.779745+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.777789+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"**What to notice**:\n",
|
|
"- Equities dominate (3 pure + 1 hybrid), reflecting their importance in ML4T\n",
|
|
"- \"Equities+Options\" is a hybrid: trades equities using options-derived features\n",
|
|
"- Each non-equity asset class (Crypto, FX, Futures, Options, Multi-Asset) has\n",
|
|
" one dedicated case study showing unique mechanics"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d1257f47",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001701,
|
|
"end_time": "2026-06-13T03:12:17.783189+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.781488+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## 2. Evaluation Protocol Summary\n",
|
|
"\n",
|
|
"Each case study defines a walk-forward evaluation protocol. The key parameters are:\n",
|
|
"- **Training window**: How much history to use for model fitting\n",
|
|
"- **Test window**: Validation fold duration\n",
|
|
"- **Holdout period**: Sealed data for final confirmation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "2c7c1261",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.787872Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.787742Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.792048Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.791521Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.00752,
|
|
"end_time": "2026-06-13T03:12:17.792472+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.784952+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div><style>\n",
|
|
".dataframe > thead > tr,\n",
|
|
".dataframe > tbody > tr {\n",
|
|
" text-align: right;\n",
|
|
" white-space: pre-wrap;\n",
|
|
"}\n",
|
|
"</style>\n",
|
|
"<small>shape: (9, 5)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Case Study</th><th>Train</th><th>Test</th><th>Folds</th><th>Holdout</th></tr><tr><td>str</td><td>str</td><td>str</td><td>i64</td><td>str</td></tr></thead><tbody><tr><td>"CME Futures"</td><td>"8Y"</td><td>"1Y"</td><td>5</td><td>"2024-01-01-2025-12-31"</td></tr><tr><td>"Crypto Perps Funding"</td><td>"2Y"</td><td>"1Y"</td><td>2</td><td>"2024-01-01-2025-12-31"</td></tr><tr><td>"ETFs"</td><td>"10Y"</td><td>"1Y"</td><td>8</td><td>"2024-01-01-2025-12-31"</td></tr><tr><td>"FX Pairs"</td><td>"P5Y"</td><td>"P1Y"</td><td>8</td><td>"2024-01-01-2025-12-31"</td></tr><tr><td>"NASDAQ-100 Microstructure"</td><td>"6M"</td><td>"6M"</td><td>2</td><td>"2021-07-01-2021-12-31"</td></tr><tr><td>"S&P 500 Equity+Options"</td><td>"2Y"</td><td>"1Y"</td><td>2</td><td>"2021-01-01-2021-12-31"</td></tr><tr><td>"S&P 500 Options"</td><td>"2Y"</td><td>"1Y"</td><td>2</td><td>"2021-01-01-2021-12-31"</td></tr><tr><td>"US Equities Panel"</td><td>"10Y"</td><td>"1Y"</td><td>16</td><td>"2016-01-01-2018-03-31"</td></tr><tr><td>"US Firm Characteristics"</td><td>"10Y"</td><td>"1Y"</td><td>10</td><td>"2016-01-01-2016-12-31"</td></tr></tbody></table></div>"
|
|
],
|
|
"text/plain": [
|
|
"shape: (9, 5)\n",
|
|
"┌───────────────────────────┬───────┬──────┬───────┬───────────────────────┐\n",
|
|
"│ Case Study ┆ Train ┆ Test ┆ Folds ┆ Holdout │\n",
|
|
"│ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n",
|
|
"│ str ┆ str ┆ str ┆ i64 ┆ str │\n",
|
|
"╞═══════════════════════════╪═══════╪══════╪═══════╪═══════════════════════╡\n",
|
|
"│ CME Futures ┆ 8Y ┆ 1Y ┆ 5 ┆ 2024-01-01-2025-12-31 │\n",
|
|
"│ Crypto Perps Funding ┆ 2Y ┆ 1Y ┆ 2 ┆ 2024-01-01-2025-12-31 │\n",
|
|
"│ ETFs ┆ 10Y ┆ 1Y ┆ 8 ┆ 2024-01-01-2025-12-31 │\n",
|
|
"│ FX Pairs ┆ P5Y ┆ P1Y ┆ 8 ┆ 2024-01-01-2025-12-31 │\n",
|
|
"│ NASDAQ-100 Microstructure ┆ 6M ┆ 6M ┆ 2 ┆ 2021-07-01-2021-12-31 │\n",
|
|
"│ S&P 500 Equity+Options ┆ 2Y ┆ 1Y ┆ 2 ┆ 2021-01-01-2021-12-31 │\n",
|
|
"│ S&P 500 Options ┆ 2Y ┆ 1Y ┆ 2 ┆ 2021-01-01-2021-12-31 │\n",
|
|
"│ US Equities Panel ┆ 10Y ┆ 1Y ┆ 16 ┆ 2016-01-01-2018-03-31 │\n",
|
|
"│ US Firm Characteristics ┆ 10Y ┆ 1Y ┆ 10 ┆ 2016-01-01-2016-12-31 │\n",
|
|
"└───────────────────────────┴───────┴──────┴───────┴───────────────────────┘"
|
|
]
|
|
},
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"protocol_rows = []\n",
|
|
"for case_id, r in all_results.items():\n",
|
|
" d = r.get(\"diagnostics\", {})\n",
|
|
" ho_s = d.get(\"holdout_start\", \"?\")\n",
|
|
" ho_e = d.get(\"holdout_end\", \"?\")\n",
|
|
" protocol_rows.append(\n",
|
|
" {\n",
|
|
" \"Case Study\": DISPLAY_NAMES.get(case_id, case_id),\n",
|
|
" \"Train\": d.get(\"train_size\", \"N/A\"),\n",
|
|
" \"Test\": d.get(\"test_size\", \"N/A\"),\n",
|
|
" \"Folds\": d.get(\"n_splits\", 0),\n",
|
|
" \"Holdout\": f\"{ho_s}-{ho_e}\",\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
"protocol_df = pl.DataFrame(protocol_rows)\n",
|
|
"protocol_df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d7e92730",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001842,
|
|
"end_time": "2026-06-13T03:12:17.796301+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.794459+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"**What to notice**:\n",
|
|
"- Training windows range from 6M (microstructure) to 10Y (firm characteristics),\n",
|
|
" reflecting both data availability and stationarity assumptions\n",
|
|
"- Fold counts vary from 2 (shorter histories: crypto, microstructure, options) to 16 (US equities)\n",
|
|
"- All case studies have a sealed holdout; this discipline is non-negotiable"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "de737772",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001736,
|
|
"end_time": "2026-06-13T03:12:17.799959+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.798223+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## 3. Cost Model and Horizon Feasibility\n",
|
|
"\n",
|
|
"Trading costs constrain viable horizons. This section summarizes the cost-horizon\n",
|
|
"analysis from each setup notebook.\n",
|
|
"\n",
|
|
"### Cost Model Classes\n",
|
|
"\n",
|
|
"| Class | Description | Implication |\n",
|
|
"|-------|-------------|-------------|\n",
|
|
"| **Dominant** | Costs are first-order; small edges live near the spread | Need very strong predictability; costs dominate feasibility |\n",
|
|
"| **Material** | Costs affect profitability but don't rule out trading | Horizon choice depends on signal decay vs cost hurdle |\n",
|
|
"\n",
|
|
"The **dominant** cost regime (NASDAQ-100 microstructure, S&P 500 options) requires\n",
|
|
"unusually strong signals to overcome friction."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"id": "0a018ad8",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.804345Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.804208Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.808152Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.807609Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.006704,
|
|
"end_time": "2026-06-13T03:12:17.808440+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.801736+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div><style>\n",
|
|
".dataframe > thead > tr,\n",
|
|
".dataframe > tbody > tr {\n",
|
|
" text-align: right;\n",
|
|
" white-space: pre-wrap;\n",
|
|
"}\n",
|
|
"</style>\n",
|
|
"<small>shape: (9, 3)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Case Study</th><th>Cost Class</th><th>Decision Cadence</th></tr><tr><td>str</td><td>str</td><td>str</td></tr></thead><tbody><tr><td>"CME Futures"</td><td>"material"</td><td>"weekly friday close"</td></tr><tr><td>"Crypto Perps Funding"</td><td>"material"</td><td>"8 hour funding aligned"</td></tr><tr><td>"ETFs"</td><td>"material"</td><td>"monthly month end"</td></tr><tr><td>"FX Pairs"</td><td>"material"</td><td>"daily ny close"</td></tr><tr><td>"NASDAQ-100 Microstructure"</td><td>"dominant"</td><td>"15 minute"</td></tr><tr><td>"S&P 500 Equity+Options"</td><td>"material"</td><td>"weekly friday close"</td></tr><tr><td>"S&P 500 Options"</td><td>"dominant"</td><td>"weekly friday"</td></tr><tr><td>"US Equities Panel"</td><td>"material"</td><td>"daily close"</td></tr><tr><td>"US Firm Characteristics"</td><td>"material"</td><td>"monthly month end"</td></tr></tbody></table></div>"
|
|
],
|
|
"text/plain": [
|
|
"shape: (9, 3)\n",
|
|
"┌───────────────────────────┬────────────┬────────────────────────┐\n",
|
|
"│ Case Study ┆ Cost Class ┆ Decision Cadence │\n",
|
|
"│ --- ┆ --- ┆ --- │\n",
|
|
"│ str ┆ str ┆ str │\n",
|
|
"╞═══════════════════════════╪════════════╪════════════════════════╡\n",
|
|
"│ CME Futures ┆ material ┆ weekly friday close │\n",
|
|
"│ Crypto Perps Funding ┆ material ┆ 8 hour funding aligned │\n",
|
|
"│ ETFs ┆ material ┆ monthly month end │\n",
|
|
"│ FX Pairs ┆ material ┆ daily ny close │\n",
|
|
"│ NASDAQ-100 Microstructure ┆ dominant ┆ 15 minute │\n",
|
|
"│ S&P 500 Equity+Options ┆ material ┆ weekly friday close │\n",
|
|
"│ S&P 500 Options ┆ dominant ┆ weekly friday │\n",
|
|
"│ US Equities Panel ┆ material ┆ daily close │\n",
|
|
"│ US Firm Characteristics ┆ material ┆ monthly month end │\n",
|
|
"└───────────────────────────┴────────────┴────────────────────────┘"
|
|
]
|
|
},
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"cost_rows = []\n",
|
|
"for case_id, r in all_results.items():\n",
|
|
" s = r.get(\"summary\", {})\n",
|
|
" cost_rows.append(\n",
|
|
" {\n",
|
|
" \"Case Study\": DISPLAY_NAMES.get(case_id, case_id),\n",
|
|
" \"Cost Class\": s.get(\"cost_model\", \"\"),\n",
|
|
" \"Decision Cadence\": s.get(\"decision_cadence\", \"\"),\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
"cost_df = pl.DataFrame(cost_rows)\n",
|
|
"cost_df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "8b0e5070",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001921,
|
|
"end_time": "2026-06-13T03:12:17.812307+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.810386+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"**What to notice**:\n",
|
|
"- FX majors have the tightest spreads (1-3 bps per leg; crosses 3-8 bps),\n",
|
|
" enabling daily horizons — see `case_studies/fx_pairs/config/setup.yaml`\n",
|
|
"- Options spreads are wide relative to premium (2-5%), making costs the binding constraint\n",
|
|
"- Horizon choice aligns with cost: higher costs push toward longer holding periods"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ef570334",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002066,
|
|
"end_time": "2026-06-13T03:12:17.816214+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.814148+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## 4. Prediction Coverage Across Case Studies\n",
|
|
"\n",
|
|
"This figure shows the calendar-year data spans for all 9 case studies,\n",
|
|
"highlighting training, validation, and holdout periods."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "934b13e4",
|
|
"metadata": {
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.002364,
|
|
"end_time": "2026-06-13T03:12:17.820710+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.818346+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Compute Coverage"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"id": "7c2f2fb8",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.826946Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.826795Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.832621Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.831900Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.009839,
|
|
"end_time": "2026-06-13T03:12:17.833229+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.823390+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def compute_coverage(results: dict[str, dict]) -> list[dict]:\n",
|
|
" \"\"\"Compute prediction coverage spans from results JSON data.\"\"\"\n",
|
|
" coverage_data = []\n",
|
|
"\n",
|
|
" for case_id, r in results.items():\n",
|
|
" d = r.get(\"diagnostics\", {})\n",
|
|
"\n",
|
|
" holdout_start = d.get(\"holdout_start\")\n",
|
|
" holdout_end = d.get(\"holdout_end\")\n",
|
|
" try:\n",
|
|
" holdout_start_year = int(str(holdout_start)[:4]) if holdout_start else None\n",
|
|
" holdout_end_year = int(str(holdout_end)[:4]) if holdout_end else None\n",
|
|
" except (ValueError, TypeError):\n",
|
|
" continue\n",
|
|
"\n",
|
|
" if holdout_start_year is None or holdout_end_year is None:\n",
|
|
" continue\n",
|
|
"\n",
|
|
" n_splits = d.get(\"n_splits\", 5)\n",
|
|
" test_size = d.get(\"test_size\", \"1Y\")\n",
|
|
"\n",
|
|
" test_years = _window_to_years(test_size)\n",
|
|
" if test_years is None:\n",
|
|
" test_years = 1.0\n",
|
|
"\n",
|
|
" val_span = n_splits * test_years\n",
|
|
" val_start_year = holdout_start_year - val_span\n",
|
|
"\n",
|
|
" # Training starts before validation by the training window size\n",
|
|
" train_size = d.get(\"train_size\", \"1Y\")\n",
|
|
" train_years = _window_to_years(train_size)\n",
|
|
" if train_years is None:\n",
|
|
" train_years = 1.0\n",
|
|
" data_start_year = val_start_year - train_years\n",
|
|
"\n",
|
|
" coverage_data.append(\n",
|
|
" {\n",
|
|
" \"id\": case_id,\n",
|
|
" \"name\": DISPLAY_NAMES.get(case_id, case_id),\n",
|
|
" \"data_start\": data_start_year,\n",
|
|
" \"val_start\": val_start_year,\n",
|
|
" \"holdout_start\": holdout_start_year,\n",
|
|
" \"holdout_end\": holdout_end_year,\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
" coverage_data.sort(key=lambda x: (x[\"data_start\"], x[\"name\"]))\n",
|
|
" return coverage_data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"id": "014d88eb",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.841301Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.841171Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.844203Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.843666Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.00782,
|
|
"end_time": "2026-06-13T03:12:17.844788+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.836968+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"case_studies_coverage = compute_coverage(all_results)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6c064794",
|
|
"metadata": {
|
|
"lines_to_next_cell": 2,
|
|
"papermill": {
|
|
"duration": 0.003569,
|
|
"end_time": "2026-06-13T03:12:17.852284+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.848715+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Coverage Figure"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"id": "0f664849",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.860764Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.860623Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:17.866049Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:17.865161Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.010222,
|
|
"end_time": "2026-06-13T03:12:17.866729+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.856507+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def plot_coverage(coverage_data):\n",
|
|
" \"\"\"Plot prediction coverage spans as horizontal stacked bars.\"\"\"\n",
|
|
" fig, ax = plt.subplots(figsize=(12, 5.5))\n",
|
|
" bar_height = 0.65\n",
|
|
"\n",
|
|
" for i, cs in enumerate(coverage_data):\n",
|
|
" y = len(coverage_data) - 1 - i\n",
|
|
"\n",
|
|
" ax.barh(\n",
|
|
" y,\n",
|
|
" cs[\"val_start\"] - cs[\"data_start\"],\n",
|
|
" left=cs[\"data_start\"],\n",
|
|
" height=bar_height,\n",
|
|
" color=\"0.3\",\n",
|
|
" edgecolor=\"white\",\n",
|
|
" linewidth=0.5,\n",
|
|
" )\n",
|
|
" ax.barh(\n",
|
|
" y,\n",
|
|
" cs[\"holdout_start\"] - cs[\"val_start\"],\n",
|
|
" left=cs[\"val_start\"],\n",
|
|
" height=bar_height,\n",
|
|
" color=\"0.55\",\n",
|
|
" edgecolor=\"white\",\n",
|
|
" linewidth=0.5,\n",
|
|
" )\n",
|
|
" ax.barh(\n",
|
|
" y,\n",
|
|
" cs[\"holdout_end\"] - cs[\"holdout_start\"] + 1,\n",
|
|
" left=cs[\"holdout_start\"],\n",
|
|
" height=bar_height,\n",
|
|
" color=\"0.8\",\n",
|
|
" edgecolor=\"white\",\n",
|
|
" linewidth=0.5,\n",
|
|
" )\n",
|
|
"\n",
|
|
" ax.set_yticks(range(len(coverage_data)))\n",
|
|
" ax.set_yticklabels([cs[\"name\"] for cs in reversed(coverage_data)])\n",
|
|
" ax.set_ylim(-0.7, len(coverage_data) - 0.3)\n",
|
|
"\n",
|
|
" min_year = min(cs[\"data_start\"] for cs in coverage_data) - 2\n",
|
|
" max_year = max(cs[\"holdout_end\"] for cs in coverage_data) + 2\n",
|
|
" ax.set_xlim(min_year, max_year)\n",
|
|
" ax.set_xlabel(\"Year\")\n",
|
|
" ax.tick_params(left=False)\n",
|
|
"\n",
|
|
" legend_elements = [\n",
|
|
" Patch(facecolor=\"0.3\", label=\"Training\"),\n",
|
|
" Patch(facecolor=\"0.55\", label=\"Validation\"),\n",
|
|
" Patch(facecolor=\"0.8\", label=\"Holdout (sealed)\"),\n",
|
|
" ]\n",
|
|
" ax.legend(\n",
|
|
" handles=legend_elements,\n",
|
|
" loc=\"upper left\",\n",
|
|
" bbox_to_anchor=(1.01, 1.0),\n",
|
|
" frameon=True,\n",
|
|
" fancybox=False,\n",
|
|
" edgecolor=\"gray\",\n",
|
|
" )\n",
|
|
" ax.set_title(\"Prediction Coverage Across Case Studies\")\n",
|
|
" fig.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"id": "52f0775d",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:17.874769Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:17.874663Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:18.029508Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:18.028911Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.159147,
|
|
"end_time": "2026-06-13T03:12:18.029835+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:17.870688+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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",
|
|
"text/plain": [
|
|
"<Figure size 1200x550 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"if case_studies_coverage:\n",
|
|
" plot_coverage(case_studies_coverage)\n",
|
|
"else:\n",
|
|
" print(\"No coverage data available. Run setup notebooks first.\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a1d945e0",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002713,
|
|
"end_time": "2026-06-13T03:12:18.035683+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.032970+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Coverage Statistics (Computed)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"id": "5bdb3ef5",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:18.041987Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:18.041809Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:18.046308Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:18.045778Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.008336,
|
|
"end_time": "2026-06-13T03:12:18.046725+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.038389+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Coverage spans 1990 to 2025 (35 years)\n",
|
|
"Validation periods: 1 to 16 years\n",
|
|
"Holdout periods: 1 to 3 years\n",
|
|
"Recent datasets (2020+): Crypto Perps Funding\n",
|
|
"Long-history datasets (pre-1995): US Equities Panel\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"if case_studies_coverage:\n",
|
|
" earliest_start = min(cs[\"data_start\"] for cs in case_studies_coverage)\n",
|
|
" latest_end = max(cs[\"holdout_end\"] for cs in case_studies_coverage)\n",
|
|
" max_span = latest_end - earliest_start\n",
|
|
"\n",
|
|
" longest_val = max(cs[\"holdout_start\"] - cs[\"val_start\"] for cs in case_studies_coverage)\n",
|
|
" shortest_val = min(cs[\"holdout_start\"] - cs[\"val_start\"] for cs in case_studies_coverage)\n",
|
|
"\n",
|
|
" holdout_lengths = [cs[\"holdout_end\"] - cs[\"holdout_start\"] + 1 for cs in case_studies_coverage]\n",
|
|
" max_holdout = max(holdout_lengths)\n",
|
|
" min_holdout = min(holdout_lengths)\n",
|
|
"\n",
|
|
" recent_datasets = [cs[\"name\"] for cs in case_studies_coverage if cs[\"data_start\"] >= 2020]\n",
|
|
" long_datasets = [cs[\"name\"] for cs in case_studies_coverage if cs[\"data_start\"] <= 1995]\n",
|
|
"\n",
|
|
" print(f\"Coverage spans {int(earliest_start)} to {int(latest_end)} ({int(max_span)} years)\")\n",
|
|
" print(f\"Validation periods: {shortest_val:.0f} to {longest_val:.0f} years\")\n",
|
|
" print(f\"Holdout periods: {min_holdout} to {max_holdout} years\")\n",
|
|
" print(f\"Recent datasets (2020+): {', '.join(recent_datasets) if recent_datasets else 'None'}\")\n",
|
|
" print(\n",
|
|
" f\"Long-history datasets (pre-1995): {', '.join(long_datasets) if long_datasets else 'None'}\"\n",
|
|
" )"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2b6a081a",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002604,
|
|
"end_time": "2026-06-13T03:12:18.052128+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.049524+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"**Interpretation** (computed from results):\n",
|
|
"\n",
|
|
"The coverage statistics above show the actual data spans. Key observations:\n",
|
|
"- **Longest histories** (US Equities, Firm Characteristics) provide deep validation\n",
|
|
" but may include regime changes that affect stationarity\n",
|
|
"- **Recent datasets** (Crypto, Microstructure) limit walk-forward depth but\n",
|
|
" reflect current market conditions\n",
|
|
"- **Holdout variation** reflects data availability: options data ends 2021,\n",
|
|
" constraining holdout to 1 year vs 2 years for other case studies"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "96a42801",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001942,
|
|
"end_time": "2026-06-13T03:12:18.056269+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.054327+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## 5. Quick Reference Table\n",
|
|
"\n",
|
|
"This table consolidates key information for quick reference when working\n",
|
|
"with any case study in the book."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"id": "537f9590",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:18.061124Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:18.060993Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:18.065168Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:18.064837Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.007391,
|
|
"end_time": "2026-06-13T03:12:18.065701+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.058310+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div><style>\n",
|
|
".dataframe > thead > tr,\n",
|
|
".dataframe > tbody > tr {\n",
|
|
" text-align: right;\n",
|
|
" white-space: pre-wrap;\n",
|
|
"}\n",
|
|
"</style>\n",
|
|
"<small>shape: (9, 9)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Case Study</th><th>Asset</th><th>N</th><th>Freq</th><th>Cost</th><th>Train</th><th>Folds</th><th>Holdout</th><th>Track</th></tr><tr><td>str</td><td>str</td><td>i64</td><td>str</td><td>str</td><td>str</td><td>i64</td><td>str</td><td>str</td></tr></thead><tbody><tr><td>"CME Futures"</td><td>"Futures"</td><td>30</td><td>"Weekly"</td><td>"mat"</td><td>"8Y"</td><td>5</td><td>"2024-01-01-2025-12-31"</td><td>"Ch6 to Ch17"</td></tr><tr><td>"Crypto Perps Funding"</td><td>"Crypto"</td><td>19</td><td>"8-hourly"</td><td>"mat"</td><td>"2Y"</td><td>2</td><td>"2024-01-01-2025-12-31"</td><td>"Ch6 to Ch12"</td></tr><tr><td>"ETFs"</td><td>"Multi-Asset"</td><td>100</td><td>"Daily"</td><td>"mat"</td><td>"10Y"</td><td>8</td><td>"2024-01-01-2025-12-31"</td><td>"Ch6 to Ch21"</td></tr><tr><td>"FX Pairs"</td><td>"FX"</td><td>20</td><td>"Daily"</td><td>"mat"</td><td>"P5Y"</td><td>8</td><td>"2024-01-01-2025-12-31"</td><td>"Ch6 to Ch17"</td></tr><tr><td>"NASDAQ-100 Microstructure"</td><td>"Equities"</td><td>114</td><td>"15-min"</td><td>"dom"</td><td>"6M"</td><td>2</td><td>"2021-07-01-2021-12-31"</td><td>"Ch6 to Ch12"</td></tr><tr><td>"S&P 500 Equity+Options"</td><td>"Equities+Options"</td><td>633</td><td>"Weekly"</td><td>"mat"</td><td>"2Y"</td><td>2</td><td>"2021-01-01-2021-12-31"</td><td>"Ch6 to Ch21"</td></tr><tr><td>"S&P 500 Options"</td><td>"Options"</td><td>0</td><td>"Weekly"</td><td>"dom"</td><td>"2Y"</td><td>2</td><td>"2021-01-01-2021-12-31"</td><td>"Ch6 to Ch21"</td></tr><tr><td>"US Equities Panel"</td><td>"Equities"</td><td>3199</td><td>"Daily"</td><td>"mat"</td><td>"10Y"</td><td>16</td><td>"2016-01-01-2018-03-31"</td><td>"Ch6 to Ch14"</td></tr><tr><td>"US Firm Characteristics"</td><td>"Equities"</td><td>0</td><td>"Daily"</td><td>"mat"</td><td>"10Y"</td><td>10</td><td>"2016-01-01-2016-12-31"</td><td>"Ch6 to Ch14"</td></tr></tbody></table></div>"
|
|
],
|
|
"text/plain": [
|
|
"shape: (9, 9)\n",
|
|
"┌───────────────┬───────────────┬──────┬──────────┬───┬───────┬───────┬──────────────┬─────────────┐\n",
|
|
"│ Case Study ┆ Asset ┆ N ┆ Freq ┆ … ┆ Train ┆ Folds ┆ Holdout ┆ Track │\n",
|
|
"│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │\n",
|
|
"│ str ┆ str ┆ i64 ┆ str ┆ ┆ str ┆ i64 ┆ str ┆ str │\n",
|
|
"╞═══════════════╪═══════════════╪══════╪══════════╪═══╪═══════╪═══════╪══════════════╪═════════════╡\n",
|
|
"│ CME Futures ┆ Futures ┆ 30 ┆ Weekly ┆ … ┆ 8Y ┆ 5 ┆ 2024-01-01-2 ┆ Ch6 to Ch17 │\n",
|
|
"│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 025-12-31 ┆ │\n",
|
|
"│ Crypto Perps ┆ Crypto ┆ 19 ┆ 8-hourly ┆ … ┆ 2Y ┆ 2 ┆ 2024-01-01-2 ┆ Ch6 to Ch12 │\n",
|
|
"│ Funding ┆ ┆ ┆ ┆ ┆ ┆ ┆ 025-12-31 ┆ │\n",
|
|
"│ ETFs ┆ Multi-Asset ┆ 100 ┆ Daily ┆ … ┆ 10Y ┆ 8 ┆ 2024-01-01-2 ┆ Ch6 to Ch21 │\n",
|
|
"│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 025-12-31 ┆ │\n",
|
|
"│ FX Pairs ┆ FX ┆ 20 ┆ Daily ┆ … ┆ P5Y ┆ 8 ┆ 2024-01-01-2 ┆ Ch6 to Ch17 │\n",
|
|
"│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 025-12-31 ┆ │\n",
|
|
"│ NASDAQ-100 ┆ Equities ┆ 114 ┆ 15-min ┆ … ┆ 6M ┆ 2 ┆ 2021-07-01-2 ┆ Ch6 to Ch12 │\n",
|
|
"│ Microstructur ┆ ┆ ┆ ┆ ┆ ┆ ┆ 021-12-31 ┆ │\n",
|
|
"│ e ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ │\n",
|
|
"│ S&P 500 Equit ┆ Equities+Opti ┆ 633 ┆ Weekly ┆ … ┆ 2Y ┆ 2 ┆ 2021-01-01-2 ┆ Ch6 to Ch21 │\n",
|
|
"│ y+Options ┆ ons ┆ ┆ ┆ ┆ ┆ ┆ 021-12-31 ┆ │\n",
|
|
"│ S&P 500 ┆ Options ┆ 0 ┆ Weekly ┆ … ┆ 2Y ┆ 2 ┆ 2021-01-01-2 ┆ Ch6 to Ch21 │\n",
|
|
"│ Options ┆ ┆ ┆ ┆ ┆ ┆ ┆ 021-12-31 ┆ │\n",
|
|
"│ US Equities ┆ Equities ┆ 3199 ┆ Daily ┆ … ┆ 10Y ┆ 16 ┆ 2016-01-01-2 ┆ Ch6 to Ch14 │\n",
|
|
"│ Panel ┆ ┆ ┆ ┆ ┆ ┆ ┆ 018-03-31 ┆ │\n",
|
|
"│ US Firm Chara ┆ Equities ┆ 0 ┆ Daily ┆ … ┆ 10Y ┆ 10 ┆ 2016-01-01-2 ┆ Ch6 to Ch14 │\n",
|
|
"│ cteristics ┆ ┆ ┆ ┆ ┆ ┆ ┆ 016-12-31 ┆ │\n",
|
|
"└───────────────┴───────────────┴──────┴──────────┴───┴───────┴───────┴──────────────┴─────────────┘"
|
|
]
|
|
},
|
|
"execution_count": 19,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"reference_rows = []\n",
|
|
"for case_id, r in all_results.items():\n",
|
|
" s = r.get(\"summary\", {})\n",
|
|
" d = r.get(\"diagnostics\", {})\n",
|
|
"\n",
|
|
" ho_s = d.get(\"holdout_start\", \"?\")\n",
|
|
" ho_e = d.get(\"holdout_end\", \"?\")\n",
|
|
"\n",
|
|
" reference_rows.append(\n",
|
|
" {\n",
|
|
" \"Case Study\": DISPLAY_NAMES.get(case_id, case_id),\n",
|
|
" \"Asset\": s.get(\"asset_class\", \"\"),\n",
|
|
" \"N\": s.get(\"universe_size\", 0),\n",
|
|
" \"Freq\": s.get(\"data_frequency\", \"\"),\n",
|
|
" \"Cost\": s.get(\"cost_model\", \"\")[:3],\n",
|
|
" \"Train\": d.get(\"train_size\", \"N/A\"),\n",
|
|
" \"Folds\": d.get(\"n_splits\", 0),\n",
|
|
" \"Holdout\": f\"{ho_s}-{ho_e}\",\n",
|
|
" \"Track\": CHAPTER_TRACKS.get(case_id, \"\"),\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
"reference_df = pl.DataFrame(reference_rows)\n",
|
|
"reference_df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6bba6afd",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.00223,
|
|
"end_time": "2026-06-13T03:12:18.070071+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.067841+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"**What to notice**:\n",
|
|
"- \"Track\" column shows which chapters use each case study, enabling readers\n",
|
|
" to follow specific datasets through the book\n",
|
|
"- Dominant-cost case studies (NASDAQ-100, Options) have shorter tracks,\n",
|
|
" reflecting their specialized, educational role\n",
|
|
"- Material-cost case studies carry through to later chapters (Ch14, Ch17, Ch21)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a942eadb",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002616,
|
|
"end_time": "2026-06-13T03:12:18.075328+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.072712+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"### Column Descriptions\n",
|
|
"\n",
|
|
"| Column | Description |\n",
|
|
"|--------|-------------|\n",
|
|
"| **N** | Universe size (number of tradable assets) |\n",
|
|
"| **Freq** | Native data frequency |\n",
|
|
"| **Cost** | Cost model class (Dom=Dominant, Mat=Material) |\n",
|
|
"| **Train** | Training window size |\n",
|
|
"| **Folds** | Number of walk-forward validation folds |\n",
|
|
"| **Holdout** | Sealed holdout period years |\n",
|
|
"| **Track** | Chapter sequence where this case study appears |"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "97d1050b",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.001957,
|
|
"end_time": "2026-06-13T03:12:18.079679+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.077722+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## 6. Setup Techniques Summary\n",
|
|
"\n",
|
|
"How each case study maps signals to positions:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"id": "2949495f",
|
|
"metadata": {
|
|
"execution": {
|
|
"iopub.execute_input": "2026-06-13T03:12:18.084674Z",
|
|
"iopub.status.busy": "2026-06-13T03:12:18.084546Z",
|
|
"iopub.status.idle": "2026-06-13T03:12:18.088351Z",
|
|
"shell.execute_reply": "2026-06-13T03:12:18.087870Z"
|
|
},
|
|
"papermill": {
|
|
"duration": 0.006984,
|
|
"end_time": "2026-06-13T03:12:18.088698+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.081714+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div><style>\n",
|
|
".dataframe > thead > tr,\n",
|
|
".dataframe > tbody > tr {\n",
|
|
" text-align: right;\n",
|
|
" white-space: pre-wrap;\n",
|
|
"}\n",
|
|
"</style>\n",
|
|
"<small>shape: (9, 3)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>Case Study</th><th>Setup Type</th><th>Position Mapping</th></tr><tr><td>str</td><td>str</td><td>str</td></tr></thead><tbody><tr><td>"CME Futures"</td><td>"long_short_carry_rank"</td><td>"rank_by_carry_or_momentum"</td></tr><tr><td>"Crypto Perps Funding"</td><td>"long_short_funding_aligned"</td><td>"threshold_or_rank_based"</td></tr><tr><td>"ETFs"</td><td>"long_only_rank_and_rebalance"</td><td>"rank_selection_top_n"</td></tr><tr><td>"FX Pairs"</td><td>"long_short_rank_rebalance"</td><td>"rank_by_momentum_or_carry"</td></tr><tr><td>"NASDAQ-100 Microstructure"</td><td>"intraday_rank_and_trade"</td><td>"rank_or_threshold"</td></tr><tr><td>"S&P 500 Equity+Options"</td><td>"long_only_rank_and_rebalance"</td><td>"rank_by_iv_signal"</td></tr><tr><td>"S&P 500 Options"</td><td>"systematic_straddle_sell"</td><td>"sell_atm_straddle_weekly"</td></tr><tr><td>"US Equities Panel"</td><td>"long_short_decile_rebalance"</td><td>"decile_sort_long_top_short_bot…</td></tr><tr><td>"US Firm Characteristics"</td><td>"long_short_decile_rebalance"</td><td>"decile_sort_long_top_short_bot…</td></tr></tbody></table></div>"
|
|
],
|
|
"text/plain": [
|
|
"shape: (9, 3)\n",
|
|
"┌───────────────────────────┬──────────────────────────────┬─────────────────────────────────┐\n",
|
|
"│ Case Study ┆ Setup Type ┆ Position Mapping │\n",
|
|
"│ --- ┆ --- ┆ --- │\n",
|
|
"│ str ┆ str ┆ str │\n",
|
|
"╞═══════════════════════════╪══════════════════════════════╪═════════════════════════════════╡\n",
|
|
"│ CME Futures ┆ long_short_carry_rank ┆ rank_by_carry_or_momentum │\n",
|
|
"│ Crypto Perps Funding ┆ long_short_funding_aligned ┆ threshold_or_rank_based │\n",
|
|
"│ ETFs ┆ long_only_rank_and_rebalance ┆ rank_selection_top_n │\n",
|
|
"│ FX Pairs ┆ long_short_rank_rebalance ┆ rank_by_momentum_or_carry │\n",
|
|
"│ NASDAQ-100 Microstructure ┆ intraday_rank_and_trade ┆ rank_or_threshold │\n",
|
|
"│ S&P 500 Equity+Options ┆ long_only_rank_and_rebalance ┆ rank_by_iv_signal │\n",
|
|
"│ S&P 500 Options ┆ systematic_straddle_sell ┆ sell_atm_straddle_weekly │\n",
|
|
"│ US Equities Panel ┆ long_short_decile_rebalance ┆ decile_sort_long_top_short_bot… │\n",
|
|
"│ US Firm Characteristics ┆ long_short_decile_rebalance ┆ decile_sort_long_top_short_bot… │\n",
|
|
"└───────────────────────────┴──────────────────────────────┴─────────────────────────────────┘"
|
|
]
|
|
},
|
|
"execution_count": 20,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"technique_rows = []\n",
|
|
"for case_id, r in all_results.items():\n",
|
|
" t = r.get(\"techniques\", {})\n",
|
|
" technique_rows.append(\n",
|
|
" {\n",
|
|
" \"Case Study\": DISPLAY_NAMES.get(case_id, case_id),\n",
|
|
" \"Setup Type\": t.get(\"setup_type\", \"\"),\n",
|
|
" \"Position Mapping\": t.get(\"position_mapping\", \"\"),\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
"technique_df = pl.DataFrame(technique_rows)\n",
|
|
"technique_df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "8b4655c0",
|
|
"metadata": {
|
|
"papermill": {
|
|
"duration": 0.002084,
|
|
"end_time": "2026-06-13T03:12:18.093017+00:00",
|
|
"exception": false,
|
|
"start_time": "2026-06-13T03:12:18.090933+00:00",
|
|
"status": "completed"
|
|
}
|
|
},
|
|
"source": [
|
|
"---\n",
|
|
"\n",
|
|
"## Key Takeaways\n",
|
|
"\n",
|
|
"1. **Diversity by design**: The 9 case studies span equities, crypto, FX, futures,\n",
|
|
" options, and multi-asset ETFs, demonstrating ML4T workflow adaptability.\n",
|
|
"\n",
|
|
"2. **Cost models matter**: The cost regime (dominant vs material) determines\n",
|
|
" viable horizons. Microstructure and options strategies face dominant costs\n",
|
|
" that require exceptionally strong signals.\n",
|
|
"\n",
|
|
"3. **Protocol heterogeneity**: Training windows range from 6 months (microstructure)\n",
|
|
" to 10 years (firm characteristics), reflecting data availability and\n",
|
|
" stationarity assumptions.\n",
|
|
"\n",
|
|
"4. **Holdout discipline**: All case studies reserve a sealed holdout period that\n",
|
|
" is never used for development decisions. This discipline is essential for\n",
|
|
" honest performance estimation.\n",
|
|
"\n",
|
|
"5. **Coverage varies**: Historical depth ranges from recent (2020+ for crypto)\n",
|
|
" to decades (1990 for US equities), affecting the reliability\n",
|
|
" of walk-forward estimates.\n",
|
|
"\n",
|
|
"**Next**: Individual setup notebooks (`case_studies/*/01_feasibility_analysis.py`) contain\n",
|
|
"the detailed trading setup and evaluation protocol for each case study."
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"jupytext": {
|
|
"cell_metadata_filter": "tags,-all"
|
|
},
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"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.3"
|
|
},
|
|
"papermill": {
|
|
"default_parameters": {},
|
|
"duration": 5.205003,
|
|
"end_time": "2026-06-13T03:12:19.010946+00:00",
|
|
"environment_variables": {},
|
|
"exception": null,
|
|
"input_path": "06_strategy_definition/02_case_study_overview.ipynb",
|
|
"output_path": "06_strategy_definition/02_case_study_overview.ipynb",
|
|
"parameters": {},
|
|
"start_time": "2026-06-13T03:12:13.805943+00:00",
|
|
"version": "2.7.0"
|
|
},
|
|
"ml4t_provenance": {
|
|
"source_py_blob": "8505ed77d7590dc856d3bf3dcb83384c4a188b9d",
|
|
"executed_at": "2026-06-13T03:12:19.339536+00:00",
|
|
"executor": "cpu-local",
|
|
"production": true,
|
|
"parameters": {},
|
|
"notes": "executed-state finalization batch (2026-06-13 run)"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|