Filter Content By
Version
Text Search
portfolio.py
#!/usr/bin/python # Copyright 2016, Gurobi Optimization, Inc. # 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, 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. from gurobipy import * from math import sqrt import pandas as pd import numpy as np import matplotlib.pyplot as plt # Import (normalized) historical return data using pandas data = pd.DataFrame.from_csv('../data/portfolio.csv') stocks = data.columns # Calculate basic summary statistics for individual stocks stock_volatility = data.std() stock_return = data.mean() # Create an empty model m = 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.show()