Transaction Cost Optimization (TCO)
Relevant source files
The following files were used as context for generating this wiki page:
Transaction Cost Optimization (TCO) is a specialized online portfolio selection algorithm within the universal-portfolios library designed to maximize final wealth while explicitly accounting for and minimizing transaction costs. Unlike many theoretical Online Portfolio Selection (OLPS) algorithms that assume zero friction, TCO integrates a smoothing parameter and transaction fee percentage directly into its weight update logic to reduce excessive turnover.
The module implements the core TCO logic as a base class and provides concrete implementations (TCO1 and TCO2) that utilize different prediction strategies, such as mean reversion or trend following. It relies on a prediction of the next period's returns to compute an optimal shift in portfolio weights that balances potential gains against the cost of rebalancing.
Sources: universal/algos/tco.py:10-15, README.md:16-18
Core Architecture and Logic
The TCO system follows the standard Algo template of the project but introduces a specific update_tco method. This method adjusts the previous portfolio weights based on predicted returns while applying a "soft thresholding" approach to dampen updates that do not sufficiently outweigh the transaction fees.
TCO Update Process
The update logic calculates the ratio of change in price ($x$) and adjusts the last weights ($b$) to reflect the current market value before applying the optimization. It uses a smoothing parameter ($\eta$) and a penalty term ($\lambda$) derived from the transaction fee percentage.
The diagram above illustrates the sequential logic applied during each time step to derive the next set of portfolio weights.
Sources: universal/algos/tco.py:30-36, universal/algos/tco.py:48-68
Key Components
| Component | Description |
|---|---|
TCO (Base Class) | Defines the transaction cost-aware update logic and the interface for return prediction. |
update_tco | The mathematical implementation of weight adjustment including fee penalties and simplex projection. |
predict | Abstract method implemented by subclasses to provide return forecasts. |
simplex_proj | Utility function ensuring that final portfolio weights are non-negative and sum to 1. |
Sources: universal/algos/tco.py:10-70, universal/tools.py:276-295
TCO Implementations
The library provides two primary variations of TCO, differentiated by how they predict the next price relatives.
TCO1: Trend and Reversal
TCO1 is a simple implementation that uses either "reversal" (predicting the next price relative as the inverse of the current one) or "trend" (predicting a continuation of the current price relative).
- Reversal Strategy: $x_{pred} = p_{t-1} / p_t$
- Trend Strategy: $x_{pred} = p_t / p_{t-1}$
Sources: universal/algos/tco.py:72-84
TCO2: Moving Average Prediction
TCO2 employs a moving average window (similar to the OLMAR algorithm) to predict returns. It calculates the mean price over a specified window relative to the current price to determine the expected move.
- Formula: $x_{pred} = mean(history[window]) / p_t$
Sources: universal/algos/tco.py:87-101, universal/algos/olmar.py:65-72
Parameters and Configuration
TCO algorithms are configured during initialization with parameters that control their sensitivity to costs and market changes.
| Parameter | Type | Default | Description |
|---|---|---|---|
trx_fee_pct | float | 0 | Transaction fee in percent (e.g., 0.001 for 0.1%). Used to calculate $\lambda$. |
eta | int | 10 | Smoothing parameter. Higher values increase the magnitude of portfolio updates. |
window | int | 5 | (TCO2 only) The number of historical periods used for moving average prediction. |
type | string | "reversal" | (TCO1 only) Determines if the algorithm follows "trend" or "reversal" logic. |
Sources: universal/algos/tco.py:21-27, universal/algos/tco.py:73-75, universal/algos/tco.py:88-96
Mathematical Implementation
The core weight update logic in update_tco is implemented using NumPy for efficient matrix operations. The algorithm first calculates the updated portfolio weights based on the actual price changes of the assets:
# last price adjusted weights
updated_b = np.multiply(b, x) / np.dot(b, x)
# Calculate variables for update
vt = x_pred / np.dot(updated_b, x_pred)
v_t_ = np.mean(vt)
# Update portfolio with smoothing and fee penalty
b_1 = self.eta * (vt - np.dot(v_t_, 1))
b_ = updated_b + np.sign(b_1) * np.maximum(
np.zeros(len(b_1)), np.abs(b_1) - lambd
)
The final step involves calling tools.simplex_proj(y=b_), which implements a projection algorithm to ensure the weights reside on a standard simplex.
Sources: universal/algos/tco.py:53-65, universal/tools.py:276-295
Relationship with Result Analysis
TCO results are analyzed through the AlgoResult class, which calculates metrics like turnover and wealth. For TCO specifically, the turnover metric is critical as it measures the effectiveness of the cost optimization.
The analysis phase verifies if the trx_fee_pct successfully lowered the turnover while maintaining total_wealth.
Sources: universal/algo.py:84-135, universal/result.py:245-250, tests/test_algos.py:54-57
Conclusion
Transaction Cost Optimization (TCO) serves as a bridge between theoretical online portfolio selection and practical trading by incorporating a penalty for turnover. By leveraging flexible prediction models (Trend, Reversal, or Moving Averages) and a robust mathematical framework for weight updates, TCO provides a configurable approach to managing the trade-off between alpha generation and execution costs.