Overall Statistics
Total Trades
1364
Average Win
30.63%
Average Loss
-0.43%
Compounding Annual Return
-71.921%
Drawdown
88.200%
Expectancy
-0.681
Net Profit
-88.092%
Sharpe Ratio
-0.98
Probabilistic Sharpe Ratio
0.007%
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
71.54
Alpha
-0.636
Beta
0.603
Annual Standard Deviation
0.53
Annual Variance
0.281
Information Ratio
-1.37
Tracking Error
0.52
Treynor Ratio
-0.861
Total Fees
$2523.40
Estimated Strategy Capacity
$83000000.00
Lowest Capacity Asset
ES XMXYBDF3IXHD
from AlgorithmImports import *

class ContinuousFutureRegressionAlgorithm(QCAlgorithm):
    '''Basic template algorithm simply initializes the date range and cash'''

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''

        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2022, 5, 1)

        self._mappings = []
        self._lastDateLog = -1
        self._continuousContract = self.AddFuture(Futures.Indices.SP500EMini,
                                                  Resolution.Minute,
                                                  dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
                                                  dataMappingMode = DataMappingMode.LastTradingDay,  # change to openinterest
                                                  contractDepthOffset= 0)
        self._currentMappedSymbol = self._continuousContract.Symbol

        self.indicators = {
            'sma': self.SMA(self._continuousContract.Symbol, 11, Resolution.Minute),
            'ema': self.EMA(self._continuousContract.Symbol, 60, Resolution.Minute),
            # 'atr': AverageTrueRange(14)
        }
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(13, 0), self.StartOfDay)  # set to 13:00
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(15, 0), self.EndOfDay)

        self.TradingTime = False

    def StartOfDay(self):
        self.TradingTime = True

    def EndOfDay(self):
        self.TradingTime = False
        # if self.Portfolio.Invested:
        #     self.Liquidate(tag='Liquidate all')

    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        if len(data.Keys) != 1:
            raise ValueError(f"We are getting data for more than one symbols! {','.join(data.Keys)}")

        for changedEvent in data.SymbolChangedEvents.Values:
            if changedEvent.Symbol == self._continuousContract.Symbol:
                self._mappings.append(str(changedEvent))
                self.Log(f"SymbolChanged event: {changedEvent}")
        
                if self._currentMappedSymbol == self._continuousContract.Mapped:
                    raise ValueError(f"Continuous contract current symbol did not change! {self._continuousContract.Mapped}")
    
                self.Liquidate(self.Securities[self._currentMappedSymbol].Symbol, tag='Switching Symbol')
                self._currentMappedSymbol = self._continuousContract.Mapped

        contract = self.Securities[self._continuousContract.Mapped]
        if not contract.HasData:
            return

        # bar = data[self._continuousContract.Mapped.Symbol]
        # bar = data[self._continuousContract.Mapped]
        # bar = data[contract]
        # bar = data[contract.Symbol]
        # bar = data.bar[contract.Symbol]
        
        open_orders = self.Transactions.GetOpenOrders(contract.Symbol)

        if self.indicators['sma'].Current.Value > self.indicators['ema'].Current.Value:
            if not self.Portfolio.Invested and len(open_orders) == 0 and self.TradingTime:
                quantity = 1  # make quantity dynamic ?
                self.entryPrice = contract.BidPrice + 1
                self.entryTicket = self.StopMarketOrder(contract.Symbol, quantity, self.entryPrice)

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            return
        
        contract = self.Securities[self._continuousContract.Mapped]

        if self.entryTicket is not None and self.entryTicket.OrderId == orderEvent.OrderId:
            quantity = self.Portfolio[contract.Symbol].Quantity
            # stopPrice = self.entryPrice - 1  # self.entryTicket.AverageFillPrice - 1
            stop_price = self.entryTicket.AverageFillPrice - 2
            self.stopTicket = self.StopMarketOrder(contract.Symbol, -quantity, stop_price, 'Exit by SL')

    def OnSecuritiesChanged(self, changes):
        self.Debug(f"{self.Time}-{changes}")

    def OnEndOfAlgorithm(self):
        self.Debug(f'mappings={self._mappings}')