Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Financioneroncios/224fa56e13c6e6070891747510160815 to your computer and use it in GitHub Desktop.
Save Financioneroncios/224fa56e13c6e6070891747510160815 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "d760e6e6",
"metadata": {},
"source": [
"# Relativistic Value at Risk Portfolio Optimization\n",
"\n",
"<br>__[Financionerioncios](https://financioneroncios.wordpress.com)__\n",
"<br>__[Dany Cajas](https://www.linkedin.com/in/dany-cajas/)__\n",
"<br>__[Riskfolio-Lib](http://riskfolio-lib.readthedocs.io/)__\n",
"<br>__[Practical Econometrics with Python](https://www.amazon.com/-/es/Marlon-Saito-ebook/dp/B08KJ1322G/ref=sr_1_1?dchild=1&qid=1603904149&refinements=p_27%3AMarlon+Saito&s=digital-text&sr=1-1&text=Marlon+Saito)__ \n",
"<br>__[Econometría Práctica con Python](https://www.amazon.com/-/es/Marlon-Saito-ebook/dp/B08KHZKV9R/ref=sr_1_2?dchild=1&qid=1603903646&refinements=p_27%3AMarlon+Saito&s=digital-text&sr=1-2&text=Marlon+Saito)__ \n",
"\n",
"In this notebook we show how to use the power cone and its application in portfolio optimization.\n",
"\n",
"## 1. Relativistic Value at Risk (RLVaR) Optimization\n",
"\n",
"__[Cajas (2023)](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4378498)__ proposed a generalization of Entropic Value at Risk (EVaR) __[Ahmadi-Javid (2012)](https://link.springer.com/article/10.1007/s10957-011-9968-2?r=1&l=ri&fst=0&error=cookies_not_supported&code=ccfb8a5e-692b-43d1-b76e-ae596c7f0bed)__ based on Kaniadakis entropy __[Kaniadakis (2001)](https://www.sciencedirect.com/science/article/pii/S0378437101001844)__. We can pose the minimization of Relativistic Value at Risk as the following convex programming problem: \n",
"\n",
"$$\n",
"\\begin{equation}\n",
"\\begin{aligned}\n",
"& \\underset{x, z, t, \\psi, \\theta, \\varepsilon, \\omega}{\\text{min}} & & t + z \\ln_{\\kappa} \\left ( \\frac{1}{\\alpha T} \\right ) + \\sum^T_{j=1} \\left ( \\psi_{j} + \\theta_{j} \\right ) \\\\\n",
"& \\text{s.t.} & & -r_{j} x - t + \\varepsilon_{j} + \\omega_{j} \\leq 0 \\; ; \\; \\forall j =1, \\ldots ,T \\\\\n",
"& & & z \\geq 0 \\\\\n",
"& & & \\left ( z \\left ( \\frac{1+\\kappa}{2\\kappa} \\right ), \\psi_{j} \\left ( \\frac{1+\\kappa}{\\kappa} \\right ), \\varepsilon_{j} \\right) \\in \\mathcal{P}_3^{1/(1+\\kappa),\\, \\kappa/(1+\\kappa)} \\\\ \n",
"& & & \\left ( \\omega_{j}\\left ( \\frac{1}{1-\\kappa} \\right ), \\theta_{j}\\left ( \\frac{1}{\\kappa} \\right), -z \\left ( \\frac{1}{2\\kappa} \\right ) \\right ) \\in \\mathcal{P}_3^{1-\\kappa,\\, \\kappa} \\\\\n",
"& & & \\sum_{i=1}^{n} x_i = 1 \\\\\n",
"& & & x_i \\geq 0 \\; ; \\; \\forall \\; i =1, \\ldots, n \\\\\n",
"\\end{aligned}\n",
"\\end{equation}\n",
"\n",
"$$\n",
"\n",
"Where $t$, $z$ $\\psi$, $\\theta$, $\\epsilon$ and $\\omega$ are auxiliary variables, $x$ are the weights of portfolio assets of size $n \\times 1$, $\\mathcal{P}^{\\alpha, 1-\\alpha}$ is a power cone, $r$ is the matrix of observed returns and $\\kappa$ is the deformation parameter of Kaniadakis logarithm."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "2a19278a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[*********************100%***********************] 14 of 14 completed\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>BAX</th>\n",
" <th>BMY</th>\n",
" <th>CMCSA</th>\n",
" <th>CNP</th>\n",
" <th>CPB</th>\n",
" <th>GE</th>\n",
" <th>GOOG</th>\n",
" <th>MO</th>\n",
" <th>MSFT</th>\n",
" <th>NI</th>\n",
" <th>SEE</th>\n",
" <th>T</th>\n",
" <th>TGT</th>\n",
" <th>VZ</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Date</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2016-01-05</th>\n",
" <td>0.4035%</td>\n",
" <td>1.9693%</td>\n",
" <td>0.0180%</td>\n",
" <td>0.9305%</td>\n",
" <td>0.3678%</td>\n",
" <td>0.0977%</td>\n",
" <td>0.0998%</td>\n",
" <td>2.0213%</td>\n",
" <td>0.4562%</td>\n",
" <td>1.5881%</td>\n",
" <td>0.9759%</td>\n",
" <td>0.6987%</td>\n",
" <td>1.7539%</td>\n",
" <td>1.3734%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2016-01-06</th>\n",
" <td>0.2412%</td>\n",
" <td>-1.7557%</td>\n",
" <td>-0.7727%</td>\n",
" <td>-1.2473%</td>\n",
" <td>-0.1736%</td>\n",
" <td>-1.5940%</td>\n",
" <td>0.1400%</td>\n",
" <td>1.0589%</td>\n",
" <td>-1.8165%</td>\n",
" <td>0.5547%</td>\n",
" <td>-1.5647%</td>\n",
" <td>0.3108%</td>\n",
" <td>-1.0155%</td>\n",
" <td>-0.9034%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2016-01-07</th>\n",
" <td>-1.6573%</td>\n",
" <td>-2.7699%</td>\n",
" <td>-1.1047%</td>\n",
" <td>-1.9770%</td>\n",
" <td>-1.2206%</td>\n",
" <td>-4.2314%</td>\n",
" <td>-2.3170%</td>\n",
" <td>-1.7407%</td>\n",
" <td>-3.4783%</td>\n",
" <td>-2.2067%</td>\n",
" <td>-3.1557%</td>\n",
" <td>-1.6148%</td>\n",
" <td>-0.2700%</td>\n",
" <td>-0.5492%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2016-01-08</th>\n",
" <td>-1.6037%</td>\n",
" <td>-2.5425%</td>\n",
" <td>0.1099%</td>\n",
" <td>-0.2241%</td>\n",
" <td>0.5706%</td>\n",
" <td>-1.7949%</td>\n",
" <td>-1.6410%</td>\n",
" <td>0.1720%</td>\n",
" <td>0.3067%</td>\n",
" <td>-0.1538%</td>\n",
" <td>-0.1448%</td>\n",
" <td>0.0896%</td>\n",
" <td>-3.3839%</td>\n",
" <td>-0.9719%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2016-01-11</th>\n",
" <td>-1.6851%</td>\n",
" <td>-1.0215%</td>\n",
" <td>0.0914%</td>\n",
" <td>-1.1791%</td>\n",
" <td>0.5674%</td>\n",
" <td>0.4569%</td>\n",
" <td>0.2183%</td>\n",
" <td>2.0947%</td>\n",
" <td>-0.0573%</td>\n",
" <td>1.6436%</td>\n",
" <td>-0.1450%</td>\n",
" <td>1.2224%</td>\n",
" <td>1.4570%</td>\n",
" <td>0.5799%</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" BAX BMY CMCSA CNP CPB GE GOOG \\\n",
"Date \n",
"2016-01-05 0.4035% 1.9693% 0.0180% 0.9305% 0.3678% 0.0977% 0.0998% \n",
"2016-01-06 0.2412% -1.7557% -0.7727% -1.2473% -0.1736% -1.5940% 0.1400% \n",
"2016-01-07 -1.6573% -2.7699% -1.1047% -1.9770% -1.2206% -4.2314% -2.3170% \n",
"2016-01-08 -1.6037% -2.5425% 0.1099% -0.2241% 0.5706% -1.7949% -1.6410% \n",
"2016-01-11 -1.6851% -1.0215% 0.0914% -1.1791% 0.5674% 0.4569% 0.2183% \n",
"\n",
" MO MSFT NI SEE T TGT VZ \n",
"Date \n",
"2016-01-05 2.0213% 0.4562% 1.5881% 0.9759% 0.6987% 1.7539% 1.3734% \n",
"2016-01-06 1.0589% -1.8165% 0.5547% -1.5647% 0.3108% -1.0155% -0.9034% \n",
"2016-01-07 -1.7407% -3.4783% -2.2067% -3.1557% -1.6148% -0.2700% -0.5492% \n",
"2016-01-08 0.1720% 0.3067% -0.1538% -0.1448% 0.0896% -3.3839% -0.9719% \n",
"2016-01-11 2.0947% -0.0573% 1.6436% -0.1450% 1.2224% 1.4570% 0.5799% "
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"####################################\n",
"# Downloading Data\n",
"####################################\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import yfinance as yf\n",
"import warnings\n",
"\n",
"warnings.filterwarnings(\"ignore\")\n",
"\n",
"yf.pdr_override()\n",
"pd.options.display.float_format = '{:.4%}'.format\n",
"\n",
"# Date range\n",
"start = '2016-01-01'\n",
"end = '2019-12-30'\n",
"\n",
"# Tickers of assets\n",
"assets = ['TGT', 'CMCSA', 'CPB', 'MO', 'T', 'BAX', 'BMY',\n",
" 'MSFT', 'SEE', 'VZ', 'CNP', 'NI', 'GE', 'GOOG']\n",
"assets.sort()\n",
"\n",
"# Downloading data\n",
"data = yf.download(assets, start = start, end = end)\n",
"data = data.loc[:,('Adj Close', slice(None))]\n",
"data.columns = assets\n",
"\n",
"# Calculating returns\n",
"Y = data[assets].pct_change().dropna()\n",
"\n",
"display(Y.head())"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "94d0f382",
"metadata": {},
"outputs": [],
"source": [
"####################################\n",
"# Auxiliary functions\n",
"####################################\n",
"\n",
"# Function that calculates the Kaniadakis logarithm\n",
"def ln_k(x, kappa=0.3):\n",
" return (x**kappa - x**(-kappa))/(2*kappa)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "583f7d9a",
"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>Weights</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>BAX</th>\n",
" <td>0.0000%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>BMY</th>\n",
" <td>9.9856%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>CMCSA</th>\n",
" <td>6.9171%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>CNP</th>\n",
" <td>12.0874%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>CPB</th>\n",
" <td>15.2284%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>GE</th>\n",
" <td>0.0000%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>GOOG</th>\n",
" <td>5.4628%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>MO</th>\n",
" <td>0.0000%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>MSFT</th>\n",
" <td>0.0000%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>NI</th>\n",
" <td>17.1999%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>SEE</th>\n",
" <td>14.5753%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>T</th>\n",
" <td>0.0000%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>TGT</th>\n",
" <td>18.5435%</td>\n",
" </tr>\n",
" <tr>\n",
" <th>VZ</th>\n",
" <td>0.0000%</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Weights\n",
"BAX 0.0000%\n",
"BMY 9.9856%\n",
"CMCSA 6.9171%\n",
"CNP 12.0874%\n",
"CPB 15.2284%\n",
"GE 0.0000%\n",
"GOOG 5.4628%\n",
"MO 0.0000%\n",
"MSFT 0.0000%\n",
"NI 17.1999%\n",
"SEE 14.5753%\n",
"T 0.0000%\n",
"TGT 18.5435%\n",
"VZ 0.0000%"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"####################################\n",
"# Finding the Min EVaR Portfolio\n",
"####################################\n",
"\n",
"import cvxpy as cp\n",
"\n",
"# Defining initial parameters\n",
"returns = Y.to_numpy()\n",
"T, n = Y.shape\n",
"alpha = 0.05\n",
"kappa = 0.3\n",
"\n",
"# Defining initial variables\n",
"w = cp.Variable((n, 1))\n",
"X = returns @ w\n",
"t = cp.Variable((1, 1))\n",
"z = cp.Variable((1, 1), nonneg=True)\n",
"omega = cp.Variable((T, 1))\n",
"psi = cp.Variable((T, 1))\n",
"theta = cp.Variable((T, 1))\n",
"epsilon = cp.Variable((T, 1))\n",
"onesvec = np.ones((T, 1))\n",
"\n",
"constraints = [\n",
" cp.PowCone3D(\n",
" z * (1 + kappa) / (2 * kappa) * onesvec,\n",
" psi * (1 + kappa) / kappa,\n",
" epsilon,\n",
" 1 / (1 + kappa),\n",
" ),\n",
" cp.PowCone3D(\n",
" omega / (1 - kappa),\n",
" theta / kappa,\n",
" -z / (2 * kappa) * onesvec,\n",
" (1 - kappa),\n",
" ),\n",
" -X * 1000 - t * 1000 + epsilon * 1000 + omega * 1000 <= 0,\n",
" cp.sum(w) == 1,\n",
" w >= 0\n",
"]\n",
"\n",
"# Defining risk objective\n",
"risk = t + z * ln_k(1 / (alpha * T), kappa) + cp.sum(psi + theta)\n",
"objective = cp.Minimize(risk)\n",
"\n",
"# Solving problem\n",
"prob = cp.Problem(objective, constraints)\n",
"prob.solve()\n",
"\n",
"# Showing Optimal Weights\n",
"weights = pd.DataFrame(w.value, index=assets, columns=['Weights'])\n",
"display(weights)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "de8cc7f7",
"metadata": {},
"source": [
"This portfolio optimization model is available in the CVXPY based library __[Riskfolio-Lib](https://github.com/dcajasn/Riskfolio-Lib)__.\n",
"\n",
"Finally, I hope you liked this example."
]
}
],
"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.10.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment