Skip to content

Commit

Permalink
portfolio
Browse files Browse the repository at this point in the history
  • Loading branch information
PharosAbad committed Apr 26, 2023
1 parent c4b1b3d commit 4ec73ed
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "LightenQP"
uuid = "732b1220-b3b1-47df-92b9-9aafce73c71b"
authors = ["Pharos Abad"]
version = "1.0.8"
version = "1.0.9"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
8 changes: 4 additions & 4 deletions examples/SP500.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ function main()

#v1.0.1
Q = OOQP(V, E, u)
ts = @elapsed xH, statusH = fPortfolio(Q; L=Inf) #HMFP (Highest Mean Frontier Portfolio)
ts = @elapsed xH, statusH = fPortfolio(Q, Inf) #HMFP (Highest Mean Frontier Portfolio)
println("HMEP (Highest Mean Efficient Portfolio) --- fPortfolio @ max mu: ", ts, " seconds")
ts = @elapsed xL, statusL = fPortfolio(Q; L=-Inf) #LMFP (Lowest Mean Frontier Portfolio)
ts = @elapsed xL, statusL = fPortfolio(Q, -Inf) #LMFP (Lowest Mean Frontier Portfolio)
println("LMEP (Lowest Mean Efficient Portfolio) --- fPortfolio @ min mu: ", ts, " seconds")
ts = @elapsed x0, status0 = fPortfolio(Q; L=0.0)
ts = @elapsed x0, status0 = fPortfolio(Q, 0.0)
println("LMEP (Lowest Mean Efficient Portfolio, also called GMVP, Global Minimum Variance Portfolio) --- fPortfolio @ L=0: ", ts, " seconds")
ts = @elapsed x2, status2 = fPortfolio(Q; L=2.0)
ts = @elapsed x2, status2 = fPortfolio(Q, 2.0)
println(" --- fPortfolio @ L=2.0: ", ts, " seconds")
end

Expand Down
35 changes: 24 additions & 11 deletions examples/SpeedAccuracy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ using EfficientFrontier, LinearAlgebra
using TranscodingStreams, CodecXz, Serialization, Downloads
using LightenQP: LightenQP #, solveOOQP
import LightenQP: OOQP, fPortfolio
using Statistics

if length(filter((x) -> x == :uOSQP, names(Main, imported=true))) == 0
include("./uOSQP.jl")
Expand All @@ -27,15 +28,17 @@ function OOQP(P::Problem{T}) where {T}
OOQP{T}(V, A, C, E, b, gq, N, M, L)
end

function fPortfolio(P::Problem{T}; settings=LightenQP.Settings{T}(), L=0.0) where {T}
#=
function fPortfolio(P::Problem{T}, L::T=0.0; settings=LightenQP.Settings{T}()) where {T}
Q = OOQP(P)
fPortfolio(Q; settings=settings, L=L)
fPortfolio(Q, L; settings=settings)
end
function fPortfolio(P::Problem{T}, mu::T; settings=LightenQP.Settings{T}(), check=true) where {T}
function fPortfolio(mu::T, P::Problem{T}; settings=LightenQP.Settings{T}(), check=true) where {T}
Q = OOQP(P)
fPortfolio(Q, mu; settings=settings, check=check)
fPortfolio(mu, Q; settings=settings, check=check)
end
=#

