markowitz.py
Go to the documentation of this file.
10
11from __future__ import print_function
12from gams import *
13import sys
14import os
15from math import fabs
16
17try:
18 import matplotlib.pyplot as plt
19except:
20 raise Exception("This example requires the matplotlib module")
21
23 return '''
24$title Standard Markowitz Portfolio Selection Model
25
26set s selected stocks
27 upper(s,s), lower(s,s) parts of covar matrix;
28alias(s,t);
29
30parameter mean(s) mean of daily return
31 covar(s,s) covariance matrix of returns (upper);
32
33$if not set data $abort 'no include file name for data file provided'
34$gdxin %data%
35$load s covar upper lower mean
36
37variables z objective variable
38 ret return
39 var variance
40 x(s) investments;
41
42positive variables x;
43
44equations obj objective
45 budget
46 varcon variance constraint
47 retcon return constraint;
48
49scalar lambda /0/;
50
51obj.. z =e= lambda*ret - (1-lambda)*var;
52budget.. sum(s, x(s)) =e= 1.0;
53varcon.. var =e= sum(upper(s,t), x(s)*covar(s,t)*x(t)) +
54 sum(lower(s,t), x(s)*covar(t,s)*x(t));
55retcon.. ret =e= sum(s, mean(s)*x(s));
56
57model markowitz /all/; '''
58
59if __name__ == "__main__":
60 if len(sys.argv) > 1:
61 ws = GamsWorkspace(system_directory = sys.argv[1])
62 else:
63 ws = GamsWorkspace()
64
65 job = ws.add_job_from_string(get_model_text())
66 opt = ws.add_options()
67 opt.all_model_types = "conopt"
68 opt.defines["data"] = "\"" + os.path.join(os.path.dirname(os.path.realpath(__file__)), "..\\Data\\markowitz.gdx") + "\""
69
70 cp = ws.add_checkpoint()
71 job.run(opt, cp)
72 mi = cp.add_modelinstance()
73 l = mi.sync_db.add_parameter("lambda", 0, "")
74 mi.instantiate("markowitz use nlp max z", GamsModifier(l))
75
76 # a list for collecting the data points
77 data_points = []
78
79 # get minimum and maximum return (lambda=0/1)
80 l.add_record().value = 0
81 mi.solve()
82 min_ret = mi.sync_db["ret"].first_record().level
83 data_points.append( (min_ret, mi.sync_db["var"].first_record().level) )
84 l.first_record().value = 1
85 mi.solve()
86 max_ret = mi.sync_db["ret"].first_record().level
87 data_points.append( (max_ret, mi.sync_db["var"].first_record().level) )
88
89 # gap that specifies the max distance (return) between two data points
90 gap = 0.02
91 # a list (stack) of intervals, where an interval is represented by a 2-tuple containing two data points
92 # each represented by a 2-tuple as well (lambda, return)
93 intervals = [((0.0, min_ret), (1.0, max_ret))]
94
95 # Algorithm that solves the model instance for multiple lambda values
96 # using a max gap between two data points to achieve a smooth graph.
97 # Lambda is dynamically calculated for an even distribution of data points
98 while intervals:
99 # pick the first interval and calculate a new value for lambda
100 i = intervals.pop()
101 min_l, min_ret = i[0][0], i[0][1]
102 max_l, max_ret = i[1][0], i[1][1]
103
104 l_val = (min_l+max_l)/2
105 l.first_record().value = l_val
106 # solve the model instance with the new lambda value
107 mi.solve()
108 # retrieve the return and variance results
109 cur_ret = mi.sync_db["ret"].first_record().level
110 data_points.append( (cur_ret, mi.sync_db["var"].first_record().level) )
111 # add new intervals if the gap is still to big
112 if cur_ret - min_ret > gap:
113 intervals.append(((min_l, min_ret), (l_val, cur_ret)))
114 if fabs(cur_ret - max_ret) > gap:
115 intervals.append(((l_val, cur_ret), (max_l, max_ret)))
116
117 # Sort data points and make two list for the plot function
118 data_points.sort(key=lambda tup: tup[0])
119 ret = map(lambda x: x[0], data_points)
120 var = map(lambda x: x[1], data_points)
121 plt.plot(ret, var, marker=".", markersize=10)
122 plt.xlabel('return')
123 plt.ylabel('variance')
124 plt.show()
def get_model_text()
Definition: markowitz.py:22