Skip to content

Introduction

Online Portfolio Selection (OPS) strategies represent trading algorithms that sequentially allocate capital among a pool of assets with the aim of maximizing investment returns. This forms a fundamental issue in computational finance, extensively explored across various research domains, including finance, statistics, artificial intelligence, machine learning, and data mining. Framed within an online machine learning context, OPS is defined as a sequential decision problem, providing a range of advanced approaches to tackle this challenge. These approaches categorize into benchmarks, “Follow-the-Winner” and “Follow-the-Loser” strategies, “Pattern-Matching” based methodologies, and "Meta-Learning" Algorithms [1].

This package offers an efficient implementation of OPS algorithms in Julia, ensuring complete type stability. All algorithms yield an OPSAlgorithm object, permitting inquiries into portfolio weights, asset count, and algorithm names. Presently, 33 algorithms are incorporated, with ongoing plans for further additions. The existing algorithms are as follows:

Note

In the following table, the abbreviations PM, ML, FL, and FW stand for Pattern-Matching, Meta-Learning, Follow the Loser, and Follow the Winner, respectively.

Row №AlgorithmStrategyYearRow №AlgorithmStrategyYear
1CORNPM201118CWMRFL2013
2DRICORN-KPM202019CAEGML2020
3BCRPMarket199120OLDEMPM2023
4UPMarket199121AICTRFW2018
5EGFW199822EGMFW2021
6BSMarket200723TPPTCombined2021
7RPRTFL202024GWRFL2019
8AnticorFL200325ONSMarket2006
91/NMarket-26DMRFL2023
10OLMARFL201227RMRFL2016
11BᴷPM200628SSPOFW2018
12LOADCombined201929WAEGML2020
13MRvolCombined202330MAEGML2022
14ClusLogPM202031SPOLCFL2020
15CW-OGDML202132TCOFL2018
16PAMRFL201233KTPTPM2018
17PPTFW2018

The available methods can be viewed by calling the opsmethods function.

Installation

The latest stable version of the package can be installed by running the following command in the Julia REPL after pressing ]:

julia
pkg> add OnlinePortfolioSelection

or

julia
julia> using Pkg; Pkg.add("OnlinePortfolioSelection")

or even

julia
juila> using Pkg; pkg"add OnlinePortfolioSelection"

The dev version can be installed usint the following command:

julia
pkg> dev OnlinePortfolioSelection

# or

julia> using Pkg; pkg"dev OnlinePortfolioSelection"

Quick Start

The package can be imported by running the following command in the Julia REPL:

julia
julia> using OnlinePortfolioSelection

Multiple strategies can be applied to a given dataset for analysis and comparison of results. The following code snippet demonstrates how to execute these strategies on a provided dataset and compare their outcomes:

julia
juila> using CSV, DataFrames

# read adjusted close prices
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];

julia> size(pr)
(24, 1276)

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(rel_pr, 50, 3);

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
julia> models = [m_corn_u, m_corn_k, m_drcorn_k];

# calculate the cumulative wealth for each algorithm
julia> wealth = [sn(model.b, rel_pr[:, end-49:end]) for model in models];

julia> using Plots

julia> plot(
            wealth, 
            label = ["CORN-U" "CORN-K" "DRICORN-K"], 
            xlabel = "Day", ylabel = "Cumulative return", legend = :bottomleft,
       )

The plot illustrates that the cumulative wealth of CORN-K consistently outperforms the other algorithms. It's important to note that the initial investment for all algorithms is standardized to 1, although this can be adjusted by setting the keyword argument init_budg for each algorithm. Now, let's delve into the performance analysis of the algorithms using prominent performance metrics:

julia
julia> all_metrics = opsmetrics.([m_corn_u.b, m_corn_k.b, m_drcorn_k.b], Ref(rel_pr), Ref(rel_pr_market));

Now, one can embed the metrics in a DataFrame and compare the performance of the algorithms with respect to each other:

julia
julia> using DataFrames

julia> nmodels = length(all_metrics);

julia> comp_algs = DataFrame(
           Algorithm = ["CORN-U", "CORN-K", "DRICORN-K"],
           MER = [all_metrics[i].MER for i = 1:nmodels],
           IR = [all_metrics[i].IR for i = 1:nmodels],
           APY = [all_metrics[i].APY for i = 1:nmodels],
           Ann_Sharpe = [all_metrics[i].Ann_Sharpe for i = 1:nmodels],
           Ann_Std = [all_metrics[i].Ann_Std for i = 1:nmodels],
           Calmar = [all_metrics[i].Calmar for i = 1:nmodels],
           MDD = [all_metrics[i].MDD for i = 1:nmodels],
           AT = [all_metrics[i].AT for i = 1:nmodels],
       )
3×9 DataFrame
 Row │ Algorithm  MER        IR         APY        Ann_Sharpe  Ann_Std   Calmar    MDD        AT        
     │ String     Float64    Float64    Float64    Float64     Float64   Float64   Float64    Float64   
─────┼──────────────────────────────────────────────────────────────────────────────────────────────────
   1 │ CORN-U     0.0514619  0.0963865  -0.126009   -0.505762  0.288691  -1.25383  0.100499   0.847198
   2 │ CORN-K     0.054396   0.198546    0.826495    2.48378   0.324705  17.688    0.0467263  0.87319
   3 │ DRICORN-K  0.0507907  0.0829576  -0.2487     -1.21085   0.22191   -2.54629  0.0976717  0.0053658

The comparison analysis, via comp_algs, highlights that CORN-K outperforms the other algorithms in terms of annualized percentage yield (APY), annualized Sharpe ratio, Calmar ratio, and maximum drawdown (MDD). However, it's essential to note that the annualized standard deviation of CORN-K surpasses that of the other algorithms within this dataset. These individual metrics can be computed separately by using corresponding functions such as sn, mer, ir. For further insights and details, please refer to the Performance evaluation.

References


Bibliography

  1. B. Li and S. C. Hoi. Online Portfolio Selection: A Survey (2013).