Overall Statistics |
Total Trades 10001 Average Win 0.02% Average Loss -0.04% Compounding Annual Return -100.0% Drawdown 82.400% Expectancy -0.863 Net Profit -82.413% Sharpe Ratio -1.025 Probabilistic Sharpe Ratio 0.000% Loss Rate 91% Win Rate 9% Profit-Loss Ratio 0.46 Alpha 0.594 Beta -0.784 Annual Standard Deviation 0.975 Annual Variance 0.951 Information Ratio -2.968 Tracking Error 1.022 Treynor Ratio 1.276 Total Fees $10157.75 Estimated Strategy Capacity $79000000.00 Lowest Capacity Asset BBBY R735QTJ8XC9X |
from datetime import datetime, timedelta import numpy as np from nltk.util import ngrams class SentimentAlphaModel(AlphaModel): def __init__(self, algo): self.algo = algo self.CandleSize = timedelta(minutes = 5) self.MaxHoldTime = 20*self.CandleSize self.Symbols = set() self.Prices = {} self.ExitPrices = {} self.BuyTimes = {} self.Holdings = set() self.MaxHoldings = 5 self.CandlesInTraining = {} self.Candles = {} self.LastCandleTime = self.algo.Time self.TradingTime = False return def UpdateCandlesInTraining(self, data): for symbol in self.Symbols: if symbol in data and data[symbol] is not None: o, h, l, c = data[symbol].Open, data[symbol].High, data[symbol].Low, data[symbol].Close candle = self.CandlesInTraining[symbol] if candle["Open"] is None: candle["Open"] = o if candle["High"] is None or h > candle["High"]: candle["High"] = h if candle["Low"] is None or l < candle["Low"]: candle["Low"] = l candle["Close"] = c def AddCandles(self): #Candles in training are finished; HA time! for symbol in self.Symbols: o, h, c, l = self.CandlesInTraining[symbol]["Open"], self.CandlesInTraining[symbol]["High"], self.CandlesInTraining[symbol]["Low"], self.CandlesInTraining[symbol]["Close"] if o is None or h is None or c is None or l is None: continue self.Prices[symbol] = c newCandle = {"Open": o, "High": h, "Low": l, "Close": c} newCandle["High"] = max([newCandle["Open"], h, newCandle["Close"]]) newCandle["Low"] = min([newCandle["Open"], l, newCandle["Close"]]) if o > c: newCandle["Color"] = "Red" else: newCandle["Color"] = "Green" newCandle["Top"] = max([newCandle["Open"], newCandle["Close"]]) newCandle["Bottom"] = min([newCandle["Open"], newCandle["Close"]]) self.Candles[symbol].append(newCandle) def UpdateCandles(self, data): self.UpdateCandlesInTraining(data) if self.algo.Time >= self.LastCandleTime + self.CandleSize: self.AddCandles() for symbol in self.Symbols: self.CandlesInTraining[symbol] = self.FreshCandle() self.LastCandleTime = self.algo.Time self.TradingTime = True def FreshCandle(self): return {"Open": None, "High": None, "Low": None, "Close": None} def BuySignal(self, symbol): if symbol not in self.Candles or len(self.Candles[symbol]) < 1: return 0 return self.Candles[symbol][-1]["High"] - self.Candles[symbol][-1]["Low"] def SellSignal(self, symbol): return (symbol not in self.ExitPrices) or (self.Prices[symbol] < self.ExitPrices[symbol][0] or self.Prices[symbol] > self.ExitPrices[symbol][1]) def OnSecuritiesChanged(self, algo, changes): for symbol in changes.AddedSecurities: self.Symbols.add(symbol.Symbol) self.CandlesInTraining[symbol.Symbol] = self.FreshCandle() self.Candles[symbol.Symbol] = [] for symbol in changes.RemovedSecurities: self.Symbols.discard(symbol.Symbol) self.CandlesInTraining.pop(symbol.Symbol, None) self.Candles.pop(symbol.Symbol, None) self.ExitPrices.pop(symbol.Symbol, None) self.Holdings.discard(symbol.Symbol) self.algo.Liquidate(symbol.Symbol) def Update(self, algo, data): self.UpdateCandles(data) res = [] if not self.TradingTime: for symbol in self.Symbols: if symbol in data and data[symbol] is not None and (symbol not in self.ExitPrices or data[symbol].Close < self.ExitPrices[symbol][0] or data[symbol].Close > self.ExitPrices[symbol][1]): # self.algo.Log(f"Selling {symbol}") res.append(Insight.Price(symbol, self.MaxHoldTime, InsightDirection.Flat)) self.Holdings.discard(symbol) return res buySignals = {} for symbol in self.Symbols: buySignals[symbol] = self.BuySignal(symbol) thingsWeShallBuy = set(sorted([symbol for symbol in buySignals.keys()], key = lambda x: buySignals[x], reverse = True)[:self.MaxHoldings - len(self.Holdings)]) for symbol in self.Symbols: if self.SellSignal(symbol) and (symbol not in thingsWeShallBuy): # self.algo.Log(f"Selling {symbol}") res.append(Insight.Price(symbol, self.MaxHoldTime, InsightDirection.Flat)) self.Holdings.discard(symbol) for symbol in thingsWeShallBuy: # self.algo.Log(f"Buying {symbol}") res.append(Insight.Price(symbol, self.MaxHoldTime, InsightDirection.Up)) self.Holdings.add(symbol) p = self.Prices[symbol] bottom = self.Candles[symbol][-1]["Bottom"] self.ExitPrices[symbol] = (p - 0.5*(p - bottom), p + 2*(p - bottom)) assert(len(self.Holdings) <= self.MaxHoldings) self.TradingTime = False return res class CreativeVioletMule(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 1, 1) self.SetEndDate(2020, 1, 1) self.SetCash(100000) self.MinEarningTime = timedelta(days = 1) self.MaxEarningTime = timedelta(days = 30) self.Symbols = set() self.SecuritiesSet = set() self.Holdings = set() self.Coarse_Count = 500 self.Current_Day = None self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.UniverseSettings.Resolution = Resolution.Minute self.SetAlpha(SentimentAlphaModel(self)) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) def CoarseSelectionFunction(self, coarse): if self.Current_Day == self.Time.day: return Universe.Unchanged sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData], key=lambda x: x.DollarVolume, reverse=True)[:self.Coarse_Count] return [i.Symbol for i in sortedByDollarVolume] def FineSelectionFunction(self, fine): if self.Current_Day == self.Time.day: return Universe.Unchanged self.Current_Day = self.Time.day res = [x for x in fine if (x.EarningReports.FileDate > self.Time - self.MaxEarningTime and x.EarningReports.FileDate < self.Time - self.MinEarningTime)] symbolRes = [x.Symbol for x in res] return symbolRes def OnData(self, data): return