{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "eba5be7c",
      "metadata": {},
      "source": [
        "# What-if scenarios\n",
        "\n",
        "**Prerequisites**\n",
        "* *Portfolios API* Tutorial\n",
        "* *Portfolio Hierarchies* Tutorial\n",
        "\n",
        "A scenario changes a report input without changing the uploaded holdings or the\n",
        "saved report settings. Applying one produces a new accessor; the original report\n",
        "remains available for comparison.\n",
        "\n",
        "This tutorial covers two portfolio what-if questions:\n",
        "\n",
        "1. What happens if an existing child portfolio changes one asset position?\n",
        "2. What happens if a fund of funds starts holding a portfolio that was previously\n",
        "   available only as a standalone portfolio?"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "952265ac",
      "metadata": {},
      "source": [
        "## Imports and setup"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "3b3cbe92",
      "metadata": {},
      "outputs": [],
      "source": [
        "import datetime as dt\n",
        "\n",
        "import polars as pl\n",
        "\n",
        "from bayesline.apiclient import BayeslineApiClient\n",
        "from bayesline.api.equity import (\n",
        "    HoldingsOverrideWindow,\n",
        "    OverrideUnit,\n",
        "    PortfolioHierarchySettings,\n",
        "    PortfolioHoldingsReportSettings,\n",
        "    PortfolioHoldingsScenario,\n",
        "    PortfolioOrganizerSettings,\n",
        "    PortfolioOverride,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a5c7fdb8",
      "metadata": {
        "tags": [
          "skip-execution"
        ]
      },
      "outputs": [],
      "source": [
        "bln = BayeslineApiClient.new_client(\n",
        "    endpoint=\"https://[ENDPOINT]\",\n",
        "    api_key=\"[API-KEY]\",\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "8806ecd2",
      "metadata": {},
      "outputs": [],
      "source": [
        "dataset_name = \"bayesline/Bayesline-US-All-1y\"\n",
        "start_date = dt.date(2026, 1, 5)\n",
        "end_date = dt.date(2026, 1, 30)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5349e2d0",
      "metadata": {},
      "source": [
        "## Create a small fund-of-funds example\n",
        "\n",
        "The baseline parent holds `whatif-existing-child` plus one security directly.\n",
        "`whatif-new-child` is uploaded separately and selected by the organizer, but it is\n",
        "not held by the parent. Keeping it in a second upload also demonstrates that a\n",
        "scenario edge is not restricted to portfolios from the same upload."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "26bd8119",
      "metadata": {},
      "outputs": [],
      "source": [
        "uploader = bln.equity.uploaders.get_data_type(\"portfolios\")\n",
        "parent_source = uploader.create_or_replace_dataset(\"whatif-parent-source\")\n",
        "child_source = uploader.create_or_replace_dataset(\"whatif-child-source\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "df19ad9f",
      "metadata": {},
      "outputs": [],
      "source": [
        "parent_holdings = pl.DataFrame(\n",
        "    {\n",
        "        \"portfolio_id\": [\n",
        "            \"whatif-parent\",\n",
        "            \"whatif-parent\",\n",
        "            \"whatif-parent\",\n",
        "            \"whatif-parent\",\n",
        "            \"whatif-existing-child\",\n",
        "            \"whatif-existing-child\",\n",
        "            \"whatif-existing-child\",\n",
        "            \"whatif-existing-child\",\n",
        "        ],\n",
        "        \"asset_id\": [\n",
        "            \"whatif-existing-child\",\n",
        "            \"whatif-existing-child\",\n",
        "            \"67066G10\",\n",
        "            \"67066G10\",\n",
        "            \"02079K305\",\n",
        "            \"02079K305\",\n",
        "            \"2588173\",\n",
        "            \"2588173\",\n",
        "        ],\n",
        "        \"asset_id_type\": [\n",
        "            \"portfolio_id\",\n",
        "            \"portfolio_id\",\n",
        "            \"cusip8\",\n",
        "            \"cusip8\",\n",
        "            \"cusip9\",\n",
        "            \"cusip9\",\n",
        "            \"sedol7\",\n",
        "            \"sedol7\",\n",
        "        ],\n",
        "        \"date\": [\n",
        "            dt.date(2026, 1, 1),\n",
        "            dt.date(2026, 1, 31),\n",
        "            dt.date(2026, 1, 1),\n",
        "            dt.date(2026, 1, 31),\n",
        "            dt.date(2026, 1, 1),\n",
        "            dt.date(2026, 1, 31),\n",
        "            dt.date(2026, 1, 1),\n",
        "            dt.date(2026, 1, 31),\n",
        "        ],\n",
        "        \"currency\": [None] * 8,\n",
        "        \"share_qty\": [None] * 8,\n",
        "        \"nav\": [80.0, 80.0, 20.0, 20.0, 60.0, 60.0, 40.0, 40.0],\n",
        "    }\n",
        ").with_columns(\n",
        "    pl.col(\"currency\").cast(pl.String),\n",
        "    pl.col(\"share_qty\").cast(pl.Float64),\n",
        ")\n",
        "\n",
        "new_child_holdings = pl.DataFrame(\n",
        "    {\n",
        "        \"portfolio_id\": [\"whatif-new-child\"] * 4,\n",
        "        \"asset_id\": [\"85371710\", \"85371710\", \"67066G10\", \"67066G10\"],\n",
        "        \"asset_id_type\": [\"cusip8\"] * 4,\n",
        "        \"date\": [\n",
        "            dt.date(2026, 1, 1),\n",
        "            dt.date(2026, 1, 31),\n",
        "            dt.date(2026, 1, 1),\n",
        "            dt.date(2026, 1, 31),\n",
        "        ],\n",
        "        \"currency\": [None] * 4,\n",
        "        \"share_qty\": [None] * 4,\n",
        "        \"nav\": [50.0, 50.0, 50.0, 50.0],\n",
        "    }\n",
        ").with_columns(\n",
        "    pl.col(\"currency\").cast(pl.String),\n",
        "    pl.col(\"share_qty\").cast(pl.Float64),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "ae0319ad",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "UploadCommitResult(version=1, committed_names=[])"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "parent_source.fast_commit(parent_holdings, mode=\"append\")\n",
        "child_source.fast_commit(new_child_holdings, mode=\"append\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b25a7795",
      "metadata": {},
      "source": [
        "The organizer selects all three source portfolios. The hierarchy exposes the\n",
        "parent and the prospective child as roots. Auto-decomposition expands the\n",
        "parent's baseline child and adds a `{REST}` row for its direct security holding."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "e37fceee",
      "metadata": {},
      "outputs": [],
      "source": [
        "organizer = PortfolioOrganizerSettings(\n",
        "    enabled_portfolios={\n",
        "        \"whatif-parent\": \"whatif-parent-source\",\n",
        "        \"whatif-existing-child\": \"whatif-parent-source\",\n",
        "        \"whatif-new-child\": \"whatif-child-source\",\n",
        "    }\n",
        ")\n",
        "hierarchy = PortfolioHierarchySettings(\n",
        "    portfolio_schema=organizer,\n",
        "    portfolio_ids=[\"whatif-parent\", \"whatif-new-child\"],\n",
        "    benchmark_ids=[None, None],\n",
        "    auto_decompose_levels=[\"fund\", \"child\"],\n",
        ")\n",
        "\n",
        "report_settings = PortfolioHoldingsReportSettings(\n",
        "    portfolio_hierarchy_settings=hierarchy,\n",
        "    currency=\"USD\",\n",
        ")\n",
        "report_engine = bln.equity.reports.load(report_settings.with_dataset(dataset_name))\n",
        "base = report_engine.calculate(\n",
        "    portfolio_names=None,\n",
        "    start_date=start_date,\n",
        "    end_date=end_date,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "d7cd9860",
      "metadata": {},
      "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: (3, 1)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>portfolio_id</th></tr><tr><td>str</td></tr></thead><tbody><tr><td>&quot;whatif-parent:whatif-existing-…</td></tr><tr><td>&quot;whatif-parent:{REST}&quot;</td></tr><tr><td>&quot;whatif-new-child&quot;</td></tr></tbody></table></div>"
            ],
            "text/plain": [
              "shape: (3, 1)\n",
              "┌─────────────────────────────────┐\n",
              "│ portfolio_id                    │\n",
              "│ ---                             │\n",
              "│ str                             │\n",
              "╞═════════════════════════════════╡\n",
              "│ whatif-parent:whatif-existing-… │\n",
              "│ whatif-parent:{REST}            │\n",
              "│ whatif-new-child                │\n",
              "└─────────────────────────────────┘"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "base.accessor.get_level_values((\"portfolio_id\",))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15378de5",
      "metadata": {},
      "source": [
        "## Asset holding scenario\n",
        "\n",
        "Scenario asset targets use the resolved asset identifier. We obtain it from the\n",
        "report instead of assuming which identifier the dataset uses internally."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "91c9e18d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'ICA17F00B9'"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "base_holdings = base.holdings()\n",
        "asset_id = (\n",
        "    base_holdings.filter(pl.col(\"input_asset_id\") == \"02079K305\")\n",
        "    .get_column(\"asset_id\")\n",
        "    .first()\n",
        ")\n",
        "assert isinstance(asset_id, str)\n",
        "asset_id"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "95ed8e6c",
      "metadata": {},
      "outputs": [],
      "source": [
        "asset_scenario = PortfolioHoldingsScenario(\n",
        "    portfolios={\n",
        "        \"whatif-existing-child\": PortfolioOverride(\n",
        "            windows=[\n",
        "                HoldingsOverrideWindow(\n",
        "                    start_date=start_date,\n",
        "                    end_date=end_date,\n",
        "                    overrides={asset_id: 90.0},\n",
        "                )\n",
        "            ]\n",
        "        )\n",
        "    }\n",
        ")\n",
        "asset_case = base.with_scenario(asset_scenario)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4ba79c75",
      "metadata": {},
      "source": [
        "The override is applied to the child portfolio and automatically cascades into\n",
        "the parent. The base and scenario accessors can be queried independently."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "756ec31a",
      "metadata": {},
      "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: (38, 6)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>date</th><th>portfolio_id</th><th>asset_id</th><th>nav</th><th>weight</th><th>case</th></tr><tr><td>date</td><td>str</td><td>str</td><td>f32</td><td>f32</td><td>str</td></tr></thead><tbody><tr><td>2026-01-05</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>72.0</td><td>0.58318</td><td>&quot;asset scenario&quot;</td></tr><tr><td>2026-01-05</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>48.542881</td><td>0.48541</td><td>&quot;base&quot;</td></tr><tr><td>2026-01-06</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>71.499603</td><td>0.580162</td><td>&quot;asset scenario&quot;</td></tr><tr><td>2026-01-06</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>48.205517</td><td>0.482312</td><td>&quot;base&quot;</td></tr><tr><td>2026-01-07</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>73.237373</td><td>0.583531</td><td>&quot;asset scenario&quot;</td></tr><tr><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td></tr><tr><td>2026-01-28</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>51.528687</td><td>0.495776</td><td>&quot;base&quot;</td></tr><tr><td>2026-01-29</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>76.938148</td><td>0.609332</td><td>&quot;asset scenario&quot;</td></tr><tr><td>2026-01-29</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>51.872215</td><td>0.512569</td><td>&quot;base&quot;</td></tr><tr><td>2026-01-30</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>76.881271</td><td>0.610901</td><td>&quot;asset scenario&quot;</td></tr><tr><td>2026-01-30</td><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;ICA17F00B9&quot;</td><td>51.83387</td><td>0.514216</td><td>&quot;base&quot;</td></tr></tbody></table></div>"
            ],
            "text/plain": [
              "shape: (38, 6)\n",
              "┌────────────┬────────────────────────────────┬────────────┬───────────┬──────────┬────────────────┐\n",
              "│ date       ┆ portfolio_id                   ┆ asset_id   ┆ nav       ┆ weight   ┆ case           │\n",
              "│ ---        ┆ ---                            ┆ ---        ┆ ---       ┆ ---      ┆ ---            │\n",
              "│ date       ┆ str                            ┆ str        ┆ f32       ┆ f32      ┆ str            │\n",
              "╞════════════╪════════════════════════════════╪════════════╪═══════════╪══════════╪════════════════╡\n",
              "│ 2026-01-05 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 72.0      ┆ 0.58318  ┆ asset scenario │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-05 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 48.542881 ┆ 0.48541  ┆ base           │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-06 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 71.499603 ┆ 0.580162 ┆ asset scenario │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-06 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 48.205517 ┆ 0.482312 ┆ base           │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-07 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 73.237373 ┆ 0.583531 ┆ asset scenario │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ …          ┆ …                              ┆ …          ┆ …         ┆ …        ┆ …              │\n",
              "│ 2026-01-28 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 51.528687 ┆ 0.495776 ┆ base           │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-29 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 76.938148 ┆ 0.609332 ┆ asset scenario │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-29 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 51.872215 ┆ 0.512569 ┆ base           │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-30 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 76.881271 ┆ 0.610901 ┆ asset scenario │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "│ 2026-01-30 ┆ whatif-parent:whatif-existing- ┆ ICA17F00B9 ┆ 51.83387  ┆ 0.514216 ┆ base           │\n",
              "│            ┆ …                              ┆            ┆           ┆          ┆                │\n",
              "└────────────┴────────────────────────────────┴────────────┴───────────┴──────────┴────────────────┘"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "base_asset = base.accessor.get_data(\n",
        "    [\n",
        "        (\"portfolio_id\", \"whatif-parent:whatif-existing-child\"),\n",
        "        (\"asset_id\", asset_id),\n",
        "    ],\n",
        "    expand=(\"date\",),\n",
        "    value_cols=(\"nav\", \"weight\"),\n",
        ")\n",
        "scenario_asset = asset_case.accessor.get_data(\n",
        "    [\n",
        "        (\"portfolio_id\", \"whatif-parent:whatif-existing-child\"),\n",
        "        (\"asset_id\", asset_id),\n",
        "    ],\n",
        "    expand=(\"date\",),\n",
        "    value_cols=(\"nav\", \"weight\"),\n",
        ")\n",
        "\n",
        "pl.concat(\n",
        "    [\n",
        "        base_asset.with_columns(pl.lit(\"base\").alias(\"case\")),\n",
        "        scenario_asset.with_columns(pl.lit(\"asset scenario\").alias(\"case\")),\n",
        "    ]\n",
        ").sort(\"date\", \"case\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "029a6686",
      "metadata": {},
      "source": [
        "## Add a child portfolio to the fund of funds\n",
        "\n",
        "The new child is already selected by the organizer and therefore already exists\n",
        "on the report's source-portfolio axis. It is not a child of `whatif-parent` in\n",
        "the uploaded holdings. Setting a nonzero override creates that scenario-only\n",
        "edge. Here we express the new parent-child holding as 25% of the parent's NAV."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "e210b149",
      "metadata": {},
      "outputs": [],
      "source": [
        "fof_scenario = PortfolioHoldingsScenario(\n",
        "    portfolios={\n",
        "        \"whatif-parent\": PortfolioOverride(\n",
        "            windows=[\n",
        "                HoldingsOverrideWindow(\n",
        "                    start_date=start_date,\n",
        "                    end_date=end_date,\n",
        "                    overrides={\"whatif-new-child\": 0.25},\n",
        "                    override_unit=OverrideUnit.WEIGHT,\n",
        "                )\n",
        "            ]\n",
        "        )\n",
        "    }\n",
        ")\n",
        "fof_case = base.with_scenario(fof_scenario)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fc1cca98",
      "metadata": {},
      "source": [
        "Applying the scenario atomically adds the derived path to the new accessor's\n",
        "portfolio hierarchy. The original accessor remains unchanged and keeps its\n",
        "original portfolio-axis hash."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "ca806cff",
      "metadata": {},
      "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>portfolio_id</th><th>case</th></tr><tr><td>str</td><td>str</td></tr></thead><tbody><tr><td>&quot;whatif-new-child&quot;</td><td>&quot;FoF scenario&quot;</td></tr><tr><td>&quot;whatif-new-child&quot;</td><td>&quot;base&quot;</td></tr><tr><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;FoF scenario&quot;</td></tr><tr><td>&quot;whatif-parent:whatif-existing-…</td><td>&quot;base&quot;</td></tr><tr><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;FoF scenario&quot;</td></tr><tr><td>&quot;whatif-parent:{REST}&quot;</td><td>&quot;FoF scenario&quot;</td></tr><tr><td>&quot;whatif-parent:{REST}&quot;</td><td>&quot;base&quot;</td></tr></tbody></table></div>"
            ],
            "text/plain": [
              "shape: (7, 2)\n",
              "┌─────────────────────────────────┬──────────────┐\n",
              "│ portfolio_id                    ┆ case         │\n",
              "│ ---                             ┆ ---          │\n",
              "│ str                             ┆ str          │\n",
              "╞═════════════════════════════════╪══════════════╡\n",
              "│ whatif-new-child                ┆ FoF scenario │\n",
              "│ whatif-new-child                ┆ base         │\n",
              "│ whatif-parent:whatif-existing-… ┆ FoF scenario │\n",
              "│ whatif-parent:whatif-existing-… ┆ base         │\n",
              "│ whatif-parent:whatif-new-child  ┆ FoF scenario │\n",
              "│ whatif-parent:{REST}            ┆ FoF scenario │\n",
              "│ whatif-parent:{REST}            ┆ base         │\n",
              "└─────────────────────────────────┴──────────────┘"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "base_portfolios = base.accessor.get_level_values((\"portfolio_id\",))\n",
        "scenario_portfolios = fof_case.accessor.get_level_values((\"portfolio_id\",))\n",
        "\n",
        "new_path = \"whatif-parent:whatif-new-child\"\n",
        "assert new_path not in base_portfolios.get_column(\"portfolio_id\")\n",
        "assert new_path in scenario_portfolios.get_column(\"portfolio_id\")\n",
        "assert (\n",
        "    base.accessor.axes_hashes[\"portfolio\"]\n",
        "    != fof_case.accessor.axes_hashes[\"portfolio\"]\n",
        ")\n",
        "\n",
        "pl.concat(\n",
        "    [\n",
        "        base_portfolios.with_columns(pl.lit(\"base\").alias(\"case\")),\n",
        "        scenario_portfolios.with_columns(pl.lit(\"FoF scenario\").alias(\"case\")),\n",
        "    ]\n",
        ").sort(\"portfolio_id\", \"case\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ae1ae0d7",
      "metadata": {},
      "source": [
        "The new row behaves like any other portfolio path. We can drill into it using\n",
        "the standard accessor API; its holdings come from the already-loaded standalone\n",
        "child portfolio."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "17bd442e",
      "metadata": {},
      "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: (19, 5)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>date</th><th>portfolio_id</th><th>input_asset_id</th><th>nav</th><th>weight</th></tr><tr><td>date</td><td>str</td><td>str</td><td>f32</td><td>f32</td></tr></thead><tbody><tr><td>2026-01-05</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>25.000996</td><td>0.2</td></tr><tr><td>2026-01-06</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>24.884048</td><td>0.199342</td></tr><tr><td>2026-01-07</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>25.132568</td><td>0.198238</td></tr><tr><td>2026-01-08</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>24.591665</td><td>0.195206</td></tr><tr><td>2026-01-09</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>24.567745</td><td>0.194223</td></tr><tr><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td></tr><tr><td>2026-01-26</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>24.781715</td><td>0.195127</td></tr><tr><td>2026-01-27</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>25.054157</td><td>0.195165</td></tr><tr><td>2026-01-28</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>25.452854</td><td>0.196717</td></tr><tr><td>2026-01-29</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>25.584423</td><td>0.201794</td></tr><tr><td>2026-01-30</td><td>&quot;whatif-parent:whatif-new-child&quot;</td><td>&quot;67066G10&quot;</td><td>25.401026</td><td>0.201272</td></tr></tbody></table></div>"
            ],
            "text/plain": [
              "shape: (19, 5)\n",
              "┌────────────┬────────────────────────────────┬────────────────┬───────────┬──────────┐\n",
              "│ date       ┆ portfolio_id                   ┆ input_asset_id ┆ nav       ┆ weight   │\n",
              "│ ---        ┆ ---                            ┆ ---            ┆ ---       ┆ ---      │\n",
              "│ date       ┆ str                            ┆ str            ┆ f32       ┆ f32      │\n",
              "╞════════════╪════════════════════════════════╪════════════════╪═══════════╪══════════╡\n",
              "│ 2026-01-05 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 25.000996 ┆ 0.2      │\n",
              "│ 2026-01-06 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 24.884048 ┆ 0.199342 │\n",
              "│ 2026-01-07 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 25.132568 ┆ 0.198238 │\n",
              "│ 2026-01-08 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 24.591665 ┆ 0.195206 │\n",
              "│ 2026-01-09 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 24.567745 ┆ 0.194223 │\n",
              "│ …          ┆ …                              ┆ …              ┆ …         ┆ …        │\n",
              "│ 2026-01-26 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 24.781715 ┆ 0.195127 │\n",
              "│ 2026-01-27 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 25.054157 ┆ 0.195165 │\n",
              "│ 2026-01-28 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 25.452854 ┆ 0.196717 │\n",
              "│ 2026-01-29 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 25.584423 ┆ 0.201794 │\n",
              "│ 2026-01-30 ┆ whatif-parent:whatif-new-child ┆ 67066G10       ┆ 25.401026 ┆ 0.201272 │\n",
              "└────────────┴────────────────────────────────┴────────────────┴───────────┴──────────┘"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "fof_case.accessor.get_data(\n",
        "    [(\"portfolio_id\", new_path)],\n",
        "    expand=(\"date\", \"input_asset_id\"),\n",
        "    value_cols=(\"nav\", \"weight\"),\n",
        "    absent=\"drop\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bdf8cb16",
      "metadata": {},
      "source": [
        "Any number of previously absent children can be added in the same scenario.\n",
        "The hierarchy expansion, `{REST}` rewrite, and lookthrough compilation happen\n",
        "together, leaving the base accessor and uploaded holdings untouched."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8208d5cc",
      "metadata": {},
      "source": [
        "## Housekeeping"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "2f260950",
      "metadata": {},
      "outputs": [],
      "source": [
        "parent_source.destroy()\n",
        "child_source.destroy()"
      ]
    }
  ],
  "metadata": {
    "jupytext": {
      "text_representation": {
        "extension": ".py",
        "format_name": "percent",
        "format_version": "1.3",
        "jupytext_version": "1.19.3"
      }
    },
    "kernelspec": {
      "display_name": ".venv",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.11.15"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}