Overall Statistics
Total Trades
395
Average Win
2.49%
Average Loss
-1.70%
Compounding Annual Return
174.031%
Drawdown
50.800%
Expectancy
0.441
Net Profit
174.788%
Sharpe Ratio
2.184
Probabilistic Sharpe Ratio
65.137%
Loss Rate
42%
Win Rate
58%
Profit-Loss Ratio
1.46
Alpha
1.565
Beta
0.282
Annual Standard Deviation
0.738
Annual Variance
0.545
Information Ratio
1.899
Tracking Error
0.761
Treynor Ratio
5.718
Total Fees
$27044.98
Estimated Strategy Capacity
$0
Lowest Capacity Asset
AMS R735QTJ8XC9X
from AlgorithmImports import *

class MaximumDrawdownPercentPerSecurity(RiskManagementModel):
    '''Provides an implementation of IRiskManagementModel that limits the drawdown per holding to the specified percentage'''

    def __init__(self, maximumDrawdownPercent = 0.05):
    #    '''Initializes a new instance of the MaximumDrawdownPercentPerSecurity class
    #   Args:
    #      maximumDrawdownPercent: The maximum percentage drawdown allowed for any single security holding'''
        self.maximumDrawdownPercent = -abs(maximumDrawdownPercent)

    def ManageRisk(self, algorithm, targets):
        '''Manages the algorithm's risk at each time step
        Args:
            algorithm: The algorithm instance
            targets: The current portfolio targets to be assessed for risk'''
        targets = []
        for kvp in algorithm.Securities:
            security = kvp.Value

            if not security.Invested:
                continue

            pnl = security.Holdings.UnrealizedProfitPercent
            if pnl < self.maximumDrawdownPercent:
                # liquidate
                targets.append(PortfolioTarget(security.Symbol, 0))

        return targets
from AlgorithmImports import *
from MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity
class WellDressedSkyBlueSardine(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2020,12, 31)
        self.SetCash(100000)
        self.rebalanceTime = datetime.min
        self.activeStocks = set()
        
        self.AddUniverse(self.CoarseFilter, self.FineFilter)
        self.UniverseSettings.Resolution = Resolution.Daily
        #self.AddRiskManagement(MaximumDrawdownPercentPerSecurity(self))
      
        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)   

            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 = []