Overall Statistics
Total Orders
1882
Average Win
1.00%
Average Loss
-0.65%
Compounding Annual Return
30.297%
Drawdown
47.100%
Expectancy
0.681
Start Equity
100000
End Equity
6280962.05
Net Profit
6180.962%
Sharpe Ratio
0.81
Sortino Ratio
0.919
Probabilistic Sharpe Ratio
8.753%
Loss Rate
34%
Win Rate
66%
Profit-Loss Ratio
1.54
Alpha
0.11
Beta
1.357
Annual Standard Deviation
0.279
Annual Variance
0.078
Information Ratio
0.674
Tracking Error
0.209
Treynor Ratio
0.167
Total Fees
$7701.62
Estimated Strategy Capacity
$37000000.00
Lowest Capacity Asset
TER R735QTJ8XC9X
Portfolio Turnover
2.08%
Drawdown Recovery
573
from AlgorithmImports import *

class TacticalEquityMomentumAlgorithm(QCAlgorithm):

    _ETF_TICKER = "SPY"
    _TRIX_TIME_PERIOD = 90

    def initialize(self):
        self.universe_settings.leverage = 1.0
        self.universe_settings.resolution = Resolution.MINUTE

        self.set_start_date(2011, 1, 1)
        self.set_benchmark(self._ETF_TICKER)
        self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
        self.set_warm_up(self._TRIX_TIME_PERIOD)

        self.add_universe_selection(ETFConstituentsUniverseSelectionModel(self._ETF_TICKER))

        self.schedule.on(
            self.date_rules.month_end(self._ETF_TICKER),
            self.time_rules.before_market_close(self._ETF_TICKER, 30),
            self._rebalance
        )

    def on_warmup_finished(self):
        self._rebalance()

    def on_securities_changed(self, changes):
        for security in changes.added_securities:
            security.indicator = self.trix(security.symbol, self._TRIX_TIME_PERIOD, resolution=Resolution.DAILY)
            self.warm_up_indicator(security.symbol, security.indicator)

        for security in changes.removed_securities:
            self.deregister_indicator(security.indicator)

    def _rebalance(self):
        available_securities = [
            s for s in self.active_securities.values()
            if hasattr(s, 'indicator') and s.indicator.is_ready
        ]

        if not available_securities:
            return

        selected_securities = sorted(available_securities, key=lambda s: s.indicator.current.value, reverse=True)[:10]

        market_caps = {}
        for s in selected_securities:
            market_caps[s.symbol] = s.fundamentals.market_cap

        total_market_cap = sum(market_caps.values())
        
        targets = []
        for symbol, mcap in market_caps.items():
            weight = mcap / total_market_cap
            targets.append(PortfolioTarget(symbol, weight))

        if targets:
            self.set_holdings(targets, liquidate_existing_holdings=True)