Overall Statistics
Total Trades
841
Average Win
0.08%
Average Loss
-0.03%
Compounding Annual Return
1015.850%
Drawdown
5.700%
Expectancy
0.536
Net Profit
8.971%
Sharpe Ratio
22.534
Probabilistic Sharpe Ratio
73.460%
Loss Rate
59%
Win Rate
41%
Profit-Loss Ratio
2.75
Alpha
0
Beta
0
Annual Standard Deviation
0.507
Annual Variance
0.257
Information Ratio
22.534
Tracking Error
0.507
Treynor Ratio
0
Total Fees
$904.24
Estimated Strategy Capacity
$15000000.00
from clr import AddReference
AddReference("System")
AddReference("QuantConnect")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")

from System import *
from System.Drawing import Color
from QuantConnect import *
from QuantConnect.Parameters import *
from QuantConnect.Benchmarks import *
from QuantConnect.Brokerages import *
from QuantConnect.Util import *
from QuantConnect.Interfaces import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Selection import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Risk import *
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.Custom import *
from QuantConnect.Data.Fundamental import *
from QuantConnect.Data.Market import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Notifications import *
from QuantConnect.Orders import *
from QuantConnect.Orders.Fees import *
from QuantConnect.Orders.Fills import *
from QuantConnect.Orders.Slippage import *
from QuantConnect.Scheduling import *
from QuantConnect.Securities import *
from QuantConnect.Securities.Equity import *
from QuantConnect.Securities.Forex import *
from QuantConnect.Securities.Interfaces import *
from datetime import date, datetime, timedelta
from QuantConnect.Python import *
from QuantConnect.Storage import *
QCAlgorithmFramework = QCAlgorithm
QCAlgorithmFrameworkBridge = QCAlgorithm
import decimal as d
import numpy as np
import pandas as pd
from io import StringIO
import random


class SymbolData:
    """
    Class to hold Data for specific Tickers.
    Currently holding:
        - SPY - 50 dEMA
    """
    def __init__(self, algorithm, symbol,
                            followerEMAPeriod = 50,
                            resolution = Resolution.Daily,
                            field = Field.Close):
        
        self.Symbol = symbol
        
        self.followerEMA = None
        self.followerEmaWindow = None
        
        self.ema = ExponentialMovingAverage(followerEMAPeriod)
        self.consolidator = None
    
    def regIndicator(self, algorithm, resolution):
        self.consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
        algorithm.RegisterIndicator(self.Symbol, self.ema, self.consolidator)
        
    def removeConsolidators(self, algorithm):
        if self.consolidator is not None:
            algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.consolidator)
        
    def warmup(self, history):
        for tuple in history.itertuples():
            self.ema.Update(tuple.Index, tuple.close)


class FollowerData:
    """
    Class to hold Data for specific Tickers.
    Currently holding:
        - SPY - 50 dEMA
    """
    def __init__(self, algorithm, security,
                            followerEMAPeriod = 50,
                            resolution = Resolution.Daily,
                            field = Field.Close):
        
        self.Security = security
        self.Symbol = security.Symbol
        
        self.followerEMA = None
        self.followerEmaWindow = None

    def FollowerEmaUpdated(self, sender, updated):
        self.followerEmaWindow.Add(updated)
        

