Skip to content

More Examples

PharosAbad edited this page Apr 22, 2023 · 13 revisions

List of examples

All these examples are available with the package, taking from https://github.com/PharosAbad/EfficientFrontier.jl/tree/main/examples

Markowitz and Todd (2000)

Markowitz and Todd (2000, chapter 13, pp.337) computes the model

$$ \begin{array} [c]{cl} \min & \frac{1}{2}\mathbf{z}^{\prime}\mathbf{Vz}-L\mathbf{z}^{\prime }\boldsymbol{\mu}\\ s.t. & \mathbf{z}^{\prime}\mathbf{1}=1\\ & \mathbf{Gz}\leq\mathbf{g}\in\mathbb{R}^{J}\\ & \boldsymbol{d}\leq\mathbf{z}\leq\boldsymbol{u}\in\mathbb{R}^{N} \end{array} $$

the CLA in Markowitz and Todd (2000) assumes either one IN or one OUT (if and only if one asset changes state). Our code handles two or more IN and/or OUT (allow any number of changes concurrently).

No short-sale

Solving the no short-sale problem:

$$ \begin{array} [c]{cl} \min & \frac{1}{2}\mathbf{z}^{\prime}\mathbf{Vz}-L\mathbf{z}^{\prime }\boldsymbol{\mu}\\ s.t. & \mathbf{z}^{\prime}\mathbf{1}=1\\ & \mathbf{z}\geq 0\in\mathbb{R}^{N} \end{array} $$

Here are the examples: compare CLA (via CLA plugin Markowitz.jl ) to Status-Segment Method

General Model

general model with lower and upper bounds, inequality constraints, and equality constraints

$$ \begin{array} [c]{cl} \min & \frac{1}{2}\mathbf{z}^{\prime}\mathbf{Vz}-L\mathbf{z}^{\prime }\boldsymbol{\mu}\\ s.t. & \mathbf{Az}=\mathbf{b}\in\mathbb{R}^{M}\\ & \mathbf{Gz}\leq\mathbf{g}\in\mathbb{R}^{J}\\ & \boldsymbol{d}\leq\mathbf{z}\leq\boldsymbol{u}\in\mathbb{R}^{N} \end{array} $$

Noting that $\mathbf{Az}=\mathbf{b}$ does include $\mathbf{z}^{\prime}\mathbf{1}=1$, but NOT include $\mathbf{z}^{\prime}\boldsymbol{\mu}=\mu$.

Do NOT convert $\mathbf{Gz}\leq\mathbf{g}$ to equalities $\mathbf{Gz} +\mathbf{y} =\mathbf{g}$ by adding slack variables $\mathbf{y}\geq 0$. That may break our procedure.

Critical Line Algorithm

an example shows why the Critical Line Algorithm (CLA) fails

Advance Examples

For advance users, or developers only!

Combinatorial Search

cbCL!: compute one or all (oneCL=false) the Critical Line Segments by enumerating (combinations of Status)

E, V = EfficientFrontier.EVdata(:Ungil, false)
E = [0.1 0.7 0.8 2.3 2.2 1.9 5.6 5.6 7.2 1.3 7.2 -0.1 4.1 7.2] #最高期望收益有多个
P = Problem(E, V)

aCLs = sCL(P)
cbCL!(aCLs, P; oneCL=false, K=2)
sort!(aCLs, by=x -> x.L1, rev=true)
display(aCLs)

Play big (forget it, unless you have a latest CPU)

E, V = EfficientFrontier.EVdata(:Ungil, false)
A = [1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
    1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0]
b = [1.0; 0.25]
G = [0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
    0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0]
G[1, :] = -G[1, :]
g = [-0.3; 0.6]
d = vec([-0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.0 -0.1 -0.1 -0.1 -0.1])
u = vec([0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.1 0.1 0.1 0.3 0.3 0.3 0.3])

Pb = Problem(E, V, u, d, G, g, A, b)
aCLb = sCL(Pb)
ts = @elapsed cbCL!(aCLb, Pb; oneCL=false, K=Pb.M)
sort!(aCLb, by=x -> x.L1, rev=true)
display(aCLb)
println("Full search:  ", ts, "  seconds")    #500 seconds
#aCLb = EfficientFrontier.ECL(Pb)   #0.0005 seconds

One and All

One CL may be found luckily, such as from a simplify model, a quick rule, or a combinatorial search. Then, ECL! will give us the entire frontier. Let us use the Pb from the previous example

#E, V = EfficientFrontier.EVdata(:Ungil, false)
aCL1 = sCL(Pb)
ts = @elapsed cbCL!(aCL1, Pb; K=5)
println("search one CL:  ", ts, "  seconds")     #0.8 seconds
nS = Settings(Pb)
ECL!(aCL1, Pb; numSettings=nS, incL=true)    #increasing L
ECL!(aCL1, Pb; numSettings=nS)    #decreasing L
display(aCL1)

Arbitrary Precision Arithmetic

Markowitz and Todd (2000)

E[4]=1.12,  but BigFloat("1.12")-E[4] is: -1.065814103640150278806686401367187500000000000000000000000000027635739376302223e-16
now convert the raw data to BigFloat to improve precision (raw data to BigFloat, not raw data to Float64 then to BigFloat)

 Assets 2 and 10 go IN at the same time, NOT the case that ONE at each time
2-element Vector{Event{BigFloat}}:
 Event{BigFloat}(UP, IN, 2, 2.494839663636363636363636363636363636363636363636363636363636363636363636363613)
 Event{BigFloat}(DN, IN, 10, 2.494839663636363636363636363636363636363636363636363636363636363636363636365064)
using BigFloat, the difference on L: -1.450876317255866697064907112950467127947488061225295272683982182988323422931288e-75

A general model

Float64 is enough thus the default

equilibrate may improve precision if range of non-zeros in abs.(E) or abs.(V) is too large

BigFloat can be tens (30 to 70), even more than 200 times slow.

If precision is a problem, Float64+equilibrate is recommended. It is better (fast and stable) most of the time, but not always. (Due to the truncation of floating number, e.g., 1/60*50-50/60 = 0, but if scaled down the data by 10, 1/6*5-5/6 = 1.1102230246251565e-16)

Plugins

to find the Status of first CL (the default Simplex method is the best: Faster speed and better accuracy), you can try

This working example also test Critical Line Algorithm (CLA), the CLA plugin Markowitz.jl is needed also.