Jump to content

Portfolios and linear programming 1

From UBC Wiki

Toy Model

Various stocks with rewards and risks on a scale of 0-3 (0 low risk, 3 high risk) are shown below.

Stock Name Reward Risk
AAA 15% 3
BBB 12% 2
CCC 4% 0.5

Decision Variables

x1=fraction of portfolio invested in AAA

x2=fraction of portfolio invested in BBB

x3=fraction of portfolio invested in CCC

Optimization Function

z=15x1+12x2+4x3

Constraints

3x1+2x2+12x3σ

σ=maximum risk

x2x30 (invest at least one dollar in CCC for every dollar invested in BBB)

x1+x2+x31

x1x2x31

x1,x2,x30

Slack Variables

x4=σ3x12x212x3

x5=x2+x3

x6=1x1x2x3

x7=1+x1+x2+x3

x4,x5,x6,x70

Worked Solution

Letσ=32

x4=323x12x212x3x5=x2+x3x6=1x1x2x3x7=1+x1+x2+x3z=15x1+12x2+4x3


x3x6x3=1x1x2x6x4=152x132x2+12x6x5=1x12x2x6x7=x6z=4+11x1+8x24x6


x2x5x2=1212x112x512x6x3=1212x1+12x512x6x4=1474x1+34x5+54x6x7=x6z=8+7x14x58x6


x1x4x1=1747x4+37x5+57x6x2=37+27x457x567x6x3=37+27x4+27x567x6x7=x6z=94x4x53x6


The optimal solution isx1=17,x2=37,x3=37,with optimal valuez=9and a total risk of32.

Dual Problem

Objective Function

minimizew=σy1+y3y4

Constraints

s.t.3y1+y3y4152y1+y2+y3y41212y1y2+y3y44y1,y2,y3,y40

Slack Variables

y5=15+3y1+y3y4

y6=12+2y1+y2+y3y4

y7=4+12y1y2+y3y4

y5,y6,y70

Worked Solution

Letσ=32

y5=15+3y1+y3y4y6=12+2y1+y2+y3y4y7=4+12y1y2+y3y4w=32y1y3+y4


y3y5y3=153y1+y4+y5y6=3y1+y2+y5y7=1152y1y2+y5w=15+32y1y5


y1y6y1=3+y2+y5y6y3=63y2+y42y5+3y6y7=7272y232y5+52y6w=212+32y2+12y532y6


y2y7y2=137y5+57y627y7y1=4+47y527y627y7y3=3+y457y5+67y6+67y7w=917y537y637y7

i.e.w=9+17y5+37y6+37y7

The optimal solution isy1=4,y2=1,y3=3,y4=0with optimal valuew=9.

Interpretation of Results

In both the primal and the dual the optimal solutions, z and w respectively, are 9. This tells us that using the investment distribution given by the primal we should see a return of 9% on our initial investment.

Now, consider the variables from the optimal solution to the dual problem.

y1: this variable refers to the first constraint. The first constraint puts an upper bound on the amount of total risk we are willing to take on. This means y1 gives the increase in output for an additional unit of risk we're willing to take on. So in this case, increasing the risk we'd take by 1 increases out total return by 4%.

y2: this variable refers to the second constraint. Here, x2x3. Lets consider what happens if you loosen the constraint by 0.1. In this case the increase in return would go up by 0.1%.

y3 and y4: these variables correspond with the constraints derived from x1+x2+x3=1. These would be the changes in return percentage based on borrowing additional money; however, borrowing is outside the scope of this toy problem so we will not discuss this any further.

Actual Portfolio

We will use these options from TD bank.

Various BMO ETFs with rewards (3 year annualized return), risks on a scale of 1-5 (1 low risk, 5 high risk) and volatility (3 year volatility) are shown below.

