{ "cells": [ { "cell_type": "markdown", "id": "39917d70", "metadata": {}, "source": [ "# Buying Round Lots\n", "\n", "The *standard mean-variance (Markowitz) portfolio selection model* determines the optimal investments by balancing risk and expected return. In this notebook, we minimize the variance (risk) of the portfolio given that the prescribed level of expected return is attained. Please refer to the [annotated list of references](../literature.rst#portfolio-optimization) for more background information on portfolio optimization.\n", "\n", "Securities on the stock market are often traded in *round lots*. A round lot is a fixed number of units (that typically depends on the financial instrument that is traded). For example, stocks are often traded in multiples of 100 shares. Any smaller quantity of traded securities is called an *odd lot*, which typically induces higher transaction costs, or slower order execution. Also, to avoid small positions, one might want to ensure that a *minimum number of units* is traded if a position is opened.\n", "\n", "In this notebook, we add the following constraints to the basic model:\n", "\n", "* If a position is opened, it must comprise a minimum number of shares and,\n", "* stocks can only be bought in round lots.\n", "\n", "For our example, we will be using a lower bound of 1000 shares per asset and a uniform lot size of 100 shares.\n", "\n", "We also include a risk-free asset in the model." ] }, { "cell_type": "code", "execution_count": 1, "id": "f73cf4f8", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:10.765354Z", "iopub.status.busy": "2025-01-31T10:06:10.765097Z", "iopub.status.idle": "2025-01-31T10:06:11.552517Z", "shell.execute_reply": "2025-01-31T10:06:11.551741Z" }, "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", "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": "0a890d90", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:11.554776Z", "iopub.status.busy": "2025-01-31T10:06:11.554554Z", "iopub.status.idle": "2025-01-31T10:06:12.197142Z", "shell.execute_reply": "2025-01-31T10:06:12.196454Z" } }, "outputs": [], "source": [ "import gurobipy as gp\n", "import gurobipy_pandas as gppd\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 3, "id": "48d33278", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.199468Z", "iopub.status.busy": "2025-01-31T10:06:12.199041Z", "iopub.status.idle": "2025-01-31T10:06:12.207562Z", "shell.execute_reply": "2025-01-31T10:06:12.206993Z" }, "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": "c0e249a4", "metadata": {}, "source": [ "## Input Data\n", "\n", "The following input data is used within the model:\n", "\n", "- $S$: set of stocks\n", "- $p_i$: last price of stock $i$ in USD\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": "d6ef0daa", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.209398Z", "iopub.status.busy": "2025-01-31T10:06:12.209221Z", "iopub.status.idle": "2025-01-31T10:06:12.213935Z", "shell.execute_reply": "2025-01-31T10:06:12.213370Z" } }, "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": "1b56be8e", "metadata": {}, "source": [ "We also import the prices of the assets:" ] }, { "cell_type": "code", "execution_count": 5, "id": "4a3173ce", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.215775Z", "iopub.status.busy": "2025-01-31T10:06:12.215585Z", "iopub.status.idle": "2025-01-31T10:06:12.221052Z", "shell.execute_reply": "2025-01-31T10:06:12.220483Z" } }, "outputs": [], "source": [ "# Import price data\n", "prices = pd.read_pickle(\"subset_weekly_closings_10yrs.pkl\").tail(1).squeeze()\n", "data = pd.DataFrame(data={\"Price\": prices})" ] }, { "cell_type": "markdown", "id": "5e90a0cb", "metadata": {}, "source": [ "## Formulation\n", "The model minimizes the variance of the portfolio given that the minimum level of expected return is attained. Also\n", "* shares can only be bought in multiples of a lot size $l$, and\n", "* if a position in an asset is bought, it must comprise at least $L$ lots (and hence at least $L\\cdot l$ shares).\n", "\n", "Mathematically, this results in a convex quadratic mixed-integer optimization problem.\n", "\n", "### Model Parameters\n", "\n", "We use the following parameters:\n", "\n", "- $\\bar\\mu$: required expected portfolio return\n", "- $\\mu_\\text{rf}$: risk-free return\n", "- $T$: total investment amount in USD (AUM)\n", "- $L$: minimal number of lots per asset\n", "- $l$: lot size" ] }, { "cell_type": "code", "execution_count": 6, "id": "3d18be8e", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.222959Z", "iopub.status.busy": "2025-01-31T10:06:12.222778Z", "iopub.status.idle": "2025-01-31T10:06:12.225684Z", "shell.execute_reply": "2025-01-31T10:06:12.225270Z" } }, "outputs": [], "source": [ "# Values for the model parameters:\n", "r = 0.25 # Required return\n", "mu_rf = 0.5 / 52 # Risk-free return rate\n", "T = 1e7 # total investment amount\n", "L = 10 # minimal number of lots\n", "l = 100 # lot size" ] }, { "cell_type": "markdown", "id": "85552527", "metadata": {}, "source": [ "### Decision Variables\n", "We need three types 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. The proportion of capital invested into the risk-free asset is denoted by $x_\\text{rf}$.\n", "\n", "3. The *number of lots* of shares bought of the considered stocks. The corresponding vector is denoted by $z$ with its component $z_i$ denoting the number of lots in stock $i$. Note that the number of shares in asset $i$ is then $lz_i$.\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, x_\\text{rf}\\leq 1 \\; , \\; i \\in S$$\n", "\n", "The $z_i$ must be integers. To enforce the minimal number $L$ of lots if an asset is bought, we will declare those variables *semi-integer*. That is,\n", "\n", "$$z_i \\in \\mathbb Z\\ \\text{and}\\ z_i=0\\ \\text{or}\\ 0< L \\leq z_i \\;, \\; i \\in S$$\n", "\n", "\n", "We will model this using the [gurobipy-pandas](https://github.com/Gurobi/gurobipy-pandas) package. Using this, we first create an extended DataFrame containing the decision variables." ] }, { "cell_type": "code", "execution_count": 7, "id": "996a9dc0", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.227446Z", "iopub.status.busy": "2025-01-31T10:06:12.227248Z", "iopub.status.idle": "2025-01-31T10:06:12.250270Z", "shell.execute_reply": "2025-01-31T10:06:12.249838Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Pricexz
APTV79.150002<gurobi.Var x[APTV]><gurobi.Var z[APTV]>
DVN44.290001<gurobi.Var x[DVN]><gurobi.Var z[DVN]>
HSY194.528000<gurobi.Var x[HSY]><gurobi.Var z[HSY]>
CAG28.020000<gurobi.Var x[CAG]><gurobi.Var z[CAG]>
HST16.980000<gurobi.Var x[HST]><gurobi.Var z[HST]>
............
AEE76.779999<gurobi.Var x[AEE]><gurobi.Var z[AEE]>
AAPL187.440002<gurobi.Var x[AAPL]><gurobi.Var z[AAPL]>
AIZ159.820007<gurobi.Var x[AIZ]><gurobi.Var z[AIZ]>
UNP215.690002<gurobi.Var x[UNP]><gurobi.Var z[UNP]>
K52.200001<gurobi.Var x[K]><gurobi.Var z[K]>
\n", "

462 rows × 3 columns

\n", "
" ], "text/plain": [ " Price x z\n", "APTV 79.150002 \n", "DVN 44.290001 \n", "HSY 194.528000 \n", "CAG 28.020000 \n", "HST 16.980000 \n", "... ... ... ...\n", "AEE 76.779999 \n", "AAPL 187.440002 \n", "AIZ 159.820007 \n", "UNP 215.690002 \n", "K 52.200001 \n", "\n", "[462 rows x 3 columns]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create an empty optimization model\n", "m = gp.Model()\n", "\n", "# Add variable: xrf denotes the proportion of risk-free asset\n", "xrf = m.addVar(lb=0, ub=1, name=\"x_rf\")\n", "\n", "# Add variables\n", "df_model = (\n", " # x[i] denotes the proportion invested in stock i\n", " data.gppd.add_vars(m, name=\"x\", ub=1)\n", " # z[i] denotes the number of lots of stock i. Must be integer and greater or equal to L or zero.\n", " # Defining the variable as semi-integer is enough to enforce the buy-in threshold requirement.\n", " .gppd.add_vars(m, name=\"z\", vtype=gp.GRB.SEMIINT, lb=L)\n", ")\n", "\n", "# Inspect the created DataFrame:\n", "m.update()\n", "df_model" ] }, { "cell_type": "markdown", "id": "ffeac2f7", "metadata": {}, "source": [ "### Constraints\n", "The budget constraint ensures that the entire capital is invested:\n", "\n", "$$\\sum_{i \\in S} x_i + x_\\text{rf} =1 $$\n", "\n", "The expected return of the portfolio must be at least $\\bar\\mu$:\n", "\n", "$$\\underbrace{\\mu_\\text{rf} x_\\text{rf}}_\\text{risk-free return} + \\underbrace{\\mu^\\top x}_\\text{risky return}\\geq \\bar\\mu$$" ] }, { "cell_type": "code", "execution_count": 8, "id": "01bb5385", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.252224Z", "iopub.status.busy": "2025-01-31T10:06:12.252025Z", "iopub.status.idle": "2025-01-31T10:06:12.260955Z", "shell.execute_reply": "2025-01-31T10:06:12.260363Z" } }, "outputs": [], "source": [ "%%capture\n", "# Budget constraint: all investments sum up to 1\n", "m.addConstr(df_model[\"x\"].sum() + xrf == 1, name=\"Budget_Constraint\")\n", "\n", "# Lower bound on expected return\n", "m.addConstr(mu.to_numpy() @ df_model[\"x\"] + mu_rf * xrf >= r, \"Minimal_Return\")" ] }, { "cell_type": "markdown", "id": "3865d42f", "metadata": {}, "source": [ "#### Round lots\n", "\n", "The relative position $x_i$ in stock $i$ and the number of round lots $z_i$ are related via the price $p_i$ as follows:\n", "\n", "$$\n", "x_i = \\frac{l z_i p_i}{T} \\; , \\; i \\in S\n", "$$" ] }, { "cell_type": "code", "execution_count": 9, "id": "01b570a5", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.262752Z", "iopub.status.busy": "2025-01-31T10:06:12.262582Z", "iopub.status.idle": "2025-01-31T10:06:12.275694Z", "shell.execute_reply": "2025-01-31T10:06:12.275081Z" } }, "outputs": [], "source": [ "%%capture\n", "gppd.add_constrs(\n", " m,\n", " df_model[\"x\"] - l / T * df_model[\"Price\"] * df_model[\"z\"],\n", " \"=\",\n", " 0,\n", " name=\"match_round_lots\",\n", ")" ] }, { "cell_type": "markdown", "id": "cfc5e516", "metadata": {}, "source": [ "### Objective Function\n", "The objective is to minimize the risk of the portfolio, which is measured by its variance:\n", "\n", "$$\\min_x x^\\top \\Sigma x$$" ] }, { "cell_type": "code", "execution_count": 10, "id": "c7d03c2e", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.277494Z", "iopub.status.busy": "2025-01-31T10:06:12.277322Z", "iopub.status.idle": "2025-01-31T10:06:12.990269Z", "shell.execute_reply": "2025-01-31T10:06:12.989587Z" } }, "outputs": [], "source": [ "# Define objective function: Minimize risk\n", "m.setObjective(df_model[\"x\"] @ Sigma.to_numpy() @ df_model[\"x\"], gp.GRB.MINIMIZE)" ] }, { "cell_type": "markdown", "id": "dc70e8ae", "metadata": {}, "source": [ "We now solve the optimization problem:" ] }, { "cell_type": "code", "execution_count": 11, "id": "3572cfad", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:12.992473Z", "iopub.status.busy": "2025-01-31T10:06:12.992293Z", "iopub.status.idle": "2025-01-31T10:06:13.806682Z", "shell.execute_reply": "2025-01-31T10:06:13.805948Z" } }, "outputs": [ { "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 464 rows, 925 columns and 1850 nonzeros\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Model fingerprint: 0x5dd8105c\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Model has 106953 quadratic objective terms\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Variable types: 463 continuous, 0 integer (0 binary)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Semi-Variable types: 0 continuous, 462 integer\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Coefficient statistics:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Matrix range [9e-05, 1e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Objective range [0e+00, 0e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " QObjective range [6e-03, 2e+02]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Bounds range [1e+00, 1e+01]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " RHS range [2e-01, 1e+00]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Presolve time: 0.02s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Presolved: 1388 rows, 1387 columns, 3697 nonzeros\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Presolved model has 106953 quadratic objective terms\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Variable types: 463 continuous, 924 integer (462 binary)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Found heuristic solution: objective 11.4196528\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Root relaxation: objective 1.803654e+00, 161 iterations, 0.01 seconds (0.01 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 1.80365 0 62 11.41965 1.80365 84.2% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 2.6454205 1.80365 31.8% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 2.5624936 1.80365 29.6% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80365 0 62 2.56249 1.80365 29.6% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 1.8235545 1.80365 1.09% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 58 1.82355 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 58 1.82355 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82355 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82355 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81054 0 53 1.82355 1.81054 0.71% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81054 0 53 1.82355 1.81054 0.71% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81096 0 51 1.82355 1.81096 0.69% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81194 0 48 1.82355 1.81194 0.64% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81734 0 42 1.82355 1.81734 0.34% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81846 0 40 1.82355 1.81846 0.28% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81846 0 40 1.82355 1.81846 0.28% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81846 0 39 1.82355 1.81846 0.28% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81846 0 39 1.82355 1.81846 0.28% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81846 0 39 1.82355 1.81846 0.28% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81846 0 39 1.82355 1.81846 0.28% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81942 0 37 1.82355 1.81942 0.23% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81942 0 37 1.82355 1.81942 0.23% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81950 0 37 1.82355 1.81950 0.22% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.81950 0 37 1.82355 1.81950 0.22% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 1.8235414 1.81950 0.22% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 1 1.82035 0 37 1.82354 1.82035 0.17% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 26 13 1.8235414 1.82193 0.09% 3.6 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Cutting planes:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " MIR: 2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Flow cover: 1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Explored 99 nodes (948 simplex iterations) in 0.80 seconds (0.49 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 8: 1.82354 1.82355 2.22438 ... 11.4197\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Optimal solution found (tolerance 1.00e-04)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Best objective 1.823541386979e+00, best bound 1.823434168542e+00, gap 0.0059%\n" ] } ], "source": [ "m.optimize()" ] }, { "cell_type": "markdown", "id": "25f122f7", "metadata": {}, "source": [ "Display basic solution data:" ] }, { "cell_type": "code", "execution_count": 12, "id": "fe1d359d", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:13.808689Z", "iopub.status.busy": "2025-01-31T10:06:13.808508Z", "iopub.status.idle": "2025-01-31T10:06:13.824960Z", "shell.execute_reply": "2025-01-31T10:06:13.824328Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Minimum Risk: 1.823541\n", "Expected return: 0.248376\n", "Solution time: 0.81 seconds\n", "\n", "Number of trades: 21\n", "\n", "Risk-free alloc: 0.168930\n", "\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
PositionSharesPrice
LLY0.1530202600.0588.539978
KDP0.07881424800.031.780001
PGR0.0756824800.0157.669998
NVDA0.0488881000.0488.880005
DPZ0.0487161300.0374.739990
NOC0.0463881000.0463.880005
ODFL0.0397791000.0397.790009
TMUS0.0396932700.0147.009995
KR0.0354088300.042.660000
TTWO0.0352822300.0153.399994
WST0.0344231000.0344.230011
WM0.0342342000.0171.169998
ED0.0280553100.090.500000
MKTX0.0226701000.0226.699997
WMT0.0218461400.0156.039993
CLX0.0218451600.0136.529999
CME0.0211061000.0211.059998
HRL0.0160034900.032.660000
MNST0.0143262600.055.099998
XEL0.0084131400.060.090000
CPB0.0064801600.040.500000
\n", "
" ], "text/plain": [ " Position Shares Price\n", "LLY 0.153020 2600.0 588.539978\n", "KDP 0.078814 24800.0 31.780001\n", "PGR 0.075682 4800.0 157.669998\n", "NVDA 0.048888 1000.0 488.880005\n", "DPZ 0.048716 1300.0 374.739990\n", "NOC 0.046388 1000.0 463.880005\n", "ODFL 0.039779 1000.0 397.790009\n", "TMUS 0.039693 2700.0 147.009995\n", "KR 0.035408 8300.0 42.660000\n", "TTWO 0.035282 2300.0 153.399994\n", "WST 0.034423 1000.0 344.230011\n", "WM 0.034234 2000.0 171.169998\n", "ED 0.028055 3100.0 90.500000\n", "MKTX 0.022670 1000.0 226.699997\n", "WMT 0.021846 1400.0 156.039993\n", "CLX 0.021845 1600.0 136.529999\n", "CME 0.021106 1000.0 211.059998\n", "HRL 0.016003 4900.0 32.660000\n", "MNST 0.014326 2600.0 55.099998\n", "XEL 0.008413 1400.0 60.090000\n", "CPB 0.006480 1600.0 40.500000" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(f\"Minimum Risk: {m.ObjVal:.6f}\")\n", "print(f\"Expected return: {mu @ df_model['x'].gppd.X:.6f}\")\n", "print(f\"Solution time: {m.Runtime:.2f} seconds\\n\")\n", "\n", "# Print investments (with non-negligible value, i.e. >= 1 share)\n", "data[\"Position\"] = pd.concat(\n", " [df_model[\"x\"].gppd.X, pd.Series([xrf.X], index=[\"risk-free\"])]\n", ")\n", "data[\"Shares\"] = df_model[\"z\"].gppd.X * l\n", "\n", "print(f\"Number of trades: {data[data['Shares'] >= 1]['Shares'].count()}\\n\")\n", "print(f\"Risk-free alloc: {xrf.X:.6f}\\n\")\n", "\n", "data[data[\"Shares\"] >= 1].sort_values(\"Position\", ascending=False)[\n", " [\"Position\", \"Shares\", \"Price\"]\n", "]" ] }, { "cell_type": "markdown", "id": "22d27fb0", "metadata": {}, "source": [ "## Comparison with the unconstrained portfolio\n", "\n", "We can also compute and compare the portfolio without the minimum buy-in and lot constraints by changing the variable type and bounds of $z$." ] }, { "cell_type": "code", "execution_count": 13, "id": "827e0bf8", "metadata": { "execution": { "iopub.execute_input": "2025-01-31T10:06:13.826904Z", "iopub.status.busy": "2025-01-31T10:06:13.826711Z", "iopub.status.idle": "2025-01-31T10:06:14.292439Z", "shell.execute_reply": "2025-01-31T10:06:14.291695Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "x_lots = pd.concat([data[\"Position\"], pd.Series([xrf.X], index=[\"risk-free\"])])\n", "\n", "# change type of z from semi-integer to continuous and lower bound to 0\n", "df_model[\"z\"].gppd.set_attr(\"vtype\", gp.GRB.CONTINUOUS)\n", "df_model[\"z\"].gppd.set_attr(\"lb\", 0)\n", "\n", "m.params.OutputFlag = 0\n", "m.optimize()\n", "\n", "x_unconstr = pd.concat([df_model[\"x\"].gppd.X, pd.Series([xrf.X], index=[\"risk-free\"])])\n", "\n", "# retrieve and display solution data\n", "mask = (x_lots > 1e-5) | (x_unconstr > 1e-5)\n", "df_data = pd.DataFrame(\n", " index=x_lots[mask].index,\n", " data={\n", " \"round lots\": x_lots[mask],\n", " \"unconstrained\": x_unconstr[mask],\n", " },\n", ").sort_values(by=[\"round lots\", \"unconstrained\"], ascending=True)\n", "\n", "axs = df_data.plot.barh(color=[\"#0b1a3c\", \"#dd2113\"])\n", "axs.set_xlabel(\"Fraction of investment sum\")\n", "plt.title(\"Minimum Variance portfolios with and without enforcing round lots\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "f82b507b", "metadata": {}, "source": [ "## Takeaways\n", "\n", "* Data from pandas DataFrames can easily be used to build an optimization model via the `gurobipy-pandas` package.\n", "* To enforce buying round lots of shares, one needs to incorporate the asset price and the total investment amount into the model.\n", "* Minimum buy-in and round lot constraints can be modeled using semi-integer variables. Semi-integer variables are integer decision variables that may either take the value 0 or a value between specified bounds. They are a convenient tool to guarantee a minimum position size if an asset is bought." ] } ], "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 }