Overall Statistics
Total Orders
2088
Average Win
1.26%
Average Loss
-0.90%
Compounding Annual Return
-33.988%
Drawdown
45.700%
Expectancy
-0.037
Start Equity
100000
End Equity
61957.2
Net Profit
-38.043%
Sharpe Ratio
-0.653
Sortino Ratio
-0.876
Probabilistic Sharpe Ratio
2.299%
Loss Rate
60%
Win Rate
40%
Profit-Loss Ratio
1.39
Alpha
-0.45
Beta
1.832
Annual Standard Deviation
0.381
Annual Variance
0.145
Information Ratio
-1.053
Tracking Error
0.341
Treynor Ratio
-0.136
Total Fees
$10517.80
Estimated Strategy Capacity
$1700000.00
Lowest Capacity Asset
ES YTG30NVEFCW1
Portfolio Turnover
3763.40%
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.

from AlgorithmImports import *

### Day trading algorithm for E-mini S&P 500 futures using a simple moving average crossover strategy.

class ESFuturesDayTradingAlgorithm(QCAlgorithm):
    def initialize(self):
        self.set_start_date(2024, 1, 1)
        self.set_end_date(2025, 12, 31)
        self.set_cash(100000)
        
        # Sizing
        self.pct_portfolio_long = 0.5
        self.pct_portfolio_short = 0.1

        # Contract symbol we're currently tracking
        self.contract_symbol = None
        
        # Strategy parameters
        self.fast_period = 30
        self.slow_period = 60
        
        # Indicators dictionary
        self.fast_sma = None
        self.slow_sma = None
        
        # Trading flags
        self.ready_to_trade = False
        self.closing_positions = False
        
        # Subscribe to ES futures
        es_futures = self.add_future(Futures.Indices.SP500EMini, Resolution.MINUTE)
        #es_futures.set_filter(timedelta(0), timedelta(30))  # Front month contracts
        es_futures.set_filter(timedelta(0), timedelta(182))  # Look ahead up to 6 months
        
        # Set benchmark
        benchmark = self.add_equity("SPY")
        self.set_benchmark(benchmark.symbol)
        
        # Security seeder for backtesting
        seeder = FuncSecuritySeeder(self.get_last_known_prices)
        self.set_security_initializer(lambda security: seeder.seed_security(security))
        
        # Use time rules that don't depend on market hours
        self.schedule.on(self.date_rules.every_day(), 
                        self.time_rules.at(9, 30), # Fixed time for start of trading (adjust as needed)
                        self.start_trading)
                        
        self.schedule.on(self.date_rules.every_day(), 
                        self.time_rules.at(15, 30), # Fixed time for end of trading (adjust as needed)
                        self.close_positions)
    
    def on_data(self, slice):
        # Skip if we don't have a contract or are not ready to trade
        if self.contract_symbol is None or not self.ready_to_trade:
            return
            
        # If we're in closing mode, don't open new positions
        if self.closing_positions:
            return
            
        # Wait for indicators to be ready
        if not (self.fast_sma.is_ready and self.slow_sma.is_ready):
            return
            
        # Get current position
        position = self.portfolio[self.contract_symbol].quantity
        
        # Trading logic based on SMA crossover
        if self.fast_sma.current.value > self.slow_sma.current.value and position <= 0:
            # Buy signal
            if position < 0:
                self.liquidate(self.contract_symbol)  # Close any short position first
                
            quantity = self.calculate_order_quantity(self.contract_symbol, self.pct_portfolio_long)
            self.market_order(self.contract_symbol, quantity)
            self.log(f"{self.time}: BUY {quantity} contracts of {self.contract_symbol}")
            
        elif self.fast_sma.current.value < self.slow_sma.current.value and position >= 0:
            # Sell signal
            if position > 0:
                self.liquidate(self.contract_symbol)  # Close any long position first
                
            quantity = self.calculate_order_quantity(self.contract_symbol, self.pct_portfolio_short)
            self.market_order(self.contract_symbol, -quantity)
            self.log(f"{self.time}: SELL {quantity} contracts of {self.contract_symbol}")
    
    def on_securities_changed(self, changes):
        # When futures change, update our contract symbol and indicators
        for added in changes.added_securities:
            if added.symbol.security_type == SecurityType.FUTURE and "ES" in added.symbol.value and not added.symbol.is_canonical():
                # Front-month ES contract added
                self.contract_symbol = added.symbol
                
                # Reset indicators for the new contract
                self.fast_sma = self.SMA(self.contract_symbol, self.fast_period, Resolution.MINUTE)
                self.slow_sma = self.SMA(self.contract_symbol, self.slow_period, Resolution.MINUTE)
                
                self.log(f"Selected contract: {self.contract_symbol}")
    
    def start_trading(self):
        self.ready_to_trade = True
        self.closing_positions = False
        self.log("Trading window open - Ready to trade")
    
    def close_positions(self):
        # Set flag to prevent new positions
        self.closing_positions = True
        self.ready_to_trade = False
        
        # Close any open positions
        if self.contract_symbol is not None and self.portfolio[self.contract_symbol].invested:
            self.liquidate(self.contract_symbol)
            self.log(f"Trading window closed - Liquidated position in {self.contract_symbol}")
    
    def on_end_of_algorithm(self):
        if self.contract_symbol is not None:
            # Get the margin requirements
            buying_power_model = self.securities[self.contract_symbol].buying_power_model
            name = type(buying_power_model).__name__
            if name != 'FutureMarginModel':
                raise Exception(f"Invalid buying power model. Found: {name}. Expected: FutureMarginModel")
            
            initial_overnight = buying_power_model.initial_overnight_margin_requirement
            maintenance_overnight = buying_power_model.maintenance_overnight_margin_requirement
            initial_intraday = buying_power_model.initial_intraday_margin_requirement
            maintenance_intraday = buying_power_model.maintenance_intraday_margin_requirement
            
            self.log(f"Margin Requirements for {self.contract_symbol}:")
            self.log(f"Initial Overnight: {initial_overnight}")
            self.log(f"Maintenance Overnight: {maintenance_overnight}")
            self.log(f"Initial Intraday: {initial_intraday}")
            self.log(f"Maintenance Intraday: {maintenance_intraday}")