Overall Statistics
Total Orders
412
Average Win
1.39%
Average Loss
-1.64%
Compounding Annual Return
21.913%
Drawdown
35.500%
Expectancy
0.257
Start Equity
100000
End Equity
269405.66
Net Profit
169.406%
Sharpe Ratio
0.585
Sortino Ratio
0.694
Probabilistic Sharpe Ratio
19.581%
Loss Rate
32%
Win Rate
68%
Profit-Loss Ratio
0.85
Alpha
0.067
Beta
1.097
Annual Standard Deviation
0.245
Annual Variance
0.06
Information Ratio
0.387
Tracking Error
0.19
Treynor Ratio
0.131
Total Fees
$466.41
Estimated Strategy Capacity
$350000000.00
Lowest Capacity Asset
GE R735QTJ8XC9X
Portfolio Turnover
2.36%
Drawdown Recovery
832
#region imports
from AlgorithmImports import *
#endregion
# https://quantpedia.com/Screener/Details/14


class MomentumEffectAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(self.end_date - timedelta(5*365))
        self.set_cash(100_000)
        self.settings.seed_initial_prices = True
        self.settings.automatic_indicator_warm_up = True
        # Define some parameters.
        self._lookback = 252
        self._liquidity_filter_size = 100
        self._universe_size = 50
        self._portfolio_size = 5
        # Add a universe of US Equities.
        self.universe_settings.resolution = Resolution.DAILY
        self._date_rule = self.date_rules.month_start('SPY')
        self.universe_settings.schedule.on(self._date_rule)
        self._universe = self.add_universe(self._select_assets)
        # Add a warm-up period so the algorithm trades right away
        # instead of waiting for the next month to start.
        self.set_warm_up(timedelta(45))

    def _select_assets(self, fundamentals):
        # Select the most liquid stocks trading above $5/share.
        filtered = [f for f in fundamentals if f.has_fundamental_data and f.price > 5]
        filtered = sorted(filtered, key=lambda f: f.dollar_volume)[-self._liquidity_filter_size:]
        # Select the subset of stocks with highest market caps.
        filtered = sorted(filtered, key=lambda f: f.market_cap, reverse=True)[:self._universe_size]
        return [f.symbol for f in filtered]

    def on_securities_changed(self, changes):
        # As assets enter the universe, add a momentum indicator to each one.
        for security in changes.added_securities:
            security.momentum = self.momp(security, self._lookback)
        # As assets leave the universe, remove their indicator and liquidate it.
        for security in changes.removed_securities:
            self.deregister_indicator(security.momentum)
            self.liquidate(security, 'Removed from universe')

    def on_warmup_finished(self):
        # Add a Scheduled Event to rebalance the portofolio monthly.
        time_rule = self.time_rules.at(8, 0)
        self.schedule.on(self._date_rule, time_rule, self._rebalance)
        # Rebalance today too.
        if self.live_mode:
            self._rebalance()
        else:
            self.schedule.on(self.date_rules.today, time_rule, self._rebalance)

    def _rebalance(self):
        # Get the stocks that have their momentum indicators primed.
        securities = []
        for symbol in self._universe.selected:
            security = self.securities[symbol]
            if security.momentum.is_ready:
                securities.append(security)
        # Select the securities with greatest momentum.
        selected = sorted(securities, key=lambda security: security.momentum)[-self._portfolio_size:]
        # Form an equal-weighted portfolio.
        targets = [PortfolioTarget(security, 1/len(selected)) for security in selected]
        self.set_holdings(targets, True)