JuPOT - Tutorial


In [10]:
push!(LOAD_PATH, "$(homedir())/desktop/financial-opt-tools/src")

using JuPOT

# Generate synthetic data sets for Demonstration
############
# Assets
############
n = 10 # No. Of Assets
returns = rand(n)
covarariance = let
    S = randn(n, n)
    S'S + eye(n)
end
names = [randstring(3) for i in 1:n] # List of asset names

# Assets data structure containing, names, expected returns, covarariance
assets = AssetsCollection(names, returns, covarariance)


Out[10]:
WGd    0.8750696218393272 
NUU    0.0909824764542102 
XkG    0.0421296129858959 
BVj    0.3566575879209919 
pRr    0.539297484964939 
Jzy    0.5215886520600004 
kiR    0.6376321186088576 
5ML    0.2587373064380125 
4Wu    0.6969136663434587 
bTp    0.4212944263872922 

Simple MVO

\begin{align} &\text{minimize} && w^\top\Sigma w \\ &\text{subject to} && \mu^\top w\geq r_{\min} \\ & && \mathbf{1}^\top w = 1 \\ & && w \succeq 0 \\ & && \sum_{i=1}^{\infty}{w_i} \succeq 0 \\ \end{align}

In [11]:
######################################################
################### SIMPLE MVO #######################
######################################################

# Example 1: Basic
target_return = 0.2
# refer to model definition for keyword arguments, etc.
mvo = SimpleMVO(assets, target_return; short_sale=false)


Out[11]:
 Sense: Min 

 Variables: 
w[1:10] >= 0

 Objective Function: 
  dot(w,10x10 Array{Float64,2}:
 10.3866    -0.89143   -1.33051   …   0.198312   4.50745    2.37707 
 -0.89143    7.09333   -3.45644       2.09936    0.348747  -1.71617 
 -1.33051   -3.45644   10.2676       -5.09831   -5.36072    1.8266  
 -0.844028   3.28496    0.410415      2.64611    1.41345    2.39396 
 -3.33323    1.31546    0.239667      0.212938  -6.14246   -1.16482 
 -1.50885    2.61073    1.95697   …  -5.33638   -3.99037   -2.14628 
  5.32728   -1.83709    2.18061      -5.61788   -0.872873   3.54495 
  0.198312   2.09936   -5.09831       9.98955    5.32627    0.232497
  4.50745    0.348747  -5.36072       5.32627   15.8035     2.1874  
  2.37707   -1.71617    1.8266        0.232497   2.1874     7.2731   * w) 

 Constraints: 
dot([0.8750696218393272,0.0909824764542102,0.0421296129858959,0.3566575879209919,0.539297484964939,0.5215886520600004,0.6376321186088576,0.2587373064380125,0.6969136663434587,0.4212944263872922],w) ≥ 0.2
dot(ones(10),w) == 1

 Assets: 
 WGd    0.8750696218393272 
NUU    0.0909824764542102 
XkG    0.0421296129858959 
BVj    0.3566575879209919 
pRr    0.539297484964939 
Jzy    0.5215886520600004 
kiR    0.6376321186088576 
5ML    0.2587373064380125 
4Wu    0.6969136663434587 
bTp    0.4212944263872922 
 

In [12]:
optimize(mvo)


Out[12]:
10-element Array{Float64,1}:
 0.0170244  
 0.0753511  
 0.183185   
 1.35262e-10
 0.185192   
 0.0834505  
 0.145646   
 0.18291    
 0.127241   
 2.27348e-9 

Constraints

constraint1: $\sum$ asset group constraints


In [55]:
##################################
# Example 2: Adding a Constraint #
##################################
function genTechIndicator()
    [0,0,1,1,0,1,0,1,1,0]
end

# Adding a simple weight constraint
constraints = Dict((:constraint1 => :(dot(w,tech) <= tech_thresh)),
                   (:constraint2 => :(dot(w,fin) <= Fin_thresh)))
