| Overall Statistics |
|
Total Trades 204 Average Win 0.24% Average Loss -0.16% Compounding Annual Return 2.718% Drawdown 4.300% Expectancy 0.277 Net Profit 3.240% Sharpe Ratio 0.452 Loss Rate 48% Win Rate 52% Profit-Loss Ratio 1.45 Alpha 0.118 Beta -5.051 Annual Standard Deviation 0.058 Annual Variance 0.003 Information Ratio 0.136 Tracking Error 0.058 Treynor Ratio -0.005 Total Fees $205.74 |
class BensdorbMeanReversionLong(QCAlgorithm):
cur_sec={}
indic={}
indic_adx={}
def Initialize(self):
self.SetStartDate(2017, 1, 18) # Set Start Date
self.SetEndDate(2018, 12, 30) # Set Start Date
self.SetCash(10000) # Set Strategy Cash
self.__numberOfSymbols = 10
self.UniverseSettings.Resolution = Resolution.Daily
self.UniverseSettings.Leverage = 1
self.AddUniverse(self.CoarseSelectionFunction)
def CoarseSelectionFunction(self, coarse):
filtered = [ x for x in coarse
if x.Price > 1 and x.DollarVolume > 2500000 ]
#self.Debug("------------")
#self.Debug(len(filtered))
#indicators without adx
#self.indic.clear()
for cf in filtered:
if cf.Symbol not in self.indic:
self.indic[cf.Symbol] = SymbolData(cf.Symbol,self)
#
indic_cond=self.indic[cf.Symbol]
indic_cond.update(cf.EndTime, cf.AdjustedPrice)
filtered=[x for x in self.indic.values() if x.is_above_ema \
and x.is_rsi_cond ]
#adx indicator
#self.indic_adx.clear()
for indic in filtered:
symb=indic.symbol
#if symb not in self.indic_adx:
try:
self.indic_adx[symb] = SymbolDataADX(indic)
self.AddEquity(str(symb.Value),Resolution.Daily)
self._updateADX(symb)
except Exception as e:
self.Debug(e)
self.Log(e)
#
filtered_adx=[x for x in self.indic_adx.values() if x.is_adx_cond \
and x.is_atr_cond]
#
if len(filtered_adx)>0:
self.Debug("###")
self.Debug(len(filtered_adx))
#
values=sorted(filtered_adx, key = lambda x: x.symb_data.rsi, \
reverse=False)[:self.__numberOfSymbols]
return [ x.symb_data.symbol for x in values]
def OnSecuritiesChanged(self, changes):
self.changes = changes
for security in changes.AddedSecurities:
symb=security.Symbol
if not security.IsTradable:
continue
try:
price=security.Close
if price>0 and symb not in self.cur_sec:
self.cur_sec[symb]={'entry_price' : price,\
'stop_price': .0, \
'profit_price': price + price * 0.03, \
'bars_since_entry' : 0}
except Exception as e:
self.Debug(e)
self.Log(e)
def OnData(self, data):
lst_to_del=[]
for symb in self.cur_sec:
symb_str=str(symb.Value)
try:
if (data.ContainsKey(symb_str))==False or data[symb_str]==None:
continue
price=data[symb_str].Close
#enter long
if self.cur_sec[symb]['entry_price'] <price - price * 0.01 \
and self.cur_sec[symb]['bars_since_entry']==1 :
self.SetHoldings(symb, 0.1)
#exit long
elif price>self.cur_sec[symb]['profit_price'] \
or price < self.cur_sec[symb]['stop_price'] \
or self.cur_sec[symb]['bars_since_entry'] > 4 :
#
self.Liquidate(symbolToLiquidate=symb_str)
lst_to_del.append(symb)
self.cur_sec[symb]['bars_since_entry']=0
else:
if self.cur_sec[symb]['bars_since_entry']>2:
self._updateADX(symb)
self.cur_sec[symb]['stop_price']= price -\
self.indic_adx[symb].atr.Current.Value / price * 2.5
self.cur_sec[symb]['bars_since_entry']+=1
#
except Exception as e:
self.Debug(e)
self.Log(e)
for symb in lst_to_del:
self.cur_sec.pop(symb)
if symb in self.indic:
self.indic.pop(symb)
if symb in self.indic_adx:
self.indic_adx.pop(symb)
self.RemoveSecurity(str(symb.Value))
def _updateADX(self,symb):
try:
self.AddEquity(str(symb.Value),Resolution.Daily)
tradeBarHistory = self.History(str(symb.Value), 7, Resolution.Daily)
for tradeBar in tradeBarHistory:
self.indic_adx[symb].update(tradeBar);
except Exception as e:
self.Debug(e)
self.Log(e)
class SymbolData(object):
def __init__(self, symbol,strat):
self.strat=strat
self.price=0
self.symbol=symbol
self.ema = ExponentialMovingAverage(150)
self.rsi =RelativeStrengthIndex(3)
self.is_above_ema = False
self.is_rsi_cond= False
def update(self,time, value):
#self.strat.Debug("indic value: " + str(value))
#self.strat.Debug("time: " + str(time))
if self.ema.Update(time,value) and self.rsi.Update(time,value):
self.price=value
ema = self.ema.Current.Value
rsi = self.rsi.Current.Value
self.is_above_ema = value > ema
#self.strat.Debug("ema: " + str(ema))
self.is_rsi_cond = rsi < 30
class SymbolDataADX(object):
def __init__(self, symb_data):
self.symb_data=symb_data
self.atr= AverageTrueRange("",10)
self.adx = AverageDirectionalIndex("",7)
self.is_adx_cond =False
self.is_atr_cond =False
def update(self, bar):
if self.adx.Update(bar) and self.atr.Update(bar):
#
atr=self.atr.Current.Value
adx=self.adx.Current.Value
#self.symb_data.strat.Debug("update atr: "+ str(atr/bar.Close))
self.is_atr_cond = atr/bar.Close > 0.04
self.is_adx_cond = adx > 45