Overall Statistics
Total Orders
999
Average Win
0.32%
Average Loss
-0.07%
Compounding Annual Return
6.547%
Drawdown
26.600%
Expectancy
3.866
Start Equity
100000
End Equity
602866.53
Net Profit
502.867%
Sharpe Ratio
0.284
Sortino Ratio
0.224
Probabilistic Sharpe Ratio
0.225%
Loss Rate
18%
Win Rate
82%
Profit-Loss Ratio
4.90
Alpha
0.006
Beta
0.353
Annual Standard Deviation
0.086
Annual Variance
0.007
Information Ratio
-0.221
Tracking Error
0.122
Treynor Ratio
0.069
Total Fees
$871.59
Estimated Strategy Capacity
$72000000.00
Lowest Capacity Asset
GPC R735QTJ8XC9X
Portfolio Turnover
0.02%
Drawdown Recovery
708
# region imports
from AlgorithmImports import *
# endregion

class DeterminedYellowButterfly(QCAlgorithm):

    def initialize(self):
        self.set_start_date(1998, 1, 1)
        self.set_cash(100000)
        self.settings.seed_initial_prices = True
        
        # Add SPY ETF constituents universe
        self._spy = self.add_equity("SPY", Resolution.DAILY).symbol
        self._universe = self.add_universe(self.universe.etf(self._spy, self.universe_settings))
        
        # Track if initial rebalance has occurred
        self._initial_rebalance_done = False
        
        # Schedule annual rebalancing on January 1st
        self.schedule.on(self.date_rules.year_start(self._spy), 
                        self.time_rules.after_market_open(self._spy, 30), 
                        self._rebalance)
    
    def on_securities_changed(self, changes):
        # Do initial rebalance once universe is populated
        if not self._initial_rebalance_done and self._universe.selected and len(self._universe.selected) > 0:
            self._rebalance()
            self._initial_rebalance_done = True
        
    def _rebalance(self):
        # Get active constituents
        if not self._universe.selected:
            return
            
        constituents = list(self._universe.selected)
        
        if not constituents:
            return
            
        # Equal weight all constituents
        weight = 1.0 / len(constituents)
        targets = [PortfolioTarget(symbol, weight) for symbol in constituents]
        
        # Rebalance portfolio and liquidate any holdings not in targets
        self.set_holdings(targets, liquidate_existing_holdings=True)