| Overall Statistics |
|
Total Orders 20559 Average Win 0.06% Average Loss -0.06% Compounding Annual Return 4.122% Drawdown 38.700% Expectancy 0.013 Start Equity 100000 End Equity 122387.25 Net Profit 22.387% Sharpe Ratio 0.015 Sortino Ratio 0.018 Probabilistic Sharpe Ratio 2.071% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 0.99 Alpha -0.062 Beta 1.076 Annual Standard Deviation 0.166 Annual Variance 0.028 Information Ratio -0.825 Tracking Error 0.07 Treynor Ratio 0.002 Total Fees $14007.03 Estimated Strategy Capacity $240000000.00 Lowest Capacity Asset RIVN XTDCDCDRI6HX Portfolio Turnover 6.67% Drawdown Recovery 1477 |
############################################
# Researched and Implemented by: Ethan Huang
# Mentored by: Rudy Osuna
# Triton Quantitative Trading @ UC San Diego
############################################
# region imports
from AlgorithmImports import *
# endregion
class EqualWeightedUniverseBenchmark(QCAlgorithm):
def initialize(self):
self.set_start_date(self.end_date - timedelta(5 * 365))
self.set_cash(100_000)
self.settings.seed_initial_prices = True
self.universe_settings.resolution = Resolution.DAILY
self.universe_settings.schedule.on(self.date_rules.week_start())
self._universe = self.add_universe(self._select)
self.set_warm_up(1)
def on_warmup_finished(self):
time_rule = self.time_rules.at(8, 0)
# Rebalance the portfolio weekly after warmup.
self.schedule.on(self.date_rules.week_start("SPY"), time_rule, self._rebalance)
# Rebalance the portfolio today too.
if self.live_mode:
self._rebalance()
else:
self.schedule.on(self.date_rules.today, time_rule, self._rebalance)
def _select(self, fundamental):
# Select the top 100 most liquid stocks by dollar volume with price above $10.
return [f.symbol for f in sorted(
[f for f in fundamental if f.has_fundamental_data and f.price > 10],
key=lambda f: f.dollar_volume
)[-100:]]
def on_securities_changed(self, changes):
# Liquidate symbols that leave the universe.
for security in changes.removed_securities:
if security.invested:
self.liquidate(security.symbol)
def _rebalance(self):
if self.is_warming_up:
return
selected_assets = [symbol for symbol in self._universe.selected if symbol in self.securities and self.securities[symbol].has_data]
if len(selected_assets) == 0:
return
weight = 1.0 / len(selected_assets)
targets = [PortfolioTarget(symbol, weight) for symbol in selected_assets]
self.set_holdings(targets, True)