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
-2.364
Tracking Error
0.121
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
class SymbolData:
    
    def __init__(self, algorithm, symbol):
        
        self.algorithm = algorithm
        self.symbol = symbol
        
        # Daily consolidator definition and subscription to data
        self.daily_consolidator = TradeBarConsolidator(timedelta(days=1))
        self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.daily_consolidator)
        self.daily_consolidator.DataConsolidated += self.OnDailyBar
        
        # signal resolution consolidator definition and subscription to data
        self.consolidator = TradeBarConsolidator(timedelta(minutes=30))
        self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.consolidator)
        self.consolidator.DataConsolidated += self.OnBar
        
        # self.algorithm.ResolveConsolidator
        # minute consolidator definition and subscription to data
        self.minute_consolidator = TradeBarConsolidator(timedelta(minutes=1))
        self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.minute_consolidator)
        self.minute_consolidator.DataConsolidated += self.OnMinuteBar
        
        # Volume daily SMA
        self.vol_sma = SimpleMovingAverage(20)
        
        # 30 min resolution - 10 period SMA for price
        self.sma = SimpleMovingAverage(10)
        self.algorithm.RegisterIndicator(self.symbol, self.sma, self.consolidator)
        
        self.minute_bars = RollingWindow[TradeBar](30)
        self.bars = RollingWindow[TradeBar](3)
        
        
    def OnDailyBar(self, sender, bar):
        # Updates volume sma with latest daily bar data
        self.vol_sma.Update(bar.EndTime, bar.Volume)
       
       
    def OnBar(self, sender, bar):
        
        # Saves signal resolution bars
        self.bars.Add(bar)
    
    def OnMinuteBar(self, sender, bar):
        
        # Saves minute bars
        self.minute_bars.Add(bar)
        
    @property
    def IsReady(self):
        
        return self.vol_sma.IsReady and self.sma.IsReady and self.minute_bars.IsReady and \
            self.bars.IsReady
        
        
    def KillConsolidators(self):
        
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.consolidator)
        
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.minute_consolidator)
        
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.daily_consolidator)
        
    @property
    def RecentDollarVolume(self):
        
        dollar_volume = 0
        
        for bar in list(self.minute_bars):
            
            dollar_volume += bar.Volume * bar.Close    
        
        return dollar_volume
        
    @property
    def CandlePatternSignal(self):
        
        # Close > Open
        # Wick < .5*Body
        # Body > 1.02*Open
        
        most_recent_bar = self.bars[0]
        
        close = most_recent_bar.Close
        open = most_recent_bar.Open
        high = most_recent_bar.High
        wick = high - close
        body = close - open
        
        return close > open and wick < 0.5 * body and body > 1.02 * open
    
    @property
    def UnusualVolume(self):
        
        vol_sma = self.vol_sma.Current.Value
        recent_volume = self.bars[0].Volume
        
        return recent_volume > 3 * vol_sma
    
    
    def UnusualVolumeSignal(self):
        
        return self.RecentDollarVolume > 500000 and self.CandlePatternSignal and self.UnusualVolume
        
        
        
        
    
class TradeManagement:
    
    def __init__(self, algorithm, symbol):
        
        self.algorithm = algorithm
        self.symbol = symbol
        
        self.entry_limit_ticket = None
        self.stop_loss = None
        self.take_profit = None
        
        
    def LimitOrder(self, quantity, limit_price):
        
        # self.entry_limit_ticket = self.algorithm.LimitOrder(...)
        # self.stop_loss = ..
        # ....
        
        pass
    
    
    def CheckAndUpdate(self):
        
        current_market_price = self.algorithm.Securities[self.symbol].Price
        
        if not self.ActivePosition:
            return 
        
        # stop loss
        # take profit
        
        # self.algorithm.Liquidate
        
    
    def CancelEntryOrder(self):
        
        if self.entry_limit_ticket is not None:
            self.entry_limit_ticket.Cancel()
        
            self.stop_loss = None
            self.take_profit = None
        
        
    @property
    def ActivePosition(self):
        
        return self.algorithm.Portfolio[self.symbol].Invested
    
    
    def GetPositionSize(self):
        
        portfolio_value = self.algorithm.Portfolio.TotalPortfolioValue
        
        #...
from SymbolData import *

class LogicalRedOrangeGoshawk(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 12, 9)
        self.SetCash(100000) 
        
        self.benchmark = "SPY"
        self.AddEquity("SPY", Resolution.Minute)
        
        self.AddUniverse(self.SelectCoarse)
        self.UniverseSettings.Resolution = Resolution.Minute
        
        self.symbols = {}
        
        self.Schedule.On(self.DateRules.EveryDay(self.benchmark), self.TimeRules.AfterMarketOpen(self.benchmark, 30), self.Rebalance)
    
    def Rebalance(self):
        
        self.Debug(f"Universe Size... {len(self.symbols)}")
        
        for symbol, symbol_data in self.symbols.items():
            
            if not symbol_data.IsReady:
                continue
            
            if symbol_data.UnusualVolumeSignal:
                
                self.Debug(f"{self.Time} -- {symbol} has a signal!")
        
    def SelectCoarse(self, coarse):
        
        filtered_by_price = [c for c in coarse if c.AdjustedPrice >= 2 and c.AdjustedPrice <= 10]
        
        return [c.Symbol for c in filtered_by_price]
        
    def OnSecuritiesChanged(self, changes):
        
        for security in changes.AddedSecurities:
            
            symbol = security.Symbol
            
            if symbol not in self.symbols and symbol.Value != self.benchmark:
                self.symbols[symbol] = SymbolData(self, symbol)
                
        
        for security in changes.RemovedSecurities:
            
            symbol = security.Symbol
            
            if symbol in self.symbols:
                
                symbol_data = self.symbols.pop(symbol, None)
                
                symbol_data.KillConsolidators()