Overall Statistics |
Total Trades 170 Average Win 0.11% Average Loss -0.04% Compounding Annual Return 12.245% Drawdown 12.600% Expectancy 2.596 Net Profit 41.104% Sharpe Ratio 1.068 Probabilistic Sharpe Ratio 51.215% Loss Rate 7% Win Rate 93% Profit-Loss Ratio 2.87 Alpha 0.094 Beta 0.077 Annual Standard Deviation 0.098 Annual Variance 0.01 Information Ratio -0.128 Tracking Error 0.214 Treynor Ratio 1.357 Total Fees $171.12 |
from datetime import timedelta import numpy as np from scipy import stats from collections import deque class ModulatedMultidimensionalReplicator(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 1, 1) #self.SetEndDate(2020, 1, 1) self.SetCash(50000) tickers = ["QQQ","SPY","IYC","IYK","IGV","GLD","TLH","TLT"] for x in tickers: symbols = [ Symbol.Create(x, SecurityType.Equity, Market.USA) ] self.AddUniverseSelection( ManualUniverseSelectionModel(symbols) ) self.UniverseSettings.Resolution = Resolution.Daily self.AddAlpha(MOMAlphaModel()) self.Settings.RebalancePortfolioOnInsightChanges = False self.Settings.RebalancePortfolioOnSecurityChanges = False self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(self.DateRules.Every(DayOfWeek.Monday))) self.SetExecution(ImmediateExecutionModel()) def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' # if not self.Portfolio.Invested: # self.SetHoldings("SPY", 1) class MOMAlphaModel(AlphaModel): def __init__(self): self.indi = {} self.indi_Filter = {} self.wind= 200 self.num=3 self.securities = [] def OnSecuritiesChanged(self, algorithm, changes): for security in changes.AddedSecurities: symbol = security.Symbol # initialize indicator self.indi[symbol] = CustomSlope( 'My_Custom', self.wind) algorithm.RegisterIndicator(symbol, self.indi[symbol], Resolution.Daily) # warmup indicator history = algorithm.History(symbol, self.wind, Resolution.Daily) self.indi[symbol].WarmUp(history) # remove securities for security in changes.RemovedSecurities: symbol = security.Symbol if security in self.indi: self.indi[symbol].remove(security) def Update(self, algorithm, data): insights = [] ## filtering filter1 = [x[0] for x in self.indi.items() if (self.indi[x[0]].Corr > 0.5) ] for symbol in self.indi: if symbol in filter1: # and filter2 and filter3 self.indi_Filter[symbol] = self.indi[symbol] ## sorting ordered = sorted(self.indi_Filter.items(), key=lambda x: x[1].Value, reverse=True)[:self.num] for x in ordered: symbol = x[0] insights.append( Insight.Price(symbol, timedelta(1), InsightDirection.Up) ) # for testing algorithm.Plot("Custom_Slope", "Value", list(self.indi.values())[0].Value *10000) return insights class CustomSlope: def __init__(self, name, period): self.Name = name self.Time = datetime.min self.IsReady = False self.Value = 0 self.Slope = 0 self.Corr = 0 self.queue = deque(maxlen=period) def __repr__(self): return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value) def Update(self, input): #self.queue.appendleft(input.close) # used by warm up self.queue.appendleft(input.Close) # used by RegisterIndicator count = len(self.queue) #self.Time = input.Index # used by warm up self.Time = input.Time # used by RegisterIndicator self.IsReady = count == self.queue.maxlen #### start here the indicator calulation if self.IsReady: y = np.log(self.queue) x = [range(len(y))] slope, corr = stats.linregress(x, y)[0], stats.linregress(x, y)[2] self.Slope = slope self.Corr = corr self.Value = slope * corr #### finish the custom indicator def WarmUp(self,history): for tuple in history.itertuples(): self.Update_warmup(tuple) def Update_warmup(self, input): self.queue.appendleft(input.close) # used by warm up #self.queue.appendleft(input.Close) # used by RegisterIndicator count = len(self.queue) self.Time = input.Index # used by warm up #self.Time = input.Time # used by RegisterIndicator self.IsReady = count == self.queue.maxlen #### start here the indicator calulation if self.IsReady: y = np.log(self.queue) x = [range(len(y))] slope, corr = stats.linregress(x, y)[0], stats.linregress(x, y)[2] self.Slope = slope self.Corr = corr self.Value = slope * corr #### finish the custom indicator