On-Line Moving Average Reversion (OLMAR)
Relevant source files
The following files were used as context for generating this wiki page:
On-Line Moving Average Reversion (OLMAR) is a technical trading strategy implemented within the universal-portfolios project. It belongs to the "Follow the Loser" category of Online Portfolio Selection (OLPS) algorithms. The primary goal of OLMAR is to exploit the mean reversion property of asset prices by using moving averages to predict future price relatives and adjusting portfolio weights accordingly to maximize final wealth.
Sources: README.md:37, universal/algos/olmar.py:10-15
Architecture and Core Logic
OLMAR is implemented as a class inheriting from the base Algo class. It operates by processing asset price history at each time step to generate a prediction of the next period's price relative. This prediction is then used to update the portfolio weights through a optimization process that satisfies a minimum return constraint while staying as close as possible to the previous weights.
Sources: universal/algos/olmar.py:10, universal/algo.py:19
Component Relationship
The following diagram illustrates the relationship between OLMAR and other system components:
This diagram shows that OLMAR inherits from the base Algo class and serves as a parent for more specialized mean reversion strategies like RMR (Robust Median Reversion) and WMAMR (Weighted Moving Average Passive Aggressive).
Sources: universal/algos/olmar.py:10, universal/algos/rmr.py:20, universal/algos/wmamr.py:12
Algorithmic Flow
The OLMAR algorithm follows a sequence of prediction and weight updating at every time step.
Step-by-Step Execution
- Price Prediction: Depending on the
ma_type, the algorithm calculates either a Simple Moving Average (SMA) or an Exponential Moving Average (EMA) to estimate the future price relative. - Constraint Check: It determines the
excess_returnof the predicted price relative against the mean prediction. - Lagrange Multiplier Calculation: It calculates a step size (
lam) based on theepsparameter and the predicted return. - Weight Adjustment: Portfolio weights are shifted toward assets with higher predicted returns.
- Simplex Projection: The new weights are projected onto a simplex to ensure they sum to 1 and are non-negative.
The diagram shows the logic flow from historical data input to the final simplex-projected weight output.
Sources: universal/algos/olmar.py:53-85
Configuration Parameters
OLMAR allows for several tuning parameters to adjust its sensitivity and prediction model.
| Parameter | Type | Default | Description |
|---|---|---|---|
window | int | 5 | The lookback window for calculating the moving average. Must be >= 3. |
eps | float | 10 | The threshold constraint on return for new weights (x * w >= eps). Must be >= 1. |
alpha | float | 0.5 | The decaying factor used when ma_type is set to "EMA". |
ma_type | string | "SMA" | The type of moving average used for prediction ("SMA" or "EMA"). |
Sources: universal/algos/olmar.py:21-36
Implementation Details
Prediction Logic
The prediction logic varies based on the moving average type. For SMA, it uses the ratio of the window mean to the last known price. For EMA, it uses a decaying factor to update the prediction relative to the real price relative.
def predict(self, x, hist):
"""Predict next price relative."""
if self.ma_type == "SMA":
return hist.mean() / hist.iloc[-1, :]
else:
real_x = hist.iloc[-1, :] / hist.iloc[-2, :]
x_pred = self.alpha + (1 - self.alpha) * np.divide(self.x_pred, real_x)
self.x_pred = x_pred
return x_pred
Sources: universal/algos/olmar.py:65-74
Weight Update and Projection
The update method attempts to satisfy the constraint $b \cdot x \ge \epsilon$ while minimizing the distance to previous weights. This often results in a portfolio that rebalances aggressively toward "losers" that are expected to revert. After adjustment, tools.simplex_proj is called to maintain valid portfolio weights.
def update(self, b, x_pred, eps):
x_pred_mean = np.mean(x_pred)
excess_return = x_pred - x_pred_mean
denominator = (excess_return * excess_return).sum()
if denominator != 0:
lam = max(0.0, (eps - np.dot(b, x_pred)) / denominator)
else:
lam = 0
b = b + lam * (excess_return)
return tools.simplex_proj(b)
Sources: universal/algos/olmar.py:77-94, universal/tools.py:465-484
Derived Algorithms
OLMAR serves as a foundation for other strategies in the project:
- Robust Median Reversion (RMR): Extends OLMAR by using a robust L1-median estimator instead of a standard mean for price prediction, controlled by a precision parameter
tau. - Weighted Moving Average Passive Aggressive (WMAMR): Combines OLMAR's mean prediction with the Passive Aggressive Mean Reversion (PAMR) weight update logic.
Sources: universal/algos/rmr.py:20-43, universal/algos/wmamr.py:12-32
Summary
OLMAR is a significant implementation in the universal-portfolios library for exploring mean-reversion strategies. By utilizing moving averages and a constrained optimization approach, it provides a programmatic way to execute "follow the loser" logic in online portfolio management. Its architecture allows it to be easily extended, as seen in the RMR and WMAMR variants.