| Overall Statistics |
|
Total Orders 16 Average Win 8.47% Average Loss -3.03% Compounding Annual Return -15.415% Drawdown 16.100% Expectancy -0.052 Start Equity 100000 End Equity 97285.6 Net Profit -2.714% Sharpe Ratio -0.071 Sortino Ratio -0.073 Probabilistic Sharpe Ratio 30.474% Loss Rate 75% Win Rate 25% Profit-Loss Ratio 2.79 Alpha 0.459 Beta 1.44 Annual Standard Deviation 0.428 Annual Variance 0.183 Information Ratio 0.858 Tracking Error 0.36 Treynor Ratio -0.021 Total Fees $34.40 Estimated Strategy Capacity $580000000.00 Lowest Capacity Asset NQ XWWD1EKJDJWH Portfolio Turnover 81.56% Drawdown Recovery 20 |
from AlgorithmImports import *
class NqHourlySanityCheck(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 1, 1)
self.SetEndDate(2022, 3, 1)
self.SetCash(100000)
# Add the canonical/continuous future (chain)
future = self.AddFuture(
Futures.Indices.NASDAQ_100_E_MINI,
Resolution.Hour,
extendedMarketHours=True
)
# Filter to a small set of near-dated contracts
future.SetFilter(0, 90)
self.canonical = future.Symbol
self.contract = None
self.ema_fast = None
self.ema_slow = None
def OnData(self, slice: Slice):
# Get the chain for the canonical symbol
chain = slice.FutureChains.get(self.canonical)
if chain is None:
return
# Choose the nearest expiry contract (front month)
contracts = sorted(chain, key=lambda x: x.Expiry)
if len(contracts) == 0:
return
front = contracts[0].Symbol
# If contract changed (roll), update indicators
if self.contract != front:
self.contract = front
self.Log(f"Front contract: {self.contract}")
self.ema_fast = self.EMA(self.contract, 12, Resolution.Hour)
self.ema_slow = self.EMA(self.contract, 48, Resolution.Hour)
if self.ema_fast is None or self.ema_slow is None:
return
if not (self.ema_fast.IsReady and self.ema_slow.IsReady):
return
# Simple crossover just to validate trading
invested = self.Portfolio.Invested
if self.ema_fast.Current.Value > self.ema_slow.Current.Value:
if not invested:
self.MarketOrder(self.contract, 1) # long 1 contract
else:
if invested:
self.Liquidate()