Overall Statistics
Total Orders
45
Average Win
8.29%
Average Loss
-4.16%
Compounding Annual Return
34.619%
Drawdown
34.000%
Expectancy
1.244
Start Equity
100000
End Equity
441627.62
Net Profit
341.628%
Sharpe Ratio
0.931
Sortino Ratio
1.029
Probabilistic Sharpe Ratio
48.354%
Loss Rate
25%
Win Rate
75%
Profit-Loss Ratio
1.99
Alpha
0.171
Beta
0.867
Annual Standard Deviation
0.236
Annual Variance
0.056
Information Ratio
0.81
Tracking Error
0.202
Treynor Ratio
0.253
Total Fees
$196.13
Estimated Strategy Capacity
$240000000.00
Lowest Capacity Asset
SMH V2LT3QH97TYD
Portfolio Turnover
1.44%
Drawdown Recovery
714
# 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.month_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)