Problem #3, MOSEL Code
(!****************************************************
ENCE723_PB2 adapted from Dash's Associates library of examples
Mosel Example Problems
======================
file folioqpgraph.mos
`````````````````````
TYPE: Portfolio optimization problem (Quadratic Programming problem)
FEATURES: small QP problem, solved repeatedly with modified
constraints, graphical representation of the results,
use of `min' and `max'
DESCRIPTION: An investor is evaluating thjree different securities (`shares').
He estimates the return on investment for a period of one year. How should the capital be divided among
the shares to minimize the risk whilst obtaining a certain target yield? The investor adopts the Markowitz idea
of getting estimates of the variance/covariance matrix of estimated returns on the
securities.
FURTHER INFO: http://www.eng.umd.edu/~sgabriel/Teaching/ence723-amsc698s(MOP)/downloads&links.htm
Similar problems:
`Xpress-MP Getting Started', Chapter 7 `Quadratic Programming'.
`Applications of optimization with Xpress-MP',
Section 13.7 `Mean variance portfolio selection'
(c) 2003 Dash Associates
author: S. Heipcke
*****************************************************!)
model "Portfolio optimization with QP"
uses "mmxprs", "mmquad", "mmive" ! Use Xpress-Optimizer with QP solver
declarations
SHARES = 1..3 ! Set of shares
RET: array(SHARES) of real ! Estimated return in investment
VAR: array(SHARES,SHARES) of real ! Variance/covariance matrix of
! estimated returns
SOLRET: array(range) of real ! Solution values (total return)
SOLDEV: array(range) of real ! Solution values (average deviation)
end-declarations
!parameters
!MinRet
!end-parameters
initializations from "folioqpgraph.dat"
! This is a regular data file, shown below the code. Normally, it is just a separate file
!RET VAR EXP
RET VAR
end-initializations
declarations
frac: array(SHARES) of mpvar ! Fraction of capital used per share
end-declarations
! Objective: mean variance
Variance:= sum(s,t in SHARES) VAR(s,t)*frac(s)*frac(t)
! Spend all the capital
sum(s in SHARES) frac(s) = 1
! Solve the problem for a range of returns: this is the efficient frontier
target:= min(s in SHARES) RET(s)
RMAX:= max(s in SHARES) RET(s)
while(target < RMAX) do
Return:= sum(s in SHARES) RET(s)*frac(s) >= target ! Target yield
minimize(Variance) ! Solve the problem
if (getprobstat = XPRS_OPT) then ! Save the optimal solution value
ct+=1
SOLDEV(ct):= getobjval
SOLRET(ct):= target
else
writeln("No solution for target return >= ", ct, "%")
break
end-if
target += 1
end-do
! Drawing a graph to represent results (`plot1') and data (`plot2' & `plot3')
declarations
plot1: integer
DEV: array(SHARES) of real ! Standard deviation
end-declarations
!initializations from "folioqpgraph.dat"
! DEV NAMES
!end-initializations
plot1 := IVEaddplot("Solution values", IVE_BLACK)
forall(r in 1..ct) IVEdrawpoint(plot1, SOLRET(r), SOLDEV(r));
forall(r in 2..ct)
IVEdrawline(plot1, SOLRET(r-1), SOLDEV(r-1), SOLRET(r), SOLDEV(r))
end-model
========= Separate Data File folioqpgraph.dat ==========
! Data file for `folioqpgraph.mos'
! 1 2 3
RET: [10 20 30]
! 1 2 3
VAR: [ 4.2 -1.9 2 ! 1
-1.90 6.7 -5 ! 2
2 -5 7 ! 3
]
! trs haw thr
DEV: [0.1 19 28]