Created with Highcharts 12.1.2EquityJul 2015Jan 2016Jul 2016Jan 2017Jul 2017Jan 2018Jul 2018Jan 2019Jul 2019Jan 2020Jul 2020Jan 20210250k500k750k1,000k0255075100012
Overall Statistics
Total Trades
198
Average Win
4.69%
Average Loss
-1.66%
Compounding Annual Return
50.362%
Drawdown
14.900%
Expectancy
1.442
Net Profit
843.029%
Sharpe Ratio
2.053
Probabilistic Sharpe Ratio
97.495%
Loss Rate
36%
Win Rate
64%
Profit-Loss Ratio
2.82
Alpha
0.439
Beta
-0.08
Annual Standard Deviation
0.209
Annual Variance
0.044
Information Ratio
1.094
Tracking Error
0.278
Treynor Ratio
-5.339
Total Fees
$2451.08
from QuantConnect.Data.UniverseSelection import *
import math
import numpy as np
import pandas as pd
import scipy as sp
import statistics
class MomentumEffectAlgorithm(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2015, 7, 1)  # Set Start Date
        self.SetEndDate(2020, 12, 28)    # Set Start Date       
        self.SetCash(100000)           # Set Strategy Cash

        self.UniverseSettings.Resolution = Resolution.Daily

        self.mom = {}           # Dict of Momentum indicator keyed by Symbol
        self.lookback = 252     # Momentum indicator lookback period
        self.num_coarse = 100   # Number of symbols selected at Coarse Selection
        self.num_fine = 50      # Number of symbols selected at Fine Selection
        self.num_long = 5       # Number of symbols with open positions

        self.month = -1
        self.rebalance = False
        self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(30)))

        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)


    def CoarseSelectionFunction(self, coarse):
        '''Drop securities which have no fundamental data or have too low prices.
        Select those with highest by dollar volume'''

        if self.month == self.Time.month:
            return Universe.Unchanged

        self.rebalance = True
        self.month = self.Time.month

        selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 5],
            key=lambda x: x.DollarVolume, reverse=True)

        return [x.Symbol for x in selected[:self.num_coarse]]


    def FineSelectionFunction(self, fine):
        filtered_fine = [x for x in fine if x.OperationRatios.OperationMargin.Value
                                        and x.ValuationRatios.PriceChange1M 
                                        and x.ValuationRatios.BookValuePerShare]
                                        
                                        
        
        
        # rank stocks by three factor.
        sortedByfactor1 = sorted(filtered_fine, key=lambda x: x.OperationRatios.OperationMargin.Value, reverse=True)
        sortedByfactor2 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PriceChange1M, reverse=True)
        sortedByfactor3 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.BookValuePerShare, reverse=True)
        
        stock_dict = {}
        
        # assign a score to each stock, you can also change the rule of scoring here.
        for i,ele in enumerate(sortedByfactor1):
            rank1 = i
            rank2 = sortedByfactor2.index(ele)
            rank3 = sortedByfactor3.index(ele)
            score = sum([rank1*0.1,rank2*0.8,rank3*0.1])
            stock_dict[ele] = score
        
        # sort the stocks by their scores
        self.sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1],reverse=True)
        sorted_symbol = [x[0] for x in self.sorted_stock][:20]        
        
        '''Select security with highest market cap'''

        fine = [f for f in fine if f.ValuationRatios.PERatio > 0
                               and f.EarningReports.BasicEPS.TwelveMonths > 0
                               and f.EarningReports.BasicAverageShares.ThreeMonths > 0]

        lowest_market_cap= sorted(fine,
            key=lambda f: f.ValuationRatios.PERatio *
                          f.EarningReports.BasicEPS.TwelveMonths *
                          f.EarningReports.BasicAverageShares.ThreeMonths,
            reverse=True)
        turnoverss=[]
        norma=[]
        for i in lowest_market_cap[:]:
            hist = self.History([i.Symbol], timedelta(days=10))
            if not hist.empty:
                
            
                norma.append(i.FinancialStatements.IncomeStatement.NetIncome.Value)
                
        norma = [float(j)/sum(norma) for j in norma] 
        j=0

           
        
        
        
        
        
        for i in lowest_market_cap[:]:
            hist = self.History([i.Symbol], timedelta(days=10))
            if not hist.empty:
                i.inc=norma[j]
                j=j+1
                i.Turnover=(hist["close"].iloc[0])
               
                i.compare= ((statistics.mean(hist["close"]))-(statistics.mean(hist["open"])))/(statistics.stdev(hist["close"]-(statistics.mean(hist["open"]))))
                
                turnoverss.append(i.compare)
            else:
                lowest_market_cap.remove(i)

        lowest_market_cappp=sorted(lowest_market_cap,key=lambda f:f.compare,reverse=False)
        lowest_market_capp=lowest_market_cappp[:5]
        turnovers=turnoverss[:3]
        som=sum(turnovers)
        self.long = [x.Symbol for x in set(lowest_market_capp).intersection(sorted_symbol)]
        self.weights = {}
        
        for i in lowest_market_capp:
            
                
                
            self.weights[str(i.Symbol)] = i.compare+i.inc*i.inc*i.inc*i.inc+i.inc
                
                  
                
        
            
        return self.long


 


    def OnData(self, data):

        if not self.rebalance: return 
        if self.long:
            stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
            # liquidate stocks not in the trading list 
            for i in stocks_invested:
                if i not in  self.long:
                    
                    
                    
                    self.Liquidate(i)   
            # goes long on stocks with the lowest turnover    
            for i in self.long:
                self.SetHoldings(i,-self.weights[str(i)])   
            # short on stocks with the highest turnover        
            

        self.rebalance = False