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.