Files
stefan-jansen--machine-lear…/02_financial_data_universe/01_us_equities_eda.ipynb
T
2026-07-13 13:26:28 +08:00

790 lines
26 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "5ad079dc",
"metadata": {
"papermill": {
"duration": 0.005414,
"end_time": "2026-06-13T02:32:24.544112+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:24.538698+00:00",
"status": "completed"
}
},
"source": [
"# US Equities — Exploratory Data Analysis\n",
"\n",
"**Docker image**: `ml4t`\n",
"\n",
"**Purpose**: Profile the Wiki Prices dataset of US equity OHLCV history and confirm\n",
"the inactive-symbol coverage that makes it usable for survivorship-bias-free\n",
"backtests.\n",
"\n",
"**Learning objectives**:\n",
"\n",
"- Load the equity panel via `data.load_us_equities` and inspect its canonical schema.\n",
"- Distinguish raw and split/dividend-adjusted price columns.\n",
"- Quantify the share of symbols that stop trading before the dataset end date.\n",
"- Check OHLC invariants and null rates across the full panel.\n",
"\n",
"**Book reference**: §2.2 (\"The Asset-Class Market Data Landscape\" — Equities).\n",
"\n",
"**Prerequisites**: `data` package on `PYTHONPATH`; Wiki Prices parquet present at\n",
"`ML4T_DATA_PATH/equities/market/us_equities/`. Run\n",
"`python data/equities/market/us_equities/download.py` if missing."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "fcba0234",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:24.551754Z",
"iopub.status.busy": "2026-06-13T02:32:24.551580Z",
"iopub.status.idle": "2026-06-13T02:32:25.784522Z",
"shell.execute_reply": "2026-06-13T02:32:25.784148Z"
},
"papermill": {
"duration": 1.237163,
"end_time": "2026-06-13T02:32:25.785024+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:24.547861+00:00",
"status": "completed"
}
},
"outputs": [],
"source": [
"\"\"\"US Equities — Exploratory data analysis of the Wiki Prices dataset.\"\"\"\n",
"\n",
"import polars as pl\n",
"\n",
"from data import load_us_equities\n",
"from utils.data_quality import check_ohlc_invariants"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "e2e6b56b",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:25.788403Z",
"iopub.status.busy": "2026-06-13T02:32:25.788307Z",
"iopub.status.idle": "2026-06-13T02:32:25.789984Z",
"shell.execute_reply": "2026-06-13T02:32:25.789599Z"
},
"papermill": {
"duration": 0.004284,
"end_time": "2026-06-13T02:32:25.790350+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:25.786066+00:00",
"status": "completed"
},
"tags": [
"parameters"
]
},
"outputs": [],
"source": [
"# Production defaults — Papermill injects overrides for CI\n",
"MAX_SYMBOLS = 0 # 0 = all"
]
},
{
"cell_type": "markdown",
"id": "a05e8378",
"metadata": {
"papermill": {
"duration": 0.000762,
"end_time": "2026-06-13T02:32:25.791966+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:25.791204+00:00",
"status": "completed"
}
},
"source": [
"## 1. Load and Inspect"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "18d4c304",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:25.793964Z",
"iopub.status.busy": "2026-06-13T02:32:25.793895Z",
"iopub.status.idle": "2026-06-13T02:32:26.253321Z",
"shell.execute_reply": "2026-06-13T02:32:26.252871Z"
},
"papermill": {
"duration": 0.460993,
"end_time": "2026-06-13T02:32:26.253751+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:25.792758+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== Wiki Prices Dataset ===\n",
"Shape: (15389314, 14)\n",
"Columns: ['symbol', 'timestamp', 'open', 'high', 'low', 'close', 'volume', 'ex-dividend', 'split_ratio', 'adj_open', 'adj_high', 'adj_low', 'adj_close', 'adj_volume']\n"
]
}
],
"source": [
"wiki = load_us_equities()\n",
"\n",
"print(\"=== Wiki Prices Dataset ===\")\n",
"print(f\"Shape: {wiki.shape}\")\n",
"print(f\"Columns: {wiki.columns}\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f3ce7b2d",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.256226Z",
"iopub.status.busy": "2026-06-13T02:32:26.256110Z",
"iopub.status.idle": "2026-06-13T02:32:26.257967Z",
"shell.execute_reply": "2026-06-13T02:32:26.257731Z"
},
"papermill": {
"duration": 0.003422,
"end_time": "2026-06-13T02:32:26.258212+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.254790+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Schema:\n",
" symbol: String\n",
" timestamp: Date\n",
" open: Float64\n",
" high: Float64\n",
" low: Float64\n",
" close: Float64\n",
" volume: Float64\n",
" ex-dividend: Float64\n",
" split_ratio: Float64\n",
" adj_open: Float64\n",
" adj_high: Float64\n",
" adj_low: Float64\n",
" adj_close: Float64\n",
" adj_volume: Float64\n"
]
}
],
"source": [
"# Schema overview\n",
"print(\"\\nSchema:\")\n",
"for col, dtype in wiki.schema.items():\n",
" print(f\" {col}: {dtype}\")"
]
},
{
"cell_type": "markdown",
"id": "7cf8fb2a",
"metadata": {
"papermill": {
"duration": 0.000835,
"end_time": "2026-06-13T02:32:26.259980+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.259145+00:00",
"status": "completed"
}
},
"source": [
"### Adjusted vs Raw Prices\n",
"\n",
"**Important**: This dataset contains both raw and adjusted prices.\n",
"\n",
"| Column Type | Examples | Use Case |\n",
"|-------------|----------|----------|\n",
"| Raw | `open`, `high`, `low`, `close`, `volume` | Historical analysis at actual prices |\n",
"| Adjusted | `adj_open`, `adj_high`, `adj_low`, `adj_close`, `adj_volume` | **Backtesting** (handles splits/dividends) |\n",
"\n",
"Always use `adj_*` columns for return calculations and strategy backtesting."
]
},
{
"cell_type": "markdown",
"id": "6d550e3b",
"metadata": {
"papermill": {
"duration": 0.000832,
"end_time": "2026-06-13T02:32:26.261676+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.260844+00:00",
"status": "completed"
}
},
"source": [
"## 2. Coverage Summary"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "3007d3af",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.264176Z",
"iopub.status.busy": "2026-06-13T02:32:26.264095Z",
"iopub.status.idle": "2026-06-13T02:32:26.348271Z",
"shell.execute_reply": "2026-06-13T02:32:26.347931Z"
},
"papermill": {
"duration": 0.086007,
"end_time": "2026-06-13T02:32:26.348675+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.262668+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== Coverage ===\n",
"Unique tickers: 3,199\n",
"Date range: 1962-01-02 to 2018-03-27\n",
"Total rows: 15,389,314\n"
]
}
],
"source": [
"# Overall coverage\n",
"print(\"=== Coverage ===\")\n",
"print(f\"Unique tickers: {wiki['symbol'].n_unique():,}\")\n",
"print(f\"Date range: {wiki['timestamp'].min()} to {wiki['timestamp'].max()}\")\n",
"print(f\"Total rows: {len(wiki):,}\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "07f7febc",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.351317Z",
"iopub.status.busy": "2026-06-13T02:32:26.351234Z",
"iopub.status.idle": "2026-06-13T02:32:26.723550Z",
"shell.execute_reply": "2026-06-13T02:32:26.723172Z"
},
"papermill": {
"duration": 0.374552,
"end_time": "2026-06-13T02:32:26.724359+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.349807+00:00",
"status": "completed"
}
},
"outputs": [],
"source": [
"# Per-stock statistics\n",
"stock_stats = wiki.group_by(\"symbol\").agg(\n",
" [\n",
" pl.len().alias(\"days\"),\n",
" pl.col(\"timestamp\").min().alias(\"start\"),\n",
" pl.col(\"timestamp\").max().alias(\"end\"),\n",
" pl.col(\"adj_close\").mean().alias(\"avg_price\"),\n",
" ]\n",
")"
]
},
{
"cell_type": "markdown",
"id": "bc6a8d8e",
"metadata": {
"papermill": {
"duration": 0.001661,
"end_time": "2026-06-13T02:32:26.728002+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.726341+00:00",
"status": "completed"
}
},
"source": [
"Per-symbol coverage distribution — number of trading days and mean adjusted price."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "eca30494",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.731023Z",
"iopub.status.busy": "2026-06-13T02:32:26.730937Z",
"iopub.status.idle": "2026-06-13T02:32:26.735753Z",
"shell.execute_reply": "2026-06-13T02:32:26.735507Z"
},
"papermill": {
"duration": 0.006674,
"end_time": "2026-06-13T02:32:26.736156+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.729482+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>statistic</th><th>days</th><th>avg_price</th></tr><tr><td>str</td><td>f64</td><td>f64</td></tr></thead><tbody><tr><td>&quot;count&quot;</td><td>3199.0</td><td>3199.0</td></tr><tr><td>&quot;null_count&quot;</td><td>0.0</td><td>0.0</td></tr><tr><td>&quot;mean&quot;</td><td>4810.663957</td><td>118.245432</td></tr><tr><td>&quot;std&quot;</td><td>2621.170846</td><td>2893.682465</td></tr><tr><td>&quot;min&quot;</td><td>4.0</td><td>0.669129</td></tr><tr><td>&quot;25%&quot;</td><td>2611.0</td><td>11.539385</td></tr><tr><td>&quot;50%&quot;</td><td>4974.0</td><td>18.519854</td></tr><tr><td>&quot;75%&quot;</td><td>6666.0</td><td>29.777315</td></tr><tr><td>&quot;max&quot;</td><td>14155.0</td><td>132897.234865</td></tr></tbody></table></div>"
],
"text/plain": [
"shape: (9, 3)\n",
"┌────────────┬─────────────┬───────────────┐\n",
"│ statistic ┆ days ┆ avg_price │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ f64 ┆ f64 │\n",
"╞════════════╪═════════════╪═══════════════╡\n",
"│ count ┆ 3199.0 ┆ 3199.0 │\n",
"│ null_count ┆ 0.0 ┆ 0.0 │\n",
"│ mean ┆ 4810.663957 ┆ 118.245432 │\n",
"│ std ┆ 2621.170846 ┆ 2893.682465 │\n",
"│ min ┆ 4.0 ┆ 0.669129 │\n",
"│ 25% ┆ 2611.0 ┆ 11.539385 │\n",
"│ 50% ┆ 4974.0 ┆ 18.519854 │\n",
"│ 75% ┆ 6666.0 ┆ 29.777315 │\n",
"│ max ┆ 14155.0 ┆ 132897.234865 │\n",
"└────────────┴─────────────┴───────────────┘"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stock_stats.select([\"days\", \"avg_price\"]).describe()"
]
},
{
"cell_type": "markdown",
"id": "e3726365",
"metadata": {
"papermill": {
"duration": 0.000927,
"end_time": "2026-06-13T02:32:26.738073+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.737146+00:00",
"status": "completed"
}
},
"source": [
"## 3. Survivorship Analysis\n",
"\n",
"A key feature of this dataset is that it includes stocks that ceased trading\n",
"before the dataset end date. This is critical for avoiding survivorship bias.\n",
"\n",
"**Note**: Stocks marked as \"inactive before end\" include both:\n",
"- Actually delisted companies (bankruptcy, acquisition, etc.)\n",
"- Stocks with incomplete coverage in this dataset\n",
"\n",
"The important point: these stocks are included, preventing survivorship bias."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "9dfb3c79",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.740278Z",
"iopub.status.busy": "2026-06-13T02:32:26.740210Z",
"iopub.status.idle": "2026-06-13T02:32:26.747184Z",
"shell.execute_reply": "2026-06-13T02:32:26.746804Z"
},
"papermill": {
"duration": 0.008672,
"end_time": "2026-06-13T02:32:26.747650+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.738978+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== Survivorship Analysis ===\n",
"Dataset end: 2018-03-27\n",
"Active at dataset end: 2,422 (75.7%)\n",
"Inactive before end: 777 (24.3%)\n",
"\n",
"This 24% inactive rate helps mitigate survivorship bias in backtests.\n"
]
}
],
"source": [
"dataset_end = wiki.select(pl.col(\"timestamp\").max()).item()\n",
"\n",
"# Identify stocks that stopped trading before dataset end\n",
"stock_stats = stock_stats.with_columns((pl.col(\"end\") < dataset_end).alias(\"inactive_before_end\"))\n",
"\n",
"n_active = stock_stats.filter(~pl.col(\"inactive_before_end\")).height\n",
"n_inactive = stock_stats.filter(pl.col(\"inactive_before_end\")).height\n",
"total = n_active + n_inactive\n",
"inactive_pct = n_inactive / total * 100\n",
"\n",
"print(\"=== Survivorship Analysis ===\")\n",
"print(f\"Dataset end: {dataset_end}\")\n",
"print(f\"Active at dataset end: {n_active:,} ({n_active / total * 100:.1f}%)\")\n",
"print(f\"Inactive before end: {n_inactive:,} ({inactive_pct:.1f}%)\")\n",
"print(f\"\\nThis {inactive_pct:.0f}% inactive rate helps mitigate survivorship bias in backtests.\")"
]
},
{
"cell_type": "markdown",
"id": "333e64d2",
"metadata": {
"papermill": {
"duration": 0.000978,
"end_time": "2026-06-13T02:32:26.749790+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.748812+00:00",
"status": "completed"
}
},
"source": [
"## 4. Data Quality"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "8041dec8",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.752249Z",
"iopub.status.busy": "2026-06-13T02:32:26.752172Z",
"iopub.status.idle": "2026-06-13T02:32:26.755615Z",
"shell.execute_reply": "2026-06-13T02:32:26.755147Z"
},
"papermill": {
"duration": 0.00514,
"end_time": "2026-06-13T02:32:26.755903+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.750763+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== Data Quality ===\n",
"Total null values: 1,299\n",
" open: 538 (0.0035%)\n",
" high: 55 (0.0004%)\n",
" low: 55 (0.0004%)\n",
" close: 1 (0.0000%)\n",
" split_ratio: 1 (0.0000%)\n",
" adj_open: 538 (0.0035%)\n",
" adj_high: 55 (0.0004%)\n",
" adj_low: 55 (0.0004%)\n",
" adj_close: 1 (0.0000%)\n",
"\n",
"Null rate: 0.0006%\n"
]
}
],
"source": [
"# Check for nulls across columns\n",
"null_counts = wiki.null_count()\n",
"total_nulls = null_counts.sum_horizontal()[0]\n",
"print(\"=== Data Quality ===\")\n",
"print(f\"Total null values: {total_nulls:,}\")\n",
"\n",
"# Show per-column breakdown (only columns with nulls)\n",
"for col in null_counts.columns:\n",
" val = null_counts[col][0]\n",
" if val > 0:\n",
" print(f\" {col}: {val:,} ({val / len(wiki) * 100:.4f}%)\")\n",
"\n",
"print(f\"\\nNull rate: {total_nulls / (len(wiki) * len(wiki.columns)) * 100:.4f}%\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "ac521b11",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.759001Z",
"iopub.status.busy": "2026-06-13T02:32:26.758834Z",
"iopub.status.idle": "2026-06-13T02:32:26.986021Z",
"shell.execute_reply": "2026-06-13T02:32:26.985683Z"
},
"papermill": {
"duration": 0.229428,
"end_time": "2026-06-13T02:32:26.986481+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.757053+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"OHLC Invariants (adjusted prices):\n",
" [OK] high_gte_low: 100.00%\n",
" [OK] high_gte_open: 100.00%\n",
" [OK] high_gte_close: 100.00%\n",
" [OK] low_lte_open: 100.00%\n",
" [OK] low_lte_close: 100.00%\n",
" [OK] volume_non_negative: 100.00%\n"
]
}
],
"source": [
"# OHLC invariants on adjusted prices\n",
"invariants = check_ohlc_invariants(\n",
" wiki,\n",
" open_col=\"adj_open\",\n",
" high_col=\"adj_high\",\n",
" low_col=\"adj_low\",\n",
" close_col=\"adj_close\",\n",
" volume_col=\"adj_volume\",\n",
")\n",
"\n",
"print(\"\\nOHLC Invariants (adjusted prices):\")\n",
"for row in invariants.iter_rows(named=True):\n",
" status = \"[OK]\" if row[\"valid_pct\"] >= 99.99 else \"[WARN]\"\n",
" print(f\" {status} {row['check']}: {row['valid_pct']:.2f}%\")"
]
},
{
"cell_type": "markdown",
"id": "f11b91fe",
"metadata": {
"papermill": {
"duration": 0.001525,
"end_time": "2026-06-13T02:32:26.989389+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.987864+00:00",
"status": "completed"
}
},
"source": [
"## 5. Example: Single Stock"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "911af454",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:26.992105Z",
"iopub.status.busy": "2026-06-13T02:32:26.992013Z",
"iopub.status.idle": "2026-06-13T02:32:27.006055Z",
"shell.execute_reply": "2026-06-13T02:32:27.005651Z"
},
"papermill": {
"duration": 0.015918,
"end_time": "2026-06-13T02:32:27.006360+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:26.990442+00:00",
"status": "completed"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== AAPL Example ===\n",
"Trading days: 9,400\n",
"Date range: 1980-12-12 to 2018-03-27\n"
]
}
],
"source": [
"# AAPL as example\n",
"aapl = wiki.filter(pl.col(\"symbol\") == \"AAPL\").sort(\"timestamp\")\n",
"\n",
"print(\"=== AAPL Example ===\")\n",
"print(f\"Trading days: {len(aapl):,}\")\n",
"print(f\"Date range: {aapl['timestamp'].min()} to {aapl['timestamp'].max()}\")"
]
},
{
"cell_type": "markdown",
"id": "84290f70",
"metadata": {
"papermill": {
"duration": 0.001127,
"end_time": "2026-06-13T02:32:27.008827+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:27.007700+00:00",
"status": "completed"
}
},
"source": [
"Five most recent trading days for AAPL on adjusted prices."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "83c34cd1",
"metadata": {
"execution": {
"iopub.execute_input": "2026-06-13T02:32:27.011649Z",
"iopub.status.busy": "2026-06-13T02:32:27.011526Z",
"iopub.status.idle": "2026-06-13T02:32:27.014436Z",
"shell.execute_reply": "2026-06-13T02:32:27.014207Z"
},
"papermill": {
"duration": 0.00492,
"end_time": "2026-06-13T02:32:27.014850+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:27.009930+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: (5, 6)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>timestamp</th><th>adj_open</th><th>adj_high</th><th>adj_low</th><th>adj_close</th><th>adj_volume</th></tr><tr><td>date</td><td>f64</td><td>f64</td><td>f64</td><td>f64</td><td>f64</td></tr></thead><tbody><tr><td>2018-03-21</td><td>175.04</td><td>175.09</td><td>171.26</td><td>171.27</td><td>3.5247358e7</td></tr><tr><td>2018-03-22</td><td>170.0</td><td>172.68</td><td>168.6</td><td>168.845</td><td>4.1051076e7</td></tr><tr><td>2018-03-23</td><td>168.39</td><td>169.92</td><td>164.94</td><td>164.94</td><td>4.0248954e7</td></tr><tr><td>2018-03-26</td><td>168.07</td><td>173.1</td><td>166.44</td><td>172.77</td><td>3.6272617e7</td></tr><tr><td>2018-03-27</td><td>173.68</td><td>175.15</td><td>166.92</td><td>168.34</td><td>3.8962839e7</td></tr></tbody></table></div>"
],
"text/plain": [
"shape: (5, 6)\n",
"┌────────────┬──────────┬──────────┬─────────┬───────────┬─────────────┐\n",
"│ timestamp ┆ adj_open ┆ adj_high ┆ adj_low ┆ adj_close ┆ adj_volume │\n",
"│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n",
"│ date ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 │\n",
"╞════════════╪══════════╪══════════╪═════════╪═══════════╪═════════════╡\n",
"│ 2018-03-21 ┆ 175.04 ┆ 175.09 ┆ 171.26 ┆ 171.27 ┆ 3.5247358e7 │\n",
"│ 2018-03-22 ┆ 170.0 ┆ 172.68 ┆ 168.6 ┆ 168.845 ┆ 4.1051076e7 │\n",
"│ 2018-03-23 ┆ 168.39 ┆ 169.92 ┆ 164.94 ┆ 164.94 ┆ 4.0248954e7 │\n",
"│ 2018-03-26 ┆ 168.07 ┆ 173.1 ┆ 166.44 ┆ 172.77 ┆ 3.6272617e7 │\n",
"│ 2018-03-27 ┆ 173.68 ┆ 175.15 ┆ 166.92 ┆ 168.34 ┆ 3.8962839e7 │\n",
"└────────────┴──────────┴──────────┴─────────┴───────────┴─────────────┘"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"aapl.select([\"timestamp\", \"adj_open\", \"adj_high\", \"adj_low\", \"adj_close\", \"adj_volume\"]).tail(5)"
]
},
{
"cell_type": "markdown",
"id": "cc275e7f",
"metadata": {
"papermill": {
"duration": 0.001054,
"end_time": "2026-06-13T02:32:27.017022+00:00",
"exception": false,
"start_time": "2026-06-13T02:32:27.015968+00:00",
"status": "completed"
}
},
"source": [
"## Key Takeaways\n",
"\n",
"1. **Mitigates survivorship bias**: 24% of symbols stop trading before the\n",
" dataset end — including these inactive tickers is what makes the panel\n",
" usable for unbiased backtests.\n",
"2. **Always use adjusted prices for returns**: the `adj_*` columns absorb\n",
" splits and dividends; the raw `open/high/low/close/volume` columns remain\n",
" available for analyses that need actual traded levels.\n",
"3. **Long history, broad cross-section**: 3,199 symbols with a max single-symbol\n",
" span of ~56 years (14,155 trading days), covering multiple market regimes.\n",
"4. **Clean panel**: null rate is 0.0006% of values and the six adjusted-price\n",
" OHLC invariants hold on 100% of rows.\n",
"\n",
"**Next**: `02_corporate_actions` validates the adjustment factors that\n",
"produce the `adj_*` columns. **Book reference**: §2.2 (Equities)."
]
}
],
"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": 3.93752,
"end_time": "2026-06-13T02:32:27.835362+00:00",
"environment_variables": {},
"exception": null,
"input_path": "02_financial_data_universe/01_us_equities_eda.ipynb",
"output_path": "02_financial_data_universe/01_us_equities_eda.ipynb",
"parameters": {},
"start_time": "2026-06-13T02:32:23.897842+00:00",
"version": "2.7.0"
},
"ml4t_provenance": {
"source_py_blob": "f34a592b987b8854cd8e3015baf91ad8f580fc4e",
"executed_at": "2026-06-13T02:32:28.047302+00:00",
"executor": "cpu-local",
"production": true,
"parameters": {},
"notes": "executed-state finalization batch (2026-06-13 run)"
}
},
"nbformat": 4,
"nbformat_minor": 5
}