Complete example
The complete model file folioloop_graph.mos with all the features discussed in this chapter looks as follows. Notice that the two modules mmxprs and mmive may be loaded with a single uses statement. The deviation data may either be added to the original data file or, as shown here, read from a second file.
model "Portfolio optimization with LP"
uses "mmxprs", "mmsvg" ! Use Xpress Optimizer with SVG graphing
parameters
DATAFILE= "folio.dat" ! File with problem data
DEVDATA= "foliodev.dat" ! File with deviation data
MAXVAL = 0.3 ! Max. investment per share
MINAM = 0.5 ! Min. investment into N.-American values
end-parameters
declarations
SHARES: set of string ! Set of shares
RISK: set of string ! Set of high-risk values among shares
NA: set of string ! Set of shares issued in N.-America
RET: array(SHARES) of real ! Estimated return in investment
DEV: array(SHARES) of real ! Standard deviation
SOLRET: array(range) of real ! Solution values (total return)
SOLDEV: array(range) of real ! Solution values (average deviation)
end-declarations
initializations from DATAFILE
RISK RET NA
end-initializations
initializations from DEVDATA
DEV
end-initializations
declarations
frac: array(SHARES) of mpvar ! Fraction of capital used per share
Return, Risk: linctr ! Constraint declaration (optional)
end-declarations
! Objective: total return
Return:= sum(s in SHARES) RET(s)*frac(s)
! Minimum amount of North-American values
sum(s in NA) frac(s) >= MINAM
! Spend all the capital
sum(s in SHARES) frac(s) = 1
! Upper bounds on the investment per share
forall(s in SHARES) frac(s) <= MAXVAL
! Solve the problem for different limits on high-risk shares
ct:=0
forall(r in 0..20) do
! Limit the percentage of high-risk values
Risk:= sum(s in RISK) frac(s) <= r/20
maximize(Return) ! Solve the problem
if (getprobstat = XPRS_OPT) then ! Save the optimal solution value
ct+=1
SOLRET(ct):= getobjval
SOLDEV(ct):= getsol(sum(s in SHARES) DEV(s)*frac(s))
else
writeln("No solution for high-risk values <= ", 100*r/20, "%")
end-if
end-do
! Drawing a graph to represent results (`GrS') and data (`GrL' & `GrH')
svgaddgroup("GrS", "Solution values", SVG_GREY)
svgaddgroup("GrL", "Low risk", SVG_GREEN)
svgaddgroup("GrH", "High risk", SVG_RED)
forall(r in 1..ct) svgaddpoint("GrS", SOLRET(r), SOLDEV(r))
svgaddline("GrS", sum(r in 1..ct) [SOLRET(r), SOLDEV(r)])
forall(s in SHARES - RISK) do
svgaddpoint("GrL", RET(s), DEV(s))
svgaddtext("GrL", RET(s)+1, 1.3*(DEV(s)-1), s)
end-do
forall(s in RISK) do
svgaddpoint("GrH", RET(s), DEV(s))
svgaddtext("GrH", RET(s)-2.5, DEV(s)-1, s)
end-do
! Scale the size of the displayed graph
svgsetgraphscale(10)
svgsetgraphpointsize(2)
! Optionally save graphic to file
svgsave("foliograph.svg")
! Display the graph and wait for window to be closed by the user
svgrefresh
svgwaitclose
end-model The problem is not feasible for small limit values on the constraint Risk. Besides the graphs we therefore obtain the following text output:
No solution for high-risk values <= 0% No solution for high-risk values <= 5% No solution for high-risk values <= 10% No solution for high-risk values <= 15%
