| Overall Statistics |
|
Total Trades 14 Average Win 2.52% Average Loss -2.50% Compounding Annual Return 0.999% Drawdown 15.500% Expectancy 0.148 Net Profit 2.341% Sharpe Ratio 0.135 Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.01 Alpha 0.026 Beta -0.941 Annual Standard Deviation 0.085 Annual Variance 0.007 Information Ratio -0.051 Tracking Error 0.085 Treynor Ratio -0.012 Total Fees $25.90 |
class Nothing(QCAlgorithm):
parent = None
def Initialize(self):
parent = self
self.SetStartDate(2017, 1, 1) # Set Start Date
self.SetCash(10000) # Set Strategy Cash
symbols = []
symbols.append(Futures.Metals.Gold)
# symbols.append(Futures.Metals.Silver)
# symbols.append(Futures.Metals.Palladium)
# symbols.append(Futures.Metals.Platinum)
# symbols.append(Futures.Energies.CrudeOilWTI)
# symbols.append(Futures.Energies.Gasoline)
# symbols.append(Futures.Energies.HeatingOil)
# symbols.append(Futures.Energies.NaturalGas)
# symbols.append(Futures.Financials.Y30TreasuryBond)
# symbols.append(Futures.Financials.Y10TreasuryNote)
# symbols.append(Futures.Financials.Y5TreasuryNote)
# symbols.append(Futures.Financials.Y2TreasuryNote)
# symbols.append(Futures.Grains.Corn)
# symbols.append(Futures.Grains.Oats)
# symbols.append(Futures.Grains.SoybeanMeal)
# symbols.append(Futures.Grains.SoybeanOil)
# symbols.append(Futures.Grains.Soybeans)
# symbols.append(Futures.Grains.Wheat)
# symbols.append(Futures.Meats.FeederCattle)
# symbols.append(Futures.Meats.LeanHogs)
# symbols.append(Futures.Meats.LiveCattle)
symbols.append(Futures.Softs.Cocoa)
symbols.append(Futures.Softs.Coffee)
symbols.append(Futures.Softs.Cotton2)
symbols.append(Futures.Softs.OrangeJuice)
symbols.append(Futures.Softs.Sugar11)
# symbols.append(Futures.Indices.Dow30EMini)
# symbols.append(Futures.Indices.NASDAQ100EMini)
symbols.append(Futures.Indices.SP500EMini)
# symbols.append(Futures.Indices.VIX)
# symbols.append(Futures.Currencies.AUD)
# symbols.append(Futures.Currencies.CAD)
# symbols.append(Futures.Currencies.CHF)
# symbols.append(Futures.Currencies.EUR)
# symbols.append(Futures.Currencies.GBP)
# symbols.append(Futures.Currencies.JPY)
# symbols.append(Futures.Currencies.NZD)
# symbols.append(Futures.Currencies.USD)
# self.UniverseSettings.Resolution = Resolution.Minute
# self.SetUniverseSelection(FuturesUniverseSelectionModel(self.SelectFuturesSymbols))
# self.SetUniverseSelection(FuturesUniverseSelectionModel(symbols))
# self.Debug(self.SelectFuturesSymbols)
# self.SetUniverseSelection(ManualUniverseSelectionModel(self.SelectFuturesSymbols))
# ManualUniverseSelectionModel(symbols)
# FuturesUniverseSelectionModel(self.SelectFuturesSymbols)
# self.UniverseSettings.Resolution = Resolution.Minute
# self.AddUniverse('my_universe_name', Resolution.Minute, symbols)
# self.SetStartDate(2016, 1, 1)
# self.SetEndDate(2016, 8, 18)
# self.SetCash(100000)
# fastPeriod = 20
# slowPeriod = 60
# self._tolerance = 1 + 0.001
# self.IsUpTrend = False
# self.IsDownTrend = False
# self.SetWarmUp(max(fastPeriod, slowPeriod))
# Adds SPY to be used in our EMA indicators
# equity = self.AddEquity("SPY", Resolution.Daily)
# self._fast = self.EMA(equity.Symbol, fastPeriod, Resolution.Daily)
# self._slow = self.EMA(equity.Symbol, slowPeriod, Resolution.Daily)
# Adds the future that will be traded and
# set our expiry filter for this futures chain
# future = self.AddFuture(Futures.Indices.SP500EMini)
# future.SetFilter(timedelta(0), timedelta(182))
# self.Highest = {}
# self.ATRs = {}
# self.Symbols = {}
self.Data = {}
# RollingWindowSize = 52
# BarSize = TimeSpan.FromDays(1)
# self.previous = {}
self.consolidators = dict()
self.UniverseSettings.Resolution = Resolution.Daily
self.SetWarmUp(52)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)
# consolidator = QuoteBarConsolidator(TimeSpan.FromDays(1))
# self._atr = ATR(20)
# self._highest = MAX(52)
# self.RegisterIndicator("SPY", self._sma, consolidator)
# self.SubscriptionManager.AddConsolidator("SPY", consolidator)
for symbol in symbols:
# self.Debug("Initializing " + symbol)
future = self.AddFuture(symbol)#, Resolution.Minute)
future.SetFilter(timedelta(0), timedelta(60))
# Overload 1: BuyingPowerModel(
# decimal initialMarginRequirement,
# decimal maintenanceMarginRequirement,
# decimal requiredFreeBuyingPowerPercent)
self.Securities[future.Symbol].MarginModel = BuyingPowerModel(0.1,0.1,0.2)
# self.Securities[future.Symbol].SetLeverage(100)
# self.Symbols[symbol] = future.Symbol
# self.Data[future.Symbol] = SymbolData(future.Symbol, BarSize, RollingWindowSize)
# self.Debug("Saving to self.Data as " + str(future.Symbol))
# for symbol, symbolData in self.Data.items():
# symbolData.ATR = AverageTrueRange(self.CreateIndicatorName(symbol, "ATR" + str(20), Resolution.Daily), 20)
# symbolData.Highest = Maximum(self.CreateIndicatorName(symbol, "MAX" + str(52), Resolution.Daily), 52)
# consolidator = QuoteBarConsolidator(BarSize)
# consolidator.DataConsolidated += self.OnDataConsolidated
# self.SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator)
# self.ATRs[future.Symbol] = self.ATR(20, MovingAverageType.Simple)
# self.Highest[future.Symbol] = self.MAX(52)
# self.RegisterIndicator(future.Symbol, self.ATRs[future.Symbol], Resolution.Daily)
# self.RegisterIndicator(future.Symbol, self.Highest[future.Symbol], Resolution.Daily)
# self.Highest[future.Symbol] = self.MAX(future.Symbol, 52, Resolution.Daily)
# self.ATRs[future.Symbol] = self.ATR(future.Symbol, 20, MovingAverageType.Simple, Resolution.Daily)
# self.Plot("Highest", self.Highest[future.Symbol], SeriesType.Line)
# for symbol, symbolData in self.Data.items():
# self.Debug("Initializing " + symbol)
# symbolData.ATR = AverageTrueRange(self.CreateIndicatorName(symbol, "ATR" + str(20), Resolution.Daily), 20)
# symbolData.Highest = Maximum(self.CreateIndicatorName(symbol, "MAX" + str(52), Resolution.Daily), 52)
# consolidator = QuoteBarConsolidator(BarSize)
# consolidator.DataConsolidated += self.OnDataConsolidated
# self.SubscriptionManager.AddConsolidator(symbolData.FullSymbol, consolidator)
def OnData(self, slice):
'''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
'''
# loop through each symbol in our structure
# for symbol in self.Data.keys():
# symbolData = self.Data[symbol]
# # this check proves that this symbol was JUST updated prior to this OnData function being called
# if symbolData.IsReady() and symbolData.WasJustUpdated(self.Time):
# if not self.Portfolio[symbol].Invested:
# self.MarketOrder(symbol, 1)
# else:
# self.Debug(str(symbol) + " already invested")
# else:
# # pass
# self.Debug(str(symbol) + " not ready yet in " + str(slice.Time))
# self.Debug("Bars: " + str(symbolData.Bars.IsReady))
# if symbolData.ATR is not None:
# self.Debug("ATR: " + str(symbolData.ATR.IsReady))
# else:
# self.Debug("ATR is None")
# if symbolData.Highest is not None:
# self.Debug("Highest: " + str(symbolData.Highest.IsReady))
# else:
# self.Debug("Highest is None")
# for symbol in slice.Bars.Keys:
# # self.Log("Slice key: " + str(symbol))
# # self.Log("Slice time: " + str(self.Time))
# # Let it initialize
# if symbol not in self.Highest or not self.Highest[symbol].IsReady:
# return
# # only once per day
# if self.previous[symbol] is not None and self.previous[symbol].date() == self.Time.date():
# return
# if slice.Bars[symbol].Close > self.Highest[symbol] - 5*self.ATR[symbol] and not self.Portfolio[symbol].Invested:
# self.MarketOrder(symbol, 1)
# elif slice.Bars[symbol].Close < self.Highest[symbol] - 5*self.ATR[symbol] and self.Portfolio[symbol].Invested:
# self.Liquidate(symbol)
# self.previous[symbol] = self.Time
# if not self.Portfolio.Invested:
# self.SetHoldings("SPY", 1)
# if self._slow.IsReady and self._fast.IsReady:
# self.IsUpTrend = self._fast.Current.Value > self._slow.Current.Value * self._tolerance
# self.IsDownTrend = self._fast.Current.Value < self._slow.Current.Value * self._tolerance
# if (not self.Portfolio.Invested) and self.IsUpTrend:
# for chain in slice.FuturesChains:
# # find the front contract expiring no earlier than in 90 days
# contracts = list(filter(lambda x: x.Expiry > self.Time + timedelta(90), chain.Value))
# # if there is any contract, trade the front contract
# if len(contracts) == 0: continue
# contract = sorted(contracts, key = lambda x: x.Expiry, reverse=True)[0]
# self.MarketOrder(contract.Symbol , 1)
# if self.Portfolio.Invested and self.IsDownTrend:
# self.Liquidate()
# for chain in slice.FutureChains.Values:
# contracts = chain.Contracts
# count = 0
# for contract in contracts:
# count = count + 1
# self.Log(str(count))
# # self.Debug(contract.Symbol)
# self.Log(type(slice.Bars))
# self.Log(slice.Bars)
# for tradebar in slice.Bars:
# self.Debug(tradebar)
# for symbol in slice.Keys:
# self.Log("slice.Key: " + symbol)
# for symbol in slice.Bars.Keys:
# self.Log("slice.Bar: " + symbol)
# for chain in slice.FutureChains:
# for contract in chain.Value:
# self.Log("{0},Open={1} High={2} Low={3} Close={4} Volume={5}".format(
# contract.Symbol.Value,
# contract.Open,
# contract.High,
# contract.Low,
# contract.Close,
# contract.Volume))
# for chain in slice.Bars:
# for contract in chain.Value:
# self.Log("{0},Bid={1} Ask={2} Last={3} OI={4}".format(
# contract.Symbol.Value,
# contract.BidPrice,
# contract.AskPrice,
# contract.LastPrice,
# contract.OpenInterest))
# for chain in slice.FutureChains:
# for i in chain.Value:
# askprice = i.AskPrice
# openinterest = i.OpenInterest
# expiry = i.Expiry
# class FuturesContract:
# self.Symbol # (Symbol) Symbol for contract needed to trade.
# self.UnderlyingSymbol # (Symbol) Underlying futures asset.
# self.Expiry # (datetime) When the future expires
# self.OpenInterest # (decimal) Number of open interest.
# self.LastPrice # (decimal) Last sale price.
# self.Volume # (long) reported volume.
# self.BidPrice # (decimal) bid quote price.
# self.BidSize # (long) bid quote size.
# self.AskPrice # (decimal) ask quote price.
# self.AskSize # (long) ask quote size.
def OnDataConsolidated(self, sender, quoteBar):
# self.Log("OnDataConsolidated called on " + str(self.Time))
# self.Debug("OnDataConsolidated called on " + str(quoteBar.Symbol) + " time " + str(self.Time))
# self.Log(str(quoteBar.Close))
symbol = quoteBar.Symbol
if symbol not in self.Data:
self.Debug("symbol key not in self.Data")
# self.Debug("-".join(self.Data.keys()))
# self.Debug(self.Data[symbol].ATR)
# self.Data[symbol].ATR.Update(quoteBar.Time, quoteBar.Close)
self.Data[symbol].ATR.Update(quoteBar)
# self.Debug(str(len(self.Data[symbol].ATR)))
self.Data[symbol].Highest.Update(quoteBar.Time, quoteBar.Close)
# self.Debug(self.Data[symbol])
self.Data[symbol].Bars.Add(quoteBar)
symbolData = self.Data[symbol]
# this check proves that this symbol was JUST updated prior to this OnData function being called
if not symbolData.IsReady():
# self.Debug(str(symbol) + " not ready yet in " + str(quoteBar.Time))
return
if not symbolData.WasJustUpdated(self.Time):
self.Debug(str(symbol) + " wasn't updated yet " + str(quoteBar.Time))
return
# else:
# pass
# self.Debug("Bars: " + str(symbolData.Bars.IsReady))
# if symbolData.ATR is not None:
# self.Debug("ATR: " + str(symbolData.ATR.IsReady))
# else:
# self.Debug("ATR is None")
# if symbolData.Highest is not None:
# self.Debug("Highest: " + str(symbolData.Highest.IsReady))
# else:
# self.Debug("Highest is None")
# # Let it initialize
# if symbol not in self.Highest or not self.Highest[symbol].IsReady:
# self.Debug("Not initialized yet: " + str(symbol))
# return
# # only once per day
# if self.previous[symbol] is not None and self.previous[symbol].date() == self.Time.date():
# self.Debug("Missing previous or already traded this day for : " + str(symbol))
# return
Highest = self.Data[symbol].Highest.Current.Value
ATR = self.Data[symbol].ATR.Current.Value
Line = Highest - 5*ATR
self.Data[symbol].Line = Line
# LONG
if quoteBar.Close >= Highest: # and not self.Portfolio[symbol].Invested:
self.Debug("CLOSE > HIGH for " + str(symbol))
# self.Debug("{0} Quantity {1}".format(self.Time, symbol))
if self.Portfolio[symbol].Quantity < 0:
# self.Debug("{0} LONG {1} Quantity {1}".format(self.Time, symbol, self.Portfolio[symbol].Quantity))
# if self.Portfolio[symbol].Quantity < 0:
# self.MarketOrder(symbol, 2)
self.Debug("{0} CLOSE SHORT {1}, Close={2} >= {3} Invested={4}".format(
self.Time, symbol, quoteBar.Close, Highest, self.Portfolio[symbol].Invested
))
self.Liquidate(symbol)
if self.Portfolio[symbol].Quantity == 0:
self.Debug("{4} OPEN LONG {0}, Close={1} >= Highest={2} Invested={3}".format(
symbol, quoteBar.Close, Highest, self.Portfolio[symbol].Invested, self.Time
))
self.MarketOrder(symbol, 1)
# SHORT
elif quoteBar.Close < Line: # and self.Portfolio[symbol].Invested:
self.Debug("CLOSE < Line for " + str(symbol))
# self.Debug("{0} Low for {1}".format(self.Time, symbol))
# self.Debug("CLOSE {0}, Close={1} Highest={2} 5*ATR={3} Invested={4}".format(
# symbol, quoteBar.Close, Highest, 5*ATR, self.Portfolio[symbol].Invested
# ))
if self.Portfolio[symbol].Quantity > 0:
# self.Debug("{0} SHORT {1} Quantity {1}".format(self.Time, symbol, self.Portfolio[symbol].Quantity))
# self.Debug("SHORT " + str(symbol) + " quantity " + str(self.Portfolio[symbol].Quantity))
# if self.Portfolio[symbol].Quantity > 0:
# self.MarketOrder(symbol, -2)
self.Debug("{0} CLOSE LONG {1}, Close={2} < {3} Invested={4}".format(
self.Time, symbol, quoteBar.Close, Line, self.Portfolio[symbol].Invested
))
self.Liquidate(symbol)
if self.Portfolio[symbol].Quantity == 0:
self.Debug("{5} OPEN SHORT {0}, Close={1} < {5} (Highest={2} - 5*ATR={3}) Invested={4}".format(
symbol, quoteBar.Close, Highest, 5*ATR, self.Portfolio[symbol].Invested, Line, self.Time
))
self.MarketOrder(symbol, -1)
# DO NOTHING
else:
# self.Debug("{5} DO NOTHING {0}, Close={1} Highest={2} Line={3} Invested={4}".format(
# symbol, quoteBar.Close, Highest, Line, self.Portfolio[symbol].Invested, self.Time
# ))
# if self.Portfolio[symbol] is not None and self.Portfolio[symbol].Invested:
# self.Debug(self.Portfolio[symbol].IsLong)
# self.Debug(self.Portfolio[symbol].IsShort)
pass
# self.Plot("My shit", str(symbol), Line)
# self.previous[symbol] = self.Time
# def OnSecuritiesChanged(self, changes):
# for security in changes.AddedSecurities:
# # self.Log("Security changed or added: ", security)
# # self.Log(security.Symbol)
# # if security.Symbol == "SPY":
# # continue
# consolidator = QuoteBarConsolidator(TimeSpan.FromDays(1))
# consolidator.DataConsolidated += self.OnDataConsolidated
# self.SubscriptionManager.AddConsolidator(security.Symbol, consolidator)
# self.consolidators[security.Symbol] = consolidator
# for security in changes.RemovedSecurities:
# # if security.Symbol == "SPY":
# # continue
# consolidator = self.consolidators.pop(security.Symbol)
# self.SubscriptionManager.RemoveConsolidator(security.Symbol, consolidator)
# consolidator.DataConsolidated -= self.OnDataConsolidated
def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
# self.Debug("Adding security: " + str(security.Symbol))
# self.Debug("OnSecuritiesChanged2: " + str(security.Symbol.Value))
self.Data[security.Symbol] = SymbolData(security.Symbol, TimeSpan.FromDays(1), 52)
self.Data[security.Symbol].ATR = AverageTrueRange(self.CreateIndicatorName(security.Symbol, "ATR" + str(20), Resolution.Daily), 20)
self.Data[security.Symbol].Highest = Maximum(self.CreateIndicatorName(security.Symbol, "MAX" + str(52), Resolution.Daily), 52)
consolidator = QuoteBarConsolidator(TimeSpan.FromDays(1))
consolidator.DataConsolidated += self.OnDataConsolidated
self.SubscriptionManager.AddConsolidator(security.Symbol, consolidator)
self.consolidators[security.Symbol] = consolidator
# symbolData = self.Data[security.Symbol]
# symbolData.ATR = AverageTrueRange(self.CreateIndicatorName(symbol, "ATR" + str(20), Resolution.Daily), 20)
# symbolData.Highest = Maximum(self.CreateIndicatorName(symbol, "MAX" + str(52), Resolution.Daily), 52)
# self.Log("Security changed or added: ", security)
# self.Log(security.Symbol)
# if security.Symbol == "SPY":
# continue
for security in changes.RemovedSecurities:
# if security.Symbol == "SPY":
# continue
consolidator = self.consolidators.pop(security.Symbol)
self.SubscriptionManager.RemoveConsolidator(security.Symbol, consolidator)
consolidator.DataConsolidated -= self.OnDataConsolidated
# def OnEndOfDay(self):
# if self.IsUpTrend:
# self.Plot("Indicator Signal", "EOD",1)
# elif self.IsDownTrend:
# self.Plot("Indicator Signal", "EOD",-1)
# elif self._slow.IsReady and self._fast.IsReady:
# self.Plot("Indicator Signal", "EOD",0)
def OnOrderEvent(self, orderEvent):
self.Log(str(orderEvent))
def OnEndOfDay(self):
# i = 0
for symbol in sorted(self.Data.keys()):
symbolData = self.Data[symbol]
# we have too many symbols to plot them all, so plot every other
# i += 1
if symbolData.IsReady() and self.Portfolio[symbol].Invested: # and i%2 == 0:
self.Plot("My shit", str(symbol), self.Portfolio[symbol].Quantity)
else:
self.Plot("My shit", str(symbol), 0)
class SymbolData(object):
def __init__(self, symbol, barPeriod, windowSize):
self.Symbol = symbol
# self.FullSymbol = fullsymbol
# The period used when population the Bars rolling window
self.BarPeriod = barPeriod
# A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and can be accessed like:
# mySymbolData.Bars[0] - most first recent piece of data
# mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing)
self.Bars = RollingWindow[IBaseDataBar](windowSize)
# The simple moving average indicator for our symbol
self.ATR = None
self.Highest = None
self.Line = None
# Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
def IsReady(self):
# if not self.Bars.IsReady:
# parent.Debug("Bars not ready")
# if not self.ATR.IsReady:
# parent.Debug("ATR not ready")
# if not self.Highest.IsReady:
# parent.Debug("Highest not ready")
return self.Bars.IsReady and self.ATR.IsReady and self.Highest.IsReady
# Returns true if the most recent trade bar time matches the current time minus the bar's period, this
# indicates that update was just called on this instance
def WasJustUpdated(self, current):
return self.Bars.Count > 0 and self.Bars[0].Time == current - self.BarPeriod