Try our new documentation site (beta).
Filter Content By
Version
Text Search
${sidebar_list_label} - Back
Filter by Language
portfolio.py
#!/usr/bin/env python3.7 # Copyright 2020, Gurobi Optimization, LLC # Portfolio selection: given a sum of money to invest, one must decide how to # spend it amongst a portfolio of financial securities. Our approach is due # to Markowitz (1959) and looks to minimize the risk associated with the # investment while realizing a target expected return. By varying the target, # one can compute an 'efficient frontier', which defines the optimal portfolio # for a given expected return. # # Note that this example reads historical return data from a comma-separated # file (../data/portfolio.csv). As a result, it must be run from the Gurobi # examples/python directory. # # This example requires the pandas (>= 0.20.3), NumPy, and Matplotlib # Python packages, which are part of the SciPy ecosystem for # mathematics, science, and engineering (http://scipy.org). These # packages aren't included in all Python distributions, but are # included by default with Anaconda Python. import gurobipy as gp from gurobipy import GRB from math import sqrt import pandas as pd import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # Import (normalized) historical return data using pandas data = pd.read_csv('../data/portfolio.csv', index_col=0) stocks = data.columns # Calculate basic summary statistics for individual stocks stock_volatility = data.std() stock_return = data.mean() # Create an empty model m = gp.Model('portfolio') # Add a variable for each stock vars = pd.Series(m.addVars(stocks), index=stocks) # Objective is to minimize risk (squared). This is modeled using the # covariance matrix, which measures the historical correlation between stocks. sigma = data.cov() portfolio_risk = sigma.dot(vars).dot(vars) m.setObjective(portfolio_risk, GRB.MINIMIZE) # Fix budget with a constraint m.addConstr(vars.sum() == 1, 'budget') # Optimize model to find the minimum risk portfolio m.setParam('OutputFlag', 0) m.optimize() # Create an expression representing the expected return for the portfolio portfolio_return = stock_return.dot(vars) # Display minimum risk portfolio print('Minimum Risk Portfolio:\n') for v in vars: if v.x > 0: print('\t%s\t: %g' % (v.varname, v.x)) minrisk_volatility = sqrt(portfolio_risk.getValue()) print('\nVolatility = %g' % minrisk_volatility) minrisk_return = portfolio_return.getValue() print('Expected Return = %g' % minrisk_return) # Add (redundant) target return constraint target = m.addConstr(portfolio_return == minrisk_return, 'target') # Solve for efficient frontier by varying target return frontier = pd.Series() for r in np.linspace(stock_return.min(), stock_return.max(), 100): target.rhs = r m.optimize() frontier.loc[sqrt(portfolio_risk.getValue())] = r # Plot volatility versus expected return for individual stocks ax = plt.gca() ax.scatter(x=stock_volatility, y=stock_return, color='Blue', label='Individual Stocks') for i, stock in enumerate(stocks): ax.annotate(stock, (stock_volatility[i], stock_return[i])) # Plot volatility versus expected return for minimum risk portfolio ax.scatter(x=minrisk_volatility, y=minrisk_return, color='DarkGreen') ax.annotate('Minimum\nRisk\nPortfolio', (minrisk_volatility, minrisk_return), horizontalalignment='right') # Plot efficient frontier frontier.plot(color='DarkGreen', label='Efficient Frontier', ax=ax) # Format and display the final plot ax.axis([0.005, 0.06, -0.02, 0.025]) ax.set_xlabel('Volatility (standard deviation)') ax.set_ylabel('Expected Return') ax.legend() ax.grid() plt.savefig('portfolio.png') print("Plotted efficient frontier to 'portfolio.png'")