| Overall Statistics |
|
Total Trades 59 Average Win 1.61% Average Loss -0.48% Compounding Annual Return 45.801% Drawdown 3.100% Expectancy 1.404 Net Profit 20.785% Sharpe Ratio 2.315 Probabilistic Sharpe Ratio 83.185% Loss Rate 45% Win Rate 55% Profit-Loss Ratio 3.36 Alpha 0.369 Beta -0.119 Annual Standard Deviation 0.147 Annual Variance 0.021 Information Ratio 0.465 Tracking Error 0.196 Treynor Ratio -2.861 Total Fees $59.00 Estimated Strategy Capacity $17000000.00 Lowest Capacity Asset SAM R735QTJ8XC9X |
from AlgorithmImports import *
from QuantConnect.DataSource import *
class QuiverWallStreetBetsDataAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021, 1, 1)
self.SetEndDate(2021, 7, 1)
self.SetCash(100000)
self.universe_data_by_symbol = {}
self.symbol_data_by_symbol = {}
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction)
def CoarseSelectionFunction(self, coarse):
sorted_by_dollar_volume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
selected = sorted_by_dollar_volume[:500]
for c in selected:
if c.Symbol not in self.universe_data_by_symbol:
self.universe_data_by_symbol[c.Symbol] = UniverseData(self, c.Symbol)
else:
self.universe_data_by_symbol[c.Symbol].Update(self.Time, c.AdjustedPrice)
selected = [c for c in selected if self.universe_data_by_symbol[c.Symbol].IsReady]
sorted_by_std = sorted(selected, key=lambda c: self.universe_data_by_symbol[c.Symbol].std.Current.Value, reverse=True)
return [ x.Symbol for x in sorted_by_std[:3] ]
def OnData(self, data):
for symbol, symbol_data in self.symbol_data_by_symbol.items():
# Gather WSB mentions data
if data.ContainsKey(symbol_data.wsb_symbol):
wsb_mentions = data[symbol_data.wsb_symbol].Mentions
symbol_data.Update(data.Time, wsb_mentions)
# Ensure we have data to place orders
if not (data.ContainsKey(symbol) and data[symbol] is not None):
continue
# Place orders
if not data[symbol].IsFillForward and symbol_data.IsReady:
target_holding = symbol_data.get_target_holding() / len(self.symbol_data_by_symbol)
self.SetHoldings(symbol, target_holding)
def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
symbol = security.Symbol
self.symbol_data_by_symbol[symbol] = SymbolData(self, symbol)
for security in changes.RemovedSecurities:
symbol = security.Symbol
self.Liquidate(symbol)
symbol_data = self.symbol_data_by_symbol.pop(symbol, None)
if symbol_data:
symbol_data.dispose()
class UniverseData:
def __init__(self, algorithm, symbol, std_period=30):
self.std = StandardDeviation(std_period)
# Warm up std indicator
history = algorithm.History(symbol, std_period, Resolution.Daily)
if history.empty or 'close' not in history.columns:
return
for time, row in history.loc[symbol].iterrows():
self.std.Update(time, row.close)
def Update(self, date, price):
self.std.Update(date, price)
@property
def IsReady(self):
return self.std.IsReady
class SymbolData:
def __init__(self, algorithm, symbol):
self.algorithm = algorithm
self.wsb_symbol = algorithm.AddData(QuiverWallStreetBets, symbol).Symbol
self.max = Maximum(7)
self.current = Maximum(1)
# Warm up max indicator
history = algorithm.History(QuiverWallStreetBets, self.wsb_symbol, 14, Resolution.Daily)
if history.empty or 'mentions' not in history.columns:
return
for time, row in history.loc[self.wsb_symbol].iterrows():
self.max.Update(time, row.mentions)
self.current.Update(time, row.mentions)
def Update(self, time, mentions):
self.max.Update(time, mentions)
self.current.Update(time, mentions)
@property
def IsReady(self):
return self.max.IsReady
def get_target_holding(self):
return int(self.current >= self.max)
def dispose(self):
self.algorithm.RemoveSecurity(self.wsb_symbol)