| Overall Statistics |
|
Total Trades 786 Average Win 0.36% Average Loss -0.27% Compounding Annual Return 24.371% Drawdown 7.600% Expectancy 0.451 Net Profit 60.711% Sharpe Ratio 1.685 Probabilistic Sharpe Ratio 86.353% Loss Rate 38% Win Rate 62% Profit-Loss Ratio 1.35 Alpha 0.139 Beta 0.163 Annual Standard Deviation 0.1 Annual Variance 0.01 Information Ratio -0.069 Tracking Error 0.196 Treynor Ratio 1.034 Total Fees $0.00 Estimated Strategy Capacity $130000.00 Lowest Capacity Asset DDOG X7ZCS8BRO6ZP |
from datetime import date, timedelta
class EarningsDatesStocks(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 1)
self.SetCash(2500)
self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFunction)
self.UniverseSettings.Leverage = 1
self.UniverseSettings.Resolution = Resolution.Daily
self.SetSecurityInitializer(lambda x: x.SetFeeModel(CustomFeeModel()))
self._changes = None
self._symbolsInvested = {}
self._openTrade = 5
self._levStock = 5
self._closeTrade = 10
self._removeKeys = list()
self.AddEquity("SPY")
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 100), Action(self.LiquidateSymbols))
def CoarseSelectionFilter(self, coarse):
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price > 10 and c.Price < 100]
return filteredByPrice
def FineSelectionFunction(self, fine):
hist = self.History([i.Symbol for i in fine], 1, Resolution.Daily)
earnings_fine = [x for x in fine if self.Time > x.EarningReports.FileDate + timedelta(days=self._openTrade)
and x.EarningReports.FileDate != date.today()]
marketcap_fine = [x for x in earnings_fine if (x.ValuationRatios.EVToEBITDA > 0)
and (x.EarningReports.BasicAverageShares.ThreeMonths > 0)
and float(x.EarningReports.BasicAverageShares.ThreeMonths) * hist.loc[str(x.Symbol)]['close'][0] > 1e9]
selected_fine = sorted(marketcap_fine, key = lambda x: x.ValuationRatios.EVToEBITDA, reverse=True)
return [i.Symbol for i in selected_fine[:100]] #[:int(100/self._levStock)]
def OnData(self, data):
for month in [1,4,7,10]:
if int(self.Time.month) == int(month):
if self._changes is None: return
for security in self._changes.AddedSecurities: #[:int(100/self._levStock)]
try:
orderStocks = round(((self.Portfolio.TotalPortfolioValue / 100) * self._levStock) \
/ self.Securities[str(security)].Price)
#if self.Portfolio.UnsettledCash < 500: return
if self.Securities[str(security)].Invested: return
#self.Debug(str(security))
self.MarketOrder(str(security), orderStocks)
self._symbolsInvested[str(security)] = [(self.Time + timedelta(self._closeTrade))]
except:
pass
for security in self._changes.RemovedSecurities:
pass
self._changes = None
def OnSecuritiesChanged(self, changes):
self._changes = changes
self.Log(f"OnSecuritiesChanged({self.UtcTime}):: {changes}")
def LiquidateSymbols(self):
for key,value in list(self._symbolsInvested.items()):
#self.Debug(str(value[0].date()) +' '+ str(self.Time.date()))
if value[0].date() <= self.Time.date():
try:
self.Liquidate(key)
self._symbolsInvested.pop(key, None)
except:
pass
class CustomFeeModel:
def GetOrderFee(self, parameters):
return OrderFee(CashAmount(0, 'USD'))