You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Decoupled `rebalance_freq` and `reopt_freq` enabling users to customize the portfolio style. Also refactored `Backtester` class for better readability.
Updated documentation and Readme with changes.
Copy file name to clipboardExpand all lines: README.md
+7-14Lines changed: 7 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,6 +12,12 @@ Visit the [documentation](https://opes.pages.dev) for detailed insights on OPES.
12
12
13
13
---
14
14
15
+
## Project Methodology
16
+
17
+
This project follows an Agile development approach. Every feature is designed to be extensible, exploratory and open to modification as the system evolves. Each GitHub commit represents a usable and coherent version of OPES. While not every commit is feature-complete or fully refined, each serves as a stable minimum viable product and a reliable snapshot of progress. Features marked as *experimental* are subject to active evaluation and will be either validated and promoted or removed entirely based on feasibility and empirical performance.
18
+
19
+
---
20
+
15
21
## Disclaimer
16
22
17
23
The information provided by OPES is for educational, research and informational purposes only. It is not intended as financial, investment or legal advice. Users should conduct their own due diligence and consult with licensed financial professionals before making any investment decisions. OPES and its contributors are not liable for any financial losses or decisions made based on this content. Past performance is not indicative of future results.
@@ -191,17 +197,4 @@ This will run three scripts, each dedicated to testing the optimizer, regularize
191
197
GOOG, AAPL, AMZN, MSFT
192
198
```
193
199
194
-
The price data is stored in the `prices.csv` file within the `tests/` directory. The number of tickers are limited to 4 since there are computationally heavy portfolio objectives (like `UniversalPortfolios`) included which may take an eternity to test well using multiple tickers.
195
-
196
-
Also it eats up RAM like pac-man.
197
-
198
-
---
199
-
200
-
## Upcoming Features (Unconfirmed)
201
-
202
-
These features are still in the works and may or may not appear in later updates:
The price data is stored in the `prices.csv` file within the `tests/` directory. The number of tickers are limited to 4 since there are computationally heavy portfolio objectives (like `UniversalPortfolios`) included which may take an eternity to test well using multiple tickers.
Copy file name to clipboardExpand all lines: docs/docs/backtesting.md
+39-24Lines changed: 39 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -71,33 +71,33 @@ It also stores transaction cost parameters for portfolio simulations.
71
71
```python
72
72
defbacktest(
73
73
optimizer,
74
-
rebalance_freq=None,
75
-
seed=None,
74
+
rebalance_freq=1,
75
+
reopt_freq=1,
76
+
seed=100,
76
77
weight_bounds=None,
77
78
clean_weights=False
78
79
)
79
80
```
80
81
81
82
Execute a portfolio backtest over the test dataset using a given optimizer.
82
83
83
-
This method performs either a static-weight backtest or a rolling-weight
84
-
backtest depending on whether `rebalance_freq` is specified. It also
85
-
applies transaction costs and ensures no lookahead bias during rebalancing.
84
+
This method performs a walk-forward backtest using the user defined `rebalance_freq`
85
+
and `reopt_freq`. It also applies transaction costs and ensures no lookahead bias.
86
86
For a rolling backtest, any common date values are dropped, the first occurrence
87
87
is considered to be original and kept.
88
88
89
89
!!! warning "Warning:"
90
90
Some online learning methods such as `ExponentialGradient` update weights based
91
-
on the most recent observations. Setting `rebalance_freq` to any value other
92
-
than `1` (or possibly `None`) may result in suboptimal performance, as
93
-
intermediate data points will be ignored and not used for weight updates.
94
-
Proceed with caution when using other rebalancing frequencies with online learning algorithms.
91
+
on the most recent observations. Setting `reopt_freq` to any value other
92
+
than `1` may result in suboptimal performance, as intermediate data points will
93
+
be ignored and not used for weight updates.
95
94
96
95
**Args:**
97
96
98
97
-`optimizer`: An optimizer object containing the optimization strategy. Accepts both OPES built-in objectives and externally constructed optimizer objects.
99
-
-`rebalance_freq` (*int or None, optional*): Frequency of rebalancing (re-optimization) in time steps. If `None`, a static weight backtest is performed. Defaults to `None`.
100
-
-`seed` (*int or None, optional*): Random seed for reproducible cost simulations. Defaults to `None`.
98
+
-`rebalance_freq` (*int, optional*): Frequency of rebalancing in time steps. Must be `>= 1`. Defaults to `1`.
99
+
-`reopt_freq` (*int, optional*): Frequency of re-optimization in time steps. Must be `>= 1`. Defaults to `1`.
100
+
-`seed` (*int or None, optional*): Random seed for reproducible cost simulations. Defaults to `100`.
101
101
-`weight_bounds` (*tuple, optional*): Bounds for portfolio weights passed to the optimizer if supported.
102
102
103
103
!!! abstract "Rules for `optimizer` Object"
@@ -107,33 +107,44 @@ is considered to be original and kept.
107
107
- `**kwargs`: For safety against breaking changes.
108
108
- `optimize` must output weights for the timestep.
109
109
110
+
!!! note "Note"
111
+
- Re-optimization does not automatically imply rebalancing. When the portfolio is re-optimized at a given timestep, weights may or may not be updated depending on the value of `rebalance_freq`.
112
+
- To ensure a coherent backtest, a common practice is to choose frequencies such that `reopt_freq % rebalance_freq == 0`. This guarantees that whenever optimization occurs, a rebalance is also performed.
113
+
- Also note that within a given timestep, rebalancing, if it occurs, is performed after optimization when optimization is scheduled for that timestep.
114
+
115
+
!!! tip "Tip"
116
+
Common portfolio styles can be constructed by appropriate choices of `rebalance_freq` and `reopt_freq`:
-`dict`: Backtest results containing the following keys:
113
125
-`'returns'` (*np.ndarray*): Portfolio returns after accounting for costs.
114
126
-`'weights'` (*np.ndarray*): Portfolio weights at each timestep.
115
127
-`'costs'` (*np.ndarray*): Transaction costs applied at each timestep.
116
-
-`'dates'` (*np.ndarray*): Dates on which the backtest was conducted.
128
+
-`'timeline'` (*np.ndarray*): Timeline on which the backtest was conducted.
117
129
118
130
**Raises**
119
131
120
132
-`DataError`: If the optimizer does not accept weight bounds but `weight_bounds` are provided.
121
133
-`PortfolioError`: If input validation fails (via `_backtest_integrity_check`).
134
+
-`OptimizationError`: If the underlying optimizer uses optimization and if it fails to optimize.
122
135
123
136
124
137
!!! note "Notes:"
125
138
- All returned arrays are aligned in time and have length equal to the test dataset.
126
-
- Static weight backtest: Uses a single set of optimized weights for all test data. This denotes a constant rebalanced portfolio.
127
-
- Rolling weight backtest: Re-optimizes weights at intervals defined by `rebalance_freq` using only historical data up to the current point to prevent lookahead bias.
128
139
- Returns and weights are stored in arrays aligned with test data indices.
129
140
130
141
!!! example "Example:"
131
142
```python
132
143
import numpy as np
133
144
134
145
# Importing necessary OPES modules
135
-
from opes.objectives.utility_theory import Kelly
136
-
from opes.backtester import Backtester
146
+
from opes.objectives import Kelly
147
+
from opes import Backtester
137
148
138
149
# Place holder for your price data
139
150
from some_random_module import trainData, testData
@@ -149,7 +160,11 @@ is considered to be original and kept.
We use `rebalance_freq=1` so we can see how the portfolio adapts to changes quickly. `seed=100` gaurantees reproducibility and Gamma slippage captures asymmetric execution costs where extreme liquidity events are rare but painful. After obtaining `return_scenario` we can get the metrics and plot wealth.
107
+
We use `rebalance_freq=1`and `reopt_freq=1`so we can see how the portfolio adapts to changes quickly. `seed=100` gaurantees reproducibility and Gamma slippage captures asymmetric execution costs where extreme liquidity events are rare but painful. After obtaining `return_scenario` we can get the metrics and plot wealth.
Since uniform equal weight has constant weights, regardless of test and train data, we can use any backtester to obtain returns. Here we use `tester_in_sample`.
Copy file name to clipboardExpand all lines: docs/docs/examples/which_kelly_is_best.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ The Kelly Criterion, proposed by John Larry Kelly Jr., is the mathematically opt
6
6
There are numerous variants of the Kelly Criterion introduced to combat this fragile dependency, such as fractional Kelly, popularized by Ed Thorpe, and distributionally robust Kelly models. In this example, we compare several of the most well-known Kelly variants under identical out-of-sample conditions, evaluating their realized performance and wealth dynamics using `opes`.
7
7
8
8
!!! warning "Warning:"
9
-
This example may be computationally heavy because of multiple optimization models running with a low `rebalance_freq=5`. If you prefer better performance, increase `rebalance_freq` to monthly (`21`) or any value much greater than `5`.
9
+
This example may be computationally heavy because of multiple optimization models running with a low `reopt_freq=5`. If you prefer better performance, increase `reopt_freq` to monthly (`21`) or any value much greater than `5`.
10
10
11
11
---
12
12
@@ -121,20 +121,20 @@ for distributionally robust variants, we utilize `KLradius` for the ambiguity ra
121
121
122
122
## Backtesting
123
123
124
-
Using the `Backtester` class from `opes`, we backtest these strategies under a constant, but high, cost of 20 bps and `rebalance_freq=5` (weekly). Oh, and we clean weights too.
124
+
Using the `Backtester` class from `opes`, we backtest these strategies under a constant, but high, cost of 20 bps and `reopt_freq=5` (weekly). `rebalance_freq` is defaulted to `1`. Oh, and we clean weights too.
0 commit comments