Overall Statistics
Total Orders
10412
Average Win
0.06%
Average Loss
-0.06%
Compounding Annual Return
-0.970%
Drawdown
10.100%
Expectancy
-0.019
Start Equity
100000
End Equity
94702.26
Net Profit
-5.298%
Sharpe Ratio
-0.508
Sortino Ratio
-0.611
Probabilistic Sharpe Ratio
0.039%
Loss Rate
51%
Win Rate
49%
Profit-Loss Ratio
0.99
Alpha
-0.016
Beta
-0.008
Annual Standard Deviation
0.034
Annual Variance
0.001
Information Ratio
-1.051
Tracking Error
0.109
Treynor Ratio
2.054
Total Fees
$10301.91
Estimated Strategy Capacity
$11000000.00
Lowest Capacity Asset
TAROF R735QTJ8XC9X
Portfolio Turnover
4.90%
#region imports
from AlgorithmImports import *
#endregion


class TwelveMonthCycle(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2013, 1, 1)  
        self.set_end_date(2018, 8, 1)  
        self.set_cash(100000) 
        self.set_security_initializer(
            BrokerageModelSecurityInitializer(
                self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)
            )
        )

        self.universe_settings.resolution = Resolution.DAILY
        self.add_universe(self._coarse_selection_function, self._fine_selection_function)
        self.add_equity("SPY", Resolution.DAILY)
        
        self.schedule.on(self.date_rules.month_start("SPY"), self.time_rules.after_market_open("SPY"), self._rebalance)
        
        self.monthly_rebalance = False 
        self.filtered_fine = None
        
    def _coarse_selection_function(self, coarse):
        if self.monthly_rebalance:
            return [x.symbol for x in coarse if x.has_fundamental_data]
        return []
    
    def _fine_selection_function(self, fine):
        if self.monthly_rebalance:
            fine = [i for i in fine if ((i.security_reference.exchange_id == "NYS") or (i.security_reference.exchange_id == "ASE"))]
            
            self.filtered_fine = []
            for i in fine:
                history_start = self.history([i.symbol], TimeSpan.from_days(365))
                history_end = self.history([i.symbol],TimeSpan.from_days(335))
                if not history_start.empty and not history_end.empty:
                    i.returns = float(history_end.iloc[0]["close"] - history_start.iloc[0]["close"])
                    self.filtered_fine.append(i)
            
            size = int(len(fine)*.3)
            self.filtered_fine = sorted(self.filtered_fine, key = lambda x: x.market_cap, reverse=True)[:size]
            self.filtered_fine = sorted(self.filtered_fine, key = lambda x: x.returns, reverse=True)
            self.filtered_fine = [i.symbol for i in self.filtered_fine]
            return self.filtered_fine

        else:
            return []
    
    def _rebalance(self):
        self.monthly_rebalance = True
    
    def on_data(self, data):
        if not self.monthly_rebalance or not self.filtered_fine: 
            return
        self.monthly_rebalance = False
        
        tradable_assets = [symbol for symbol in self.filtered_fine if self.securities[symbol].price]
        portfolio_size = int(len(tradable_assets)/10)
        weight = 1/(portfolio_size*2)
        targets = [PortfolioTarget(symbol, weight) for symbol in tradable_assets[:portfolio_size]]
        targets += [PortfolioTarget(symbol, -weight) for symbol in tradable_assets[-portfolio_size:]]
        self.set_holdings(targets, True)