| Overall Statistics |
|
Total Orders 1796 Average Win 0.11% Average Loss -0.14% Compounding Annual Return -1.669% Drawdown 13.000% Expectancy -0.053 Start Equity 100000 End Equity 91926.48 Net Profit -8.074% Sharpe Ratio -0.806 Sortino Ratio -0.895 Probabilistic Sharpe Ratio 0.080% Loss Rate 47% Win Rate 53% Profit-Loss Ratio 0.78 Alpha -0.041 Beta -0.092 Annual Standard Deviation 0.059 Annual Variance 0.003 Information Ratio -0.704 Tracking Error 0.164 Treynor Ratio 0.516 Total Fees $1878.53 Estimated Strategy Capacity $1700000.00 Lowest Capacity Asset IJK RWQR2INKP0TH Portfolio Turnover 2.42% Drawdown Recovery 722 |
# region imports
from AlgorithmImports import *
# endregion
class MomentumAndStyleRotationAlgorithm(QCAlgorithmFramework):
def initialize(self):
self.set_start_date(self.end_date - timedelta(5*365))
self.set_cash(100_000)
self.settings.automatic_indicator_warm_up = True
tickers = [
"IJJ", # iShares S&P MidCap 400 Value Index ETF
"IJS", # iShares S&P SmallCap 600 Value ETF
"IVE", # iShares S&P 500 Value Index ETF
"IVW", # iShares S&P 500 Growth ETF
"IJK", # iShares S&P Mid-Cap 400 Growth ETF
"IJT", # iShares S&P Small-Cap 600 Growth ETF
]
symbols = [Symbol.create(t, SecurityType.EQUITY, Market.USA) for t in tickers]
self.universe_settings.resolution = Resolution.DAILY
self.set_universe_selection(ManualUniverseSelectionModel(symbols))
self.set_alpha(MomentumAndStyleRotationAlphaModel(self))
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
self.set_execution(ImmediateExecutionModel())
self.set_risk_management(NullRiskManagementModel())
# Add a warm-up period so the algorithm trades on deployment.
self.set_warm_up(timedelta(45))
class MomentumAndStyleRotationAlphaModel(AlphaModel):
'''Alpha model that uses the Momentum Indicator to create insights'''
def __init__(self, algorithm, period=12*20, resolution=Resolution.DAILY):
'''
Initializes a new instance of the MomentumAndStyleRotationAlphaModel class
Args:
period: The Momentum lookback period
resolution: The data resolution
'''
self._period = period
self._resolution = resolution
self._securities = []
self._insights = []
# Add a Scheduled Event to create new insights each month.
algorithm.schedule.on(
algorithm.date_rules.month_start('SPY'),
algorithm.time_rules.at(8, 0),
self._create_insights
)
def on_securities_changed(self, algorithm, changes):
# As assets enter the universe, create momentum indicators for them.
for security in changes.added_securities:
security.momentum = algorithm.mom(security, self._period, self._resolution)
self._securities.append(security)
def _create_insights(self):
# Sort the assets by their momentum.
sorted_by_momentum = sorted(
[s for s in self._securities if s.momentum.is_ready],
key=lambda security: security.momentum
)
self._insights = [
# Buy the stock with the greatest momentum.
Insight.price(sorted_by_momentum[-1], Expiry.END_OF_MONTH, InsightDirection.UP),
# Short the stock with the lowest momentum.
Insight.price(sorted_by_momentum[0], Expiry.END_OF_MONTH, InsightDirection.DOWN),
]
def update(self, algorithm, data):
# Return the insights for the Portfolio Construction model.
insights = self._insights.copy()
self._insights.clear()
return insights