Overall Statistics |
Total Trades 142 Average Win 1.16% Average Loss -1.16% Compounding Annual Return 5.874% Drawdown 12.800% Expectancy 0.026 Net Profit 5.907% Sharpe Ratio 0.541 Loss Rate 49% Win Rate 51% Profit-Loss Ratio 0.99 Alpha 0.112 Beta -4.095 Annual Standard Deviation 0.089 Annual Variance 0.008 Information Ratio 0.367 Tracking Error 0.089 Treynor Ratio -0.012 Total Fees $12818.65 |
# https://quantpedia.com/Screener/Details/23 from datetime import timedelta from math import floor from decimal import Decimal import numpy as np class CommodityMomentumCombinedWithTermStructureAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2016, 1, 1) self.SetEndDate(2017, 1, 1) self.SetCash(10000000) tickers = [ Futures.Softs.Cocoa, Futures.Softs.Coffee, Futures.Grains.Corn, Futures.Softs.Cotton2, Futures.Grains.Oats, Futures.Softs.OrangeJuice, Futures.Grains.SoybeanMeal, Futures.Grains.SoybeanOil, Futures.Grains.Soybeans, Futures.Softs.Sugar11, Futures.Grains.Wheat, Futures.Meats.FeederCattle, Futures.Meats.LeanHogs, Futures.Meats.LiveCattle, Futures.Energies.CrudeOilWTI, Futures.Energies.HeatingOil, Futures.Energies.NaturalGas, Futures.Energies.Gasoline, Futures.Metals.Gold, Futures.Metals.Palladium, Futures.Metals.Platinum, Futures.Metals.Silver ] for ticker in tickers: future = self.AddFuture(ticker) future.SetFilter(timedelta(0), timedelta(days = 90)) self.chains = {} self.AddEquity("SPY", Resolution.Minute) self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 30), self.Rebalance) self.rebalance = False def OnData(self,slice): if not self.rebalance: return # Saves the Futures Chains for chain in slice.FutureChains: if chain.Value.Contracts.Count < 2: continue if chain.Value.Symbol.Value not in self.chains: self.chains[chain.Value.Symbol.Value] = [i for i in chain.Value] self.chains[chain.Value.Symbol.Value] = [i for i in chain.Value] self.Liquidate() roll_return = {} for symbol, chain in self.chains.items(): contracts = sorted(chain, key = lambda x: x.Expiry) expiry_nearest = contracts[0].Expiry price_nearest = float(contracts[0].LastPrice) if contracts[0].LastPrice>0 else 0.5*float(contracts[0].AskPrice+contracts[0].BidPrice) for x in contracts[1:]: roll_return[x] = (price_nearest-float(x.LastPrice))*365 / (x.Expiry-expiry_nearest).days sorted_by_roll_return = sorted(roll_return, key = lambda x: roll_return[x], reverse =True) tertile = floor(1/3*len(sorted_by_roll_return)) high = sorted_by_roll_return[:tertile] low = sorted_by_roll_return[-tertile:] mean_return_high = {} for i in high: hist = self.History(i.Symbol, timedelta(days = 21), Resolution.Minute) if hist.empty: continue hist_close = hist['close'][i.Expiry][i.Symbol.Value] mean_return_high[i] = np.mean(hist_close.pct_change()) high_winners = sorted(mean_return_high, key = lambda x: mean_return_high[x], reverse=True)[:int(len(high)*0.5)] mean_return_low = {} for i in low: hist = self.History(i.Symbol, timedelta(days = 21), Resolution.Minute) if hist.empty: continue hist_close = hist['close'][i.Expiry][i.Symbol.Value] mean_return_low[i] = np.mean(hist_close.pct_change()) low_losers = sorted(mean_return_low, key = lambda x: mean_return_low[x], reverse=True)[-int(len(low)*0.5):] short_weight = 0.5/len(low_losers) for short in low_losers: self.SetHoldings(short.Symbol, -short_weight) long_weight = 0.5/len(high_winners) for long in high_winners: self.SetHoldings(long.Symbol, long_weight) self.rebalance = False def Rebalance(self): self.rebalance = True