Overall Statistics
Total Trades
448
Average Win
0.44%
Average Loss
-0.18%
Compounding Annual Return
4.759%
Drawdown
6.100%
Expectancy
0.054
Net Profit
5.410%
Sharpe Ratio
0.622
Probabilistic Sharpe Ratio
34.405%
Loss Rate
69%
Win Rate
31%
Profit-Loss Ratio
2.36
Alpha
0.088
Beta
-0.131
Annual Standard Deviation
0.08
Annual Variance
0.006
Information Ratio
-1.487
Tracking Error
0.16
Treynor Ratio
-0.381
Total Fees
$1113.84
from QuantConnect.Data.Consolidators import CalendarInfo

class UncoupledMultidimensionalAutosequencers(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 1, 1)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        
        tickers = ["SPY", "TLT"]
        
        # Dictionary to hold Symbol Data
        self.symbolData = {}
        
        for ticker in tickers:
            # Add equity data
            symbol = self.AddEquity(ticker, Resolution.Minute).Symbol
            # Create symbol data for respective symbol
            self.symbolData[symbol] = SymbolData(self, symbol)

class SymbolData:
    
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        # Define our consolidator for 30 min bars
        hourlyConsolidator = TradeBarConsolidator(self.Custom)
        hourlyConsolidator.DataConsolidated += self.OnDataConsolidated
        algorithm.SubscriptionManager.AddConsolidator(symbol, hourlyConsolidator)
        
        # Define our indicator
        self.sma = SimpleMovingAverage(14)
        # Register indicator to our consolidator
        algorithm.RegisterIndicator(symbol, self.sma, hourlyConsolidator)
        # Rolling window to hold 30 min bars
        self.barWindow = RollingWindow[TradeBar](2)
    
    # Store every thirty minute bar in rolling window
    def OnDataConsolidated(self, sender, bar):
        self.barWindow.Add(bar)
        
        if self.IsReady:
            lastBar = self.barWindow[1]
            currentBar = self.barWindow[0]
            sma = self.sma.Current.Value
            # Buy if there is a long cross over
            if lastBar.Close < sma and currentBar.Close > sma:
                self.algorithm.SetHoldings(self.symbol, 0.5)
            elif lastBar.Close > sma and currentBar.Close < sma:
                self.algorithm.SetHoldings(self.symbol, -0.5)
                
    @property
    def IsReady(self):
        return self.sma.IsReady and self.barWindow.IsReady
        
    def Custom(self, dt):
        period = timedelta(hours=1)
        start = dt.replace(minute=30)
        if start > dt:
            start -= period
        return CalendarInfo(start, period)