Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
import numpy as np
import datetime
from scipy import stats 

### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>
class StocksOnTheMove(QCAlgorithm):
    '''Basic template algorithm simply initializes the date range and cash'''

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''

        self.SetStartDate(2013,1,1)  #Set Start Date
        self.SetEndDate(2013,2,1)    #Set End Date
        self.SetCash(100000)           #Set Strategy Cash
        # Find more symbols here: http://quantconnect.com/data
        self.AddEquity("SPY", Resolution.Daily)
        
        # what resolution should the data *added* to the universe be?
        self.UniverseSettings.Resolution = Resolution.Daily
        
        # How many stocks in the starting universe?
        self.__numberOfSymbols = 20
        
        # How many stocks in the portfolio?
        self.number_stocks = 5
        
        # this add universe method accepts two parameters:
        self.AddUniverse(self.CoarseSelectionFunction)
        
        # How far back are we looking for momentum?
        self.momentum_period = 20
        
        # Schedule Indicator Update, Ranking + Rebal
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 30), Action(self.rebalance))
        
        # Set Risk Factor for position sizing
        self.risk_factor = 0.001
        
        # Set empty list for universe
        self.universe = []
        
        # Set empty dictionary for managing & ranking the slope
        self.indicators = {}
        
        # Set empty dictionary to manage ATR position sizing for ranked securities
        self.target_portfolio = {}

    def OnData(self, data):
        pass
    
    # Run a coarse selection filter for starting universe
    def CoarseSelectionFunction(self, coarse):
    
        today = self.Time
        #self.Log("Day = {} Month = {}".format(today.day,today.month))
        
        # Set the Universe to rebalance on the 1st day of each quarter (can play around with this as required)
        if today.day == 1 and (today.month == 1 or today.month == 4 or today.month == 7 or today.month == 10):
            CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData]
            sortedByDollarVolume = sorted(CoarseWithFundamental, key=lambda x: x.DollarVolume, reverse=True)
            result = [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]
            self.universe = result
            return self.universe
        else:
            return self.universe
            
    def rebalance(self):
        
        # This updates the indicators at each data step(based on resolution)
        for symbol in self.universe:
            
            # is symbol iin Slice object? (do we even have data on this step for this asset)
            if not self.Securities.ContainsKey(symbol):
                continue
            
            
            # 686 | 13:35:43: Runtime Error: Python.Runtime.PythonException: AttributeError : 'NoneType' object has no attribute 'Price'
            #if data[symbol] is None:
            #    continue
            
            # Does this slice have the price data we need at this moment?
            #if data[symbol].Price is None:
            #    continue
            
            # Update the dictionary for the indicator
            #history = self.History(symbol, self.momentum_period, Resolution.Daily)["close"].unstack(level=0)
            #self.indicators[symbol] = regression_slope(history)
            self.indicators[symbol] = update_indicator(self.Time, self.Securities[symbol].Price)
            
        # Sort the Dictionary from highest to lowest and take the top values
        self.target_portfolio = sorted(self.indicators, key=self.indicators.get, reverse=True)[:self.number_stocks]
            
        for symbol in self.target_portfolio:
            
            # Liquidate if not in target portfolio
            if symbol.Invested:
                if symbol not in self.target_portfolio:
                    self.Liquidate(symbol)
                elif symbol in self.target_portfolio:
                    continue
                
            # Place orders for stocks not current in target portfolio
            elif symbol.Invested == False:
                
                #self.Log("{} {} {}"symbol,)
                
                # Update ATR for the stock in the new dictionary
                self.target_portfolio[symbol].update_value(self.Time, self.Securities[symbol].Price)
                
                self.Log("{} {} {}".format(symbol,self.Securities[symbol].Price,self.indicators[symbol].ATR.Current.Value))
                
                # Calculate number of shares to buy
                quantity = self.target_portfolio[symbol].ATR.Current.Value/(Portfolio.TotalPortfolioValue*self.risk_factor)
                
                # Send Orders
                self.MarketOrder(stock, quantity)
            
            
class SymbolData(object):
    def __init__(self, symbol, context):
        self.symbol = symbol
        """
        I had to pass ATR from outside object to get it to work, could pass context and use any indica
        var atr = ATR(Symbol symbol, int period, MovingAverageType type = null, Resolution resolution = null, Func`2[Data.IBaseData,Data.Market.IBaseDataBar] selector = null)
        """
        self.ATR = context.ATR(symbol, 20)

    """
    Runtime Error: Python.Runtime.PythonException: NotSupportedException : AverageTrueRange does not support Update(DateTime, decimal) method overload. Use Update(IBaseDataBar) instead.
    """
        
        # Use the below update method for ATR which is used for position sizing
    def update_value(self, time, value):
        self.ATR.Update(time, value)
        
class CustomIndicator(object):
    def __init__(self, symbol, context):
        history = self.History(symbol, self.momentum_period, Resolution.Daily)["close"].unstack(level=0)

        # Get Regression Stats & Compute Slope * R^2
    def regression_slope(self, time, value):  
        x = np.arange(len(history))
        log_ts = np.log(history)
        slope, intercept, r_value, p_value, std_err = stats.linregress(x, log_ts)
        annualized_slope = (np.power(np.exp(slope), 250) - 1) * 100
        annualized_slope = annualized_slope * (r_value ** 2)
        # Return the Indicator
        return annualized_slope
        
    def update_indicator(self, time, value):
        self.regression_slope.Update(time, value)