Evaluating Wealth: Result Class
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The AlgoResult class is the primary mechanism for evaluating the performance of Online Portfolio Selection (OLPS) algorithms. It centralizes the calculation of portfolio wealth, transaction costs, risk metrics, and visualization tools. By consuming price relatives and portfolio weights generated by an algorithm's run method, it provides a standardized interface for financial analysis.
Within the project architecture, AlgoResult acts as the output container for all strategy simulations. It transforms raw weight allocations into actionable insights such as Sharpe ratios, drawdowns, and turnover metrics, allowing for direct comparison between different trading strategies and benchmarks like the Uniform Constant Rebalanced Portfolio (UCRP).
Sources: universal/result.py:28-38, README.md:10-15, universal/algo.py:141-143
Core Performance Metrics
The AlgoResult class implements a comprehensive suite of financial indicators to assess both absolute and risk-adjusted returns.
Wealth and Return Calculation
The class calculates the daily returns (r) by taking the dot product of price relatives and portfolio weights, adjusted for risk-free rates and transaction fees.
| Metric | Description | Logic |
|---|---|---|
| Total Wealth | The final value of the portfolio at the end of the simulation. | Product of all periodic returns. |
| Annualized Return | The geometric mean return scaled to a yearly frequency. | (r.mean() - 1) * frequency |
| Growth Rate | The average logarithmic return of the portfolio. | log(r).mean() * frequency |
| Profit Factor | Ratio of gross gains to gross losses. | sum(log_gains) / sum(abs(log_losses)) |
Sources: universal/result.py:108-111, universal/result.py:133-138, universal/result.py:141-143, universal/result.py:192-194
Risk and Volatility
Risk assessment is primarily handled through standard deviation and drawdown analysis.
- Sharpe Ratio: Calculated using annualized log returns. It accounts for a risk-free rate and frequency (defaulting to 252 for daily data).
- Max Drawdown: Represents the maximum peak-to-trough decline in the portfolio's equity curve.
- Ulcer Index: Measures the depth and duration of drawdowns to quantify "stress" or "discomfort."
- Annualized Volatility: The standard deviation of logarithmic returns scaled by the square root of the frequency.
Sources: universal/result.py:149-152, universal/result.py:183-185, universal/result.py:196-198, universal/result.py:210-212
Data Flow and Recalculation Logic
The class employs a _recalculate method that is triggered whenever key inputs—such as prices (X), weights (B), risk-free rates, or fees—are updated.
The diagram shows how raw algorithm outputs are processed through the result class to produce performance metrics.
Sources: universal/result.py:90-111
Transaction Costs and Rebalancing
The AlgoResult class handles transaction costs through a fee property, which can be a single float or a series for individual assets.
Rebalancing Logic
Transaction costs are calculated based on the difference between the target weights for the next period and the "held" weights (how current weights changed due to price movements).
- Turnover: Total rebalancing volume divided by the number of years in the simulation.
- Special Cases: Specific logic is included for Close-to-Open (
_CO) and Open-to-Close (_OC) rebalancing, where rebalancing is assumed to occur twice, effectively doubling the transaction impact for those specific columns.
Sources: universal/result.py:218-232, universal/result.py:234-239, universal/tools.py:840-853
Benchmarking and Comparison
AlgoResult supports benchmarking against standard strategies, primarily the Uniform Constant Rebalanced Portfolio (UCRP).
Benchmark Integration
- Information Ratio: Measures the active return of the portfolio relative to the benchmark return, adjusted for the volatility of those active returns.
- CAPM Analysis: Utilizes
tools.capmto compute Alpha and Beta against a benchmark or market proxy. - Appraisal Ratio: calculated as Alpha divided by the standard deviation of residuals.
Sources: universal/result.py:187-201, universal/result.py:254-265, universal/result.py:277-284
ListResult Class
For comparing multiple strategies, the ListResult class acts as a container for multiple AlgoResult objects.
| Feature | Description |
|---|---|
| Summary Table | Aggregates summary statistics for all contained strategies. |
| Combined Plot | Overlays equity curves of all strategies, including optional UCRP and Buy-And-Hold (BAH) baselines. |
| Pickle Support | Inherits PickleMixin to save/load multiple results as a single file. |
Sources: universal/result.py:440-445, universal/result.py:495-510
Visualization Tools
The class provides integrated plotting capabilities using matplotlib and seaborn.
plotmethod: Generates a multi-panel visualization. The top panel displays the equity curve of the portfolio alongside assets, while the bottom panel shows portfolio weights (either as lines or a stacked area chart).- Weight Importance: Includes logic to show only "important" assets (top 20) to prevent cluttered visualizations in large portfolios.
plot_total_weights: specifically visualizes the latest weight allocation and the historical sum of weights to identify dominant assets.
Sources: universal/result.py:348-375, universal/result.py:417-425
Conclusion
The AlgoResult class is the analytical engine of the universal-portfolios library. It ensures that algorithm performance is not just a theoretical wealth figure but a nuanced evaluation involving risk adjustment, transaction cost modeling, and comparative benchmarking. Its tight integration with the Algo base class and the tools module provides a seamless pipeline from strategy execution to detailed financial reporting.
Sources: universal/result.py:28-35, universal/algo.py:141-143