| Overall Statistics |
|
Total Orders 3553 Average Win 0.11% Average Loss -0.09% Compounding Annual Return 14.373% Drawdown 24.200% Expectancy 0.766 Start Equity 1000000000 End Equity 3832974979.31 Net Profit 283.297% Sharpe Ratio 0.722 Sortino Ratio 0.785 Probabilistic Sharpe Ratio 19.774% Loss Rate 23% Win Rate 77% Profit-Loss Ratio 1.29 Alpha 0.009 Beta 0.98 Annual Standard Deviation 0.131 Annual Variance 0.017 Information Ratio 0.143 Tracking Error 0.052 Treynor Ratio 0.096 Total Fees $10505589.32 Estimated Strategy Capacity $42000000.00 Lowest Capacity Asset JNJ R735QTJ8XC9X Portfolio Turnover 1.07% |
from AlgorithmImports import *
from QuantConnect.DataSource import *
class ETFConstituentUniverseAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2010, 1, 1)
self.set_end_date(2020, 1, 1)
self.set_cash(1_000_000_000)
self.universe_settings.asynchronous = True
self.universe_settings.resolution = Resolution.MINUTE
# Requesting data
self.spy = self.add_equity("SPY").symbol
self._universe = self.add_universe(self.universe.etf(self.spy, self.universe_settings, self.etf_constituents_filter))
# Example of Historical Universe Data
history = self.history(self._universe, 30, Resolution.DAILY)
for (universe_symbol, time), constituents in history.items():
for constituent in constituents:
self.debug(f'{constituent.symbol}: {constituent.weight}')
self.weight_by_symbol = {}
# Set up daily rebalance scheduled event
self.schedule.on(
self.date_rules.every_day(self.spy),
self.time_rules.after_market_open(self.spy, 1),
self.rebalance)
def etf_constituents_filter(self, constituents: List[ETFConstituentUniverse]) -> List[Symbol]:
# Get the 10 securities with the largest weight in the index, save the weights
selected = sorted([c for c in constituents if c.weight],
key=lambda c: c.weight, reverse=True)[:10]
self.weight_by_symbol = {c.symbol: c.weight for c in selected}
return list(self.weight_by_symbol.keys())
def rebalance(self) -> None:
spy_weight = sum(self.weight_by_symbol.values())
# Liquidate the ones not in top 10 weights
if spy_weight > 0:
for symbol in self.portfolio.Keys:
if symbol not in self.weight_by_symbol:
self.liquidate(symbol)
# Invest portfolio by normalized weights of the top 10 constituents
for symbol, weight in self.weight_by_symbol.items():
self.set_holdings(symbol, 1 * weight / spy_weight)
def on_securities_changed(self, changes: SecurityChanges) -> None:
for security in changes.removed_securities:
if security.invested:
self.liquidate(security.symbol, 'Removed From Universe')
for security in changes.added_securities:
# Historical data for newly added constituents
history = self.history(security.symbol, 7, Resolution.DAILY)
self.debug(f'We got {len(history)} prices for asset from our history request for {security.symbol}')