class CAlphaModel(AlphaModel):
    '''
    Custom Alpha Model.
  
    '''

    def __init__(self, slowPeriod = 50,
                lookup = 490,
                resolution = Resolution.Daily,
                field = Field.Close):

        self.lookup = lookup
        self.slowPeriod = slowPeriod
    
        self.resolution = resolution
        self.field = field
        
        self.insightPeriod = timedelta(minutes=10)
    
        # ETF watchers
        self.followers = {'XLK' : True, 'XLC' : True, 'XLV' : True, 'XLY' : True,
                            'XLI' : True, 'XLF' : True, 'XLRE' : True, 'XLE' : True,
                            'XLP' : True, 'XLU' : True, 'XLB' : True, 'SPY' : True,
                            'IYZ' : True, 'ITB' : True, 'CARZ' : True, 'BJK' : True,
                            'ITA' : True, 'SMH' : True, 'KCE' : True, 'KIE' : True,
                            'KRE' : True, 'KBE' : True, 'XHS' : True, 'XBI' : True,
                            'XHE' : True, 'XPH' : True, 'XES' : True, 'XME' : True,
                            'WOOD' : True, 'ICLN' : True, 'XRT' : True, 'ONLN' : True,
                            'GLD' : True, 'SLX' : True, 'MJ' : True, 'CEX' : True,
                            'XWEB' : True, 'IGV' : True, 'JETS' : True, 'IYT' : True
        }
        self.followerData = {}
        self.symbolData = {}
    
        resolutionString = Extensions.GetEnumString(resolution, Resolution)
        self.Name = '{}({},{})'.format(self.__class__.__name__, slowPeriod, resolutionString)
        
    def Update(self, algorithm, data):

        insights = []
        
        key = 'SPY'
        spyData = self.followerData[key]
        
        if not (data.ContainsKey(spyData.Symbol) and data.Bars.ContainsKey(spyData.Symbol)):
            return insights
            
        spyTime = data[spyData.Symbol].Time
        spyClose = data[spyData.Symbol].Close
        
        if spyClose < spyData.followerEMA.Current.Value:
            algorithm.Debug(f"- SPY < 50dEMA - {spyTime} close:{spyClose} 50dEMA method#1:{spyData.followerEMA.Current.Value} 50dEMA RW:{spyData.followerEmaWindow[0].Value} 50dEMA method#2:{self.symbolData[key].ema.Current.Value}")
            self.followers['SPY'] = False
            
        elif spyClose > spyData.followerEMA.Current.Value:
            algorithm.Debug(f"- SPY > 50dEMA - {spyTime} close:{spyClose} 50dEMA method#1:{spyData.followerEMA.Current.Value} 50dEMA_window:{spyData.followerEmaWindow[0].Value} 50dEMA method#2:{self.symbolData[key].ema.Current.Value}")
            self.followers['SPY'] = True
            
        for key, follower in self.followerData.items():
            if follower.Symbol.Value not in self.followers:
                
                if not (data.ContainsKey(follower.Symbol) and data.Bars.ContainsKey(follower.Symbol)):
                    continue
            
                if not self.followers['SPY']:
                    # self.Liquidate(key.Value)
                    insight = Insight.Price(follower.Symbol, self.insightPeriod, InsightDirection.Flat)
                    insights.append(insight)
                    
                elif self.followers['SPY']:
                    # self.SetHoldings(key.Value, 0.1)
                    insight = Insight.Price(follower.Symbol, self.insightPeriod, InsightDirection.Up)
                    insights.append(insight)
                        
        return insights

    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the add/remove securities from the data feed.
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''
        
        # method 1
        symbols = [x.Symbol for x in changes.AddedSecurities]
        his = algorithm.History(symbols, self.lookup)
        
        if his.empty:
            return
    
        tickers = his.index.levels[0]
        
        for ticker in tickers:
            symbol = SymbolCache.GetSymbol(ticker)
                
            if symbol.Value in self.followers and symbol.Value not in self.symbolData:
                sd = SymbolData(algorithm, symbol, self.slowPeriod, self.resolution)
                self.symbolData[symbol.Value] = sd
                sd.regIndicator(algorithm, self.resolution)
                sd.warmup(his.loc[ticker])
          
        # method 2      
        for added in changes.AddedSecurities:

            if not added.Symbol in self.followerData: 
                follower = FollowerData(algorithm, added, self.slowPeriod, self.resolution)
                
                follower.followerEMA = algorithm.EMA(added.Symbol, self.slowPeriod, self.resolution, self.field)
                follower.followerEMA.Updated += follower.FollowerEmaUpdated
                follower.followerEmaWindow = RollingWindow[IndicatorDataPoint](self.slowPeriod)

                # warmup our indicators by pushing history through the indicators
                history = algorithm.History(added.Symbol, self.lookup, self.resolution)
                
                if history.empty:
                    continue
                    
                if 'close' in history:
                    history = history.close.unstack(0).squeeze()
                    for time, value in history.iteritems():
                        follower.followerEMA.Update(time, value)

                self.followerData[added.Symbol.Value] = follower
                continue
               
        for removed in changes.RemovedSecurities:
            pass
