Overall Statistics
Total Trades
331
Average Win
0.66%
Average Loss
-0.76%
Compounding Annual Return
-4.186%
Drawdown
20.400%
Expectancy
-0.047
Net Profit
-6.415%
Sharpe Ratio
-0.336
Probabilistic Sharpe Ratio
2.167%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
0.87
Alpha
-0.028
Beta
0.197
Annual Standard Deviation
0.078
Annual Variance
0.006
Information Ratio
-0.211
Tracking Error
0.157
Treynor Ratio
-0.132
Total Fees
$345.09
Estimated Strategy Capacity
$24000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
Portfolio Turnover
58.14%
#region imports
from AlgorithmImports import *
from QuantConnect.Data.UniverseSelection import *
#endregion

class ShortAlgorithm(QCAlgorithm):
    
    def __init__(self):

        self.reb = 1
        self.num_fine = 10
        self.symbols = None

    def Initialize(self):

        self.SetCash(100000)

        self.SetStartDate(2022, 1, 1)

        self.AddIndex("VIX", Resolution.Daily)
        
        self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol

        self.s200 = self.SMA("SPY", 200, Resolution.Daily)

        self.SetBenchmark("SPY")

        self.UniverseSettings.Resolution = Resolution.Daily
        
        self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
        
        self.Schedule.On(self.DateRules.EveryDay(self.spy), 
        self.TimeRules.AfterMarketOpen(self.spy, 0), Action(self.rebalance))

    def OnData(self, data):

        if not data["SPY"]: 
            return
        if not self.s200.IsReady:
            return
   
    def CoarseSelectionFunction(self, coarse):

        if self.reb != 1:
            return self.symbols

        filtered_coarse = [x.Symbol for x in coarse if (x.HasFundamentalData) 
                                                and x.Price > 5
                                                and x.Price < SimpleMovingAverage(200).Current.Value
                                                and x.Volume > 1e5

        ]

        return filtered_coarse

    def FineSelectionFunction(self, fine):

        if self.reb != 1:
            return self.symbols
            
        self.reb = 0
            
        filtered_fine = [x for x in fine if
                                                x.MarketCap > 2e9

        ]

        top = sorted(filtered_fine, key = lambda x: x.MarketCap, reverse=True)[:self.num_fine]

        self.symbols = [x.Symbol for x in top]

        return self.symbols

    def OnData(self, data):
        pass
    
    def rebalance(self):
    # if this month the stock are not going to be long/short, liquidate it.
        long_short_list = self.symbols
        for i in self.Portfolio.Values:
            if (i.Invested) and (i not in long_short_list):
                self.Liquidate(i.Symbol)
                

        if self.Securities["SPY"].Price < self.s200.Current.Value:
            if self.Securities["VIX"].Price > 20:
                for i in self.symbols:
                    self.SetHoldings(i, -1/self.num_fine)
            else:
                self.SetHoldings("SPY", 1)
        else:
            self.SetHoldings("SPY", 1)
        
        self.reb = 1