| 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}")