Overall Statistics
Total Trades
115
Average Win
0.36%
Average Loss
-0.45%
Compounding Annual Return
7.682%
Drawdown
18.500%
Expectancy
-0.199
Net Profit
7.682%
Sharpe Ratio
0.429
Probabilistic Sharpe Ratio
25.972%
Loss Rate
55%
Win Rate
45%
Profit-Loss Ratio
0.79
Alpha
0.08
Beta
0.016
Annual Standard Deviation
0.194
Annual Variance
0.038
Information Ratio
-0.359
Tracking Error
0.259
Treynor Ratio
5.09
Total Fees
$168.53
# from System import *
# from clr import AddReference
# AddReference("QuantConnect.Algorithm")
# from QuantConnect import *
# from QuantConnect.Orders import *
# from QuantConnect.Algorithm import *
# from QuantConnect.Algorithm.Framework import *
# from QuantConnect.Algorithm.Framework.Execution import *
# from QuantConnect.Algorithm.Framework.Portfolio import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
# from QuantConnect.Algorithm.Framework.Portfolio import PortfolioConstructionModel

class NadionUncoupledPrism(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2010, 1, 1)
        self.SetEndDate(2011,1 ,1)
        self.SetCash(100000)
        self.SetBenchmark("QQQ")
        self.averages = {}
        #self.SetAlpha()
        self.AddEquity("SPY", Resolution.Daily)
        self.AddUniverseSelection(TechnologyUniverseModule())
        self.AddRiskManagement(NullRiskManagementModel())
        self.SetPortfolioConstruction(NullPortfolioConstructionModel())
        self.SetExecution(ImmediateExecutionModel())
        self.UniverseSettings.Resolution = Resolution.Daily
        

    def OnData(self, data):

        if self.IsWarmingUp:
            
            return


        for security in self.changes.RemovedSecurities:
            
            if security.Invested:
                
                self.Liquidate(security.Symbol)
                
                
        for security in self.changes.AddedSecurities:
            
            if not security.Invested:
                
                self.SetHoldings(security.Symbol, .05)
                    
            
        else:
            
            return


    def OnSecuritiesChanged(self, changes):
        
        self.changes = changes


class TechnologyUniverseModule(FundamentalUniverseSelectionModel):
    
    #This module selects the most liquid stocks listed on the Nasdaq Stock Exchange.
    
    def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None):
        self.numberOfSymbolsCoarse = 1000
        self.numberOfSymbolsFine = 100
        self.dollarVolumeBySymbol = {}
        self.lastMonth = -1
        self.averages = {}
        #Initializes a new default instance of the TechnologyUniverseModule
        super().__init__(filterFineData, universeSettings, securityInitializer)
        
    def SelectCoarse(self, algorithm, coarse):
        
        selected = []

        if algorithm.Time.month == self.lastMonth: 
            
            return Universe.Unchanged
            
    
        coarse = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 10],
                key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse] 

        
        for security in coarse:  
            
            symbol = security.Symbol
            
            if symbol not in self.averages:

                history = algorithm.History(symbol, 200, Resolution.Daily)

                self.averages[symbol] = SelectionData(history) 


            self.averages[symbol].update(algorithm.Time, security.AdjustedPrice)
            
            if  self.averages[symbol].is_ready() and self.averages[symbol].fast > self.averages[symbol].slow:
                
                self.dollarVolumeBySymbol[symbol] = security.DollarVolume
        
        '''
        -The stock must have fundamental data
        -The stock must have positive previous-month close price
        -The stock must have positive volume on the previous trading month
        '''
            

        #self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume}
        
        
        # If no security has met the QC500 criteria, the universe is unchanged.
        if len(self.dollarVolumeBySymbol) == 0:
            
            return Universe.Unchanged
            

        return list(self.dollarVolumeBySymbol.keys())
        #return list(self.dollarVolumeBySymbol.keys())


    def SelectFine(self, algorithm, fine):

        sortedByDollarVolume =  sorted([x for x in fine if x.CompanyReference.CountryId == "USA" \
                                and x.CompanyReference.PrimaryExchangeID == "NAS" \
                                and x.CompanyReference.IndustryTemplateCode == "N" \
                                and (algorithm.Time - x.SecurityReference.IPODate).days > 180], \
            key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True)


        if len(sortedByDollarVolume) == 0:
            
            return Universe.Unchanged
            
            
        self.lastMonth = algorithm.Time.month
        
        return [x.Symbol for x in sortedByDollarVolume[:20]]
        
        
class SelectionData():
    # Update the constructor to accept a history array
    
    def __init__(self, history):
        self.slow = ExponentialMovingAverage(200)
        self.fast = ExponentialMovingAverage(50)
        
        # Loop over the history data and update the indicators
        
        for bar in history.itertuples():
            self.fast.Update(bar.Index[1], bar.close)
            self.slow.Update(bar.Index[1], bar.close)
    
    def is_ready(self):
        return self.slow.IsReady and self.fast.IsReady
    
    def update(self, time, price):
        self.fast.Update(time, price)
        self.slow.Update(time, price)
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

class TechnologyUniverseModule(FundamentalUniverseSelectionModel):
    '''
    This module selects the most liquid stocks listed on the Nasdaq Stock Exchange.
    '''
    def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None):
        '''Initializes a new default instance of the TechnologyUniverseModule'''
        super().__init__(filterFineData, universeSettings, securityInitializer)
        self.numberOfSymbolsCoarse = 1000
        self.numberOfSymbolsFine = 100
        self.dollarVolumeBySymbol = {}
        self.lastMonth = -1

    def SelectCoarse(self, algorithm, coarse):
        '''
        Performs a coarse selection:
        
        -The stock must have fundamental data
        -The stock must have positive previous-day close price
        -The stock must have positive volume on the previous trading day
        '''
        if algorithm.Time.month == self.lastMonth: 
            return Universe.Unchanged

        sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.Volume > 0 and x.Price > 0],
            key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]

        self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume}
        
        # If no security has met the QC500 criteria, the universe is unchanged.
        if len(self.dollarVolumeBySymbol) == 0:
            return Universe.Unchanged

        return list(self.dollarVolumeBySymbol.keys())

    def SelectFine(self, algorithm, fine):
        '''
        Performs a fine selection:
        
        -The company's headquarter must in the U.S.
        -The stock must be traded on the NASDAQ stock exchange
        -The stock must be in the Industry Template Code catagory N
        -At least half a year since its initial public offering
        '''
        # Filter stocks and sort on dollar volume
        sortedByDollarVolume = sorted([x for x in fine if x.CompanyReference.CountryId == "USA"
                                        and x.CompanyReference.PrimaryExchangeID == "NAS"
                                        and x.CompanyReference.IndustryTemplateCode == "N"
                                        and (algorithm.Time - x.SecurityReference.IPODate).days > 180],
            key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True)

        if len(sortedByDollarVolume) == 0:
            return Universe.Unchanged
            
        self.lastMonth = algorithm.Time.month

        return [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]]