{ "cells": [ { "cell_type": "markdown", "id": "d7d0afb1", "metadata": {}, "source": [ "# Investing with Transaction Costs\n", "\n", "The *standard mean-variance (Markowitz) portfolio selection model* determines an optimal investment portfolio that balances risk and expected return. In this notebook, we maximize the portfolio's expected return while constraining the admissible variance (risk) to a given maximum level. Please refer to the [annotated list of references](../literature.rst#portfolio-optimization) for more background information on portfolio optimization.\n", "\n", "To this basic model, we add *transaction costs and fees*. These have two components:\n", "* Fixed transaction costs, which are independent of the amount invested in each separate asset.\n", "* Variable transaction fees, which are proportional to the amount invested in each asset.\n", "\n", "This notebook focuses on constructing a new portfolio and assumes that the investor has no initial positions." ] }, { "cell_type": "code", "execution_count": 1, "id": "ea27c247", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:19.453477Z", "iopub.status.busy": "2025-01-31T10:06:19.453249Z", "iopub.status.idle": "2025-01-31T10:06:20.224919Z", "shell.execute_reply": "2025-01-31T10:06:20.224167Z" }, "nbsphinx": "hidden" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: numpy in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (2.2.2)\r\n", "Requirement already satisfied: scipy in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (1.15.1)\r\n", "Requirement already satisfied: gurobipy in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (11.0.3)\r\n", "Requirement already satisfied: pandas in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (2.2.3)\r\n", "Requirement already satisfied: matplotlib in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (3.10.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from pandas) (2.9.0.post0)\r\n", "Requirement already satisfied: pytz>=2020.1 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from pandas) (2025.1)\r\n", "Requirement already satisfied: tzdata>=2022.7 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from pandas) (2025.1)\r\n", "Requirement already satisfied: contourpy>=1.0.1 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (1.3.1)\r\n", "Requirement already satisfied: cycler>=0.10 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (0.12.1)\r\n", "Requirement already satisfied: fonttools>=4.22.0 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (4.55.8)\r\n", "Requirement already satisfied: kiwisolver>=1.3.1 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (1.4.8)\r\n", "Requirement already satisfied: packaging>=20.0 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (24.2)\r\n", "Requirement already satisfied: pillow>=8 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (11.1.0)\r\n", "Requirement already satisfied: pyparsing>=2.3.1 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from matplotlib) (3.2.1)\r\n", "Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "# Install dependencies\n", "%pip install numpy scipy gurobipy pandas matplotlib" ] }, { "cell_type": "code", "execution_count": 2, "id": "a3065ce3", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:20.227074Z", "iopub.status.busy": "2025-01-31T10:06:20.226856Z", "iopub.status.idle": "2025-01-31T10:06:20.848930Z", "shell.execute_reply": "2025-01-31T10:06:20.848215Z" } }, "outputs": [], "source": [ "import gurobipy as gp\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 3, "id": "aaced655", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:20.851441Z", "iopub.status.busy": "2025-01-31T10:06:20.851108Z", "iopub.status.idle": "2025-01-31T10:06:20.859766Z", "shell.execute_reply": "2025-01-31T10:06:20.859209Z" }, "nbsphinx": "hidden" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter WLSAccessID\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Set parameter WLSSecret\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Set parameter LicenseID to value 2443533\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WLS license 2443533 - registered to Gurobi GmbH\n" ] } ], "source": [ "# Hidden cell to avoid licensing messages\n", "# when docs are generated.\n", "with gp.Model():\n", " pass" ] }, { "cell_type": "markdown", "id": "7834a7b4", "metadata": {}, "source": [ "## Input Data\n", "\n", "The following input data is used within the model:\n", "\n", "- $S$: set of stocks\n", "- $\\mu$: vector of expected returns\n", "- $\\Sigma$: PSD variance-covariance matrix\n", " - $\\sigma_{ij}$ covariance between returns of assets $i$ and $j$\n", " - $\\sigma_{ii}$ variance of return of asset $i$" ] }, { "cell_type": "code", "execution_count": 4, "id": "50457259", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:20.861629Z", "iopub.status.busy": "2025-01-31T10:06:20.861442Z", "iopub.status.idle": "2025-01-31T10:06:20.866570Z", "shell.execute_reply": "2025-01-31T10:06:20.865962Z" } }, "outputs": [], "source": [ "# Import some example data set\n", "Sigma = pd.read_pickle(\"sigma.pkl\")\n", "mu = pd.read_pickle(\"mu.pkl\")" ] }, { "cell_type": "markdown", "id": "35843746", "metadata": {}, "source": [ "## Formulation\n", "\n", "The model creates a new portfolio (no initial positions held by the investor) by maximizing the expected net return while ensuring that the variance of the portfolio return does not exceed a specified level. It also accounts for the impact of transaction costs on the available investment budget.\n", "\n", "The transaction costs are twofold:\n", "\n", "1. The fixed transaction costs for buying each asset, which do not depend on the amount invested.\n", "2. The variable transaction fees, which are proportional (also called *linear*) to the amount invested into each asset.\n", "\n", "Mathematically, this results in a convex quadratically constrained mixed-integer optimization problem.\n", "\n", "### Model Parameters\n", "We use the following parameters:\n", "\n", "- $\\bar\\sigma^2$: maximal admissible variance for the portfolio return\n", "- $\\ell>0$: lower bound on position size\n", "- $c$: fixed transaction costs for any asset, relative to total investment value\n", "- $f_i$: variable transaction fee for asset $i$, relative to total investment value\n", "\n", "In this notebook, we assume that the fixed costs are the same for each asset, while the variable fees may differ for different assets. Both costs and fees are given relative to the total capital." ] }, { "cell_type": "code", "execution_count": 5, "id": "da36e79e", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:20.868376Z", "iopub.status.busy": "2025-01-31T10:06:20.868197Z", "iopub.status.idle": "2025-01-31T10:06:20.871194Z", "shell.execute_reply": "2025-01-31T10:06:20.870772Z" } }, "outputs": [], "source": [ "# Values for the model parameters:\n", "V = 4.0 # Maximal admissible variance (sigma^2)\n", "l = 0.001 # Minimal position size\n", "c = 0.0001 # Fixed transaction costs\n", "f = 0.001 * np.ones(mu.shape) # Variable transaction fees" ] }, { "cell_type": "markdown", "id": "d0111970", "metadata": {}, "source": [ "### Decision Variables\n", "We need two sets of decision variables:\n", "\n", "1. The proportions of capital invested among the considered stocks. The corresponding vector of positions is denoted by $x$ with its component $x_i$ denoting the proportion of capital invested in stock $i$.\n", "\n", "2. Binary variables $b_i$ indicating whether or not asset $i$ is held. If $b_i$ is 0, the holding $x_i$ is also 0; otherwise if $b_i$ is 1, the investor holds asset $i$ (that is, $x_i \\geq \\ell$).\n", "\n", "### Variable Bounds\n", "\n", "Each position must be between 0 and 1; this prevents leverage and short-selling:\n", "\n", "$$0\\leq x_i\\leq 1 \\; , \\; i \\in S$$\n", "\n", "The $b_i$ must be binary:\n", "\n", "$$b_i \\in \\{0,1\\} \\; , \\; i \\in S$$" ] }, { "cell_type": "code", "execution_count": 6, "id": "3db2081f", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:20.872947Z", "iopub.status.busy": "2025-01-31T10:06:20.872766Z", "iopub.status.idle": "2025-01-31T10:06:20.878434Z", "shell.execute_reply": "2025-01-31T10:06:20.877981Z" } }, "outputs": [], "source": [ "%%capture\n", "# Create an empty optimization model\n", "m = gp.Model()\n", "\n", "# Add variables: x[i] denotes the proportion invested in stock i\n", "x = m.addMVar(len(mu), lb=0, ub=1, name=\"x\")\n", "\n", "# Add variables: b[i]=1 if stock i is held, and b[i]=0 otherwise\n", "b = m.addMVar(len(mu), vtype=gp.GRB.BINARY, name=\"b\")" ] }, { "cell_type": "markdown", "id": "96d6f05c", "metadata": {}, "source": [ "### Constraints\n", "\n", "The estimated risk must not exceed a prespecified maximal admissible level of variance $\\bar\\sigma^2$:\n", "\n", "$$x^\\top \\Sigma x \\leq \\bar\\sigma^2$$" ] }, { "cell_type": "code", "execution_count": 7, "id": "ba97e3f0", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:20.880192Z", "iopub.status.busy": "2025-01-31T10:06:20.879980Z", "iopub.status.idle": "2025-01-31T10:06:21.050612Z", "shell.execute_reply": "2025-01-31T10:06:21.050067Z" } }, "outputs": [], "source": [ "%%capture\n", "# Upper bound on variance\n", "m.addConstr(x @ Sigma.to_numpy() @ x <= V, name=\"Variance\")" ] }, { "cell_type": "markdown", "id": "954a0c53", "metadata": {}, "source": [ "From the bounds we set earlier, $x$ can take any value between $0$ and $1$. To enforce the desired relationship between $x$ and the binary variables $b$, we use the following sets of discrete constraints:\n", "\n", "\n", "Ensure that $x_i = 0$ if $b_i = 0$:\n", "\\begin{equation*}\n", "x_i \\leq b_i \\; , \\; i \\in S\\tag{1}\n", "\\end{equation*}\n", "\n", "Note that since $x_i$ has an upper bound of 1, the above constraint is non-restrictive when $b_i = 1$.\n", "\n", "\n", "Ensure a minimal position size of $\\ell$ if asset $i$ is traded:\n", "\\begin{equation*}\n", "x_i \\geq \\ell b_i \\; , \\; i \\in S\\tag{2}\n", "\\end{equation*}\n", "\n", "Hence $b_i = 1$ implies $x_i \\geq \\ell$. Additionally, if $b_i = 0$, the above constraint is non-restrictive since $x_i$ has a lower bound of 0." ] }, { "cell_type": "code", "execution_count": 8, "id": "21e253f3", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:21.053287Z", "iopub.status.busy": "2025-01-31T10:06:21.052951Z", "iopub.status.idle": "2025-01-31T10:06:21.063606Z", "shell.execute_reply": "2025-01-31T10:06:21.063090Z" } }, "outputs": [], "source": [ "%%capture\n", "# Force x to 0 if not traded; see formula (1) above\n", "m.addConstr(x <= b, name=\"Indicator\")\n", "# Minimal position; see formula (2) above\n", "m.addConstr(x >= l * b, name=\"Minimal_Position\")" ] }, { "cell_type": "markdown", "id": "5f56d3e7", "metadata": {}, "source": [ "Without any costs or fees, we would have the budget constraint $\\sum_{i} x_i = 1$ to ensure that all investments sum up to one.\n", "However, we must also deduct the resulting fixed transaction costs and variable transaction fees from the capital.\n", "\n", "The *fixed costs* are incurred whenever an asset is held and do not depend on the position size; hence, the fixed cost for each asset $i$ is $cb_i$. The *variable fees* are proportional to the position size; hence, the fee for each asset $i$ is $f_ix_i$.\n", "\n", "We include these in the left-hand side of the equation:\n", "\n", "\\begin{equation*}\n", "\\underbrace{\\sum_{i \\in S} x_i}_\\text{investments}\n", "+ \\underbrace{c \\sum_{i \\in S} b_i}_\\text{fixed costs}\n", "+ \\underbrace{\\sum_{i \\in S}f_i x_i}_\\text{variable fees}\n", "= 1 \\tag{3}\n", "\\end{equation*}" ] }, { "cell_type": "code", "execution_count": 9, "id": "2efe49d6", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:21.066099Z", "iopub.status.busy": "2025-01-31T10:06:21.065859Z", "iopub.status.idle": "2025-01-31T10:06:21.070967Z", "shell.execute_reply": "2025-01-31T10:06:21.070472Z" } }, "outputs": [], "source": [ "# Budget constraint: all investments, costs, and fees sum up to 1; see formula (3) above\n", "budget_constr = m.addConstr(\n", " x.sum() + b.sum() * c + f @ x == 1, name=\"Budget_Constraint\"\n", ")" ] }, { "cell_type": "markdown", "id": "9829d0e7", "metadata": {}, "source": [ "### Objective Function\n", "The objective is to maximize the expected return of the portfolio:\n", "\n", "$$\\max_x \\mu^\\top x $$" ] }, { "cell_type": "code", "execution_count": 10, "id": "f0dc5536", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:21.072917Z", "iopub.status.busy": "2025-01-31T10:06:21.072739Z", "iopub.status.idle": "2025-01-31T10:06:21.076747Z", "shell.execute_reply": "2025-01-31T10:06:21.076266Z" } }, "outputs": [], "source": [ "# Define objective: Maximize expected return\n", "m.setObjective(mu.to_numpy() @ x, gp.GRB.MAXIMIZE)" ] }, { "cell_type": "markdown", "id": "a34f97fe", "metadata": {}, "source": [ "We now solve the optimization problem:" ] }, { "cell_type": "code", "execution_count": 11, "id": "ce98d634", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:21.079614Z", "iopub.status.busy": "2025-01-31T10:06:21.078909Z", "iopub.status.idle": "2025-01-31T10:06:33.067558Z", "shell.execute_reply": "2025-01-31T10:06:33.066924Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set parameter MIPGap to value 0.01\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Gurobi Optimizer version 11.0.3 build v11.0.3rc0 (linux64 - \"Ubuntu 24.04.1 LTS\")\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "CPU model: AMD EPYC 7763 64-Core Processor, instruction set [SSE2|AVX|AVX2]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Thread count: 1 physical cores, 2 logical processors, using up to 2 threads\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WLS license 2443533 - registered to Gurobi GmbH\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Optimize a model with 925 rows, 924 columns and 2772 nonzeros\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Model fingerprint: 0xa1c281a1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Model has 1 quadratic constraint\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Variable types: 462 continuous, 462 integer (462 binary)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Coefficient statistics:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Matrix range [1e-04, 1e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " QMatrix range [3e-03, 1e+02]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Objective range [7e-02, 6e-01]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Bounds range [1e+00, 1e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " RHS range [1e+00, 1e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " QRHS range [4e+00, 4e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Presolve time: 0.09s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Presolved: 925 rows, 924 columns, 2772 nonzeros\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Presolved model has 1 quadratic constraint(s)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Variable types: 462 continuous, 462 integer (462 binary)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Root relaxation: objective 5.914499e-01, 3 iterations, 0.00 seconds (0.00 work units)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Nodes | Current Node | Objective Bounds | Work\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.59145 0 2 - 0.59145 - - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.56243 0 2 - 0.56243 - - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.43870 0 3 - 0.43870 - - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.43867 0 3 - 0.43867 - - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.43863 0 4 - 0.43863 - - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.42948 0 4 - 0.42948 - - 1s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.42931 0 5 - 0.42931 - - 1s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.42852 0 5 - 0.42852 - - 1s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.41285 0 5 - 0.41285 - - 1s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.41285 0 5 - 0.41285 - - 1s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.40003 0 6 - 0.40003 - - 1s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.39462 0 5 - 0.39462 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.39461 0 5 - 0.39461 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.39245 0 6 - 0.39245 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.39245 0 6 - 0.39245 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.39230 0 7 - 0.39230 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38943 0 7 - 0.38943 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38892 0 8 - 0.38892 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38786 0 9 - 0.38786 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38569 0 8 - 0.38569 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38274 0 8 - 0.38274 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38246 0 9 - 0.38246 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.38045 0 8 - 0.38045 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37876 0 7 - 0.37876 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37860 0 8 - 0.37860 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37798 0 9 - 0.37798 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37756 0 9 - 0.37756 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37729 0 10 - 0.37729 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37714 0 9 - 0.37714 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37708 0 10 - 0.37708 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37548 0 9 - 0.37548 - - 2s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 0.37546 0 9 - 0.37546 - - 4s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 0.3287054 0.37546 14.2% - 4s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 0.3517700 0.37546 6.74% - 5s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 0.3517700 0.37546 6.74% - 6s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 2 0.37546 0 9 0.35177 0.37546 6.74% - 6s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 27 27 0.3528615 0.37541 6.39% 3.1 7s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 52 52 0.3528616 0.37537 6.38% 4.5 8s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 172 171 0.3530050 0.37512 6.26% 6.4 9s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 176 177 0.35782 19 1 0.35301 0.37512 6.26% 6.4 10s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 259 253 0.3530594 0.37310 5.68% 7.2 11s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Explored 261 nodes (2209 simplex iterations) in 11.97 seconds (11.13 work units)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Thread count was 2 (of 2 available processors)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Solution count 5: 0.353059 0.353005 0.352862 ... 0.328705\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Optimal solution found (tolerance 1.00e-02)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Best objective 3.530593974701e-01, best bound 3.542219836852e-01, gap 0.3293%\n" ] } ], "source": [ "m.params.mipgap = 0.01\n", "m.optimize()" ] }, { "cell_type": "markdown", "id": "09f266e8", "metadata": {}, "source": [ "Display basic solution data, costs, and fees:" ] }, { "cell_type": "code", "execution_count": 12, "id": "b2c1ca70", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:33.069527Z", "iopub.status.busy": "2025-01-31T10:06:33.069323Z", "iopub.status.idle": "2025-01-31T10:06:33.076094Z", "shell.execute_reply": "2025-01-31T10:06:33.075514Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Expected return: 0.353059\n", "Solution time: 11.98 seconds\n", "\n", "Fixed costs: 0.001800\n", "Variable fees: 0.000997\n", "Number of trades: 18.0\n", "\n", "TSLA 0.015914\n", "KR 0.028793\n", "PGR 0.129702\n", "ORLY 0.051440\n", "ODFL 0.032633\n", "KDP 0.065108\n", "UNH 0.022161\n", "AVGO 0.063054\n", "DXCM 0.018769\n", "NFLX 0.021747\n", "LLY 0.247388\n", "DPZ 0.032827\n", "WST 0.025197\n", "TMUS 0.037445\n", "NOC 0.052476\n", "TTWO 0.034686\n", "ENPH 0.010428\n", "NVDA 0.107435\n", "Name: Position, dtype: float64\n" ] } ], "source": [ "print(f\"Expected return: {m.ObjVal:.6f}\")\n", "print(f\"Solution time: {m.Runtime:.2f} seconds\\n\")\n", "print(f\"Fixed costs: {c * sum(b.X):.6f}\")\n", "print(f\"Variable fees: {f @ x.X:.6f}\")\n", "print(f\"Number of trades: {sum(b.X)}\\n\")\n", "\n", "# Print investments (with non-negligible value, i.e. >1e-5)\n", "positions = pd.Series(name=\"Position\", data=x.X, index=mu.index)\n", "print(positions[positions > 1e-5])" ] }, { "cell_type": "markdown", "id": "f45d854f", "metadata": {}, "source": [ "## Comparison with the unconstrained portfolio\n", "\n", "We can also optimize the portfolio without considering the transaction costs and compare the resulting portfolios." ] }, { "cell_type": "code", "execution_count": 13, "id": "edab859c", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:33.077944Z", "iopub.status.busy": "2025-01-31T10:06:33.077764Z", "iopub.status.idle": "2025-01-31T10:06:36.851380Z", "shell.execute_reply": "2025-01-31T10:06:36.850664Z" } }, "outputs": [ { "data": { "image/png": "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UBBSUlIKqytERERUihTqoRNtbW3MnDkTr169ynK+EALdu3fHtGnTMGLECISHhyMkJATW1tbw8PDAzp07pbrJycnw8vLCjBkzMHDgQJw5cwYXLlzAkCFDsGjRIty4caMwu0JERESlRKGeVmvevDnu3r2LgIAAzJo1K9P8zZs3Y+vWrdi9ezfatWsnlf/vf/9DTEwM+vfvjxYtWkBPTw/z58/HyZMncenSJdSsWVOqW7FiRXTp0gXJycmF2RUiIiIqJQr1yJG6ujqmT5+ORYsW4dGjR5nmr1+/Ho6OjiqJUYbRo0cjJiYGhw8fBgCsW7cOzZs3V0mMMmhqakJPTy/LGJKSkhAXF6cyEREREWWn0Adkd+zYETVq1IC/vz8CAwNV5t25cwfOzs5ZLpdRfufOHQBAREQEPDw88rz+gIAATJ06NVN5wyQnyNRK7Xj0z0pCcQdARESkpEgu15o5cybWrFmD8PDwTPOEELlqI7f1PuTn54fY2FhpevjwYb7aISIiotKhSJKjJk2awMvLC35+firljo6OWSZMAKRyR0dH6d9bt27led1yuRyGhoYqExEREVF2iuxGPzNmzMCePXtw9uxZqax79+6IiIjAnj17MtWfM2cOTE1N0aJFCwDAd999hyNHjuDKlSuZ6qakpODNmzeFFzwRERGVGkWWHLm4uMDb2xsLFy6Uyrp3746OHTvCx8cHgYGBiIqKwrVr1zBo0CDs3r0bq1atkgZajxw5Em5ubmjWrBmWLFmCq1ev4v79+9i8eTPq16+PiIiIouoKERERfcFkIr+DeT7C19cXr1+/VrlXUVRUFJycnJCcnCyNIUpNTcX8+fMRHByMiIgIaGtro0GDBpg0aRLc3NxU2kxKSsK8efOwfv16REREQFdXF87OzhgwYAC8vb2hofHxAdZxcXEwMjJCbGwsT7ERERGVEEX5/V1oydHniskRERFRyVOU3998uBgRERGREiZHREREREqYHBEREREpYXJEREREpITJEREREZESJkdERERESpgcERERESlhckRERESk5OO3lP5CRbrawkCNuWFxqnj/RXGHQERElEmBZgcPHz5E3759YWFhAS0tLdjY2GDEiBGIiYmR6nh4eEAmk0Emk0FbWxuOjo4ICAiA8o26o6KiIJPJEBYWJpWtXbsWenp6uHv3rso6nzx5AhMTEyxevLggu0JE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QUFBiI6Olqbdu3d/aqhEREREH/XJR46GDBkCLS0tHDp0CDo6OgCAChUqoGbNmrC3t8eECROwbNkyAICuri4UCgUAwMrKCvXr10flypXRt29fdO3aFc2bN5faNTY2luoSERERFZVPOnL08uVLHDx4ED/88IOUGGVQKBTw9vbGpk2bkNOzbX18fGBiYoLt27d/SihEREREBeKTkqOIiAgIIeDs7JzlfGdnZ7x69Qr//fdf9gGoqcHR0RFRUVEq5T169IC+vr407dy5M18xJiUlIS4uTmUiIiIiyk6BDMjO6chQbpf/cBD2vHnzVE6zmZub56vtgIAATJ06NVN5wyQnyNQKpPslRsLjU8UdAhER0Wfvk44cVapUCTKZDOHh4VnODw8Ph4mJCczMzLJtIy0tDREREbCzs1MpVygUqFSpkjTp6enlK0Y/Pz/ExsZK08OHD/PVDhEREZUOn5QcmZqaokWLFli6dCkSExNV5j19+hTr1q1Dt27dsrw0P8OaNWvw6tUrdO7c+VNCyZZcLoehoaHKRERERJSdTz6vtHjxYjRs2BBeXl749ddfYWdnhxs3bmDs2LGwtLTEb7/9JtV9+/Ytnj59itTUVDx69Ag7duzAvHnzMHjwYHh6euZpvZGRkQgLC1Mpc3BwyPcRJiIiIiKgAJIjBwcHXLp0Cf7+/ujatStevnwJhUKBDh06wN/fH2XKlJHqrly5EitXroSWlhZMTU1Ru3ZtbNq0CR07dszzekeNGpWp7NSpU2jUqNEn9YeIiIhKN5n41NHUJUxcXByMjIwQGxvLU2xEREQlRFF+f5e+52cQERER5YDJEREREZESJkdERERESpgcERERESlhckRERESkhMkRERERkRImR0RERERKmBwRERERKWFyRERERKTkkx8fUlJFutrCQO3LzQ0r3n9R3CEQERGVSJ9NduDr64sOHTqolG3duhXa2tqYM2cOfH19IZPJIJPJoKmpCTs7O/z000949+5d8QRMREREX6TPJjn60KpVq+Dt7Y1ly5Zh9OjRAICWLVsiOjoa9+/fx7x587BixQr4+/sXc6RERET0Jfksk6NZs2Zh2LBh2LhxI/r06SOVy+VyKBQKWFtbo0OHDmjevDkOHz5cjJESERHRl+azG3M0btw4LF26FHv37kWzZs2yrffPP//gzJkzsLGxybG9pKQkJCUlSa/j4uIKLFYiIiL68nxWydH+/fuxa9cuHD16FE2bNs00f+/evdDX10dqaiqSkpKgpqaGxYsX59hmQEAApk6dmqm8YZITZGqfVfcLRMLjU8UdAhERUYn2WZ1Wc3V1ha2tLfz9/ZGQkJBpvqenJ8LCwnD+/Hn4+PigT58+6Ny5c45t+vn5ITY2VpoePnxYWOETERHRF+CzSo4sLS0REhKCx48fo2XLloiPj1eZr6enh0qVKqF69epYvXo1zp8/j8DAwBzblMvlMDQ0VJmIiIiIsvNZJUcAYGNjgxMnTuDp06dZJkgZ1NTU8PPPP2PixIlITEws4iiJiIjoS/XZJUcAYG1tjZCQEDx//hxeXl7ZDqLu0qUL1NXVsWTJkiKOkIiIiL5Un+2IZCsrK4SEhMDT0xNeXl4wNzfPVEdDQwNDhw7FrFmzMHjwYOjp6eW6/ejbB3mKjYiIiDKRCSFEcQdRlOLi4mBkZITY2FgmR0RERCVEUX5/f5an1YiIiIiKC5MjIiIiIiVMjoiIiIiUMDkiIiIiUsLkiIiIiEgJkyMiIiIiJUyOiIiIiJQwOSIiIiJSwuSIiIiISEmhPD5k+fLlGDt2LF69egUNjferSEhIgImJCdzc3BASEiLVzXhEyN27d5GQkIBJkybh3LlziIuLg0KhQL169bBo0SIsXboUU6dOzXG9ebnZd6SrLQzUSm5uWPH+i+IOgYiI6ItUKNmBp6cnEhIScOnSJans1KlTUCgUOH/+PN69eyeVHz9+HBUqVIChoSGaNWuGMmXK4ODBgwgPD0dQUBAsLCzw5s0bjBkzBtHR0dJkZWWFadOmqZQRERERfapCOXLk5OQEc3NzhISEoH79+gDeHyFq3749jh07hnPnzsHDw0Mq9/T0RGhoKGJjY7Fq1SrpaJOdnR08PT2ldvX19aX/q6urw8DAAAqFojC6QERERKVUoZ1X8vT0xPHjx6XXx48fh4eHB9zd3aXyxMREnD9/Hp6enlAoFEhNTcWOHTvydHqMiIiIqCAVanIUGhqK1NRUxMfH48qVK3B3d0eTJk2kMUdnz55FUlISPD09Ub9+ffz888/47rvvULZsWbRq1QqzZ8/Gs2fPPimOpKQkxMXFqUxERERE2SmU02oA4OHhgTdv3uDixYt49eoVHB0dYWZmBnd3d/Tp0wfv3r1DSEgIKlasiAoVKgAAfvvtN4waNQrHjh3D+fPnsXz5ckyfPh0nT56Ei4tLvuIICAjIciB3wyQnyNQKrfuFKuHxqeIOgYiI6ItVaEeOKlWqBCsrKxw/fhzHjx+Hu7s7AMDCwgLW1tY4c+YMjh8/jqZNm6osZ2pqii5duuD3339HeHg4LCws8Pvvv+c7Dj8/P8TGxkrTw4cPP6lfRERE9GUr1EMnnp6eCAkJwatXrzB27FipvEmTJti/fz8uXLiAwYMHZ7u8lpYW7O3t8ebNm3zHIJfLIZfL8708ERERlS6FnhwNGTIEKSkp0pEjAHB3d8fQoUORnJwsXY22d+9ebNy4Ed27d4ejoyOEENizZw/27duHoKCgwgyTiIiISFLoyVFiYiIqV66M8uXLS+Xu7u6Ij4+XLvkHgCpVqkBXVxejR4/Gw4cPIZfL4eDggFWrVqFXr16FGSYRERGRRCZK2XXzcXFxMDIyQmxsLAwNDYs7HCIiIsqFovz+LrnPzyAiIiIqBEyOiIiIiJQwOSIiIiJSwuSIiIiISAmTIyIiIiIlTI6IiIiIlDA5IiIiIlLC5IiIiIhICZMjIiIiIiWF+viQz1mkqy0M1D7/3LDi/RfFHQIREVGpUmjZgYeHB0aOHJmpPDg4GMbGxgCAKVOmQCaT4fvvv1epExYWBplMhqioKABAVFQUZDIZwsLCcr0eIiIiovwo9kMn2traCAwMRERERHGHQkRERFT8yZGTkxM8PT0xYcKE4g6FiIiI6PMYczRjxgx89dVXuHTpEurUqVOgbSclJSEpKUl6HRcXV6DtExER0Zfls0iOatWqha5du2LcuHE4evRotvUaNmwItQ8GUScmJqJGjRrZLhMQEICpU6dmbivJCTK1z6L72Up4fKq4QyAiIip1Ppvs4Ndff4WzszMOHTqEcuXKZVln06ZNcHZ2Vinz9vbOsV0/Pz+MGjVKeh0XFwdra+tPD5iIiIi+SIWWHBkaGiI2NjZT+evXr2FkZJSp3N7eHgMGDMD48eMRGBiYZZvW1taoVKmSSpmOjk6Occjlcsjl8jxETkRERKVZoQ3IdnJywuXLlzOVX758GY6OjlkuM3nyZNy5cwcbN24srLCIiIiIclRoydHgwYNx584dDB8+HNeuXcPt27cxd+5cbNiwAaNHj85ymfLly2PUqFFYuHBhYYVFRERElKNCO61WsWJFnDx5EhMmTEDz5s2RnJyMypUrY8uWLWjZsmW2y40ZMwbLli3Du3fvCis0AED07YMwNDQs1HUQERFRySMTQojiDqIoxcXFwcjICLGxsUyOiIiISoii/P4u9ptAEhEREX1OmBwRERERKWFyRERERKSEyRERERGREiZHREREREqYHBEREREpYXJEREREpITJEREREZESJkdERERESgrt8SGfu0hXWxiofb65YcX7L4o7BCIiolKpQLIDX19fyGQyzJgxQ6V8586dkMlkAICQkBDIZLJM08SJE1Xmv379Ost1dOvWDXXr1kVaWppUlpKSgtq1a8Pb27sgukFERERUcKfVtLW1MXPmTLx69SrHerdv30Z0dLQ0jR8/PlftL126FP/++69KAvbLL78gOjoaixcv/qTYiYiIiDIU2Gm15s2b4+7duwgICMCsWbOyrVeuXDkYGxvnuX1TU1P873//Q5cuXdCuXTskJycjICAAu3btgomJySdETkRERPR/Ciw5UldXx/Tp0/Hdd99h+PDhsLKyKqimJd988w26d++O3r17IyUlBT4+PmjdunWOyyQlJSEpKUl6HRcXV+BxERER0ZejQAdkd+zYETVq1IC/vz8CAwOzrPNh0vTgwQOYmprmeh3z58+HpaUlDA0NMXfu3I/WDwgIwNSpUzOVN0xygkztMx6PbtkYCY9PFXcUREREpU6BX641c+ZMrFmzBuHh4VnOP3XqFMLCwqQpr6fENmzYAJlMhhcvXuDWrVsfre/n54fY2FhpevjwYZ7WR0RERKVLgR86adKkCby8vODn5wdfX99M8+3s7PI15ggA7t+/j59++gnLli3D8ePH4evriytXrkAul2e7jFwuz3E+ERERkbJCudHPjBkzsGfPHpw9e7bA2kxPT4evry+aNWuG3r17Y/78+YiPj8fkyZMLbB1EREREhTLoxsXFBd7e3li4cGGel71+/ToMDAyk1zKZDNWrV8eCBQtw48YN3LhxAwBgZGSEVatWoW3btujcuTPq1q1bYPETERFR6VVoI5KnTZuGTZs25Xm5Jk2aqLxWV1fHzZs3MWHCBKxatQoKhUKa5+XlhT59+uTq9NqHom8fhKGhYZ7jIyIioi+bTAghijuIohQXFwcjIyPExsYyOSIiIiohivL7+/N9uBgRERFRMWByRERERKSEyRERERGREiZHREREREqYHBEREREpYXJEREREpITJ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YDkIDg6GsbFxcYchiYqKgkwmQ1hYWHGHQvTFYnJEVIhatmyJ6OholcnOzi5TveTk5EKLQUtLCwqFAjKZrNDWkVv37t1D06ZNYWVllW3CYWZmBl1d3aINjIhICZMjokIkl8uhUChUJnV1dXh4eGDo0KEYOXIkypYtCy8vLwDA3Llz4eLiAj09PVhbW+OHH35AQkKCSpuhoaHw8PCArq4uTExM4OXlhVevXsHX1xcnTpzAggULpKNUUVFRWZ5W27ZtG6pWrQq5XA5bW1vMmTNHZR22traYPn06+vbtCwMDA1SoUAH/+9//cuxrUlIShg8fjnLlykFbWxuNGjXCxYsXAfzf0Y6YmBj07dsXMpks2yNHH55Wk8lkWLVqFTp27AhdXV04ODhg9+7dAN4/EdzKygrLli1TaePKlStQU1PDgwcPAACvX79G//79YWZmBkNDQzRt2hRXr16V6l+9ehWenp4wMDCAoaEhateujUuXLiEkJAR9+vRBbGystE2nTJkixfnrr7+id+/e0NfXh42NDXbv3o3//vsP7du3h76+PlxdXXHp0iWV2E6fPo3GjRtDR0cH1tbWGD58ON68eZPrbZ+RXNesWRMymQweHh5ZbsdXr17B29sbZmZm0NHRgYODA4KCggBkfao1LCxM2meA/ztitnfvXjg5OUFXVxfffvst3r59izVr1sDW1hYmJiYYPnw40tLSsoyBqMQq1ie7EX3BfHx8RPv27bOc5+7uLvT19cXYsWPFrVu3xK1bt4QQQsybN08cO3ZMREZGiqNHjwonJycxePBgabkrV64IuVwuBg8eLMLCwsQ///wjFi1aJP777z/x+vVr0aBBAzFgwADpydepqani+PHjAoB49eqVEEKIS5cuCTU1NTFt2jRx+/ZtERQUJHR0dERQUJC0HhsbG1GmTBmxZMkSERERIQICAoSampoUZ1aGDx8uLCwsxL59+8SNGzeEj4+PMDExETExMSI1NVVER0cLQ0NDMX/+fBEdHS3evn2bZTs2NjZi3rx50msAwsrKSqxfv15ERESI4cOHC319fRETEyOEEGLMmDGiUaNGKm2MHj1apax58+aiXbt24uLFi+LOnTti9OjRwtTUVGqjatWqomfPniI8PFzcuXNHbN68WYSFhYmkpCQxf/58YWhomOlp4hnbaPny5eLOnTti8ODBwtDQULRs2VJs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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# remove budget constraint\n", "m.remove(budget_constr)\n", "# add new budget constraint without costs\n", "m.addConstr(x.sum() == 1, name=\"Budget_Constraint\")\n", "m.params.OutputFlag = 0\n", "m.optimize()\n", "\n", "# retrieve and display solution data\n", "positions_no_costs = pd.Series(name=\"Position\", data=x.X, index=mu.index)\n", "mask = (positions > 1e-5) | (positions_no_costs > 1e-5)\n", "df = pd.DataFrame(\n", " index=positions[mask].index,\n", " data={\n", " \"with transaction costs\": positions,\n", " \"without transaction costs\": positions_no_costs,\n", " },\n", ").sort_values(\"with transaction costs\", ascending=True)\n", "\n", "axs = df.plot.barh(color=[\"#0b1a3c\", \"#dd2113\"])\n", "axs.set_xlabel(\"Fraction of investment sum\")\n", "plt.title(\"Minimum Variance portfolios with and without transaction costs\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "0c68ad3f", "metadata": {}, "source": [ "## Takeaways\n", "* Transaction costs and fees can be incorporated into the basic budget constraint.\n", "* Fixed costs are independent of the traded amount and can be modeled using binary decision variables.\n", "* Variable fees are proportional to the traded amount and can be modeled using continuous decision variables." ] } ], "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.11.11" } }, "nbformat": 4, "nbformat_minor": 5 }