Overall Statistics
Total Orders
526
Average Win
1.65%
Average Loss
-1.32%
Compounding Annual Return
-0.221%
Drawdown
26.500%
Expectancy
0.025
Start Equity
100000
End Equity
96177.60
Net Profit
-3.822%
Sharpe Ratio
-0.518
Sortino Ratio
-0.686
Probabilistic Sharpe Ratio
0.000%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
1.25
Alpha
-0.022
Beta
0.026
Annual Standard Deviation
0.041
Annual Variance
0.002
Information Ratio
-0.364
Tracking Error
0.156
Treynor Ratio
-0.815
Total Fees
$2372.88
Estimated Strategy Capacity
$3400000.00
Lowest Capacity Asset
IJT RWQR2INKP0TH
Portfolio Turnover
2.02%
#region imports
from AlgorithmImports import *
#endregion
# https://www.quantconnect.com/tutorials/strategy-library/momentum-and-style-rotation-effect
# https://quantpedia.com/Screener/Details/91


class MomentumAndStyleRotationAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2001, 1, 1)
        self.set_end_date(2018, 8, 1)
        self.set_cash(100000)

        tickers = ["IJJ",   # iShares S&P Mid-Cap 400 Value Index ETF
                   "IJK",   # iShares S&P Mid-Cap 400 Growth ETF
                   "IJS",   # iShares S&P Small-Cap 600 Value ETF
                   "IJT",   # iShares S&P Small-Cap 600 Growth ETF
                   "IVE",   # iShares S&P 500 Value Index ETF
                   "IVW"]   # iShares S&P 500 Growth ETF

        lookback = 12*20

        # Save all momentum indicator into the dictionary
        self.set_security_initializer(BrokerageModelSecurityInitializer(
            self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)))
        self._momp = dict()
        for ticker in tickers:
            symbol = self.add_equity(ticker, Resolution.DAILY).symbol
            self._momp[symbol] = self.momp(symbol, lookback)

        self.set_warm_up(lookback)

        # Portfolio monthly rebalance
        self.schedule.on(self.date_rules.month_start("IJJ"), self.time_rules.at(0, 0), self._rebalance)


    def _rebalance(self):
        '''Sort securities by momentum.
        Short the one with the lowest momentum.
        Long the one with the highest momentum.
        Liquidate positions of other securities'''
        
        # Order the MOM dictionary by value
        sorted_mom = sorted(self._momp, key=lambda x: self._momp[x].current.value)

        # Liquidate the ETFs that are no longer selected
        for symbol in sorted_mom[1:-1]:
            if self.portfolio[symbol].invested:
                self.liquidate(symbol, 'No longer selected')

        self.set_holdings(sorted_mom[-1], -0.5)   # Short the ETF with lowest MOM
        self.set_holdings(sorted_mom[0], 0.5)     # Long the ETF with highest MOM