Variable Symbol Stock Name Reward Risk Volatility
x1 ZXB BMO 2015 Corporate Bond Target Mat ETF -0.23% 3 6.55
x2 ZXC BMO 2020 Corporate Bond Target Mat ETF 2.63% 3 7.81
x3 ZXD BMO 2025 Corporate Bond Target Mat ETF 0.91% 4 7.55
x4 ZAG BMO Aggregate Bond ETF 2.50% 3 9.31
x5 ZDV BMO Canadian Dividend ETF 6.43% 3 9.46
x6 ZCH BMO China Equity ETF 26.73% 3 13.60
x7 ZWB BMO Covered Call Canadian Banks ETF 11.47% 4 12.23
x8 ZWA BMO Covered Call DJIA Hedged to CAD ETF 11.76% 3 11.18
x9 ZDJ BMO Dow Jones Ind Avg Hdgd CAD ETF 13.63% 3 11.96
x10 ZEF BMO Emerging Market Bnd Hdgd to CAD ETF 3.88% 5 10.85
x11 ZRE BMO Equal Weight REITs ETF 1.99% 2 12.10
x12 ZUB BMO Eq Weight US Banks Hdgd to CAD ETF 22.05% 4 15.73
x13 ZGI BMO Global Infrastructure ETF 17.37% 3 10.66
x14 ZHY BMO High Yld US Corp Bd Hdgd to CAD ETF 5.00% 5 8.14
x15 ZJN BMO Junior Gas ETF 9.75% 4 21.80
x16 ZJG BMO Junior Gold ETF -27.79% 5 42.71
x17 ZJO BMO Junior Oil ETF 1.46% 4 22.12
x18 ZLC BMO Long Corporate Bond ETF 2.92% 2 9.72
x19 ZFL BMO Long Federal Bond ETF -0.20% 3 10.59
x20 ZLB BMO Low Volatility Canadian Equity ETF 19.23% 1 8.52
x21 ZCM BMO Mid Corporate Bond ETF 2.67% 5 7.53
x22 ZFM BMO Mid Federal Bond ETF 0.20% 5 7.92
x23 ZMI BMO Monthly Income ETF 4.60% 4 7.96
x24 ZDM BMO MSCI EAFE Hdg to CAD ETF 18.95% 4 10.56
x25 ZEM BMO MSCI Emerging Markets ETF 8.86% 3 10.97
x26 ZQQ BMO NASDAQ 100 Equity Hedged to CAD ETF 20.36% 5 12.61
x27 ZRR BMO Real Return Bond ETF -2.31% 4 11.77
x28 ZUE BMO S&P 500 Hedged to CAD ETF 17.36% 4 11.07
x29 ZCN BMO S&P/TSX Capped Composite ETF 9.92% 3 9.16
x30 ZEB BMO S&P/TSX Equal Weight Banks ETF 13.06% 3 13.34
x31 ZMT BMO S&P/TSX EqWt Glb BM Hdgd to CAD ETF -4.23% 4 20.63
x32 ZEO BMO S&P/TSX Equal Weight Oil&Gas ETF 0.27% 1 16.66
x33 ZCS BMO Short Corporate Bond ETF 0.74% 4 6.44
x34 ZFS BMO Short Federal Bond ETF -0.61% 4 6.41
x35 ZPS BMO Short Provincial Bond ETF 0.08% 5 6.27
x36 ZST BMO Ultra Short-Term Bond ETF -0.97% 3 6.78

LP Problem

maximizez=n=136Yieldnxn

s.t.n=136Rewardnxn10n=136xn=10xn0.15forn=1,2,3,,36

Results

Z = 15.9009

Symbol Percentage Invested
ZXB 0
ZXC 0
ZXD 0
ZAG 0
ZDV 0
ZCH 0.15
ZWB 0
ZWA 0
ZDJ 0
ZEF 0
ZRE 0
ZUB 0
ZGI 0.15
ZHY 0
ZJN 0
ZJG 0
ZJO 0
ZLC 0
ZFL 0
ZLB 0.15
ZCM 0
ZFM 0
ZMI 0
ZDM 0.15
ZEM 0
ZQQ 0
ZRR 0
ZUE 0.15
ZCN 0.0849481
ZEB 0
ZMT 0
ZEO 0
ZCS 0.15
ZFS 0
ZPS 0.0150519
ZST 0

Solver Code

Here is the code to solve the LP program using python.

Operating System: Ubuntu 14.04 LTS This uses a modified version PyGLPK found at https://github.com/bradfordboyle/pyglpk Ran on python version 2.7

Both the code, called solve.py, and the datafile it uses, data.txt are shown below. Note, data.txt must be in the same directory as solve.py.

