Project_Carmignac/analyse_rupture.ipynb

1213 lines
913 KiB
Plaintext
Raw Normal View History

2026-02-02 00:52:00 +01:00
{
"cells": [
{
2026-04-05 17:49:37 +02:00
"cell_type": "markdown",
"id": "ed5a464c",
2026-02-02 00:52:00 +01:00
"metadata": {},
"source": [
2026-04-05 17:49:37 +02:00
"# AUMFlow Consistency Analysis\n",
"\n",
"3 sections: \n",
"1. Build Panel\n",
"2. Rupture Detection (data-driven threshold)\n",
"3. Figures & Diagnostics"
]
},
{
"cell_type": "markdown",
"id": "d3e84a67",
"metadata": {},
"source": [
"## 0. Imports & Data Loading"
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "code",
2026-04-05 17:49:37 +02:00
"execution_count": 1,
"id": "68b07738",
2026-02-02 00:52:00 +01:00
"metadata": {},
"outputs": [
{
2026-04-05 17:49:37 +02:00
"name": "stdout",
2026-02-02 00:52:00 +01:00
"output_type": "stream",
"text": [
2026-04-05 17:49:37 +02:00
"Stocks: (4880297, 19)\n",
"Flows: (2574461, 25)\n"
2026-02-02 00:52:00 +01:00
]
}
],
"source": [
2026-04-05 17:49:37 +02:00
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import plotly.graph_objects as go\n",
"\n",
"stocks = pd.read_csv('stocks.csv', low_memory=False)\n",
"flows = pd.read_csv('flows.csv', low_memory=False)\n",
"\n",
"stocks[\"Centralisation Date\"] = pd.to_datetime(stocks[\"Centralisation Date\"])\n",
"flows[\"Centralisation Date\"] = pd.to_datetime(flows[\"Centralisation Date\"])\n",
"\n",
"print(f\"Stocks: {stocks.shape}\")\n",
"print(f\"Flows: {flows.shape}\")"
]
},
{
"cell_type": "markdown",
"id": "eb07a566",
"metadata": {},
"source": [
"## 1. Build Panel (Account x ISIN x Date)\n",
"\n",
"Merge AUM and flows at the finest granularity. Missing flows are filled with 0. Lagged variables are computed to reconstruct the accounting identity Q(t) = Q(t-1) + F(t-1)."
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "code",
2026-04-05 17:49:37 +02:00
"execution_count": 2,
"id": "851395c4",
2026-02-02 00:52:00 +01:00
"metadata": {},
"outputs": [
{
2026-04-05 17:49:37 +02:00
"name": "stdout",
2026-02-02 00:52:00 +01:00
"output_type": "stream",
"text": [
2026-04-05 17:49:37 +02:00
"Panel size: (4880297, 11)\n",
"Accounts: 12,501\n",
"ISINs: 491\n",
"Dates: 130\n"
2026-02-02 00:52:00 +01:00
]
}
],
"source": [
2026-04-05 17:49:37 +02:00
"KEY = [\"Registrar Account - ID\", \"Product - Isin\", \"Centralisation Date\"]\n",
"GROUP = [\"Registrar Account - ID\", \"Product - Isin\"]\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"stocks_panel = stocks[KEY + [\"Quantity - AUM\"]].copy()\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"flows_panel = (\n",
" flows[KEY + [\"Quantity - NetFlows\"]]\n",
" .groupby(KEY, as_index=False)[\"Quantity - NetFlows\"]\n",
2026-02-02 00:52:00 +01:00
" .sum()\n",
")\n",
"\n",
2026-04-05 17:49:37 +02:00
"df = stocks_panel.merge(flows_panel, on=KEY, how=\"left\")\n",
"df[\"Quantity - NetFlows\"] = df[\"Quantity - NetFlows\"].fillna(0)\n",
"df = df.sort_values(KEY)\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"df[\"prev_stock\"] = df.groupby(GROUP)[\"Quantity - AUM\"].shift(1)\n",
"df[\"prev_flows\"] = df.groupby(GROUP)[\"Quantity - NetFlows\"].shift(1).fillna(0)\n",
"df[\"expected_stock\"] = df[\"prev_stock\"] + df[\"prev_flows\"]\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"df[\"gap\"] = df[\"Quantity - AUM\"] - df[\"expected_stock\"]\n",
"df[\"gap_abs\"] = df[\"gap\"].abs()\n",
"df[\"gap_rel\"] = df[\"gap_abs\"] / df[\"prev_stock\"].abs().replace(0, np.nan)\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"print(f\"Panel size: {df.shape}\")\n",
"print(f\"Accounts: {df['Registrar Account - ID'].nunique():,}\")\n",
"print(f\"ISINs: {df['Product - Isin'].nunique():,}\")\n",
"print(f\"Dates: {df['Centralisation Date'].nunique():,}\")"
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "markdown",
2026-04-05 17:49:37 +02:00
"id": "dec85f01",
2026-02-02 00:52:00 +01:00
"metadata": {},
"source": [
2026-04-05 17:49:37 +02:00
"## 2. Rupture Detection (data-driven threshold)\n",
"\n",
"The detection threshold EPSILON is calibrated from the data:\n",
"1. Trim the top 10% of relative gaps to avoid calibrating on resets\n",
"2. Define EPSILON as the 99th percentile of the trimmed distribution\n",
"\n",
"A rupture is flagged when gap_rel > EPSILON, conditional on prev_stock > 0."
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "code",
2026-04-05 17:49:37 +02:00
"execution_count": 3,
"id": "bd7cfce8",
2026-02-02 00:52:00 +01:00
"metadata": {},
2026-04-05 17:49:37 +02:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Detection threshold EPSILON: 32.4591%\n",
"Total ruptures detected: 189,537\n",
"Share of observations flagged: 3.88%\n"
]
}
],
2026-02-02 00:52:00 +01:00
"source": [
2026-04-05 17:49:37 +02:00
"# Calibration sample: valid observations with positive previous stock\n",
"valid_gaps = df.loc[\n",
" df[\"gap_rel\"].notna() & (df[\"prev_stock\"] > 0),\n",
" \"gap_rel\"\n",
"]\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"# Trim top 10% to avoid calibrating on structural resets\n",
"gap_rel_trimmed = valid_gaps[valid_gaps <= valid_gaps.quantile(0.90)]\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"# EPSILON = 99th percentile of the trimmed distribution\n",
"EPSILON = gap_rel_trimmed.quantile(0.99)\n",
"print(f\"Detection threshold EPSILON: {EPSILON:.4%}\")\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"# Flag ruptures\n",
2026-02-02 00:52:00 +01:00
"df[\"rupture_flag\"] = (\n",
" df[\"prev_stock\"].notna()\n",
2026-04-05 17:49:37 +02:00
" & (df[\"prev_stock\"] > 0)\n",
" & (df[\"gap_rel\"] > EPSILON)\n",
2026-02-02 00:52:00 +01:00
")\n",
"\n",
2026-04-05 17:49:37 +02:00
"# Remove edge effect at last observation date\n",
2026-02-02 00:52:00 +01:00
"last_date = df[\"Centralisation Date\"].max()\n",
2026-04-05 17:49:37 +02:00
"df.loc[(df[\"rupture_flag\"]) & (df[\"Centralisation Date\"] == last_date), \"rupture_flag\"] = False\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"# ISIN-level summary\n",
2026-02-02 00:52:00 +01:00
"rupture_isin_summary = (\n",
2026-04-05 17:49:37 +02:00
" df.groupby(GROUP)\n",
2026-02-02 00:52:00 +01:00
" .agg(\n",
2026-04-05 17:49:37 +02:00
" n_ruptures =(\"rupture_flag\", \"sum\"),\n",
" total_obs =(\"rupture_flag\", \"count\"),\n",
2026-02-02 00:52:00 +01:00
" rupture_ratio=(\"rupture_flag\", \"mean\"),\n",
2026-04-05 17:49:37 +02:00
" max_gap_abs =(\"gap_abs\", \"max\"),\n",
" max_gap_rel =(\"gap_rel\", \"max\")\n",
2026-02-02 00:52:00 +01:00
" )\n",
" .reset_index()\n",
")\n",
"\n",
2026-04-05 17:49:37 +02:00
"# Account-level summary\n",
"rupture_account_summary = (\n",
2026-02-02 00:52:00 +01:00
" df.groupby(\"Registrar Account - ID\")\n",
" .agg(\n",
2026-04-05 17:49:37 +02:00
" n_ruptures =(\"rupture_flag\", \"sum\"),\n",
" total_obs =(\"rupture_flag\", \"count\"),\n",
2026-02-02 00:52:00 +01:00
" rupture_ratio=(\"rupture_flag\", \"mean\"),\n",
2026-04-05 17:49:37 +02:00
" max_gap_abs =(\"gap_abs\", \"max\"),\n",
" max_gap_rel =(\"gap_rel\", \"max\")\n",
2026-02-02 00:52:00 +01:00
" )\n",
" .reset_index()\n",
")\n",
"\n",
"df.to_csv(\"aum_flow_gaps.csv\", index=False)\n",
"rupture_isin_summary.to_csv(\"rupture_isin_summary.csv\", index=False)\n",
2026-04-05 17:49:37 +02:00
"rupture_account_summary.to_csv(\"rupture_summary.csv\", index=False)\n",
"\n",
"print(f\"Total ruptures detected: {df['rupture_flag'].sum():,}\")\n",
"print(f\"Share of observations flagged: {df['rupture_flag'].mean():.2%}\")"
]
},
{
"cell_type": "markdown",
"id": "cce6f71a",
"metadata": {},
"source": [
"## 3. Figures"
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "code",
2026-04-05 17:49:37 +02:00
"execution_count": 5,
"id": "9a5a1298",
2026-02-02 00:52:00 +01:00
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.plotly.v1+json": {
"config": {
"plotlyServerURL": "https://plot.ly"
},
"data": [
{
"hole": 0.45,
"hoverinfo": "label+percent",
"labels": [
2026-04-05 17:49:37 +02:00
"Clean / quasi-clean (<=1%)",
"Moderate (1-10%)",
"High (10-30%)",
2026-02-02 00:52:00 +01:00
"Severe (>30%)"
],
"textinfo": "percent",
"type": "pie",
"values": {
2026-04-05 17:49:37 +02:00
"bdata": "mpmZmZkZS0DNzMzMzMxFQGZmZmZmZv4/MzMzMzMz0z8=",
2026-02-02 00:52:00 +01:00
"dtype": "f8"
}
}
],
"layout": {
"legend": {
"orientation": "h",
"title": {
"text": "Rupture ratio"
},
"x": 0.5,
"xanchor": "center",
"y": -0.15,
"yanchor": "top"
},
"template": {
"data": {
"bar": [
{
"error_x": {
"color": "#2a3f5f"
},
"error_y": {
"color": "#2a3f5f"
},
"marker": {
"line": {
"color": "#E5ECF6",
"width": 0.5
},
"pattern": {
"fillmode": "overlay",
"size": 10,
"solidity": 0.2
}
},
"type": "bar"
}
],
"barpolar": [
{
"marker": {
"line": {
"color": "#E5ECF6",
"width": 0.5
},
"pattern": {
"fillmode": "overlay",
"size": 10,
"solidity": 0.2
}
},
"type": "barpolar"
}
],
"carpet": [
{
"aaxis": {
"endlinecolor": "#2a3f5f",
"gridcolor": "white",
"linecolor": "white",
"minorgridcolor": "white",
"startlinecolor": "#2a3f5f"
},
"baxis": {
"endlinecolor": "#2a3f5f",
"gridcolor": "white",
"linecolor": "white",
"minorgridcolor": "white",
"startlinecolor": "#2a3f5f"
},
"type": "carpet"
}
],
"choropleth": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"type": "choropleth"
}
],
"contour": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"colorscale": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
],
"type": "contour"
}
],
"contourcarpet": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"type": "contourcarpet"
}
],
"heatmap": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"colorscale": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
],
"type": "heatmap"
}
],
"histogram": [
{
"marker": {
"pattern": {
"fillmode": "overlay",
"size": 10,
"solidity": 0.2
}
},
"type": "histogram"
}
],
"histogram2d": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"colorscale": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
],
"type": "histogram2d"
}
],
"histogram2dcontour": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"colorscale": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
],
"type": "histogram2dcontour"
}
],
"mesh3d": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"type": "mesh3d"
}
],
"parcoords": [
{
"line": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "parcoords"
}
],
"pie": [
{
"automargin": true,
"type": "pie"
}
],
"scatter": [
{
"fillpattern": {
"fillmode": "overlay",
"size": 10,
"solidity": 0.2
},
"type": "scatter"
}
],
"scatter3d": [
{
"line": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scatter3d"
}
],
"scattercarpet": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scattercarpet"
}
],
"scattergeo": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scattergeo"
}
],
"scattergl": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scattergl"
}
],
"scattermap": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scattermap"
}
],
"scattermapbox": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scattermapbox"
}
],
"scatterpolar": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scatterpolar"
}
],
"scatterpolargl": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scatterpolargl"
}
],
"scatterternary": [
{
"marker": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"type": "scatterternary"
}
],
"surface": [
{
"colorbar": {
"outlinewidth": 0,
"ticks": ""
},
"colorscale": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
],
"type": "surface"
}
],
"table": [
{
"cells": {
"fill": {
"color": "#EBF0F8"
},
"line": {
"color": "white"
}
},
"header": {
"fill": {
"color": "#C8D4E3"
},
"line": {
"color": "white"
}
},
"type": "table"
}
]
},
"layout": {
"annotationdefaults": {
"arrowcolor": "#2a3f5f",
"arrowhead": 0,
"arrowwidth": 1
},
"autotypenumbers": "strict",
"coloraxis": {
"colorbar": {
"outlinewidth": 0,
"ticks": ""
}
},
"colorscale": {
"diverging": [
[
0,
"#8e0152"
],
[
0.1,
"#c51b7d"
],
[
0.2,
"#de77ae"
],
[
0.3,
"#f1b6da"
],
[
0.4,
"#fde0ef"
],
[
0.5,
"#f7f7f7"
],
[
0.6,
"#e6f5d0"
],
[
0.7,
"#b8e186"
],
[
0.8,
"#7fbc41"
],
[
0.9,
"#4d9221"
],
[
1,
"#276419"
]
],
"sequential": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
],
"sequentialminus": [
[
0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1,
"#f0f921"
]
]
},
"colorway": [
"#636efa",
"#EF553B",
"#00cc96",
"#ab63fa",
"#FFA15A",
"#19d3f3",
"#FF6692",
"#B6E880",
"#FF97FF",
"#FECB52"
],
"font": {
"color": "#2a3f5f"
},
"geo": {
"bgcolor": "white",
"lakecolor": "white",
"landcolor": "#E5ECF6",
"showlakes": true,
"showland": true,
"subunitcolor": "white"
},
"hoverlabel": {
"align": "left"
},
"hovermode": "closest",
"mapbox": {
"style": "light"
},
"paper_bgcolor": "white",
"plot_bgcolor": "#E5ECF6",
"polar": {
"angularaxis": {
"gridcolor": "white",
"linecolor": "white",
"ticks": ""
},
"bgcolor": "#E5ECF6",
"radialaxis": {
"gridcolor": "white",
"linecolor": "white",
"ticks": ""
}
},
"scene": {
"xaxis": {
"backgroundcolor": "#E5ECF6",
"gridcolor": "white",
"gridwidth": 2,
"linecolor": "white",
"showbackground": true,
"ticks": "",
"zerolinecolor": "white"
},
"yaxis": {
"backgroundcolor": "#E5ECF6",
"gridcolor": "white",
"gridwidth": 2,
"linecolor": "white",
"showbackground": true,
"ticks": "",
"zerolinecolor": "white"
},
"zaxis": {
"backgroundcolor": "#E5ECF6",
"gridcolor": "white",
"gridwidth": 2,
"linecolor": "white",
"showbackground": true,
"ticks": "",
"zerolinecolor": "white"
}
},
"shapedefaults": {
"line": {
"color": "#2a3f5f"
}
},
"ternary": {
"aaxis": {
"gridcolor": "white",
"linecolor": "white",
"ticks": ""
},
"baxis": {
"gridcolor": "white",
"linecolor": "white",
"ticks": ""
},
"bgcolor": "#E5ECF6",
"caxis": {
"gridcolor": "white",
"linecolor": "white",
"ticks": ""
}
},
"title": {
"x": 0.05
},
"xaxis": {
"automargin": true,
"gridcolor": "white",
"linecolor": "white",
"ticks": "",
"title": {
"standoff": 15
},
"zerolinecolor": "white",
"zerolinewidth": 2
},
"yaxis": {
"automargin": true,
"gridcolor": "white",
"linecolor": "white",
"ticks": "",
"title": {
"standoff": 15
},
"zerolinecolor": "white",
"zerolinewidth": 2
}
}
}
}
},
2026-04-05 17:49:37 +02:00
"image/png": "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
2026-02-02 00:52:00 +01:00
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
2026-04-05 17:49:37 +02:00
"# ---- Figure A: Distribution of accounts by rupture intensity ----\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"rs = rupture_account_summary.copy()\n",
"bins = [0, 0.01, 0.10, 0.30, 1.01]\n",
"labels = [\"Clean / quasi-clean (<=1%)\", \"Moderate (1-10%)\", \"High (10-30%)\", \"Severe (>30%)\"]\n",
"rs[\"rupture_class\"] = pd.cut(rs[\"rupture_ratio\"], bins=bins, labels=labels, include_lowest=True)\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"dist = (rs[\"rupture_class\"].value_counts(normalize=True).sort_index() * 100).round(1)\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"fig_a = go.Figure(data=[go.Pie(\n",
" labels=dist.index, values=dist.values,\n",
" hole=0.45, textinfo=\"percent\", hoverinfo=\"label+percent\"\n",
")])\n",
"fig_a.update_layout(\n",
" legend=dict(orientation=\"h\", yanchor=\"top\", y=-0.15, xanchor=\"center\", x=0.5),\n",
2026-02-02 00:52:00 +01:00
" legend_title_text=\"Rupture ratio\"\n",
")\n",
2026-04-05 17:49:37 +02:00
"fig_a.show()"
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "code",
2026-04-05 17:49:37 +02:00
"execution_count": 6,
"id": "3a065d8f",
2026-02-02 00:52:00 +01:00
"metadata": {},
"outputs": [
{
2026-04-05 17:49:37 +02:00
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1200x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
2026-02-02 00:52:00 +01:00
}
],
"source": [
2026-04-05 17:49:37 +02:00
"# ---- Figure B: Rupture rate over time (active flows only) ----\n",
"# Denominator restricted to observations with active flows\n",
"# to avoid dilution by dormant positions.\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"active_obs = df[df[\"Quantity - NetFlows\"] != 0]\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"time_stats = (\n",
" active_obs\n",
" .groupby(\"Centralisation Date\")\n",
" .agg(total_obs=(\"rupture_flag\", \"count\"), n_ruptures=(\"rupture_flag\", \"sum\"))\n",
" .reset_index()\n",
2026-02-02 00:52:00 +01:00
")\n",
2026-04-05 17:49:37 +02:00
"time_stats[\"rupture_rate\"] = time_stats[\"n_ruptures\"] / time_stats[\"total_obs\"]\n",
"time_stats[\"rupture_rate_ma\"] = time_stats[\"rupture_rate\"].rolling(window=6, center=True).mean()\n",
2026-02-02 00:52:00 +01:00
"\n",
2026-04-05 17:49:37 +02:00
"plt.figure(figsize=(12, 5))\n",
"plt.plot(time_stats[\"Centralisation Date\"], time_stats[\"rupture_rate\"] * 100,\n",
" color=\"lightgray\", linewidth=1, alpha=0.6, label=\"Monthly rupture rate (active flows only)\")\n",
"plt.plot(time_stats[\"Centralisation Date\"], time_stats[\"rupture_rate_ma\"] * 100,\n",
" color=\"#1f77b4\", linewidth=2.5, label=\"6-month moving average\")\n",
"plt.ylabel(\"Rupture rate (%)\")\n",
"plt.xlabel(\"Date\")\n",
"plt.grid(True, linestyle=\"--\", alpha=0.4)\n",
"plt.legend(frameon=False)\n",
"plt.tight_layout()\n",
"plt.show()"
2026-02-02 00:52:00 +01:00
]
},
{
"cell_type": "code",
2026-04-05 17:49:37 +02:00
"execution_count": 7,
"id": "85efa034",
2026-02-02 00:52:00 +01:00
"metadata": {},
"outputs": [
{
"data": {
2026-04-05 17:49:37 +02:00
"image/png": "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
"text/plain": [
"<Figure size 1000x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA9sAAAGGCAYAAABrBpLcAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnXd8E+Ufxz+XtOketEAHdAAFyiwbyl6yEWSKKJYWcaGIKMhPGW4EQVFURGlxsJGhDBEQZG+QVUqBltlCoU13kya53x/hzsu+S5MO+L5fr76a3D25e+5yuXs+z3cxLMuyIAiCIAiCIAiCIAjCYcgqugMEQRAEQRAEQRAE8ahBYpsgCIIgCIIgCIIgHAyJbYIgCIIgCIIgCIJwMCS2CYIgCIIgCIIgCMLBkNgmCIIgCIIgCIIgCAdDYpsgCIIgCIIgCIIgHAyJbYIgCIIgCIIgCIJwMCS2CYIgCIIgCIIgCMLBkNgmCIIgCIIgCIIgCAdDYpsgCKIKEhMTA4ZhsH///oruisP48ssvsW3bNpvt8vLyMGfOHLRr1w7+/v4ICgrC4MGDce7cOZO2ubm5SEhIQEBAAHx8fDBixAhkZGSYtDt06BBiY2Ph4eGBiIgIfPbZZ2BZ1qDNt99+i0GDBqFGjRpgGAbr16832c6uXbvw9NNPIzIyEp6enmjcuDHmz5+P0tJSg3YMw1j8M9c/AHjjjTfAMAwmTZpksPzKlSt46aWX0KJFC7i4uKBp06YWz92yZcvQoEEDuLu7IyYmBlu2bLHY1lns3bsXDMPgxIkT/LKioiJ88MEHaNy4MTw9PREYGIi2bdvi3XffNfgswzD4/PPP+fdz5swBwzDo2rWryX7eeOMNREZGiuqLub/79+8b7IP7CwwMROfOnS1eq2LOsZjr8sSJExg/fjwaNWoEmUyGQYMGmd0fy7KYO3cuwsPD4eHhgdjYWBw5csSgTVZWFiZPnoz27dvDzc0N3t7eVs8LAJw8eRJyudxs29u3b2P06NHw8/ODj48PnnzySaSlpRm0EftbAIA//vgDMTExcHd3R4MGDZCUlGRyvoYPH47IyEh4eHigRo0a6N+/P44fP27zOAiCICoSEtsEQRBVjAsXLuDs2bMAgJUrV1ZwbxyHWLF948YNfP/99+jTpw/Wrl2LH374Abm5uejQoQOSk5MN2o4ePRp//fUXlixZghUrViAlJQX9+/eHRqPh21y5cgV9+/ZFSEgItmzZgjfeeAOzZs3CggULDLb1888/4/79+xgwYIDFvn3//ffIz8/HBx98gG3btmHcuHGYPXs2Jk6caNDu8OHDJn/169dHixYtEBISYrLdc+fOITExEb6+vibrLly4gK1btyIqKgqNGze22LfVq1fjhRdewOjRo7F9+3bExsbiqaeeMhFmFcGIESOwaNEiJCQkYMuWLVi6dCl69eqFTZs2ifr8/v37sXfvXrv3n5SUZPJ9+Pv78+s9PDz45T/88ANKSkowePBgHDp0yGA7Ys+xmOvy4MGD2L9/P1q1aoXw8HCLff/ss88we/ZsTJkyBVu2bEFISAj69OmDa9eu8W1u376N1atXo2bNmmjTpo3N88GyLCZNmoQaNWqYrNNqtejfvz9OnDiBpUuX4pdffsHNmzfRs2dPFBQU8O3E/hYOHDiAp556CrGxsdi+fTtGjx6NhIQEg8kslUoFd3d3zJw5E1u3bsXSpUtRVFSEnj174vLlyzaPhyAIosJgCYIgiCrFjBkzWJlMxvbo0YMNDAxk1Wp1RXfJIURERLCvvvqqzXYFBQVsYWGhwbL8/Hw2ICCAnTRpEr/s0KFDLAB2x44d/LJLly6xDMOwa9as4ZdNnDiRjYiIYFUqFb9sxowZrL+/P1tSUsIv02q1LMuybFpaGguAXbdunUnfsrKyTJZ9/PHHLMMwZtdxcNucN2+e2fVdu3ZlZ82aZfYccf1iWZZ9/vnn2SZNmpjdRoMGDdgxY8YYLIuNjWX79+9vsV/OYM+ePSwA9vjx4yzLsmxqaioLgP3pp59M2gqPjWVZFgA7f/58/v3s2bNZLy8vtl27dmzPnj0N2k6ePJmNiIiQ1BdzcPsQcuvWLZZhGHbixIkGy8WcY7HXpfDYu3Xrxg4cONCkb8XFxayvry87Y8YMfplKpWIjIiLYl19+2ey2zB2PMcuWLWOjoqLYGTNmmLRdtWoVC4D9999/+WW3bt1i3dzc2IULF/LLxP4W+vTpw3bs2NGg3ZgxY9hGjRpZ7WN+fj6rUCjYjz/+2Go7giCIioQs2wRBEFUIlmWxatUq9OzZE2+++SYePHiAP//806RdcnIyhg0bhoCAAHh6eiImJgarVq3i1+t0OixcuBCNGjWCm5sbgoODMXLkSOTm5vJt9u3bh44dO8LDwwPVq1dHfHw8srOz+fXm3IEBYOjQoejevTv/fs6cOfD29sa5c+fQuXNneHp6omnTptixYwffJjIyEtevX8c333zDu+suX77c7Dnw8vKCp6enwTJvb29ERUXhzp07/LLt27fD398fTzzxBL+sYcOGaNGihYEFffv27Rg6dCgUCgW/7Omnn4ZSqcThw4f5ZTKZ7Udm9erVTZa1bNkSLMtadA8H9B4KDMNgzJgxJutWrFiBtLQ0TJ8+3exnxfTr2rVruHz5MkaNGmWw/Omnn8bu3buhUqlsbsNZ5OTkAIBZi76YYwOAmTNn4u+//zaxNDuLWrVqoUaNGrhx4wa/TOw5Fntdijn2Q4cOIS8vz2CfCoUCw4YNk7wtDqVSiXfeeQdffPGFwW+C4/Tp0wgODkbz5s35ZbVq1ULTpk3xxx9/8MvE/BZUKhX27NmDkSNHGrR7+umnkZycjPT0dIv99PLygru7O9RqtehjIwiCKG9IbBMEQVQhDh06hPT0dDzzzDPo27cvAgMDTVzJU1NTERsbi9TUVHz11Vf4/fffMX78eANh8Nprr2HatGkYNGgQ/vjjD3zzzTfw8fHh3UBPnjyJJ554Aj4+Pli3bh0+++wz/PHHH+jfvz+0Wq3kfpeWlmLs2LGIi4vDxo0bUbNmTQwfPhwPHjwAAGzcuBHBwcEYMWIE7647cOBA0dtXKpU4f/48GjVqxC+7dOkSGjZsCIZhDNo2atQIly5dAgAUFhbi5s2biI6ONmgTHR0NhmH4dmXhwIEDcHNzQ506dSy2WbVqFbp27YratWsbLM/Pz8fbb7+N+fPnm0wwSIE7DuPjbNSoEdRqtUm8bXnSsGFDeHt7Y+rUqdiyZYuBK7JYBg0ahJYtW+L999+3qw9arRYajYb/0+l0VtsXFBQgOzvb4DsVe47FXJdisbbPGzduoLi4WNL2AOC9995D69atLcaIl5SUwM3NzWS5m5ubSRiHMca/hatXr6K0tNRs/wGYnA+dTgeNRoOMjAxMnToVMpkM48aNE31sBEEQ5Y1LRXeAIAiCEM/KlSvh7u6OYcOGwdXVFSNGjMAvv/yCgoICPpHRnDlzoFAocPDgQT7Gt3fv3vw2Ll++jO+++w4ff/wxZsyYwS8fPnw4//rjjz9GcHAwtmzZAldXVwBAWFgY+vbti23btmHw4MGS+q1WqzF37lw+3rlhw4aoU6cOtm/fjmeffRYtW7aEm5sbgoKC0KFDB8nnZdq0aWAYBi+99BK/LCcnxyDulqNatWq8hV6pVAKASTuFQgFPT08DS749pKamYtGiRXjppZcsJqU6e/Yszp8/j++//95k3Zw5cxAVFYXRo0eXqR+c9dj4OKtVqwYAZT7OsuDr64tly5ZhwoQJGDx4MORyOWJiYjBs2DC88cYb8PLyErWd9957D8OHD8exY8fQrl07SX0wvuYSEhLw448/Gizj4qnv3LmDadOmwcfHB5MnT+bXiz3HYq5LseTk5MDNzQ3u7u4m22JZFjk5OfDw8BC9vTNnzmDZsmU4ffq0xTb169fHrVu3cOfOHYSGhgLQTz5cuHDBqrg391uQel3OmjULH3/8MQCgZs2a2LZtG+rWrSv6+AiCIMobsmwTBEFUETQaDdatW4cBAwbAz88PAPDMM8+gqKgIGzdu5Nvt3r0bI0aMMJtMCwD+/vt
"text/plain": [
"<Figure size 1000x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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Dx/i6emJm5tbhn12djlfRtSqVYu+ffvyySefoNPp8qKJZjGnrTExMaxbt4433ngj2175UqVKZdjWoEEDAO7cuZPtOXx8fEhNTc32uVi1ahWenp4888wz6rZdu3Zx/fp1q16/Pj4+ACavTXOeD4OVK1fy77//MmnSpEz3p6am4uHhgUajUbd5eXkBmAy3EEKIJ5UE3UIIUYQdOnSI69evM2jQILp06YKPjw+rVq0yKRMaGkrz5s0JDQ3lyy+/5Pfff2f48OHcuHFDLfPmm28yceJEevbsycaNG1m0aBEeHh7ExcUBcPLkSZ5++mk8PDxYv349s2fPZuPGjXTr1g2tVmtxu1NTUxk8eDDDhg3j119/xdfXl379+vHgwQMAfv31V/z8/Ojfvz+HDx/m8OHD9OjRI9s6FUUhLS2NqKgofvrpJ3bs2GEy9vTIkSOAPhW9YcOGODg4UKFChSzHBHfv3h17e3ueeuop3nnnnSxTktPS0oiNjWXz5s38+OOPjB07Nss23rt3jz179pikvBvaFhAQwPLly6lYsSIODg7Ur1/fZMx0QWnUqBF37tzhtdde48yZM1YFzh988AGXL19m7dq1edBC2zl16hQpKSk4OjrStm1bHB0d8fPzU1O5s3PgwAGATMfqp6WlkZCQwP79+1mwYAFvvPEGjo6OmdaTmprK//73P/r06WMypvvIkSP4+Phw4sQJatSogYODA9WrV+fHH3/MtB6tVktSUhKnTp1i+vTpPPvss/j7+5v5TPy/2NhY3nnnHebOnZvpjRfQj72/cOECixcvJjo6mn/++Yf33nuPBg0a0LJlS4vPKYQQj50C7mkXQgiRC2+88Ybi4uKiREVFKYqiT/N0c3NTYmNj1TKDBg1SSpUqpURHR2dax+XLlxWNRqPMnDkzy/P06dNHqVChgknq+vbt2xVA+f333xVFyTotu1evXkrbtm3V36dOnaoAyubNm9Vt//77rwIoP/30k7rN0vTynTt3KoACKA4ODso333xjsn/WrFkKoJQoUUKZMWOGsmfPHmXSpEmKRqMxKXvq1Cll4sSJyqZNm5Tdu3cr77//vuLs7JxpOnJoaKh6TkD54IMPsm3jF198oQDK5cuXTbZ36dJFKVasmFK6dGll+fLlyo4dO5RevXopDg4Oyrlz58x+DmwhfUp3WlqaMmjQIPUxenh4KL169VJ+++03k+OySi83/A2feeYZpVatWmoKcn6nlxvLKr189erV6mOcMGGCsmfPHuXTTz9VnJyclHfffTfLdkRERChly5ZVevXqlWFfamqqyWtk6NChJqnd6f32228KoGzfvt1k+6uvvqq4uLgoxYsXV7766itl9+7dyogRIxRA2bZtW4Z6ypUrp56za9euSlxcXJbnzO5/bcKECUrr1q1zLLtx40bFw8NDPWf9+vWVsLCwLM8phBBPEplITQghiqi0tDTWr19P9+7d1VTOQYMG8e233/Lrr7/y4osvArB792769++f6QRIoJ+cSVGUbFOb9+/fz8CBA0165zp37oy3tzcHDhwwSYM1h52dHZ06dVJ/9/f3x9XVNVczdQcFBXH8+HGio6PZtm0bb775Jg4ODurjMvTQDh06lPfffx9AnR38k08+4dVXXwX0acKGVGGADh06UKZMGUaPHs2xY8do2rSpuq98+fI
"text/plain": [
"<Figure size 1000x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA9sAAAGGCAYAAABrBpLcAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd4U2X7wPFv0r0XhZbZIqvI3kUUZFiGvirgQBTKUFFQhoryEwG34ouAguIohVfZbkGWDJW9ZUPBQkFaCnTvNjm/P2qOJ23SJh2Uwv25rl4k5zw5eZKm4dznfp770SmKoiCEEEIIIYQQQogKo6/qDgghhBBCCCGEEDcbCbaFEEIIIYQQQogKJsG2EEIIIYQQQghRwSTYFkIIIYQQQgghKpgE20IIIYQQQgghRAWTYFsIIYQQQgghhKhgEmwLIYQQQgghhBAVTIJtIYQQQgghhBCigkmwLYQQQgghhBBCVDAJtoUQohpq3bo1Op2OP/74o6q7UmHmzJnDL7/8Umq7tLQ0ZsyYQadOnfD19aVWrVrcd999HDlypFjb1NRURo0ahb+/P15eXgwePJj4+Phi7Xbs2EF4eDhubm40aNCA999/H0VRzNp88skn3HvvvQQGBqLT6fjmm2+KHefXX3/l0UcfJSQkBHd3d5o3b84HH3xAfn6+WTudTmf1x1L/ACZMmIBOp2PcuHFm28+cOcOYMWNo06YNjo6OtGjRwup7FxUVRZMmTXB1daV169asXr3aatvKsnXrVnQ6Hfv27VO3ZWVl8cYbb9C8eXPc3d0JCAigY8eOvPrqq2aP1el0/Pe//1Xvz5gxA51Ox1133VXseSZMmEBISIhNfbH0c/XqVbPnMP0EBATQrVs3q59VW95jWz6X+/btY8SIEYSFhaHX67n33nstPp+iKLz33nvUr18fNzc3wsPD2bVrl1mbK1euMH78eDp37oyLiwuenp4lvi8A+/fvx8HBwWLb8+fPM2TIEIKDg/Hy8qJjx458++23xdqtXr2adu3a4eLiQr169Zg+fToGg8GsjcFgYObMmTRr1gx3d3caNmzISy+9REZGhlm7N998kz59+uDr61vs8yOEEDcqCbaFEKKaOXbsGIcPHwZg6dKlVdybimNrsB0XF8dnn33GPffcw8qVK/niiy9ITU2lS5cunDhxwqztI488woYNG1iwYAFLlizh1KlT9OvXj4KCArXNmTNniIiIIDg4mNWrVzNhwgSmTZvGrFmzzI71v//9j6tXr9K/f3+rffvss89IT0/njTfe4JdffmHYsGFMnz6dp556yqzdzp07i/00btyYNm3aEBwcXOy4R44cYeHChXh7exfbd+zYMdasWUOjRo1o3ry51b4tX76cJ598kkceeYS1a9cSHh7Ogw8+WCwwqwqDBw9m7ty5jBo1itWrV/P555/Tq1cvfvjhB5se/8cff7B169YyP390dHSx34evr6+6383NTd3+xRdfkJOTw3333ceOHTvMjmPre2zL53L79u388ccftGvXjvr161vt+/vvv8/06dOZOHEiq1evJjg4mHvuuYe//vpLbfP333+zfPlyatasSYcOHUp9PxRFYdy4cQQGBhbbl5ubS9++fTl06BBz587lu+++IywsjIceeoj169er7Xbt2sX9999P8+bN+emnn5g4cSIffPABL7/8stnx3n77bV599VUiIyNZs2YNEydOZMGCBTz99NNm7T777DPy8vLo3bt3qf0XQogbhiKEEKJamTJliqLX65W7775bCQgIUPLy8qq6SxWiQYMGytixY0ttl5GRoWRmZpptS09PV/z9/ZVx48ap23bs2KEAyvr169VtJ0+eVHQ6nbJixQp121NPPaU0aNBAyc3NVbdNmTJF8fX1VXJyctRtBoNBURRFiY2NVQBl1apVxfp25cqVYtvefvttRafTWdxnYjrmzJkzLe6/6667lGnTpll8j0z9UhRFGT58uHL77bdbPEaTJk2UIUOGmG0LDw9X+vXrZ7VflWHLli0KoOzdu1dRFEWJiYlRAGXx4sXF2mpfm6IoCqB88MEH6v3p06crHh4eSqdOnZSePXuatR0/frzSoEEDu/piiek5tC5evKjodDrlqaeeMttuy3ts6+dS+9q7d++uDBgwoFjfsrOzFW9vb2XKlCnqttzcXKVBgwbKM888Y/FYll5PUVFRUUqjRo2UKVOmFGu7c+dOBVC2bNlidvyQkBBl5MiR6raIiAilXbt2Zo/973//qzg5OSkJCQnqtqZNmyrDhw83azdt2jTFxcVFyc/PL/YabPmdCSHEjUIy20IIUY0oisKyZcvo2bMnkyZN4tq1a6xbt65YuxMnTjBw4ED8/f1xd3endevWLFu2TN1vNBr58MMPCQsLw8XFhaCgIB566CFSU1PVNr///jtdu3bFzc2NGjVqMHLkSJKSktT9loYDAzzwwAP06NFDvT9jxgw8PT05cuQI3bp1w93dnRYtWphlwUJCQjh//jzz589Xh+suWrTI4nvg4eGBu7u72TZPT08aNWrEpUuX1G1r167F19eXPn36qNuaNm1KmzZtzDLoa9eu5YEHHsDZ2Vnd9uijj5KSksLOnTvVbXp96f9l1qhRo9i2tm3boiiK1eHhUDhCQafTMWTIkGL7lixZQmxsbLGMoD39+uuvvzh9+jQPP/yw2fZHH32UTZs2kZubW+oxKktycjKAxYy+La8N4LXXXmPz5s3FMs2VpU6dOgQGBhIXF6dus/U9tvVzactr37FjB2lpaWbP6ezszMCBA+0+lklKSgqvvPIKs2fPNvubMDFNifDx8TE7vpeXl9nUi4MHD3LPPfeYPTYiIoL8/Hyzv/38/HyzY5mObTQazbbZ8xqEEOJGId9cQghRjezYsYNz587x2GOPERERQUBAQLGh5DExMYSHhxMTE8NHH33ETz/9xIgRI8wCg+eee47Jkydz77338vPPPzN//ny8vLzUeZL79++nT58+eHl5sWrVKt5//31+/vln+vXrV2zOpS3y8/MZOnQokZGRfP/999SsWZNBgwZx7do1AL7//nuCgoIYPHiwOlx3wIABNh8/JSWFo0ePEhYWpm47efIkTZs2RafTmbUNCwvj5MmTAGRmZnLhwgWaNWtm1qZZs2bodDq1XXls27YNFxcXQkNDrbZZtmwZd911F3Xr1jXbnp6ezksvvcQHH3xQ7AKDPUyvo+jrDAsLIy8vj9jY2DIfu7yaNm2Kp6cnL7zwAqtXry42V9cW9957L23btuX1118vUx8MBgMFBQXqT9FAr6iMjAySkpLMfqe2vse2fC5tVdJzxsXFkZ2dbdfxAKZOnUr79u2tzhEPDw/n9ttv59VXXyU2NpaUlBQ+/vhjTp8+zZNPPqm2y8nJwcXFxeyxpvva6R6jR4/mq6++YvPmzWRkZLBnzx4+/vhjxowZg6Ojo939F0KIG4l8iwkhRDWydOlSXF1dGThwIE5OTgwePJivvvqKjIwMtZDRjBkzcHZ2Zvv27eocX+08x9OnT/Ppp5/y9ttvM2XKFHX7oEGD1Ntvv/02QUFBrF69GicnJwDq1atHREQEv/zyC/fdd59d/c7Ly+O9995T5zs3bdqU0NBQ1q5dy+OPP07btm1xcXGhVq1adOnSxe73ZfLkyeh0OsaMGaNuS05ONpt3a+Ln56dm6FNSUgCKtXN2dsbd3d0sk18WMTExzJ07lzFjxlgtSnX48GGOHj3KZ599VmzfjBkzaNSoEY888ki5+mHKHhd9nX5+fgDlfp3l4e3tTVRUFKNHj+a+++7DwcGB1q1bM3DgQCZMmICHh4dNx5k6dSqDBg1iz549dOrUya4+FP3MjRo1ii+//NJsm2k+9aVLl5g8eTJeXl6MHz9e3W/re2zL59JWycnJuLi44OrqWuxYiqKQnJyMm5ubzcc7dOgQUVFRHDx40GobR0dHNm/ezH/+8x8aNmwIFM5pX758OeHh4Wq7xo0bs2fPHrPHmuaua1/nlClTyM3NpXfv3mpm/PHHH2fOnDk291sIIW5UktkWQohqoqCggFWrVtG/f3912OVjjz1GVlYW33//vdp
2026-02-02 00:52:00 +01:00
"text/plain": [
2026-04-05 17:49:37 +02:00
"<Figure size 1000x400 with 1 Axes>"
2026-02-02 00:52:00 +01:00
]
},
"metadata": {},
2026-04-05 17:49:37 +02:00
"output_type": "display_data"
2026-02-02 00:52:00 +01:00
}
],
"source": [
2026-04-05 17:49:37 +02:00
"# ---- Figure C: Example trajectories (top 5 worst) ----\n",
"\n",
"def plot_isin_dynamics(df, account_id, isin, title_suffix=\"\"):\n",
2026-02-02 00:52:00 +01:00
" sub = df[\n",
" (df[\"Registrar Account - ID\"] == account_id) &\n",
" (df[\"Product - Isin\"] == isin)\n",
2026-04-05 17:49:37 +02:00
" ].sort_values(\"Centralisation Date\")\n",
2026-02-02 00:52:00 +01:00
"\n",
" if sub.empty:\n",
" print(\"No data for this (account, ISIN).\")\n",
" return\n",
"\n",
2026-04-05 17:49:37 +02:00
" fig, ax = plt.subplots(figsize=(10, 4))\n",
" ax.plot(sub[\"Centralisation Date\"], sub[\"Quantity - AUM\"],\n",
" label=\"Observed AUM\", linewidth=2, color=\"black\")\n",
" ax.plot(sub[\"Centralisation Date\"], sub[\"expected_stock\"],\n",
" label=\"Flow-implied AUM\", linestyle=\"--\", linewidth=2, color=\"grey\")\n",
2026-02-02 00:52:00 +01:00
" rupt = sub[sub[\"rupture_flag\"]]\n",
2026-04-05 17:49:37 +02:00
" ax.scatter(rupt[\"Centralisation Date\"], rupt[\"Quantity - AUM\"],\n",
" color=\"red\", s=25, zorder=5, label=\"Discontinuity\")\n",
" ax.set_title(f\"Account {account_id} — ISIN {isin} {title_suffix}\", fontsize=11)\n",
" ax.set_ylabel(\"AUM (shares)\")\n",
" ax.legend(loc=\"best\")\n",
2026-02-02 00:52:00 +01:00
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
2026-04-05 17:49:37 +02:00
"worst = rupture_isin_summary.sort_values(\"rupture_ratio\", ascending=False).head(5)\n",
"for _, row in worst.iterrows():\n",
" plot_isin_dynamics(df, row[\"Registrar Account - ID\"], row[\"Product - Isin\"])"
2026-02-02 00:52:00 +01:00
]
}
],
"metadata": {
"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.13.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}