Anticorrelation (Anticor)
Relevant source files
The following files were used as context for generating this wiki page:
Anticorrelation (Anticor) is a heuristic online portfolio selection algorithm implemented within the universal-portfolios library. It operates on the principle of mean reversion, specifically adopting the consistency of positive lagged cross-correlation and negative autocorrelation to adjust portfolio weights. Unlike some other algorithms in the library, Anticor is not mathematically proven to be a "universal" portfolio (i.e., it has no known performance bounds relative to the Best Constant Rebalanced Portfolio), but it has demonstrated strong empirical results in historical trading simulations.
Within the project architecture, Anticor inherits from the base Algo class, which provides the standardized interface for all portfolio selection strategies. It utilizes rolling statistics calculated via utility tools to determine "claims" between assets—essentially deciding how much capital should be transferred from an outperforming asset to an underperforming one based on their correlation patterns.
Sources: universal/algos/anticor.py:11-23, README.md:41-52, universal/algo.py:14-25
Architecture and Class Hierarchy
Anticor is part of the "Follow the Loser" category of strategies in the universal-portfolios package. It leverages the core Algo framework to process price relative data and output a sequence of portfolio weights.
The diagram above shows the inheritance relationship where Anticor specializes the weights method to implement its specific logic.
Sources: universal/algos/anticor.py:11, universal/algo.py:14, README.md:45
Algorithm Logic and Data Flow
The Anticor algorithm operates by examining two consecutive windows of price relatives. It identifies assets that have performed well in the recent past and transfers their weights to assets that have performed poorly, provided there is a positive cross-correlation between them.
Transfer Mechanism
- Correlation Calculation: The algorithm calculates rolling correlations and expected returns (
EX) using a specified window. - Claim Determination: For every pair of stocks $(i, j)$, a "claim" is created from stock $i$ to stock $j$ if stock $i$ has higher average returns than $j$ and they are positively correlated.
- Self-Correction: Claims are increased if an asset shows negative autocorrelation (indicating it is likely to revert).
- Weight Update: The weights for the next period are adjusted by summing all incoming transfers and subtracting all outgoing transfers.
The logic flow identifies how the algorithm iterates through time to redistribute wealth across the portfolio.
Sources: universal/algos/anticor.py:31-71, universal/tools.py:273-298
Key Implementation Details
Configuration Parameters
Anticor provides two primary initialization parameters to control its behavior and performance.
| Parameter | Type | Default | Description |
|---|---|---|---|
window | int | 30 | The size of the lookback window for calculating correlations and means. |
c_version | bool | True | Flag to enable the optimized C implementation (via scipy.weave) for a ~10x speedup. |
Sources: universal/algos/anticor.py:25-30
Performance Optimization
Because the triple-nested loops (time, asset $i$, asset $j$) required for Anticor are computationally expensive in pure Python, the implementation includes a C-based version. If scipy.weave is available, the algorithm executes an inline C block to perform the weight updates. If the C extension is unavailable (e.g., in most Python 3 environments where weave was deprecated), the algorithm falls back to a standard Python loop.
# universal/algos/anticor.py:37-45
if self.c_version:
try:
from scipy import weave
except ImportError:
warnings.warn(
"scipy.weave is not available in python3, falling back to python version"
)
self.c_version = False
Sources: universal/algos/anticor.py:37-45, universal/algos/anticor.py:73-120
Integration with the Results System
Once Anticor.run(S) is called, the weights generated are passed to the AlgoResult class. This class is responsible for calculating financial metrics such as the Sharpe ratio, maximum drawdown, and turnover based on the specific weights provided by the Anticor strategy.
| Metric | Derivation |
|---|---|
| Total Wealth | Product of daily returns $r_t = \sum (X_t \cdot B_t)$. |
| Turnover | Calculated by tools.to_rebalance comparing $B_t$ with previous holdings. |
| Fees | Applied to the rebalancing amount based on the fee parameter in AlgoResult. |
Sources: universal/result.py:30-90, universal/tools.py:612-622
Conclusion
Anticor serves as a powerful mean-reversion heuristic within the universal-portfolios library. By leveraging cross-correlation and autocorrelation, it attempts to capture market reversals. Its implementation is tightly integrated with the project's utility tools for correlation calculation and the results framework for performance analysis, providing an optimized C-fallback path for high-performance backtesting.