(!******************************************************
Mosel Example Problems
======================
file folioqp_py.mos
```````````````````
Modeling a small QP problem
to perform portfolio optimization.
-- 1. QP: minimize variance
2. MIQP: limited number of assets --
-- Using Python to calculate covariance matrix --
(c) 2018 Fair Isaac Corporation
author: S. Lannez, J. Müller, April 2018
*******************************************************!)
model "Portfolio optimization with QP/MIQP"
uses "mmxprs", "mmnl"
uses "python3" ! Use Python functions
parameters
MAXVAL = 0.3 ! Max. investment per share
MINAM = 0.5 ! Min. investment into N.-American values
MAXNUM = 4 ! Max. number of different assets
TARGET = 9.0 ! Minimum target yield
end-parameters
declarations
SHARES = 1..10 ! Set of shares
RISK: set of integer ! Set of high-risk values among shares
NA: set of integer ! Set of shares issued in N.-America
DATES: set of string ! Historical dates
RET: array(SHARES) of real ! Estimated return in investment
VAR: array(SHARES,SHARES) of real ! Variance/covariance matrix of
! estimated returns
OPEN: array(SHARES,DATES) of real ! Historical share value at market opening
CLOSE: array(SHARES,DATES) of real ! Historical share value at market closing
end-declarations
initializations from "folioqp.dat"
RISK RET NA
end-initializations
! Load historical values to compute the covariance
initializations from "folioqphist.dat"
OPEN CLOSE
end-initializations
! **** Perform some statistics using Python ****
! Copy array to Python environment
initialisations to PY_IO_GLOBAL_VAR
OPEN
CLOSE
end-initialisations
! Import functions from Python script
writeln('Importing pandas and covariance function.')
pyrun('folioqp_pandas.py')
! Print covariance of share value at market openings
writeln("Covariances at market openings:")
pyexec('covariance_of_series(pd.Series(OPEN))')
! Calculate and retrieve covariance of mean value
writeln("Covariances of mean value of openings and closings:")
pyexec('VAR = covariance_of_series((pd.Series(OPEN) + pd.Series(CLOSE)) / 2).to_dict()')
initialisations from PY_IO_GLOBAL_VAR
VAR
end-initialisations
declarations
frac: array(SHARES) of mpvar ! Fraction of capital used per share
end-declarations
! **** First problem: unlimited number of assets ****
! Objective: mean variance
Variance:= sum(s,t in SHARES) VAR(s,t)*frac(s)*frac(t)
! Minimum amount of North-American values
sum(s in NA) frac(s) >= MINAM
! Spend all the capital
sum(s in SHARES) frac(s) = 1
! Target yield
sum(s in SHARES) RET(s)*frac(s) >= TARGET
! Upper bounds on the investment per share
forall(s in SHARES) frac(s) <= MAXVAL
! Solve the problem
minimize(Variance)
! Solution printing
writeln("With a target of ", TARGET, " minimum variance is ", getobjval)
forall(s in SHARES) writeln(s, ": ", getsol(frac(s))*100, "%")
! **** Second problem: limit total number of assets ****
declarations
buy: array(SHARES) of mpvar ! 1 if asset is in portfolio, 0 otherwise
end-declarations
! Limit the total number of assets
sum(s in SHARES) buy(s) <= MAXNUM
forall(s in SHARES) do
buy(s) is_binary
frac(s) <= buy(s)
end-do
! Solve the problem
minimize(Variance)
writeln("With a target of ", TARGET," and at most ", MAXNUM,
" assets,\n minimum variance is ", getobjval)
forall(s in SHARES) writeln(s, ": ", getsol(frac(s))*100, "%")
! Round integer values and resolve
fixglobal(true)
minimize(Variance)
writeln("With all binary variables rounded to the nearest integer:")
forall(s in SHARES) writeln(s, ": ", getsol(frac(s))*100, "%")
end-model
|