Overall Statistics |
Total Trades 50 Average Win 0.69% Average Loss -0.24% Compounding Annual Return 48.942% Drawdown 6.700% Expectancy 1.297 Net Profit 8.176% Sharpe Ratio 2.108 Loss Rate 40% Win Rate 60% Profit-Loss Ratio 2.83 Alpha 0.749 Beta -22.963 Annual Standard Deviation 0.169 Annual Variance 0.028 Information Ratio 2.006 Tracking Error 0.169 Treynor Ratio -0.015 Total Fees $63.07 |
sp500=['MMM','AOS','ABT','ABBV','ACN','ATVI','AYI','ADBE','AAP','AMD','AES','AET','AMG','AFL','A','APD','AKAM','ALK','ALB','ARE','ALXN','ALGN','ALLE','AGN','ADS','LNT','ALL','GOOGL','GOOG','MO','AMZN','AEE','AAL','AEP','AXP','AIG','AMT','AWK','AMP','ABC','AME','AMGN','APH','APC','ADI','ANDV','ANSS','ANTM','AON','APA','AIV','AAPL','AMAT','APTV','ADM','ARNC','AJG','AIZ','T','ADSK','ADP','AZO','AVB','AVY','BHGE','BLL','BAC','BAX','BBT','BDX','BRK.B','BBY','BIIB','BLK','HRB','BA','BKNG','BWA','BXP','BSX','BHF','BMY','AVGO','BF.B','CHRW','CA','COG','CDNS','CPB','COF','CAH','KMX','CCL','CAT','CBOE','CBRE','CBS','CELG','CNC','CNP','CTL','CERN','CF','SCHW','CHTR','CVX','CMG','CB','CHD','CI','XEC','CINF','CTAS','CSCO','C','CFG','CTXS','CME','CMS','KO','CTSH','CL','CMCSA','CMA','CAG','CXO','COP','ED','STZ','GLW','COST','COTY','CCI','CSRA','CSX','CMI','CVS','DHI','DHR','DRI','DVA','DE','DAL','XRAY','DVN','DLR','DFS','DISCA','DISCK','DISH','DG','DLTR','D','DOV','DWDP','DPS','DTE','DUK','DRE','DXC','ETFC','EMN','ETN','EBAY','ECL','EIX','EW','EA','EMR','ETR','EVHC','EOG','EQT','EFX','EQIX','EQR','ESS','EL','RE','ES','EXC','EXPE','EXPD','ESRX','EXR','XOM','FFIV','FB','FAST','FRT','FDX','FIS','FITB','FE','FISV','FLIR','FLS','FLR','FMC','FL','F','FTV','FBHS','BEN','FCX','GPS','GRMN','IT','GD','GE','GGP','GIS','GM','GPC','GILD','GPN','GS','GT','GWW','HAL','HBI','HOG','HRS','HIG','HAS','HCA','HCP','HP','HSIC','HES','HPE','HLT','HOLX','HD','HON','HRL','HST','HPQ','HUM','HBAN','HII','IDXX','INFO','ITW','ILMN','INCY','IR','INTC','ICE','IBM','IP','IPG','IFF','INTU','ISRG','IVZ','IPGP','IQV','IRM','JBHT','JEC','SJM','JNJ','JCI','JPM','JNPR','KSU','K','KEY','KMB','KIM','KMI','KLAC','KSS','KHC','KR','LB','LLL','LH','LRCX','LEG','LEN','LUK','LLY','LNC','LKQ','LMT','L','LOW','LYB','MTB','MAC','M','MRO','MPC','MAR','MMC','MLM','MAS','MA','MAT','MKC','MCD','MCK','MDT','MRK','MET','MTD','MGM','KORS','MCHP','MU','MSFT','MAA','MHK','TAP','MDLZ','MON','MNST','MCO','MS','MSI','MYL','NDAQ','NOV','NAVI','NKTR','NTAP','NFLX','NWL','NFX','NEM','NWSA','NWS','NEE','NLSN','NKE','NI','NBL','JWN','NSC','NTRS','NOC','NCLH','NRG','NUE','NVDA','ORLY','OXY','OMC','OKE','ORCL','PCAR','PKG','PH','PAYX','PYPL','PNR','PBCT','PEP','PKI','PRGO','PFE','PCG','PM','PSX','PNW','PXD','PNC','RL','PPG','PPL','PX','PFG','PG','PGR','PLD','PRU','PEG','PSA','PHM','PVH','QRVO','QCOM','PWR','DGX','RRC','RJF','RTN','O','RHT','REG','REGN','RF','RSG','RMD','RHI','ROK','COL','ROP','ROST','RCL','SPGI','CRM','SBAC','SCG','SLB','STX','SEE','SRE','SHW','SPG','SWKS','SLG','SNA','SO','LUV','SWK','SBUX','STT','SRCL','SYK','STI','SIVB','SYMC','SYF','SNPS','SYY','TROW','TTWO','TPR','TGT','TEL','FTI','TXN','TXT','BK','CLX','COO','HSY','MOS','TRV','DIS','TMO','TIF','TWX','TJX','TMK','TSS','TSCO','TDG','TRIP','FOXA','FOX','TSN','USB','UDR','ULTA','UAA','UA','UNP','UAL','UNH','UPS','URI','UTX','UHS','UNM','VFC','VLO','VAR','VTR','VRSN','VRSK','VZ','VRTX','VIAB','V','VNO','VMC','WMT','WBA','WM','WAT','WEC','WFC','WELL','WDC','WU','WRK','WY','WHR','WMB','WLTW','WYN','WYNN','XEL','XRX','XLNX','XL','XYL','YUM','ZBH','ZION','ZTS']
data = {'COUP': '12/3/2018\n', 'SMAR': '12/3/2018\n', 'RH': '12/3/2018\n', 'FNSR': '12/3/2018\n', 'ZS': '12/4/2018\n', 'GWRE': '12/4/2018\n', 'MDB': '12/4/2018\n', 'TOL': '12/4/2018\n', 'HQY': '12/4/2018\n', 'AZO': '12/4/2018\n', 'HPE': '12/4/2018\n', 'MOV': '12/4/2018\n', 'OLLI': '12/4/2018\n', 'MRVL': '12/4/2018\n', 'HDS': '12/4/2018\n', 'CONN': '12/4/2018\n', 'BMO': '12/4/2018\n', 'DG': '12/4/2018\n', 'DCI': '12/4/2018\n', 'GMS': '12/4/2018\n', 'CLDR': '12/5/2018\n', 'OKTA': '12/5/2018\n', 'FIVE': '12/5/2018\n', 'NTIOF': '12/5/2018\n', 'BF.B': '12/5/2018\n', 'SNPS': '12/5/2018\n', 'GEF': '12/5/2018\n', 'CMTL': '12/6/2018\n', 'SCWX': '12/6/2018\n', 'DOCU': '12/6/2018\n', 'AOBC': '12/6/2018\n', 'DOMO': '12/6/2018\n', 'HOME': '12/6/2018\n', 'VRNT': '12/6/2018\n', 'SAIC': '12/6/2018\n', 'ZUMZ': '12/6/2018\n', 'MEI': '12/6/2018\n', 'KR': '12/6/2018\n', 'GCO': '12/6/2018\n', 'HRB': '12/6/2018\n', 'MIK': '12/6/2018\n', 'LULU': '12/6/2018\n', 'PDCO': '12/6/2018\n', 'KFY': '12/6/2018\n', 'AVGO': '12/6/2018\n', 'GIII': '12/6/2018\n', 'SIG': '12/6/2018\n', 'ULTA': '12/6/2018\n', 'BPMX': '12/6/2018\n', 'DLTH': '12/6/2018\n', 'PLCE': '12/6/2018\n', 'JW.A': '12/6/2018\n', 'COO': '12/6/2018\n', 'FIZZ': '12/6/2018\n', 'TTC': '12/6/2018\n', 'THO': '12/6/2018\n', 'UNFI': '12/6/2018\n', 'FGP': '12/6/2018\n', 'MTN': '12/7/2018\n', 'BIG': '12/7/2018\n', 'SFIX': '12/10/2018\n', 'ASNA': '12/10/2018\n', 'CDMO': '12/10/2018\n', 'CASY': '12/10/2018\n', 'ASPU': '12/10/2018\n', 'SEAC': '12/10/2018\n', 'NX': '12/10/2018\n', 'IRET': '12/10/2018\n', 'PVTL': '12/11/2018\n', 'PLAY': '12/11/2018\n', 'DSW': '12/11/2018\n', 'ASHTY': '12/11/2018\n', 'FRAN': '12/11/2018\n', 'AEO': '12/11/2018\n', 'MMMB': '12/11/2018\n', 'SMMT': '12/11/2018\n', 'TLRD': '12/12/2018\n', 'PLAB': '12/12/2018\n', 'SKIS': '12/12/2018\n', 'NDSN': '12/12/2018\n', 'OXM': '12/12/2018\n', 'VRA': '12/12/2018\n', 'CHKE': '12/13/2018\n', 'CIEN': '12/13/2018\n', 'COST': '12/13/2018\n', 'ADBE': '12/13/2018\n', 'KALV': '12/14/2018\n', 'VIRC': '12/14/2018\n', 'UBA': '12/14/2018\n', 'RHT': '12/17/2018\n', 'ORCL': '12/17/2018\n', 'HEI': '12/17/2018\n', 'LAKE': '12/17/2018\n', 'CSBR': '12/17/2018\n', 'SCS': '12/18/2018\n', 'LOVE': '12/18/2018\n', 'NAV': '12/18/2018\n', 'JBL': '12/18/2018\n', 'AIR': '12/18/2018\n', 'FDS': '12/18/2018\n', 'ABM': '12/18/2018\n', 'MU': '12/18/2018\n', 'DRI': '12/18/2018\n', 'FDX': '12/18/2018\n', 'WOR': '12/18/2018\n', 'RAD': '12/19/2018\n', 'WGO': '12/19/2018\n', 'GIS': '12/19/2018\n', 'MLHR': '12/19/2018\n', 'PAYX': '12/19/2018\n', 'NCS': '12/19/2018\n', 'REVG': '12/19/2018\n', 'PIR': '12/19/2018\n', 'BB': '12/20/2018\n', 'CAG': '12/20/2018\n', 'NKE': '12/20/2018\n', 'ATU': '12/20/2018\n', 'ACN': '12/20/2018\n', 'CAMP': '12/20/2018\n', 'NEOG': '12/20/2018\n', 'CTAS': '12/20/2018\n', 'WBA': '12/20/2018\n', 'CCL': '12/20/2018\n', 'SCHL': '12/20/2018\n', 'APOG': '12/20/2018\n', 'SAFM': '12/20/2018\n', 'SHLO': '12/20/2018\n', 'KMX': '12/21/2018\n'}
from QuantConnect.Data.UniverseSelection import * import math import numpy as np import pandas as pd import talib import time from datetime import timedelta, date, datetime from data import data from SP500 import sp500 class FundamentalFactorAlgorithm(QCAlgorithm): def Initialize(self): #Dropbox url: https://www.dropbox.com/s/hl38drkfweosmur/earnings_dates_6months.txt?dl=0 dates = self.Download('https://www.dropbox.com/s/5mw3jvm6wvabqo0/earnings_6month.csv?dl=1') dates = dates.split('\n') #self.Log(dates) #self.Debug(self.earnings[0]) self.SetStartDate(2017, 12, 20) self.SetEndDate(2018, 3, 1) #self.SetStartDate(2018, 11, 15) #self.SetEndDate(2019, 1, 1) self.SetCash(100000) self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) #self.AddUniverse(self.FineSelectionFunction) ''' # In your initialize method: # Chart - Master Container for the Chart: stockPlot = Chart("Trade Plot") # On the Trade Plotter Chart we want 3 series: trades and price: stockPlot.AddSeries(Series("Buy", SeriesType.Scatter, 0)) stockPlot.AddSeries(Series("Sell", SeriesType.Scatter, 0)) stockPlot.AddSeries(Series("Price", SeriesType.Line, 0)) self.AddChart(stockPlot) ''' self.sample_size = 10 ''' for ticker in list(data): self.AddEquity(ticker) ''' self.AddEquity("SPY", Resolution.Daily) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 15), Action(self.onOpen)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 60), Action(self.beforeClose)) self.universe = [] self.filtered = [] self.traded = False ''' RSI max/min ''' self.rsi_max = 60 self.rsi_min = 30 ''' Set the holding period in days (prior to earnings) ''' self.holding_period = 10 self.history_period = 30 * 2 self.stop_percent = .05 self.target_percent = 0.15 #P/L self.pl = {} self.logger = True if self.logger: self.Debug('S&P 500 length: {0}'.format(len(sp500))) self.data = data self.data = {} for line in dates: #self.Debug(line.split(',')) try: split = line.split(',') ticker = split[0] date = split[1] if ticker in list(self.data): pass else: self.data[ticker]=date #self.Debug('TICKER: {0} DATE: {1}'.format(ticker, date)) except: pass def getEarnings(self, ticker): if ticker in list(self.data): return date(int(self.data[ticker].split('/')[2].split('\n')[0]), int(self.data[ticker].split('/')[0]), int(self.data[ticker].split('/')[1])) else: return None def CoarseSelectionFunction(self, coarse): return [ x.Symbol for x in coarse if x.Symbol.Value in sp500] def FineSelectionFunction(self, fine): #fine.OperationRatios.NetIncomeGrowth.OneMonth ##fine.OperationRatios.RevenueGrowth.OneMonth self.universe = [ x.Symbol for x in fine ] return self.universe ''' def FineSelectionFunction(self, fine): #fine = [x for x in fine if self.Time > x.EarningReports.FileDate + timedelta(days=0)and x.EarningReports.FileDate != datetime.time()] #fine = [x for x in fine if x.EarningReports.FileDate == datetime.time()] self.Debug(fine[0].EarningsReports) fine = [x for x in fine if x.Symbol.Value in sp500] #today_ = datetime.time() for item in fine: self.Log('Symbole {0} Earnings date: {1} Today: {2}'.format(item.Symbol.Value, item.EarningsReports.FileDate, datetime.time())) return [i.Symbol for i in fine] ''' def onOpen(self): for stock in list(self.pl): if self.pl[stock]<1: self.Liquidate(stock) else: self.pl[stock]-=1 self.filtered = [] current_day = date(self.Time.year, self.Time.month, self.Time.day) ''' Loop through SP500 for earnings date that is within holding period and append to filtered ''' #for ticker in sp500: for symbol in self.universe: next_earnings = self.getEarnings(symbol.Value) if next_earnings is not None: offset = next_earnings - current_day #self.Debug('ticker: {2} next_earnings_date: {0} offset: {1}'.format(next_earnings, offset, ticker)) if int(offset.days)==self.holding_period: #self.AddEquity(ticker, True) self.filtered.append(symbol) def beforeClose(self): if self.filtered: self.Log('filtered: {0}'.format(self.filtered)) for symbol in self.filtered: if not self.Securities.ContainsKey(symbol): continue if not self.Securities[symbol].IsTradable: continue #hist = self.History(self.Symbol(ticker), self.history_period) hist = self.History(symbol, self.history_period) #self.Log(hist) current = self.Securities[symbol].Price #close_avg = hist['close'].mean() #open_avg = hist['open'].mean() close = np.array(hist['close']) open_ = np.array(hist['open']) #high = np.array(hist['high']) #low = np.array(hist['low']) ''' Position based on close averages if current>close_avg: self.SetHoldings(ticker, .15) elif current<close_avg: self.SetHoldings(ticker, -.15) ''' ''' Position based on SMA sma = talib.SMA(close) ''' ''' Position based on RSI ''' rsi = talib.RSI(close, timeperiod=14) if rsi[-1]>self.rsi_max: pass elif rsi[-1]<self.rsi_min: pass else: continue ''' Holding period new high/low ''' if current>max(close[:self.holding_period]) and current>max(open_[:self.holding_period]): #self.SetHoldings(symbol, .10) self.MarketOrder(symbol, 10000/current) self.Plot("Trade Plot", "Buy", current) #self.pl[symbol.Value]=current elif current<min(close[:self.holding_period]) and current<min(open_[:self.holding_period]): #self.SetHoldings(symbol, -.10) self.MarketOrder(symbol, -10000/current) self.Plot("Trade Plot", "Sell", current) #self.pl[symbol.Value]=-current def OnOrderEvent(self, orderEvent): s = orderEvent.Symbol if orderEvent.FillQuantity<0: self.pl[s.Value]=orderEvent.FillPrice self.Debug(orderEvent.FillPrice) elif orderEvent.FillQuantity>0: self.pl[s.Value]=orderEvent.FillPrice self.Debug(orderEvent.FillPrice) def OnData(self, data): pass ''' def OnOrderEvent(self, orderEvent): s = orderEvent.Symbol if orderEvent.FillQuantity < 0: self.shorts[s.Value]=float(orderEvent.FillPrice) self.level[s.Value]=[False,False, 91] if self.log: self.Log(str(orderEvent)) ''' def OnEndOfDay(self): #Log the end of day prices: #self.Plot("Trade Plot", "Price", self.lastPrice) for position in list(self.pl): if not self.Securities.ContainsKey(position): continue if not self.Securities[position].IsTradable: continue current = self.Securities[position].Price entry = self.pl[position] if entry<0: #and self.Portfolio[position].Invested: target = entry - (entry*self.target_percent) exit = entry + (entry*self.stop_percent) if current < target or current > exit: self.Liquidate(position) elif entry>0: target = entry + (entry*self.target_percent) exit = entry - (entry*self.stop_percent) if target < current or current < exit: self.Liquidate(position)