Overall Statistics
Total Trades
877
Average Win
2.12%
Average Loss
-1.28%
Compounding Annual Return
194.232%
Drawdown
54.600%
Expectancy
0.476
Net Profit
768.290%
Sharpe Ratio
2.571
Probabilistic Sharpe Ratio
85.068%
Loss Rate
44%
Win Rate
56%
Profit-Loss Ratio
1.65
Alpha
1.426
Beta
0.269
Annual Standard Deviation
0.574
Annual Variance
0.329
Information Ratio
2.186
Tracking Error
0.591
Treynor Ratio
5.491
Total Fees
$116544.85
Estimated Strategy Capacity
$0
Lowest Capacity Asset
BNSOF R735QTJ8XC9X
from AlgorithmImports import *
from Risk.TrailingStopRiskManagementModel import TrailingStopRiskManagementModel


class WellDressedSkyBlueSardine(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2021,12, 31)
        self.SetCash(100000)
        self.rebalanceTime = datetime.min
        self.activeStocks = set()
        self.SetRiskManagement(TrailingStopRiskManagementModel(0.11))
        
        self.AddUniverse(self.CoarseFilter, self.FineFilter)
        self.UniverseSettings.Resolution = Resolution.Daily
      
        self.portfolioTargets = []
        
        
        #Parameters
        
        timedelta = self.GetParameter("timedelta")
        sortedByPE = self.GetParameter("sortedByPE")
        MarketCap = self.GetParameter("MarketCap")
        
        self.PRAM_timedelta = 16 if timedelta is None else int(timedelta)
        self.PRAM_sortedByPE = 8 if sortedByPE is None else int(sortedByPE)
        self.PRAM_MarketCap = 10000000 if MarketCap is None else int(MarketCap)

    def CoarseFilter(self, coarse):
        # Rebalancing monthly
        if self.Time <= self.rebalanceTime:
            return self.Universe.Unchanged
        self.rebalanceTime = self.Time + timedelta(self.PRAM_timedelta)
        
        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=False)
        return [x.Symbol for x in sortedByDollarVolume if x.Price < 10
                                                and x.HasFundamentalData][:200]

    def FineFilter(self, fine):
        sortedByPE = sorted(fine, key=lambda x: x.MarketCap, reverse=False)
        return [x.Symbol for x in sortedByPE if x.MarketCap > self.PRAM_MarketCap][:self.PRAM_sortedByPE]
        
    
    def OnSecuritiesChanged(self, changes):
        # close positions in removed securities
        for x in changes.RemovedSecurities:
            self.Liquidate(x.Symbol)
            self.activeStocks.remove(x.Symbol)
        
        # can't open positions here since data might not be added correctly yet
        for x in changes.AddedSecurities:
            self.activeStocks.add(x.Symbol)   

        # adjust targets if universe has changed
        #if self.SetRiskManagement is True:
        #    self.SetHoldings(-1)
        #else:
            self.portfolioTargets = [PortfolioTarget(symbol, 1/len(self.activeStocks)) 
                            for symbol in self.activeStocks]
                            
                            

    def OnData(self, data):
        
        if self.portfolioTargets == []:
            return
        
        for symbol in self.activeStocks:
            if symbol not in data:
                return
       
        self.SetHoldings(self.portfolioTargets)
        
        self.portfolioTargets = []
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            self.Debug(f'Processed Order: {orderEvent.Symbol}, Quantity: {orderEvent.FillQuantity}')