Overall Statistics
Total Trades
852
Average Win
0.10%
Average Loss
-0.28%
Compounding Annual Return
2.919%
Drawdown
26.600%
Expectancy
-0.339
Net Profit
9.171%
Sharpe Ratio
0.226
Loss Rate
52%
Win Rate
48%
Profit-Loss Ratio
0.38
Alpha
0.157
Beta
-7.02
Annual Standard Deviation
0.174
Annual Variance
0.03
Information Ratio
0.13
Tracking Error
0.174
Treynor Ratio
-0.006
Total Fees
$864.43
from QuantConnect.Data.UniverseSelection import *
import numpy as np
import pandas as pd

### <summary>

### </summary>

class FiftyTwoWeeksHighEffectInStocks(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015,10,15)  #Set Start Date
        self.SetEndDate(2018,10,31)
        self.SetCash(100000)            #Set Strategy Cash
    
        self.symbols = None
        self.rebalance = 1
        self.windows = {}
        self.ratios = {}
        self.mktCap = {}
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
    
        self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol 
        self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.At(9,31), self.month_rebalance)
        
        
        #We define self.symbols in FineSelectionFunction, if we use warmup then Ondata and OnSecuritiesChanged will have no idea what self.symbols is
        # self.SetWarmup(252)  


        
    def CoarseSelectionFunction(self, coarse):
        if self.rebalance or self.symbols is None:
            selected = [x for x in coarse if (x.HasFundamentalData) and (float(x.Price) > 3)]
            filtered = sorted(selected, key=lambda x: x.DollarVolume, reverse=True) 
            return [x.Symbol for x in filtered[:500]]    #Pick 1000 most liquid stocks
        else:
            return self.symbols
    
    def FineSelectionFunction(self, fine):
        if self.rebalance or self.symbols is None:
            #Group the stocks by industry sector
            self.BasicMaterialsIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.BasicMaterials]
            self.ConsumerCyclicalIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.ConsumerCyclical]
            self.FinancialServicesIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.FinancialServices]
            self.RealEstateIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.RealEstate]
            self.ConsumerDefensiveIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.ConsumerDefensive]
            self.HealthcareIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Healthcare]
            self.UtilitiesIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Utilities]
            self.CommunicationServicesIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.CommunicationServices]
            self.EnergyIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Energy]
            self.IndustrialsIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Industrials]
            self.TechnologyIndustry = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology]
     
            self.pools = self.BasicMaterialsIndustry + self.ConsumerCyclicalIndustry + self.FinancialServicesIndustry + self.RealEstateIndustry + self.ConsumerDefensiveIndustry + self.HealthcareIndustry + self.UtilitiesIndustry + self.CommunicationServicesIndustry + self.EnergyIndustry + self.IndustrialsIndustry + self.TechnologyIndustry
            
            hist = self.History([i.Symbol for i in self.pools], 252, Resolution.Daily)   #The hist.index is in this format: "X R735QTJ8XC9
            for x in self.pools:
                self.mktCap[x.Symbol] = float(x.EarningReports.BasicAverageShares.ThreeMonths) * hist.loc[str(x.Symbol)]['close'][-1]  #str(x.Symbol) is "X R735QTJ8XC9X" ; #x.Symbol.Value is "X" so we should use str(x.Symbol) here

            
            self.symbols = [x.Symbol for x in self.pools]
            for symbol in self.symbols:
                self.windows[symbol] = RollingWindow[Decimal](252)
                for historical_close in hist.loc[str(symbol)]['close']:
                    self.windows[symbol].Add(historical_close)
                    
            self.rebalance = 0
            self.Log(f'{self.Time}:FineSelection is running! The size of self.symbols is {len(self.symbols)}')
            return self.symbols
        else:
            return self.symbols
            
    def OnData(self, data):  #Update the rolling windows
        if self.symbols is not None:
            for symbol in self.symbols:
                self.Log(symbol)

                if data.ContainsKey(symbol) and data[symbol] is not None :
                    self.Log(data[symbol].Close)
                    self.windows[symbol].Add(data[symbol].Close)
                    
                    self.Log("02")
                else:
                    self.windows[symbol].Add(0)
                    self.Log("03")

      

    def month_rebalance(self):
        
        self.Log(f'{self.Time} month_rebalance is running')
        self.rebalance = 1
        
        #Calculate the weighted close/52-week-high ratios for each sector
        
        industry_list = [self.BasicMaterialsIndustry,
                        self.ConsumerCyclicalIndustry, 
                        self.FinancialServicesIndustry,
                        self.RealEstateIndustry,
                        self.ConsumerDefensiveIndustry,
                        self.HealthcareIndustry,
                        self.UtilitiesIndustry,
                        self.CommunicationServicesIndustry,
                        self.EnergyIndustry,
                        self.IndustrialsIndustry,
                        self.TechnologyIndustry]

        weighted_scores = []
        for i in range(0,len(industry_list)):
            mktCap_sum = sum([self.mktCap[x.Symbol] for x in industry_list[i]])     #The sum of mkt capitalization of i-th sector
            self.Log(f"{self.Time} {i}-th maktCap is good")
            
            curPrice = np.array([self.windows[x.Symbol][0] for x in (industry_list[i])])   #The current prices of each stock in i-th sector
            
            # self.Log(curPrice)
            # self.Log(f'curPrice of {i}-th industry:{curPrice}')

            self.Log(f"{self.Time} {i}-th curPrice is good")
            
            
            fiftyTwoHigh = np.array( [ max(self.windows[x.Symbol]) for x in industry_list[i] ] ) #The 52-week high of each stock in i-th sector
            x = industry_list[i][0]


            # self.Log(f'fiftyTwoHigh of {i}-th industry:{fiftyTwoHigh}')
            self.Log(f'{self.Time} {i}-th fiftyTwoHigh is good')
            
           
            
            ratios = curPrice/fiftyTwoHigh                                       # Ratio (current prices/52-week high) of each stock in i-th sector
            # self.Log(f'ratios of {i}-th industry:{ratios}}')
            self.Log(f'{self.Time} {i}-th ratios is good')
            
            weights = np.array([self.mktCap[x.Symbol]/mktCap_sum for x in industry_list[i]]) #Weighted ratio for i-th sector
            self.Log(f'{self.Time} {i}-th weights is good')
            
            weighted_scores.append(sum(ratios*weights))   #Add weighted ratio to weighted_scores -> list
        
        self.Log("OK1")
        # self.Log(f'weighted_scores: {weighted_scores}')
      
        
        

        long_industry = industry_list[np.argmax(weighted_scores)]
        short_industry = industry_list[np.argmin(weighted_scores)]

        self.Log('long_industry and short_industry is good')
        for x in long_industry:
            self.SetHoldings(x.Symbol, 0.5/len(long_industry))
        for x in short_industry:
            self.SetHoldings(x.Symbol, -0.5/len(short_industry))