solve.py

   import glpk
   max_percent_per_stock = 0.15
   max_volatility = 10
   data_filename = 'data.txt'
   the_file = open(data_filename, 'r')
   lines = []
   for line in the_file:
       l = line.strip()
       l = line.split()
       lines.append(l)
   # Drop first line. It's column labels.
   stocks       = lines[1:]
   n            = len(stocks)
   names        = [stock[0] for stock in stocks]
   rewards      = [float(stock[1].replace("%", "")) for stock in stocks]
   risks        = [stock[2] for stock in stocks]
   volatilities = [float(stock[3]) for stock in stocks]
   # Referencing solver code from http://tfinley.net/software/pyglpk/ex_ref.html
   lp              = glpk.LPX()
   lp.name         = '340project'
   lp.obj.maximize = True
   # add rows
   #   1 row for first constraint
   #   1 row for second constraint
   #   n rows for last constraint
   lp.rows.add(n+2)
   for row in lp.rows:
       row.name = 's{0}'.format(row.index)
   # put bounds on constraints
   # constraint 1: 0 \leq x_n \leq 0.15 \text{ for }n=1, 2, ..., n
   for row in lp.rows[:n]:
       # TODO ISSUE: 0 \leq x_n \leq 0.15? Can I use None or should I use 0?
       row.bounds = None, max_percent_per_stock
   # constraint 2: \sum\limits{n=1}_{36} Volatility_n*x_n \leq 10
   lp.rows[n].bounds = None, max_volatility
   # constraint 3: \sum\limits{n=1}_{36} x_n = 1
   lp.rows[n+1].bounds = 1.0, 1.0
   # initial dictionary has n non-basic variables so we need n columns
   lp.cols.add(n)
   for col in lp.cols:
       col.name = '{0}'.format(names[col.index])
       col.bounds = 0, None
   # set the objective function
   lp.obj[:] = rewards
   # build matrix of coeffs. We refer to this as matrix A in class.
   matrix = []
   # constraint 1: 0 \leq x_n \leq 0.15 \text{ for }n=1, 2, ..., n
   for stock_num in xrange(len(stocks)):
       row_of_zeros = [0 for x in xrange(n)]
       row_of_zeros[stock_num] = 1
       matrix += row_of_zeros
   # constraint 2: \sum\limits{n=1}_{36} Volatility_n*x_n \leq 10
   matrix += volatilities
   # constraint 3: \sum\limits{n=1}_{36} x_n = 1
   matrix += [1 for x in xrange(n)]
   lp.matrix = matrix
   lp.simplex()
   print 'Z = %g\n' % lp.obj.value,
   print '{| class="wikitable" style="text-align: center;"'
   print '|-'
   print '! Symbol !! Percentage Invested'
   print '|-'
   print '\n|-\n'.join('| %s || %g' % (c.name, c.primal) for c in lp.cols)
   print '|-'
   print '|}'

data.txt

   Symbol Reward Risk Volatility
   ZXB 	-0.23% 	3 	6.55
   ZXC 	2.63% 	3 	7.81
   ZXD 	0.91% 	4 	7.55
   ZAG 	2.50% 	3 	9.31
   ZDV 	6.43% 	3 	9.46
   ZCH 	26.73% 	3 	13.60
   ZWB 	11.47% 	4 	12.23
   ZWA 	11.76% 	3 	11.18
   ZDJ 	13.63% 	3 	11.96
   ZEF 	3.88% 	5 	10.85
   ZRE 	1.99% 	2 	12.10
   ZUB 	22.05% 	4 	15.73
   ZGI 	17.37% 	3 	10.66
   ZHY 	5.00% 	5 	8.14
   ZJN 	9.75% 	4 	21.80
   ZJG 	-27.79% 5 	42.71
   ZJO 	1.46% 	4 	22.12
   ZLC 	2.92% 	2 	9.72
   ZFL 	-0.20% 	3 	10.59
   ZLB 	19.23% 	1 	8.52
   ZCM 	2.67% 	5 	7.53
   ZFM 	0.20% 	5 	7.92
   ZMI 	4.60% 	4 	7.96
   ZDM 	18.95% 	4 	10.56
   ZEM 	8.86% 	3 	10.97
   ZQQ 	20.36% 	5 	12.61
   ZRR 	-2.31% 	4 	11.77
   ZUE 	17.36% 	4 	11.07
   ZCN 	9.92% 	3 	9.16
   ZEB 	13.06% 	3 	13.34
   ZMT 	-4.23% 	4 	20.63
   ZEO 	0.27% 	1 	16.66
   ZCS 	0.74% 	4 	6.44
   ZFS 	-0.61% 	4 	6.41
   ZPS 	0.08% 	5 	6.27
   ZST 	-0.97% 	3 	6.78