Overall Statistics
Total Trades
1130
Average Win
1.41%
Average Loss
-1.31%
Compounding Annual Return
5.320%
Drawdown
46.700%
Expectancy
0.106
Net Profit
89.362%
Sharpe Ratio
0.376
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
1.08
Alpha
0.143
Beta
-5.54
Annual Standard Deviation
0.139
Annual Variance
0.019
Information Ratio
0.258
Tracking Error
0.139
Treynor Ratio
-0.009
Total Fees
$4070.34
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel

class HorizontalMultidimensionalReplicator(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2007, 1, 1)  # Set Start Date
        self.SetCash(100000)            # Set Strategy Cash
        
        self.AddAlpha(PanicToExcuberanceAlphaModel(self))

        self.SetExecution(ImmediateExecutionModel())

        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())

        symbols = [ Symbol.Create("SPY", SecurityType.Equity, Market.USA) ]
        self.SetUniverseSelection( ManualUniverseSelectionModel(symbols) )


class PanicToExcuberanceAlphaModel(AlphaModel):
    
        # This Alpha uses data from URC that contains the number of companies currently reaching new highs
        # in stock price, within the NASDAQ exchange. It is likely that very few companies are reaching 
        # new highs when a recession is imminent. Many companies reach new highs when market participants 
        # are exuberant. 

        # This Alpha Model uses smoothed Exponential Moving Average (EMA) to determine how many companies
        # on average are reaching a new high. If the number of companies is less than 50, then it emits 
        # insights and continues to do so until the number of companies is greater than 150.
        
        ## More URC market data can be found at Quandl
        ## https://www.quandl.com/data/URC-Unicorn-Research-Corporation
    
    def __init__(self, algorithm):
        
        # Add Quandl data
        self.yearlyHighs = algorithm.AddData(QuandlData, 'URC/NASDAQ_52W_HI',Resolution.Daily).Symbol
        
        # Set predicition period
        self.period = timedelta(days=1)
        
        # Set lookback window for Rolling Window and EMA Indicator
        self.lookback = 5
        
        # Set resolution for EMA Indicator
        self.resolution = Resolution.Daily
        self.emitInsights = False

        self.cnt = 0
    
    def Update(self, algorithm, data):
        insights = []
        
        # Return if no data
        if not data.ContainsKey(self.yearlyHighs): return insights
        
        # Set emitInsights to false when the number of companies greater than 150
        if self.emaWin[0].Value > 150:
            self.emitInsights = False
        # Set emitInsights to false when the number of companies is less than 50
        elif self.emaWin[0].Value < 50:
            self.emitInsights = True
            
        # Emit insights    
        if self.emitInsights:
            insights.append(Insight.Price("SPY", self.period, InsightDirection.Up, 0.001))
            
        return insights
        
    def OnSecuritiesChanged(self,algorithm,changes):
        for added in changes.AddedSecurities:
            # Only add EMA and Rolling Window for custom data
            if added.Symbol == self.yearlyHighs:

                # Construct an EMA indicator and a rolling window for added securities
                algorithm.EMA(added.Symbol, self.lookback,self.resolution).Updated += self.emaUpdated
                self.emaWin = RollingWindow[IndicatorDataPoint](self.lookback)
            
    # Adds values to rolling window
    def emaUpdated(self, sender, updated):
        self.emaWin.Add(updated)

           
class QuandlData(PythonQuandl):
    
    def __init__(self):
        ## Retrieve the data from the the Quandl object, specifying the data field used on Quandl
        self.ValueColumnName = "NUMBERS OF STOCKS"