Overall Statistics
Total Orders
2689
Average Win
0.48%
Average Loss
-0.29%
Compounding Annual Return
19.631%
Drawdown
17.600%
Expectancy
0.265
Start Equity
100000
End Equity
236479.8
Net Profit
136.480%
Sharpe Ratio
0.743
Sortino Ratio
1.359
Probabilistic Sharpe Ratio
29.870%
Loss Rate
52%
Win Rate
48%
Profit-Loss Ratio
1.66
Alpha
0.132
Beta
-0.128
Annual Standard Deviation
0.162
Annual Variance
0.026
Information Ratio
0.107
Tracking Error
0.256
Treynor Ratio
-0.938
Total Fees
$6295.20
Estimated Strategy Capacity
$420000000.00
Lowest Capacity Asset
ES YLZ9Z50BJE2P
Portfolio Turnover
169.84%
from AlgorithmImports import *

class DailyESFutures(QCAlgorithm):
    
    def Initialize(self):
        # Set the start and end dates for the backtest
        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2024, 10, 20)
        
        # Set the initial cash balance for the algorithm
        self.SetCash(100000)

        # Add the S&P 500 E-mini futures contract to trade
        futureES = self.AddFuture(Futures.Indices.SP500EMini, Resolution.Minute)

        # Filter to select the nearest expiring contract, up to 3 months out
        futureES.SetFilter(timedelta(0), timedelta(90))

        # Initialize the contract symbol to None (will be updated later)
        self.contractSymbol = None

        # Set the parameters for the SMA periods
        self.sma_5min_period = 9  # 5-minute SMA period
        self.sma_30min_period = 27  # 30-minute SMA period

        # Define the indicators (will be set up later)
        self.sma_5min = None
        self.sma_30min = None

        # Schedule the daily buy/sell event
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(15, 54), Action(self.TradeES))
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(15, 59), Action(self.SellES))

    def OnData(self, slice):
        # Iterate through future contracts in the slice (market data for the current time step)
        for chain in slice.FutureChains:
            contracts = list(chain.Value)
            if len(contracts) > 0:
                # Sort the contracts by expiration date and select the nearest contract
                nearest_contract = sorted(contracts, key=lambda x: x.Expiry)[0]
                
                # If we don't already have this contract symbol, update it and set up indicators
                if self.contractSymbol != nearest_contract.Symbol:
                    self.contractSymbol = nearest_contract.Symbol
                    self.SetupIndicators(self.contractSymbol)

    def SetupIndicators(self, symbol):
        # Set up the 5-minute and 30-minute SMA indicators for the given contract symbol
        self.sma_5min = self.SMA(symbol, self.sma_5min_period, Resolution.Minute)
        self.sma_30min = self.SMA(symbol, self.sma_30min_period, Resolution.Minute)

    def TradeES(self):
        # Only trade if we have a contract symbol and we are not already invested
        if self.contractSymbol and not self.Portfolio.Invested:
            # Make sure both SMAs are ready (i.e., enough data points are available)
            if self.sma_5min.IsReady and self.sma_30min.IsReady:
                # Buy if 5-minute SMA is above the 30-minute SMA (bullish signal)
                if self.sma_5min.Current.Value > self.sma_30min.Current.Value:
                    self.MarketOrder(self.contractSymbol, 1)  # Buy 1 contract
                    self.Debug(f"Bought 1 contract at {self.Time}, 5-min SMA: {self.sma_5min.Current.Value}, 30-min SMA: {self.sma_30min.Current.Value}")
                else:
                    # Short if 5-minute SMA is below the 30-minute SMA (bearish signal)
                    self.MarketOrder(self.contractSymbol, -1)  # Short 1 contract
                    self.Debug(f"Shorted 1 contract at {self.Time}, 5-min SMA: {self.sma_5min.Current.Value}, 30-min SMA: {self.sma_30min.Current.Value}")
    
    def SellES(self):
        # If invested in the contract, sell everything at the scheduled time
        if self.contractSymbol and self.Portfolio[self.contractSymbol].Invested:
            self.Liquidate(self.contractSymbol)
            self.Debug(f"Liquidated position at {self.Time}")