Overall Statistics |
Total Orders 120 Average Win 5.08% Average Loss -5.90% Compounding Annual Return -34.380% Drawdown 77.700% Expectancy -0.393 Start Equity 100000 End Equity 28221.44 Net Profit -71.779% Sharpe Ratio -0.167 Sortino Ratio -0.174 Probabilistic Sharpe Ratio 0.805% Loss Rate 67% Win Rate 33% Profit-Loss Ratio 0.86 Alpha -0.117 Beta 0.191 Annual Standard Deviation 0.621 Annual Variance 0.386 Information Ratio -0.279 Tracking Error 0.627 Treynor Ratio -0.543 Total Fees $360.62 Estimated Strategy Capacity $0 Lowest Capacity Asset GNF WTDK2AZMTCZL Portfolio Turnover 9.58% |
#region imports from AlgorithmImports import * #endregion class CommidityMomentumEffect(QCAlgorithm): def initialize(self): self.set_start_date(2015,1, 1) self.set_end_date(2018, 1, 1) self.set_cash(100000) self.set_security_initializer( BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)) ) symbols = [ Futures.Dairy.CASH_SETTLED_BUTTER, Futures.Dairy.CASH_SETTLED_CHEESE, Futures.Dairy.CLASS_III_MILK, Futures.Dairy.DRY_WHEY, Futures.Dairy.CLASS_IV_MILK, Futures.Dairy.NONFAT_DRY_MILK, Futures.Meats.LIVE_CATTLE, Futures.Meats.FEEDER_CATTLE, Futures.Meats.LEAN_HOGS, Futures.Forestry.RANDOM_LENGTH_LUMBER ] period = 252 self._data = {} for symbol in symbols: future = self.add_future(symbol, resolution=Resolution.MINUTE, extended_market_hours=True, data_normalization_mode=DataNormalizationMode.BACKWARDS_RATIO, data_mapping_mode=DataMappingMode.OPEN_INTEREST, contract_depth_offset=0 ) future.set_leverage(1) self._data[future.symbol] = SymbolData(self, future, period) # Rebalance the portfolio every month self._rebalance = self.time def on_data(self, slice): if self._rebalance <= self.time: # sorted futures by 12-month return reversely sorted_roc = sorted([x for x in self._data.values() if x.is_ready], key = lambda x: x.value, reverse=True) number_futures = int(0.25*len(sorted_roc)) if number_futures == 0: return longs = [x for x in sorted_roc[:number_futures]] shorts = [x for x in sorted_roc[-number_futures:]] for symbol, security_holding in self.portfolio.items(): # liquidate the futures which is no longer in the trading list if security_holding.invested and symbol not in [x.mapped for x in longs + shorts]: self.liquidate(symbol) for long_ in longs: qty = self.calculate_order_quantity(long_.mapped, 0.5/number_futures) // long_.multiplier if qty: self.market_order(long_.mapped, qty) for short in shorts: qty = self.calculate_order_quantity(short.mapped, -0.5/number_futures) // short.multiplier if qty: self.market_order(short.mapped, qty) self._rebalance = Expiry.end_of_month(self.time) class SymbolData: def __init__(self, algorithm, future, period): self._future = future symbol = future.symbol self._roc = algorithm.roc(symbol, period, Resolution.DAILY) # warm up indicator algorithm.warm_up_indicator(symbol, self._roc, Resolution.DAILY) @property def is_ready(self): return self._roc.is_ready 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.symbol_properties.contract_multiplier