Overall Statistics
Total Orders
1466
Average Win
3.95%
Average Loss
-1.91%
Compounding Annual Return
61.327%
Drawdown
25.400%
Expectancy
0.642
Start Equity
5000
End Equity
4390778.15
Net Profit
87715.563%
Sharpe Ratio
1.779
Sortino Ratio
2.546
Probabilistic Sharpe Ratio
99.835%
Loss Rate
46%
Win Rate
54%
Profit-Loss Ratio
2.07
Alpha
0.322
Beta
0.571
Annual Standard Deviation
0.208
Annual Variance
0.043
Information Ratio
1.418
Tracking Error
0.201
Treynor Ratio
0.649
Total Fees
$51511.38
Estimated Strategy Capacity
$2800000.00
Lowest Capacity Asset
QLD TJNNZWL5I4IT
Portfolio Turnover
23.25%
from AlgorithmImports import *

class RSIRebalanceStrategy(QCAlgorithm):

    def Initialize(self):
        self.set_start_date(2011, 1, 1)
        self.set_cash(5000)
        self.settings.free_portfolio_value_percentage = 0.01
        self.set_warmup(timedelta(days=250))

        self.qqq = self.add_equity("QQQ", Resolution.MINUTE, data_normalization_mode=DataNormalizationMode.RAW).Symbol
        self.qld = self.add_equity("QLD", Resolution.MINUTE, data_normalization_mode=DataNormalizationMode.RAW).Symbol
        self.spy = self.add_equity("SPY", Resolution.MINUTE, data_normalization_mode=DataNormalizationMode.RAW).Symbol
        # self.itot = self.add_equity("VT", Resolution.DAILY, data_normalization_mode=DataNormalizationMode.RAW).Symbol
        # self.xlp = self.add_equity("XLP", Resolution.DAILY).Symbol
        self.xlu = self.add_equity("XLU", Resolution.MINUTE).Symbol
        self.bil = self.add_equity("BIL", Resolution.MINUTE).Symbol
        self.vixy = self.add_equity("UVXY", Resolution.MINUTE).Symbol

        self.qqq_rsi = self.rsi(self.qqq, 10)
        self.spy_sma_200 = self.sma(self.spy, 200)
        self.spy_sma_30 = self.sma(self.spy, 30)

        self.schedule.on(self.date_rules.every_day(), self.time_rules.before_market_close(self.spy, 3), self.Rebalance)
        self.schedule.on(self.date_rules.week_end(), self.time_rules.after_market_close(self.spy, 0), self.add_cash)


    def add_cash(self): 
        self.portfolio.cash_book["USD"].add_amount(80)

    def RSI2(self,equity,period):
        extension = min(period*5,250)
        r_w = RollingWindow[float](extension)
        history = self.history(equity,extension - 1,Resolution.DAILY)
        for historical_bar in history:
            r_w.add(historical_bar.close)
        while r_w.count < extension:
            current_price = self.securities[equity].price
            r_w.add(current_price)
        if r_w.is_ready:
            average_gain = 0
            average_loss = 0
            gain = 0
            loss = 0
            for i in range(extension - 1,extension - period -1,-1):
                gain += max(r_w[i-1] - r_w[i],0)
                loss += abs(min(r_w[i-1] - r_w[i],0))
            average_gain = gain/period
            average_loss = loss/period
            for i in range(extension - period - 1,0,-1):
                average_gain = (average_gain*(period-1) + max(r_w[i-1] - r_w[i],0))/period
                average_loss = (average_loss*(period-1) + abs(min(r_w[i-1] - r_w[i],0)))/period
            if average_loss == 0:
                return 100
            else:
                rsi = 100 - (100/(1 + average_gain / average_loss))
                return rsi
        else:
            return None

    def SMA2(self,equity,period):
        r_w = RollingWindow[float](period)
        history = self.history(equity,period - 1,Resolution.DAILY)
        for historical_bar in history:
            r_w.add(historical_bar.close)
        while r_w.count < period:
            current_price = self.securities[equity].price
            r_w.add(current_price)        
        if r_w.is_ready:
            sma = sum(r_w) / period
            return sma
        else:
            return 0

    def Rebalance(self):
        if not self.qqq_rsi.IsReady or not self.spy_sma_200.IsReady or not self.spy_sma_30.IsReady:
            return

        rsi_value = self.RSI2("QQQ", 10)
        spy_price = self.securities[self.spy].Price
        spy_sma_200 = self.SMA2("SPY", 200)
        spy_sma_30 = self.SMA2("SPY", 30)

        # self.plot("Chart1", "RSI", rsi_value)
        # self.plot("SPY 30 + 200 SMA", spy_sma_30, spy_sma_200)

        if rsi_value > 79:
            liquidate = not self.portfolio[self.vixy].invested
            self.set_holdings(self.vixy, 1, liquidate)
            # self.liquidate()
        elif rsi_value < 31:
            liquidate = not self.portfolio[self.qld].invested
            self.set_holdings(self.qld, 1, liquidate)
        elif spy_price > spy_sma_200:
            if spy_price > spy_sma_30:
                liquidate = not self.portfolio[self.qqq].invested
                self.set_holdings(self.qqq, 1, liquidate)
            else:
                # self.set_holdings([PortfolioTarget(self.xlp, 0.5), PortfolioTarget(self.xlu, 0.5)], True)
                liquidate = not self.portfolio[self.xlu].invested
                self.set_holdings(self.xlu, 1, liquidate)

        else:
            if spy_price > spy_sma_30:
                # self.set_holdings([PortfolioTarget(self.xlp, 0.5), PortfolioTarget(self.xlu, 0.5)], True)
                liquidate = not self.portfolio[self.xlu].invested
                self.set_holdings(self.xlu, 1, liquidate)

            else:
                liquidate = not self.portfolio[self.bil].invested
                self.set_holdings(self.bil, 1, liquidate)
                # self.liquidate()