{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "p6-intro",
   "metadata": {},
   "source": [
    "# AlphaGen tutorial notebook\n",
    "\n",
    "This notebook drives a full calibration + prediction cycle against\n",
    "the AlphaGen REST API on the bundled TTF / IFS-weather sample data.\n",
    "\n",
    "The model is **`alphagen-3`**, the default every plan can run.\n",
    "This notebook stays on the standard calibration path — the\n",
    "walkforward mode is an advanced option and is not used here.\n",
    "\n",
    "## Prerequisites — team scope\n",
    "\n",
    "Every AlphaGen resource lives inside a **team**. Your API token is\n",
    "bound to one specific team; every request in this notebook acts on\n",
    "behalf of that team, sees only that team's projects, and counts\n",
    "against that team's plan quotas.\n",
    "\n",
    "- If you belong to a single team (typical solo signup), the personal\n",
    "  team auto-created on registration is used — nothing else to do.\n",
    "- If you belong to several teams, pick the right one when you create\n",
    "  the token in **Profile → API tokens**.\n",
    "- **Seat requirement** — calibrations, predictions and project\n",
    "  creation require a **`builder`** or **`manager`** seat in that team.\n",
    "  A `viewer` or `guest` token will hit `403` at the calibration step.\n",
    "- **Ejection auto-revokes the token** — if you get removed from the\n",
    "  team, every cell in this notebook will start returning `401`. Create\n",
    "  a new token from a team you still belong to.\n",
    "\n",
    "The auth check cell below prints the team currently bound to your\n",
    "token so you can confirm the scope before running anything else.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "initial_id",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:41:50.506294Z",
     "start_time": "2026-05-10T16:41:49.964865Z"
    },
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Importation of required libraries\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "import datetime as dt\n",
    "import time\n",
    "import requests\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import math\n",
    "from typing import Any\n",
    "import warnings\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "load_dotenv(dotenv_path=\".env\")\n",
    "TOKEN = os.getenv(\"ALPHAGEN_TOKEN\")\n",
    "URL = os.getenv(\"ALPHAGEN_API_URL\")\n",
    "WEBAPP_URL = os.getenv(\"ALPHAGEN_WEBAPP_URL\")\n",
    "PROJECT = \"DEMO_PROJECT\"\n",
    "\n",
    "# Create a new project if not exists\n",
    "headers = {\n",
    "            \"Authorization\": f\"Bearer {TOKEN}\",\n",
    "            \"Content-Type\": \"application/json\",\n",
    "        }\n",
    "res = requests.post(\n",
    "    f\"{URL}project/create\",\n",
    "    params={\"name\": PROJECT},\n",
    "    headers=headers\n",
    ")\n",
    "response = res.json()\n",
    "print(response)\n",
    "\n",
    "# Utilities functions\n",
    "def _is_nan_like(value: Any) -> bool:\n",
    "    # Détecte numpy.nan, pandas NA, float('nan')\n",
    "    try:\n",
    "        if value is None:\n",
    "            return False\n",
    "        # pandas NA (pandas.NA) - compare is not reliable, use pandas.isna\n",
    "        if pd.isna(value):\n",
    "            return True\n",
    "    except Exception:\n",
    "        pass\n",
    "    # numpy.nan etc.\n",
    "    if isinstance(value, float):\n",
    "        return not math.isfinite(value)\n",
    "    return False\n",
    "\n",
    "def _sanitize(obj: Any) -> Any:\n",
    "    # Recursively remplace NaN/NA/inf par None; convertit numpy types en types natifs\n",
    "    if isinstance(obj, dict):\n",
    "        return {k: _sanitize(v) for k, v in obj.items()}\n",
    "    if isinstance(obj, list):\n",
    "        return [_sanitize(v) for v in obj]\n",
    "    if isinstance(obj, tuple):\n",
    "        return tuple(_sanitize(v) for v in obj)\n",
    "    # numpy scalar\n",
    "    if isinstance(obj, (np.generic,)):\n",
    "        try:\n",
    "            py = obj.item()\n",
    "        except Exception:\n",
    "            py = obj\n",
    "        return _sanitize(py)\n",
    "    # pandas Timestamp / numpy datetime64 -> isoformat string\n",
    "    try:\n",
    "        if isinstance(obj, pd.Timestamp):\n",
    "            return obj.isoformat()\n",
    "    except Exception:\n",
    "        pass\n",
    "    # detect NaN / inf\n",
    "    if _is_nan_like(obj):\n",
    "        return None\n",
    "    return obj\n",
    "\n",
    "def _sanitize_payload(payload: Any) -> Any:\n",
    "    if payload is None:\n",
    "        return None\n",
    "    return _sanitize(payload)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "p6-team-check",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Confirm which team your token is bound to. This call reads the token,\n",
    "# resolves the (user, team) pair, and returns every team you belong to\n",
    "# plus the one currently active for this token.\n",
    "res = requests.get(f\"{URL}account/teams\", headers=headers)\n",
    "res.raise_for_status()\n",
    "teams = res.json()\n",
    "\n",
    "print(f\"Active team for this token: {teams['current_team_id']}\")\n",
    "print(\"You are a member of:\")\n",
    "for t in teams[\"teams\"]:\n",
    "    marker = \" (active)\" if t[\"id\"] == teams[\"current_team_id\"] else \"\"\n",
    "    print(f\"  - {t['name']:30s}  seat={t['seat']}  personal={t['is_personal']}{marker}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e485e65c728b35c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:41:50.749778Z",
     "start_time": "2026-05-10T16:41:50.509687Z"
    }
   },
   "outputs": [],
   "source": [
    "# We load and process our timeseries\n",
    "variables = pd.read_excel(\"data/forecast_ifs_allemagne_step_24.xlsx\")\n",
    "price = pd.read_excel(\"data/ttf.xlsx\")\n",
    "\n",
    "# We simulate 2 != files with 3 three variables\n",
    "X1 = variables[[\"Date\", \"Temperature (Celcius)\"]].rename(columns = {\n",
    "    \"Date\": \"date\", \"Temperature (Celcius)\": \"temperature\"\n",
    "})\n",
    "\n",
    "X2 = variables[[\"Date\", \"Wind speed (m/s)\"]].rename(columns = {\n",
    "    \"Date\": \"date\", \"Wind speed (m/s)\": \"wind_speed\"\n",
    "})\n",
    "X3 = variables[[\"Date\", \"Precipitation rate (mm/h)\"]].rename(columns = {\n",
    "    \"Date\": \"date\", \"Precipitation rate (mm/h)\": \"precip_rate\"\n",
    "})\n",
    "X2 = X2.set_index(\"date\").join(X3.set_index(\"date\"), how = \"outer\").reset_index()\n",
    "\n",
    "y = price[[\"date\", \"nearby\", \"px_delta\"]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5be0e56f22c731b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:41:50.762149Z",
     "start_time": "2026-05-10T16:41:50.752958Z"
    }
   },
   "outputs": [],
   "source": [
    "# We convert dataframe into json list of records\n",
    "y[\"date\"] = y[\"date\"].dt.strftime(\"%Y-%m-%d\")\n",
    "y = y.to_dict(orient=\"records\")\n",
    "\n",
    "X1[\"date\"] = X1[\"date\"].dt.strftime(\"%Y-%m-%d\")\n",
    "X1 = X1.to_dict(orient=\"records\")\n",
    "\n",
    "X2[\"date\"] = X2[\"date\"].dt.strftime(\"%Y-%m-%d\")\n",
    "X2 = X2.to_dict(orient=\"records\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "p6-seat-note",
   "metadata": {},
   "source": [
    "### Model Calibration Step\n",
    "\n",
    "> **Seat gate** — the `POST /model/calibrate` call below requires a\n",
    "> `builder` or `manager` seat in the team the token is bound to. A\n",
    "> `viewer` or `guest` token returns `403` with a seat message. See the\n",
    "> auth-check cell above if unsure of your seat.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5695a9b97d8dc0ae",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:41:50.769631Z",
     "start_time": "2026-05-10T16:41:50.765222Z"
    }
   },
   "outputs": [],
   "source": [
    "parameters = {\n",
    "    \"backtest\": {\n",
    "        \"compute_pnl_from_return\": True,\n",
    "        \"return_type\": \"px_delta\",\n",
    "        \"allocation_schema\": \"target_var\",\n",
    "        \"initial_liquidation_value\": 10_000_000,\n",
    "        \"contract_size\": 1,\n",
    "        \"max_value_at_risk\": 10_000,\n",
    "        \"signal_activation_model\": \"sign\", # \"linear\", \"sign\", \"tanh\"\n",
    "        # Only read when signal_activation_model == \"tanh\": steepness of\n",
    "        # the S-curve. 1.0 = soft, higher = closer to \"sign\".\n",
    "        \"signal_activation_slope\": 1.0,\n",
    "        \"start_date\": \"2023-01-01\",\n",
    "    },\n",
    "    \"datasets\": {\n",
    "        \"dataset_1\": {\n",
    "            \"variables\": {\n",
    "                \"temperature\": {\n",
    "                    \"monthly_analysis\": False,\n",
    "                    \"include_week_ends\": True,\n",
    "                    \"has_seasonality\": True,\n",
    "                    \"has_trend\": False,\n",
    "                    \"has_only_positive\": False,\n",
    "                    \"is_ndvi\": False,\n",
    "                    \"impact\": \"Negative\",\n",
    "                },\n",
    "            }\n",
    "        },\n",
    "        \"dataset_2\": {\n",
    "            \"variables\": {\n",
    "                \"wind_speed\": {\n",
    "                    \"monthly_analysis\": False,\n",
    "                    \"include_week_ends\": True,\n",
    "                    \"has_seasonality\": True,\n",
    "                    \"has_trend\": False,\n",
    "                    \"has_only_positive\": True,\n",
    "                    \"is_ndvi\": False,\n",
    "                    \"impact\": \"Negative\",\n",
    "                },\n",
    "                \"precip_rate\": {\n",
    "                    \"monthly_analysis\": False,\n",
    "                    \"include_week_ends\": True,\n",
    "                    \"has_seasonality\": True,\n",
    "                    \"has_trend\": False,\n",
    "                    \"has_only_positive\": True,\n",
    "                    \"is_ndvi\": False,\n",
    "                    \"impact\": \"Negative\",\n",
    "                },\n",
    "            }\n",
    "        }\n",
    "    },\n",
    "}\n",
    "\n",
    "payload = {\n",
    "    \"model\": \"alphagen-3\",\n",
    "    \"price\": {\n",
    "        \"name\"        : \"TTF Futures Prices\", # Provide a name for the price series\n",
    "        \"column_date\" : \"date\", # Specify the column name containing the date\n",
    "        \"column_price\": \"nearby\", # Specify the column name containing the price\n",
    "        \"column_delta\": \"px_delta\", # Specify the column name containing the price change\n",
    "        \"payload\": y # Provide the price series as a list of dictionaries\n",
    "    },\n",
    "    \"variables\": [\n",
    "        {\n",
    "            \"name\": \"Temperature\", # Provide a name for the variable\n",
    "            \"dataset\": \"dataset_1\",\n",
    "            \"column_date\": \"date\", # Specify the column name containing the date\n",
    "            \"column_variable\": \"temperature\", # Specify the column name containing the variable\n",
    "            \"payload\": X1 # Provide the variable series as a list of dictionaries\n",
    "        },\n",
    "        {\n",
    "            \"name\": \"Wind Speed\", # Provide a name for the variable\n",
    "            \"dataset\": \"dataset_2\",\n",
    "            \"column_date\": \"date\", # Specify the column name containing the date\n",
    "            \"column_variable\": \"wind_speed\", # Specify the column name containing the variable\n",
    "            \"payload\": X2 # Provide the variable series as a list of dictionaries\n",
    "        },\n",
    "        {\n",
    "            \"name\": \"Precipitation Rate\", # Provide a name for the variable\n",
    "            \"dataset\": \"dataset_2\",\n",
    "            \"column_date\": \"date\", # Specify the column name containing the date\n",
    "            \"column_variable\": \"precip_rate\", # Specify the column name containing the variable\n",
    "            \"payload\": X2 # Provide the variable series as a list of dictionaries\n",
    "        }\n",
    "    ],\n",
    "    \"tag\": \"tag-of-the-calibration\", # Provide a tag for the calibration to be able to track it later\n",
    "    \"description\": \"Tutorial calibration.\", # Provide a description for the calibration\n",
    "    \"parameters\": parameters\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8758f5eda8f71e1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:42:42.317083Z",
     "start_time": "2026-05-10T16:41:50.772098Z"
    }
   },
   "outputs": [],
   "source": [
    "headers = {\n",
    "            \"Authorization\": f\"Bearer {TOKEN}\",\n",
    "            \"Content-Type\": \"application/json\",\n",
    "        }\n",
    "\n",
    "safe_payload = _sanitize_payload(payload)\n",
    "res = requests.post(\n",
    "    f\"{URL}model/calibrate\",\n",
    "    json=safe_payload,\n",
    "    params={\"project_name\": PROJECT},\n",
    "    headers=headers\n",
    ")\n",
    "response = res.json()\n",
    "print(response)\n",
    "\n",
    "calibration_id = response[\"payload\"][\"id\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dc2d2d98869f2074",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:42:48.410278Z",
     "start_time": "2026-05-10T16:42:42.387818Z"
    }
   },
   "outputs": [],
   "source": [
    "done   = False\n",
    "while not done:\n",
    "    print (\"Waiting for calibration to be done\")\n",
    "    res = requests.get(\n",
    "        f\"{URL}model/fetch/calibration\",\n",
    "        params={\"calibration_id\": calibration_id},\n",
    "        headers=headers\n",
    "    )\n",
    "    response = res.json()\n",
    "    payload = response[\"payload\"]\n",
    "\n",
    "    done = payload[\"done\"]\n",
    "    time.sleep(5)\n",
    "\n",
    "payload = response[\"payload\"]\n",
    "calibration_data = payload.get(\"payload\")\n",
    "\n",
    "if payload[\"failed\"]:\n",
    "    print (\"Calibration failed! Check at your email for more information\")\n",
    "else:\n",
    "    print (\"Calibration done! You can checkout the result in this notebook or see them in the dashboard\")\n",
    "    print (f\"Dashboard URL: {WEBAPP_URL}/projects/{PROJECT}/calibrations/{calibration_id}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e8ae7dde0990047",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:42:48.457667Z",
     "start_time": "2026-05-10T16:42:48.445623Z"
    }
   },
   "outputs": [],
   "source": [
    "intensity_temperature = pd.DataFrame(calibration_data[\"results\"][\"variables\"][\"dataset_1.temperature\"][\"intensity\"])\n",
    "intensity_wind_speed  = pd.DataFrame(calibration_data[\"results\"][\"variables\"][\"dataset_2.wind_speed\"][\"intensity\"])\n",
    "intensity_precip_rate = pd.DataFrame(calibration_data[\"results\"][\"variables\"][\"dataset_2.precip_rate\"][\"intensity\"])\n",
    "intensity_aggregated  = pd.DataFrame(calibration_data[\"results\"][\"aggregation\"][\"intensity\"])[[\"date\", \"intensity\"]]\n",
    "\n",
    "intensity_df = pd.DataFrame()\n",
    "\n",
    "for variable, dataset in [\n",
    "    (\"temperature\", intensity_temperature),\n",
    "    (\"wind_speed\", intensity_wind_speed),\n",
    "    (\"precip_rate\", intensity_precip_rate),\n",
    "    (\"aggregation\", intensity_aggregated)\n",
    "]:\n",
    "    intensity_df = intensity_df.join(\n",
    "        dataset.set_index(\"date\").rename(columns={\"intensity\":variable}),\n",
    "        how = \"outer\"\n",
    "    )\n",
    "\n",
    "print (\"Intensities table:\")\n",
    "print(intensity_df.tail(10))\n",
    "\n",
    "print (\"\\n\\nBacktest results:\")\n",
    "print(pd.DataFrame(calibration_data[\"results\"][\"aggregation\"][\"yearly_statistics\"]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6162f24ae619df96",
   "metadata": {},
   "source": [
    "### Model Prediction Step"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f32bbc4eefb7e44",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:42:48.470443Z",
     "start_time": "2026-05-10T16:42:48.466399Z"
    }
   },
   "outputs": [],
   "source": [
    "parameters = {\n",
    "    \"backtest\": {\n",
    "        \"compute_pnl_from_return\": True,\n",
    "        \"return_type\": \"px_delta\",\n",
    "        \"allocation_schema\": \"target_var\",\n",
    "        \"initial_liquidation_value\": 10_000_000,\n",
    "        \"contract_size\": 1,\n",
    "        \"max_value_at_risk\": 10_000,\n",
    "        \"signal_activation_model\": \"sign\", # \"linear\", \"sign\", \"tanh\"\n",
    "        \"signal_activation_slope\": 1.0,   # only used when model == \"tanh\"\n",
    "        \"start_date\": \"2024-01-01\",\n",
    "    },\n",
    "}\n",
    "\n",
    "payload = {\n",
    "    \"price\": {\n",
    "        \"name\"        : \"TTF Futures Prices\", # Provide a name for the price series\n",
    "        \"column_date\" : \"date\", # Specify the column name containing the date\n",
    "        \"column_price\": \"nearby\", # Specify the column name containing the price\n",
    "        \"column_delta\": \"px_delta\", # Specify the column name containing the price change\n",
    "        \"payload\": y # Provide the price series as a list of dictionaries\n",
    "    },\n",
    "    \"variables\": [\n",
    "        {\n",
    "            \"name\": \"Temperature\", # Provide a name for the variable\n",
    "            \"dataset\": \"dataset_1\",\n",
    "            \"column_date\": \"date\", # Specify the column name containing the date\n",
    "            \"column_variable\": \"temperature\", # Specify the column name containing the variable\n",
    "            \"payload\": X1 # Provide the variable series as a list of dictionaries\n",
    "        },\n",
    "        {\n",
    "            \"name\": \"Wind Speed\", # Provide a name for the variable\n",
    "            \"dataset\": \"dataset_2\",\n",
    "            \"column_date\": \"date\", # Specify the column name containing the date\n",
    "            \"column_variable\": \"wind_speed\", # Specify the column name containing the variable\n",
    "            \"payload\": X2 # Provide the variable series as a list of dictionaries\n",
    "        },\n",
    "        {\n",
    "            \"name\": \"Precipitation Rate\", # Provide a name for the variable\n",
    "            \"dataset\": \"dataset_2\",\n",
    "            \"column_date\": \"date\", # Specify the column name containing the date\n",
    "            \"column_variable\": \"precip_rate\", # Specify the column name containing the variable\n",
    "            \"payload\": X2 # Provide the variable series as a list of dictionaries\n",
    "        }\n",
    "    ],\n",
    "    \"tag\": \"tag-of-the-prediction\", # Provide a tag for the calibration to be able to track it later\n",
    "    \"description\": \"Tutorial prediction.\", # Provide a description for the calibration\n",
    "    \"parameters\": parameters\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4c5a95b997142f42",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:43:06.095655Z",
     "start_time": "2026-05-10T16:42:48.473474Z"
    }
   },
   "outputs": [],
   "source": [
    "safe_payload = _sanitize_payload(payload)\n",
    "res = requests.post(\n",
    "    f\"{URL}model/predict\",\n",
    "    json=safe_payload,\n",
    "    params={\"calibration_id\": calibration_id},\n",
    "    headers=headers\n",
    ")\n",
    "response = res.json()\n",
    "print(response)\n",
    "\n",
    "prediction_id = response[\"payload\"][\"id\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6f13da6ea9cb4b8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:43:12.667747Z",
     "start_time": "2026-05-10T16:43:06.143378Z"
    }
   },
   "outputs": [],
   "source": [
    "done   = False\n",
    "while not done:\n",
    "    print (\"Waiting for prediction to be done\")\n",
    "    res = requests.get(\n",
    "        f\"{URL}model/fetch/prediction\",\n",
    "        params={\"prediction_id\": prediction_id},\n",
    "        headers=headers\n",
    "    )\n",
    "    response = res.json()\n",
    "    payload = response[\"payload\"]\n",
    "\n",
    "    done = payload[\"done\"]\n",
    "    time.sleep(5)\n",
    "\n",
    "payload = response[\"payload\"]\n",
    "prediction_data = payload.get(\"payload\")\n",
    "\n",
    "if payload[\"failed\"]:\n",
    "    print (\"Prediction failed! Check at your email for more information\")\n",
    "else:\n",
    "    print (\"Prediction done! You can checkout the result in this notebook or see them in the dashboard\")\n",
    "    print (f\"Dashboard URL: {WEBAPP_URL}/projects/{PROJECT}/calibrations/{calibration_id}/predictions/{prediction_id}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b883f04aa2f55a33",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:43:12.734738Z",
     "start_time": "2026-05-10T16:43:12.722219Z"
    }
   },
   "outputs": [],
   "source": [
    "intensity_temperature = pd.DataFrame(prediction_data[\"results\"][\"variables\"][\"dataset_1.temperature\"][\"intensity\"])\n",
    "intensity_wind_speed  = pd.DataFrame(prediction_data[\"results\"][\"variables\"][\"dataset_2.wind_speed\"][\"intensity\"])\n",
    "intensity_precip_rate = pd.DataFrame(prediction_data[\"results\"][\"variables\"][\"dataset_2.precip_rate\"][\"intensity\"])\n",
    "intensity_aggregated  = pd.DataFrame(prediction_data[\"results\"][\"aggregation\"][\"intensity\"])[[\"date\", \"intensity\"]]\n",
    "\n",
    "intensity_df = pd.DataFrame()\n",
    "\n",
    "for variable, dataset in [\n",
    "    (\"temperature\", intensity_temperature),\n",
    "    (\"wind_speed\", intensity_wind_speed),\n",
    "    (\"precip_rate\", intensity_precip_rate),\n",
    "    (\"aggregation\", intensity_aggregated)\n",
    "]:\n",
    "    intensity_df = intensity_df.join(\n",
    "        dataset.set_index(\"date\").rename(columns={\"intensity\":variable}),\n",
    "        how = \"outer\"\n",
    "    )\n",
    "\n",
    "print (\"Intensities table:\")\n",
    "print(intensity_df.tail(10))\n",
    "\n",
    "print (\"\\n\\nBacktest results:\")\n",
    "print(pd.DataFrame(prediction_data[\"results\"][\"aggregation\"][\"yearly_statistics\"]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a463a7c78bdae789",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-05-10T16:43:12.741056Z",
     "start_time": "2026-05-10T16:43:12.739075Z"
    }
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
