Overall Statistics |
Total Trades 449 Average Win 1.28% Average Loss -0.89% Compounding Annual Return 9.227% Drawdown 22.700% Expectancy 0.067 Net Profit 14.172% Sharpe Ratio 0.409 Probabilistic Sharpe Ratio 18.559% Loss Rate 56% Win Rate 44% Profit-Loss Ratio 1.44 Alpha 0.096 Beta -0.107 Annual Standard Deviation 0.214 Annual Variance 0.046 Information Ratio 0.016 Tracking Error 0.263 Treynor Ratio -0.817 Total Fees $3727.75 Estimated Strategy Capacity $130000000.00 Lowest Capacity Asset LBS 1S1 |
#region imports from AlgorithmImports import * #endregion # futs_list = [Futures.Indices.SP500EMini, Futures.Grains.Corn, Futures.Currencies.JPY] futs_list = [ Futures.Grains.BlackSeaCornFinanciallySettledPlatts, Futures.Grains.BlackSeaWheatFinanciallySettledPlatts, Futures.Grains.SRWWheat, Futures.Grains.HRWWheat, Futures.Grains.Corn, Futures.Grains.Soybeans, Futures.Grains.SoybeanMeal, Futures.Grains.SoybeanOil, Futures.Grains.Oats, Futures.Currencies.GBP, Futures.Currencies.CAD, Futures.Currencies.JPY, Futures.Currencies.CHF, Futures.Currencies.EUR, Futures.Currencies.AUD, Futures.Currencies.NZD, Futures.Currencies.RUB, Futures.Currencies.BRL, Futures.Currencies.MXN, Futures.Currencies.ZAR, # Futures.Currencies.AUDCAD, # Futures.Currencies.AUDJPY, # Futures.Currencies.AUDNZD, # Futures.Currencies.BTC, # Futures.Currencies.CADJPY, # Futures.Currencies.StandardSizeUSDOffshoreRMBCNH, # Futures.Currencies.EuroFXEmini, # Futures.Currencies.EURAUD, # Futures.Currencies.EURCAD, # Futures.Currencies.EURSEK, # Futures.Currencies.JapaneseYenEmini, # Futures.Energies.PropaneNonLDHMontBelvieu, # Futures.Energies.ArgusPropaneFarEastIndexBALMO, # Futures.Energies.MiniEuropeanThreePointPercentFiveFuelOilBargesPlatts, # Futures.Energies.MiniSingaporeFuelOil180CstPlatts, # Futures.Energies.GulfCoastULSDPlattsUpDownBALMO, # Futures.Energies.GulfCoastJetPlattsUpDownBALMO, # Futures.Energies.PropaneNonLDHMontBelvieuOPIS, # Futures.Energies.EuropeanPropaneCIFARAArgusBALMO, # Futures.Energies.PremiumUnleadedGasoline10ppmFOBMEDPlatts, # Futures.Energies.ArgusPropaneFarEastIndex, # Futures.Energies.GasolineEurobobOxyNWEBargesArgusCrackSpreadBALMO, # Futures.Energies.MontBelvieuNaturalGasolineOPIS, # Futures.Energies.MontBelvieuNormalButaneOPISBALMO, # Futures.Energies.ConwayPropaneOPIS, # Futures.Energies.MontBelvieuLDHPropaneOPISBALMO, # Futures.Energies.ArgusPropaneFarEastIndexVsEuropeanPropaneCIFARAArgus, # Futures.Energies.ArgusPropaneSaudiAramco, # Futures.Energies.GroupThreeULSDPlattsVsNYHarborULSD, # Futures.Energies.GroupThreeSuboctaneGasolinePlattsVsRBOB, # Futures.Energies.SingaporeFuelOil180cstPlattsBALMO, # Futures.Energies.SingaporeFuelOil380cstPlattsBALMO, # Futures.Energies.MontBelvieuEthaneOPIS, # Futures.Energies.MontBelvieuNormalButaneOPIS, # Futures.Energies.BrentCrudeOilVsDubaiCrudeOilPlatts, # Futures.Energies.ArgusLLSvsWTIArgusTradeMonth, # Futures.Energies.SingaporeGasoilPlattsVsLowSulphurGasoilFutures, # Futures.Energies.LosAngelesCARBOBGasolineOPISvsRBOBGasoline, # Futures.Energies.LosAngelesJetOPISvsNYHarborULSD, # Futures.Energies.LosAngelesCARBDieselOPISvsNYHarborULSD, # Futures.Energies.EuropeanNaphthaPlattsBALMO, # Futures.Energies.EuropeanPropaneCIFARAArgus, # Futures.Energies.MontBelvieuNaturalGasolineOPISBALMO, # Futures.Energies.RBOBGasolineCrackSpread, # Futures.Energies.GulfCoastHSFOPlattsBALMO, # Futures.Energies.MarsArgusVsWTITradeMonth, # Futures.Energies.MarsArgusVsWTIFinancial, # Futures.Energies.EthanolT2FOBRdamIncludingDutyPlatts, # Futures.Energies.MontBelvieuLDHPropaneOPIS, # Futures.Energies.GasolineEurobobOxyNWEBargesArgus, # Futures.Energies.WTIBrentFinancial, # Futures.Energies.ThreePointFivePercentFuelOilBargesFOBRdamPlattsCrackSpread1000mt, # Futures.Energies.GasolineEurobobOxyNWEBargesArgusBALMO, # Futures.Energies.BrentLastDayFinancial, Futures.Energies.CrudeOilWTI, # Futures.Energies.GulfCoastCBOBGasolineA2PlattsVsRBOBGasoline, # Futures.Energies.ClearbrookBakkenSweetCrudeOilMonthlyIndexNetEnergy, # Futures.Energies.WTIFinancial, # Futures.Energies.ChicagoEthanolPlatts, # Futures.Energies.SingaporeMogas92UnleadedPlattsBrentCrackSpread, # Futures.Energies.DubaiCrudeOilPlattsFinancial, # Futures.Energies.JapanCnFNaphthaPlattsBALMO, Futures.Energies.Ethanol, # Futures.Energies.EuropeanNaphthaPlattsCrackSpread, # Futures.Energies.EuropeanPropaneCIFARAArgusVsNaphthaCargoesCIFNWEPlatts, # Futures.Energies.SingaporeFuelOil380cstPlattsVsEuropeanThreePointFivePercentFuelOilBargesFOBRdamPlatts, # Futures.Energies.EastWestGasolineSpreadPlattsArgus, # Futures.Energies.EastWestNaphthaJapanCFvsCargoesCIFNWESpreadPlatts, # Futures.Energies.RBOBGasolineVsEurobobOxyNWEBargesArgusThreeHundredFiftyThousandGallons, # Futures.Energies.ThreePointFivePercentFuelOilBargesFOBRdamPlattsCrackSpread, # Futures.Energies.FreightRouteTC14Baltic, # Futures.Energies.OnePercentFuelOilCargoesFOBNWEPlattsVsThreePointFivePercentFuelOilBargesFOBRdamPlatts, # Futures.Energies.GulfCoastHSFOPlattsVsEuropeanThreePointFivePercentFuelOilBargesFOBRdamPlatts, Futures.Energies.WTIHoustonCrudeOil, # Futures.Energies.NaturalGasHenryHubLastDayFinancial, Futures.Energies.HeatingOil, # Futures.Energies.NaturalGasHenryHubPenultimateFinancial, # Futures.Energies.WTIHoustonArgusVsWTITradeMonth, Futures.Energies.Gasoline, Futures.Energies.NaturalGas, Futures.Financials.Y30TreasuryBond, Futures.Financials.Y10TreasuryNote, Futures.Financials.Y5TreasuryNote, Futures.Financials.Y2TreasuryNote, Futures.Financials.EuroDollar, # Futures.Financials.FiveYearUSDMACSwap, # Futures.Financials.UltraUSTreasuryBond, # Futures.Financials.UltraTenYearUSTreasuryNote, Futures.Indices.SP500EMini, Futures.Indices.NASDAQ100EMini, # Futures.Indices.Dow30EMini, # Futures.Indices.VIX, # Futures.Indices.Russell2000EMini, Futures.Indices.Nikkei225Dollar, Futures.Indices.BloombergCommodityIndex, Futures.Indices.NASDAQ100BiotechnologyEMini, Futures.Indices.FTSEEmergingEmini, Futures.Indices.SP400MidCapEmini, Futures.Indices.SPGSCICommodity, Futures.Indices.USDDenominatedIbovespa, Futures.Indices.MSCITaiwanIndex, Futures.Indices.Nikkei225Yen, Futures.Indices.Nifty50, Futures.Indices.HangSeng, Futures.Forestry.RandomLengthLumber, Futures.Meats.LiveCattle, Futures.Meats.FeederCattle, Futures.Meats.LeanHogs, Futures.Metals.Gold, Futures.Metals.Silver, Futures.Metals.Platinum, Futures.Metals.Palladium, Futures.Metals.AluminumMWUSTransactionPremiumPlatts25MT, Futures.Metals.AluminiumEuropeanPremiumDutyPaidMetalBulletin, Futures.Metals.Copper, Futures.Metals.USMidwestDomesticHotRolledCoilSteelCRUIndex, Futures.Softs.Sugar11CME, Futures.Softs.Cocoa, Futures.Dairy.CashSettledButter, Futures.Dairy.CashSettledCheese, Futures.Dairy.ClassIIIMilk, Futures.Dairy.DryWhey, Futures.Dairy.ClassIVMilk, Futures.Dairy.NonfatDryMilk, ]
# region imports from AlgorithmImports import * # endregion from Futs import futs_list class FutureObject(object): def __init__(self, algo, symbol): self.algo = algo self.future = self.algo.AddFuture(symbol, self.algo.Resolution, dataNormalizationMode = DataNormalizationMode.BackwardsRatio, dataMappingMode = DataMappingMode.OpenInterest, contractDepthOffset = 0) self.consolidator = TradeBarConsolidator(timedelta(days=1)) # before continuous futures they recommended QuoteBarConsolidator. self.consolidator.DataConsolidated += self.algo.OnDataConsolidated self.algo.SubscriptionManager.AddConsolidator(self.future.Symbol, self.consolidator) self.multiplier = self.future.SymbolProperties.ContractMultiplier self.fast_ma_bars = 50 self.slow_ma_bars = 100 self.atr_bars = 100 self.lookback_bars = 252 self.fast_highlow_bars = 25 self.slow_highlow_bars = 50 self.fast_ma = SimpleMovingAverage(f"FAST_MA", self.fast_ma_bars) self.slow_ma = SimpleMovingAverage(f"SLOW_MA", self.slow_ma_bars) self.atr = AverageTrueRange(f"ATR", self.atr_bars) self.fast_high = Maximum(f"FAST_HIGH", self.fast_highlow_bars) self.slow_high = Maximum(f"SLOW_HIGH", self.slow_highlow_bars) self.fast_low = Minimum(f"FAST_LOW", self.fast_highlow_bars) self.slow_low = Minimum(f"SLOW_LOW", self.slow_highlow_bars) self.logr = LogReturn(f"LOGR", 1) self.logr.Updated += self.logr_updated self.closes = RollingWindow[float](self.lookback_bars) self.volumes = RollingWindow[float](3) self.logrs = RollingWindow[float](self.lookback_bars) self.volume = 0 self.invested = 0 self.size = 0 self.high_since_buy = 0 self.low_since_buy = 9e99 self.indicators = [ self.fast_ma, self.slow_ma, self.atr, self.fast_high, self.slow_high, self.fast_low, self.slow_low, self.logr, ] def reset(self): self.invested = 0 self.size = 0 self.high_since_buy = 0 self.low_since_buy = 9e99 def logr_updated(self, sender, updated): self.logrs.Add(updated.Value) def is_ready(self): for indicator in self.indicators: if not indicator.IsReady: return False return True def trade(self, close): signal = self.signal(close) if self.invested == 0: if signal == 1: self.open_position(1, close) elif signal == -1: self.open_position(-1, close) else: if signal == -1: self.close_position() def close_position(self): self.algo.Liquidate(self.future.Symbol) self.reset() def open_position(self, signal, price): contracts = self.get_size(price) if (signal == 1) and (contracts): self.algo.Debug(f"Buying {self.future.Symbol}") self.algo.Buy(self.future.Symbol, contracts) self.size = contracts self.invested = 1 elif (signal == -1) and (contracts): self.algo.Debug(f"Shorting {self.future.Symbol}") self.algo.Sell(self.future.Symbol, contracts) self.size = contracts self.invested = -1 def signal(self, close): if self.invested == 0: if (self.fast_ma.Current.Value > self.slow_ma.Current.Value) and (close > self.slow_high.Current.Value): return 1 if (self.fast_ma.Current.Value < self.slow_ma.Current.Value) and (close < self.slow_low.Current.Value): return -1 return 0 self.high_since_buy = np.max([self.high_since_buy, close]) self.low_since_buy = np.min([self.low_since_buy, close]) if self.invested == 1: if (close < self.fast_low.Current.Value): return -1 if (close < self.high_since_buy - self.atr.Current.Value * 3): return -1 return 0 elif self.invested == -1: if (close > self.fast_high.Current.Value): return -1 if (close > self.low_since_buy + self.atr.Current.Value * 3): return -1 return 0 def get_volume(self, close): self.volume = np.mean([x for x in list(self.volumes)]) def get_size(self, price): atr = self.atr.Current.Value if atr == 0: return 0 num_contracts = (self.algo.risk_factor * self.algo.Portfolio.TotalPortfolioValue) / \ (atr * self.multiplier) notional = num_contracts * self.multiplier * price if (notional > self.algo.Portfolio.MarginRemaining): self.algo.Debug(f"Not enough margin remaining to buy {num_contracts} of {self.future.Symbol} ({notional})") return None if (num_contracts < 1): self.algo.Debug(f"Contracts too expensive (can't buy {num_contracts} of {self.future.Symbol})") return 0 return num_contracts def validate(self, data): if (not self.future.Symbol in data.Bars) | (not self.algo.Securities.ContainsKey(self.future.Symbol)): # if self.invested != 0: self.close_position() return False return True class FatOrangePelican(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 11, 28) # Set Start Date self.SetCash(1_000_000) # Set Strategy Cash self.risk_factor = 0.005 self.Resolution = Resolution.Minute self.n_contracts = 40 self.tickers = [ Futures.Indices.SP500EMini, Futures.Indices.NASDAQ100EMini, Futures.Indices.Russell2000EMini, Futures.Indices.Nikkei225Dollar, Futures.Indices.HangSeng, Futures.Indices.FTSEEmergingEmini, \ Futures.Currencies.AUD, Futures.Currencies.GBP, Futures.Currencies.EUR, Futures.Currencies.JPY, Futures.Currencies.NZD, Futures.Currencies.CAD, Futures.Currencies.CHF, \ Futures.Grains.Corn, Futures.Forestry.RandomLengthLumber, Futures.Meats.LiveCattle, Futures.Meats.LeanHogs, Futures.Grains.Oats, Futures.Grains.Soybeans, Futures.Softs.Sugar11CME, Futures.Grains.SRWWheat, \ Futures.Energies.CrudeOilWTI, Futures.Energies.HeatingOil, Futures.Energies.NaturalGas, Futures.Energies.Gasoline, \ Futures.Metals.Gold, Futures.Metals.Palladium, Futures.Metals.Platinum, Futures.Metals.Silver, \ Futures.Financials.Y30TreasuryBond, Futures.Financials.Y10TreasuryNote, Futures.Financials.Y5TreasuryNote, Futures.Financials.Y2TreasuryNote, Futures.Financials.EuroDollar] self.futures = { x.future.Symbol:x for x in [FutureObject(self, y) for y in self.tickers] } def OnDataConsolidated(self, sender, bar: TradeBar): symbol = bar.Symbol future = self.futures[symbol] for indicator in future.indicators: if indicator.Name == 'ATR': indicator.Update(bar) else: indicator.Update(bar.Time, bar.Close) future.closes.Add(bar.Close) future.volumes.Add(bar.Volume * future.multiplier * bar.Close) def OnData(self, data: Slice): if len([x.is_ready() for x in self.futures.values()]) == 0: return # universe = self.get_universe(data) # self.Debug(f"Validating...") for f in self.futures.values(): if not f.validate(data): continue # self.Debug(f"Successfully validated {f.future.Symbol}") close = data.Bars[f.future.Symbol].Close f.trade(close) # self.Debug(str([x.Value for x in self.Portfolio.Keys])) def get_universe(self, data): min_volume = sorted([future.volume for future in self.futures.values() if future.validate(data)], reverse=True) if len(min_volume) == 0: min_volume = 0 else: min_volume = min_volume[min(len(min_volume)-1, self.n_contracts)] universe = [future for future in self.futures.values() if (future.volume >= min_volume) and (future.validate(data))] return universe