Overall Statistics |
Total Trades 224 Average Win 4.44% Average Loss -1.40% Compounding Annual Return 25.539% Drawdown 16.500% Expectancy 2.051 Net Profit 1771.160% Sharpe Ratio 1.902 Probabilistic Sharpe Ratio 99.327% Loss Rate 27% Win Rate 73% Profit-Loss Ratio 3.18 Alpha 0.26 Beta 0.068 Annual Standard Deviation 0.141 Annual Variance 0.02 Information Ratio 0.631 Tracking Error 0.238 Treynor Ratio 3.924 Total Fees $4750.33 |
# From: https://www.quantconnect.com/forum/discussion/9597/the-in-amp-out-strategy-continued-from-quantopian/p1 import pandas as pd import numpy as np class InOut(QCAlgorithm): def Initialize(self): self.SetStartDate(2008,1,1) # Set Start Date # self.SetEndDate(2015,1,3) # Set Start Date self.SetCash(100000) # Set Strategy Cash # Algo Parameters self.shiftprds = range(55,66) # momentum periods self.hprd = 252 # history period (days) # initialize out of trading period to 3 weeks, days out to 0; maximum days out; waiting period decay, and percentile for extreme indicator self.init_wait, self.adj_wait, self.daysout, self.maxwait, self.decay, self.pctile = [15,15,0,60,0.5,1] self.be_in = True # Assets self.ineq = ['QQQ'] # Risk on securities (equal allocation) self.outeq = ['TLT','IEF'] # Risk off securities (equal allocation) self.sigeqs = ['DBB','IGE','SHY','XLI'] # Indicator securities self.other = ['FXA','FXF','GLD','SLV','SPY','UUP','XLU'] # Indicator securities with mod self.eqs = list(set(self.ineq+self.outeq+self.sigeqs+self.other)) for eq in self.eqs: self.AddEquity(eq,Resolution.Minute) # Initialize weights self.wts = pd.Series(0,self.ineq+self.outeq) self.wtson, self.wtsoff, self.lastwts = [self.wts.copy(),self.wts.copy(),self.wts.copy()] self.wtson[self.ineq] = 1/len(self.ineq) self.wtsoff[self.outeq] = 1/len(self.outeq) # Schedule functions self.Schedule.On(self.DateRules.EveryDay(self.ineq[0]),self.TimeRules.AfterMarketOpen(self.ineq[0],120),self.rebalout) self.Schedule.On(self.DateRules.WeekEnd(self.ineq[0]),self.TimeRules.AfterMarketOpen(self.ineq[0],120),self.rebalin) def rebalout(self): # average of historical values over shiftprds for each security hist = self.History(self.eqs,self.hprd,Resolution.Daily)['close'].unstack(level=0).dropna() # close history h_shift = sum([hist.shift(x) for x in self.shiftprds])/len(self.shiftprds) #pd.concat([hist.shift(x) for x in self.shiftprds]).groupby(level=0).mean() # return over shiftprds average ret = (hist/h_shift-1) # key return indicators, negative of UUP, and differences: silver less gold, industrial - utility, AUS$ less Swiss Franc retkey = pd.concat([ret.loc[:,x] for x in self.sigeqs]+ [-ret.loc[:,'UUP'],ret.loc[:,'SLV']-ret.loc[:,'GLD'], ret.loc[:,'XLI']-ret.loc[:,'XLU'],ret.loc[:,'FXA']-ret.loc[:,'FXF']], axis=1) # extreme returns if less than 1 percentile extreme = retkey.iloc[-1] < np.nanpercentile(retkey,self.pctile,axis=0) # days to wait before getting back in market self.adj_wait = int(max(self.decay * self.adj_wait,self.init_wait * max(1, np.where((ret['GLD'].iloc[-1]>0) & (ret['SLV'].iloc[-1]<0) & (ret['SLV'].iloc[-2]>0), self.init_wait, 1), np.where((ret['XLU'].iloc[-1]>0) & (ret['XLI'].iloc[-1]<0) & (ret['XLI'].iloc[-2]>0), self.init_wait, 1), np.where((ret['FXF'].iloc[-1]>0) & (ret['FXA'].iloc[-1]<0) & (ret['FXA'].iloc[-2]>0), self.init_wait, 1)))) adjwaitdays = min(self.maxwait, self.adj_wait) # in market indicator if extreme.any(): self.daysout = 0 self.be_in = False self.wts = self.wtsoff if self.daysout >= adjwaitdays: self.be_in = True self.daysout += 1 def rebalin(self): if self.be_in: self.wts = self.wtson def OnData(self, data): # Trade if allocation has changed if not self.wts.equals(self.lastwts): port_tgt = [PortfolioTarget(x,y) for x,y in zip(self.wts.index,self.wts.values)] self.SetHoldings(port_tgt) self.lastwts = self.wts.copy()