| 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 |
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)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']