Overall Statistics |
Total Trades 2289 Average Win 0.30% Average Loss -0.03% Compounding Annual Return 0.115% Drawdown 4.700% Expectancy 0.036 Net Profit 1.285% Sharpe Ratio -0.856 Sortino Ratio -0.952 Probabilistic Sharpe Ratio 0.007% Loss Rate 90% Win Rate 10% Profit-Loss Ratio 8.87 Alpha -0.015 Beta -0.011 Annual Standard Deviation 0.019 Annual Variance 0 Information Ratio -0.733 Tracking Error 0.144 Treynor Ratio 1.414 Total Fees $5653.83 Estimated Strategy Capacity $470000000.00 Lowest Capacity Asset GC YGCFVVNJRYXP Portfolio Turnover 8.19% |
from AlgorithmImports import * class ESFuturesTrendFollowingAlgorithm(QCAlgorithm): threshold = 0.01 # 1% def Initialize(self) -> None: self.SetCash(1000000) self.SetStartDate(2015, 1, 1) # Start date # Define the futures contract for ES self.es_continuous_contract = self.AddFuture(Futures.Metals.Gold, dataNormalizationMode=DataNormalizationMode.BackwardsRatio, dataMappingMode=DataMappingMode.OpenInterest, contractDepthOffset=0) self.symbol = self.es_continuous_contract.Symbol # Historical data history = self.History(self.symbol, 100, Resolution.Daily) self.Debug(f"We got {len(history)} items from our history request") self.ema = self.EMA(self.symbol, 100, Resolution.Daily) if not history.empty: for time, row in history.droplevel(0).loc[self.symbol].iterrows(): self.ema.Update(IndicatorDataPoint(time, row.close)) self.Debug("Initialization complete. EMA100 is set up.") def OnData(self, slice: Slice) -> None: # Accessing data and handling roll overs for symbol, changed_event in slice.SymbolChangedEvents.items(): self.HandleRollover(changed_event) mapped_symbol = self.es_continuous_contract.Mapped if not (slice.Bars.ContainsKey(self.symbol) and self.ema.IsReady and mapped_symbol): return # If you have subscribed to a single futures contract: if self.symbol in slice.Bars: bar = slice.Bars[self.symbol] # Now you can access open, high, low, close, and volume of the bar open_price = bar.Open high_price = bar.High low_price = bar.Low close_price = bar.Close price = bar.Price volume = bar.Volume # Trend-following logic based on 100 EMA if price > self.ema.Current.Value * (1+self.threshold) and not self.Portfolio[mapped_symbol].IsLong: self.MarketOrder(mapped_symbol, 1) # Adjust position size as needed self.Log(f"Going Long on {mapped_symbol}. Price: {price}, EMA100: {self.ema.Current.Value}, at Time: {self.Time}.") elif price < self.ema.Current.Value * (1+self.threshold) and not self.Portfolio[mapped_symbol].IsShort: self.MarketOrder(mapped_symbol, -1) # Adjust position size as needed self.Log(f"Going Short on {mapped_symbol}. Price: {price}, EMA100: {self.ema.Current.Value}, at Time: {self.Time}.") def HandleRollover(self, changed_event): old_symbol = changed_event.OldSymbol new_symbol = changed_event.NewSymbol tag = f"Rollover at {self.Time}: {old_symbol} -> {new_symbol}" quantity = self.Portfolio[old_symbol].Quantity # Rolling over: to liquidate any position of the old mapped contract and switch to the newly mapped contract self.Liquidate(old_symbol, tag=tag) if quantity != 0: self.MarketOrder(new_symbol, quantity, tag = tag) self.Log(tag)