parameters = Dict(:tech=>genTechIndicator(), 
                  :tech_thresh => 0.3,
                  :fin=> [1,1,0,0,1,0,1,0,0,0],
                  :Fin_thresh => 0.05)
# refer to model definition for keyword arguments, etc.
mvo = SimpleMVO(assets, target_return, constraints; short_sale=false)
w = optimize(mvo, parameters)

# add checkers for constraints


Out[55]:
10-element Array{Float64,1}:
 1.08235e-10
 0.0404122  
 4.03129e-10
 9.94083e-11
 0.00958781 
 0.194771   
 7.34928e-11
 0.105229   
 2.20301e-10
 0.65       

In [17]:
####################################################### 
# Example 3: Changing a Constraint's parameter values #
#######################################################

# Changing values of an entered constraint
parameters[:tech_thresh] = 0.04

# refer to model definition for keyword arguments, etc.
mvo = SimpleMVO(assets, target_return, constraints; short_sale=false)
optimize(mvo, parameters)


Out[17]:
10-element Array{Float64,1}:
 4.9691e-11 
 0.0499999  
 1.53707e-10
 1.3058e-10 
 6.88396e-8 
 0.04       
 3.35711e-11
 5.70681e-11
 8.17501e-11
 0.91       

In [19]:
####################################
# Example 4: Deleting a Constraint #
####################################

# Removing a previously defined constraint
delete!(constraints, :constraint2)
delete!(parameters, :Fin_thresh)
# refer to model definition for keyword arguments, etc.
mvo = SimpleMVO(assets, target_return, constraints; short_sale=false)
optimize(mvo, parameters)


Out[19]:
10-element Array{Float64,1}:
 0.152713   
 0.21905    
 0.00936567 
 1.96236e-11
 0.31893    
 3.21006e-11
 0.0845705  
 8.39941e-11
 0.0306343  
 0.184737   

In [23]:
##########################################
# Example 5: Adding multiple Constraints #
##########################################

# Adding a multiple weight constraints
# constraints = Dict(:constraint1 => :(w[1:5] .<= assets_1_5_max), :constraint2 => :(w[6:n] .<= assets_6_n_max))
# Adding a simple weight constraint
constraints_1 = [symbol("x$i") => :(min_thresh <= w[$i]) for i=1:n]
constraints_2 = [symbol("y$i") => :( w[$i] <= max_thresh) for i=1:n]
parameters_1 = Dict(:min_thresh => 0, :max_thresh => 0.5, :n => n)

# Different constraint sets can be merged to form new ones
constraints = merge(constraints,constraints_1,constraints_2)
parameters = merge(parameters,parameters_1)
# refer to model definition for keyword arguments, etc.
mvo = SimpleMVO(assets, target_return, constraints; short_sale=false)
optimize(mvo, parameters)


Out[23]:
10-element Array{Float64,1}:
 0.152713   
 0.21905    
 0.00936567 
 6.82782e-12
 0.31893    
 1.58286e-11
 0.0845705  
 1.82652e-10
 0.0306343  
 0.184737   

In [27]:
#####################################
# Example 6: Using Different Assets #
#####################################

############
# Asset #2 #
############
n = 10 # No. Of Assets
returns_new = rand(n)
covarariance_new = let
    S = randn(n, n)
    S'S + eye(n)
end
names_new = [randstring(3) for i in 1:n]
# Assets data structure containing, names, expected returns, covarariance
assets_new = AssetsCollection(names_new, returns_new, covarariance_new)


# Using the same previously defined constraints we can run the model on a different set of assets effortlessly
mvo = SimpleMVO(assets_new, target_return; short_sale=false)
optimize(mvo, parameters)


Out[27]:
10-element Array{Float64,1}:
 0.059491   
 2.11897e-8 
 0.207639   
 4.07243e-12
 2.90081e-12
 0.275566   
 2.24249e-11
 0.258529   
 0.00451188 
 0.194264   