from clr import AddReference
AddReference("System")
AddReference("QuantConnect")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")

from System import *
from System.Drawing import Color
from QuantConnect import *
from QuantConnect.Parameters import *
from QuantConnect.Benchmarks import *
from QuantConnect.Brokerages import *
from QuantConnect.Util import *
from QuantConnect.Interfaces import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Selection import *
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Risk import *
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from QuantConnect.Data.Consolidators import *
from QuantConnect.Data.Custom import *
from QuantConnect.Data.Fundamental import *
from QuantConnect.Data.Market import *
from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Notifications import *
from QuantConnect.Orders import *
from QuantConnect.Orders.Fees import *
from QuantConnect.Orders.Fills import *
from QuantConnect.Orders.Slippage import *
from QuantConnect.Scheduling import *
from QuantConnect.Securities import *
from QuantConnect.Securities.Equity import *
from QuantConnect.Securities.Forex import *
from QuantConnect.Securities.Interfaces import *
from datetime import date, datetime, timedelta
import pandas as pd
from io import StringIO
import numpy as np
import random
from QuantConnect.Python import *
from QuantConnect.Storage import *
QCAlgorithmFramework = QCAlgorithm
QCAlgorithmFrameworkBridge = QCAlgorithm

from CUniverse import EmaUniverseSelectionModel
from Alpha import CAlphaModel


class GeekyOrangeSheep(QCAlgorithmFramework):

    def Initialize(self):
        self.SetStartDate(2021, 1, 20) # Set Start Date
        self.SetEndDate(2021, 2, 1)

        # self.SetEndDate(datetime.now() - timedelta(1))
        
        self.SetCash(100000)
        
        # Adjust the cash buffer from the default 2.5% to 5%
        self.Settings.FreePortfolioValuePercentage = 0.05

        # Rebalance when the insights state changes/added/expire.         
        self.Settings.RebalancePortfolioOnInsightChanges = False

        # Rebalance when new assets are added to the universe.  
        self.Settings.RebalancePortfolioOnSecurityChanges = False

        #Brokerage model and account type:
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
        
        # Adjust the market fill-timeout to 30 seconds.
        self.Transactions.MarketOrderFillTimeout = timedelta(minutes=30)
        
        self.UniverseSettings.Resolution = Resolution.Daily
        self.UniverseSettings.Leverage = 1

        self.SetUniverseSelection(EmaUniverseSelectionModel())
        self.SetAlpha(CAlphaModel())
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
        self.SetExecution(ImmediateExecutionModel())
        self.SetRiskManagement(NullRiskManagementModel())

        # set Security to SplitAdjusted price
        self.SetSecurityInitializer(self.CustomSecurityInitializer)
        

    def CustomSecurityInitializer(self, security):
        '''
        Initialize the security with SplitAdjusted prices
        mimic using a cash account in backtesting by setting security leverage to 1.
        '''
        security.SetDataNormalizationMode(DataNormalizationMode.SplitAdjusted)
        security.SetLeverage(1)
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm.Framework")

from QuantConnect.Data.UniverseSelection import *
from QuantConnect.Indicators import ExponentialMovingAverage
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
import random
import numpy as np

class SymbolData:
    """
    Holds every symbol's information and indicators.
    """
    def __init__(self, symbol, algorithm,
                        volPeriod = 30,
                        rocPeriod = 9,
                        volMax = 1000000):

        self.Symbol = symbol
        self.Volume = 0
        self.Price = 0
        
        self.algo = algorithm
        
        self.avgVolPeriod = volPeriod
        self.avgVolMax = volMax     
        
        self.sma = SimpleMovingAverage(self.avgVolPeriod)
        self.rocp = RateOfChangePercent(rocPeriod + 1)

        self.rocW = RollingWindow[float](rocPeriod + 2)
        self.rocV = 0

        self.isGood = False
    
    def update(self, time, volume, price):
        
        self.Volume = volume
        self.Price = price 
        
        self.sma.Update(time, volume)
        self.rocp.Update(time, price) 
        
        self.rocW.Add(price)
        
        if self.sma.IsReady and self.rocp.IsReady:
            sma = self.sma.Current.Value
            roc = self.rocp.Current.Value
            
            self.rocV = 100 * (self.rocW[0] - self.rocW[self.rocW.Count-1]) / self.rocW[self.rocW.Count-1]
            
            self.isGood = sma > self.avgVolMax and roc > 0

    def warmup(self, history):
        for index, row in history.loc[str(self.Symbol)].iterrows():
            c = row['close']
            v = row['volume']

            self.sma.Update(index, v)
            self.rocp.Update(index, c) 
            self.rocW.Add(c)
            
        self.rocV = 100 * (self.rocW[0] - self.rocW[self.rocW.Count-1]) / self.rocW[self.rocW.Count-1]
        
