| Overall Statistics |
|
Total Trades 16036 Average Win 0.05% Average Loss -0.04% Compounding Annual Return 17.606% Drawdown 52.800% Expectancy 0.314 Net Profit 141.085% Sharpe Ratio 0.711 Probabilistic Sharpe Ratio 18.977% Loss Rate 46% Win Rate 54% Profit-Loss Ratio 1.42 Alpha 0.201 Beta -0.143 Annual Standard Deviation 0.254 Annual Variance 0.065 Information Ratio 0.12 Tracking Error 0.318 Treynor Ratio -1.263 Total Fees $73305.88 Estimated Strategy Capacity $4800000.00 |
import pandas as pd
import numpy as np
from io import StringIO
class PensiveTanAnguilline(QCAlgorithm):
### Use a new file
def Initialize(self):
self.SetStartDate(2015, 9, 1) # Set Start Date
self.SetEndDate(2021, 2, 1)
self.SetCash(2000000) # Set Strategy Cash
# self.AddEquity("SPY", Resolution.Minute)
self.SetSecurityInitializer(self.CustomSecurityInitializer)
self.symbols = ['A','AAL','AAP','AAPL','ABBV','ABC','ABMD','ABT','ACN','ADBE','ADI','ADM','ADP','ADSK','AEE','AEP','AES','AFL','AIG','AIZ','AJG','AKAM','ALB','ALGN','ALK','ALL','ALLE','ALXN','AMAT','AMCR','AMD','AME','AMGN','AMP','AMT','AMZN','ANET','ANSS','ANTM','AON','AOS','APA','APD','APH','APTV','ARE','ATO','ATVI','AVB','AVGO','AVY','AWK','AXP','AZO','BA','BAC','BAX','BBY','BDX','BEN','BFb','BIIB','BIO','BK','BKNG','BKR','BLK','BLL','BMY','BR','BRKb','BSX','BWA','BXP','C','CAG','CAH','CARR','CAT','CB','CBOE','CBRE','CCI','CCL','CDNS','CDW','CE','CERN','CF','CFG','CHD','CHRW','CHTR','CI','CINF','CL','CLX','CMA','CMCSA','CME','CMG','CMI','CMS','CNC','CNP','COF','COG','COO','COP','COST','CPB','CPRT','CRM','CSCO','CSX','CTAS','CTLT','CTSH','CTVA','CTXS','CVS','CVX','D','DAL','DD','DE','DFS','DG','DGX','DHI','DHR','DIS','DISCA','DISCK','DISH','DLR','DLTR','DOV','DOW','DPZ','DRE','DRI','DTE','DUK','DVA','DVN','DXC','DXCM','EA','EBAY','ECL','ED','EFX','EIX','EL','EMN','EMR','ENPH','EOG','EQIX','EQR','ES','ESS','ETN','ETR','ETSY','EVRG','EW','EXC','EXPD','EXPE','EXR','F','FANG','FAST','FB','FBHS','FCX','FDX','FE','FFIV','FIS','FISV','FITB','FLIR','FLS','FLT','FMC','FOXA','FRC','FRT','FTNT','FTV','GD','GE','GILD','GIS','GL','GLW','GM','GOOG','GOOGL','GPC','GPN','GPS','GRMN','GS','GWW','HAL','HAS','HBAN','HBI','HCA','HD','HES','HFC','HIG','HII','HLT','HOLX','HON','HPE','HPQ','HRL','HSIC','HST','HSY','HUM','HWM','IBM','ICE','IDXX','IEX','IFF','ILMN','INCY','INFO','INTC','INTU','IP','IPG','IPGP','IQV','IR','IRM','ISRG','IT','ITW','IVZ','JBHT','JCI','JEC','JKHY','JNJ','JNPR','JPM','K','KEY','KEYS','KHC','KIM','KLAC','KMB','KMI','KMX','KO','KR','KSU','L','LB','LDOS','LEG','LEN','LH','LHX','LIN','LKQ','LLY','LMT','LNC','LNT','LOW','LRCX','LUMN','LUV','LVS','LW','LYB','LYV','MA','MAA','MAR','MAS','MCD','MCHP','MCK','MCO','MDLZ','MDT','MET','MGM','MHK','MKC','MKTX','MLM','MMC','MMM','MNST','MO','MOS','MPC','MPWR','MRK','MRO','MS','MSCI','MSFT','MSI','MTB','MTD','MU','MXIM','NCLH','NDAQ','NEE','NEM','NFLX','NI','NKE','NLOK','NLSN','NOC','NOV','NOW','NRG','NSC','NTAP','NTRS','NUE','NVDA','NVR','NWL','NWSA','O','ODFL','OKE','OMC','ORCL','ORLY','OTIS','OXY','PAYC','PAYX','PBCT','PCAR','PEAK','PEG','PEP','PFE','PFG','PG','PGR','PH','PHM','PKG','PKI','PLD','PM','PNC','PNR','PNW','POOL','PPG','PPL','PRGO','PRU','PSA','PSX','PVH','PWR','PXD','PYPL','QCOM','QRVO','RCL','RE','REG','REGN','RF','RHI','RJF','RL','RMD','ROK','ROL','ROP','ROST','RSG','RTX','SBAC','SBUX','SCHW','SEE','SHW','SIVB','SJM','SLB','SLG','SNA','SNPS','SO','SPG','SPGI','SRE','STE','STT','STX','STZ','SWK','SWKS','SYF','SYK','SYY','T','TAP','TDG','TDY','TEL','TER','TFC','TFX','TGT','TJX','TMO','TMUS','TPR','TRMB','TROW','TRV','TSCO','TSLA','TSN','TT','TTWO','TWTR','TXN','TXT','TYL','UA','UAA','UAL','UDR','UHS','ULTA','UNH','UNM','UNP','UPS','URI','USB','V','VAR','VFC','VIAC','VLO','VMC','VNO','VNT','VRSK','VRSN','VRTX','VTR','VTRS','VZ','WAB','WAT','WBA','WDC','WEC','WELL','WFC','WHR','WLTW','WM','WMB','WMT','WRB','WRK','WST','WU','WY','WYNN','XEL','XLNX','XOM','XRAY','XRX','XYL','YUM','ZBH','ZBRA','ZION','ZTS']
self.allSymbols = {}
self.allSecurities = []
self.SetBenchmark("SPY")
for symbol in self.symbols:
security = self.AddEquity(symbol, Resolution.Daily).Symbol
# explication
self.allSymbols[security.Value] = [0, 0] #[position,transaction]
self.allSecurities.append(security)
#self.AddRiskMangement(TrailingStopRiskManagementModel(0.05))
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
self.tradableSecurities = []
# retirer le '#' pour le warmUp
self.SetWarmUp(timedelta(days = 30))
# changer le lien
# old link : https://www.dropbox.com/s/qrta0p6pu2nv9yy/signaux_presentable_wednesday.csv?dl=1
# new link : https://www.dropbox.com/s/qur4qqfgwvdh4ti/new_factor_signaux_presentable.csv?dl=1
csv = self.Download("https://www.dropbox.com/s/qur4qqfgwvdh4ti/new_factor_signaux_presentable.csv?dl=1")
self.df = pd.read_csv(StringIO(csv))
self.externalData = list(self.df.itertuples())
self.table_position = 0
# self.Schedule.On(self.DateRules.EveryDay("SPY"),
# self.TimeRules.At(0, 0),
# self.rebalance)
self.investedCount = 0
# A RETIRER EVENTUELLEMENT
# NE jamais faire le rebalancement a 0 minutes de la fermature
# car l'ordre est exécuté le lendemain au cours d'ouverture
# donc fort risque de hausse de prix faisant qu'il n'est plus possible d'acheter le titre
self.Schedule.On(self.DateRules.Every(DayOfWeek.Wednesday),
self.TimeRules.BeforeMarketClose("SPY", 1), # We receive the signal monday 22h swiss
self.rebalance )
# Assigning securities custom fee models:
#self.Securities["AAPL"].SetFeeModel(CustomFeeModel())
for symbol in self.symbols:
self.Securities[symbol].SetFeeModel(CustomFeeModel())
def OnData(self, data):
self.data = data
# A REMETTRE
#self.rebalance()
pass
def rebalance(self):
'''Include sell statement for removed securities'''
algYear = self.Time.year
algMonth = self.Time.month
algDay = self.Time.day
currentDate = str(algDay) + "/" + str(algMonth) + "/" + str(algYear)
# displayed based on the resolution (Daily)
#self.Debug("currentDate : " + currentDate)
i = 0
for row in self.externalData:
#try: #If there is an error with dates a tuple(row) then continue to the next row
date = row[1] #Date is the index of the tuple(final colum in the dataframe)
# DD/MM/YYYY
date = str(date)
# erreur ce devrait etre day puis month
day = date[0:2]
month = date[3:5]
year = date[6:]
"""
i = i + 1
if (i == 3): # vérifier que les mois et jours sont juste
self.Debug("month : " + month)
self.Debug("day : " + day)
self.Debug("year : " + year)
"""
# retrait du 0 dans jours et mois ex : 01/01/2010 --> 1/1/2010
if day[0] == '0':
day = day[1]
if month[0] == '0':
month = month[1]
newDate = str(day) + "/" + str(month) + "/" + str(year)
if newDate == currentDate:
#self.Debug("Is Current")
#self.Debug('currentDate : ' + currentDate)
#self.Debug('newDate : ' + newDate)
position = row[2]
transaction = row[3]
symbol = row[-1]
#self.Debug('row[2] : ' + str(row[2]))
#self.Debug('row[3] : ' + str(row[3]))
#self.Debug('row[-1] : ' + str(row[-1]))
self.allSymbols[row[-1]] = [row[2], row[3]]
self.trade()
""" # IF THERE IS ENOUGH STOCK IN NEW PORTFOLIO
self.Debug("We trade")
#ELSE
#RETURN
self.Debug("We do not trade") """
def trade(self):
buySecurities = []
investingInto = []
#positions : [position, transaction]
# séparer le traitement
# liquider seulement si on rebalance
for symbol, positions in self.allSymbols.items():
# ATTENTION il est possible d'ajouter plusieurs fois le même symbol ?
# vérifier si limiter à l'instance en cours
# SI oui risque de LEVIER !!
# NON IL N'Y A PAS DE DOUBLON
if positions[0] == 1:
buySecurities.append(symbol)
for symbol in buySecurities:
if self.data.ContainsKey(self.allSecurities[self.symbols.index(symbol)]):
investingInto.append(symbol)
#self.Debug('investingInto : ' + str(investingInto))
algYear = self.Time.year
algMonth = self.Time.month
algDay = self.Time.day
currentDate = str(algDay) + "/" + str(algMonth) + "/" + str(algYear)
self.Debug(currentDate)
# --------------------------------------------------------
# Don't affect the algo why ?
MIN_PORTFOLIO_SIZE = 20
if(len(investingInto) < MIN_PORTFOLIO_SIZE):
self.Debug("We do not rebalance, because only : " + str(len(investingInto)) + " stocks to invest in")
"""
self.Debug("Portfolio holdings")
self.Debug("------------------------------------------------")
nb_stocks_in_portfolio = 0
algYear = self.Time.year
algMonth = self.Time.month
algDay = self.Time.day
currentDate = str(algDay) + "/" + str(algMonth) + "/" + str(algYear)
for kvp in self.Portfolio:
security_holding = kvp.Value
# Quantity of the security held
quantity = security_holding.Quantity
# Quand je fais type quantity, rien ne s'affiche
# caster la valeur en un INTEGER
#self.Debug("type(quantity): " + str(type(quantity)) + " - fin")
# type(security_holding): 2019-12-03 00:00:00
#self.Debug("int(quantity) : " + str(int(quantity)) + " - fin")
if(int(quantity) > 0):
nb_stocks_in_portfolio = nb_stocks_in_portfolio + 1
#symbol = security_holding.Symbol.Value
# Average price of the security holdings
#price = security_holding.AveragePrice
self.Debug("currentDate : " + currentDate + " / ")
self.Debug("nb_stocks_in_portfolio : " + str(nb_stocks_in_portfolio))"""
return
else:
for symbol, positions in self.allSymbols.items():
#self.Debug('symbol : ' + symbol + ', position : ' + str(positions))
if positions[0] == 0:
self.Liquidate(symbol)
# 0.5% cash buffer --> 221 warning
# 1.0% cash buffer --> 221 warning BIZZARD
for symbol in investingInto:
self.SetHoldings([PortfolioTarget(symbol, 0.999/len(investingInto))])
self.Debug("We rebalance because : " + str(len(investingInto)) + " stocks to invest in")
"""
self.Debug("Portfolio holdings")
self.Debug("------------------------------------------------")
for kvp in self.Portfolio:
security_holding = kvp.Value
#symbol = security_holding.Symbol.Value
# Quantity of the security held
quantity = security_holding.Quantity
self.Debug("quantity : " + str(quantity))
# Average price of the security holdings
#price = security_holding.AveragePrice
"""
#if(len(buySecurities) < 50):
#self.Debug("buySecurities : " + str(len(buySecurities)))
#if(len(investingInto) < 50):
#self.Debug("investingInto : " + str(len(investingInto)))
def CustomSecurityInitializer(self, security):
security.SetLeverage(1)
class CustomFeeModel:
def GetOrderFee(self, parameters):
PERCENTAGE_FEE = 0.0002 # vraie valeur 0.0002
fee = max(1, parameters.Security.Price
* parameters.Order.AbsoluteQuantity
* PERCENTAGE_FEE)
return OrderFee(CashAmount(fee, 'USD'))