diff --git a/MyIA.AI.Notebooks/QuantConnect/projects/Research-Executor/research_commodity_term_structure.ipynb b/MyIA.AI.Notebooks/QuantConnect/projects/Research-Executor/research_commodity_term_structure.ipynb index 075a9a24f4..a69d950566 100644 --- a/MyIA.AI.Notebooks/QuantConnect/projects/Research-Executor/research_commodity_term_structure.ipynb +++ b/MyIA.AI.Notebooks/QuantConnect/projects/Research-Executor/research_commodity_term_structure.ipynb @@ -2,7 +2,17 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "id": "a3ba4b4a", + "metadata": { + "papermill": { + "duration": 0.001983, + "end_time": "2026-09-28T01:05:52.107129", + "exception": false, + "start_time": "2026-09-28T01:05:52.105146", + "status": "completed" + }, + "tags": [] + }, "source": [ "# Commodity Term Structure - Research Notebook\n", "\n", @@ -14,48 +24,77 @@ { "cell_type": "code", "execution_count": 1, + "id": "9d93477b", "metadata": { "execution": { - "iopub.execute_input": "2026-05-12T18:47:29.724218Z", - "iopub.status.busy": "2026-05-12T18:47:29.724084Z", - "iopub.status.idle": "2026-05-12T18:47:30.416582Z", - "shell.execute_reply": "2026-05-12T18:47:30.415544Z" - } + "iopub.execute_input": "2026-09-28T01:05:52.111199Z", + "iopub.status.busy": "2026-09-28T01:05:52.110196Z", + "iopub.status.idle": "2026-09-28T01:05:52.464054Z", + "shell.execute_reply": "2026-09-28T01:05:52.464054Z" + }, + "papermill": { + "duration": 0.356923, + "end_time": "2026-09-28T01:05:52.465070", + "exception": false, + "start_time": "2026-09-28T01:05:52.108147", + "status": "completed" + }, + "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Universe: 21 commodity futures across 5 sectors\n", + "Local environment - loading 21 front-month commodity futures via yfinance\n", " Softs (5): Cocoa, Coffee, Cotton, Orange Juice, Sugar\n", " Grains (6): Corn, Oats, Soybean Meal, Soybean Oil, Soybeans, Wheat\n", " Meats (3): Feeder Cattle, Lean Hogs, Live Cattle\n", " Energies (4): Crude Oil WTI, Heating Oil, Natural Gas, Gasoline\n", - " Metals (3): Gold, Palladium, Silver\n", - "\n", - "Roll return formula: R = (ln(P_near) - ln(P_distant)) * 365 / days_diff\n", - "Rebalance: Monthly, equal-weighted long-short\n" + " Metals (3): Gold, Silver, Copper\n" ] } ], "source": [ - "from AlgorithmImports import *\n", - "qb = QuantBook()\n", + "try:\n", + " from AlgorithmImports import *\n", + " qb = QuantBook()\n", + " QC_ENV = True\n", + "except (ImportError, NameError):\n", + " import pandas as pd\n", + " import numpy as np\n", + " QC_ENV = False\n", + " qb = None\n", + "\n", + "if QC_ENV:\n", + " print(\"Universe: 21 commodity futures across 5 sectors (QC continuous contracts)\")\n", + "else:\n", + " # Local research path: the same 21 commodities via front-month Yahoo symbols.\n", + " # Scope note: roll returns need the DISTANT expiry, which Yahoo does not\n", + " # expose reliably -- the local screen measures realized front-month returns\n", + " # (see below); the true roll-return screen runs on QC Cloud.\n", + " print(\"Local environment - loading 21 front-month commodity futures via yfinance\")\n", "\n", - "print(f\"Universe: 21 commodity futures across 5 sectors\")\n", - "print(f\" Softs (5): Cocoa, Coffee, Cotton, Orange Juice, Sugar\")\n", - "print(f\" Grains (6): Corn, Oats, Soybean Meal, Soybean Oil, Soybeans, Wheat\")\n", - "print(f\" Meats (3): Feeder Cattle, Lean Hogs, Live Cattle\")\n", - "print(f\" Energies (4): Crude Oil WTI, Heating Oil, Natural Gas, Gasoline\")\n", - "print(f\" Metals (3): Gold, Palladium, Silver\")\n", - "print(f\"\\nRoll return formula: R = (ln(P_near) - ln(P_distant)) * 365 / days_diff\")\n", - "print(f\"Rebalance: Monthly, equal-weighted long-short\")" + "print(\" Softs (5): Cocoa, Coffee, Cotton, Orange Juice, Sugar\")\n", + "print(\" Grains (6): Corn, Oats, Soybean Meal, Soybean Oil, Soybeans, Wheat\")\n", + "print(\" Meats (3): Feeder Cattle, Lean Hogs, Live Cattle\")\n", + "print(\" Energies (4): Crude Oil WTI, Heating Oil, Natural Gas, Gasoline\")\n", + "print(\" Metals (3): Gold, Silver, Copper\")" ] }, { "cell_type": "markdown", - "metadata": {}, + "id": "81d87c4e", + "metadata": { + "papermill": { + "duration": 0.002013, + "end_time": "2026-09-28T01:05:52.468596", + "exception": false, + "start_time": "2026-09-28T01:05:52.466583", + "status": "completed" + }, + "tags": [] + }, "source": [ "## Strategy Logic\n", "\n", @@ -84,54 +123,144 @@ { "cell_type": "code", "execution_count": 2, + "id": "2f0edf25", "metadata": { "execution": { - "iopub.execute_input": "2026-05-12T18:47:30.436912Z", - "iopub.status.busy": "2026-05-12T18:47:30.436762Z", - "iopub.status.idle": "2026-05-12T18:47:30.441108Z", - "shell.execute_reply": "2026-05-12T18:47:30.440318Z" - } + "iopub.execute_input": "2026-09-28T01:05:52.472597Z", + "iopub.status.busy": "2026-09-28T01:05:52.472597Z", + "iopub.status.idle": "2026-09-28T01:05:58.951874Z", + "shell.execute_reply": "2026-09-28T01:05:58.951874Z" + }, + "papermill": { + "duration": 6.48232, + "end_time": "2026-09-28T01:05:58.952922", + "exception": false, + "start_time": "2026-09-28T01:05:52.470602", + "status": "completed" + }, + "tags": [] }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error 404: {\"quoteSummary\":{\"result\":null,\"error\":{\"code\":\"Not Found\",\"description\":\"Quote not found for symbol: SM=F\"}}}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "$SM=F: possibly delisted; no price data found (period=1y) (Yahoo error = \"No data found, symbol may be delisted\")\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error 404: {\"quoteSummary\":{\"result\":null,\"error\":{\"code\":\"Not Found\",\"description\":\"Quote not found for symbol: FC=F\"}}}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "$FC=F: possibly delisted; no price data found (period=1y) (Yahoo error = \"No data found, symbol may be delisted\")\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "Simulated Roll Returns (21 commodities):\n", - " Mean: -0.0140\n", - " Std: 0.1466\n", - " Positive (backwardation): 9\n", - " Negative (contango): 12\n", + "Front-month futures loaded: 19/21\n", + "\n", + "1-year realized return per commodity (measured, front-month continuous):\n", + " Heating Oil +92.43%\n", + " Gasoline +60.71%\n", + " Crude WTI +46.70%\n", + " Soybean Oil +38.75%\n", + " Copper +38.25%\n", + " Silver +36.43%\n", + " Oats +34.96%\n", + " Wheat +34.60%\n", + " Soybeans +30.43%\n", + " Cotton +25.15%\n", + " Corn +24.61%\n", + " Gold +10.73%\n", + " Sugar +9.36%\n", + " Live Cattle -3.97%\n", + " Natural Gas -4.50%\n", + " Cocoa -19.93%\n", + " Coffee -25.28%\n", + " Lean Hogs -31.76%\n", + " Orange Juice -36.31%\n", "\n", - "Quintile size: 4\n", - "Long positions (top backwardation): 4\n", - "Short positions (top contango): 4\n", - "Total positions: 8\n", - "Weight per position: 2.5%\n" + "Quintile structure of the long-short mechanism (on realized returns):\n", + " LONG leg (top 3): Heating Oil, Gasoline, Crude WTI (mean +66.61%)\n", + " SHORT leg (bottom 3): Coffee, Lean Hogs, Orange Juice (mean -31.12%)\n", + " Long-short spread: +97.73%\n", + "\n", + "Note: this ranks REALIZED front-month returns, not roll returns -- Yahoo\n", + "does not expose the distant expiry needed for the true term-structure\n", + "signal. The roll-return screen (near/distant ratio, annualized) runs on\n", + "QC Cloud with proper multi-contract data.\n" ] } ], "source": [ - "import numpy as np\n", - "np.random.seed(42)\n", - "n_commodities = 21\n", - "roll_returns = np.random.normal(0, 0.15, n_commodities)\n", - "print(\"Simulated Roll Returns (21 commodities):\")\n", - "print(f\" Mean: {roll_returns.mean():.4f}\")\n", - "print(f\" Std: {roll_returns.std():.4f}\")\n", - "print(f\" Positive (backwardation): {(roll_returns > 0).sum()}\")\n", - "print(f\" Negative (contango): {(roll_returns < 0).sum()}\")\n", - "quintile = n_commodities // 5\n", - "print(f\"\\nQuintile size: {quintile}\")\n", - "print(f\"Long positions (top backwardation): {quintile}\")\n", - "print(f\"Short positions (top contango): {quintile}\")\n", - "print(f\"Total positions: {quintile * 2}\")\n", - "print(f\"Weight per position: {0.1 / quintile:.1%}\")" + "# REAL data: 21 front-month futures, 1-year realized returns (measured, no simulation)\n", + "import yfinance as yf\n", + "\n", + "UNIVERSE = {\n", + " \"CC=F\": \"Cocoa\", \"KC=F\": \"Coffee\", \"CT=F\": \"Cotton\", \"OJ=F\": \"Orange Juice\", \"SB=F\": \"Sugar\",\n", + " \"ZC=F\": \"Corn\", \"ZO=F\": \"Oats\", \"SM=F\": \"Soybean Meal\", \"ZL=F\": \"Soybean Oil\", \"ZS=F\": \"Soybeans\", \"ZW=F\": \"Wheat\",\n", + " \"FC=F\": \"Feeder Cattle\", \"HE=F\": \"Lean Hogs\", \"LE=F\": \"Live Cattle\",\n", + " \"CL=F\": \"Crude WTI\", \"HO=F\": \"Heating Oil\", \"NG=F\": \"Natural Gas\", \"RB=F\": \"Gasoline\",\n", + " \"GC=F\": \"Gold\", \"SI=F\": \"Silver\", \"HG=F\": \"Copper\",\n", + "}\n", + "\n", + "rows = {}\n", + "for sym, name in UNIVERSE.items():\n", + " try:\n", + " h = yf.Ticker(sym).history(period=\"1y\", auto_adjust=False)\n", + " if len(h) > 100:\n", + " rows[name] = h[\"Close\"].iloc[-1] / h[\"Close\"].iloc[0] - 1\n", + " except Exception:\n", + " pass\n", + "\n", + "perf = pd.Series(rows, name=\"1y return\").sort_values(ascending=False)\n", + "print(f\"Front-month futures loaded: {len(perf)}/21\")\n", + "print(f\"\\n1-year realized return per commodity (measured, front-month continuous):\")\n", + "for name, r in perf.items():\n", + " print(f\" {name:<15} {r:+7.2%}\")\n", + "\n", + "n = len(perf)\n", + "q = max(1, n // 5)\n", + "top_q, bot_q = perf.head(q), perf.tail(q)\n", + "print(f\"\\nQuintile structure of the long-short mechanism (on realized returns):\")\n", + "print(f\" LONG leg (top {len(top_q)}): {', '.join(top_q.index)} (mean {top_q.mean():+.2%})\")\n", + "print(f\" SHORT leg (bottom {len(bot_q)}): {', '.join(bot_q.index)} (mean {bot_q.mean():+.2%})\")\n", + "print(f\" Long-short spread: {top_q.mean() - bot_q.mean():+.2%}\")\n", + "print(\"\\nNote: this ranks REALIZED front-month returns, not roll returns -- Yahoo\")\n", + "print(\"does not expose the distant expiry needed for the true term-structure\")\n", + "print(\"signal. The roll-return screen (near/distant ratio, annualized) runs on\")\n", + "print(\"QC Cloud with proper multi-contract data.\")" ] }, { "cell_type": "markdown", - "metadata": {}, + "id": "14029fe4", + "metadata": { + "papermill": { + "duration": 0.001814, + "end_time": "2026-09-28T01:05:58.956259", + "exception": false, + "start_time": "2026-09-28T01:05:58.954445", + "status": "completed" + }, + "tags": [] + }, "source": [ "## Key Observations\n", "\n", @@ -159,71 +288,106 @@ { "cell_type": "code", "execution_count": 3, + "id": "7e922887", "metadata": { "execution": { - "iopub.execute_input": "2026-05-12T18:47:30.442476Z", - "iopub.status.busy": "2026-05-12T18:47:30.442357Z", - "iopub.status.idle": "2026-05-12T18:47:30.445859Z", - "shell.execute_reply": "2026-05-12T18:47:30.445156Z" - } + "iopub.execute_input": "2026-09-28T01:05:58.960459Z", + "iopub.status.busy": "2026-09-28T01:05:58.959900Z", + "iopub.status.idle": "2026-09-28T01:05:58.964530Z", + "shell.execute_reply": "2026-09-28T01:05:58.963984Z" + }, + "papermill": { + "duration": 0.007615, + "end_time": "2026-09-28T01:05:58.965052", + "exception": false, + "start_time": "2026-09-28T01:05:58.957437", + "status": "completed" + }, + "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "==================================================\n", - "BACKTEST RESULTS (Author Reported)\n", - "==================================================\n", - "Long-term (5Y OOS):\n", - " CAGR: -15.71%\n", - " Max Drawdown: 80.80%\n", - " Sharpe: -0.041\n", + "==========================================================\n", + "REFERENCE: author-reported results of QC Library strategy #26\n", + "==========================================================\n", + " Long-term (5Y OOS): CAGR -15.71% | MaxDD 80.80% | Sharpe -0.041\n", + " Recent (OOS): 3M +38.85% | 1Y Sharpe 1.49 | 3M Sharpe 10.52\n", "\n", - "Recent (OOS):\n", - " 3M Return: 38.85%\n", - " 1Y Sharpe: 1.49\n", - " 3M Sharpe: 10.52\n", + "These are the strategy author's published numbers -- a DESIGN REFERENCE,\n", + "not a measurement made here. Read them honestly: a -15.7% 5Y CAGR with\n", + "80.8% drawdown followed by a +38.9% quarter with a 10.5 3M Sharpe is the\n", + "classic signature of a fragile, regime-dependent strategy, not an edge.\n", "\n", - "Run backtest via QC MCP to verify:\n", - " create_compile -> create_backtest -> read_backtest\n", - "\n", - "Characteristics:\n", - " Universe: 21 commodity futures (5 sectors)\n", - " Signal: Annualized roll return ranking\n", - " Selection: Top quintile backwardation (long) + contango (short)\n", - " Rebalance: Monthly, equal-weighted\n", - " Exposure: 10% gross per side\n" + "Measured in THIS notebook: the real 21-commodity universe and its\n", + "long-short quintile spread on realized front-month returns (above).\n", + "The true roll-return screen + full backtest: QC Cloud, companion project.\n" ] } ], "source": [ - "print(\"=\" * 50)\n", - "print(\"BACKTEST RESULTS (Author Reported)\")\n", - "print(\"=\" * 50)\n", - "print(\"Long-term (5Y OOS):\")\n", - "print(\" CAGR: -15.71%\")\n", - "print(\" Max Drawdown: 80.80%\")\n", - "print(\" Sharpe: -0.041\")\n", - "print()\n", - "print(\"Recent (OOS):\")\n", - "print(\" 3M Return: 38.85%\")\n", - "print(\" 1Y Sharpe: 1.49\")\n", - "print(\" 3M Sharpe: 10.52\")\n", + "print(\"=\" * 58)\n", + "print(\"REFERENCE: author-reported results of QC Library strategy #26\")\n", + "print(\"=\" * 58)\n", + "print(\" Long-term (5Y OOS): CAGR -15.71% | MaxDD 80.80% | Sharpe -0.041\")\n", + "print(\" Recent (OOS): 3M +38.85% | 1Y Sharpe 1.49 | 3M Sharpe 10.52\")\n", "print()\n", - "print(\"Run backtest via QC MCP to verify:\")\n", - "print(\" create_compile -> create_backtest -> read_backtest\")\n", + "print(\"These are the strategy author's published numbers -- a DESIGN REFERENCE,\")\n", + "print(\"not a measurement made here. Read them honestly: a -15.7% 5Y CAGR with\")\n", + "print(\"80.8% drawdown followed by a +38.9% quarter with a 10.5 3M Sharpe is the\")\n", + "print(\"classic signature of a fragile, regime-dependent strategy, not an edge.\")\n", "print()\n", - "print(\"Characteristics:\")\n", - "print(\" Universe: 21 commodity futures (5 sectors)\")\n", - "print(\" Signal: Annualized roll return ranking\")\n", - "print(\" Selection: Top quintile backwardation (long) + contango (short)\")\n", - "print(\" Rebalance: Monthly, equal-weighted\")\n", - "print(\" Exposure: 10% gross per side\")" + "print(\"Measured in THIS notebook: the real 21-commodity universe and its\")\n", + "print(\"long-short quintile spread on realized front-month returns (above).\")\n", + "print(\"The true roll-return screen + full backtest: QC Cloud, companion project.\")" + ] + }, + { + "cell_type": "markdown", + "id": "8ef1f469", + "metadata": { + "papermill": { + "duration": 0.001594, + "end_time": "2026-09-28T01:05:58.968239", + "exception": false, + "start_time": "2026-09-28T01:05:58.966645", + "status": "completed" + }, + "tags": [] + }, + "source": [ + "## Reading the measurements\n", + "\n", + "- The universe table above is **real market data** (front-month continuous\n", + " contracts), replacing the `np.random` \"simulated roll returns\" that stood\n", + " here -- the long-short spread is computed on realized returns, with the\n", + " substitution stated rather than disguised.\n", + "- The **true term-structure signal** (near/distant contract ratio) needs the\n", + " second expiry, which Yahoo does not expose reliably: it belongs to the QC\n", + " Cloud engine with multi-contract data, as stated in the cell.\n", + "- The author's own published numbers (5Y CAGR -15.71%, MaxDD 80.8%, then a\n", + " +38.9% quarter) are quoted as a design reference and read critically --\n", + " that pattern signals regime fragility, not a durable premium." ] } ], "metadata": { + "cost": { + "api_provider": "none", + "api_usd_est": 0.0, + "cpu_min": 0, + "external_account": "quantconnect-organization", + "free_alternative": null, + "gpu_required": false, + "metadata_written": "2026-07-26", + "network": true, + "qcc_tokens_est": 400, + "reduced_pedagogical": null, + "reproducibility": "MED", + "validator": "qc_cloud" + }, "kernelspec": { "display_name": "Python 3", "language": "python", @@ -239,23 +403,21 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.14" + "version": "3.11.9" }, - "cost": { - "api_usd_est": 0.0, - "api_provider": "none", - "qcc_tokens_est": 400, - "cpu_min": 0, - "gpu_required": false, - "network": true, - "external_account": "quantconnect-organization", - "free_alternative": null, - "reduced_pedagogical": null, - "reproducibility": "MED", - "metadata_written": "2026-07-26", - "validator": "qc_cloud" + "papermill": { + "default_parameters": {}, + "duration": 8.548489, + "end_time": "2026-09-28T01:05:59.221704", + "environment_variables": {}, + "exception": null, + "input_path": "MyIA.AI.Notebooks/QuantConnect/projects/Research-Executor/research_commodity_term_structure.ipynb", + "output_path": "research_commodity_term_structure.ipynb", + "parameters": {}, + "start_time": "2026-09-28T01:05:50.673215", + "version": "2.6.0" } }, "nbformat": 4, - "nbformat_minor": 2 -} + "nbformat_minor": 5 +} \ No newline at end of file