| Overall Statistics |
|
Total Orders 6259 Average Win 0.08% Average Loss -0.07% Compounding Annual Return 17.830% Drawdown 31.600% Expectancy 0.631 Start Equity 1000000 End Equity 5058048.84 Net Profit 405.805% Sharpe Ratio 0.675 Sortino Ratio 0.711 Probabilistic Sharpe Ratio 17.449% Loss Rate 24% Win Rate 76% Profit-Loss Ratio 1.13 Alpha 0.026 Beta 1.098 Annual Standard Deviation 0.171 Annual Variance 0.029 Information Ratio 0.593 Tracking Error 0.058 Treynor Ratio 0.105 Total Fees $9085.74 Estimated Strategy Capacity $1900000000.00 Lowest Capacity Asset PG R735QTJ8XC9X Portfolio Turnover 1.15% |
# region imports
from AlgorithmImports import *
from dateutil.relativedelta import relativedelta
# endregion
class TOPTAnalysisAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2014, 12, 31)
self.set_cash(1_000_000)
spy = Symbol.create('SPY', SecurityType.EQUITY, Market.USA)
self.set_security_initializer(
BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))
)
# Add a universe of daily data.
self.universe_settings.resolution = Resolution.DAILY
self._universe = self.add_universe(
self.universe.etf(
Symbol.create('SPY', SecurityType.EQUITY, Market.USA),
universe_filter_func=lambda constituents: [
c.symbol for c in sorted(
[c for c in constituents if c.weight],
key=lambda c: c.weight
)[-20:]
]
)
)
#self._universe = self.add_universe(
# lambda fundamentals: [f.symbol for f in sorted(fundamentals, key=lambda f: f.market_cap)[-20:]]
#)
# Create a Scheduled Event to record new daily prices and
# rebelance the portfolio.
self.schedule.on(
self.date_rules.every_day(spy),
# The fund is dynamically rebalanced on a quarterly basis - the 3rd Friday
# of March, June, September, and December.
# Source: https://www.ishares.com/us/strategies/top-20#top-5-companies
#FuncDateRule(
# name="third_friday_of_the_quarter_end_month",
# get_dates_function=self._third_friday_of_the_quarter_end_month
#),
self.time_rules.at(0, 1),
self._rebalance
)
self.set_warm_up(timedelta(30))
def _rebalance(self):
if self.is_warming_up or not self._universe.selected:
return
symbols = [s for s in self._universe.selected if s in self.securities and self.securities[s].price]
if not symbols:
return
market_cap_sum = sum([self.securities[s].fundamentals.market_cap for s in symbols])
if not market_cap_sum:
return
self.set_holdings([PortfolioTarget(symbol, self.securities[symbol].fundamentals.market_cap/market_cap_sum) for symbol in symbols], True)
def _third_friday_of_the_quarter_end_month(self, start_date, end_date):
dt = start_date.replace(day=1).replace(tzinfo=None)
dates = []
while dt <= end_date:
if dt.month in [3, 6, 9, 12]:
days_until_friday = (4 - dt.weekday()) % 7 # 4 represents Friday
first_friday = dt + timedelta(days=days_until_friday)
third_friday = first_friday + timedelta(weeks=2)
dates.append(third_friday)
dt += relativedelta(months=1)
return dates