Overall Statistics
Total Trades
1109
Average Win
0.09%
Average Loss
-0.08%
Compounding Annual Return
-16.449%
Drawdown
16.800%
Expectancy
-0.406
Net Profit
-16.737%
Sharpe Ratio
-2.048
Probabilistic Sharpe Ratio
0.000%
Loss Rate
72%
Win Rate
28%
Profit-Loss Ratio
1.13
Alpha
0
Beta
0
Annual Standard Deviation
0.056
Annual Variance
0.003
Information Ratio
-2.048
Tracking Error
0.056
Treynor Ratio
0
Total Fees
$1486.59
Estimated Strategy Capacity
$8300000.00
Lowest Capacity Asset
P R735QTJ8XC9X
#region imports
from AlgorithmImports import *
#endregion



import numpy as np
from trend0 import *
class UglyBrownDolphin(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 5, 25)
        self.SetCash(100000) 
        
        self.stopLossPercentLong = .99
        self.takeProfitPercentLong = 1.02
        self.stopLossPercentShort = 1.004
        self.takeProfitPercentShort = .995

        self.UniverseSettings.Resolution = Resolution.Minute
        self.AddUniverse(self.CoarseSelectionFunction)    
        self.SetCash(100000)
        self.SetTimeZone("America/New_York")
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)   
        self.averages = {}
        self.symbolData = {}
        
        
        
        
       
#####################################################################
# 100 stocks 10$ and up, highest dollar volume
    
    def CoarseSelectionFunction(self, universe):
        selected = []
        universe = sorted(universe, key = lambda c: c.DollarVolume, reverse=True)
        universe = [c for c in universe if c.Price > 10][:100]
        
        for coarse in universe:
            selectionSymbol = coarse.Symbol
            
        if selectionSymbol not in self.averages:
            
            history = self.History(selectionSymbol, 30, Resolution.Daily)
            self.averages[selectionSymbol] = SelectionData(history)
            
        self.averages[selectionSymbol].update(self.Time, coarse.AdjustedPrice)
        
        if self.averages[selectionSymbol].fast > self.averages[selectionSymbol].slow:
            if self.averages[selectionSymbol].is_ready():
                selected.append(selectionSymbol)
                
        return selected[:10]
    
    
    
#####################################################################
# Create SymbolData object for each stock added to universe
    
    def OnSecuritiesChanged(self, changes):
        
        for ticker in changes.AddedSecurities:
            symbol = ticker.Symbol
            if symbol not in self.symbolData:
                indicatorHistory = self.History(symbol, 90, Resolution.Minute)
                self.symbolData[symbol] = SymbolData(self, symbol, indicatorHistory)
 
                
#####################################################################
        
        
    def OnData(self, slice):
        
        
        
        for symbol, data in self.symbolData.items():
            price = self.Securities[symbol].Price
            
            if not data.indicator.IsReady:
                return
                  
            if data.indicator.Current.Value > 1 and data.openTrade:
                self.SetHoldings(symbol, 0.1)
                data.stopmarketorderticket = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, price * .995)
                data.limitorderticket = self.LimitOrder(symbol, -self.Portfolio[symbol].Quantity, price * 1.01)
                data.openTrade = False
        
        
            #ignore
                '''self.SetHoldings(symbol, -1.0)
                self.stopmarketorderticketshort = self.StopMarketOrder(symbol, -self.Portfolio[self.symbol].Quantity, price * 1.005)
                self.limitorderticketshort = self.LimitOrder(symbol, -self.Portfolio[self.symbol].Quantity, price * .99)'''
    
#####################################################################    
        
    def OnOrderEvent(self, orderEvent):
        
        data = self.symbolData.get(orderEvent.Symbol, None)
        if not data or orderEvent.Status != OrderStatus.Filled:
            return
        
        for symbol, data in self.symbolData.items():
            price = self.Securities[symbol].Price
            
            if orderEvent.Status != OrderStatus.Filled:
                return
        
        if data.stopmarketorderticket != None and data.stopmarketorderticket.OrderId == orderEvent.OrderId:
            data.limitorderticket.Cancel()
            data.openTrade = True
        
        if data.limitorderticket != None and data.limitorderticket.OrderId == orderEvent.OrderId:
            data.stopmarketorderticket.Cancel()
            data.openTrade = True
            
        if data.stopmarketorderticketshort != None and data.stopmarketorderticketshort == orderEvent.OrderId:
            data.limitorderticketshort.Cancel()
            data.openTrade = True 
                
        if data.limitorderticketshort != None and data.limitorderticketshort == orderEvent.OrderId:
            data.stopmarketorderticketshort.Cancel()
            data.openTrade = True

#####################################################################        
# instantiate and initialize symbols, feed with history request 
            
            
class SymbolData:
    def __init__(self, algorithm, symbol, indicatorHistory):
        #algorithm.Securities[symbol].SetLeverage(2.0)
        
        
        self.stopmarketorderticket = None
        self.limitorderticket = None
        self.stopmarketorderticketshort = None
        self.limitorderticketshort = None
        self.openTrade = True
        
        
        
        self.indicator = MomentumPercent(90)
        if indicatorHistory.empty:
            return
      
    
        for bar in indicatorHistory.itertuples():
            self.indicator.Update(bar.Index[1], bar.close)
                
        def is__ready(self):
            return self.indicator.IsReady
            
        def update_(self, time, price):
            self.indicator.Update(time, price)
        
        self.RegisterIndicator = algorithm.RegisterIndicator(symbol, self.indicator, Resolution.Minute) # Is this how I should update indictor with fresh data, or DIY an update method within OnData?


        
#####################################################################        
# Only add stocks to universe that are trending up the past 10 days
class SelectionData:
    
    def __init__(self, history):
        self.slow = ExponentialMovingAverage(30)
        self.fast = ExponentialMovingAverage(10)
        
        for bar in history.itertuples():
            self.slow.Update(bar.Index[1], bar.close)
            self.fast.Update(bar.Index[1], bar.close)
    def is_ready(self):
        return self.slow.IsReady and self.fast.IsReady
        
    def update(self, time, price):
        self.fast.Update(time, price)
        self.slow.Update(time, price)
            
            
            
            
            
            
        
#region imports
from AlgorithmImports import *
#endregion
# 11613  trend0 custom python indicator by Derek Melchin
# inspired by Warren Harding https://www.quantconnect.com/forum/discussion/11613/algo-trend0/p1

class Trend0(PythonIndicator):
    def __init__(self, name, period, power):
        self.Name = name
        self.period = period
        self.power = power
        self.Time = datetime.min
        self.Value = 0
        self.prices = np.array([])
        

    def Update(self, time, close):
        self.prices = np.append(self.prices, close)[-self.period:]

        if len(self.prices) != self.period:
            self.Value = 0
            return False
        
        self.Value = self.calc_trend()
        return True
        
    
    def calc_trend(self):
        changes = np.array([])
        for i in range(len(self.prices) - 1):
            _return = (self.prices[i + 1] - self.prices[i]) / self.prices[i]
            changes = np.append(changes, _return)
        return self.power_weighted_moving_average(changes)
        
    
    def power_weighted_moving_average(self, changes):
        return self.weighted_average(changes, self.power_weights(len(changes)))
        
        
    def power_weights(self, length):
        weights = np.array([])
        for i in range(length):
            w = i + 1
            weights = np.append(weights, w**self.power)
        return weights
        
        
    def weighted_average(self, changes, weights):
        products = []
        for i in range(len(changes)):
            products.append(changes[i] * weights[i])
        return sum(products) / sum(weights)