Overall Statistics
Total Orders
1806
Average Win
0.93%
Average Loss
-0.61%
Compounding Annual Return
30.901%
Drawdown
49.800%
Expectancy
0.690
Start Equity
100000
End Equity
6502432.44
Net Profit
6402.432%
Sharpe Ratio
0.86
Sortino Ratio
0.952
Probabilistic Sharpe Ratio
22.797%
Loss Rate
33%
Win Rate
67%
Profit-Loss Ratio
1.53
Alpha
0.121
Beta
1.218
Annual Standard Deviation
0.261
Annual Variance
0.068
Information Ratio
0.704
Tracking Error
0.198
Treynor Ratio
0.184
Total Fees
$9042.18
Estimated Strategy Capacity
$21000000.00
Lowest Capacity Asset
KEYS VV9PLPU5EI5H
Portfolio Turnover
1.94%
Drawdown Recovery
539
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_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)

        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
        )

        self.set_benchmark(self._ETF_TICKER)
        self.set_warm_up(self._TRIX_TIME_PERIOD, Resolution.DAILY)

    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)

        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)