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
Probabilistic 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
Estimated Strategy Capacity
$0
Lowest Capacity Asset
# region imports

from AlgorithmImports import *
from statistics import stdev
# endregion

class MeasuredTanTermite(QCAlgorithm):

    stopMarketTicket = None
    stopMarketFillTime = datetime.min
    highestprice = 0
    def Initialize(self):
        self.SetStartDate(2022, 6, 1)
        self.SetEndDate(2022, 6, 2)
        self.SetCash(1000000)
        self.rebalanceTime = datetime.min
        self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFilter)
        self.UniverseSettings.Resolution = Resolution.Second #resolution of the securities in the universe, default is minute
        self.AddEquity("SPY")
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 1), self.ExitPositions)
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.Every(timedelta(seconds=5)), self.GoFast)
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.At(9, 30, 20), self.ScanTargets)
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.Midnight, self.ClearFills)
        self.Data = {}
        self.open_prices = {}
        self.Targets = {}
        self.ValueCheck= {}
        self.filled_today = {}
        self.banned_tickers = {}
        self.highest_price_list = {}
        self.pricedata = {}
        self.myOrder = None
        self.highestprice = 0
        self.highesttime = 0
        self.lowprice = 10000000
        self.lowpricetime = 0
        self.buylines = {}
        
    def GoFast (self):

        for symbol in self.Targets.keys():
            symbolData = self.Data[symbol]

            if not symbolData.IsReady: 
               continue

            if not (self.Time.hour >= 9 and self.Time.minute >= 30 and self.Time.second >= 20): #let at least two data points enter for the rolling window of the previous day to finish
                return

            open_orders = self.Transactions.GetOpenOrders(symbol)

            price = self.Securities[symbol].Price

            if price > self.highestprice:
                self.highestprice = price
                self.highesttime = self.Time

            if price < self.lowprice:
                self.lowprice = price
                self.lowpricetime = self.Time

            if not self.Portfolio[symbol].Invested and len(open_orders) == 0 and symbol not in self.filled_today.keys() and symbol.Value not in self.banned_tickers.keys():

                self.filled_today[symbol] = SymbolData(self, symbol)

            if (self.Time.hour == 15 and self.Time.minute == 59 and self.Time.second == 30) and symbol in self.filled_today.keys():
                self.Log(",Symbol," + str(symbol.Value) + ",HighestPrice," + str(self.highestprice) + ",TimeofHigh," + str(self.highesttime) + ",LowestPrice," + str(self.lowprice) + ",TimeofLOw," + str(self.lowpricetime))
               
                self.highestprice = 0
                self.lowprice = 0

    def ExitPositions(self):

        self.Targets = {}
        self.ValueCheck= {}

    def ClearFills(self):

        self.filled_today = {}
        self.banned_tickers = {}

    def ScanTargets(self):

        for symbol in self.Data.keys():
            symbolData = self.Data[symbol]

            if not symbolData.IsReady: 
                continue

            # this loop blocks tickers that have no price action day to day
            k = 0 
            t = 0
            while t <= 4: 
                if symbolData.Bars[t].High == symbolData.Bars[t+1].High and symbolData.Bars[t].Low == symbolData.Bars[t+1].Low or symbolData.Bars[t].Close == symbolData.Bars[t].Open:
                    t += 1
                    k += 1
                else:
                    t += 1

            if symbol not in self.Targets.keys() and symbolData.Bars[0].High > symbolData.Bars[1].Close:
                   
                if symbol.Value in self.ValueCheck.keys(): #fixes a known QC issue where multiple tickers trade the same underlying ticker (happens with buyouts or acquisitions)
                    self.banned_tickers[symbol.Value] = SymbolData(self, symbol)

                else:

                    avevolume = 0 
                    k = 0
                    while k <= 5: 
                        avevolume += symbolData.Bars[k].Volume
                        k += 1
                        
                    avevolume = avevolume/k

                    self.Targets[symbol] = SymbolData(self, symbol)
                    self.ValueCheck[symbol.Value] = SymbolData(self, symbol)
                    self.Log(",Symbol," + str(symbol.Value) + ",Open," + str(self.Securities[symbol].Open) + ",Market," + str(symbol.ID.Market) + ",ave 5 day volume," + str(avevolume))

    def CoarseSelectionFilter(self, coarse): #updates at midnight during backtesting, and around 6-7am in live trading, based on previous day data

        if self.Time <= self.rebalanceTime:
            return self.Universe.Unchanged
        self.rebalanceTime = self.Time + timedelta(35)

        symbols_by_price = [c for c in coarse if c.Price > 1 and c.Price < 25 and c.HasFundamentalData and c.Volume > 50000 and len(c.Symbol.Value) <= 4 and c.Market == 'usa']
        self.filteredByPrice = symbols_by_price[:650]
        return [c.Symbol for c in self.filteredByPrice]

    def FineSelectionFilter(self, fine):
        sortedByMarketCap = sorted(fine, key=lambda c: c.MarketCap)
        symbols_by_marketcap = [c for c in sortedByMarketCap if c.MarketCap > 0]
        self.filteredBymarketcap = symbols_by_marketcap

        for c in symbols_by_marketcap:
	        self.Log(",Symbol," + str(c.Symbol.Value) + ",MarketCap," + str(c.MarketCap)+ ",Price," + str(c.Price) + ",IPO," + str(c.SecurityReference.IPODate)+ ",IsREIT," + str(c.CompanyReference.IsREIT) + ",LastEarningsDate," + str(c.EarningReports.FileDate) + ",CompanyProfile.EnterpriseValue," + str(c.CompanyProfile.EnterpriseValue)+ ",FinancialHealthGrade," + str(c.AssetClassification.FinancialHealthGrade)+ ",ProfitabilityGrade," + str(c.AssetClassification.ProfitabilityGrade)+ ",SizeScore," + str(c.AssetClassification.SizeScore)+ ",ValueScore," + str(c.AssetClassification.ValueScore)+ ",GrowthScore," + str(c.AssetClassification.GrowthScore) + ",Sector," + str(c.AssetClassification.MorningstarSectorCode) + ",Sphere," + str(c.AssetClassification.MorningstarEconomySphereCode) + ",IndustryGroup," + str(c.AssetClassification.MorningstarIndustryGroupCode)) 
        return [c.Symbol for c in self.filteredBymarketcap]

    def OnSecuritiesChanged(self, changes):
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            if symbol not in self.Data:
                self.Data[symbol] = SymbolData(self, symbol)
        
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            if symbol in self.Data:
                symbolData = self.Data.pop(symbol, None)
                self.SubscriptionManager.RemoveConsolidator(symbol, symbolData.consolidator)

class SymbolData:
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        self.Bars = RollingWindow[TradeBar](7)
        self.consolidator = TradeBarConsolidator(timedelta(days=1))
        self.consolidator.DataConsolidated += self.OnDataConsolidated
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
    
    def OnDataConsolidated(self, sender, bar):
        self.Bars.Add(bar)
    
    @property
    def IsReady(self):
        return self.Bars.IsReady