In [28]:
# Forgot what constraints and parameters were defined for initial constraints? No Problem!
constraints # Prints the constraints


Out[28]:
Dict{Symbol,Expr} with 21 entries:
  :y6          => :(w[6] <= max_thresh)
  :x4          => :(min_thresh <= w[4])
  :x10         => :(min_thresh <= w[10])
  :y9          => :(w[9] <= max_thresh)
  :y10         => :(w[10] <= max_thresh)
  :y8          => :(w[8] <= max_thresh)
  :y4          => :(w[4] <= max_thresh)
  :y7          => :(w[7] <= max_thresh)
  :constraint1 => :(dot(w,tech) <= tech_thresh)
  :y1          => :(w[1] <= max_thresh)
  :x2          => :(min_thresh <= w[2])
  :x3          => :(min_thresh <= w[3])
  :x9          => :(min_thresh <= w[9])
  :y2          => :(w[2] <= max_thresh)
  :x1          => :(min_thresh <= w[1])
  :x7          => :(min_thresh <= w[7])
  :x5          => :(min_thresh <= w[5])
  :y3          => :(w[3] <= max_thresh)
  :y5          => :(w[5] <= max_thresh)
  :x6          => :(min_thresh <= w[6])
  :x8          => :(min_thresh <= w[8])

In [29]:
parameters # prints the parameters


Out[29]:
Dict{Symbol,Any} with 6 entries:
  :tech        => [0,0,1,1,0,1,0,1,1,0]
  :tech_thresh => 0.04
  :max_thresh  => 0.5
  :fin         => [1,1,0,0,1,0,1,0,0,0]
  :n           => 10
  :min_thresh  => 0

In [30]:
# Using old constraints on new assets
mvo = SimpleMVO(assets_new, target_return, constraints; short_sale=false)
optimize(mvo, parameters)


Out[30]:
10-element Array{Float64,1}:
 0.29987    
 0.160755   
 0.04       
 4.19273e-13
 1.04397e-12
 3.50401e-12
 0.246086   
 2.27611e-12
 7.99382e-13
 0.253289   

In [32]:
##############################
#  Example 7 Using Robust MVO#
##############################

# refer to model definition for keyword arguments, etc
# If no uncertainty matrix is entered the model defaults
# to the ellipse whose axes are proportional to the 
# individual variances of each asset

rmvo = RobustMVO(assets, target_return; short_sale=true)
optimize(rmvo, parameters)


Out[32]:
10-element Array{Float64,1}:
 0.0819074
 0.117726 
 0.120242 
 0.0572045
 0.159447 
 0.0917164
 0.086467 
 0.116344 
 0.0741187
 0.0948265

In [52]:
#################################################################
#  Example 8 Creating Custom Functions (e.g efficient frontier) #
#################################################################

n = 20
risk = Array(Float32,n)
index = Array(Float32,n)
for i in 1:n
   target_ret = i/21
   mvo = SimpleMVO(assets, target_ret; short_sale=true)
   optimize(mvo, parameters)
   risk[i] = mvo.objVal
   index[i] = target_ret
end

In [53]:
risk


Out[53]:
20-element Array{Float32,1}:
 0.461836
 0.461836
 0.461836
 0.461836
 0.461836
 0.461836
 0.461836
 0.461985
 0.483955
 0.543207
 0.639742
 0.773559
 0.944659
 1.15304 
 1.3987  
 1.68165 
 2.00188 
 2.35939 
 2.75418 
 3.18626 

In [54]:
index


Out[54]:
20-element Array{Float32,1}:
 0.047619 
 0.0952381
 0.142857 
 0.190476 
 0.238095 
 0.285714 
 0.333333 
 0.380952 
 0.428571 
 0.47619  
 0.52381  
 0.571429 
 0.619048 
 0.666667 
 0.714286 
 0.761905 
 0.809524 
 0.857143 
 0.904762 
 0.952381 

In [ ]: