Skip to content

Commit

Permalink
Merge pull request #83 from shayandavoodii:CORN-modification
Browse files Browse the repository at this point in the history
Modify CORN
  • Loading branch information
shayandavoodii authored Mar 6, 2024
2 parents c907d7b + 8c364b4 commit 65933a6
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 74 deletions.
53 changes: 29 additions & 24 deletions docs/src/PM.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,34 @@ julia> prices = prices |> permutedims;
# run the algorithm on the last 5 days
julia> horizon, w = 5, 10

julia> rel_prices = prices[:, 2:end] ./ prices[:, 1:end-1]

julia> model = cornu(prices, horizon, w)
julia> model = cornu(rel_prices, horizon, w)

julia> model.b
5×5 Matrix{Float64}:
0.0 0.198536 0.0995612 0.0 0.0
0.0 0.389272 0.0 0.0 0.0980504
0.0 0.0 0.430479 0.0998267 0.0
0.714743 0.0 0.0 0.0 0.203183
0.285257 0.412192 0.46996 0.900173 0.698766
0.759879 0.37932 0.518244 0.841716 0.538972
0.0600301 0.0798703 0.0198005 0.0395709 0.0397726
0.0600301 0.0798703 0.0198005 0.0395709 0.0397726
0.0600301 0.0798703 0.0198005 0.0395709 0.0397726
0.0600301 0.381069 0.422354 0.0395709 0.34171
```

One can compute the cumulative wealth during the investment period by using the [`sn`](@ref) function:

```julia
julia> rel_price = prices[:, 2:end] ./ prices[:, 1:end-1];

julia> sn(model.b, rel_price)
julia> sn(model.b, rel_prices)
6-element Vector{Float64}:
1.0
0.9910701218600744
0.9956345799968089
1.0038929232387375
0.9914403615208097
0.9851289224781754
0.9874863981778458
0.9867337486209383
0.997125392069827
0.9899191819701306
0.9791598729100073
```

The result indicates that the algorithm experienced a loss of 1.5% of the initial wealth during the investment period. Further analysis of the algorithm's performance can be conducted using the [`mer`](@ref), [`ir`](@ref), [`apy`](@ref), [`ann_sharpe`](@ref), [`ann_std`](@ref), [`calmar`](@ref), and [`mdd`](@ref) functions. For more detailed information, refer to the [Performance evaluation](@ref) section.
The result indicates that the algorithm experienced a loss of ~2% of the initial wealth during the investment period. Further analysis of the algorithm's performance can be conducted using the [`mer`](@ref), [`ir`](@ref), [`apy`](@ref), [`ann_sharpe`](@ref), [`ann_std`](@ref), [`calmar`](@ref), and [`mdd`](@ref) functions. For more detailed information, refer to the [Performance evaluation](@ref) section.

### Run CORN-K

Expand All @@ -67,27 +68,31 @@ The key parameters of CORN-K include `k` (number of best experts used for portfo
# run the algorithm on the last 5 days
julia> horizon, k, w, rho = 5, 10, 5, 5, 5;

julia> model = cornk(prices, horizon, k, w, rho);
julia> model = cornk(rel_prices, horizon, k, w, rho);

julia> model.b
5×5 Matrix{Float64}:
0.679862 0.279356 0.681348 0.581841 0.678181
0.0800344 0.0798487 0.0796631 0.0795637 0.079953
0.0800344 0.0798487 0.0796631 0.0795637 0.079953
0.0800344 0.0798487 0.0796631 0.0795637 0.079953
0.0800344 0.481098 0.0796631 0.179468 0.0819602
```

Last but not least, the cumulative wealth of the algorithm on the investment period and given dataset can be computed by using the [`sn`](@ref) function:

```julia
julia> rel_price = prices[:, 2:end] ./ prices[:, 1:end-1];

julia> sn(model.b, rel_price)
julia> sn(model.b, rel_prices)
6-element Vector{Float64}:
1.0
0.9920219584145965
0.997769753240107
1.0153550964116513
1.004610801506029
1.0017637293758395
0.9875572675972655
0.9873565694624061
0.9913102075729211
0.9827281883555271
0.9722491752324016
```

Expectedly, CORN-K performed better than CORN-U on the same dataset. The result indicates that the algorithm has gained ~0.18% of the initial wealth during the investment period. Further analysis of the algorithm can be done by using the [`mer`](@ref), [`ir`](@ref), [`apy`](@ref), [`ann_sharpe`](@ref), [`ann_std`](@ref), [`calmar`](@ref), and [`mdd`](@ref) functions. See [Performance evaluation](@ref) section for more information.
Expectedly, CORN-K performed better than CORN-U on the same dataset. The result indicates that the algorithm has lost ~3.1% of the initial wealth during the investment period. Further analysis of the algorithm can be done by using the [`mer`](@ref), [`ir`](@ref), [`apy`](@ref), [`ann_sharpe`](@ref), [`ann_std`](@ref), [`calmar`](@ref), and [`mdd`](@ref) functions. See [Performance evaluation](@ref) section for more information.

## Dynamic RIsk CORrelation-driven Non-parametric (DRICORN)

Expand Down
10 changes: 5 additions & 5 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ julia> pr = CSV.read("data\\sp500.csv", DataFrame) |> Matrix |> permutedims;

julia> pr = pr[2:end, :];

# calculate the relative prices
julia> rel_pr = pr[:, 2:end] ./ pr[:, 1:end-1];

julia> market_pr = pr[1, :];

julia> rel_pr_market = market_pr[2:end] ./ market_pr[1:end-1];
Expand All @@ -90,19 +93,16 @@ julia> size(pr)
The dataset encompasses adjusted close prices of 24 stocks in the S&P 500 across 1276 trading days. Suppose we aim to apply the strategies to the most recent 50 days of the dataset using default arguments:

```julia
julia> m_corn_u = cornu(pr, 50, 3);
julia> m_corn_u = cornu(rel_pr, 50, 3);

julia> m_corn_k = cornk(pr, 50, 3, 2, 2);
julia> m_corn_k = cornk(rel_pr, 50, 3, 2, 2);

juila> m_drcorn_k = dricornk(pr, market_pr, 50, 5, 5, 5);
```

Next, let's visualize the daily cumulative budgets' trends for each algorithm. To do this, we'll need to compute them by utilizing the attained portfolio weights and relative prices within the same time period.

