| Overall Statistics |
|
Total Orders 937 Average Win 0.56% Average Loss -0.47% Compounding Annual Return 30.207% Drawdown 27.800% Expectancy 0.647 Start Equity 100000 End Equity 478922.33 Net Profit 378.922% Sharpe Ratio 0.957 Sortino Ratio 1.239 Probabilistic Sharpe Ratio 50.448% Loss Rate 24% Win Rate 76% Profit-Loss Ratio 1.17 Alpha 0.131 Beta 0.709 Annual Standard Deviation 0.202 Annual Variance 0.041 Information Ratio 0.624 Tracking Error 0.168 Treynor Ratio 0.272 Total Fees $1410.18 Estimated Strategy Capacity $5600000.00 Lowest Capacity Asset PHM R735QTJ8XC9X Portfolio Turnover 1.39% Drawdown Recovery 748 |
# region imports
from AlgorithmImports import *
# endregion
class SquareAsparagusHippopotamus(QCAlgorithm):
def initialize(self):
self.set_start_date(2020, 1, 1)
self.set_cash(100000)
# Add universe selection for US equities
self.add_universe(self.coarse_selection, self.fine_selection)
# Rebalance monthly
self.schedule.on(
self.date_rules.month_start(),
self.time_rules.after_market_open("SPY", 30),
self.rebalance
)
self._selected_stocks = []
self._rebalance_flag = False
def coarse_selection(self, coarse):
# Filter for liquid stocks with price > $5
filtered = [x for x in coarse if x.has_fundamental_data and x.price > 5 and x.dollar_volume > 10000000]
# Sort by dollar volume and take top 500
sorted_by_volume = sorted(filtered, key=lambda x: x.dollar_volume, reverse=True)
return [x.symbol for x in sorted_by_volume[:500]]
def fine_selection(self, fine):
# Select stocks with PE ratio < 10
filtered = [x for x in fine if x.valuation_ratios.pe_ratio > 0 and x.valuation_ratios.pe_ratio < 10]
# Take top 20 by market cap for diversification
sorted_by_market_cap = sorted(filtered, key=lambda x: x.market_cap, reverse=True)
self._selected_stocks = [x.symbol for x in sorted_by_market_cap[:20]]
self._rebalance_flag = True
return self._selected_stocks
def rebalance(self):
if not self._rebalance_flag or len(self._selected_stocks) == 0:
return
# Equal weight allocation
weight = 1.0 / len(self._selected_stocks)
# Liquidate stocks not in current selection
for symbol in self.portfolio.keys():
if symbol not in self._selected_stocks and self.portfolio[symbol].invested:
self.liquidate(symbol)
# Equal weight the selected stocks
for symbol in self._selected_stocks:
self.set_holdings(symbol, weight)
self._rebalance_flag = False