Overall Statistics
Total Trades
1292
Average Win
0.01%
Average Loss
0.00%
Compounding Annual Return
-5.222%
Drawdown
0.500%
Expectancy
-0.953
Net Profit
-0.469%
Sharpe Ratio
-3.598
Probabilistic Sharpe Ratio
0.005%
Loss Rate
99%
Win Rate
1%
Profit-Loss Ratio
6.67
Alpha
-0.046
Beta
0.01
Annual Standard Deviation
0.01
Annual Variance
0
Information Ratio
-5.785
Tracking Error
0.154
Treynor Ratio
-3.568
Total Fees
$1292.00
Estimated Strategy Capacity
$1100000.00
Lowest Capacity Asset
XPEV XHD34ASNWZ1H
# region imports
from AlgorithmImports import *
# endregion

class MeasuredTanTermite(QCAlgorithm):

    stopMarketTicket = None
    stopMarketFillTime = datetime.min

    def Initialize(self):
        #self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash)
        self.SetStartDate(2022, 7, 1)
        self.SetEndDate(2022, 8, 1)
        self.SetCash(1000000)
        self.rebalanceTime = datetime.min
        self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFilter)
        self.UniverseSettings.Resolution = Resolution.Minute #resolution of the securities in the universe, default is minute
        self.AddEquity("SPY")
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 10), self.ExitPositions)
        self.Data = {}
        self.AddRiskManagement(TrailingStopRiskManagementModel(0.03))
        self.open_prices = {}
        
    def OnData(self, data):
        for symbol in self.Data.keys():
            symbolData = self.Data[symbol]

            if not symbolData.IsReady: 
                continue

            for symbol, open_price_indicator in self.open_prices.items():
                openingBar = open_price_indicator.Current.Value
                
            open_orders = self.Transactions.GetOpenOrders(symbol) #returns a list of all open orders which include buy and sell order types (limit, marlet, stops, etc.)

            if not self.Portfolio[symbol].Invested and len(open_orders) == 0: #and self.Transactions.GetOpenOrders(symbol) is False: symbolData.Bars[0].Open < symbolData.Bars[0].Close
                i = 0
                while i <= 8: 
                    if symbolData.Bars[i].High >= symbolData.Bars[i+1].High: #checks if daily high is higher than the day before, starts with [0] which was yesterday because each rolling window is 1 day
                        i += 1
                    else:          #exits while loop and saves the value of i 
                        break

                if openingBar > symbolData.Bars[i].High and i >= 1: #checks if todays opening price is higher than yesterdays high
                    orderTicket = self.MarketOrder(symbol, 100)
                    price = self.Securities[symbol].Price
                    self.Debug("Order for symbol " + str(symbol) + " ,Price " + str(price) + " ,Open bar=" + str(openingBar) + " ,i=" + str(i))

            else:       #if portfolio is invested or open orders, return to top of for loop
                continue
            
    def ExitPositions(self):
        self.Liquidate()
       
    def CoarseSelectionFilter(self, coarse):
        if self.Time <= self.rebalanceTime: #checks if it has been 1 day since rebalancing
            return self.Universe.Unchanged #if not do not change the universe
        self.rebalanceTime = self.Time + timedelta(1) #set rebalance time to 1 day

        sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
        symbols_by_price = [c.Symbol for c in sortedByDollarVolume if c.Price > 1 and c.Price < 100 and c.HasFundamentalData and c.Volume > 100000]
        self.filteredByPrice = symbols_by_price[:100]
        return self.filteredByPrice

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

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

            if open_price_indicator:
                open_price_indicator.Reset()    # free memory

class SymbolData:
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        self.Bars = RollingWindow[TradeBar](10) # Rolling window for data bars
        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