Overall Statistics
Total Trades
294
Average Win
0.26%
Average Loss
-0.20%
Compounding Annual Return
-2.089%
Drawdown
6.800%
Expectancy
0.031
Net Profit
-2.428%
Sharpe Ratio
-0.427
Loss Rate
56%
Win Rate
44%
Profit-Loss Ratio
1.34
Alpha
-0.04
Beta
0.986
Annual Standard Deviation
0.047
Annual Variance
0.002
Information Ratio
-0.853
Tracking Error
0.047
Treynor Ratio
-0.02
Total Fees
$0.00
import pandas as pd

class MomentumAndStyleRotationAlgorithm(QCAlgorithmFramework):

    def Initialize(self):

        self.SetStartDate(2018, 1, 1) 
        self.SetEndDate(2019, 3, 1)    
        self.SetCash(100000)             # Set Strategy Cash
        
        self.SetSecurityInitializer(lambda security: security.SetFeeModel(ConstantFeeModel(0)))

        symbols = [Symbol.Create(ticker, SecurityType.Equity, Market.USA) 
            for ticker in [ "IJJ", # iShares S&P MidCap 400 Value Index ETF
                            "IJS", # iShares S&P SmallCap 600 Value ETF 
                            "IVE", # iShares S&P 500 Value Index ETF 
                            "IVW", # iShares S&P 500 Growth ETF   
                            "IJK", # iShares S&P Mid-Cap 400 Growth ETF
                            "IJT", # iShares S&P Small-Cap 600 Growth ETF
                          ]]

        self.UniverseSettings.Resolution = Resolution.Daily
        self.SetUniverseSelection( ManualUniverseSelectionModel(symbols) )

        self.SetAlpha(MomentumAndStyleRotationAlphaModel())

        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) 
        self.SetExecution(ImmediateExecutionModel())
        self.SetRiskManagement(NullRiskManagementModel())
    
class MomentumAndStyleRotationAlphaModel(AlphaModel):
    '''Alpha model that uses the Momentum Indicator to create insights'''

    def __init__(self,
                 period = 12*20,
                 resolution = Resolution.Daily):
        '''
        Initializes a new instance of the MomentumAndStyleRotationAlphaModel class
        Args:
            period: The Momentum lookback period
            resolution: The data resolution
        '''
        self.period = period
        self.resolution = resolution
        self.MomentumBySymbol = dict()

        resolutionString = Extensions.GetEnumString(resolution, Resolution)
        self.Name = f'{self.__class__.__name__}({period},{resolutionString})'
        
        self.lastMonth = -1
        
    def Update(self, algorithm, data):
        '''
        Updates this alpha model with the latest data from the algorithm.
        This is called each time the algorithm receives data for subscribed securities
        Args:
            algorithm: The algorithm instance
            data: The new data available
        Returns:
            The new insights generated
        '''
        month = algorithm.Time.month
        if month == self.lastMonth:
            return []
        self.lastMonth = month

        momentumBySymbol = {symbol: value for symbol, value in self.MomentumBySymbol.items() if value.IsReady}
        sortedMomentum = [x[0] for x in sorted(momentumBySymbol.items(), key = lambda kv: kv[1], reverse=True)]
        
        expiry = algorithm.Time.replace(month = month + 1, day = 1) if month < 12 else \
            algorithm.Time.replace(year = algorithm.Time.year + 1, month = 1, day = 1)
            
        return Insight.Group(
            [
                Insight.Price(sortedMomentum[0], expiry, InsightDirection.Up),
                Insight.Price(sortedMomentum[-1], expiry, InsightDirection.Down)
            ])

    def OnSecuritiesChanged(self, algorithm, changes):
        '''
        Event fired each time the we add securities from the data feed
        
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm
        '''
        addedSymbols = [ x.Symbol for x in changes.AddedSecurities ]
        history = algorithm.History(addedSymbols, self.period, self.resolution)
        history = history.close.unstack(level=0)
        
        for symbol in addedSymbols:
            data = self.MomentumBySymbol.setdefault(symbol, algorithm.MOM(symbol, self.period, self.resolution))
            for time, value in history[str(symbol)].iteritems():
                data.Update(time, value)