Overall Statistics |
Total Trades
1720
Average Win
0.75%
Average Loss
-0.76%
Compounding Annual Return
1.043%
Drawdown
25.100%
Expectancy
0.021
Net Profit
9.790%
Sharpe Ratio
0.158
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
0.99
Alpha
0.014
Beta
-0.002
Annual Standard Deviation
0.09
Annual Variance
0.008
Information Ratio
-0.602
Tracking Error
0.173
Treynor Ratio
-6.663
Total Fees
$0.00
|
# https://quantpedia.com/strategies/term-structure-effect-in-commodities/ # # This simple strategy buys each month the 20% of commodities with the highest roll-returns and shorts the 20% of commodities with the lowest # roll-returns and holds the long-short positions for one month. The contracts in each quintile are equally-weighted. # The investment universe is all commodity futures contracts. from datetime import datetime from collections import deque class Term_Structure_Commodities(QCAlgorithm): def Initialize(self): self.SetStartDate(2010, 1, 1) self.SetEndDate(2019, 1, 1) self.SetCash(100000) self.symbols = ["CME_S", # Soybean Futures, Continuous Contract "CME_W", # Wheat Futures, Continuous Contract "CME_SM", # Soybean Meal Futures, Continuous Contract "CME_BO", # Soybean Oil Futures, Continuous Contract "CME_C", # Corn Futures, Continuous Contract "CME_O", # Oats Futures, Continuous Contract "CME_LC", # Live Cattle Futures, Continuous Contract "CME_FC", # Feeder Cattle Futures, Continuous Contract "CME_LN", # Lean Hog Futures, Continuous Contract "CME_GC", # Gold Futures, Continuous Contract "CME_SI", # Silver Futures, Continuous Contract "CME_PL", # Platinum Futures, Continuous Contract "CME_CL", # Crude Oil Futures, Continuous Contract "CME_HG", # Copper Futures, Continuous Contract "CME_LB", # Random Length Lumber Futures, Continuous Contract "CME_PA", # Palladium Futures, Continuous Contract "CME_RR", # Rough Rice Futures, Continuous Contract "ICE_CC", # Cocoa Futures, Continuous Contract "ICE_CT", # Cotton No. 2 Futures, Continuous Contract "ICE_KC", # Coffee C Futures, Continuous Contract "ICE_O", # Heating Oil Futures, Continuous Contract "ICE_OJ", # Orange Juice Futures, Continuous Contract "ICE_SB" # Sugar No. 11 Futures, Continuous Contract ] self.lookup_period = 12 * 21 self.SetWarmUp(self.lookup_period) self.data = {} # True -> Quantpedia data # False -> Quandl free data self.use_quantpedia_data = True if self.use_quantpedia_data: for symbol in self.symbols: sym = symbol + '1' data = self.AddData(QuantpediaFutures, sym, Resolution.Daily) #data.SetLeverage(2) self.symbols2 = ['CHRIS/' + x for x in self.symbols] for symbol in self.symbols2: for symbol_index in range(1,3): sym = symbol + str(symbol_index) self.AddData(QuandlFutures, sym, Resolution.Daily) self.Schedule.On(self.DateRules.MonthStart(self.symbols2[0] + '1'), self.TimeRules.AfterMarketOpen(self.symbols2[0] + '1'), self.Rebalance) def Rebalance(self): if self.IsWarmingUp: return # Roll return sorting roll_return = {} for symbol_index in range(0, len(self.symbols2)): symbol = self.symbols2[symbol_index] sym1 = symbol + '1' sym2 = symbol + '2' traded_symbol = '' if self.use_quantpedia_data: traded_symbol = self.symbols[symbol_index] + '1' else: traded_symbol = sym1 roll_return[traded_symbol] = (self.Securities[sym2].Price - self.Securities[sym1].Price) / self.Securities[sym1].Price if len(roll_return) == 0: return sorted_by_roll = sorted(roll_return.items(), key=lambda x: x[1], reverse = True) quintile = int(len(sorted_by_roll)/5) top = sorted_by_roll[-quintile:] top = [x[0] for x in top] low = sorted_by_roll[:quintile] low = [x[0] for x in low] # Trade execution count = len(top+low) self.Liquidate() for symbol in top: self.SetHoldings(symbol, 1/count) for symbol in low: self.SetHoldings(symbol, -1/count) def Return(self, history): return (history[-1] - history[0]) / history[0] # Quantpedia data class QuantpediaFutures(PythonData): def GetSource(self, config, date, isLiveMode): return SubscriptionDataSource("http://data.quantpedia.com/backtesting_data/futures/{0}.csv".format(config.Symbol.Value), SubscriptionTransportMedium.RemoteFile, FileFormat.Csv) def Reader(self, config, line, date, isLiveMode): data = QuantpediaFutures() data.Symbol = config.Symbol try: if not line[0].isdigit(): return None split = line.split(';') data.Time = datetime.strptime(split[0], "%d.%m.%Y") + timedelta(days=1) data['settle'] = float(split[1]) data.Value = float(split[1]) except: return None return data # Quandl free data class QuandlFutures(PythonQuandl): def __init__(self): self.ValueColumnName = "settle"