| Overall Statistics |
|
Total Trades 754 Average Win 0.38% Average Loss -0.46% Compounding Annual Return -2.269% Drawdown 17.700% Expectancy -0.068 Net Profit -11.850% Sharpe Ratio -0.425 Loss Rate 49% Win Rate 51% Profit-Loss Ratio 0.82 Alpha -0.048 Beta 1.367 Annual Standard Deviation 0.05 Annual Variance 0.002 Information Ratio -0.817 Tracking Error 0.05 Treynor Ratio -0.015 Total Fees $0.00 |
# https://quantpedia.com/Screener/Details/118
from QuantConnect.Python import PythonQuandl
import numpy as np
class TimeSeriesMomentumEffect(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2013,1, 1)
self.SetEndDate(2018, 7, 1)
self.SetCash(1000000)
self.symbols = ["CHRIS/CME_LC1", # Live Cattle Futures, Continuous Contract #1
"CHRIS/CME_LN1", # Lean Hog Futures, Continuous Contract #1
"CHRIS/ICE_B1", # Brent Crude Futures, Continuous Contract
"CHRIS/ICE_G1", # Gas Oil Futures, Continuous Contract
"CHRIS/ICE_CT1", # Cotton No. 2 Futures, Continuous Contract
"CHRIS/ICE_KC1", # Coffee C Futures, Continuous Contract
"CHRIS/ICE_CC1", # Cocoa Futures, Continuous Contract
"CHRIS/ICE_SB1", # Sugar No. 11 Futures, Continuous Contract
"CHRIS/CME_C1", #Corn Futures, Continuous Contract #1 (C1) (Front Month)
"CHRIS/CME_S1", #Soybean Futures, Continuous Contract #1 (S1) (Front Month)
"CHRIS/CME_SM1", #Soybean Meal Futures, Continuous Contract #1 (SM1) (Front Month)
"CHRIS/CME_BO1", #Soybean Oil Futures, Continuous Contract #1 (BO1) (Front Month)
"CHRIS/CME_W1", #Wheat Futures, Continuous Contract #1 (W1) (Front Month)
]
period = 252
self.roc = {}
for symbol in self.symbols:
self.AddData(QuandlFutures, symbol, Resolution.Daily)
self.roc[symbol] = self.ROC(symbol, period)
# hist = self.History([symbol], 300, Resolution.Daily).loc[symbol]
# for i in hist.itertuples():
# self.roc[symbol].Update(i.Index, i.settle)
self.RegisterIndicator(symbol, self.roc[symbol], Resolution.Daily)
self.SetWarmup(period)
# Rebalance the portfolio every month
self.Schedule.On(self.DateRules.MonthStart("CHRIS/CME_S1"), self.TimeRules.AfterMarketOpen("CHRIS/CME_S1"), self.Rebalance)
def OnData(self, data):
# Update the indicator value every day
# for symbol in self.symbols:
# if data.ContainsKey(symbol) and self.roc[symbol].IsReady:
# self.roc[symbol].Update(self.Time, data[symbol].Value)
pass
def Rebalance(self):
#choose contracts with positive momentum to long
long_symbols = [symbol for symbol in self.roc if self.roc[symbol].Current.Value >= 0]
#choose contracts with negative momentum to short
short_symbols = [symbol for symbol in self.roc if self.roc[symbol].Current.Value < 0]
self.Liquidate()
weights_long = {} #contracts' weights for long
weights_short = {} #contracts' weights for short
volatility = {} #estimated volatility
try:
for symbol in self.symbols:
hist = self.History(self.Symbol(symbol), 252, Resolution.Daily).loc[symbol]['value']
log_return = np.log((hist/hist.shift()).dropna().tolist())
volatility[symbol] = 1/np.std(log_return,ddof = 1)
#calculate the historical volatility and get its reciprocal because the weight is inversely proportional to its volatility
for long_symbol in long_symbols:
weights_long[long_symbol] = volatility[long_symbol]/sum(volatility.values()) #normalize the weights, making sure the sum is 1
for short_symbol in short_symbols:
weights_short[short_symbol] = volatility[short_symbol]/sum(volatility.values()) #normalize the weights, making sure the sum is 1
#SetHoldings to trade
for short_symbol in short_symbols:
self.SetHoldings(short_symbol, -0.5*weights_short[short_symbol]/sum(weights_short.values()))
for long_symbol in long_symbols:
self.SetHoldings(long_symbol, 0.5*weights_long[long_symbol]/sum(weights_long.values()))
except:
pass
class QuandlFutures(PythonQuandl):
def __init__(self):
self.ValueColumnName = "Settle"
#set the column name of value to "Settle", becasue the column name of desired data from Quandl is "Settle".