Best So Far Benchmark
Relevant source files
The following files were used as context for generating this wiki page:
The BestSoFar benchmark is a selection-based algorithm within the universal-portfolios library that identifies and invests in the single asset demonstrating the highest performance over a specified historical window. Unlike sophisticated Online Portfolio Selection (OLPS) strategies like UP or MPT, it serves as a simple performance-chasing benchmark by allocating 100% of the portfolio to the asset with the best trailing returns or Sharpe ratio.
This algorithm inherits from the base Algo class and operates by evaluating price relatives at each time step. It is primarily used to contrast the effectiveness of more complex rebalancing strategies against a naive "winner-takes-all" approach based on historical data.
Sources: universal/algos/best_so_far.py:1-35, universal/algo.py:16-25
Architecture and Implementation
BestSoFar implements a sequential weight calculation logic where the portfolio is concentrated in a single asset at any given time $t$. The algorithm's behavior is governed by the chosen performance metric and the historical window size.
Core Components
The implementation relies on the following structural elements:
- Metric Selection: Supports
return(cumulative product of price relatives) andsharpe(annualized risk-adjusted return). - Windowing: Uses a look-back period $n$ to calculate performance. If $n$ is not provided, the entire available history is used.
- Tie-Breaking: Incorporates a small random noise factor ($10^{-10} \times \text{Gaussian noise}$) to resolve cases where multiple assets have identical performance.
Sources: universal/algos/best_so_far.py:10-33
Logic Flow Diagram
The following diagram illustrates how the step function determines portfolio weights for the next period based on incoming price relatives.
The algorithm uses history.prod() for return-based selection and tools.sharpe for risk-adjusted selection.
Sources: universal/algos/best_so_far.py:22-33, universal/tools.py:382-414
Configuration and Parameters
The BestSoFar class accepts several parameters during initialization to define its benchmarking behavior.
| Parameter | Type | Default | Description |
|---|---|---|---|
n | int | None | The number of trailing days to consider for performance calculation. |
metric | str | "return" | The performance measure used to rank assets ("return" or "sharpe"). |
min_history | int | None | Minimum history required before the algorithm starts selecting specific assets. |
metric_kwargs | dict | {} | Additional arguments passed to the tools.sharpe function (e.g., rf_rate). |
Sources: universal/algos/best_so_far.py:13-17, universal/algo.py:32-37
Data Processing and Calculations
The algorithm operates on "ratio" price types, representing $p_t / p_{t-1}$.
Weight Initialization
Before sufficient history is accumulated, the algorithm defaults to uniform weights.
def init_weights(self, columns):
# use uniform weights until you get enough history
m = len(columns)
return np.ones(m) / m
Sources: universal/algos/best_so_far.py:19-22
Sharpe Ratio Calculation
When metric="sharpe" is used, the algorithm invokes tools.sharpe. This function annualizes the return and standard deviation based on the index frequency.
- Frequency Detection: Automatically determines trading frequency (e.g., 252 for daily) from the index.
- Risk-Free Rate Adjustment: Subtracts the risk-free rate from returns before calculating the ratio.
Sources: universal/tools.py:382-414, universal/tools.py:444-458
Class Relationships
BestSoFar is part of the universal.algos package and inherits from the fundamental Algo interface, which provides the run and weights infrastructure.
Summary
The BestSoFar benchmark provides a baseline for comparing OLPS algorithms against a momentum-based selection strategy. By concentrating wealth in the historically "best" asset, it highlights whether more complex algorithms add value through diversification or sophisticated rebalancing compared to simple performance chasing. Its implementation is concise, leveraging the project's tools module for financial metrics and the Algo base class for sequential simulation.
Sources: universal/algos/best_so_far.py:1-35, universal/result.py:270-300