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
-6.087
Tracking Error
0.076
Treynor Ratio
0
Total Fees
$0.00
import pandas as pd
import numpy as np
from datetime import timedelta
from collections import deque



class DynamicTransdimensionalEngine(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)
        self.SetEndDate(2020, 1, 15)
        self.SetCash(100000)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction)
        self.sadfs = {}
    
    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][:10]
        
        for coarse in universe:
            symbol = coarse.Symbol
            
            if symbol not in self.sadfs:
                self.sadfs[symbol] = SelectionData(self, symbol) 
            self.sadfs[symbol].update(self.Time, coarse.Price)
            
            if  self.sadfs[symbol].is_ready() and self.sadfs[symbol].sadf < 1:
                selected.append(symbol)

        return selected[:10]
        
    def OnSecuritiesChanged(self, changes):
        for security in changes.RemovedSecurities:
            self.Liquidate(security.Symbol)
       
        for security in changes.AddedSecurities:
            self.SetHoldings(security.Symbol, 0.10)


class SelectionData(object):
    def __init__(self, algorithm, symbol):
        period = 150
        self.sadf = SadfIndicator('sadf', period)
        
        ####### HISTORY WARM UP
        history = algorithm.History(symbol, 150, Resolution.Daily)
        if history.empty or 'close' not in history:
            return
        closes = history.loc[symbol].close
        for time, close in closes.iteritems():
            self.sadf.Update(time, close)
        ####### HISTORY WARM UP

    def is_ready(self):
        return self.sadf.IsReady
    
    def update(self, time, close):
        self.sadf.Update(time, close)


class SadfIndicator(PythonIndicator):
    def __init__(self, name, period):
        self.Name = name
        self.Time = datetime.min
        self.Value = 0
        # self.IsReady = False
        self.queue = deque(maxlen=period)
        self.queueTime = deque(maxlen=period)
        self.CurrentReturn = 0

    def sadf_last(self, close):
        return 1 ### Added by Derek
        
        sadf_linear = get_sadf(
            close,
            min_length=50,
            add_const=True,
            model='linear',
            # phi=0.5,
            lags=4)
        if len(sadf_linear) > 0:
            last_value = sadf_linear.values[-1].item()
        else:
            last_value = 0
        return last_value
        
    def Update(self, time, close):
        self.queue.appendleft(close)
        self.queueTime.appendleft(time)
        self.Time = time
        if len(self.queue) > 100:
            close_ = pd.Series(self.queue, index=self.queueTime).rename('close').sort_index()
            self.CurrentReturn = close_.pct_change(periods=1)[-1]
            self.Value = self.sadf_last(close=close_)
        count = len(self.queue)
        # self.IsReady = count == self.queue.maxlen
        return count == self.queue.maxlen