function testData(ds::Symbol)
if ds == :Ungil
Expand Down Expand Up @@ -91,10 +94,10 @@ function SpeedAccuracy(aEF, P, QPsolver, M=16)
for k in 1:N
for m = 1:M
mu = ((M + 1 - m) * aEF.mu[k] + (m - 1) * aEF.mu[k+1]) / M
z = ePortfolio(aEF, mu)
z = ePortfolio(mu, aEF)
if QPsolver == :LightenQP
#ts = @elapsed y, status = fPortfolio(P, mu; check=false)
ts = @elapsed y, status = fPortfolio(P, mu; check=check)
#ts = @elapsed y, status = fPortfolio(mu, P; check=check)
ts = @elapsed y, status = fPortfolio(mu, OOQP(P); check=check)
check = false
st = status > 0
elseif QPsolver == :OSQP
Expand Down Expand Up @@ -149,6 +152,8 @@ function cmpSA(ds::Symbol)
println("")
#Accuracy
println("\n------- Accuracy -------LightenQP/OSQP/Clarabel ", round.([norm(Al, Inf), norm(Ao, Inf), norm(Ac, Inf)], sigdigits=3))
println("---- quantile 99% ---- ", round.([quantile(Al[:], 0.99), quantile(Ao[:], 0.99), quantile(Ac[:], 0.99)], sigdigits=3))
println("------- median ------- ", round.([median(Al[:]), median(Ao[:]), median(Ac[:])], sigdigits=3))
show(stdout, "text/plain", round.(Al, sigdigits=3))
println("")
show(stdout, "text/plain", round.(Ao, sigdigits=3))
Expand All @@ -157,6 +162,8 @@ function cmpSA(ds::Symbol)
println("")
#Speed
println("\n--- Speed (time span, smaller for faster speed) ---LightenQP/OSQP/Clarabel ", round.([norm(Tl, Inf), norm(To, Inf), norm(Tc, Inf)], sigdigits=3))
println("---- quantile 99% ---- ", round.([quantile(Tl[:], 0.99), quantile(To[:], 0.99), quantile(Tc[:], 0.99)], sigdigits=3))
println("------- median ------- ", round.([median(Tl[:]), median(To[:]), median(Tc[:])], sigdigits=3))
show(stdout, "text/plain", round.(Tl, sigdigits=3))
println("")
show(stdout, "text/plain", round.(To, sigdigits=3))
Expand All @@ -165,6 +172,8 @@ function cmpSA(ds::Symbol)
println("")
#Objective function
println("\n--- Objective function value (diff in sd, not variance) ---LightenQP/OSQP/Clarabel ", round.([norm(Ol, Inf), norm(Oo, Inf), norm(Oc, Inf)], sigdigits=3))
println("---- quantile 99% ---- ", round.([quantile(Ol[:], 0.99), quantile(Oo[:], 0.99), quantile(Oc[:], 0.99)], sigdigits=3))
println("------- median ------- ", round.([median(Ol[:]), median(Oo[:]), median(Oc[:])], sigdigits=3))
show(stdout, "text/plain", round.(Ol, sigdigits=3))
println("")
show(stdout, "text/plain", round.(Oo, sigdigits=3))
Expand All @@ -190,11 +199,9 @@ function SpeedAccuracyL(aEF, P, aCL, QPsolver, M=16)
for m = 1:M
#mu = ((M + 1 - m) * aEF.mu[k] + (m - 1) * aEF.mu[k+1]) / M
L = ((M + 1 - m) * t.L1 + (m - 1) * t.L0) / M
#z = ePortfolio(aEF, mu)
z = ePortfolio(aCL, P, L)
z = ePortfolio(P, L, aCL)
if QPsolver == :LightenQP
#ts = @elapsed y, status = fPortfolio(P, mu; check=false)
ts = @elapsed y, status = fPortfolio(OOQP(P); L) #fPortfolio(P; L) use active-set numerical solver
ts = @elapsed y, status = fPortfolio(OOQP(P), L) #fPortfolio(P; L) use active-set numerical solver
st = status > 0
elseif QPsolver == :OSQP
#ts = @elapsed y = OpSpQP(P, mu)
Expand Down Expand Up @@ -250,6 +257,8 @@ function cmpSA_L(ds::Symbol)
println("")
#Accuracy
println("\n------- Accuracy -------LightenQP/OSQP/Clarabel ", round.([norm(Al, Inf), norm(Ao, Inf), norm(Ac, Inf)], sigdigits=3))
println("---- quantile 99% ---- ", round.([quantile(Al[:], 0.99), quantile(Ao[:], 0.99), quantile(Ac[:], 0.99)], sigdigits=3))
println("------- median ------- ", round.([median(Al[:]), median(Ao[:]), median(Ac[:])], sigdigits=3))
show(stdout, "text/plain", round.(Al, sigdigits=3))
println("")
show(stdout, "text/plain", round.(Ao, sigdigits=3))
Expand All @@ -258,6 +267,8 @@ function cmpSA_L(ds::Symbol)
println("")
#Speed
println("\n--- Speed (time span, smaller for faster speed) ---LightenQP/OSQP/Clarabel ", round.([norm(Tl, Inf), norm(To, Inf), norm(Tc, Inf)], sigdigits=3))
println("---- quantile 99% ---- ", round.([quantile(Tl[:], 0.99), quantile(To[:], 0.99), quantile(Tc[:], 0.99)], sigdigits=3))
println("------- median ------- ", round.([median(Tl[:]), median(To[:]), median(Tc[:])], sigdigits=3))
show(stdout, "text/plain", round.(Tl, sigdigits=3))
println("")
show(stdout, "text/plain", round.(To, sigdigits=3))
Expand All @@ -266,6 +277,8 @@ function cmpSA_L(ds::Symbol)
println("")
#Objective function
println("\n--- Objective function value (diff in sd, not variance) ---LightenQP/OSQP/Clarabel ", round.([norm(Ol, Inf), norm(Oo, Inf), norm(Oc, Inf)], sigdigits=3))
println("---- quantile 99% ---- ", round.([quantile(Ol[:], 0.99), quantile(Oo[:], 0.99), quantile(Oc[:], 0.99)], sigdigits=3))
println("------- median ------- ", round.([median(Ol[:]), median(Oo[:]), median(Oc[:])], sigdigits=3))
show(stdout, "text/plain", round.(Ol, sigdigits=3))
println("")
show(stdout, "text/plain", round.(Oo, sigdigits=3))
Expand Down
5 changes: 3 additions & 2 deletions examples/portfolio.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ function main()