```julia
# calculate the relative prices
julia> rel_pr = pr[:, 2:end] ./ pr[:, 1:end-1];

julia> models = [m_corn_u, m_corn_k, m_drcorn_k];

# calculate the cumulative wealth for each algorithm
Expand Down
81 changes: 36 additions & 45 deletions src/Algos/CORN.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
"""
cornu(
adj_close::Matrix{T},
x::AbstractMatrix{T},
horizon::M,
w::M;
rho::T=0.2,
init_budg=1,
progress::Bool=false
) where {T<:Float64, M<:Int}
) where {T<:AbstractFloat, M<:Integer}
Run CORN-U algorithm.
# Arguments
- `adj_close::Matrix{T}`: Adjusted close prices of assets.
- `x::AbstractMatrix{T}`: price relative matrix of assets.
- `horizon::M`: The number of periods to invest.
- `w::M`: maximum length of time window to be examined.
Expand All @@ -21,18 +21,18 @@ Run CORN-U algorithm.
- `progress::Bool=false`: Whether to show the progress bar.
!!! warning "Beware!"
`adj_close` should be a matrix of size `n_assets` × `n_periods`.
`x` should be a matrix of size `n_assets` × `n_periods`.
# Returns
- `::OPSAlgorithm(n_assets, b, alg)`: An object of type `OPSAlgorithm`.
- `::OPSAlgorithm`: An object of type [`OPSAlgorithm`](@ref).
# Examples
```julia
julia> using OnlinePortfolioSelection
julia> adj_close = rand(5, 100);
julia> x = rand(5, 100);
julia> model = cornu(adj_close, 10, 5, 0.5);
julia> model = cornu(x, 10, 5, 0.5);
julia> model.alg
"CORN-U"
Expand All @@ -47,32 +47,27 @@ See [`cornk`](@ref), and [`dricornk`](@ref).
> [CORN: Correlation-driven nonparametric learning approach for portfolio selection](https://doi.org/10.1145/1961189.1961193)
"""
function cornu(
adj_close::Matrix{T},
x::AbstractMatrix{T},
horizon::M,
w::M;
rho::T=0.2,
init_budg=1,
progress::Bool=false
) where {T<:Float64, M<:Int}

) where {T<:AbstractFloat, M<:Integer}
n_assets, _ = size(x)
0rho<1 || ArgumentError("The value of `rho` should be in the range of [0, 1).") |> throw
n_experts = w

# Calculate relative prices
relative_prices = adj_close[:, 2:end] ./ adj_close[:, 1:end-1]
n_assets = size(relative_prices, 1)
q = 1/w

n_experts = w
q = 1/w
# Store the budgets of experts in each period t
Sₜ_ = zeros(T, n_experts, horizon+1)
Sₜ_[:, 1] .= init_budg
weights = zeros(T, n_assets, horizon)
bₜ = similar(x, n_assets, n_experts)
for t 0:horizon-1
bₜ = Matrix{T}(undef, n_assets, n_experts)
for ω 1:w
b = corn_expert(relative_prices, horizon, ω, rho, t, n_assets)
b = corn_expert(x, horizon, ω, rho, t, n_assets)
bₜ[:, ω] = b
Sₜ_[ω, t+2] = S(Sₜ_[ω, t+1], b, relative_prices[:, end-horizon+t+1])
Sₜ_[ω, t+2] = S(Sₜ_[ω, t+1], b, x[:, end-horizon+t+1])
end
progress && progressbar(stdout, horizon, t+1)
weights[:, t+1] = final_weights(q, Sₜ_[:, t+2], bₜ)
Expand All @@ -83,19 +78,19 @@ end

"""
cornk(
adj_close::Matrix{Float64},
x::AbstractMatrix{<:AbstractFloat},
horizon::T,
k::T,
w::T,
p::T;
init_budg=1,
progress::Bool=false
) where T<:Int
) where T<:Integer
Run CORN-K algorithm.
# Arguments
- `adj_close::Matrix{Float64}`: Adjusted close prices of assets.
- `x::AbstractMatrix{<:AbstractFloat}`: price relative matrix of assets.
- `horizon::T`: The number of periods to invest.
- `k::T`: The number of top experts to be selected.
- `w::T`: maximum length of time window to be examined.
Expand All @@ -106,18 +101,18 @@ Run CORN-K algorithm.
- `progress::Bool=false`: Whether to show the progress bar.
!!! warning "Beware!"
`adj_close` should be a matrix of size `n_assets` × `n_periods`.
`x` should be a matrix of size `n_assets` × `n_periods`.
# Returns
- `::OPSAlgorithm(n_assets, b, alg)`: An object of type `OPSAlgorithm`.
- `::OPSAlgorithm`: An object of type [`OPSAlgorithm`](@ref).
# Examples
```julia
julia> using OnlinePortfolioSelection
julia> adj_close = rand(5, 100);
julia> x = rand(5, 100);
julia> model = cornk(adj_close, 10, 3, 5, 3);
julia> model = cornk(x, 10, 3, 5, 3);
julia> model.alg
"CORN-K"
Expand All @@ -132,38 +127,34 @@ See [`cornu`](@ref), and [`dricornk`](@ref).
> [CORN: Correlation-driven nonparametric learning approach for portfolio selection](https://doi.org/10.1145/1961189.1961193)
"""
function cornk(
adj_close::Matrix{Float64},
x::AbstractMatrix{<:AbstractFloat},
horizon::T,
k::T,
w::T,
p::T;
init_budg=1,
progress::Bool=false
) where T<:Int

) where T<:Integer
p<2 && ArgumentError("The value of `p` should be more than 1.") |> throw
n_experts = w*(p+1)
k>n_experts && ArgumentError(
"The value of k ($k) is more than number of experts ($n_experts)"
) |> throw

# Calculate relative prices
relative_prices = adj_close[:, 2:end] ./ adj_close[:, 1:end-1]
n_assets = size(relative_prices, 1)
P = (iszero(pᵢ) ? 0. : (pᵢ-1)/pᵢ for pᵢ0:p)
q = 1/k
weights = zeros(Float64, n_assets, horizon)
Sₜ_ = zeros(Float64, n_experts, horizon+1)
Sₜ_[:, 1] .= init_budg
n_assets = size(x, 1)
P = (iszero(pᵢ) ? 0. : (pᵢ-1)/pᵢ for pᵢ0:p)
q = 1/k
weights = similar(x, n_assets, horizon)
Sₜ_ = similar(x, n_experts, horizon+1)
Sₜ_[:, 1] .= init_budg
bₜ = similar(x, n_assets, n_experts)
for t 0:horizon-1
bₜ = Matrix{Float64}(undef, n_assets, n_experts)
expert = 1
for ω 1:w
for ρ P
b = corn_expert(relative_prices, horizon, ω, ρ, t, n_assets)
b = corn_expert(x, horizon, ω, ρ, t, n_assets)
bₜ[:, expert] = b
Sₜ_[expert, t+2] = S(
Sₜ_[expert, t+1], b, relative_prices[:, end-horizon+t+1]
Sₜ_[expert, t+1], b, x[:, end-horizon+t+1]
)
expert += 1
end
Expand All @@ -185,7 +176,7 @@ end
rho::T,
t::S,
n_assets::S
) where {T<:Float64, S<:Int}
) where {T<:AbstractFloat, S<:Int}
Create an expert to perform the algorithm according to the given parameters.
Expand All @@ -198,7 +189,7 @@ Create an expert to perform the algorithm according to the given parameters.
- `n_assets::S`: number of assets.
# Returns
- `::Vector{Float64}`: Weights of assets.
- `::Vector{AbstractFloat}`: Weights of assets.
"""
function corn_expert(
relative_prices::Matrix{T},
Expand All @@ -207,7 +198,7 @@ function corn_expert(
rho::T,
t::S,
n_assets::S
) where {T<:Float64, S<:Int}
) where {T<:AbstractFloat, S<:Int}

horizonsize(relative_prices, 2) && ArgumentError("""The "horizon" ($horizon) is \
bigger than data samples $(size(relative_prices, 2)).\nYou should either decrease \
Expand Down

0 comments on commit 65933a6

Please sign in to comment.