Project_Carmignac/notebooks/aum_flows_analysis.ipynb

1194 lines
513 KiB
Plaintext
Raw Normal View History

2026-02-22 15:02:41 +01:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# AUM Analysis\n",
"\n",
"This notebook sums the **Value - AUM €** by **Product - Asset Type** and by **Product - Fund** from the AUM sample data."
]
},
{
"cell_type": "code",
2026-03-20 09:21:54 +01:00
"execution_count": 1,
2026-02-22 15:02:41 +01:00
"metadata": {},
"outputs": [
2026-03-20 09:21:54 +01:00
{
"name": "stderr",
"output_type": "stream",
"text": [
"Matplotlib is building the font cache; this may take a moment.\n"
]
},
2026-02-22 15:02:41 +01:00
{
"name": "stdout",
"output_type": "stream",
"text": [
2026-03-20 09:21:54 +01:00
"Collecting openpyxl\n",
" Downloading openpyxl-3.1.5-py2.py3-none-any.whl.metadata (2.5 kB)\n",
"Collecting et-xmlfile (from openpyxl)\n",
" Downloading et_xmlfile-2.0.0-py3-none-any.whl.metadata (2.7 kB)\n",
"Downloading openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)\n",
"Downloading et_xmlfile-2.0.0-py3-none-any.whl (18 kB)\n",
"Installing collected packages: et-xmlfile, openpyxl\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2/2\u001b[0m [openpyxl]1/2\u001b[0m [openpyxl]\n",
"\u001b[1A\u001b[2KSuccessfully installed et-xmlfile-2.0.0 openpyxl-3.1.5\n"
2026-02-22 15:02:41 +01:00
]
}
],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"!pip install openpyxl\n",
"import os\n",
"import s3fs\n",
"import seaborn as sns\n",
"import plotly.express as px\n",
"import re"
2026-02-22 15:02:41 +01:00
]
},
{
"cell_type": "code",
2026-03-20 09:21:54 +01:00
"execution_count": null,
2026-02-22 15:02:41 +01:00
"metadata": {},
"outputs": [],
"source": [
"fs = s3fs.S3FileSystem(\n",
" client_kwargs={'endpoint_url': 'https://'+'minio-simple.lab.groupe-genes.fr'},\n",
" key = os.environ[\"AWS_ACCESS_KEY_ID\"], \n",
" secret = os.environ[\"AWS_SECRET_ACCESS_KEY\"], \n",
" token = os.environ[\"AWS_SESSION_TOKEN\"])"
]
},
{
"cell_type": "code",
2026-03-20 09:21:54 +01:00
"execution_count": null,
2026-02-22 15:02:41 +01:00
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
2026-03-20 09:21:54 +01:00
"/tmp/ipykernel_3944/2679329308.py:2: DtypeWarning: Columns (0,1,2,3) have mixed types. Specify dtype option on import or set low_memory=False.\n",
" flows = pd.read_csv(f, sep=\";\")\n"
2026-02-22 15:02:41 +01:00
]
}
],
"source": [
2026-03-20 09:21:54 +01:00
"with fs.open('projet-bdc-data//carmignac/Flows ENSAE V2 -20251105.csv', 'rb') as f:\n",
" flows = pd.read_csv(f, sep=\";\")\n",
2026-02-22 15:02:41 +01:00
"\n",
"with fs.open('projet-bdc-data//carmignac/AUM ENSAE V2 -20251105.csv', 'rb') as f:\n",
" stocks = pd.read_csv(f, sep=\";\")\n",
"\n",
"#with fs.open('projet-bdc-data/carmignac/Monthly AUM and NAV since 2010.xlsx', 'rb') as f:#\n",
" #nav_raw = pd.read_excel(f, header=None, engine=\"openpyxl\")\n",
"\n",
"#nav = nav_raw[0].str.split(\",\", expand=True)\n",
"#nav.columns = nav.iloc[0]\n",
"#nav = nav[1:].reset_index(drop=True)"
]
},
{
"cell_type": "code",
2026-03-10 23:01:34 +01:00
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Agreement - Code</th>\n",
" <th>Company - Id</th>\n",
" <th>Company - Ultimate Parent Id</th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>Registrar Account - Region</th>\n",
" <th>RegistrarAccount - Country</th>\n",
" <th>Product - Asset Type</th>\n",
" <th>Product - Strategy</th>\n",
" <th>Product - Legal Status</th>\n",
" <th>Product - Is Dedie ?</th>\n",
" <th>Product - Fund</th>\n",
" <th>Product - Shareclass Type</th>\n",
" <th>Product - Shareclass Currency</th>\n",
" <th>Product - Isin</th>\n",
" <th>Centralisation Date</th>\n",
" <th>Quantity - AUM</th>\n",
" <th>Value - AUM CCY</th>\n",
" <th>Value - AUM €</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>3</td>\n",
" <td>166.0</td>\n",
" <td>166.0</td>\n",
" <td>200000647</td>\n",
" <td>France</td>\n",
" <td>France</td>\n",
" <td>Diversified</td>\n",
" <td>Patrimoine</td>\n",
" <td>FCP</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>A</td>\n",
" <td>EUR</td>\n",
" <td>FR0010135103</td>\n",
" <td>2015-03-31</td>\n",
" <td>35.368</td>\n",
" <td>2.464867e+04</td>\n",
" <td>2.464867e+04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>3</td>\n",
" <td>166.0</td>\n",
" <td>166.0</td>\n",
" <td>200000647</td>\n",
" <td>France</td>\n",
" <td>France</td>\n",
" <td>Diversified</td>\n",
" <td>Patrimoine</td>\n",
" <td>FCP</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>A</td>\n",
" <td>EUR</td>\n",
" <td>FR0010135103</td>\n",
" <td>2015-11-30</td>\n",
" <td>35.368</td>\n",
" <td>2.241306e+04</td>\n",
" <td>2.241306e+04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>3</td>\n",
" <td>166.0</td>\n",
" <td>166.0</td>\n",
" <td>200000647</td>\n",
" <td>France</td>\n",
" <td>France</td>\n",
" <td>Diversified</td>\n",
" <td>Patrimoine</td>\n",
" <td>FCP</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>A</td>\n",
" <td>EUR</td>\n",
" <td>FR0010135103</td>\n",
" <td>2015-12-31</td>\n",
" <td>35.368</td>\n",
" <td>2.205124e+04</td>\n",
" <td>2.205124e+04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>3</td>\n",
" <td>166.0</td>\n",
" <td>166.0</td>\n",
" <td>200000647</td>\n",
" <td>France</td>\n",
" <td>France</td>\n",
" <td>Diversified</td>\n",
" <td>Patrimoine</td>\n",
" <td>FCP</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>A</td>\n",
" <td>EUR</td>\n",
" <td>FR0010135103</td>\n",
" <td>2016-03-31</td>\n",
" <td>35.368</td>\n",
" <td>2.162612e+04</td>\n",
" <td>2.162612e+04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>3</td>\n",
" <td>166.0</td>\n",
" <td>166.0</td>\n",
" <td>200000647</td>\n",
" <td>France</td>\n",
" <td>France</td>\n",
" <td>Diversified</td>\n",
" <td>Patrimoine</td>\n",
" <td>FCP</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>A</td>\n",
" <td>EUR</td>\n",
" <td>FR0010135103</td>\n",
" <td>2016-11-30</td>\n",
" <td>35.368</td>\n",
" <td>2.248945e+04</td>\n",
" <td>2.248945e+04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4880292</th>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>Fixed Income</td>\n",
" <td>Sécurité</td>\n",
" <td>SICAV</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>AW &amp; AW-R</td>\n",
" <td>EUR</td>\n",
" <td>LU1299306321</td>\n",
" <td>2020-02-29</td>\n",
" <td>26801.000</td>\n",
" <td>2.740670e+06</td>\n",
" <td>2.740670e+06</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4880293</th>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>Fixed Income</td>\n",
" <td>Sécurité</td>\n",
" <td>SICAV</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>AW &amp; AW-R</td>\n",
" <td>EUR</td>\n",
" <td>LU1299306321</td>\n",
" <td>2020-06-30</td>\n",
" <td>3099.000</td>\n",
" <td>3.122862e+05</td>\n",
" <td>3.122862e+05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4880294</th>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>Fixed Income</td>\n",
" <td>Sécurité</td>\n",
" <td>SICAV</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>AW &amp; AW-R</td>\n",
" <td>EUR</td>\n",
" <td>LU1299306321</td>\n",
" <td>2020-10-31</td>\n",
" <td>3099.000</td>\n",
" <td>3.184222e+05</td>\n",
" <td>3.184222e+05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4880295</th>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>Fixed Income</td>\n",
" <td>Sécurité</td>\n",
" <td>SICAV</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>AW &amp; AW-R</td>\n",
" <td>EUR</td>\n",
" <td>LU1299306321</td>\n",
" <td>2021-07-31</td>\n",
" <td>2835.000</td>\n",
" <td>2.976183e+05</td>\n",
" <td>2.976183e+05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4880296</th>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Private Client</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>Fixed Income</td>\n",
" <td>Sécurité</td>\n",
" <td>SICAV</td>\n",
" <td>NO</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>FW &amp; FW-R</td>\n",
" <td>EUR</td>\n",
" <td>LU1792391911</td>\n",
" <td>2020-07-31</td>\n",
" <td>2916.394</td>\n",
" <td>2.874106e+05</td>\n",
" <td>2.874106e+05</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>4880297 rows × 18 columns</p>\n",
"</div>"
],
"text/plain": [
" Agreement - Code Company - Id Company - Ultimate Parent Id \\\n",
"0 3 166.0 166.0 \n",
"1 3 166.0 166.0 \n",
"2 3 166.0 166.0 \n",
"3 3 166.0 166.0 \n",
"4 3 166.0 166.0 \n",
"... ... ... ... \n",
"4880292 Private Client Private Client Private Client \n",
"4880293 Private Client Private Client Private Client \n",
"4880294 Private Client Private Client Private Client \n",
"4880295 Private Client Private Client Private Client \n",
"4880296 Private Client Private Client Private Client \n",
"\n",
" Registrar Account - ID Registrar Account - Region \\\n",
"0 200000647 France \n",
"1 200000647 France \n",
"2 200000647 France \n",
"3 200000647 France \n",
"4 200000647 France \n",
"... ... ... \n",
"4880292 Private Client Switzerland \n",
"4880293 Private Client Switzerland \n",
"4880294 Private Client Switzerland \n",
"4880295 Private Client Switzerland \n",
"4880296 Private Client Switzerland \n",
"\n",
" RegistrarAccount - Country Product - Asset Type Product - Strategy \\\n",
"0 France Diversified Patrimoine \n",
"1 France Diversified Patrimoine \n",
"2 France Diversified Patrimoine \n",
"3 France Diversified Patrimoine \n",
"4 France Diversified Patrimoine \n",
"... ... ... ... \n",
"4880292 Switzerland Fixed Income Sécurité \n",
"4880293 Switzerland Fixed Income Sécurité \n",
"4880294 Switzerland Fixed Income Sécurité \n",
"4880295 Switzerland Fixed Income Sécurité \n",
"4880296 Switzerland Fixed Income Sécurité \n",
"\n",
" Product - Legal Status Product - Is Dedie ? \\\n",
"0 FCP NO \n",
"1 FCP NO \n",
"2 FCP NO \n",
"3 FCP NO \n",
"4 FCP NO \n",
"... ... ... \n",
"4880292 SICAV NO \n",
"4880293 SICAV NO \n",
"4880294 SICAV NO \n",
"4880295 SICAV NO \n",
"4880296 SICAV NO \n",
"\n",
" Product - Fund Product - Shareclass Type \\\n",
"0 Carmignac Patrimoine A \n",
"1 Carmignac Patrimoine A \n",
"2 Carmignac Patrimoine A \n",
"3 Carmignac Patrimoine A \n",
"4 Carmignac Patrimoine A \n",
"... ... ... \n",
"4880292 Carmignac Portfolio Sécurité AW & AW-R \n",
"4880293 Carmignac Portfolio Sécurité AW & AW-R \n",
"4880294 Carmignac Portfolio Sécurité AW & AW-R \n",
"4880295 Carmignac Portfolio Sécurité AW & AW-R \n",
"4880296 Carmignac Portfolio Sécurité FW & FW-R \n",
"\n",
" Product - Shareclass Currency Product - Isin Centralisation Date \\\n",
"0 EUR FR0010135103 2015-03-31 \n",
"1 EUR FR0010135103 2015-11-30 \n",
"2 EUR FR0010135103 2015-12-31 \n",
"3 EUR FR0010135103 2016-03-31 \n",
"4 EUR FR0010135103 2016-11-30 \n",
"... ... ... ... \n",
"4880292 EUR LU1299306321 2020-02-29 \n",
"4880293 EUR LU1299306321 2020-06-30 \n",
"4880294 EUR LU1299306321 2020-10-31 \n",
"4880295 EUR LU1299306321 2021-07-31 \n",
"4880296 EUR LU1792391911 2020-07-31 \n",
"\n",
" Quantity - AUM Value - AUM CCY Value - AUM € \n",
"0 35.368 2.464867e+04 2.464867e+04 \n",
"1 35.368 2.241306e+04 2.241306e+04 \n",
"2 35.368 2.205124e+04 2.205124e+04 \n",
"3 35.368 2.162612e+04 2.162612e+04 \n",
"4 35.368 2.248945e+04 2.248945e+04 \n",
"... ... ... ... \n",
"4880292 26801.000 2.740670e+06 2.740670e+06 \n",
"4880293 3099.000 3.122862e+05 3.122862e+05 \n",
"4880294 3099.000 3.184222e+05 3.184222e+05 \n",
"4880295 2835.000 2.976183e+05 2.976183e+05 \n",
"4880296 2916.394 2.874106e+05 2.874106e+05 \n",
"\n",
"[4880297 rows x 18 columns]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"stocks"
]
},
{
"cell_type": "code",
2026-03-20 09:21:54 +01:00
"execution_count": 7,
2026-02-22 15:02:41 +01:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Date conversion done.\n"
]
}
],
"source": [
2026-03-20 09:21:54 +01:00
"flows[\"Centralisation Date\"] = pd.to_datetime(flows[\"Centralisation Date\"], errors=\"coerce\")\n",
2026-02-22 15:02:41 +01:00
"#flows[\"Centralisation Date\"] = pd.to_datetime(flows[\"Centralisation Date\"], errors=\"coerce\")\n",
"#nav[\"NavDate\"] = pd.to_datetime(nav[\"NavDate\"], format=\"%d/%m/%Y\", errors=\"coerce\")\n",
"\n",
"print(\"Date conversion done.\")"
]
},
2026-03-20 09:21:54 +01:00
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"flows_head = flows.head(100)\n",
"flows_head.to_csv(\"flows_head.csv\")"
]
},
2026-03-10 23:01:34 +01:00
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_94182/1741685825.py:2: DtypeWarning: Columns (1,2,3) have mixed types. Specify dtype option on import or set low_memory=False.\n",
" equity_stocks = pd.read_csv(f, sep=\",\")\n"
]
}
],
"source": [
"with fs.open('s3://projet-bdc-carmignac-g3/aum_equity_95pct.csv', 'rb') as f:\n",
" equity_stocks = pd.read_csv(f, sep=\",\")\n",
"\n",
"equity_stocks[\"Centralisation Date\"] = pd.to_datetime(equity_stocks[\"Centralisation Date\"], errors=\"coerce\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"equity_stocks_head = equity_stocks.head(150)\n",
"equity_stocks_head.to_csv(\"equity_stocks_head.csv\")"
]
},
2026-02-22 15:02:41 +01:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sum of AUM by Product - Asset Type"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"AUM (€) by Product - Asset Type:\n",
"Product - Asset Type\n",
"Diversified 2.249487e+12\n",
"Fixed Income 1.901982e+12\n",
"Equity 9.811712e+11\n",
"Alternative 1.208047e+11\n",
"NaN 1.786480e+10\n",
"Private Assets 2.205183e+09\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Product - Asset Type</th>\n",
" <th>Total AUM (€)</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Diversified</td>\n",
" <td>2.249487e+12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Fixed Income</td>\n",
" <td>1.901982e+12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Equity</td>\n",
" <td>9.811712e+11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Alternative</td>\n",
" <td>1.208047e+11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>NaN</td>\n",
" <td>1.786480e+10</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>Private Assets</td>\n",
" <td>2.205183e+09</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Product - Asset Type Total AUM (€)\n",
"0 Diversified 2.249487e+12\n",
"1 Fixed Income 1.901982e+12\n",
"2 Equity 9.811712e+11\n",
"3 Alternative 1.208047e+11\n",
"4 NaN 1.786480e+10\n",
"5 Private Assets 2.205183e+09"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Sum Value - AUM € per Product - Asset Type\n",
"aum_by_asset_type = stocks.groupby('Product - Asset Type', dropna=False)['Value - AUM €'].sum().sort_values(ascending=False)\n",
"\n",
"print(\"AUM (€) by Product - Asset Type:\")\n",
"print(aum_by_asset_type.to_string())\n",
"\n",
"# Display as DataFrame for nicer formatting\n",
"aum_by_asset_type_df = aum_by_asset_type.reset_index()\n",
"aum_by_asset_type_df.columns = ['Product - Asset Type', 'Total AUM (€)']\n",
"aum_by_asset_type_df"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(figsize=(10, 5))\n",
"aum_by_asset_type.plot(kind='bar', ax=ax, color='steelblue', edgecolor='navy', alpha=0.8)\n",
"ax.set_title('AUM Distribution by Product - Asset Type')\n",
"ax.set_xlabel('Product - Asset Type')\n",
"ax.set_ylabel('Total AUM (€)')\n",
"ax.tick_params(axis='x', rotation=45)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# For each asset type: AUM per account (sum across funds/dates)\n",
"aum_per_account = stocks.groupby(['Product - Asset Type', 'Registrar Account - ID'], dropna=False)['Value - AUM €'].sum().reset_index()\n",
"\n",
"# Build cumulative concentration curves per asset type\n",
"fig, ax = plt.subplots(figsize=(10, 6))\n",
"\n",
"for asset_type in aum_per_account['Product - Asset Type'].unique():\n",
" subset = aum_per_account[aum_per_account['Product - Asset Type'] == asset_type].copy()\n",
" subset = subset.sort_values('Value - AUM €', ascending=False).reset_index(drop=True)\n",
" \n",
" total_aum = subset['Value - AUM €'].sum()\n",
" if total_aum == 0:\n",
" continue\n",
" \n",
" subset['cumsum_aum'] = subset['Value - AUM €'].cumsum()\n",
" subset['cumsum_pct'] = 100 * subset['cumsum_aum'] / total_aum\n",
" subset['n_accounts'] = range(1, len(subset) + 1)\n",
" \n",
" ax.plot(subset['n_accounts'], subset['cumsum_pct'], label=asset_type if pd.notna(asset_type) else '(empty)', linewidth=2)\n",
"\n",
"ax.axhline(y=90, color='gray', linestyle='--', alpha=0.5, label='90% threshold')\n",
"ax.set_xlabel('Number of accounts (sorted by AUM, largest first)')\n",
"ax.set_ylabel('Cumulative % of total AUM')\n",
"ax.set_title('Account concentration: how many accounts hold X% of each asset type?')\n",
"ax.legend(loc='lower right')\n",
"ax.grid(True, alpha=0.3)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Product - Asset Type</th>\n",
" <th>50% of AUM</th>\n",
" <th>75% of AUM</th>\n",
" <th>90% of AUM</th>\n",
" <th>95% of AUM</th>\n",
" <th>99% of AUM</th>\n",
" <th>Total accounts</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Alternative</td>\n",
" <td>19</td>\n",
" <td>80</td>\n",
" <td>193</td>\n",
" <td>309</td>\n",
" <td>667</td>\n",
" <td>2679</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Diversified</td>\n",
" <td>36</td>\n",
" <td>113</td>\n",
" <td>289</td>\n",
" <td>480</td>\n",
" <td>1100</td>\n",
" <td>8846</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Equity</td>\n",
" <td>35</td>\n",
" <td>125</td>\n",
" <td>331</td>\n",
" <td>556</td>\n",
" <td>1378</td>\n",
" <td>9123</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Fixed Income</td>\n",
" <td>33</td>\n",
" <td>114</td>\n",
" <td>307</td>\n",
" <td>514</td>\n",
" <td>1132</td>\n",
" <td>7348</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Private Assets</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>3</td>\n",
" <td>18</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Product - Asset Type 50% of AUM 75% of AUM 90% of AUM 95% of AUM \\\n",
"0 Alternative 19 80 193 309 \n",
"1 Diversified 36 113 289 480 \n",
"2 Equity 35 125 331 556 \n",
"3 Fixed Income 33 114 307 514 \n",
"4 Private Assets 1 1 1 1 \n",
"\n",
" 99% of AUM Total accounts \n",
"0 667 2679 \n",
"1 1100 8846 \n",
"2 1378 9123 \n",
"3 1132 7348 \n",
"4 3 18 "
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Summary: number of accounts holding X% of each asset type\n",
"thresholds = [50, 75, 90, 95, 99]\n",
"results = []\n",
"\n",
"for asset_type in aum_per_account['Product - Asset Type'].unique():\n",
" subset = aum_per_account[aum_per_account['Product - Asset Type'] == asset_type].copy()\n",
" subset = subset.sort_values('Value - AUM €', ascending=False).reset_index(drop=True)\n",
" total_aum = subset['Value - AUM €'].sum()\n",
" if total_aum == 0:\n",
" continue\n",
" \n",
" cumsum_pct = 100 * subset['Value - AUM €'].cumsum() / total_aum\n",
" \n",
" row = {'Product - Asset Type': asset_type if pd.notna(asset_type) else '(empty)'}\n",
" for pct in thresholds:\n",
" n_accounts = (cumsum_pct >= pct).idxmax() + 1 if (cumsum_pct >= pct).any() else len(subset)\n",
" row[f'{pct}% of AUM'] = n_accounts\n",
" row['Total accounts'] = len(subset)\n",
" results.append(row)\n",
"\n",
"pd.DataFrame(results)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Alternative: 309 accounts (95% AUM) → 50947 rows → aum_95pct_by_asset_type/aum_alternative_95pct.csv\n",
"Diversified: 480 accounts (95% AUM) → 354694 rows → aum_95pct_by_asset_type/aum_diversified_95pct.csv\n",
"Equity: 556 accounts (95% AUM) → 431011 rows → aum_95pct_by_asset_type/aum_equity_95pct.csv\n",
"Fixed Income: 514 accounts (95% AUM) → 345213 rows → aum_95pct_by_asset_type/aum_fixed_income_95pct.csv\n",
"Private Assets: 1 accounts (95% AUM) → 88 rows → aum_95pct_by_asset_type/aum_private_assets_95pct.csv\n",
"nan: 4 accounts (95% AUM) → 3076 rows → aum_95pct_by_asset_type/aum_empty_95pct.csv\n",
"\n",
"Done. Files saved in 'aum_95pct_by_asset_type/'\n"
]
}
],
"source": [
"OUTPUT_DIR = 'aum_95pct_by_asset_type'\n",
"os.makedirs(OUTPUT_DIR, exist_ok=True)\n",
"\n",
"def safe_filename(asset_type):\n",
" \"\"\"Convert asset type to a safe filename.\"\"\"\n",
" if pd.isna(asset_type) or str(asset_type).strip() == '':\n",
" return 'empty'\n",
" return re.sub(r'[^\\w\\-]', '_', str(asset_type).strip().lower().replace(' ', '_'))\n",
"\n",
"# For each asset type: get accounts holding 95% of AUM\n",
"for asset_type in aum_per_account['Product - Asset Type'].unique():\n",
" if pd.isna(asset_type):\n",
" subset = aum_per_account[aum_per_account['Product - Asset Type'].isna()].copy()\n",
" else:\n",
" subset = aum_per_account[aum_per_account['Product - Asset Type'] == asset_type].copy()\n",
" subset = subset.sort_values('Value - AUM €', ascending=False).reset_index(drop=True)\n",
" total_aum = subset['Value - AUM €'].sum()\n",
" \n",
" if total_aum == 0:\n",
" n_accounts_95 = 0\n",
" accounts_95 = set()\n",
" else:\n",
" cumsum_pct = 100 * subset['Value - AUM €'].cumsum() / total_aum\n",
" n_accounts_95 = (cumsum_pct >= 95).idxmax() + 1 if (cumsum_pct >= 95).any() else len(subset)\n",
" accounts_95 = set(subset.head(n_accounts_95)['Registrar Account - ID'])\n",
" \n",
" # Extract all rows from original df for these accounts AND this asset type\n",
" if pd.isna(asset_type):\n",
" type_mask = stocks['Product - Asset Type'].isna()\n",
" else:\n",
" type_mask = stocks['Product - Asset Type'] == asset_type\n",
" mask = type_mask & (stocks['Registrar Account - ID'].isin(accounts_95))\n",
" df_subset = stocks.loc[mask]\n",
" \n",
" filename = f\"aum_{safe_filename(asset_type)}_95pct.csv\"\n",
" filepath = os.path.join(OUTPUT_DIR, filename)\n",
" df_subset.to_csv(filepath, index=False)\n",
" \n",
" print(f\"{asset_type or '(empty)'}: {len(accounts_95)} accounts (95% AUM) → {len(df_subset)} rows → {filepath}\")\n",
"\n",
"print(f\"\\nDone. Files saved in '{OUTPUT_DIR}/'\")"
]
},
2026-02-22 15:02:41 +01:00
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sum of AUM by Product - Fund"
]
},
{
"cell_type": "code",
"execution_count": 6,
2026-02-22 15:02:41 +01:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"AUM (€) by Product - Fund:\n",
"Product - Fund\n",
"Carmignac Patrimoine 1.838372e+12\n",
"Carmignac Sécurité 1.053010e+12\n",
"Carmignac Investissement 5.300035e+11\n",
"Carmignac Portfolio Sécurité 2.562135e+11\n",
"Carmignac Portfolio Flexible Bond 2.223185e+11\n",
"Carmignac Portfolio Patrimoine 2.035761e+11\n",
"Carmignac Emergents 1.218833e+11\n",
"Carmignac Portfolio Global Bond 1.119945e+11\n",
"Carmignac Portfolio Credit 8.413277e+10\n",
"Carmignac Court Terme 8.224046e+10\n",
"Carmignac Portfolio Emerging Patrimoine 7.216283e+10\n",
"Carmignac Portfolio Grande Europe 6.404670e+10\n",
"Carmignac Portfolio Long-Short European Equities 6.162365e+10\n",
"Carmignac Portfolio Climate Transition 5.125412e+10\n",
"Carmignac Absolute Return Europe 4.100414e+10\n",
"Carmignac Credit 2027 3.937522e+10\n",
"Carmignac Portfolio Patrimoine Europe 3.880186e+10\n",
"Carmignac Portfolio Investissement 3.643094e+10\n",
"Carmignac Investissement Latitude 3.474053e+10\n",
"Carmignac Portfolio Emergents 2.942745e+10\n",
"Carmignac Portfolio Asia Discovery 2.934378e+10\n",
"Carmignac Multi Expertise 2.633552e+10\n",
"Carmignac Euro-Entrepreneurs 2.522512e+10\n",
"Carmignac Credit 2029 1.738790e+10\n",
"Carmignac Portfolio Grandchildren 1.627555e+10\n",
"Carmignac Credit 2025 1.547217e+10\n",
"Fonditalia Carmignac Active Allocation 1.452571e+10\n",
"Carmignac Portfolio EM Debt 1.231814e+10\n",
"UFF Grande Europe 0-100 1.222263e+10\n",
"Carmignac Profil Réactif 75 1.178726e+10\n",
"Carmignac Global Active 1.079949e+10\n",
"Carmignac Profil Réactif 100 1.032957e+10\n",
"FP Carmignac European Leaders 8.759356e+09\n",
"Mapfre Carmignac F.P. 8.205244e+09\n",
"Carmignac Portfolio Flexible Allocation 2024 6.464648e+09\n",
"Carmignac China New Economy 5.961919e+09\n",
"Carmignac Portfolio Investissement Latitude 5.955304e+09\n",
"Carmignac Credit 2031 5.310328e+09\n",
"FP Carmignac Global Equity Compounders 4.482628e+09\n",
"Carmignac Portfolio Merger Arbitrage Plus 4.335203e+09\n",
"Credit Suisse Carmignac Emerging Markets Multi-Asset Fund 3.920236e+09\n",
"Carmignac Portfolio Euro-Entrepreneurs 3.670384e+09\n",
"Carmignac Portfolio Merger Arbitrage 3.643225e+09\n",
"Carmignac Portfolio Human Xperience 3.477910e+09\n",
"Carmignac Alts ICAV Carmignac Credit Opportunities 3.294673e+09\n",
"Carmignac Alts ICAV European Long Short 3.260443e+09\n",
"Carmignac Portfolio Capital Cube 2.773859e+09\n",
"Carmignac Portfolio China New Economy 2.757754e+09\n",
"FP Carmignac Emerging Markets 2.224219e+09\n",
"FP Carmignac Global Bond 2.208401e+09\n",
"Carmignac S.A. SICAV - PART II UCI Private Evergreen 2.205183e+09\n",
"Carmignac Portfolio Family Governed 2.104642e+09\n",
"Carmignac Portfolio Tech Solutions 1.812327e+09\n",
"FP Carmignac Emerging Patrimoine 1.486110e+09\n",
"Carmignac Portfolio Long-Short Global Equities 1.450546e+09\n",
"FP Carmignac Patrimoine 1.367843e+09\n",
"FP Carmignac Emerging Discovery 1.315189e+09\n",
"Carmignac Portfolio Global Market Neutral 8.912455e+08\n",
"Carmignac Portfolio China 8.898217e+08\n",
"Carmignac Portfolio Inflation Solution 8.063914e+08\n",
"Carmignac Portfolio Absolute Return Europe 7.929928e+08\n",
"Solys - Carmignac Equity Selection 6.677506e+08\n",
"LUX IM - Carmignac Emerging Flexible Bond 6.397498e+08\n",
"Carmignac Portfolio Evolution 5.464840e+08\n",
"Carmignac Portfolio Alpha Themes 5.085499e+08\n",
"Carmignac Portfolio Active Risk Allocation 3.816403e+08\n",
"Carmignac Portfolio Cross Asset Opportunities 2.291751e+08\n",
"Carmignac Portfolio Sustainable Bond 6.016398e+07\n",
"Carmignac Epargne Actions Monde ISR 1.858147e+07\n",
"CFP 1 2.300000e+02\n",
"Carmignac Innovation 0.000000e+00\n",
"Carmignac Euro-Investissement 0.000000e+00\n",
"Carmignac Portfolio Infotech 0.000000e+00\n",
"Carmignac Portfolio Market Neutral 0.000000e+00\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Product - Fund</th>\n",
" <th>Total AUM (€)</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>1.838372e+12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1.053010e+12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Carmignac Investissement</td>\n",
" <td>5.300035e+11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>2.562135e+11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>2.223185e+11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>69</th>\n",
" <td>CFP 1</td>\n",
" <td>2.300000e+02</td>\n",
" </tr>\n",
" <tr>\n",
" <th>70</th>\n",
" <td>Carmignac Innovation</td>\n",
" <td>0.000000e+00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>71</th>\n",
" <td>Carmignac Euro-Investissement</td>\n",
" <td>0.000000e+00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>72</th>\n",
" <td>Carmignac Portfolio Infotech</td>\n",
" <td>0.000000e+00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>73</th>\n",
" <td>Carmignac Portfolio Market Neutral</td>\n",
" <td>0.000000e+00</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>74 rows × 2 columns</p>\n",
"</div>"
],
"text/plain": [
" Product - Fund Total AUM (€)\n",
"0 Carmignac Patrimoine 1.838372e+12\n",
"1 Carmignac Sécurité 1.053010e+12\n",
"2 Carmignac Investissement 5.300035e+11\n",
"3 Carmignac Portfolio Sécurité 2.562135e+11\n",
"4 Carmignac Portfolio Flexible Bond 2.223185e+11\n",
".. ... ...\n",
"69 CFP 1 2.300000e+02\n",
"70 Carmignac Innovation 0.000000e+00\n",
"71 Carmignac Euro-Investissement 0.000000e+00\n",
"72 Carmignac Portfolio Infotech 0.000000e+00\n",
"73 Carmignac Portfolio Market Neutral 0.000000e+00\n",
"\n",
"[74 rows x 2 columns]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
2026-02-22 15:02:41 +01:00
"source": [
"# Sum Value - AUM € per Product - Fund\n",
"aum_by_fund = stocks.groupby('Product - Fund', dropna=False)['Value - AUM €'].sum().sort_values(ascending=False)\n",
"\n",
"print(\"AUM (€) by Product - Fund:\")\n",
"print(aum_by_fund.to_string())\n",
"\n",
"# Display as DataFrame for nicer formatting\n",
"aum_by_fund_df = aum_by_fund.reset_index()\n",
"aum_by_fund_df.columns = ['Product - Fund', 'Total AUM (€)']\n",
"aum_by_fund_df"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x800 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(figsize=(10, 8))\n",
"aum_by_fund.plot(kind='barh', ax=ax, color='coral', edgecolor='darkred', alpha=0.8)\n",
"ax.set_title('AUM Distribution by Product - Fund')\n",
"ax.set_xlabel('Total AUM (€)')\n",
"ax.set_ylabel('Product - Fund')\n",
"plt.tight_layout()\n",
"plt.show()"
]
2026-02-22 15:02:41 +01:00
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}