Overall Statistics
Total Orders
5462
Average Win
0.39%
Average Loss
-0.23%
Compounding Annual Return
9.271%
Drawdown
13.900%
Expectancy
0.045
Start Equity
100000
End Equity
155806.31
Net Profit
55.806%
Sharpe Ratio
0.31
Sortino Ratio
0.383
Probabilistic Sharpe Ratio
18.597%
Loss Rate
61%
Win Rate
39%
Profit-Loss Ratio
1.70
Alpha
0.028
Beta
0.042
Annual Standard Deviation
0.098
Annual Variance
0.01
Information Ratio
-0.226
Tracking Error
0.167
Treynor Ratio
0.734
Total Fees
$11785.04
Estimated Strategy Capacity
$120000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
458.52%
Drawdown Recovery
444
# region imports
from AlgorithmImports import *
# endregion


class SPY_SMA(QCAlgorithm):

    def initialize(self):
        self.set_start_date(self.end_date - timedelta(5*365))
        self.set_cash(100_000)
        self._can_trade = True
        # Add SPY to trade.
        self._spy = self.add_equity("SPY")
        # Consolidate SPY data into 5-minute bars.
        consolidator = self.consolidate(self._spy, timedelta(minutes=5), self._consolidation_handler)
        # Create some indicators to detect trading opportunities.
        self._sma_fast = SimpleMovingAverage(5)
        self._sma_slow = SimpleMovingAverage(30)
        # Hook up the indicators to be updated with the 5-min bars.
        for indicator in [self._sma_slow, self._sma_fast]:
            self.register_indicator(self._spy.symbol, indicator, consolidator)
        # Add a warm-up period to warm up the indicators.
        self.set_warm_up(timedelta(7)) 
        # Add a Scheduled Event to liquidate positions before the market closes.
        self.schedule.on(
            self.date_rules.every_day(self._spy), 
            self.time_rules.before_market_close(self._spy, 1), 
            self.liquidate
        )

    def on_end_of_day(self, symbol):
        self._yesterday_aum = self.portfolio.total_portfolio_value
        self._can_trade = True

    def _consolidation_handler(self, bar):
        if (self.is_warming_up or 
            not self._can_trade or 
            not self._sma_slow.is_ready or
            not self._spy.exchange.hours.is_open(self.time, False)):
            return
        # If the portfolio value has dropped 5% or more today,
        # stop trading for the rest of the day.
        if self.portfolio.total_portfolio_value / self._yesterday_aum - 1 <= -0.05:
            self.liquidate()
            self._can_trade = False
            return
        # Scan for long trades.
        sma_fast = self._sma_fast.current.value
        sma_slow = self._sma_slow.current.value
        if not self._spy.holdings.is_long and bar.close > sma_fast > sma_slow:
            self.set_holdings(self._spy, 1)
        # Scan for short trades.
        elif not self._spy.holdings.is_short and bar.close < sma_fast < sma_slow:
            self.set_holdings(self._spy, -1)