class EmaUniverseSelectionModel(FundamentalUniverseSelectionModel):
    '''Provides an implementation of FundamentalUniverseSelectionModel that subscribes to
    symbols with the larger delta by percentage between the two exponential moving average'''

    def __init__(self, slowPeriod = 50,
                 resolution = Resolution.Daily,
                 field = Field.Close,
                 universeSettings = None,
                 securityInitializer = None):
        '''Initializes a new instance of the EmaCrossUniverseSelectionModel class
        Args:
            fastPeriod: Fast EMA period
            slowPeriod: Slow EMA period
            universeCount: Maximum number of members of this universe selection
            universeSettings: The settings used when adding symbols to the algorithm, specify null to use algorthm.UniverseSettings
            securityInitializer: Optional security initializer invoked when creating new securities, specify null to use algorithm.SecurityInitializer'''
        super().__init__(True, universeSettings, securityInitializer)

        self.slowPeriod = slowPeriod
        self.resolution = resolution
        self.field = field

        self.coarseData = {}
        
        self.week = 0
        self.month = -1

        self.__avgVolPeriod = 30
        self.__avgVolMax = 1000000      #1M
        self.__dailyVol = 500000

        self.__filterPriceMin = 2
        self.__filterPriceMax = 500

        self.__numberOfSymbols = 100
        
        self.spy = Symbol.Create('SPY', SecurityType.Equity, 'USA')
        
    def SelectCoarse(self, algorithm, coarse):
        '''Defines the coarse fundamental selection function.
        Args:
            algorithm: The algorithm instance
            coarse: The coarse fundamental data used to perform filtering</param>
        Returns:
            An enumerable of symbols passing the filter'''
          
        # current_week = algorithm.Time.month
        # if current_week == self.week:
        #     return self.symbols
 
        # self.week = current_week  
        
        symbols = [x for x in coarse if self.__filterPriceMax > x.Price > self.__filterPriceMin and \
                                                                    x.Volume > self.__dailyVol]
        
        symbols = sorted(symbols, key = lambda x: x.Volume, reverse=True)[:300]
        
        for cf in symbols:
        
            if not cf.Symbol in self.coarseData: 

                history = algorithm.History([cf.Symbol], 30, self.resolution)
    
                if history.empty:
                    continue
                if history.size < 30:
                    continue
                
                self.coarseData[cf.Symbol] = SymbolData(cf.Symbol, algorithm)
                self.coarseData[cf.Symbol].warmup(history)

            self.coarseData[cf.Symbol].update(cf.EndTime, cf.Volume, cf.AdjustedPrice)

        algorithm.Debug(f"-Universe Coarse- {algorithm.Time - timedelta(1)}")
        
        values = list(filter(lambda x: x.isGood, self.coarseData.values()))
        values = sorted(values, key = lambda x: x.rocV, reverse=True)[:self.__numberOfSymbols]
        
        algorithm.Debug(f"\t symbols: {[x.Symbol.Value for x in values]}")
        res = [x.Symbol for x in values]
        res.append(self.spy)   
        return res

    def SelectFine(self, algorithm, fine):

        # current_week = algorithm.Time.month
        
        # if current_week == self.week:
        #     return self.symbols
        
        symbols = [x.Symbol for x in fine if x.SecurityReference.ExchangeId in ["NAS", "NYS", "ASE"]]
        symbols.append(self.spy)
        return symbols

    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the add/remove securities from the data feed.
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''
            
        for removed in changes.RemovedSecurities:
            # clean up data from removed securities
            symbol = removed.Symbol

            if symbol in self.coarseData:
                data = self.coarseData.pop(symbol)