Overall Statistics
Total Trades
21
Average Win
6.61%
Average Loss
-1.73%
Compounding Annual Return
384.780%
Drawdown
27.000%
Expectancy
3.287
Net Profit
94.680%
Sharpe Ratio
2.04
Loss Rate
11%
Win Rate
89%
Profit-Loss Ratio
3.82
Alpha
1.555
Beta
0.023
Annual Standard Deviation
0.756
Annual Variance
0.572
Information Ratio
2.306
Tracking Error
0.896
Treynor Ratio
67.233
Total Fees
$636.08
import numpy as np
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")
import math as mt
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from System.Collections.Generic import List
import decimal as d
from datetime import timedelta
### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>

def make_div_by_05(s, buy=False):
        s *= 20.00
        s =  mt.floor(s) if buy else mt.ceil(s)
        s /= 20.00
        return s               
class theMAs(object):
    def __init__(self,symbol):
        self.dv = 0 
        price = 0 
        self.symbol = symbol
        self.Short = SimpleMovingAverage(3)
        self.Long = SimpleMovingAverage(45)
        self.percent_diff = 0 
    def update(self,time,value):
        if self.Short.Update(time,value) and self.Long.Update(time,value):
            short = self.Short.Current.Value
            Long = self.Long.Current.Value
class BasicTemplateAlgorithm(QCAlgorithm):
    def __init__(self):
        self.Age = {}
    def Initialize(self):
        self.firstbuy = 1
        self.days = 0
        self.Tobuy = 0
        self.filtered_stocks = []
        self.averages = {}
        self.MaxCandidates=30
        self.MaxBuyOrdersAtOnce=10
        self.MyLeastPrice=0.40
        self.MyMostPrice=1.40
        self.MyFireSalePrice=self.MyLeastPrice
        self.MyFireSaleAge=3
        self.SetStartDate(2008,8,07)  #Set Start Date
        self.SetEndDate(2009,01,07)    #Set End Date
        self.SetCash(10000)           #Set Strategy Cash
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddEquity("SPY", Resolution.Daily)
        self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
        self.Schedule.On(self.DateRules.EveryDay(),self.TimeRules.Every(timedelta(minutes=10)),Action(self.rebalance))
        self.Schedule.On(self.DateRules.EveryDay(),self.TimeRules.At(9,37),Action(self.before_trading_start))
    def CoarseSelectionFunction(self, coarse):
        
        stocks_To_buy = filter(lambda x: x.Price >=self.MyLeastPrice,coarse)
        stocks_To_buy = filter(lambda x: x.Price <=self.MyMostPrice,stocks_To_buy)
        stocks_To_buy = filter(lambda x: x.HasFundamentalData,stocks_To_buy)
        
        #for stock in stocks_To_buy[:10]:
            #self.Log("The market of the stock is {}".format(stock.StandardName))
            
        #Symbols with more than 5 letters are usually not common stocks and otc's have 5 letters
        
        #Check here for more info https://www.investopedia.com/ask/answers/06/nasdaqfifthletter.asp(could take off)
        
        return [x.Symbol for x in stocks_To_buy[:60] if len(str(x.Symbol.Value)) < 5 and x.Symbol.Value != 'SPY' ]
        
    def FineSelectionFunction(self, fine):
        #Making sure not mlp
        stocks_To_buy = filter(lambda x: 'lp' not in str(x.CompanyReference.ShortName).lower(),fine)
        #Making sure not adr
        stocks_To_buy = filter(lambda x: int(x.SecurityReference.IsDepositaryReceipt) ==0,stocks_To_buy)
        #Making sure is primary adr
        stocks_To_buy = filter(lambda x: x.SecurityReference.IsPrimaryShare,stocks_To_buy)
        #Making sure not otc
        stocks_To_buy = filter(lambda x: str(x.SecurityReference.ExchangeId) != "OTC",stocks_To_buy)
        #get moving averages and dollar volume
        for stock in stocks_To_buy:
            self.AddEquity(str(stock.Symbol.Value))
            hist = self.History([stock.Symbol.Value],20,Resolution.Daily)
            if 'volume' in hist:
                dv = (hist['volume'].mean()*hist['close'].mean())/len(hist)
                #self.dvolume[stock.Symbol.Value] = dvolume(stock.Symbol.Value,dv)  
                #self.Log(("Volume for stock {} is {}".format(self.dvolume[stock.Symbol.Value].symbol,self.dvolume[stock.Symbol.Value].dvolAvg)))
            
                if stock.Symbol not in self.averages:
                    self.averages[stock.Symbol] = theMAs(stock.Symbol)
                avg = self.averages[stock.Symbol]
                avg.dv=dv
                avg.price = self.Securities[stock.Symbol.Value].Price
                avg.update(stock.EndTime,self.Securities[stock.Symbol.Value].Price)
                if float(str(avg.Long)) >0 :
                    avg.percent_diff = (float(str(avg.Short)) - float(str(avg.Long))) / float(str(avg.Long))
                    #self.Log("The long ma for {} is {}".format(stock.Symbol.Value,avg.dv))
        values = self.averages.values()
        
        values.sort(key=lambda x: x.dv)
        
        minmum_range = int(round(len(values) * 0.06))
        maximum_range = int(round(len(values) * 0.40))
        if minmum_range < 1:
            minmum_range =0
        if maximum_range < 1:
            maximum_range = 1
        values = values[minmum_range:maximum_range]
        values.sort(key=lambda x: x.percent_diff)
        values = values[:10]
        #self.Log(str(values[0].dv))
        #for stock in values:
            #self.Log("{0} {1}".format(str(stock.symbol),str(stock.percent_diff)))
        #self.Log("--------")
        #for stock in stocks_To_buy:
            #self.Log("here is the stock{}".format(str(stock.SecurityReference.ExchangeId)))
            
        return [ x.symbol for x in values]
        
    def before_trading_start(self):
        day = str(self.UtcTime).split("-")[-1]
        day = day.split(" ")[0]
        #self.Log(str(day))
        MyLeastPrice=0.40
        MyMostPrice=1.40
        for stock in self.Portfolio.Values:
            if stock.Invested:
                if str(stock.Symbol) not in self.Age:
                    self.Age[str(stock.Symbol)] = 0
                else:
                    self.Age[str(stock.Symbol)]+=1
                #self.Log(str(self.Age[stock.Symbol]))
        """for stock.Symbol in self.Age:
            if stock.Symbol not in self.Portfolio.Values:
                self.Age.pop(stock.Symbol)
                
            #self.Log(str(self.Age[stock.Symbol]))
        lowestprice = MyLeastPrice
        if len(self.Portfolio.Transactions) > 0:
            for stock in self.Portfolio.Transactions:
                self.Log(str(stock))
                if stock.Invested:
                #theid = self.Transactions.LastOrderId(str(stock.Symbol))
                #self.Log(str(self.Transactions.GetOrderById(theid)))
                    curr_price = float(self.Securities[stock.Symbol].Price)
                if curr_price < lowestprice:
                    lowestprice = curr_price
        else:
            self.Log(str(self.Portfolio.Transactions))"""
                   
            
            
    def OnSecuritiesChanged(self, changes):
        time = str(self.Time).split(' ')[1]
        hour = time.split(':')[0]
        m = time.split(':')[1]
        self.filtered_stocks = [stock for stock in changes.AddedSecurities]
        #self.Log("amount of stocks in universe {}".format(len(self.filtered_stocks)))

    def rebalance(self):
        
        cash = float(self.Portfolio.Cash)
        self.Tobuy = float(len(self.filtered_stocks))
        if self.Tobuy > 0:
            weight = float(1/self.Tobuy)
        self.days+=1
        BuyFactor=.99
        SellFactor=1.01
        for stock in self.Portfolio.Values:
            if stock.Invested:
                if len(self.Transactions.GetOpenOrders(stock.Symbol)) == 0:
                    curr_price = float(self.Securities[stock.Symbol].Price)
                    cost_basis = float(self.Portfolio[stock.Symbol].AveragePrice)
                    shares_held = self.Portfolio[stock.Symbol].Quantity
                    sell_price = make_div_by_05(cost_basis*SellFactor,buy = False)
                    if (sell_price)== 0 and shares_held > 0:
                        pass
                    if stock.Symbol in self.Age:
                        if(self.Age[str(stock.Symbol)] % 3 == 0) and self.Age[str(stock.Symbol)] >= self.MyFireSaleAge \
                        and self.MyLeastPrice > curr_price or cost_basis >curr_price:
                            sell_price = float(make_div_by_05(.95*curr_price,buy=False))
                            self.StopMarketOrder(stock.Symbol,-shares_held,sell_price)
                    else:
                        self.LimitOrder(stock.Symbol,-shares_held,sell_price)
        if len(self.filtered_stocks) > 0 and cash > 0:
            self.Log(str(cash))
            for stock in self.filtered_stocks:
                shares_held = self.Portfolio[stock.Symbol].Quantity
                oo = len(self.Transactions.GetOpenOrders(stock.Symbol))
                if shares_held == 0 and oo == 0:
                    hist = self.History([stock.Symbol],20,Resolution.Daily)
                    if 'close' in hist.columns:
                        avg_price = float(hist['close'].mean())
                        curr_price = float(self.Securities[stock.Symbol].Price)
                        if curr_price == None or curr_price == 0:
                            pass
                        else:
                            if curr_price > (1.25* avg_price):
                                buy_price = curr_price
                            else:
                                buy_price=float(make_div_by_05(BuyFactor*curr_price, buy=True))
                                #self.Log("The cash{} The weight{} the curr_price{} the buy_price{}".format(cash,weight,curr_price,buy_price))
                            StockShares = float((weight*cash)/buy_price)    
                            self.LimitOrder(stock.Symbol,StockShares,buy_price)
                            self.filtered_stocks.pop(self.filtered_stocks.index(stock))