The BaseStrategy class provides a foundational structure for creating custom investment strategies.
Below is a step-by-step guide for extending BaseStrategy.
First, ensure you have the necessary modules imported:
import datetime as dt
import pandas as pd
from investos.portfolio.strategy import BaseStrategy
from investos.util import values_in_time
Subclass BaseStrategy
to implement the desired strategy.
class CustomStrategy(BaseStrategy):
You may want to add additional attributes specific to your strategy. Override the __init__
method:
def __init__(self, *args, custom_param=None, **kwargs):
super().__init__(*args, **kwargs)
self.custom_param = custom_param
generate_trade_list
Method:This is the core method where your strategy logic resides.
Given a series of holdings indexed by asset, and a date t
, it should calculate and return a trade list series, also indexed by asset.
For example, a simple, contrived momentum-based strategy might look like this:
def generate_trade_list(self, holdings: pd.Series, t: dt.datetime) -> pd.Series:
# A placeholder example:
### Buy assets that have had positive returns in the last period
returns = values_in_time(self.actual_returns, t)
buy_assets = returns[returns > 0].index
trade_values = pd.Series(index=holdings.index, data=0.0)
trade_values[buy_assets] = 100 # Buying $100 of each positive-return asset
return trade_values
You can add custom helper methods to factor in specific logic or utilities that help in constructing your strategy (and help in keeping your logic understandable).
You can test that your custom strategy generates trades as expected for a specific datetime period:
actual_returns = pd.DataFrame(...) # Add your data here. Each asset should be a column, and it should be indexed by datetime
initial_holdings = pd.Series(...) # Holding values, indexed by asset
strategy = CustomStrategy(
actual_returns=actual_returns,
custom_param="example_value"
)
trade_list = strategy.generate_trade_list(
initial_holdings,
dt.datetime.now()
)
print(trade_list)
You can also plug your custom strategy into BacktestController to run a full backtest!
backtest_controller = inv.portfolio.BacktestController(
strategy=strategy
)
Use the costs
parameter (in BaseStrategy
) to incorporate costs.
If your strategy uses convex optimization, use the constraints
parameter (in BaseStrategy
) to incorporate constraints.
Both RankLongShort and SPO classes, which extend BaseStrategy, offer a base foundation for implementing investment strategies.
While their structure is designed for general use, for users seeking to implement more advanced and nuanced strategies, their architecture supports customization and extension.
Dynamic Leverage: Rather than using a fixed leverage ratio, you could dynamically adjust leverage based on market volatility, market sentiment, or other indicators.
Adaptive Percent Long/Short: Adjust the percentage of assets that are long or short based on changing market conditions. For example, during bullish markets, increase the percent long.
Sector-Based Ranking: Instead of ranking all assets, classify them by sectors and rank within each sector. This can ensure diversification across various sectors.
Custom Weighting Mechanisms: Override the _get_trade_weights_for_t
method to use custom weights beyond simple ranking, perhaps factoring in other metrics such as asset volatility or liquidity.
Custom Unwind Logic: Modify the unwinding logic for positions to not just be based on time but on market conditions, metrics, or other constraints.
Post-Solution Adjustments: After the solver has provided a solution, make post-optimization adjustments, perhaps for real-world considerations like rounding off to whole shares or accounting for latest market prices.
Advanced Error Handling: Instead of just handling errors by zeroing trades when the solver fails, consider implementing a fallback mechanism or use an alternative optimization approach.
Like BaseStrategy, both RankLongShort and SPO are designed to be extensible.
Make sure you test extensively with historical data before deploying to a live environment!