Making the Minimum, Mandatory Changes
01: model "Portfolio optimization with LP"
02:
03: uses "mminsight" ! Mandatory for Xpress insight
04: uses "mmxprs" ! Use Xpress-Optimizer
05:
06: parameters
07: DATAFILE= "folio.dat" ! File with problem data
08: OUTFILE= "result.dat" ! Output file
09: MAXRISK = 1/3 ! Max. investment into high-risk values
10: MAXVAL = 0.3 ! Max. investment per share
11: MINAM = 0.5 ! Min. investment into N.-American values
12: end-parameters
13:
14: declarations
15: SHARES: set of string ! Set of shares
16: RISK: set of string ! Set of high-risk values among shares
17: NA: set of string ! Set of shares issued in N.-America
18: RET: array(SHARES) of real ! Estimated return in investment
19: end-declarations
20:
21: forward procedure datainput
22:
23: case insightgetmode of
24: INSIGHT_MODE_LOAD: do
25: datainput
26: exit(0)
27: end-do
28: INSIGHT_MODE_RUN:
29: insightpopulate
30: else
31: datainput
32: end-case
33:
34: procedure datainput
35: initializations from DATAFILE
36: RISK RET NA
37: end-initializations
38: end-procedure
39:
40: declarations
41: frac: array(SHARES) of mpvar ! Fraction of capital used per share
42: end-declarations
43:
44: ! Objective: total return
45: Return:= sum(s in SHARES) RET(s)*frac(s)
46:
47: ! Limit the percentage of high-risk values
48: sum(s in RISK) frac(s) <= MAXRISK
49:
50: ! Minimum amount of North-American values
51: sum(s in NA) frac(s) >= MINAM
52:
53: ! Spend all the capital
54: sum(s in SHARES) frac(s) = 1
55:
56: ! Upper bounds on the investment per share
57: forall(s in SHARES) frac(s) <= MAXVAL
58:
59: ! Solve the problem
60: insightmaximize(Return)
61:
62: ! Solution printing to a file
63: fopen(OUTFILE, F_OUTPUT)
64: writeln("Total return: ", getobjval)
65: forall(s in SHARES)
66: writeln(strfmt(s,-12), ": \t", strfmt(getsol(frac(s))*100,5,2), "%")
67: fclose(F_OUTPUT)
68:
69: end-model
Commentary
Line 3 includes the mminsight package.
Line 21 contains a forward declaration of a procedure called datainput, which has been created so that it can be invoked from a later case statement, which takes one of three code paths depending on the value of insightgetmode.
Lines 23-32 contain the LOAD mode code. If Xpress Insight is loading data, then datainput is called (line 25). If it is simply starting a run, then insightpopulate is called (line 29). If neither of these is true (i.e. the model is running in non-Xpress Insight mode) then datainput is called and execution continues with the next statements.
Lines 34-38 wrap the original initializations block as the datainput procedure so it is only run if invoked explicitly.
Line 60 now contains a call to insightmaximize instead of maximize.
A copy of this code without line numbers is available in Code Samples for you to cut and paste into your own editor.
