Overall Statistics
Total Trades
2840
Average Win
0.50%
Average Loss
-0.49%
Compounding Annual Return
5.073%
Drawdown
18.700%
Expectancy
0.046
Net Profit
32.316%
Sharpe Ratio
0.488
Probabilistic Sharpe Ratio
10.517%
Loss Rate
48%
Win Rate
52%
Profit-Loss Ratio
1.02
Alpha
0.069
Beta
-0.076
Annual Standard Deviation
0.119
Annual Variance
0.014
Information Ratio
-0.346
Tracking Error
0.232
Treynor Ratio
-0.77
Total Fees
$73567.16
from sklearn.linear_model import LinearRegression
import numpy as np
import pandas as pd

class QuantumOptimizedContainmentField(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015, 1, 1)
        self.SetCash(1000000)
        
        self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
        
        lookback = 10*5+1 # 10 weeks of training data
        self.history = self.History(self.symbol, lookback, Resolution.Daily)
        
        # Rollback history timestamp by 1 day to match consolidation timestamps
        if self.history.shape[0] > 0:
            self.history = self.history.unstack(level=0)
            self.history = self.history.set_index(self.history.index.map(lambda x: x - timedelta(days=1))).stack().swaplevel()
        
        self.history = self.history.loc[self.symbol]
        
        self.history['gap'] = (self.history['open'] - self.history['close'].shift(1)) / self.history['close'].shift(1)
        self.history['intraday_return'] = (self.history['close'] - self.history['open']) / self.history['close']
        self.history = self.history[['intraday_return', 'gap', 'close']].iloc[1:]
        self.history['weekday'] = self.history.index.map(datetime.weekday)
        
        self.consolidator = TradeBarConsolidator(timedelta(days=1))
        self.consolidator.DataConsolidated += self.CustomHandler
        self.SubscriptionManager.AddConsolidator(self.symbol, self.consolidator)
        
        self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol, 1), self.Open)
        self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.BeforeMarketClose(self.symbol, 1), self.Close)
        
        
    def CustomHandler(self, sender, consolidated):
        intraday_return = (consolidated.Close - consolidated.Open) / consolidated.Open
        gap = (consolidated.Open - self.history.iloc[-1]['close']) / self.history.iloc[-1]['close']
        row = pd.DataFrame({'intraday_return': intraday_return,
                            'gap': gap,
                            'close' : consolidated.Close,
                            'weekday' : consolidated.Time.weekday()},
                            index=[consolidated.Time])
        self.history = self.history.append(row).iloc[1:]
        

    def Open(self):
        weekday = self.Time.weekday()
        
        historical_performance = self.history[self.history.weekday == weekday]
        lm = LinearRegression()
        model = lm.fit(historical_performance[['intraday_return']], historical_performance.gap)
        alpha_direction = np.sign(model.coef_)
        
        gap_direction = np.sign(self.Securities[self.symbol].Open - self.history.iloc[-1].close)
        trade_direction = alpha_direction * gap_direction
        self.SetHoldings(self.symbol, -trade_direction)
        
    def Close(self):
        self.Liquidate()