Overall Statistics
Total Orders
110
Average Win
3.85%
Average Loss
-1.68%
Compounding Annual Return
33.520%
Drawdown
29.600%
Expectancy
1.277
Start Equity
100000
End Equity
423914.45
Net Profit
323.914%
Sharpe Ratio
0.913
Sortino Ratio
1.021
Probabilistic Sharpe Ratio
47.452%
Loss Rate
31%
Win Rate
69%
Profit-Loss Ratio
2.28
Alpha
0.164
Beta
0.84
Annual Standard Deviation
0.231
Annual Variance
0.053
Information Ratio
0.78
Tracking Error
0.199
Treynor Ratio
0.251
Total Fees
$445.68
Estimated Strategy Capacity
$300000000.00
Lowest Capacity Asset
SMH V2LT3QH97TYD
Portfolio Turnover
2.93%
Drawdown Recovery
751
# region imports
from AlgorithmImports import *
# endregion


class FinalProjectMomentumStrategy(QCAlgorithm):

    def initialize(self):
        self.set_cash(100_000)
        self.set_start_date(self.end_date - timedelta(5 * 365))
        self._lookback = 252
        self._securities = []
        for ticker in ["QQQ", "XLK", "SMH", "XLP", "XLU", "GLD", "TLT", "IEF"]:
            self._securities.append(self.add_equity(ticker, Resolution.DAILY))
        self.set_warm_up(self._lookback + 5, Resolution.DAILY)
        self.schedule.on(self.date_rules.week_start("SPY"), self.time_rules.at(8, 0), self._rebalance)

    def on_warmup_finished(self):
        self._rebalance()

    def _rebalance(self):
        if self.is_warming_up:
            return
        momentum_by_security = {}
        for security in self._securities:
            history = self.history(security, self._lookback + 1, Resolution.DAILY)
            if history.empty or len(history) < self._lookback:
                continue
            closes = history["close"]
            momentum_by_security[security] = closes.iloc[-1] / closes.iloc[0] - 1
        # Hold the single strongest name, but only while its momentum is positive.
        selected = [security for security in sorted(momentum_by_security, key=lambda s: momentum_by_security[s])[-1:] if momentum_by_security[security] > 0]
        if not selected:
            selected = [self._securities[0]]
        weight = 0.97 / len(selected)
        targets = [PortfolioTarget(security, weight if security in selected else 0) for security in self._securities]
        self.set_holdings(targets)