| Overall Statistics |
|
Total Trades 116 Average Win 4.48% Average Loss -4.21% Compounding Annual Return -18.568% Drawdown 56.500% Expectancy -0.266 Net Profit -46.086% Sharpe Ratio -0.059 Probabilistic Sharpe Ratio 1.360% Loss Rate 64% Win Rate 36% Profit-Loss Ratio 1.06 Alpha -0.025 Beta -0.039 Annual Standard Deviation 0.476 Annual Variance 0.227 Information Ratio -0.227 Tracking Error 0.488 Treynor Ratio 0.715 Total Fees $335.92 Estimated Strategy Capacity $72000.00 Lowest Capacity Asset CSC WQWXTW2FXGJL |
#region imports
from AlgorithmImports import *
#endregion
class CommidityMomentumEffect(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015,1, 1)
self.SetEndDate(2018, 1, 1)
self.SetCash(100000)
self.symbols = [
Futures.Dairy.CashSettledButter,
Futures.Dairy.CashSettledCheese,
Futures.Dairy.ClassIIIMilk,
Futures.Dairy.DryWhey,
Futures.Dairy.ClassIVMilk,
Futures.Dairy.NonfatDryMilk,
Futures.Meats.LiveCattle,
Futures.Meats.FeederCattle,
Futures.Meats.LeanHogs,
Futures.Forestry.RandomLengthLumber
]
period = 252
self.data = {}
for symbol in self.symbols:
future = self.AddFuture(symbol,
resolution = Resolution.Daily,
extendedMarketHours = True,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.OpenInterest,
contractDepthOffset = 0
)
future.SetLeverage(1)
self.data[future.Symbol] = SymbolData(self, future, period)
# Rebalance the portfolio every month
self.rebalance = self.Time
def OnData(self, slice):
# Update the indicator value every day
for symbol, symbol_data in self.data.items():
if slice.Bars.ContainsKey(symbol):
symbol_data.Update(slice.Bars[symbol])
if self.rebalance <= self.Time:
# sorted futures by 12-month return reversely
self.sorted_roc = sorted([x for x in self.data.values() if x.IsReady], key = lambda x: x.Value, reverse=True)
number_futures = int(0.25*len(self.sorted_roc))
if number_futures == 0: return
self.long = [x for x in self.sorted_roc[:number_futures]]
self.short = [x for x in self.sorted_roc[-number_futures:]]
for symbol in self.Portfolio.Keys:
# liquidate the futures which is no longer in the trading list
if self.Portfolio[symbol].Invested and symbol not in [x.Mapped for x in self.long + self.short]:
self.Liquidate(symbol)
for long in self.long:
qty = self.CalculateOrderQuantity(long.Mapped, 0.5/number_futures)
self.MarketOrder(long.Mapped, qty // long.Multiplier)
for short in self.short:
qty = self.CalculateOrderQuantity(short.Mapped, -0.5/number_futures)
self.MarketOrder(short.Mapped, qty // short.Multiplier)
self.rebalance = Expiry.EndOfMonth(self.Time)
class SymbolData:
def __init__(self, algorithm, future, period):
self._future = future
self.Symbol = future.Symbol
self.ROC = RateOfChange(period)
# warm up indicator
algorithm.WarmUpIndicator(self.Symbol, self.ROC, Resolution.Daily)
@property
def IsReady(self):
return self.ROC.IsReady and self._future.Mapped is not None
@property
def Value(self):
return self.ROC.Current.Value
@property
def Mapped(self):
return self._future.Mapped
@property
def Multiplier(self):
return self._future.SymbolProperties.ContractMultiplier
def Update(self, bar):
self.ROC.Update(bar.EndTime, bar.Close)