This Python package brings together Online Portfolio Selection (OLPS) algorithms from the literature, implemented faithfully to their papers and run under one interface, so that they can be compared and their claims checked.
In short, OLPS algorithms choose portfolio weights in every period to maximize final wealth. Examples include the Markowitz portfolio and the Universal portfolio. Many papers in this field report spectacular backtests. The point of this package is to make it easy to see how much of that survives a closer look. Contributions and corrections are more than welcome.
The results you get from these algorithms on the bundled datasets say very little about how they would do with real money.
- The datasets only contain survivors. NYSE(O), NYSE(N), DJIA, SP500 and TSE are the standard stock benchmarks of the OLPS literature (MSCI holds country indices). They include only stocks that traded every day of the period: none went bankrupt or was delisted. Some are also picked in hindsight. SP500 is the 25 stocks with the largest market cap in April 2003, after the period ends, and NYSE(N) keeps 23 of NYSE(O)'s 36 stocks. The Anticor paper (p. 592), CWMR (§5.5) and OLMAR (§5.5) acknowledge this. Many later papers, such as PPT and SSPO, don't mention it.
- Survivor-only data hides the main risk of "follow the loser" algorithms. OLMAR, PAMR, PPT, SSPO and the like move money into stocks that just fell. Survivor-only data still has stocks that fall a long way, but none that fall all the way and get delisted, so these algorithms never meet one.
examples/survivorship_bias.ipynbsimulates this on random walks. Survivorship alone doesn't make these algorithms beat uniform CRP. But once stocks can go bankrupt, they keep buying into the collapsing ones. Even when only 1–7% of the stocks go bankrupt, OLMAR, PAMR and PPT end with 46–76% of CRP's wealth, against 84–94% on survivors, while buy-and-hold loses less than CRP. - Transaction costs. Most headline numbers assume rebalancing for free at the daily close. The mean-reversion algorithms trade most of their wealth every day. PPT, for example, falls behind uniform CRP at fees of 0.14–0.6% per unit traded on the bundled datasets, and SSPO at 0.5% round trip ends below CRP on SP500. Set
result.feebefore believing any number. - Parameters are often tuned on the same data. PPT's step size and four of SSPO's five parameters were chosen by final wealth on the same five datasets the papers then report, with no out-of-sample period.
- Independent re-tests are discouraging. On recent S&P 500 stocks, Moon et al. (2019) find that OLMAR and PAMR lose almost everything at 0.25% costs.
Use this package to study the algorithms and their failure modes, not to pick a trading strategy.
-
Python notebooks:
- Online Portfolios: explains the basic use of the library. Script sequence, various options, method arguments, and a strategy template to get you started.
- Modern Portfolio Theory: goes deeper into the OLPS principle and the tools developed in this library to approach it.
- Survivorship bias: what survivor-only datasets hide about mean-reversion algorithms, on simulated data.
-
universal.datacontains various datasets to help you in your journey. -
universal.algoshosts the implementations of various OLPS algorithms from the literature:
| Benchmarks | Follow the winner | Follow the loser | Pattern matching | Other |
|---|---|---|---|---|
| BAH | Universal Portfolios | Anticorr | BNN | Markowitz |
| CRP | Exponential Gradient | PAMR | CORN | Kelly |
| BCRP | Soft-Bayes | OLMAR | Best so far | |
| DCRP | AdaHedge | RMR | ONS | |
| CWMR | MPT | |||
| WMAMR | ||||
| RPRT | ||||
| PPT | ||||
| SSPO |
-
universal.algoprovides a general class inherited by all the individual algos' subclasses. Algo computes the weights at every timestep. -
universal.resultcomputes the portfolio wealth from the weights and various metrics on the strategy's performance.
from universal import tools
from universal.algos import CRP
if __name__ == '__main__':
# Run CRP on a computer-generated portfolio of 3 stocks and plot the results
tools.quickrun(CRP())If you do not know what an online portfolio is, look at Ernest Chan's blog, CASTrader, or a recent survey by Bin Li and Steven C. H. Hoi.
Paul Perry followed up on this and made a comparison of all algorithms on more recent ETF datasets. The original authors of some of the algorithms recently published their own implementation on GitHub - Online Portfolio Selection Toolbox in MATLAB.
If you are more into R or just looking for a good resource about Universal Portfolios, check out the blog and package logopt by Marc Delvaux.
Note: If you don't want to install the package locally, you can run both notebooks with Binder - modern-portfolio-theory.ipynb or On-line portfolios.ipynb
pip install universal-portfolios
Set up .venv, install dependencies and run tests with:
make test
Creator: Marigold
Thank you for your contributions!
Alexander Myltsev | angonyfox | booxter | dexhunter | DrPaprikaa | paulorodriguesxv | stergnator | Xander Dunn
This software is for educational purposes only and is far from any production environment. Do not risk money you are afraid to lose. Use the software at your own risk. The authors assume no responsibility for your trading results.