Overall Statistics |
Total Trades 7986 Average Win 0.35% Average Loss -0.18% Compounding Annual Return -83.012% Drawdown 84.400% Expectancy -0.234 Net Profit -83.094% Sharpe Ratio -2.859 Probabilistic Sharpe Ratio 0.000% Loss Rate 74% Win Rate 26% Profit-Loss Ratio 1.92 Alpha -0.694 Beta -0.224 Annual Standard Deviation 0.262 Annual Variance 0.069 Information Ratio -3.394 Tracking Error 0.295 Treynor Ratio 3.346 Total Fees $14774.10 |
import clr import decimal as d import pandas as pd class FuturesMovingAverage (QCAlgorithm): def Initialize(self): self.contract = None self.SetStartDate(2019, 1, 1) self.SetEndDate(2020, 1, 1) self.SetCash(100000) self.SetWarmUp(TimeSpan.FromDays(5)) self.SetTimeZone("America/New_York") self.new_day = True self.reset = True CL = self.AddFuture(Futures.Energies.CrudeOilWTI) CL.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(360)) self.consolidators = {} self.movingAverages = {} self.sma = None self.sma_period = 60 self.window = RollingWindow[TradeBar](3) def OnData(self, slice): if not self.InitUpdateContract(slice): return if self.reset: self.reset = False def InitUpdateContract(self, slice): if not self.new_day: return True if self.contract != None and (self.contract.Expiry - self.Time).days >= 3: return True for chain in slice.FutureChains.Values: idx = 0 if self.contract != None: self.Log('Expiry days away {} - {}'.format((self.contract.Expiry-self.Time).days, self.contract.Expiry)) if self.contract != None and (self.contract.Expiry - self.Time).days < 3: idx = 1 contracts = list(chain.Contracts.Values) chain_contracts = list(contracts) chain_contracts = sorted(chain_contracts, key=lambda x: x.Expiry) if len(chain_contracts) < 2: return False first = chain_contracts[idx] second = chain_contracts[idx+1] if (first.Expiry - self.Time).days >= 3: self.contract = first elif (first.Expiry - self.Time).days < 3 and (second.Expiry - self.Time).days >= 3: self.contract = second self.Log("Setting contract to: {}".format(self.contract.Symbol.Value)) self.new_day = False self.reset = True if self.contract.Symbol not in self.consolidators: self.consolidators[self.contract.Symbol] = self.Consolidate( self.contract.Symbol, timedelta(minutes=5), self.OnFiveMinutes) if self.contract.Symbol not in self.movingAverages: self.movingAverages[self.contract.Symbol] = self.SMA(self.contract.Symbol, self.sma_period, Resolution.Minute) history = self.History(self.contract.Symbol, self.sma_period, Resolution.Minute) if not history.empty: history = history.close.unstack(1) for index, close in history[self.contract.Symbol].items(): time = index[1] self.movingAverages[self.contract.Symbol].Update(time, close) return True return False def OnFiveMinutes(self, bar): self.window.Add(bar) if not self.window.IsReady: return currentBar = self.window[0] nearBar = self.window[1] farBar = self.window[2] if bar.Symbol != self.contract.Symbol: return sma = self.movingAverages.get(bar.Symbol, None) if sma is None or not sma.IsReady: return near = nearBar.Close far = farBar.Close sma = sma.Current.Value price = bar.Close holdings = self.Portfolio[bar.Symbol].Quantity if not self.Portfolio.Invested: if far < sma and near > sma and price > near: self.MarketOrder(bar.Symbol, 1) if far > sma and near < sma and price < near: self.MarketOrder(bar.Symbol, -1) if holdings > 0 and price < sma: self.Liquidate(bar.Symbol) if holdings < 0 and price > sma: self.Liquidate(bar.Symbol) def OnEndOfDay(self): self.new_day = True