{ "cells": [ { "cell_type": "markdown", "id": "9f566aff", "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": "58e955d9", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:42.503898Z", "iopub.status.busy": "2026-07-03T11:05:42.503710Z", "iopub.status.idle": "2026-07-03T11:05:43.118363Z", "shell.execute_reply": "2026-07-03T11:05:43.117236Z" }, "nbsphinx": "hidden" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: numpy in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (2.4.6)\r\n", "Requirement already satisfied: scipy in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (1.17.1)\r\n", "Requirement already satisfied: gurobipy in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (13.0.2)\r\n", "Requirement already satisfied: pandas in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (3.0.3)\r\n", "Requirement already satisfied: matplotlib in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (3.11.0)\r\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from pandas) (2.9.0.post0)\r\n", "Requirement already satisfied: contourpy>=1.0.1 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from matplotlib) (1.3.3)\r\n", "Requirement already satisfied: cycler>=0.10 in /opt/hostedtoolcache/Python/3.11.15/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.15/x64/lib/python3.11/site-packages (from matplotlib) (4.63.0)\r\n", "Requirement already satisfied: kiwisolver>=1.3.1 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from matplotlib) (1.5.0)\r\n", "Requirement already satisfied: packaging>=20.0 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from matplotlib) (26.2)\r\n", "Requirement already satisfied: pillow>=9 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from matplotlib) (12.3.0)\r\n", "Requirement already satisfied: pyparsing>=3 in /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages (from matplotlib) (3.3.2)\r\n", "Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.11.15/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": "57c5cc4e", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.120307Z", "iopub.status.busy": "2026-07-03T11:05:43.120096Z", "iopub.status.idle": "2026-07-03T11:05:43.783079Z", "shell.execute_reply": "2026-07-03T11:05:43.782217Z" } }, "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": "1c18972f", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.785115Z", "iopub.status.busy": "2026-07-03T11:05:43.784819Z", "iopub.status.idle": "2026-07-03T11:05:43.794896Z", "shell.execute_reply": "2026-07-03T11:05:43.793951Z" }, "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": "07383aa2", "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": "4acc1190", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.796676Z", "iopub.status.busy": "2026-07-03T11:05:43.796518Z", "iopub.status.idle": "2026-07-03T11:05:43.802110Z", "shell.execute_reply": "2026-07-03T11:05:43.800938Z" } }, "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": "33a932a0", "metadata": {}, "source": [ "We also import the prices of the assets:" ] }, { "cell_type": "code", "execution_count": 5, "id": "beeebc24", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.803857Z", "iopub.status.busy": "2026-07-03T11:05:43.803674Z", "iopub.status.idle": "2026-07-03T11:05:43.813221Z", "shell.execute_reply": "2026-07-03T11:05:43.812492Z" } }, "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": "0fa6695a", "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": "b486263b", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.815346Z", "iopub.status.busy": "2026-07-03T11:05:43.815157Z", "iopub.status.idle": "2026-07-03T11:05:43.818957Z", "shell.execute_reply": "2026-07-03T11:05:43.817793Z" } }, "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": "a12a4b0f", "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": "3abfe970", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.820631Z", "iopub.status.busy": "2026-07-03T11:05:43.820454Z", "iopub.status.idle": "2026-07-03T11:05:43.840663Z", "shell.execute_reply": "2026-07-03T11:05:43.839724Z" } }, "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": "f27c4b3e", "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": "e5186526", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.842647Z", "iopub.status.busy": "2026-07-03T11:05:43.842443Z", "iopub.status.idle": "2026-07-03T11:05:43.850494Z", "shell.execute_reply": "2026-07-03T11:05:43.849503Z" } }, "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": "db766b08", "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": "9cb3a315", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.852575Z", "iopub.status.busy": "2026-07-03T11:05:43.852383Z", "iopub.status.idle": "2026-07-03T11:05:43.864350Z", "shell.execute_reply": "2026-07-03T11:05:43.863303Z" } }, "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": "63bda8ba", "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": "8e3e3ba8", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:43.866432Z", "iopub.status.busy": "2026-07-03T11:05:43.866238Z", "iopub.status.idle": "2026-07-03T11:05:44.466748Z", "shell.execute_reply": "2026-07-03T11:05:44.465792Z" } }, "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": "2fcd15d8", "metadata": {}, "source": [ "We now solve the optimization problem:" ] }, { "cell_type": "code", "execution_count": 11, "id": "3120fd63", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:44.469232Z", "iopub.status.busy": "2026-07-03T11:05:44.469048Z", "iopub.status.idle": "2026-07-03T11:05:45.059594Z", "shell.execute_reply": "2026-07-03T11:05:45.058653Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Gurobi Optimizer version 13.0.2 build v13.0.2rc1 (linux64 - \"Ubuntu 24.04.4 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 (Min)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Model fingerprint: 0x5dd8105c\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Model has 0 linear objective coefficients\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": [ "\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.6779857 1.80365 32.6% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 2.6491462 1.80365 31.9% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 2.6455642 1.80365 31.8% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 2.6443389 1.80365 31.8% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 2.0051518 1.80365 10.0% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 1.8416417 1.80365 2.06% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "H 0 0 1.8235582 1.80365 1.09% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80365 0 59 1.82356 1.80365 1.09% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80365 0 59 1.82356 1.80365 1.09% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80365 0 59 1.82356 1.80365 1.09% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82356 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82356 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82356 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82356 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 0 1.80449 0 57 1.82356 1.80449 1.05% - 0s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " 0 2 1.80449 0 57 1.82356 1.80449 1.05% - 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: 3\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Explored 147 nodes (891 simplex iterations) in 0.58 seconds (0.40 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.82356 1.84164 2.00515 ... 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.823558188851e+00, best bound 1.823393521111e+00, gap 0.0090%\n" ] } ], "source": [ "m.optimize()" ] }, { "cell_type": "markdown", "id": "4e5489d5", "metadata": {}, "source": [ "Display basic solution data:" ] }, { "cell_type": "code", "execution_count": 12, "id": "4ed77c24", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:45.061492Z", "iopub.status.busy": "2026-07-03T11:05:45.061299Z", "iopub.status.idle": "2026-07-03T11:05:45.080055Z", "shell.execute_reply": "2026-07-03T11:05:45.079101Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Minimum Risk: 1.823558\n", "Expected return: 0.248349\n", "Solution time: 0.58 seconds\n", "\n", "Number of trades: 20\n", "\n", "Risk-free alloc: 0.171827\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", "
PositionSharesPrice
LLY0.1589062700.0588.539978
KDP0.08040325300.031.780001
PGR0.0788355000.0157.669998
NVDA0.0488881000.0488.880005
DPZ0.0487161300.0374.739990
NOC0.0463881000.0463.880005
TMUS0.0411632800.0147.009995
WM0.0410812400.0171.169998
ODFL0.0397791000.0397.790009
TTWO0.0368162400.0153.399994
WST0.0344231000.0344.230011
KR0.0337017900.042.660000
WMT0.0249661600.0156.039993
ED0.0235302600.090.500000
MKTX0.0226701000.0226.699997
CLX0.0204791500.0136.529999
HRL0.0179635500.032.660000
MNST0.0137752500.055.099998
XEL0.0096141600.060.090000
CPB0.0060751500.040.500000
\n", "
" ], "text/plain": [ " Position Shares Price\n", "LLY 0.158906 2700.0 588.539978\n", "KDP 0.080403 25300.0 31.780001\n", "PGR 0.078835 5000.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", "TMUS 0.041163 2800.0 147.009995\n", "WM 0.041081 2400.0 171.169998\n", "ODFL 0.039779 1000.0 397.790009\n", "TTWO 0.036816 2400.0 153.399994\n", "WST 0.034423 1000.0 344.230011\n", "KR 0.033701 7900.0 42.660000\n", "WMT 0.024966 1600.0 156.039993\n", "ED 0.023530 2600.0 90.500000\n", "MKTX 0.022670 1000.0 226.699997\n", "CLX 0.020479 1500.0 136.529999\n", "HRL 0.017963 5500.0 32.660000\n", "MNST 0.013775 2500.0 55.099998\n", "XEL 0.009614 1600.0 60.090000\n", "CPB 0.006075 1500.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": "da573604", "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": "06505930", "metadata": { "execution": { "iopub.execute_input": "2026-07-03T11:05:45.081887Z", "iopub.status.busy": "2026-07-03T11:05:45.081701Z", "iopub.status.idle": "2026-07-03T11:05:45.581567Z", "shell.execute_reply": "2026-07-03T11:05:45.580737Z" } }, "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": "aea2f285", "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.15" } }, "nbformat": 4, "nbformat_minor": 5 }