{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "d760e6e6",
"metadata": {},
"source": [
"# Relativistic Value at Risk Portfolio Optimization\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=3792520)__ 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": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" BAX | \n",
" BMY | \n",
" CMCSA | \n",
" CNP | \n",
" CPB | \n",
" GE | \n",
" GOOG | \n",
" MO | \n",
" MSFT | \n",
" NI | \n",
" SEE | \n",
" T | \n",
" TGT | \n",
" VZ | \n",
"
\n",
" \n",
" Date | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" 2016-01-05 | \n",
" 0.4035% | \n",
" 1.9693% | \n",
" 0.0180% | \n",
" 0.9305% | \n",
" 0.3678% | \n",
" 0.0977% | \n",
" 0.0998% | \n",
" 2.0213% | \n",
" 0.4562% | \n",
" 1.5881% | \n",
" 0.9759% | \n",
" 0.6987% | \n",
" 1.7539% | \n",
" 1.3734% | \n",
"
\n",
" \n",
" 2016-01-06 | \n",
" 0.2412% | \n",
" -1.7557% | \n",
" -0.7727% | \n",
" -1.2473% | \n",
" -0.1736% | \n",
" -1.5940% | \n",
" 0.1400% | \n",
" 1.0589% | \n",
" -1.8165% | \n",
" 0.5547% | \n",
" -1.5647% | \n",
" 0.3108% | \n",
" -1.0155% | \n",
" -0.9034% | \n",
"
\n",
" \n",
" 2016-01-07 | \n",
" -1.6573% | \n",
" -2.7699% | \n",
" -1.1047% | \n",
" -1.9770% | \n",
" -1.2206% | \n",
" -4.2314% | \n",
" -2.3170% | \n",
" -1.7407% | \n",
" -3.4783% | \n",
" -2.2067% | \n",
" -3.1557% | \n",
" -1.6148% | \n",
" -0.2700% | \n",
" -0.5492% | \n",
"
\n",
" \n",
" 2016-01-08 | \n",
" -1.6037% | \n",
" -2.5425% | \n",
" 0.1099% | \n",
" -0.2241% | \n",
" 0.5706% | \n",
" -1.7949% | \n",
" -1.6410% | \n",
" 0.1720% | \n",
" 0.3067% | \n",
" -0.1538% | \n",
" -0.1448% | \n",
" 0.0896% | \n",
" -3.3839% | \n",
" -0.9719% | \n",
"
\n",
" \n",
" 2016-01-11 | \n",
" -1.6851% | \n",
" -1.0215% | \n",
" 0.0914% | \n",
" -1.1791% | \n",
" 0.5674% | \n",
" 0.4569% | \n",
" 0.2183% | \n",
" 2.0947% | \n",
" -0.0573% | \n",
" 1.6436% | \n",
" -0.1450% | \n",
" 1.2224% | \n",
" 1.4570% | \n",
" 0.5799% | \n",
"
\n",
" \n",
"
\n",
"
"
],
"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": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Weights | \n",
"
\n",
" \n",
" \n",
" \n",
" BAX | \n",
" 0.0000% | \n",
"
\n",
" \n",
" BMY | \n",
" 9.9856% | \n",
"
\n",
" \n",
" CMCSA | \n",
" 6.9171% | \n",
"
\n",
" \n",
" CNP | \n",
" 12.0874% | \n",
"
\n",
" \n",
" CPB | \n",
" 15.2284% | \n",
"
\n",
" \n",
" GE | \n",
" 0.0000% | \n",
"
\n",
" \n",
" GOOG | \n",
" 5.4628% | \n",
"
\n",
" \n",
" MO | \n",
" 0.0000% | \n",
"
\n",
" \n",
" MSFT | \n",
" 0.0000% | \n",
"
\n",
" \n",
" NI | \n",
" 17.1999% | \n",
"
\n",
" \n",
" SEE | \n",
" 14.5753% | \n",
"
\n",
" \n",
" T | \n",
" 0.0000% | \n",
"
\n",
" \n",
" TGT | \n",
" 18.5435% | \n",
"
\n",
" \n",
" VZ | \n",
" 0.0000% | \n",
"
\n",
" \n",
"
\n",
"
"
],
"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
}