Overall Statistics
Total Orders
65
Average Win
0.49%
Average Loss
-0.69%
Compounding Annual Return
-0.254%
Drawdown
6.400%
Expectancy
-0.073
Start Equity
100000
End Equity
98734.10
Net Profit
-1.266%
Sharpe Ratio
-1.434
Sortino Ratio
-0.544
Probabilistic Sharpe Ratio
0.284%
Loss Rate
46%
Win Rate
54%
Profit-Loss Ratio
0.71
Alpha
-0.044
Beta
0.07
Annual Standard Deviation
0.027
Annual Variance
0.001
Information Ratio
-0.802
Tracking Error
0.134
Treynor Ratio
-0.559
Total Fees
$99.69
Estimated Strategy Capacity
$150000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
1.31%
Drawdown Recovery
9
# region imports
from AlgorithmImports import *
# endregion


class RSI_Strategy(QCAlgorithm):

    def initialize(self):
        self.set_start_date(self.end_date - timedelta(5*365))
        self.set_cash(100_000)
        # Add the assets and their indicators.
        for ticker in ['SPY', 'IEF']:
            equity = self.add_equity(ticker)
            equity.atr = self.atr(equity, 1, MovingAverageType.SIMPLE, Resolution.DAILY)
            equity.rsi = self.rsi(equity, 2, MovingAverageType.WILDERS, Resolution.DAILY)
            equity.rsi.window[2]  # Store 2 historical RSI values.
        # Warm up the indicators and the RSI history.
        self.set_warmup(timedelta(30))

    def on_data(self, data):
        # Only trade when the slice has assets price data (not corporate actions).
        if self.is_warming_up or not data.bars:
            return
        for security in self.securities.values():
            # Ensure the indicators are ready.
            if not (security.rsi.is_ready and security.atr.is_ready):
                continue
            # Scan for entries.
            if not security.invested and sum([rsi.value for rsi in security.rsi.window]) < 15:
                self.set_holdings(security, 1/len(self.securities))
            # Scan for exits.
            if security.invested and security.rsi.current.value > 70:
                self.liquidate(security)
        
    # When the entry order fills and we know the fill price, add a stop loss.
    def on_order_event(self, order_event):
        if not (order_event.Status == OrderStatus.FILLED and order_event.fill_quantity > 0): 
            return
        symbol = order_event.symbol
        stop_price = order_event.fill_price - 2 * self.securities[symbol].atr.current.value
        self.stop_market_order(symbol, -order_event.fill_quantity, stop_price)