#v1.0.1
O = OOQP(V, E, u)
y, statusy = fPortfolio(O; L=1.0)
#y, statusy = fPortfolio(O; L=1.0)
y, statusy = fPortfolio(O, 1.0)
display(norm(x.x - y.x, Inf)) #0
end

Expand All @@ -38,7 +39,7 @@ aCL = EfficientFrontier.ECL(P; numSettings=nS)
aEF = eFrontier(aCL, P)
mu = x.x'*E
z = ePortfolio(aEF, mu)
z = ePortfolio(mu, aEF)
x.x - z
=#

Expand Down
12 changes: 6 additions & 6 deletions src/mpcQP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ end

"""
x, status = fPortfolio(O::OOQP; settings, L::T=0.0)
x, status = fPortfolio(O::OOQP, mu; settings, check=true)
x, status = fPortfolio(O::OOQP, L::T=0.0; settings)
x, status = fPortfolio(mu, O::OOQP; settings, check=true)
find the minimum variance portfolio: See [`Portfolio Selection · LightenQP`](https://github.com/PharosAbad/LightenQP.jl/wiki/User-Guides#portfolio-selection-1)
Expand All @@ -204,14 +204,14 @@ if `check=false`, we do not check if mu is feasible or not (between lowest and h
See also [`OOQP`](@ref), [`solveOOQP`](@ref), [`Solution`](@ref), [`Settings`](@ref)
"""
function fPortfolio(O::OOQP{T}, mu::T; settings=Settings{T}(), check=true) where {T}
function fPortfolio(mu::T, O::OOQP{T}; settings=Settings{T}(), check=true) where {T}
#FP(mu=mu)
(; V, A, C, q, b, g, N, M, L) = O
#tol = settings.tol
mu1 = mu
if check
#make sure mu is feasible, otherwise, change mu to be the highest or lowest
#HMFP (Highest Mean Frontier Portfolio)
#HMFP (Highest Mean Frontier Portfolio)
xH, status = mpcLP(q, A, b, C, g; settings=settings, min=false) #find the Highest mu
if status == 0
error("mu for Highest Mean Frontier Portfolio: infeasible")
Expand Down Expand Up @@ -251,7 +251,7 @@ function fPortfolio(O::OOQP{T}, mu::T; settings=Settings{T}(), check=true) where
end


function fPortfolio(O::OOQP{T}; settings=Settings{T}(), L::T=0.0) where {T}
function fPortfolio(O::OOQP{T}, L::T=0.0; settings=Settings{T}()) where {T}
#FP(L=L)
(; V, A, C, q, b, g, N, M) = O
if isfinite(L) #@ given L
Expand All @@ -263,7 +263,7 @@ function fPortfolio(O::OOQP{T}; settings=Settings{T}(), L::T=0.0) where {T}
Q = OOQP{T}(V, A, C, qq, b, g, N, M, O.L)
return solveOOQP(Q; settings=settings)
end

#L == ±Inf, using LP to find HMEP LMEP
min = L == Inf ? false : true
x, status = mpcLP(q, A, b, C, g; settings=settings, min=min)
Expand Down

2 comments on commit 4ec73ed

@PharosAbad
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/82342

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.0.9 -m "<description of version>" 4ec73ed4c2d946a79fab96e418a1b06d2448183f
git push origin v1.0.9

Please sign in to comment.