Overall Statistics
Total Trades
2
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
$56000000.00
Lowest Capacity Asset
NVDA RHM8UTD8DT2D
Portfolio Turnover
3.45%
#region imports
from AlgorithmImports import *
#endregion
import statistics
from sklearn.linear_model import LinearRegression
from scipy.stats import norm
import time as tm
import statsmodels.formula.api as smf
import talib
import pandas
import scipy.stats as stats

def green_red_prop_any(self, opened, high, low, close):
    green = 0
    red = 0
    
    #doji
    if opened == close:
        return .50

    #green
    elif close > opened:
        green += abs(close - opened)
        
        #wicks
        green += abs(high - close) + abs(low - opened)
        red += abs(high - close) + abs(low - opened)
            
    #red
    elif close < opened: 
        red += abs(close - opened)
            
        #wicks
        green += abs(high - opened) + abs(low - close)
        red += abs(high - opened) + abs(low - close)
    
    if (green + red) != 0:
        return green / (green + red)
    else:
        return "NA"
        

#is there any EMA that has never decreased and is >= midpnt
#long
#see physical notes from 7/3/21
def find_EMA_neverDecr_gteMid(self, s, closes, midpnt):
    
    l, r = 0, 2048
    while l <= r:
        mid = (l + r) // 2
        currEMA, EMAs = calcEMA(self, s, closes, mid)
        
        #ever decreased?
        #i.e., is sorted? could maybe be faster
        currEMAeverDecr = 0
        for i in range(1, len(EMAs)):
            if EMAs[i] < EMAs[i-1]:
                currEMAeverDecr = 1
                break
        
        #gte midpnt
        currEMA_gte_midpnt = 0
        if currEMA >= midpnt:
            currEMA_gte_midpnt = 1
        
        #make longer
        if currEMAeverDecr and currEMA_gte_midpnt:
            l = mid + 1
        elif currEMAeverDecr and (not currEMA_gte_midpnt):
            return -1
        #return left
        elif (not currEMAeverDecr) and currEMA_gte_midpnt:
            return mid
        #make shorter
        elif (not currEMAeverDecr) and (not currEMA_gte_midpnt):
            r = mid - 1
        
    return -1


def find_EMA_lte_midpnt(self, s, closes, midpnt, l):
    r = 2048
    while l <= r:
        mid = (l + r) // 2
        currEMA, EMAs = calcEMA(self, s, closes, mid)

        if currEMA <= midpnt:
            return mid
        else:
            r = mid - 1
    return -1

    
#get the EMA that:
#   always increasing
#       it will ever decrease if price < EMA
#   start of EMA is of shortest time backward
#   of longest period
#   closest to midpnt of ignition move
def EMA_midpoint(self, s, closes, midpnt, which = "NA"):
    
    #if which == "CD":
    #    self.Debug("which CD")
    
    low = closes[0]
    
    low_start = 0
    high_start = len(closes) - 1
    mid_start = 0
    closes_start = []
    
    start_final = "NA"
    best_period_final = "NA"
    
    while low_start <= high_start:
        
        mid_start = (high_start + low_start) // 2
        closes_start = closes[mid_start:]
        closes_start[0] = low
        
        #if midpoint EMA exist on this iteration of while loop
        found_EMA = 0
        
        #does midpoint EMA exist at 
        left = find_EMA_neverDecr_gteMid(self, s, closes_start, midpnt)
        if left != -1:
            right = find_EMA_lte_midpnt(self, s, closes_start, midpnt, left)
            if right != -1:

                best_period = "NA"
                closest_dist = 2000000000
                count = 0
                all_bounds = set()
                #binary search within these bounds
                while left <= right:
                    
                    #the current middle is the period
                    middle = (left + right) // 2
            
                    currEMA, EMAs = calcEMA(self, s, closes_start, middle)
            
                    #closer to midpoint, and hasn't decreased yet
                    if abs(currEMA - midpnt) < closest_dist: 
                        best_period = middle
                        closest_dist = abs(currEMA - midpnt)
            
                    #make longer
                    if currEMA > midpnt:
                        left = middle + 1
                    #make shorter
                    elif currEMA < midpnt:
                        right = middle + 1
                    #return current start from closes, and the best EMA period
                    else:
                        found_EMA = 1
                        start_final = mid_start 
                        best_period_final = best_period
                        break
                    
                    ###repeat bounds
                    #not sure why this makes infinite loop otherwise (at least for TWTR 9:33 6/24 RH, start should be 0 period 6)
                    curr_bounds = str(middle) + " " + str(left) + " " + str(right)
                    if curr_bounds in all_bounds:
                        for val in middle, left, right:
                            currEMA, EMAs = calcEMA(self, s, closes, val)
            
                            #closer to midpoint, and hasn't decreased yet
                            if abs(currEMA - midpnt) <= closest_dist: 
                                best_period = val
                                closest_dist = abs(currEMA - midpnt)
                        
                        found_EMA = 1
                        start_final = mid_start 
                        best_period_final = best_period
                        break
                    ###
                    all_bounds.add(curr_bounds)
                
                #if which == "CD":
                #    self.Debug("binary search iter, mid start and whether found EMA or not")
                #    self.Debug(mid_start)
                #    self.Debug(found_EMA)
                
                found_EMA = 1
                start_final = mid_start 
                best_period_final = best_period
                #break
        

        
        ###go to next iter
        #found, so try longer
        if found_EMA == 1:
            high_start = mid_start - 1
        #not found, try shorter
        else:
            low_start = mid_start + 1
    
    
    #did log2(len(closes)) tries, return 
    return start_final, best_period_final


#is there any EMA that has never increasined and is <= midpnt
def find_EMA_neverIncr_lteMid(self, s, closes, midpnt):
    
    l, r = 0, 2048
    while l <= r:
        mid = (l + r) // 2
        currEMA, EMAs = calcEMA(self, s, closes, mid)
        
        #ever decreased?
        #i.e., is sorted? could maybe be faster
        currEMAeverIncr = 0
        for i in range(1, len(EMAs)):
            if EMAs[i] > EMAs[i-1]:
                currEMAeverIncr = 1
                break
        
        #gte midpnt
        currEMA_lte_midpnt = 0
        if currEMA <= midpnt:
            currEMA_lte_midpnt = 1
        
        #make longer
        if currEMAeverIncr and currEMA_lte_midpnt:
            l = mid + 1
        elif currEMAeverIncr and (not currEMA_lte_midpnt):
            return -1
        #return left
        elif (not currEMAeverIncr) and currEMA_lte_midpnt:
            return mid
        #make shorter
        elif (not currEMAeverIncr) and (not currEMA_lte_midpnt):
            r = mid - 1
        
    return -1


def find_EMA_gte_midpnt(self, s, closes, midpnt, l):
    r = 2048
    while l <= r:
        mid = (l + r) // 2
        currEMA, EMAs = calcEMA(self, s, closes, mid)

        if currEMA >= midpnt:
            return mid
        else:
            r = mid - 1
    return -1


def EMA_midpoint_short(self, s, closes, midpnt):
    
    low = closes[0]
    
    for start in range(0, len(closes)):
        left = find_EMA_neverIncr_lteMid(self, s, closes, midpnt)
        if left != -1:
            right = find_EMA_gte_midpnt(self, s, closes, midpnt, left)
            if right != -1:

                best_period = "NA"
                closest_dist = 2000000000
                count = 0
                all_bounds = set()
                #binary search within these bounds
                while left <= right:
                    
                    #the current middle is the period
                    middle = (left + right) // 2
            
                    currEMA, EMAs = calcEMA(self, s, closes, middle)
            
                    #closer to midpoint, and hasn't decreased yet
                    if abs(currEMA - midpnt) < closest_dist: 
                        best_period = middle
                        closest_dist = abs(currEMA - midpnt)
            
                    #make longer
                    if currEMA < midpnt:
                        left = middle + 1
                    #make shorter
                    elif currEMA > midpnt:
                        right = middle + 1
                #return current start from closes, and the best EMA period
                    else:
                        return start, best_period
                    
                    ###repeat bounds
                    #not sure why this makes infinite loop otherwise (at least for TWTR 9:33 6/24 RH, start should be 0 period 6)
                    curr_bounds = str(middle) + " " + str(left) + " " + str(right)
                    if curr_bounds in all_bounds:
                        for val in middle, left, right:
                            currEMA, EMAs = calcEMA(self, s, closes, val)
            
                            #closer to midpoint, and hasn't decreased yet
                            if abs(currEMA - midpnt) <= closest_dist: 
                                best_period = val
                                closest_dist = abs(currEMA - midpnt)
                        return start, best_period
                    ###
                    all_bounds.add(curr_bounds)    
                return start, best_period
                
        
        #couldn't find EMA -- go to next iter
        closes.pop(0)
        try:
            closes[0] = low
        except:
            self.EMAerrorShort.add(s)
            break
        
    return "NA", "NA"


def grp_second(self, s, df):

    #volume sums
    tot_vol = 0
    
    green_vol_day = 0
    red_vol_day = 0

    green_vol_tot = 0
    red_vol_tot = 0
    
    green_vol_ignition = 0
    red_vol_ignition = 0

    green_vol_consol = 0
    red_vol_consol = 0
    
    green_vol_cd = 0
    red_vol_cd = 0

    green_vol_second_cd = 0
    red_vol_second_cd = 0
    
    w_green_vol_cd = 0
    w_red_vol_cd = 0

    w_green_vol_second_cd = 0
    w_red_vol_second_cd = 0

    w_green_vol_consol = 0
    w_red_vol_consol = 0

    #start of move, start of consol, start of cd leg
    move_start = 0
    consol_count = 0
    cd_count = 0
    second_half_consol_count = 0

    #second half of consol
    n_rows = df.shape[0]
    consol_length = "NA"


    #n_consol = 0
    row_count = 0
    start_of_second_consol = "NA"

    #GRP weights
    #weight = 1.0 - (proportion_remaining / 2.0)
    #proportion_remaining =  amount_left / total
    #proportion_remaining =  n_rows -  / (n_rows - start)

    #=1 so they don't error out with divide by 0
    CD_length = 1
    second_half_consol_length = 1
    consol_length = 1

    for row in df.itertuples():
        row_count += 1

        low = float(row.low)
        high = float(row.high)
        
        curr_range = high - low
        
        #did moves/legs start
        if low <= self.moves[s]["RH"]["low"]:
            move_start = 1
        
        if move_start == 1 and high >= self.moves[s]["RH"]["high"] and consol_count == 0:
            consol_count = 1
            consol_length = n_rows - row_count

            start_second_CD = row_count + ((n_rows - row_count)/2) #halfway through consolidation

        if move_start == 1 and consol_count >= 1 and low <= self.moves[s]["RH"]["consol_low"]:
            cd_count = 1
            CD_length = n_rows - row_count
        
        if cd_count >= 1 and row_count >= start_second_CD and second_half_consol_count == 0:
            second_half_consol_count = 1
            second_half_consol_length = n_rows - row_count

            #can remove this, just to print
            start_of_second_consol = row

        ###assign grp
        opened = float(row.open)
        close = float(row.close)
        volume = float(row.volume)
        low = float(row.low)

        green = .50
        red = .50
            
        
        #green proportion
        if high - low != 0:

            ###green proportion as total distance moved
            body = abs(opened - close)
            wick1 = 0
            wick2 = 0

            if close > opened: #green
                wick1 = high - close
                wick2 = opened - low
            else: #red
                wick1 = high - opened
                wick2 = close - low

            distance = body + (wick1*2.0) + (wick2*2.0) 

            try:
                if close > opened:
                    green = (body + wick1 + wick2) / distance
                    red = 1.0 - green
                else:
                    red = (body + wick1 + wick2) / distance
                    green = 1.0 - red
            except:
                error=1

        #assign volume
        green_vol_day += green * volume 
        red_vol_day += red * volume
        tot_vol += volume

        if move_start == 1: #all of move
            green_vol_tot += green * volume
            red_vol_tot += red * volume
            if consol_count == 0: #ignition only
                green_vol_ignition += green * volume
                red_vol_ignition += red*volume

        if consol_count > 0: #all of consolidation
            green_vol_consol += green * volume
            red_vol_consol += red * volume
            consol_count += 1

            #add weighted
            if consol_length == 0: #error for some reason very infrequently
                consol_length = 1
            weight = (1.0 - ((consol_length - consol_count) / consol_length) / 2.0) 

            w_green_vol_consol += green * volume * weight
            w_red_vol_consol += red * volume * weight

        if cd_count > 0:
            green_vol_cd += green * volume
            red_vol_cd += red * volume
            cd_count += 1
        
            #add weighted
            try:
                weight = 1.0 - (((CD_length - cd_count) / CD_length) / 2.0)
            except:
                self.CDerror.add(s.Value)
                weight = 0

            w_green_vol_cd += green * volume * weight
            w_red_vol_cd += red * volume * weight

        if second_half_consol_count > 0:
            green_vol_second_cd += green * volume
            red_vol_second_cd += red * volume
            second_half_consol_count += 1

            #add weighted
            weight = 1.0 - (((second_half_consol_length - second_half_consol_count) / second_half_consol_length) / 2.0)

            w_green_vol_second_cd += green * volume * weight
            w_red_vol_second_cd += red * volume * weight

    return green_vol_day, red_vol_day, green_vol_tot, red_vol_tot, green_vol_consol, red_vol_consol, green_vol_cd, red_vol_cd, green_vol_second_cd, red_vol_second_cd, green_vol_ignition, red_vol_ignition, start_of_second_consol, w_green_vol_cd, w_red_vol_cd, w_green_vol_second_cd, w_red_vol_second_cd, w_green_vol_consol, w_red_vol_consol

#this is mostly from chatGPT
def getDailyVolumes2(self, s):
    df = self.History(self.Symbol(s), timedelta(365), Resolution.Minute)
    df = df.drop(columns=['askclose', 'askhigh', 'asklow', 'askopen', 'asksize', 'bidclose', 'bidhigh', 'bidlow', 'bidopen', 'bidsize'])

    dates = pd.Series(df.index.get_level_values(1)).dt.date.astype(str).to_numpy()
    minutes = (df.index.get_level_values(1).hour * 60 + df.index.get_level_values(1).minute).to_numpy()
    
    pm = minutes <= 570 #all the time before 9:30, not including 9:30 i.e., including the 9:30:00 is before premarket
    rh = ~pm & (minutes <= 574)

    volumes = df['volume'].to_numpy()
    rh_vol = np.zeros_like(volumes)
    pm_vol = np.zeros_like(volumes)

    rh_vol[rh] = volumes[rh]
    pm_vol[pm] = volumes[pm]

    daily_volumes = pd.DataFrame({'Date': dates, 'RH_vol': rh_vol, 'PM_vol': pm_vol})
    daily_volumes = daily_volumes.groupby('Date').agg({'RH_vol': 'sum', 'PM_vol': 'sum'}).reset_index()

    last_row = daily_volumes.iloc[-1]  # Store the last row before removing it
    daily_volumes = daily_volumes.tail(-1) #remove today's row

    return daily_volumes, last_row


#predict EOD range based on current volume, range, distance
#split by PM and regular hours
def getDailyVolumes(self, s):
        
    df = self.History(self.Symbol(s), timedelta(365), Resolution.Minute)
    df = df.drop(columns=['askclose', 'askhigh', 'asklow', 'askopen', 'asksize', 'bidclose','bidhigh', 'bidlow', 'bidopen', 'bidsize'])

    #self.Debug(s)
    #self.Debug(df.shape)
    #self.Debug(self.Time)

    vals = {}
    for row in df.itertuples():
        date, clock = str(row.Index[1]).split()
        date = str(date)
            
        vol = row.volume
            
        if date not in vals:
            vals[date] = {}
            vals[date]["PM_vol"] = 0
            vals[date]["RH_vol"] = 0

        pm = self.isPM(clock)

        #update premarket values
        if pm == 1:
            vals[date]["PM_vol"] += vol
                
        #update regular hours
        elif pm == 0 and self.timeInMin(clock) <= 573 : #change to first 3 minutes
            vals[date]["RH_vol"] += vol
    

    #print out to file           
    rows_list = []
    for date in sorted(vals): #these are correctly sorted by date
        row = {}

        row["Date"] = date
        row["RH_vol"] = vals[date]["RH_vol"]                    
        row["PM_vol"] = vals[date]["PM_vol"]
                
        rows_list.append(row)

    tmp = pd.DataFrame(rows_list)

    return tmp


#get mean volumes
def getMeanVols(self, vols):
    past20 = vols.tail(21)
    past20 = past20[:-1]
    past20['Sum_vol'] = past20['RH_vol'] + past20['PM_vol']
    mean_RH = past20["RH_vol"].mean()
    mean_PM = past20["PM_vol"].mean()
    mean_sum = past20["Sum_vol"].mean()

    return [float(mean_RH), float(mean_PM), float(mean_sum)]

#predict interval for today's EOD range based on past 14 days, using daily candles from past year
def modelEODRange(self, s):
    
    start = tm.time()
    
    df = self.History(self.Symbol(s), timedelta(365), Resolution.Daily)
    
    #self.Debug(df.tail())

    #put OHLC, range, ATR, in lists
    vals = {}
    vals["date"] = []
    vals["open"] = []
    vals["high"] = []
    vals["low"] = []
    vals["close"] = []
    vals["range"] = []
    vals["atr"] = []
    
    count = 0
    date_minus1 = ""
    for row in df.itertuples():
        if count > 0:
                        
            opened = row.open
            high = row.high
            low = row.low
            close = row.close

            vals["date"].append(date_minus1)
            vals["open"].append(opened)
            vals["high"].append(high)
            vals["low"].append(low)
            vals["close"].append(close)
            vals["range"].append(high - low)

        if count >1:
            vals["atr"].append(max(high-low, abs(high - vals["close"][-2]), abs(low - vals["close"][-2])))
        else:
            vals["atr"].append("NA")

        date_minus1 = str(row.Index[1])
        count += 1
    
    
    #less than 50 daily days
    if len(vals["date"]) < 50:
        return "NA", "NA", "NA"
    
    
    #minutely prediction
    vols, today_vols = getDailyVolumes2(self, s)
    #self.Debug(vols)
    #return "NA", "NA", "NA"
    mean_vols = getMeanVols(self, vols)

    #calc avgs for output to df:
        #abs_gap, sqrt(abs_gap)
        #atr, average range, inside day
            #yday, 2 day, 5 day, 14 day
    rows_list = []
    today_row = {}
    for i in range(16, len(vals["open"])):
        
        row = {}
        date = vals["date"][i].replace(" 00:00:00", "")
        row["Date"] = date
        row["Range_today"] = vals["range"][i]
        
        #gap
        row["abs_Gap"] = abs(vals["open"][i] - vals["close"][i-1])
        row["sqrt_abs_Gap"] = math.sqrt(abs(vals["open"][i] - vals["close"][i-1]))
        
        #average range and ATR
        for j in [1, 2, 5, 14]:
            row["range_" + str(j) + "day"] = statistics.mean(vals["range"][i-j:i])
            row["atr_" + str(j) + "day"] = statistics.mean(vals["atr"][i-j:i])
        
        #inside or not
        if vals["open"][i] > vals["high"][i-1] or vals["open"][i] < vals["low"][i-1]:
            row["outside_open"] = 1
        else:
            row["outside_open"] = 0
        
        if vals["high"][i] > vals["high"][i-1] or vals["low"][i] < vals["low"][i-1]:
            row["outside_ever"] = 1
        else:
            row["outside_ever"] = 0
        
        #if yesterday closed outside of 2 days ago range
        if vals["close"][i-1] > vals["high"][i-2] or vals["close"][i-1] < vals["low"][i-2]:
            row["outside_close"] = 1
        else:
            row["outside_close"] = 0
        
        
        ###today's values that can be filled in before open
        for j in [1, 2, 5, 14]:
            today_row["range_" + str(j) + "day"] = statistics.mean(vals["range"][-j:])
            today_row["atr_" + str(j) + "day"] = statistics.mean(vals["atr"][-j:])
            
        if vals["close"][-1] > vals["high"][-2] or vals["close"][-1] < vals["low"][-2]:
            today_row["outside_close"] = 1
        else:
            today_row["outside_close"] = 0

        #df conversion
        rows_list.append(row)

    tmp = pd.DataFrame(rows_list)
    merged = pd.merge(vols, tmp, on="Date")

    '''
    #output lbl
    # Print the headers
    self.Debug('\t'.join(merged.columns))

    # Iterate through each row
    count = 0
    total_rows = merged.shape[0]  # Get total number of rows
    for index, row in merged.iterrows():
        count += 1
        if count <= 20 or count == total_rows:  # Print the first 19 rows and the final row
            self.Debug('\t'.join(row.astype(str)))
    '''

    X = merged[["abs_Gap", "sqrt_abs_Gap", "range_1day", "range_2day", "range_5day", "range_14day", "outside_open", "outside_ever", "RH_vol", "PM_vol"]]
    y = merged["Range_today"]
    
    #currPred = runModel.iloc[-1:].drop(columns=["Range_today"])
    #rmLast = runModel.iloc[:-1] 

    #quantile regression
    #models = []
    #for tau in taus:
    #    model = smf.quantreg('Range_today ~ abs_Gap + sqrt_abs_Gap + range_1day + range_2day + range_5day + range_14day + outside_open + outside_ever + RH_vol + PM_vol', merged).fit(q=tau)
    #    models.append(model)

    #linear regression
    model = LinearRegression().fit(X, y)
    predictions = model.predict(X)
    
    #all you need is SD of residuals
    sd = get_residuals_sd(self, y, predictions)

    #model rsq
    #self.Debug(model.summary())
    rsq = model.score(X, y)
    
    #self.Debug(rsq)
    #self.Debug(sd)
    today_row["RH_vol"] = today_vols['RH_vol']
    today_row["PM_vol"] = today_vols['PM_vol']
    
    #return the model, its rsq, todays vals that dont depend on today, and ydays ohlc
    return model, today_row, [opened, high, low, close], sd, mean_vols, rsq


def predictEODRange(self, model, tr, today_ohl, yday_ohlc):
    
    #tr stands for today_row
    yday_o, yday_h, yday_l, yday_c = yday_ohlc
    today_o, today_h, today_l = today_ohl
    
    ###make the rest of features that need values from today
    #gap
    tr["abs_Gap"] = abs(today_o - yday_c)
    tr["sqrt_abs_Gap"] = math.sqrt(abs(today_o - yday_c))
    
    #inside or not
    if today_o > yday_h or today_o < yday_l:
        tr["outside_open"] = 1
    else:
        tr["outside_open"] = 0
        
    if today_h > yday_h or today_l < yday_l:
        tr["outside_ever"] = 1
    else:
        tr["outside_ever"] = 0
    
    #volume
    #tr["RH_vol"] = threeMinVol
    #tr["PM_vol"] = pmvol

    #self.Debug(threeMinVol)
    #self.Debug(pmvol)

    ###get prediction
    #topred_vals = [[tr["abs_Gap"], tr["sqrt_abs_Gap"], tr["range_1day"], tr["atr_1day"], tr["range_2day"], tr["atr_2day"], tr["range_5day"], tr["atr_5day"], tr["range_14day"], tr["atr_14day"], tr["outside_open"], tr["outside_ever"], tr["outside_close"]]]
    #topred = pd.DataFrame(topred_vals, columns = ["abs_Gap", "sqrt_abs_Gap", "range_1day", "atr_1day", "range_2day", "atr_2day", "range_5day", "atr_5day", "range_14day", "atr_14day", "outside_open", "outside_ever", "outside_close"])
    topred_vals = [[tr["abs_Gap"], tr["sqrt_abs_Gap"], tr["range_1day"], tr["range_2day"], tr["range_5day"], tr["range_14day"], tr["outside_open"], tr["outside_ever"], tr["RH_vol"], tr["PM_vol"]]]
    topred = pd.DataFrame(topred_vals, columns = ["abs_Gap", "sqrt_abs_Gap", "range_1day", "range_2day", "range_5day", "range_14day", "outside_open", "outside_ever", "RH_vol", "PM_vol"])
    pred = model.predict(topred)
    
    return pred


def get_residuals_sd(self, y_test, test_predictions):
    #get standard deviation of y_test
    sum_errs = np.sum((y_test - test_predictions)**2)
    stdev = np.sqrt(1 / (len(y_test) - 2) * sum_errs)
    
    return stdev


#https://towardsdatascience.com/prediction-intervals-in-linear-regression-2ea14d419981
def get_prediction_interval(self, prediction, stdev, bound):
    #get interval from standard deviation
    ppf_lookup = 1 - bound
    z_score = norm.ppf(ppf_lookup)
    interval = z_score * stdev
    
    #generate prediction interval lower bound
    return (prediction-interval)


#https://towardsdatascience.com/prediction-intervals-in-linear-regression-2ea14d419981
def get_prediction_interval(self, prediction, y_test, test_predictions, bound):
    #get standard deviation of y_test
    sum_errs = np.sum((y_test - test_predictions)**2)
    stdev = np.sqrt(1 / (len(y_test) - 2) * sum_errs)
    
    #get interval from standard deviation
    ppf_lookup = 1 - bound
    z_score = norm.ppf(ppf_lookup)
    interval = z_score * stdev
    
    #generate prediction interval lower bound
    return (prediction-interval)


#EMA for consolidation, midpoint of high to low
def calc_shortEMA(self, s, all_prices):
    
    #consolidation prices
    consol_short_prices = []
    hit_high = 0
    for p in all_prices:
        if p == self.moves[s]["RH"]["high"]:
            hit_high = 1
        
        if hit_high == 1:
            consol_short_prices.append(p)
     
                
    #midpoint, and low of consolidation to high of consolidation post-low
    midpoint_short = ((max(consol_short_prices) + min(consol_short_prices)) / 2.0)
    consol_hl = []
    for p in consol_short_prices:
        consol_hl.append(p)
        if p == min(consol_short_prices):
            break
    
    #only need to recalc if it's going to be different
    start_short = "N"
    EMA_period_short = "A"
    if s not in self.prevStartPeriod["bc"] or consol_hl != self.prevPrices["bc"][s]:
        start_short, EMA_period_short = EMA_midpoint_short(self, s, consol_hl, midpoint_short)
        self.prevStartPeriod["bc"][s] = str(start_short) + " " + str(EMA_period_short)
        self.prevPrices["bc"][s] = consol_hl
    else:
        start_short, EMA_period_short = self.prevStartPeriod["bc"][s].split()
        
    if not (start_short != "N" and EMA_period_short != "A"):
        self.Debug("is NA")
        return
        
    adj_closes_EMA_short = consol_short_prices[int(start_short):]
    adj_closes_EMA_short[0] = consol_short_prices[0]
        
    currEMA, EMAs = calcEMA(self, s, adj_closes_EMA_short, EMA_period_short)
    
    return currEMA, EMAs, start_short


def calc_ignEMA(self, s):
    midpoint = ((self.moves[s]["RH"]["high"] + self.moves[s]["RH"]["low"]) / 2.0)
    #ign_time = self.moves[s]["ign_time"]*2
        
    #ign is low to high
    ign_prices = [] 
    for p in self.moves[s]["RH"]["candle_halves"]["Price"]:
        ign_prices.append(p)
        if p == self.moves[s]["RH"]["high"]:
            break

    #only need to recalc if it's going to be different
    start = "NA"
    EMA_period = "NA"
    if s not in self.prevStartPeriod["ab"] or (s in self.prevPrices["ab"] and ign_prices != self.prevPrices["ab"][s]):
        start, EMA_period = EMA_midpoint(self, s, ign_prices, midpoint)
        self.prevStartPeriod["ab"][s] = str(start) + " " + str(EMA_period)
        self.prevPrices["ab"][s] = ign_prices
    else:
        start, EMA_period = self.prevStartPeriod["ab"][s].split(" ")
        start = int(start)
        EMA_period = int(EMA_period)
       
    if not (start != "NA" and EMA_period != "NA"): return 0, [], "NA"
    
    adj_closes_EMA = self.moves[s]["RH"]["candle_halves"]["Price"][int(start):]
    adj_closes_EMA[0] = self.moves[s]["RH"]["candle_halves"]["Price"][0]
        
    currEMA, EMAs = calcEMA(self, s, adj_closes_EMA, int(EMA_period))
    
    return currEMA, EMAs, start


def calc_ignEMAwPM(self, s):
    midpoint_wPM = ((self.moves[s]["PM"]["high"] + self.moves[s]["PM"]["low"]) / 2.0)
        
    #ign is low to high
    ign_prices_wPM = [] 
    for p in self.moves[s]["PM"]["candle_halves"]["Price"]:
        ign_prices_wPM.append(p)
        if p == self.moves[s]["PM"]["high"]:
            break
        
    #only need to recalc if it's going to be different
    start_wPM = "NA"
    EMA_period_wPM = "NA"
    if s not in self.prevStartPeriod["ab_wPM"] or ign_prices_wPM != self.prevPrices["ab_wPM"][s]:
        start_wPM, EMA_period_wPM = EMA_midpoint(self, s, ign_prices_wPM, midpoint_wPM)
        self.prevStartPeriod["ab_wPM"][s] = str(start_wPM) + " " + str(EMA_period_wPM)
        self.prevPrices["ab_wPM"][s] = ign_prices_wPM
    else:
        start_wPM, EMA_period_wPM = self.prevStartPeriod["ab_wPM"][s].split()
        
    adj_closes_EMA_wPM = []
    
    try:
        adj_closes_EMA_wPM = self.moves[s]["PM"]["candle_halves"]["Price"][int(start_wPM):]
    except:
        self.EMAwPMerror.add(s)
        return 0, [], "NA"
    
    adj_closes_EMA_wPM[0] = self.moves[s]["PM"]["candle_halves"]["Price"][0]
    currEMA_wPM, EMAs_wPM = calcEMA(self, s, adj_closes_EMA_wPM, int(EMA_period_wPM))

    return currEMA_wPM, EMAs_wPM, start_wPM



def calc_CD_EMA_postBreak(self, s, all_prices, ema_price):
    #midpoint = ((self.movesCurr[s]["high"] + self.movesCurr[s]["low"]) / 2.0)
        
    #start of move to postbreak
    prices = [] 
    for p in all_prices:
        prices.append(p)
        if p > self.movesCurr[s]["high"]:
            break
    prices.append(self.movesCurr[s]["high"])


    #only need to recalc if it's going to be different
    start = "NA"
    EMA_period = "NA"
    if s not in self.prevStartPeriod["postbreak"] or prices != self.prevPrices["postbreak"][s]:
        start, EMA_period = EMA_midpoint(self, s, prices, ema_price, "CD")

        self.prevStartPeriod["postbreak"][s] = str(start) + " " + str(EMA_period)
        self.prevPrices["postbreak"][s] = prices
    else:
        start, EMA_period = self.prevStartPeriod["postbreak"][s].split()
    start = int(start)
    EMA_period = int(EMA_period)
        
    adj_closes_EMA = []
    
    try:
        adj_closes_EMA = all_prices[start:]
    except:
        #self.EMAwPMerror.add(s)
        return 0, [], "NA"
    
    adj_closes_EMA[0] = all_prices[0]
    currEMA, EMAs = calcEMA(self, s, adj_closes_EMA, EMA_period)

    return currEMA, EMAs, start



#calculate VWMA
def VWMA(self, s, volumes, prices, fromwhen, vp = 0, v = 0):
    vwmas = []
    #vp = 0
    #v = 0

    if fromwhen == "beginning":
        for i in range(0, len(volumes)):
            vp += volumes[i]*prices[i]
            v += volumes[i]
                
            if v != 0:
                vwmas.append(vp/v)
            else:
                vwmas.append(prices[i])
                self.VWMA_vol_zero.add(s.Value)
                    
    elif fromwhen == "consol":
            
        high_ind = ign_high_ind(self, prices, self.moves[s]["RH"]["high"])
            
        try:
            for i in range(high_ind, len(volumes)): #archived: high_ind+1 to start after the high
                vp += volumes[i]*prices[i]
                v +=  volumes[i]
            
                if v != 0: 
                    vwmas.append(vp/v)
                #divide by 0 error, else just make it price. should be super infrequent
                else:
                    vwmas.append(prices[i])
                    self.VWMA_vol_zero.add(s.Value)
                    
        except:
            self.Debug("ign_high_ind error")
            self.Debug(s)
            self.Debug(self.Time)
            self.Debug(self.moves[s]["RH"]["high"])
            
                
    elif fromwhen == "cd":
        consol_low_ind = get_consol_low_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"], self.moves[s]["RH"]["consol_low"])
        for i in range(consol_low_ind, len(self.moves[s]["RH"]["candle_halves"]["Volume"])): #archived: high_ind+1 to start after the high
            vp += self.moves[s]["RH"]["candle_halves"]["Volume"][i]*self.moves[s]["RH"]["candle_halves"]["Price"][i]
            v +=  self.moves[s]["RH"]["candle_halves"]["Volume"][i]
            
            if v != 0: 
                vwmas.append(vp/v)
            #divide by 0 error, else just make it price. should be super infrequent
            else:
                vwmas.append(self.moves[s]["RH"]["candle_halves"]["Price"][i])
                self.VWMA_vol_zero.add(s.Value)
    
    
    
    elif fromwhen == "bc_curr" or fromwhen == "cd_curr":
        ind = "NA"
        if fromwhen == "bc_curr":
            ind = ign_high_ind(self, self.movesCurr[s]["candle_halves"]["Price"], self.movesCurr[s]["high"])
        elif fromwhen == "cd_curr":
            ind = get_consol_low_ind(self, self.movesCurr[s]["candle_halves"]["Price"], self.movesCurr[s]["high"], self.movesCurr[s]["consol_low"])
        
        for i in range(ind, len(self.movesCurr[s]["candle_halves"]["Volume"])):
            vp += self.movesCurr[s]["candle_halves"]["Volume"][i]*self.movesCurr[s]["candle_halves"]["Price"][i]
            v +=  self.movesCurr[s]["candle_halves"]["Volume"][i]
            
            if v != 0: 
                vwmas.append(vp/v)
            #divide by 0 error, else just make it price. should be super infrequent
            else:
                vwmas.append(self.moves[s]["RH"]["candle_halves"]["Price"][i])
                self.VWMA_vol_zero.add(s.Value)
    
    elif fromwhen == "single_minute":
        for i in range(0, len(volumes)):
            vp += volumes[i]*prices[i]
            v +=  volumes[i]
                
            if v != 0: 
                vwmas.append(vp/v)
            #divide by 0 error, else just make it price. should be super infrequent
            else:
                vwmas.append(prices[i])
                self.VWMA_vol_zero.add(s.Value)
        #self.Debug(vwmas)
    
    elif fromwhen == "breakout":
        ind = "NA"
        for i in range(len(prices)-1, -1, -1):
            if prices[i] < self.movesCurr[s]["high"]:
                ind = i
                break
                
        for i in range(ind, len(volumes)):
            vp += volumes[i]*prices[i]
            v +=  volumes[i]
                
            if v != 0: 
                vwmas.append(vp/v)
            #divide by 0 error, else just make it price. should be super infrequent
            else:
                vwmas.append(prices[i])
                self.VWMA_vol_zero.add(s.Value)
    
    
    elif fromwhen == "d":
        ind = "NA"
        for i in range(len(prices)-1, -1, -1):
            if prices[i] == max(prices):
                ind = i
                break
                
        for i in range(ind, len(volumes)):
            vp += volumes[i]*prices[i]
            v +=  volumes[i]
                
            if v != 0: 
                vwmas.append(vp/v)
            #divide by 0 error, else just make it price. should be super infrequent
            else:
                vwmas.append(prices[i])
                self.VWMA_vol_zero.add(s.Value)
    
    else:
        self.Debug("ERROR: input from when for VWMA()")
    
    return vwmas, vp, v

def get_currhigh_ind(s, prices):
    ind = "NA"
    max_price = max(prices)
    for i in range(0, len(prices)):
        if prices[i] < max_price:
            return i

def get_breakout_ind(self, s, prices):
    ind = "NA"
    for i in range(len(prices)-1, -1, -1):
        if prices[i] < self.movesCurr[s]["high"]:
            return i
    
def calc_z(self, x, mu, sd):
    return (x - mu) / sd
    
def x_from_z(self, z, mu, sd):
    return (z*sd) + mu

#index of consol low
def get_consol_low_ind(self, prices, high, curr_consol_low):
    consol_low_ind = "NA"
    hit_high = 0
    for i in range(0, len(prices)):
        if prices[i] == high:
            hit_high = 1
        if hit_high == 1 and prices[i] == curr_consol_low:
            consol_low_ind = i
            break
    return consol_low_ind

#index of ignition high    
def ign_high_ind(self, prices, high):
    for i in range(0, len(prices)):
        if prices[i] == high:
            return i

#calculate long EMA
#start to generalize this
def calc_longEMA_general(self, s, EMAtype, all_prices):
    point = "NA"
    prices = []
    
    #(bigger) AB leg, when in position, so check every second
    if EMAtype == "ab_inpos":
        
        #midpoint of low and current high
        point = ((self.movesCurr[s]["new_high"] + self.movesCurr[s]["low"]) / 2.0)
        
        #ign is low to high
        for p in all_prices:
            prices.append(p)
            if p == self.movesCurr[s]["new_high"]:
                break

    #only need to recalc if it's going to be different
    start = "NA"
    EMA_period = "NA"
    if s not in self.prevStartPeriod[EMAtype] or (s in self.prevPrices[EMAtype] and prices != self.prevPrices[EMAtype][s]):
        start, EMA_period = EMA_midpoint(self, s, prices, point)
        if start != "NA" and EMA_period != "NA":
            self.prevStartPeriod[EMAtype][s] = str(start) + " " + str(EMA_period)
            self.prevPrices[EMAtype][s] = prices
    else:
        start, EMA_period = self.prevStartPeriod[EMAtype][s].split(" ")
        start = int(start)
        EMA_period = int(EMA_period)
       
    if not (start != "NA" and EMA_period != "NA"): return 0, [], "NA"
    
    adj_closes_EMA = all_prices[int(start):]
    adj_closes_EMA[0] = all_prices[0]
        
    currEMA, EMAs = calcEMA(self, s, adj_closes_EMA, int(EMA_period))
    
    return currEMA, EMAs, start

    
#Returns a value rounded down to a specific number of decimal places.
#https://kodify.net/python/math/round-decimals/
def round_decimals_down(self, number:float, decimals:int=2):
    if not isinstance(decimals, int):
        raise TypeError("decimal places must be an integer")
    elif decimals < 0:
        raise ValueError("decimal places has to be 0 or more")
    elif decimals == 0:
        return math.floor(number)

    factor = 10 ** decimals
    return math.floor(number * factor) / factor

#volume profile from start of day
#so basically, VWAP instead of VWMA
#market open is fine
def volumeProfile_general(self, s, stop, highs, lows, vols):
    
    #high and low of every candle
    hls_set = set()
        
    for i in range(0, len(highs)):
        hls_set.add(highs[i])
        hls_set.add(lows[i])
            
    #sorted list
    hls = sorted(hls_set)

    #for each stretch between highs and lows of any candle
        #get all candles that overlap
        #add the candle's volume / proportion of the candle in the current range
            
    vp = {}
    for i in range(0, len(hls) - 1):
        range_low = hls[i]
        range_high = hls[i+1]
            
        for j in range(0, len(highs)):
            #if ranges overlap, add to vp
            overlap = 0
            if lows[j] >= range_low and lows[j] < range_high and highs[j] >= range_high:
                overlap = range_high - lows[j]
            elif highs[j] >= range_low and highs[j] < range_high and lows[j] < range_low:
                overlap = highs[j] - range_low
            elif lows[j] >= range_low and highs[j] < range_high:
                overlap = highs[j] - lows[j]
            elif lows[j] < range_low and highs[j] >= range_high:
                overlap = range_high - range_low
                
            #if any overlap, set to proportion
            if highs[j] - lows[j] != 0:
                overlap = overlap / (highs[j] - lows[j])
            else: #this should never happen because set()
                overlap = 0
                
                
            #formatting
            lowprint = str(range_low)
            if len(lowprint.split(".")[1]) == 1:
                lowprint = lowprint + "0"
            
            if lowprint not in vp:
                vp[lowprint] = overlap*vols[j]
            else:
                vp[lowprint] += overlap*vols[j]
                 
        
    #print and return
    #self.Debug("Range_inclusive_to_next_LessThan\tVolume")
    #totVol = 0
    #for lowprint in sorted(vp):
    #    self.Debug(lowprint + "\t" + str(vp[lowprint]))
    #    totVol += vp[lowprint]
    #self.Debug(str(self.moves[s]["high"]) + "\t0")
    
    #these should be equal
    #self.Debug("candlesum: " + str(sum(self.moves[s]["candles"]["v"])))
    #self.Debug("vp sum: " + str(totVol))
    
    quantile = vpQuantile(self, s, vp, stop)
    
    return quantile

#running simple moving average
def calcSMA(self, vals):
    count = 1.0
    running_sum = 0.0
    SMAs = []
    for v in vals:
        running_sum += v
        SMAs.append(running_sum / count)
        count += 1
    return SMAs

    
def vpQuantile(self, s, vp, quantile):
    #wantedVol = sum(self.moves[s]["candles"]["v"]) * quantile
    
    wantedVol = sum(self.pastNoPre[s]["v"]) * quantile
    
    #find the prices with volume that wantedVol is between
    prevVol = 0
    currVol = 0
    currPrice = "NA"
    nextPrice = "NA"
    broken = 0
    excessVol = 0
    for price in sorted(vp):
        if broken == 0:
            prevVol = currVol
            currPrice = price
            currVol += vp[price]
            
            if currVol >= wantedVol:
                excessVol = currVol - wantedVol
                broken = 1
        else:
            nextPrice = price
            break
        
    return float(currPrice) + ( (excessVol / (currVol - prevVol)) * (float(nextPrice) - float(currPrice)) )


#thinkorswim also includes 4 lookback periods
#the earliest are first
def calcEMA(self, s, closes, period):
    currEMA = 0
    EMAs = []
    alpha = 2.0 / (float(period)+1.0)
    for i in range(0, len(closes)):
        if i == 0:
            currEMA = closes[0]
        else:
            try:
                currEMA = alpha*closes[i] + (1.0-alpha)*currEMA
            except:
                self.calc_EMA_error.add(s)
                return 0, 0
        EMAs.append(currEMA)
    return currEMA, EMAs


#calc daily EMAs for intervals in wanted_EMAs
def calcDailyEMAs(self, s, close, wanted_EMAs):
    df = self.History(self.Symbol(s), timedelta(365), Resolution.Daily)
    
    closes = []
    for row in df.itertuples():
        closes.append(row.close)
    closes.append(close) #current price
    
    all_EMAs = []
    for i in wanted_EMAs:
        ema, EMAs = calcEMA(self, s, closes[-i:], i)
        all_EMAs.append(EMAs)

    return all_EMAs

#not sure this is right but perhaps it is off by a constant (related to the 2.0 scaling)
def weighted_RVOL(self, s, vols, avg_day_vol):
    
    tot_rvol = 0
    tot_weight = 0

    len_vols = len(vols)

    try:
        for i in range(0, len_vols):
            weight = (1.0 - ((len_vols - i) / len_vols) / 2.0) 
            tot_rvol += (vols[i] / avg_day_vol) * weight
            tot_weight += weight
    except:
        return "weighted RVOL error"

    #add current minute
    if self.Time.second != 1:
        tot_rvol += self.pastSixty[s]["v"] / (avg_day_vol * (self.Time.second /60.0)) 
        tot_weight += self.Time.second / 60.0

    w_avg_CD_vol = tot_rvol / tot_weight

    return w_avg_CD_vol 


def dailyMA_percAwayChange(self, close, EMAs):
    #price % away from EMA  
    dist = close - EMAs[-1]
    perc_away = (dist/close)*100.0

    #total change
    perc_change = ((EMAs[-1] - EMAs[0]) / EMAs[0])*100.0


    return perc_away, perc_change

#sharpe
def calcSharpe(self, rr, pr): #pr is prob_success
    
    E = rr*pr + -1*(1-pr) #expectation
    sd = math.sqrt( pr*((rr-E)**2) + (1-pr)*((-1-E)**2)) #standard devation

    sharpe = 0
    if pr == 1:
        sharpe = 999
    elif pr == 0:
        sharpe = -999
    if sd != 0:
        sharpe = E/sd

    return E, sharpe

#gt_yday_high and lt_yday_low
def gt_lt_yday(self, yday, close):
    gt_yday_high = "NA"
    lt_yday_low =  "NA"

    if close > yday.high:
        gt_yday_high = 1
    else:
        gt_yday_high = 0
    
    if close < yday.low:
        lt_yday_low = 1
    else:
        lt_yday_low = 0

    return gt_yday_high, lt_yday_low


def anchoredVWAP(self, s, period, close, volume): #today's volume    
    df = self.History(self.Symbol(s), timedelta(365), Resolution.Daily)
    
    closes = []
    volumes = []
    for row in df.itertuples():
        closes.append(row.close)
        volumes.append(row.volume)
    
    #today's price and volume
    closes.append(close)
    volumes.append(volume)
    
    #self.Debug(closes[-3])
    #self.Debug(closes[-2])
    #self.Debug(closes[-1])

    #self.Debug(volumes[-3])
    #self.Debug(volumes[-2])
    #self.Debug(volumes[-1])

    #you want this to be a little different than VWMA actually
    #it shouldn't have any values for the first N periods b/c it needs them all to have the first one
    #like, else the first VWMA value is always just the price of the first entry
    vwmas = []
    for i in range(len(volumes) - period, len(volumes)): #only get those in period

        vp = 0
        v = 0
        for j in range(i - period+1, i+1):
            try:
                vp += volumes[j]*closes[j]
                v += volumes[j]
            except:
                self.AVWAPerror.add(s)

        if v != 0:
            vwmas.append(vp/v)
        else:
            try:
                vwmas.append(closes[i])
            except:
                self.AVWAPerror.add(s)

    return vwmas

#this is grp_second copy+pasted but changed for pastNoPre
def grp_minute(self, s, df):

    #volume sums
    tot_vol = 0
    
    green_vol_day = 0
    red_vol_day = 0

    green_vol_tot = 0
    red_vol_tot = 0
    
    green_vol_ignition = 0
    red_vol_ignition = 0

    green_vol_consol = 0
    red_vol_consol = 0
    
    green_vol_cd = 0
    red_vol_cd = 0

    green_vol_second_cd = 0
    red_vol_second_cd = 0
    
    w_green_vol_cd = 0
    w_red_vol_cd = 0

    w_green_vol_second_cd = 0
    w_red_vol_second_cd = 0

    w_green_vol_consol = 0
    w_red_vol_consol = 0

    #start of move, start of consol, start of cd leg
    move_start = 0
    consol_count = 0
    cd_count = 0
    second_half_consol_count = 0

    #second half of consol
    n_rows = len(df["v"]) #different from second

    consol_length = "NA"


    #n_consol = 0
    row_count = 0
    start_of_second_consol = "NA"

    #GRP weights
    #weight = 1.0 - (proportion_remaining / 2.0)
    #proportion_remaining =  amount_left / total
    #proportion_remaining =  n_rows -  / (n_rows - start)

    #=1 so they don't error out with divide by 0
    CD_length = 1
    second_half_consol_length = 1
    consol_length = 1

    for minute_num in range(0, len(df["v"])):
        row_count += 1

        low = float(df["l"][minute_num])
        high = float(df["h"][minute_num])
        
        curr_range = high - low
        
        #did moves/legs start
        if low <= self.moves[s]["RH"]["low"]:
            move_start = 1
        
        if move_start == 1 and high >= self.moves[s]["RH"]["high"] and consol_count == 0:
            consol_count = 1
            consol_length = n_rows - row_count

            start_second_CD = row_count + ((n_rows - row_count)/2) #halfway through consolidation

        if move_start == 1 and consol_count >= 1 and low <= self.moves[s]["RH"]["consol_low"]:
            cd_count = 1
            CD_length = n_rows - row_count
        
        if cd_count >= 1 and row_count >= start_second_CD and second_half_consol_count == 0:
            second_half_consol_count = 1
            second_half_consol_length = n_rows - row_count

        ###assign grp
        opened = float(df["o"][minute_num])
        close = float(df["c"][minute_num])
        volume = float(df["v"][minute_num])
        low = float(df["l"][minute_num])

        green = .50
        red = .50
            
        #green proportion
        if high - low != 0:

            ###green proportion as total distance moved
            body = abs(opened - close)
            wick1 = 0
            wick2 = 0

            if close > opened: #green
                wick1 = high - close
                wick2 = opened - low
            else: #red
                wick1 = high - opened
                wick2 = close - low

            distance = body + (wick1*2.0) + (wick2*2.0) 

            try:
                if close > opened:
                    green = (body + wick1 + wick2) / distance
                    red = 1.0 - green
                else:
                    red = (body + wick1 + wick2) / distance
                    green = 1.0 - red
            except:
                error=1

        #assign volume
        green_vol_day += green * volume 
        red_vol_day += red * volume
        tot_vol += volume

        if move_start == 1: #all of move
            green_vol_tot += green * volume
            red_vol_tot += red * volume
            if consol_count == 0: #ignition only
                green_vol_ignition += green * volume
                red_vol_ignition += red*volume

        if consol_count > 0: #all of consolidation
            green_vol_consol += green * volume
            red_vol_consol += red * volume
            consol_count += 1

            #add weighted
            if consol_length == 0: #error for some reason very infrequently
                consol_length = 1
            weight = (1.0 - ((consol_length - consol_count) / consol_length) / 2.0) 

            w_green_vol_consol += green * volume * weight
            w_red_vol_consol += red * volume * weight

        if cd_count > 0:
            green_vol_cd += green * volume
            red_vol_cd += red * volume
            cd_count += 1
        
            #add weighted
            try:
                weight = 1.0 - (((CD_length - cd_count) / CD_length) / 2.0)
            except:
                self.CDerror.add(s.Value)
                weight = 0

            w_green_vol_cd += green * volume * weight
            w_red_vol_cd += red * volume * weight

        if second_half_consol_count > 0:
            green_vol_second_cd += green * volume
            red_vol_second_cd += red * volume
            second_half_consol_count += 1

            #add weighted
            weight = 0
            try:
                weight = 1.0 - (((second_half_consol_length - second_half_consol_count) / second_half_consol_length) / 2.0)
            except:
                tmp=1

            w_green_vol_second_cd += green * volume * weight
            w_red_vol_second_cd += red * volume * weight

    return green_vol_day, red_vol_day, green_vol_tot, red_vol_tot, green_vol_consol, red_vol_consol, green_vol_cd, red_vol_cd, green_vol_second_cd, red_vol_second_cd, green_vol_ignition, red_vol_ignition, start_of_second_consol, w_green_vol_cd, w_red_vol_cd, w_green_vol_second_cd, w_red_vol_second_cd, w_green_vol_consol, w_red_vol_consol

#is level between current price and target/stop
def priceIsBetween(self, level, target_stop, close, sr):
    if sr == "r":
        if close < level <= target_stop:
            return 1
        else:
            return 0
    elif sr == "s":
        if target_stop < level <= close:
            return 1
        else:
            return 0
    return "NA"

def solve_percentile(x, mean, sd):
    percentile = stats.norm.cdf(x, loc=mean, scale=sd)
    return percentile
#region imports
from AlgorithmImports import *

import calculate
import statistics
import copy
import time as tm

import print_or_update
#endregion

def enter(self, s, close): #have enter() return the step that it go to if self.enter_time is not ""
    vwap = self.sd[s].vwap.Current.Value

    ########
    # misc #
    ########
    if not self.Portfolio[s].Invested and s in self.positions:
        del self.positions[s]
    if not (not self.Portfolio[s].Invested): return #doesn't already have position
    if s in self.positions: return "already_in_position"

        
    ##############
    # above VWAP #
    ##############
    if not (close > vwap): return "below_VWAP" #above VWAP
    #doesn't need to break VWAP, just be above it

    ######################
    # resolution too low #
    ######################
    if not (len(self.moves[s]["RH"]["candles"]["o"]) >= 4): return "lt_4_minutes"

    #################
    # enough volume #
    #################
    if not (statistics.median(self.moves[s]["RH"]["candles"]["v"]) > 9000): return "lt_9000_volume"

    #####################
    # above/broke level #
    #####################
    df = self.History(self.Symbol(s), timedelta(7), Resolution.Daily)
    self.ydays[s] = df.iloc[-1] #save this for later
        
    if s not in self.pmHigh:
        self.notInPMHigh.add(s)
        return "no_PM_high_for_some_reason"
        
    levels = set()
    try:
        levels.add(self.pmHigh[s])
            
        #only add levels if they haven't been broken by something more recent
        if df.iloc[-1].high > self.pmHigh[s]: #yday high will always be >= yday close
            levels.add(df.iloc[-1].high)

    except:
        self.Debug("single positional indexer is out-of-bounds")
        self.Debug(s)
        self.Debug(self.Time)
        return "PM_high_failed"
        
    #hod level has broken other level
    toremove = set()
    if s in self.hod_level:
        for l in levels:
            if self.hod_level[s] > l:
                toremove.add(l)
        
    for l in toremove:
        levels.remove(l)
        levels.add(self.hod_level[s])
        
    #get level that was max broken
    max_broken = 0
    for level in levels:
        if self.moves[s]["RH"]["high"] > level and level > max_broken:
            max_broken = level

    #if not (close >= max_broken and max_broken != 0): return "not_above_max_broken_level" #must be above broken level
    if not (close >= max_broken or max_broken == 0): return "not_above_max_broken_level, levels: " + str(levels)


    ###############
    # >daily EMAs #
    ###############
    wanted_EMAs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50, 200]
    all_EMAs = calculate.calcDailyEMAs(self, s, close, wanted_EMAs)

    EMAs = {}
    EMAs["2"] = all_EMAs[0]
    EMAs["3"] = all_EMAs[1]
    EMAs["4"] = all_EMAs[2]
    EMAs["5"] = all_EMAs[3]
    EMAs["6"] = all_EMAs[4]
    EMAs["7"] = all_EMAs[5]
    EMAs["8"] = all_EMAs[6]
    EMAs["9"] = all_EMAs[7]
    EMAs["10"] = all_EMAs[8]
    EMAs["20"] = all_EMAs[9]
    EMAs["50"] = all_EMAs[10]
    EMAs["200"] = all_EMAs[11]

    #########################
    # get EOD prediction    #
    #########################
    if (tm.time() - self.startTime) > 500: #lt 500 seconds
        return "time out EOD pred"

    #sd = 0
    #mean_vols = [-1, -1, -1]
    #rsq = 0
    if s not in self.EODmodels and s.Value not in self.EODmodelErr:
        try:
            model, today_row, yday_ohlc, sd, mean_vols, rsq = calculate.modelEODRange(self, s)
            self.EODmodels[s] = [model, today_row, yday_ohlc, sd, mean_vols, rsq]

        except:
            self.EODmodelErr.add(s.Value)
            return "EOD_model_error_1 " + str(s)           

    if not (s.Value not in self.EODmodelErr and self.EODmodels[s][0] != "NA"): return "EOD_model_error_2" #check for self.EODmodelErr also
    
    pred_series = calculate.predictEODRange(self, self.EODmodels[s][0], self.EODmodels[s][1], [self.open[s], self.hod[s], self.lod[s]], self.EODmodels[s][2]) #self.pmVol[s], self.rhvol3[s]
    pred = pred_series[0]

    #only enter if today range < predicted EOD range
    if not ( (self.hod[s] - self.lod[s]) < pred ): return "gt_daily_prediction"

    #add to <1 minute staging
    self.staging[s] = {}
    self.staging[s]["max_broken"] = max_broken
    self.staging[s]["pred"] = pred
    self.staging[s]["levels"] = levels
    self.staging[s]["EMAs"] = EMAs
    self.staging[s]["sd"] = self.EODmodels[s][3]
    self.staging[s]["mean_vols"] = self.EODmodels[s][4]
    self.staging[s]["rsq"] = self.EODmodels[s][5]

    enter_staged(self, s, close, max_broken, pred, levels, EMAs, self.EODmodels[s][4], self.EODmodels[s][3], self.EODmodels[s][5])

    return "enter_staged"



def enter_staged(self, s, close, max_broken, pred, levels, dailyEMAs, mean_vols, sd, rsq):
    vwap = self.sd[s].vwap.Current.Value
        
    #VWAP increasing
    if not (vwap >= self.prevVWAP[s]): return "VWAP_not_increasing"


    #######################
    # enough volume in CD #
    #######################
    #average volume CD or total volume CD wrt to ignition
    #the "candle_halves" are thirds (20 seconds) not halves (30 seconds) btw
    cd_ind = calculate.get_consol_low_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"], self.moves[s]["RH"]["consol_low"])
    ign_ind = calculate.ign_high_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"])

    #max length of CD is half of consolidation
    cd_length = 0
    consol_length = 0
    cd_half = 0
    if cd_ind != "NA" and ign_ind != "NA":
        cd_length = len(self.moves[s]["RH"]["candle_halves"]["Price"]) - int(cd_ind)
        consol_length = len(self.moves[s]["RH"]["candle_halves"]["Price"]) - int(ign_ind)

        if cd_length > ((consol_length)/2.0):
            cd_ind = int(ign_ind + (consol_length/2))
            cd_half = 1
        cd_length = len(self.moves[s]["RH"]["candle_halves"]["Price"]) - int(cd_ind)


    #AB volume
    ign_vol = 0
    for i in range(0, len(self.moves[s]["RH"]["candle_halves"]["Price"])):
        ign_vol += self.moves[s]["RH"]["candle_halves"]["Volume"][i]
        if i == ign_ind:
            break
        
    #BC volume
    bc_vol = 0
    for i in range(ign_ind, len(self.moves[s]["RH"]["candle_halves"]["Price"])):
        bc_vol += self.moves[s]["RH"]["candle_halves"]["Volume"][i]
        if i == cd_ind:
            break

    #CD volume
    cd_vol = 0
    try:
        for i in range(cd_ind, len(self.moves[s]["RH"]["candle_halves"]["Price"])):
            cd_vol += self.moves[s]["RH"]["candle_halves"]["Volume"][i]
    except:
        return "CD_volume_error, cd_ind: " + str(cd_ind) + " len candle_halves[]: " + str(len(self.moves[s]["RH"]["candle_halves"]["Price"]))
    
    if self.Time.second != 1:
        cd_vol += self.pastSixty[s]["v"]

    if not (cd_vol > (ign_vol * .35)): return ("CD_volume_lt_1/3_ign_volume") #ENPH 8/2/22 9:40
    if not (cd_vol > (bc_vol * .35)): return ("CD_volume_lt_1/3_BC_volume, cd_vol:" + str(cd_vol) + " bc_vol: " + str(bc_vol))


    ################################
    # Holding above level and VWAP #
    ################################
    cd_closes = self.moves[s]["RH"]["candle_halves"]["Price"][int(cd_ind):]
    bd_closes = self.moves[s]["RH"]["candle_halves"]["Price"][int(ign_ind):]

    if self.Time.second != 1:
        cd_closes.append(close)
        bd_closes.append(close)
        
    cd_SMAs = calculate.calcSMA(self, cd_closes)
    bd_SMAs = calculate.calcSMA(self, bd_closes)
                                
    #if not ((cd_SMAs[-1] > vwap and cd_SMAs[-1] > max_broken) or (bc_SMAs[-1] > vwap and bc_SMAs[-1] > max_broken)): return
    if not (bd_SMAs[-1] > vwap and cd_SMAs[-1] > vwap): return "not holding above level and VWAP"


    ###########################
    # EMA midpnt of ignition  #
    ###########################
        
    currEMA, EMAs, start = calculate.calc_ignEMA(self, s)

    #staging
    if self.Time.second != 1:
        start, EMA_period = self.prevStartPeriod["ab"][s].split(" ")
        start = int(start)
        EMA_period = int(EMA_period)
       
        if not (start != "NA" and EMA_period != "NA"): return 0, [], "NA"
    
        adj_closes_EMA = self.moves[s]["RH"]["candle_halves"]["Price"][int(start):]
        adj_closes_EMA[0] = self.moves[s]["RH"]["candle_halves"]["Price"][0]
        
        currEMA, EMAs = calculate.calcEMA(self, s, adj_closes_EMA, int(EMA_period))


    #TypeError : 'NoneType' object is not iterable
    if currEMA == 0 or EMAs == [] or start == "NA": return "failed to calc EMA for some reason"
        
    #start = int(start) - 1
        
    #bollinger
    diffs = []
    closes = self.moves[s]["RH"]["candle_halves"]["Price"][int(start):]

    for i in range(0, len(EMAs)):
        diffs.append(abs(closes[i] - EMAs[i]))
    avgdevs = calculate.calcSMA(self, diffs)
        
    #if avg devs ever < 60% of avgdevs[ign_ind] and avg devs ever < 25% of move
    ign_dev = 0
    try:
        ign_dev = avgdevs[ign_ind]
    except:
        return "avgdevs[ign_ind] error"
    lt_perc_avgdev = 0
    lt_perc_move = 0

    try:
        for i in range(ign_ind + 1, len(avgdevs)):
            if avgdevs[i] < .60*ign_dev: #ENPH 8/2/22 ~9:40 from .60
                lt_perc_avgdev = 1
            if avgdevs[i] < .25*(self.moves[s]["RH"]["high"] - self.moves[s]["RH"]["low"]):
                lt_perc_move = 1
            if lt_perc_move == 1 and lt_perc_avgdev == 1:
                break
    except:
        #self.Debug("ign ind + 1 oob len(avgdevs)")
        self.avgdevoob.add(s)
        
    
    if not (lt_perc_move == 1 and lt_perc_avgdev == 1): return "has not consolidated enough from bollinger, lt_perc_move: " + str(lt_perc_move) + " lt_perc_avgdev: " + str(lt_perc_avgdev)

                
    ##################################################
    # EMA midpoint of low of entire day including PM #
    ##################################################
    currEMA_wPM, EMAs_wPM, start_wPM = calculate.calc_ignEMAwPM(self, s)

    #TypeError : 'NoneType' object is not iterable
    if currEMA_wPM == 0 or EMAs_wPM == [] or start_wPM == "NA": return "failed to calc EMA for some reason"


    #EMA within 25% of total move of current close
    if not( abs(close - currEMA_wPM) < .25*(self.moves[s]["PM"]["high"] - self.moves[s]["PM"]["low"])): return "EMA not close enough to close"


    ###########
    # high RR #
    ###########

    #use minutes including PM
    mins = self.timeInMin(str(self.Time).split()[1])

    df_mins = self.History(self.Symbol(s), timedelta(1), Resolution.Minute)
    df_mins = df_mins.tail(mins - 240)

    highs = []
    lows = []
    vols = []
    closes = []

    #use minutes for premarket
    for row in df_mins.itertuples():
        highs.append(float(row.high))
        lows.append(float(row.low))
        vols.append(float(row.volume))
        closes.append(float(row.close))

    # stop calculation, use volume profile 
    #vp_stop = calculate.volumeProfile_general(self, s, .30, highs, lows, vols)

    #stop = vp_stop

    currRange = self.moves[s]["RH"]["high"] - self.lod[s]
    
    #bd_range = max(bd_closes) - min(bd_closes)

    half = int(len(self.moves[s]["RH"]["candle_halves"]["Price"])/2)
    second_half = self.moves[s]["RH"]["candle_halves"]["Price"][half:]
    second_half_range = max(second_half) - min(second_half)

    #avg_range = (currRange + bd_range) / 2.0
    avg_range = (currRange + second_half_range) / 2.0
    

    consol_stop = min(cd_closes) - (avg_range*.15) 
    vwap_stop = vwap - (avg_range*.15)

    stop = min(consol_stop, vwap_stop)


    #if stop > consol_low:
    #    stop = (stop + consol_low) / 2.0

    #stop must be at least 5 cents, else resolution is too low
    if (abs(stop - close) < .04): return "stop resolution too low"
        #stop = close - .05

    #only enter if R:R is big e.g., >2.5:1
    #self.Debug(preds)
    rr = ((pred + self.lod[s]) - close) / (close - stop)
    #rr_25 = ((preds[1] + self.lod[s]) - close) / (close - stop)

    if not (rr > 1.0 and rr < 10.0): return "RR not high enough or too high, rr: " + str(rr) #change this from .10 pred and 1.0

    VWMAs, vp, v = calculate.VWMA(self, s, vols, closes, "beginning")


    ##############
    # GRP volume #
    ##############
    grp_timeframe = "minute"
    df = self.pastNoPre[s]

    if grp_timeframe == "second":
        df = self.History(self.Symbol(s), timedelta(1), Resolution.Second)    
        df = df.tail((mins - 570)*60 + 1 + int(self.Time.second))

    #green_vol_day, red_vol_day, green_vol_tot, red_vol_tot, green_vol_consol, red_vol_consol, green_vol_cd, red_vol_cd, green_vol_half_cd, red_vol_half_cd, green_vol_ign, red_vol_ign, half_cd_start, w_green_vol_cd, w_red_vol_cd, w_green_vol_second_cd, w_red_vol_second_cd, w_green_vol_consol, w_red_vol_consol = calculate.grp_second(self, s, df)
    green_vol_day, red_vol_day, green_vol_tot, red_vol_tot, green_vol_consol, red_vol_consol, green_vol_cd, red_vol_cd, green_vol_half_cd, red_vol_half_cd, green_vol_ign, red_vol_ign, half_cd_start, w_green_vol_cd, w_red_vol_cd, w_green_vol_second_cd, w_red_vol_second_cd, w_green_vol_consol, w_red_vol_consol = calculate.grp_minute(self, s, df)


    #error out
    if red_vol_tot + green_vol_tot == 0: return "error in init red and green volume tot"
    if red_vol_consol + green_vol_consol == 0: return "error in init red and green volume consol"
    if red_vol_cd + green_vol_cd == 0: return "error in init red and green volume cd"
    if red_vol_ign + green_vol_ign == 0: return "error in init red and green volume ign"

    #calc grp
    grp_day = green_vol_day / (green_vol_day + red_vol_day)
    grp_tot = green_vol_tot / (red_vol_tot + green_vol_tot)
    grp_consol = (green_vol_consol /  (red_vol_consol + green_vol_consol))
    grp_cd = green_vol_cd / (red_vol_cd + green_vol_cd)
    grp_ign = green_vol_ign / (red_vol_ign + green_vol_ign)

    w_grp_cd = 0
    try:
        w_grp_cd = w_green_vol_cd / (w_red_vol_cd + w_green_vol_cd)
    except:
        tmp=1

    if cd_half == 1:
        try:
            grp_cd = green_vol_half_cd / (red_vol_half_cd + green_vol_half_cd)
            w_grp_cd = w_green_vol_second_cd / (w_red_vol_second_cd + w_green_vol_second_cd)
        except:
            grp_cd = 0
            w_grp_cd = 0

    #to print out later
    move_day_vol = (green_vol_tot + red_vol_tot) / (red_vol_day + green_vol_day)


    #filter
    #if self.printout == 0:
    if not (grp_day > .25): return "green vol day: " + str(grp_day) #EQT 5/3/22
    if not (grp_tot > .25): return "green vol tot: " + str(grp_tot) #EQT 5/3/22
    if not (grp_consol > .25): return "grp consol: " + str(grp_consol)
    if not (grp_cd > .40): return "green vol cd: " + str(grp_cd) #HAL 8/16/22 10:07


    ###################################
    # relative volume CD and ignition #
    ###################################

    #number of 30 second periods
    len_CD = len(self.moves[s]["RH"]["candle_halves"]["Price"]) - cd_ind
    len_ign = ign_ind
    len_day = (len(self.pastNoPre[s]["o"]))*3.0 + (self.Time.second/20.0)
    len_tot = len(self.moves[s]["RH"]["candle_halves"]["Volume"]) #this is in thirds (20 seconds), not halves (30 seconds)

    #CD volume
    ign_vols = self.moves[s]["RH"]["candle_halves"]["Volume"][:ign_ind]
    cd_vols = self.moves[s]["RH"]["candle_halves"]["Volume"][cd_ind:]
    
    #avg_ign_vol = statistics.mean(ign_vols)
    #avg_cd_vol = statistics.mean(cd_vols)
    #avg_day_vol = ((red_vol_day + green_vol_day) / len_day) #per 30 seconds, so compare directly to values in "candle_halves"



    #w_avg_move_move = calculate.weighted_RVOL(self, s, self.moves[s]["RH"]["candle_halves"]["Volume"], statistics.mean(self.moves[s]["RH"]["candle_halves"]["Volume"]))
    #w_avg_move_day = calculate.weighted_RVOL(self, s, self.moves[s]["RH"]["candle_halves"]["Volume"], avg_day_vol)


    #average vol, per minute
    avg_CD_vol = ((cd_vol) / len_CD)*2.0
    avg_ign_vol = ((ign_vol) / len_ign)*2.0
    avg_day_vol = ((red_vol_day + green_vol_day) / len_day)*2.0


    ###calculate RVOLs
    #weighted
    w_avg_CD_ign = calculate.weighted_RVOL(self, s, cd_vols, avg_ign_vol)
    w_avg_CD_day = calculate.weighted_RVOL(self, s, cd_vols, avg_day_vol)
    w_avg_ign_day = calculate.weighted_RVOL(self, s, ign_vols, avg_day_vol)

    #unweighted
    avg_CD_ign = avg_CD_vol / avg_ign_vol
    avg_CD_day = avg_CD_vol / avg_day_vol
    avg_ign_day = avg_ign_vol / avg_day_vol

    #proportion of ign and CD of total move
    prop_len_CD = len_CD / len_tot
    prop_len_ign = float(len_ign) / float(len_tot)

    #prop total move vs day
    prop_len_move_day = len_tot / len_day

    #rvol_ign_x_cd = w_avg_ign_day * w_avg_CD_day
    #rvol_ign_plus_cd = w_avg_ign_day + w_avg_CD_day

    #if self.printout == 0:
    if not (w_avg_CD_day > .40): return "avg CD vol < 40 perc of avg day volume: " + str(w_avg_CD_day) #0.48739860564657245 HAL 10:07 8/16/22, you need to save OXY 5/3/22 though
#        if not (w_avg_CD_ign > .40): return "avg CD vol < 40 perc of avg ign vol: " + str(w_avg_CD_ign) #EQT 5/3/22


    #############
    # EMA calcs #
    #############
    perc_aways = []
    perc_changes = []
    for i in ["2", "3", "4", "5", "6", "7", "8", "9", "10", "20", "50", "200"]:
        perc_away, perc_change = calculate.dailyMA_percAwayChange(self, close, dailyEMAs[i])
        perc_aways.append(perc_away)
        perc_changes.append(perc_change)

    #######################
    # Anchored VWAP calcs #
    #######################
    avwaps = {}
    avwaps["avwap2"] = calculate.anchoredVWAP(self, s, 2, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap3"] = calculate.anchoredVWAP(self, s, 3, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap4"] = calculate.anchoredVWAP(self, s, 4, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap5"] = calculate.anchoredVWAP(self, s, 5, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap6"] = calculate.anchoredVWAP(self, s, 6, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap7"] = calculate.anchoredVWAP(self, s, 7, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap8"] = calculate.anchoredVWAP(self, s, 8, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap9"] = calculate.anchoredVWAP(self, s, 9, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap10"] = calculate.anchoredVWAP(self, s, 10, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap20"] = calculate.anchoredVWAP(self, s, 20, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap50"] = calculate.anchoredVWAP(self, s, 50, close, sum(self.pastNoPre[s]["v"]))
    avwaps["avwap200"] = calculate.anchoredVWAP(self, s, 200, close, sum(self.pastNoPre[s]["v"]))

    perc_aways_avwap = {}
    perc_changes_avwap = {}
    for avwap in avwaps:
        perc_away, perc_change = calculate.dailyMA_percAwayChange(self, close, avwaps[avwap])
        perc_aways_avwap[avwap] = perc_away
        perc_changes_avwap[avwap] = perc_change

    ##########################
    # levels, today and yday #
    ##########################

    #PM high, today open, yday close, yday low, yday high, PM low
    pm_high = self.pmHigh[s]
    pm_low = self.pmLow[s]
    yday_high = self.ydays[s].high
    yday_low = self.ydays[s].low
    yday_close = self.ydays[s].close
    today_open = self.open[s]

    #stop and tp
    target = self.lod[s] + pred
    #stop = stop
    #close = close

    resistance = {}
    support = {}
    resistance["pm_high"] = calculate.priceIsBetween(self, pm_high, target, close, "r")
    resistance["pm_low"] = calculate.priceIsBetween(self, pm_low, target, close, "r")
    resistance["yday_high"] = calculate.priceIsBetween(self, yday_high, target, close, "r")
    resistance["yday_low"] = calculate.priceIsBetween(self, yday_low, target, close, "r")
    resistance["yday_close"] = calculate.priceIsBetween(self, yday_close, target, close, "r")
    resistance["today_open"] = calculate.priceIsBetween(self, today_open, target, close, "r")
    resistance["hod"] = 0
    if self.hod[s] > self.moves[s]["RH"]["high"]:
        resistance["hod"] = 1

    support["pm_high"] = calculate.priceIsBetween(self, pm_high, stop, close, "s")
    support["pm_low"] = calculate.priceIsBetween(self, pm_low, stop, close, "s")
    support["yday_high"] = calculate.priceIsBetween(self, yday_high, stop, close, "s")
    support["yday_low"] = calculate.priceIsBetween(self, yday_low, stop, close, "s")
    support["yday_close"] = calculate.priceIsBetween(self, yday_close, stop, close, "s")
    support["today_open"] = calculate.priceIsBetween(self, today_open, stop, close, "s")
    support["lod"] = calculate.priceIsBetween(self, self.lod[s], stop, close, "s")
    

    #######################
    # prob success vs R:R #
    #######################
    #calc spread
    spread = ((self.Securities[s].AskPrice - self.Securities[s].BidPrice) + self.pastNoPre[s]["mean_spread"][-1] + self.pastNoPre[s]["mean_spread"][-2] + self.pastNoPre[s]["mean_spread"][-3]) / 4.0 #avg of past 3 minutes
    
    shares, shares_no_spread = self.positionSize(stop, close, self.dollar_risk, spread)
    ratio = shares / shares_no_spread

    #make GRP variables
    GRP_CD_scaled = (grp_cd - .50) * prop_len_CD * prop_len_move_day
    wRVOL_CD_scaled = w_avg_CD_day * prop_len_CD * prop_len_move_day
    CD_RVOL_x_GRP = GRP_CD_scaled * wRVOL_CD_scaled

    df = pd.DataFrame()

    #today's range percentile of EOD pred
    percentile = calculate.solve_percentile((self.hod[s] - self.lod[s]), pred, self.EODmodels[s][3])

    #X = df[["RR.10", "GRP_day", "GRP_CD_scaled", "CD_wRVOL_x_GRP", "wRVOL_CD_scaled", "PercChangeEMA3", "PercChangeEMA5", "PercChangeEMA8", "PercFromPriceEMA3", "PercFromPriceEMA5",  "PercFromPriceEMA8", "PercChangeAVWAP3", "PercChangeAVWAP5", "PercChangeAVWAP8", "PercFromPriceAVWAP3", "PercFromPriceAVWAP5", "PercFromPriceAVWAP8", "pm_high_bw_target", "yday_high_bw_target", "yday_close_bw_target", "today_open_bw_target", "yday_low_bw_target", "pm_low_bw_target", "pm_high_bw_stop", "yday_high_bw_stop", "yday_close_bw_stop", "today_open_bw_stop"]]
    #y = df[["ReachedTarget"]]

    df['RR'] = [float(rr)]
    df['GRP_day'] = [float(grp_day)]
    df['GRP_CD_scaled'] = [float(GRP_CD_scaled)]
    df['CD_wRVOL_x_GRP'] = [float(CD_RVOL_x_GRP)]
    df['wRVOL_CD_scaled'] = [float(wRVOL_CD_scaled)]

    df['PercChangeEMA3'] = [float(perc_changes[1])]
    df['PercChangeEMA5'] = [float(perc_changes[3])]
    df['PercChangeEMA8'] = [float(perc_changes[6])]
    df['PercFromPriceEMA3'] = [float(perc_aways[1])]
    df['PercFromPriceEMA5'] = [float(perc_aways[3])]
    df['PercFromPriceEMA8'] = [float(perc_aways[6])]
    
    df['PercChangeAVWAP3'] = [float(perc_changes_avwap["avwap3"])]
    df['PercChangeAVWAP5'] = [float(perc_changes_avwap["avwap5"])]
    df['PercChangeAVWAP8'] = [float(perc_changes_avwap["avwap8"])]
    df['PercFromPriceAVWAP3'] = [float(perc_aways_avwap["avwap3"])]
    df['PercFromPriceAVWAP5'] = [float(perc_aways_avwap["avwap5"])]
    df['PercFromPriceAVWAP8'] = [float(perc_aways_avwap["avwap8"])]

    df['pm_high_bw_target'] = resistance["pm_high"]
    df['yday_high_bw_target'] = resistance["yday_high"]
    df['yday_close_bw_target'] = resistance["yday_close"]
    df['today_open_bw_target'] = resistance["today_open"]
    df['yday_low_bw_target'] = resistance["yday_low"]
    df['pm_low_bw_target'] = resistance["pm_low"]
    df['pm_high_bw_stop'] = support["pm_high"]
    df['yday_high_bw_stop'] = support["yday_high"]
    df['yday_close_bw_stop'] = support["yday_close"]
    df['today_open_bw_stop'] = support["today_open"]

    

    '''
    calibrated_proba = self.calibrated.predict_proba(df)

    E, sharpe = calculate.calcSharpe(self, rr_10*ratio, calibrated_proba[:,1])

    if self.sharpeThresh != "":
        if not (sharpe > float(self.sharpeThresh)): return "Sharpe not high enough"
    '''

    #########
    # enter #
    #########
    #order
    shares_close = -1.0*shares
        
    #put in orders
    self.MarketOrder(s, shares) #enter
    self.StopMarketOrder(s, shares_close, stop) #stop
    #self.StopMarketOrder(s, shares_close, float(self.lod[s] + preds[0])) #take profit

    #logs
    self.Debug("LONG: " + s.Value + " " + str(self.Time))
    if self.printMinimal != 1:

        self.Debug("Stop: " + str(stop))
        self.Debug("Current price: " + str(close))
        self.Debug("Take profit: " + str(self.lod[s] + pred))
    
    
    #self.Debug("VWAP: " + str(vwap))
    #self.Debug("VWMA, market open: " + str(VWMAs[-1]))


    #self.Debug("Levels: ")
    #self.Debug(levels)
    #self.Debug("max broken: " + str(max_broken))
    #self.Debug("green:red : "  + str(self.green_red_prop_ignition(s)))
    #self.Debug("pred 25% EOD range: " + str(pred))
        self.Debug("RR pred: " + str(rr*ratio))
    #self.Debug("RR 25%: " + str(rr_25*ratio))
    #self.Debug("Prob success: " + str(prob))
    #self.Debug("Prob success needed: " + str(prob_needed))
    #self.Debug("Prob/prob needed: " + str(prob/prob_needed))
    #self.Debug("median 1-min volume:" + str(statistics.median(self.moves[s]["RH"]["candles"]["v"])))
        
    #self.Debug("CD length: " + str(cd_length))
    #self.Debug("Consol length: " + str(consol_length))


    #self.Debug("grp_day: " + str(grp_day))
    #self.Debug("grp_tot: " + str(grp_tot))
    #self.Debug("grp_ign: " + str(grp_ign))
    #self.Debug("grp_consol: " + str(grp_consol))
    #self.Debug("grp_cd: " + str(grp_cd))
    #self.Debug("w_grp_cd: " + str(w_grp_cd))

    #self.Debug("ign_vol: " + str(ign_vol))
    #self.Debug("bc_vol: " + str(bc_vol))
    #self.Debug("cd_vol: " + str(cd_vol))

    #self.Debug("weighted avg CD/ign: " +  str(w_avg_CD_ign))
    #self.Debug("weighted avg CD/day: " +  str(w_avg_CD_day))
    #self.Debug("weighted avg ign/day: " +  str(w_avg_ign_day)) 

        self.Debug("prob success:" + str(calibrated_proba[:,1]))
        self.Debug("expectation: " + str(E))
        self.Debug("sharpe: " +  str(sharpe))
    #self.Debug("weighted avg move/move: " +  str(w_avg_move_move))
    #self.Debug("weighted avg move/day: " +  str(w_avg_move_day))

    #self.Debug("rvol_ign_x_cd: " +  str(rvol_ign_x_cd))  
    #self.Debug("rvol_ign_plus_cd: " +  str(rvol_ign_plus_cd))  

    #self.Debug("avg CD vol ratio: " +  str(avg_CD_vol / avg_day_vol))

    #self.Debug("avg CD vol: " + str(avg_CD_vol))
    #self.Debug("avg ign vol: " + str(avg_ign_vol))
    #self.Debug("avg day vol: " + str(avg_day_vol))

        #end print

    #move for current position
    self.movesCurr[s] = copy.deepcopy(self.moves[s]["RH"]) #don't use dict() or .copy() https://stackoverflow.com/questions/2465921/how-to-copy-a-dictionary-and-only-edit-the-copy
    self.movesCurr[s]["ign_ind"] = calculate.ign_high_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"])
    self.movesCurr[s]["consol_low_ind"] = calculate.get_consol_low_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"], self.moves[s]["RH"]["consol_low"])
    self.movesCurr[s]["broke_high"] = 0
    #self.movesCurr[s]["green_vol"] = green_vol_tot
    #self.movesCurr[s]["red_vol"] = red_vol_tot
    self.movesCurr[s]["new_high"] = self.movesCurr[s]["high"]

    #add to current positions
    self.positions[s] = {}
    self.positions[s]["time"] = self.Time
    self.positions[s]["pred"] = pred
    self.positions[s]["stop"] = stop
    self.positions[s]["shares_close"] = shares_close
    self.positions[s]["take_profit"] = float(self.lod[s] + pred)

    if s not in self.everPosition:
        self.everPosition[s] = {}
        self.everPosition[s]["N_entries"] = 1
    else:
        self.everPosition[s]["N_entries"] += 1
    self.everPosition[s]["time"] = self.Time
    self.everPosition[s]["pmvol"] = self.PM_atSelection[s]["pmvol"]
    self.everPosition[s]["pm_nonzero"] = self.PM_atSelection[s]["pm_nonzero"]
    self.everPosition[s]["R:R"] = rr
    self.everPosition[s]["prop_of_pred_range"] = (self.hod[s] - self.lod[s]) / pred


    #if in position, not stagin anymore
    del self.staging[s]
    

    #above/below yday
    gt_yday_high, lt_yday_low = calculate.gt_lt_yday(self, self.ydays[s], close)

    #what percentage of expected move is today's range
    percentage_EOD_pred = (self.hod[s] - self.lod[s]) / pred 

    #to print out later
    self.movesCurr[s]["time"] = self.Time
    self.movesCurr[s]["high_move"] = close #Max_moved_before_stop
    self.movesCurr[s]["curr_range"] = self.hod[s] - self.lod[s]
    self.movesCurr[s]["entry"] = close
    self.movesCurr[s]["stopLOD"] = self.lod[s] - .01
    self.movesCurr[s]["stopCustom"] = stop
    self.movesCurr[s]["entryLOD"] = self.lod[s]
    self.movesCurr[s]["entryHOD"] = self.hod[s]
    self.movesCurr[s]["pred"] = pred
    self.movesCurr[s]["stoppedCustom"] = 0
    self.movesCurr[s]["stoppedLOD"] = 0
    self.movesCurr[s]["stoppedCustomTime"] = "NA"
    self.movesCurr[s]["stoppedLODTime"] = "NA"
    self.movesCurr[s]["stopCustom_highMove"] = "NA"
    self.movesCurr[s]["stopLOD_highMove"] = "NA"

    self.movesCurr[s]["grp_day"] = grp_day
    self.movesCurr[s]["grp_tot"] = grp_tot
    self.movesCurr[s]["grp_ign"] = grp_ign
    self.movesCurr[s]["grp_consol"] = grp_consol
    self.movesCurr[s]["grp_cd"] = grp_cd

    self.movesCurr[s]["w_grp_cd"] = w_grp_cd

    self.movesCurr[s]["rvol_CD_day"] = avg_CD_day
    self.movesCurr[s]["rvol_CD_ign"] = avg_CD_ign
    self.movesCurr[s]["rvol_ign_day"] = avg_ign_day

    self.movesCurr[s]["w_rvol_CD_day"] = w_avg_CD_day
    self.movesCurr[s]["w_rvol_CD_ign"] = w_avg_CD_ign
    self.movesCurr[s]["w_rvol_ign_day"] = w_avg_ign_day

    self.movesCurr[s]["prop_len_CD"] = prop_len_CD
    self.movesCurr[s]["prop_len_ign"] = prop_len_ign

    self.movesCurr[s]["perc_aways"] = perc_aways
    self.movesCurr[s]["perc_changes"] = perc_changes

    self.movesCurr[s]["time_in_sec"] = self.timeInSec(str(self.Time).split()[1])

    self.movesCurr[s]["move_day_vol"] = move_day_vol
    self.movesCurr[s]["prop_len_move_day"] = prop_len_move_day

    self.movesCurr[s]["gt_yday_high"] = gt_yday_high
    self.movesCurr[s]["lt_yday_low"] = lt_yday_low

    self.movesCurr[s]["EMAs"] = dailyEMAs

    self.movesCurr[s]["perc_aways_avwap"] = perc_aways_avwap
    self.movesCurr[s]["perc_changes_avwap"] = perc_changes_avwap

    self.movesCurr[s]["resistance"] = resistance
    self.movesCurr[s]["support"] = support

    self.movesCurr[s]["spread"] = spread

    self.movesCurr[s]["mean_vols"] = mean_vols

    self.movesCurr[s]["percentage_EOD_pred"] = percentage_EOD_pred

    self.movesCurr[s]["pm_high"] = pm_high
    self.movesCurr[s]["pm_low"] = pm_low
    self.movesCurr[s]["yday_high"] = yday_high
    self.movesCurr[s]["yday_low"] = yday_low
    self.movesCurr[s]["yday_close"] = yday_close
    self.movesCurr[s]["today_open"] = today_open

    self.movesCurr[s]["bd_SMA"] = bd_SMAs[-1]
    self.movesCurr[s]["cd_SMA"] = cd_SMAs[-1]

    self.movesCurr[s]["residual_sd"] = sd
    self.movesCurr[s]["model_rsq"] = rsq

    self.movesCurr[s]["percentile"] = percentile

    #move_len = len(self.moves[s]["RH"]["candle_halves"]["Price"])
    #self.movesCurr[s]["ign_prop"] = float(ign_ind) / float(move_len)
    #self.movesCurr[s]["cd_prop"] = float(cd_length) / float(move_len)

    return "entered"
    


def updateMovesPrint(self, s, close, low, high):
    if high > self.movesCurr[s]["high_move"]:
        self.movesCurr[s]["high_move"] = high

    if self.movesCurr[s]["stoppedCustom"] == 0 and close <= self.movesCurr[s]["stopCustom"]: #did it stop out, and when
        self.movesCurr[s]["stoppedCustom"] = 1
        self.movesCurr[s]["stoppedCustomTime"] = self.Time
        self.movesCurr[s]["stopCustom_highMove"] = self.movesCurr[s]["high_move"]

    if self.movesCurr[s]["stoppedLOD"] == 0 and close <= self.movesCurr[s]["stopLOD"]: #did it stop out, and when
        self.movesCurr[s]["stoppedLOD"] = 1
        self.movesCurr[s]["stoppedLODTime"] = self.Time
        self.movesCurr[s]["stopLOD_highMove"] = self.movesCurr[s]["high_move"]

    if self.Time.hour == 3 and self.Time.minute == 55 and self.Time.second == 1:
        self.movesCurr[s]["EOD_price"] = close

    return


#get high and low of move, volume
#and convert candles to 1/4 candles
#the price and volume candles of movesCurr should be the same as moves
#movesCurr is mostly just for the consol_low, so it doesn't get recent on new high
def updateMovesCurr(self, s, opened, high, low, close, vol):
        
    mins = self.timeInMin(str(self.Time).split()[1])
        
    #new low of consolidation
    if self.movesCurr[s]["consol_low"] == "NA" or low < self.movesCurr[s]["consol_low"]:
        self.movesCurr[s]["consol_low"] = low
        self.movesCurr[s]["consol_low_ind"] = calculate.get_consol_low_ind(self, self.movesCurr[s]["candle_halves"]["Price"], self.movesCurr[s]["high"], self.movesCurr[s]["consol_low"])
        
    #updateCandleHalves    
    self.movesCurr[s]["candle_halves"]["Price"][-1] = (self.movesCurr[s]["candle_halves"]["Price"][-1] + opened) / 2.0
    self.movesCurr[s]["candle_halves"]["Volume"][-1] += vol / 6.0
        
        
    if close >= opened:
        self.movesCurr[s]["candle_halves"]["Price"].append(low)
        self.movesCurr[s]["candle_halves"]["Price"].append(high)
    elif close < opened:
        self.movesCurr[s]["candle_halves"]["Price"].append(high)
        self.movesCurr[s]["candle_halves"]["Price"].append(low)

    self.movesCurr[s]["candle_halves"]["Price"].append(close)
        
    self.movesCurr[s]["candle_halves"]["Volume"].append(vol / 3.0)
    self.movesCurr[s]["candle_halves"]["Volume"].append(vol / 3.0)
    self.movesCurr[s]["candle_halves"]["Volume"].append(vol / 6.0)
        
    self.movesCurr[s]["candle_halves"]["Time"].append(mins - .667)
    self.movesCurr[s]["candle_halves"]["Time"].append(mins - .333)
    self.movesCurr[s]["candle_halves"]["Time"].append(mins)
        
    self.movesCurr[s]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
    self.movesCurr[s]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
    self.movesCurr[s]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
    
    return 0
        
        
        

#get high and low of move, volume
#and convert candles to 1/4 candles
def updateMoves(self, s, opened, high, low, close, vol, t):
    #t = time = "PM" or "RH"
        
    #init for either t
    if s not in self.moves:
        self.moves[s] = {}

    ##############################
    # ignition and consolidation #
    ##############################
        
    mins = self.timeInMin(str(self.Time).split()[1])
        
    #new low, reset everything
    if (t in self.moves[s] and low < self.moves[s][t]["low"]) or t not in self.moves[s]:
            
        #update HOD
        #it's the highest high of all previous moves
        ##so, can only exist if there is a new move
        if t == "RH" and t in self.moves[s]:
            #if s not in self.hod_level or self.moves[s]["RH"]["high"] > self.hod_level[s]:
            if s not in self.hod_level or self.hod[s] > self.hod_level[s]:
                #self.Debug("update hod_level")
                #self.Debug(self.Time)
                #self.Debug(self.moves[s]["RH"]["high"])
                    
                #self.hod_level[s] = self.moves[s]["RH"]["high"]
                self.hod_level[s] = self.hod[s]

            
        #update move
        self.moves[s][t] = {}
        self.moves[s][t]["low"] = low
            
        self.moves[s][t]["consol_low"] = "NA"
        #self.moves[s][t]["ign_vol"] = vol
        #self.moves[s][t]["consol_vol"] = 0
            
        self.moves[s][t]["candles"] = {} #reset all candles
        
        #half candles
        print_or_update.updateCandleHalves(self, s, mins, opened, high, low, close, vol, "low", t)
            
        #if first candle is red and is max of move, then high won't exist in candle_halves
        self.moves[s][t]["high"] = max(self.moves[s][t]["candle_halves"]["Price"])
        
        #if self.Time.hour == 9 and 30 < self.Time.minute < 40:
        #    self.Debug(self.Time)
        #    self.Debug(self.moves[s][t]["candle_halves"]["Price"])
        
    #new high (post new low)
    elif high > self.moves[s][t]["high"]:
        self.moves[s][t]["high"] = high
        #self.moves[s][t]["ign_vol"] += vol + self.moves[s][t]["consol_vol"]
        self.moves[s][t]["consol_low"] = "NA"
        #self.moves[s][t]["consol_vol"] = 0
            
        #half candles
        print_or_update.updateCandleHalves(self, s, mins, opened, high, low, close, vol, "high", t)
        
    #consolidation (no new high)
    else:
        #self.moves[s][t]["consol_vol"] += vol
    
        #new low of consolidation
        if self.moves[s][t]["consol_low"] == "NA" or low < self.moves[s][t]["consol_low"]:
            self.moves[s][t]["consol_low"] = low
        print_or_update.updateCandleHalves(self, s, mins, opened, high, low, close, vol, "consol_low", t)

    #always add new candle
    if "o" not in self.moves[s][t]["candles"]:
        self.moves[s][t]["candles"]["o"] = []
        self.moves[s][t]["candles"]["h"] = []
        self.moves[s][t]["candles"]["l"] = []
        self.moves[s][t]["candles"]["c"] = []
        self.moves[s][t]["candles"]["v"] = []
    self.moves[s][t]["candles"]["o"].append(opened)
    self.moves[s][t]["candles"]["h"].append(high)
    self.moves[s][t]["candles"]["l"].append(low)
    self.moves[s][t]["candles"]["c"].append(close)
    self.moves[s][t]["candles"]["v"].append(vol)
    
    return 0
        
#region imports
from AlgorithmImports import *
#endregion
from clr import AddReference
AddReference("QuantConnect.Research")
#clr.AddReference('QuantConnect.Research')

from QuantConnect.Research import QuantBook
import statistics
import pandas as pd
import numpy as np
import math
import time as tm
from sklearn.linear_model import LinearRegression
import statsmodels.formula.api as smf
import statsmodels.api as sm
import copy
from scipy.stats import zscore
import pickle
import base64
import sklearn
from sklearn.calibration import CalibratedClassifierCV
import io 
from datetime import datetime
import calendar

import calculate
import print_or_update
import longs


class TachyonMultidimensionalChamber(QCAlgorithm):

    def Initialize(self):
        
        '''
        #run for two weeks
        wk = 2
        month = 6
        yr = 2022
        if wk == 1:
            #run for first two weeks
            start_date = datetime(yr, month, 1)
            end_date = datetime(yr, month, 15)
            self.SetStartDate(start_date.year, start_date.month, start_date.day)
            self.SetEndDate(end_date.year, end_date.month, end_date.day)    
        elif wk == 2:
            #run for rest of month
            start_date = datetime(yr, month, 16)
            _, last_day_of_month = calendar.monthrange(start_date.year, start_date.month)
            self.SetStartDate(start_date.year, start_date.month, start_date.day)
            self.SetEndDate(start_date.year, start_date.month, last_day_of_month)  
        '''

        
        #run for a month 
        #start_date = datetime(2020, 4, 1)
        #_, last_day_of_month = calendar.monthrange(start_date.year, start_date.month)

        #self.SetStartDate(start_date.year, start_date.month, start_date.day)
        #self.SetEndDate(start_date.year, start_date.month, last_day_of_month)    
        

        #run for a day
        self.SetStartDate(2021, 6, 11)  # Set Start Date
        self.SetEndDate(2021, 6, 11) # Set End Date
        

        #set these values        
        self.symbol = "NVDA" #set this to "" and it will do all, set to "<symbol>" for that symbol
        self.got_to_time = "" #"" if don't report, else do format colon-delimited time e.g., "9:35"
        self.EODmodels_in_PM = 0 #1 if calc models in PM (e.g., running live), 0 if not (e.g., backtesting)
        self.sharpeThresh = "" #"" if no threshold
        self.printMinimal = 1 #1 for just entries and exits, 0 for more stuff

        #do other stuff
        self.SetCash(400000)  # Set Strategy Cash
        self.AddUniverse(self.CoarseSelectionFunction)
        
        self.SetSecurityInitializer(self.SecurityInitializer)
        
        self.UniverseSettings.ExtendedMarketHours = True
        #self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
        self.SetBrokerageModel(BrokerageName.TradierBrokerage, AccountType.Margin)
        self.UniverseSettings.Leverage = 4
        self.UniverseSettings.Resolution = Resolution.Second #can comment/change this out
        #self.SetWarmUp(5)

        
        for s in self.Securities:
            self.Debug(self.Securities[s])
        
        
        ###variables to keep track of
        self.sd = {} #all symbol data
        self.initVars()
        
        
    def initVars(self):
        self.pastNoPre = {}

        self.movesCurr = {} #moves for those currently in position
        self.moves = {} #this has both PM and RH moves
        self.ranges = {}
        
        self.curr_ranges = {} #ranges for a certain day, for updateRangesMultiple()
        self.pastSixty = {}
        self.models = {}
        
        self.dollar_risk = 50.0 #size of positins in dollars
        
        #pm
        self.pmHigh = {}
        self.pmLow = {}
        self.pmVol = {}
        self.pmNonZeroVol = {}
        self.everBelowOneDollar = set()
        self.PM_atSelection = {}
        #
        
        self.prevVWMA = {}
        self.prevVWAP = {}
        
        self.end = tm.time()
        self.start = tm.time()
        
        self.dailyLevels = {}
        
        self.hod = {}
        self.lod = {}
        self.hod_level = {} #hod and lod for calculating daily range
        self.lod_level = {}
        self.open = {}

        self.positions = {} #symbol, and misc things about position entry/exit

        self.minutes = {} #n minutes of data for each symbol

        self.everPosition = {}

        self.buffer = 0 #only enter trades after N buffer after open (prob just 1 minute)

        #error reports
        self.max_arg_empty_seq = set()
        self.calc_EMA_error = set()
        self.VWMA_vol_zero = set()
        self.EMAwPMerror = set()
        self.EMAerrorLong = set()
        self.EMAerrorShort = set()
        self.EODmodelErr = set()
        self.avgdevoob = set()
        self.notInPMHigh = set()
        self.CDerror = set()
        self.AVWAPerror = set()
        self.noVolVWAP = set()

        #prevPrices, for EMA calc -- if they are the same, don't need to recalculate EMA
        self.prevPrices = {}
        self.prevPrices["ab"] = {}
        self.prevPrices["ab_wPM"] = {}
        self.prevPrices["bc"] = {}
        self.prevPrices["cd"] = {}
        self.prevPrices["postbreak"] = {}
        self.prevPrices["ab_inpos"] = {}
        
        self.prevStartPeriod = {}
        self.prevStartPeriod["ab"] = {}
        self.prevStartPeriod["ab_wPM"] = {}
        self.prevStartPeriod["bc"] = {}
        self.prevStartPeriod["cd"] = {}
        self.prevStartPeriod["postbreak"] = {}
        self.prevStartPeriod["ab_inpos"] = {}
    
        #EOD model things
        self.EODmodels = {}
        self.EODmodels_entry = {}
        
        #times (just regular hours), debugging
        self.times = {}
        self.s_times = {}

        #end day early
        self.stop_trading = 0
        self.stop_entering = 0

        #check these on shorter tf than 1 minute
        self.staging = {}

        #model coefficients for 
        self.content = {}

        #has printed out yet
        self.EOD = 0

        #model
        self.calibrated = ""

        #yday ohlc
        self.ydays = {}

        #4 min volume
        self.rhvol3 = {}

    def SecurityInitializer(self, security):
        security.SetLeverage(4)
    
    
    def CoarseSelectionFunction(self, universe):  
        selected = []
        blacklist = set()

        for coarse in universe:  
            #if coarse.Volume > 5000000 and coarse.Value > 1 and coarse.HasFundamentalData: 
            if self.symbol != "": 
                if coarse.Symbol.Value == self.symbol:
                    symbol = coarse.Symbol
                    selected.append(symbol)
            elif coarse.Volume > 2000000 and coarse.Value > .90 and coarse.HasFundamentalData:
                if coarse.Symbol.Value not in blacklist:
                    symbol = coarse.Symbol
                    selected.append(symbol)
        return selected #list of objects of type Symbol
    
    
    def OnSecuritiesChanged(self, changed):
        for security in changed.AddedSecurities:
            symbol = security.Symbol
            if symbol not in self.sd:
                self.sd[symbol] = SymbolData(self, symbol)
            security.SetFeeModel(ConstantFeeModel(0))
        for security in changed.RemovedSecurities:
            symbol = security.Symbol
            self.sd.pop(symbol, None)

    ###reset these every day
    def OnEndOfDay(self):
        for s in self.sd:
            self.sd[s].vwap.Reset()
        self.initVars()


    ################
    # functions #
    ################
    ###sizing
    def positionSize(self, stop, currPrice, dollars_risk, spread):
        #nShares_spread = math.floor(dollars_risk / (abs(stop - currPrice) + 2.0*spread + .001) ) #these are with .1 cents per share fee
        #nShares = math.floor(dollars_risk / abs(stop - currPrice) + .001)

        nShares_spread = math.floor(dollars_risk / (abs(stop - currPrice) + 2.0*spread) ) #2.0 spread for entry and exit
        nShares = math.floor(dollars_risk / abs(stop - currPrice))

        return nShares_spread, nShares
    
    
    #do this every second if in position      
    def take_profit(self, s, close, high, low):
        if close >= self.positions[s]["take_profit"] and self.Portfolio[s].Invested:
            self.Debug("Exited: " + s.Value + " " + str(self.Time))
            self.Liquidate(s)
            self.Transactions.CancelOpenOrders(s)
            if s in self.positions:
                del self.positions[s]
        return


    #time is premarket or not
    #time of format: HH:MM:SS
    def isPM(self, clock):
        hour, minute, sec = clock.split(":")
        if int(hour) < 9:
            return 1
        if int(hour) == 9 and int(minute) < 31:
            return 1
        return 0

    def isAH(self, clock):
        hour, minute, sec = clock.split(":")
        if int(hour) > 16 or (int(hour) == 16 and int(minute) > 0):
            return 1
        return 0
    
    #time in minutes (since midnight)
    def timeInMin(self, clock):
        hour, minute, sec = clock.split(":")
        return (int(hour)*60) + int(minute)
    
    def timeInSec(self, clock):
        hour, minute, sec = clock.split(":")
        return (int(hour)*3600) + (int(minute)*60) + int(sec)

    #read in and calibrate xgboost model
    def read_and_calibrate_model(self):

        base64_model = self.Download("https://www.dropbox.com/s/38ro5pddzmsucge/xgboost_withAVWAP_Jan21-Dec22_minusJanJuneJuneDec_uncalibrated.base64?dl=1")
        base64_bytes_model = base64_model.encode('ascii')
        decoded_model = base64.b64decode(base64_bytes_model)
        clf = pickle.loads(decoded_model)

        data = self.Download("https://www.dropbox.com/s/b4qbls7qgcodaov/Jan21-Dec22_minusJanJunJunDec_test.txt?dl=1")
        df = pd.read_csv(io.StringIO(data), sep="\t")

        X = df[["RR.10", "GRP_day", "GRP_CD_scaled", "CD_wRVOL_x_GRP", "wRVOL_CD_scaled", "PercChangeEMA3", "PercChangeEMA5", "PercChangeEMA8", "PercFromPriceEMA3", "PercFromPriceEMA5",  "PercFromPriceEMA8", "PercChangeAVWAP3", "PercChangeAVWAP5", "PercChangeAVWAP8", "PercFromPriceAVWAP3", "PercFromPriceAVWAP5", "PercFromPriceAVWAP8", "pm_high_bw_target", "yday_high_bw_target", "yday_close_bw_target", "today_open_bw_target", "yday_low_bw_target", "pm_low_bw_target", "pm_high_bw_stop", "yday_high_bw_stop", "yday_close_bw_stop", "today_open_bw_stop"]]
        y = df[["ReachedTarget"]]

        '''
        #calibrated = CalibratedClassifierCV(clf, method='isotonic', cv=2) #if you don't use cv='prefit' it times out
        try:
            calibrated = CalibratedClassifierCV(clf, method='isotonic', cv='prefit') #isotonic or sigmoid
            calibrated.fit(X, y.values.ravel())
        except:
            calibrated = clf
        '''
        
        calibrated = CalibratedClassifierCV(clf, method='isotonic', cv='prefit') #isotonic or sigmoid
        calibrated.fit(X, y.values.ravel())

        return calibrated


    ########### 
    # on data #
    ###########
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
            Arguments:
                data: Slice object keyed by symbol containing the stock data
        '''

        #close all at 3:55 if any positions are open
        #should change this to time to market close
        #use BeforeMarketClose()
        if self.Time.hour >= 15 and self.Time.minute >= 55 and self.EOD == 0: 
            self.Debug("Stopping -- EOD 3:55")

            print_or_update.printMoves(self)

            self.EOD = 1
            self.positions = {}
            self.Liquidate()

            return

        #stop trading at whatever time e.g., noon
        #then, after market closes, allow trading again for the next day
        if self.stop_trading != 0:
            return



        if self.Time.hour == 4 and self.Time.minute == 1 and self.Time.second == 1:
            self.initVars()
            self.Debug("Number of symbols: ")
            self.Debug(len(self.sd))

        #every minute:
        #check if below 1, if so remove
            #only do this in PM (?)
        #reset list of symbols to stage
        if self.Time.second == 1:
            for s in self.everBelowOneDollar:
                if s in self.ranges:
                    del self.ranges[s]
                if s in self.sd:
                    del self.sd[s]

            self.staging = {}

        #remove stocks without premarket action
        if self.Time.hour == 9 and self.Time.minute == 0 and self.Time.second == 1:
            
            self.Debug("stocks before pm removal: " + str(len(self.sd)))
            toremove = set()
            for s in self.sd:
                if s in self.pmVol and s in self.pmNonZeroVol:
                    if self.pmVol[s] < 5000 or self.pmNonZeroVol[s] < 20:
                        toremove.add(s)
                elif s not in self.pmHigh:
                    toremove.add(s)
                
            for s in toremove:
                if s in self.sd:
                    del self.sd[s]
                    
            self.Debug("stocks after pm removal: " +  str(len(self.sd)))
            
            for s in self.sd:
                if s in self.pmVol and s in self.pmNonZeroVol:
                    #self.Debug(str(s))
                    #self.Debug(self.pmVol[s]) 
                    #self.Debug(self.pmNonZeroVol[s]) 

                    self.PM_atSelection[s] = {}
                    self.PM_atSelection[s]["pmvol"] = self.pmVol[s]
                    self.PM_atSelection[s]["pm_nonzero"] = self.pmNonZeroVol[s]
            
            #get model
            #self.calibrated = self.read_and_calibrate_model() 

            #calculate EOD models
            if self.EODmodels_in_PM == 1:
                for s in self.sd:
                    if self.Time.hour == 9 and self.Time.minute < 29:
                        try:
                            model, today_row, yday_ohlc, sd, mean_vols = calculate.modelEODRange(self, s)

                            self.EODmodels[s] = [model, today_row, yday_ohlc]
                        except Exception as e:
                            self.Debug(e)
                            self.EODmodelErr.add(s.Value)
                            return "EOD_model_error_1"

        self.startTime = tm.time()
        for s in self.sd:   
            
            start = tm.time()
            
            if data.ContainsKey(s) and data.Bars.ContainsKey(s) and self.Time.hour < 16:
                second = data.Bars
                if s not in self.pastSixty:
                    self.pastSixty[s] = {}
                    self.pastSixty[s]["o"] = second[s].Open
                    self.pastSixty[s]["h"] = second[s].High
                    self.pastSixty[s]["l"] = second[s].Low
                    self.pastSixty[s]["v"] = second[s].Volume
                    self.pastSixty[s]["spread"] = [self.Securities[s].AskPrice - self.Securities[s].BidPrice]
                else:
                    #update
                    if second[s].Open > self.pastSixty[s]["h"]:
                        self.pastSixty[s]["h"] = second[s].High
                    if second[s].Low < self.pastSixty[s]["l"]:
                        self.pastSixty[s]["l"] = second[s].Low
                    self.pastSixty[s]["v"] += second[s].Volume
            
                    self.pastSixty[s]["spread"].append(self.Securities[s].AskPrice - self.Securities[s].BidPrice)

                if self.Time.second == 1: #should this be 1 actually? 
                    #add 1 more minute for this symbol
                    if s not in self.minutes:
                        self.minutes[s] = 1
                    else:
                        self.minutes[s] += 1
                    
                    #if s in self.positions:
                    #    self.Debug(self.Portfolio[s].Quantity)
                    
                    ############################################################
                    # store ohlcv for past self.keepPast candles, with premarket #
                    ############################################################
                    
                    ###consolidate past 60 seconds
                    opened = self.pastSixty[s]["o"]
                    high = self.pastSixty[s]["h"]
                    low = self.pastSixty[s]["l"]
                    close = second[s].Close
                    vol = self.pastSixty[s]["v"]
                    currRange = self.pastSixty[s]["h"] - self.pastSixty[s]["l"]
                    
                    #re-init with current second
                    self.pastSixty[s]["o"] = second[s].Open
                    self.pastSixty[s]["h"] = second[s].High
                    self.pastSixty[s]["l"] = second[s].Low
                    self.pastSixty[s]["v"] = second[s].Volume
                    self.pastSixty[s]["spread"] = [self.Securities[s].AskPrice - self.Securities[s].BidPrice]

                    #save pmHigh
                    #put this in a function
                    if not self.IsMarketOpen(s):
                        if s not in self.pmHigh:
                            self.pmHigh[s] =  high
                            self.pmLow[s] = low
                            self.pmVol[s] = vol
                            self.pmNonZeroVol[s] = 0
                        
                        if high > self.pmHigh[s]:
                            self.pmHigh[s] =  high

                        if low < self.pmLow[s]:
                            self.pmLow[s] = low   

                        self.pmVol[s] += vol
                        if vol != 0:
                            self.pmNonZeroVol[s] += 1
                        if low < 1:
                            self.everBelowOneDollar.add(s)
            
            
                    longs.updateMoves(self, s, opened, high, low, close, vol, "PM")
            
                                        
                    #update moves
                    if s in self.positions:
                        longs.updateMovesCurr(self, s, opened, high, low, close, vol)
                
                    #these are to print out the positions, for modeling
                    if s in self.everPosition: 
                        longs.updateMovesPrint(self, s, close, low, high)


                    #market is open now
                    if self.IsMarketOpen(s) and self.buffer == 1 and self.stop_entering == 0:
                        if s not in self.open:
                            self.open[s] = opened
            
                        ##########################################################
                        # save ohlcv of intraday candles (save range separately) #
                        ##########################################################
                        if s not in self.pastNoPre:
                            self.pastNoPre[s] = {}
                            self.pastNoPre[s]["o"] = []
                            self.pastNoPre[s]["h"] = []
                            self.pastNoPre[s]["l"] = []
                            self.pastNoPre[s]["c"] = []
                            self.pastNoPre[s]["v"] = []
                            self.pastNoPre[s]["VWAP"] = []
                            self.pastNoPre[s]["mean_spread"] = []

                        self.pastNoPre[s]["o"].append(opened)
                        self.pastNoPre[s]["h"].append(high)
                        self.pastNoPre[s]["l"].append(low)
                        self.pastNoPre[s]["c"].append(close)
                        self.pastNoPre[s]["v"].append(vol)
                        self.pastNoPre[s]["VWAP"].append(self.sd[s].vwap.Current.Value)
                        self.pastNoPre[s]["mean_spread"].append(statistics.mean(self.pastSixty[s]["spread"]))

                        #volume in first 4 minutes
                        if s not in self.rhvol3 and len(self.pastNoPre[s]["v"]) >= 4:
                            self.rhvol3[s] = self.pastNoPre[s]["v"][0] + self.pastNoPre[s]["v"][1] + self.pastNoPre[s]["v"][2] + self.pastNoPre[s]["v"][3]

                        ################################
                        # price, volume, time of moves #
                        # ranges                       #
                        # levels                       #
                        # EMAs (trend)                 #
                        ################################

                        longs.updateMoves(self, s, opened, high, low, close, vol, "RH")
                    
                        #######################
                        # HOD and LOD, for range calc #
                        # these are not necessarily levels
                        # literally just HOD and LOD
                        #######################
                        if s not in self.hod or (s in self.hod and high > self.hod[s]):
                            self.hod[s] = high

                        if s not in self.lod or (s in self.lod and low < self.lod[s]):
                            self.lod[s] = low
                    
                        #########
                        # entry #
                        #########
                        if s not in self.positions: #perhaps comment this out when actually running, instead of just printing out
                            if s not in self.everPosition: #one entry per day
                                got_to = longs.enter(self, s, close)
                                print_or_update.print_got_to(self, got_to, self.got_to_time)
                        

                        ###################
                        # previous values #
                        ###################
                        self.prevVWAP[s] = self.sd[s].vwap.Current.Value
                
                        
                    ##############################
                    # debugging                  #
                    # print things out for test  #
                    ##############################
                    
                    
                    #if self.Time.hour == 9 and self.Time.minute == 45:
                    #    print_or_update.printCandleHalves(self, s)
                    
                    
                    #if self.Time.hour == 11 and self.Time.minute == 19:
                    #    if s in self.positions:
                    #        self.printCandleHalvesCurr(s)
                    
                    
                #########################################
                # adjustments and exit                  #
                # check/update every second, not minute #
                #########################################

                #every second see if hit T/P
                if s in self.positions:

                    self.take_profit(s, second[s].Close, second[s].High, second[s].Low)    

                    #get price 10 seconds after entry (for modeling time delay)
                    if self.timeInSec(str(self.Time).split()[1]) == self.movesCurr[s]["time_in_sec"] + 10:
                        self.movesCurr[s]["10_seconds_after"] = second[s].Close

                #############################################################
                # if not in position, close all open orders for that symbol #
                #############################################################
                if not self.Portfolio[s].Invested: 
                    self.Transactions.CancelOpenOrders(s)

                    #openOrders = self.Transactions.GetOpenOrders()
                    #if len(openOrders)> 0:
                    #    self.Debug(self.Time)
                    #    for x in openOrders:
                    #       self.Debug(x)
                    #       self.Transactions.CancelOrder(x.Id)
                    #self.Transactions.CancelOpenOrders(s)

                ################################################
                # if symbol is in staging from previous minute #
                ################################################
                if s in self.staging:
                    #if self.Time.second == 1:
                        #self.staging[s]["volumes_thisMin"] = []
                        #self.staging[s]["closes_thisMin"] = []
                    #self.staging[s]["volumes_thisMin"].append(second[s].Volume)
                    #self.staging[s]["closes_thisMin"].append(second[s].Close)
                    
                    if self.Time.second % 10 == 1:
                        got_to = longs.enter_staged(self, s, second[s].Close, self.staging[s]["max_broken"], self.staging[s]["pred"], self.staging[s]["levels"], self.staging[s]["EMAs"], self.staging[s]["mean_vols"], self.staging[s]["sd"], self.staging[s]["rsq"])
            
                        print_or_update.print_got_to(self, got_to, self.got_to_time)
            
            #count total time for each ticker
            end = tm.time()
            if s not in self.times:
                self.times[s] = 0
            self.times[s] += (end - start)              


        #no new entries after 11
        if self.Time.hour >= 11 and self.stop_entering == 0:
            self.Debug("11:00 -- no new positions")
            self.stop_entering = 1

            self.Debug("max() arg is empty sequence:")
            for s in self.max_arg_empty_seq:
                self.Debug(s.Value)
    
            self.Debug("Volume in VWMA is 0: " + str(self.VWMA_vol_zero))
            #for s in self.VWMA_vol_zero:
            #    self.Debug(s.Value)
    
            self.Debug("calc EMA error:")
            for s in self.calc_EMA_error:
                self.Debug(s.Value)
                
            self.Debug("calc EMA wPM error:")  
            for s in self.EMAwPMerror:
                self.Debug(s.Value)
                    
            self.Debug("calc EMA long error:")
            for s in self.EMAerrorLong:
                self.Debug(s.Value)

            #self.Debug("ever positions:")
            #for s in self.everPosition:
            #    self.Debug(str(s.Value) + "\t" + str(self.everPosition[s]["time"]))

            self.Debug("EOD model error: " + str(self.EODmodelErr))
            #self.Debug(EODmodelErr)
            #for s in self.EODmodelErr:
            #    self.Debug(str(s.Value))

            self.Debug("no volume for VWAP: " + str(self.noVolVWAP))

            self.Debug("avg dev ign ind oob: ")
            for s in self.avgdevoob:
                self.Debug(str(s.Value))

            self.Debug("CD GRP error: " + str(self.CDerror))
            #for s in self.CDerror:
            #    self.Debug(s.Value)

            self.Debug("AVWAP error: ")
            for s in self.AVWAPerror:
                self.Debug(s.Value)

            profit_s = {}
            for s in self.everPosition:
                profit_s[self.Portfolio[s].NetProfit] = s
                
            #for profit in sorted(profit_s):
            #    self.Debug("net profit " + profit_s[profit].Value + ": " + str(profit))
            
            #print_or_update.printEverPosition(self)
            #print_or_update.printMoves(self)

            #if no current positions
            if not self.positions:
                self.stop_trading = 1


        #first minute has passed
        if self.sd and self.IsMarketOpen(s) and self.buffer == 0 and self.Time.minute == 31:
        #if self.Time.hour == 9 and self.Time.minute == 31 and self.buffer == 0:
            self.buffer = 1
        
    def exit(self, s):
        self.Debug("Exited")
        self.Debug(s.Value)
        self.Debug(self.Time)
        self.Liquidate(s)
        self.Transactions.CancelOpenOrders(s)
        if s in self.positions:
            del self.positions[s]
        
        return

class SymbolData:
    def __init__(self, algorithm, symbol):
        self.vwap = algorithm.VWAP(symbol, 2000, Resolution.Minute) #60*24 = 1440 minutes in a day
        prehist = algorithm.History(symbol, 10, Resolution.Minute)
        
        if not prehist.empty:
            hist = prehist.loc[symbol]
            
            if 'volume' not in prehist.columns:
                #algorithm.Log(f"No volume: {symbol}") #don't need to output b/c makes log longer
                #self.noVolVWAP.add(str(symbol)) #Runtime Error: 'SymbolData' object has no attribute 'noVolVWAP'
                return
            
            for idx, bar in hist.iterrows():
                tradeBar = TradeBar(idx, symbol, bar.open, bar.high, bar.low, bar.close, bar.volume, timedelta(minutes=1))
                self.vwap.Update(tradeBar)
    
#region imports
from AlgorithmImports import *
#endregion

#print out table of ranges
def print_ranges(self, s):    
    #self.Debug("Period\tOpen\tHigh\tLow\tClose\tVolume\tDistance\tMins_since_first\tTime\tDate")
    self.Debug("Period\tClose_minus_open\tVolume\tMins_since_first") #start is Mins_since_first - Period
    for date in self.ranges[s]:
        for period in sorted(self.ranges[s][date]):
            for i in range (0, len(self.ranges[s][date][period]["high"])):
                #self.Debug(str(period) + "\t" + str(round(self.ranges[s][period]["open"][i], 2)) + "\t" + str(round(self.ranges[s][period]["high"][i], 2)) + "\t" + str(round(self.ranges[s][period]["low"][i], 2)) + "\t" + str(round(self.ranges[s][period]["close"][i], 2)) + "\t" + str(self.ranges[s][period]["vol"][i]) + "\t" + str(self.ranges[s][period]["time"][i]))
                #self.Debug(str(period) + "\t" + str(round(self.ranges[s][date][period]["open"][i], 2)) + "\t" + str(round(self.ranges[s][date][period]["high"][i], 2)) + "\t" + str(round(self.ranges[s][date][period]["low"][i], 2)) + "\t" + str(round(self.ranges[s][date][period]["close"][i], 2)) + "\t" + str(self.ranges[s][date][period]["vol"][i]) + "\t" + str(round(self.ranges[s][date][period]["dist"][i], 2)) + "\t" + str(self.ranges[s][date][period]["minute"][i]) + "\t" + str(self.ranges[s][date][period]["time"][i]) + "\t" + date)
                self.Debug(str(period) + "\t" + str(round(self.ranges[s][date][period]["close"][i] - self.ranges[s][date][period]["open"][i], 2)) + "\t" + str(self.ranges[s][date][period]["vol"][i]) + "\t" + str(self.ranges[s][date][period]["minute"][i]))
                

'''
#low of consolidation to current price, postbreak
#so, use movesCurr
def calc_consolEMA(self, s):
    #get consol low to current price
    consol_low_prices = []
    hit_high = 0
    consol_low = 2000000000
    for p in self.moves[s]["RH"]["candle_halves"]["Price"]:
        #consolidating, get the low
        if hit_high == 1:
            #if new low, reset
            if p < consol_low:
                consol_low = p
                consol_low_prices = []
            consol_low_prices.append(p)
        #past high of the move
        elif p == self.moves[s]["RH"]["high"]:
            hit_high = 1
        
    if len(consol_low_prices) == 0:
        return "NAN"
    
    #midpoint, and low of consolidation to high of consolidation post-low
    midpoint_consol = ((max(consol_low_prices) + min(consol_low_prices)) / 2.0)
    consol_low_to_high = []
    for p in consol_low_prices:
        consol_low_to_high.append(p)
        if p == max(consol_low_prices):
            break

    #only need to recalc if it's going to be different
    start_consol = "N"
    EMA_period_consol = "A"
    if s not in self.prevStartPeriod["cd"] or consol_low_to_high != self.prevPrices["cd"][s]:
        start_consol, EMA_period_consol = EMA_midpoint(self, s, consol_low_to_high, midpoint_consol)
        self.prevStartPeriod["cd"][s] = str(start_consol) + " " + str(EMA_period_consol)
        self.prevPrices["cd"][s] = consol_low_to_high
    else:
        start_consol, EMA_period_consol = self.prevStartPeriod["cd"][s].split()

        
    if not (start_consol != "N" and EMA_period_consol != "A"):
        self.Debug("is NA")
        return
    
    adj_closes_EMA_consol = []
    try:
        adj_closes_EMA_consol = consol_low_prices[int(start_consol):] 
    except:
        self.Debug("adj_closes_EMA_consol error")
        self.Debug(s)
    adj_closes_EMA_consol[0] = consol_low_prices[0]
        
    currEMA_consol, EMAs_consol = self.calcEMA(s, adj_closes_EMA_consol, EMA_period_consol)
    
    return currEMA_consol, EMAs_consol, start_consol
'''
#region imports
from AlgorithmImports import *
#endregion
import calculate




def printMoves(self):

    ################
    # print header #
    ################
    #Ticker Date Time Entry Stop_custom Stop_LOD Time_stopped_custom Time_stopped_LOD Max_moved_before_stop_custom Max_moved_before_stop_LOD EOD_price Percentage_moves_[.10..95]    
    header = "Ticker\tDate\tEntry_time\tMinutes_since_opened\tEntry_price\tEntry_price_10s\tSpread\t"
    header += "Current_range\tLOD_entry\tHOD_entry\t"
    header += "Stop\tStop_LOD\tStop_risk\tStop_LOD_risk\tRR\t"
    header += "GRP_day\tGRP_total_move\tGRP_ignition\tGRP_consol\tGRP_CD\tw_GRP_CD\t"
    header += "RVOL_CD_day\tw_RVOL_CD_day\tRVOL_ignition_day\t"
    header += "Prop_len_ign_move\tProp_len_CD_move\tProp_len_move_day\tProp_vol_move_day\t"
    header += "RVOL20_RH\tRVOL20_PM\tRVOL20_sum\t"
    header += "BD_SMA\tCD_SMA\t"

    header += "PercFromPriceEMA2\tPercFromPriceEMA3\tPercFromPriceEMA4\tPercFromPriceEMA5\t"
    header += "PercFromPriceEMA6\tPercFromPriceEMA7\tPercFromPriceEMA8\tPercFromPriceEMA9\t"
    header += "PercFromPriceEMA10\tPercFromPriceEMA20\tPercFromPriceEMA50\tPercFromPriceEMA200\t"
    
    header += "PercChangeEMA2\tPercChangeEMA3\tPercChangeEMA4\tPercChangeEMA5\t"
    header += "PercChangeEMA6\tPercChangeEMA7\tPercChangeEMA8\tPercChangeEMA9\t"
    header += "PercChangeEMA10\tPercChangeEMA20\tPercChangeEMA50\tPercChangeEMA200\t"

    header += "PercFromPriceAVWAP2\tPercFromPriceAVWAP3\tPercFromPriceAVWAP4\tPercFromPriceAVWAP5\t"
    header += "PercFromPriceAVWAP6\tPercFromPriceAVWAP7\tPercFromPriceAVWAP8\tPercFromPriceAVWAP9\t"
    header += "PercFromPriceAVWAP10\tPercFromPriceAVWAP20\tPercFromPriceAVWAP50\tPercFromPriceAVWAP200\t"

    header += "PercChangeAVWAP2\tPercChangeAVWAP3\tPercChangeAVWAP4\tPercChangeAVWAP5\t"
    header += "PercChangeAVWAP6\tPercChangeAVWAP7\tPercChangeAVWAP8\tPercChangeAVWAP9\t"
    header += "PercChangeAVWAP10\tPercChangeAVWAP20\tPercChangeAVWAP50\tPercChangeAVWAP200\t"

    header += "gt_yday_high\tlt_yday_low\t"

    header += "pm_high\tpm_low\tyday_high\tyday_low\tyday_close\ttoday_open\t"
    
    header += "pm_high_bw_target\tpm_low_bw_target\tyday_high_bw_target\tyday_low_bw_target\tyday_close_bw_target\ttoday_open_bw_target\t"
    header += "pm_high_bw_stop\tpm_low_bw_stop\tyday_high_bw_stop\tyday_low_bw_stop\tyday_close_bw_stop\ttoday_open_bw_stop\t"
    header += "LOD_support\tHOD_resistance\t"

    header += "Time_stopped\tTime_stopped_LOD\t"
    header += "High_post_entry\tHigh_before_stop\tHigh_before_stop_LOD\tEOD_price\tpred_EOD_range\tresid_SD\tresid_SD_div_pred_EOD_range\tmodel_R2\tPercentileEOD\tPropEOD"

    self.Debug(header)

    ################
    # print values #
    ################
    for s in self.everPosition:

        ###values
        close = self.pastSixty[s]["o"]

        stop_custom_risk = str(self.movesCurr[s]["entry"] - self.movesCurr[s]["stopCustom"])
        stop_LOD_risk = str(self.movesCurr[s]["entry"] - self.movesCurr[s]["stopLOD"])

        #min since open
        min_since_open = (self.movesCurr[s]["time_in_sec"] - 34201 ) / 60.0

        ###print
        toprint = s.Value + "\t" + str(self.Time).split()[0] + "\t" + str(self.movesCurr[s]["time"]).split()[1] + "\t" + str(min_since_open) + "\t" + str(self.movesCurr[s]["entry"]) + "\t" + str(self.movesCurr[s]["10_seconds_after"]) + "\t" + str(self.movesCurr[s]["spread"]) + "\t"
        toprint += str(self.movesCurr[s]["curr_range"]) + "\t" + str(self.movesCurr[s]["entryLOD"]) + "\t" + str(self.movesCurr[s]["entryHOD"]) + "\t"
        toprint += str(self.movesCurr[s]["stopCustom"]) + "\t" + str(self.movesCurr[s]["stopLOD"]) + "\t" + stop_custom_risk + "\t" + stop_LOD_risk + "\t" + str(self.everPosition[s]["R:R"]) + "\t"
        toprint += str(self.movesCurr[s]["grp_day"]) + "\t" + str(self.movesCurr[s]["grp_tot"]) + "\t" + str(self.movesCurr[s]["grp_ign"]) + "\t" + str(self.movesCurr[s]["grp_consol"]) + "\t" + str(self.movesCurr[s]["grp_cd"]) + "\t" + str(self.movesCurr[s]["w_grp_cd"]) + "\t"
        toprint += str(self.movesCurr[s]["rvol_CD_day"]) + "\t" + str(self.movesCurr[s]["w_rvol_CD_day"]) + "\t" + str(self.movesCurr[s]["rvol_ign_day"]) + "\t"
        toprint += str(self.movesCurr[s]["prop_len_ign"]) + "\t" + str(self.movesCurr[s]["prop_len_CD"]) + "\t" + str(self.movesCurr[s]["prop_len_move_day"]) + "\t" + str(self.movesCurr[s]["move_day_vol"]) + "\t"
        toprint += str(float(self.rhvol3[s])/self.movesCurr[s]["mean_vols"][0]) + "\t" + str(self.pmVol[s]/self.movesCurr[s]["mean_vols"][1]) + "\t" + str((float(self.rhvol3[s]) + self.pmVol[s])/self.movesCurr[s]["mean_vols"][2]) + "\t"
        toprint += str(self.movesCurr[s]["bd_SMA"]) + "\t" + str(self.movesCurr[s]["cd_SMA"]) + "\t"

        for i in range(0, len(self.movesCurr[s]["perc_aways"])):
            toprint += str(self.movesCurr[s]["perc_aways"][i]) + "\t"

        for i in range(0, len(self.movesCurr[s]["perc_changes"])):
            toprint += str(self.movesCurr[s]["perc_changes"][i]) + "\t"

        for avwap in self.movesCurr[s]["perc_aways_avwap"]:
            toprint += str(self.movesCurr[s]["perc_aways_avwap"][avwap]) + "\t"

        for avwap in self.movesCurr[s]["perc_changes_avwap"]:
            toprint += str(self.movesCurr[s]["perc_aways_avwap"][avwap]) + "\t"
        
        toprint += str(self.movesCurr[s]["gt_yday_high"]) + "\t" + str(self.movesCurr[s]["lt_yday_low"]) +"\t"

        toprint += str(self.movesCurr[s]["pm_high"]) + "\t" + str(self.movesCurr[s]["pm_low"]) + "\t" + str(self.movesCurr[s]["yday_high"]) + "\t" + str(self.movesCurr[s]["yday_low"]) + "\t" + str(self.movesCurr[s]["yday_close"]) + "\t" + str(self.movesCurr[s]["today_open"]) + "\t"

        #levels
        for levels in ["resistance", "support"]:
            toprint += str(self.movesCurr[s][levels]["pm_high"]) + "\t" + str(self.movesCurr[s][levels]["pm_low"]) + "\t" + str(self.movesCurr[s][levels]["yday_high"]) + "\t" + str(self.movesCurr[s][levels]["yday_low"]) + "\t" + str(self.movesCurr[s][levels]["yday_close"]) + "\t" + str(self.movesCurr[s][levels]["today_open"]) + "\t" 

        toprint += str(self.movesCurr[s]["support"]["lod"]) + "\t" + str(self.movesCurr[s]["resistance"]["hod"]) + "\t"

        toprint += str(self.movesCurr[s]["stoppedCustomTime"]) + "\t" + str(self.movesCurr[s]["stoppedLODTime"]) + "\t"

        if str(self.movesCurr[s]["stopCustom_highMove"]) == "NA":
            self.movesCurr[s]["stopCustom_highMove"] = self.movesCurr[s]["high_move"]
        if str(self.movesCurr[s]["stopLOD_highMove"]) == "NA":
            self.movesCurr[s]["stopLOD_highMove"] = self.movesCurr[s]["high_move"]

        toprint += str(self.movesCurr[s]["high_move"]) + "\t" + str(self.movesCurr[s]["stopCustom_highMove"]) + "\t" + str(self.movesCurr[s]["stopLOD_highMove"]) + "\t" + str(close) + "\t"
        toprint += str(self.movesCurr[s]["pred"]) + "\t" + str(self.movesCurr[s]["residual_sd"]) + "\t" + str(self.movesCurr[s]["residual_sd"] / self.movesCurr[s]["pred"]) + "\t" + str(self.movesCurr[s]["model_rsq"]) + "\t" 
        toprint += str(self.movesCurr[s]["percentile"]) + "\t" + str(self.movesCurr[s]["curr_range"] / self.movesCurr[s]["pred"])

        #round to 4 decimal places, to make log smaller
        toprint_list = toprint.split("\t")
        toprint_rounded = ""
        for l in toprint_list:
            try:
                val = round(float(l), 4)
                toprint_rounded += str(val) + "\t"
            except:
                toprint_rounded += l + "\t"
        
        self.Debug(toprint_rounded.rstrip())

    return


        
#add to "candle_halves", every half of candle
def updateCandleHalves(self, s, mins, opened, high, low, close, vol, typeOfCandle, t):
        
    #new point every 20 seconds
    #change between earlier high or low depending on if candle red or green
        
    #init new move
    if "candle_halves" not in self.moves[s][t] or typeOfCandle == "low":
        self.moves[s][t]["candle_halves"] = {}
        self.moves[s][t]["candle_halves"]["Price"] = []
        self.moves[s][t]["candle_halves"]["Volume"] = []
        self.moves[s][t]["candle_halves"]["Time"] = []
        self.moves[s][t]["candle_halves"]["Time_wall"] = []
            
        #add first candle, start at low
        self.moves[s][t]["candle_halves"]["Price"].append(low)
        self.moves[s][t]["candle_halves"]["Volume"].append(vol / 3.0)
        self.moves[s][t]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
            
        if close >= opened:
            self.moves[s][t]["candle_halves"]["Price"].append(high)
            self.moves[s][t]["candle_halves"]["Volume"].append(vol / 3.0)
            self.moves[s][t]["candle_halves"]["Time"].append(mins - .667)
            self.moves[s][t]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
        self.moves[s][t]["candle_halves"]["Time"].append(mins - .333)

        #always add the close
        self.moves[s][t]["candle_halves"]["Price"].append(close)
        self.moves[s][t]["candle_halves"]["Volume"].append(vol / 6.0)
        self.moves[s][t]["candle_halves"]["Time"].append(mins)
        self.moves[s][t]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])

    else:
            
    #add new 1/3 candles
        #add 1/6 of volume to old close
        #1/3 to low, 1/3 to high
        #1/6 to current close
        
        self.moves[s][t]["candle_halves"]["Price"][-1] = (self.moves[s][t]["candle_halves"]["Price"][-1] + opened) / 2.0
        self.moves[s][t]["candle_halves"]["Volume"][-1] += vol / 6.0
        
        if close >= opened:
            self.moves[s][t]["candle_halves"]["Price"].append(low)
            self.moves[s][t]["candle_halves"]["Price"].append(high)
        elif close < opened:
            self.moves[s][t]["candle_halves"]["Price"].append(high)
            self.moves[s][t]["candle_halves"]["Price"].append(low)

        #these are always the same 
        self.moves[s][t]["candle_halves"]["Price"].append(close)
            
        self.moves[s][t]["candle_halves"]["Volume"].append(vol / 3.0)
        self.moves[s][t]["candle_halves"]["Volume"].append(vol / 3.0)
        self.moves[s][t]["candle_halves"]["Volume"].append(vol / 6.0)
            
        self.moves[s][t]["candle_halves"]["Time"].append(mins - .667)
        self.moves[s][t]["candle_halves"]["Time"].append(mins - .333)
        self.moves[s][t]["candle_halves"]["Time"].append(mins)
        
        self.moves[s][t]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
        self.moves[s][t]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
        self.moves[s][t]["candle_halves"]["Time_wall"].append(str(self.Time).split()[1])
        
    return 0
    
#print out half candles, so can plot in R
def printCandleHalves(self, s):
        
    #VWMAs        
    vwmas, vp, v = calculate.VWMA(self, s, self.moves[s]["RH"]["candle_halves"]["Volume"], self.moves[s]["RH"]["candle_halves"]["Price"], "beginning")
    vwma_consol, vp_consol, v_consol = calculate.VWMA(self, s, self.moves[s]["RH"]["candle_halves"]["Volume"], self.moves[s]["RH"]["candle_halves"]["Price"], "consol")
    #vwma_cd = self.VWMA(s, self.moves[s]["RH"]["candle_halves"]["Volume"], self.moves[s]["RH"]["candle_halves"]["Price"], "cd")

    #EMAs
    currEMA, EMAs, start = calculate.calc_ignEMA(self, s)
    #currEMA_consol, EMAs_consol, start_consol = calculate.calc_consolEMA(self, s)
    currEMA_short, EMAs_short, start_short = calculate.calc_shortEMA(self, s, self.moves[s]["RH"]["candle_halves"]["Price"])

    #ign time and time to consol low
    ign_time = calculate.ign_high_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"])
    consol_low_ind = calculate.get_consol_low_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"], self.moves[s]["RH"]["consol_low"])
        
        
    ######print
    self.Debug("Time_wall\tTime\tValue\tCategory")
        
    #including PM
    #for i in range(0, len(self.moves_wPM[s]["candle_halves"]["Time"])):
    #    for cat in sorted(self.moves_wPM[s]["candle_halves"]):
    #        if cat != "Time" and cat != "Time_wall" and cat != "Price_noconsollow" and cat != "Price_nohighs":
    #            self.Debug(str(self.moves_wPM[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves_wPM[s]["candle_halves"]["Time"][i]) + "\t" + str(self.moves_wPM[s]["candle_halves"][cat][i]) + "\t" + cat + "_wPM")
    #    
    #    if i >= start_wPM:
    #        self.Debug(str(self.moves_wPM[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves_wPM[s]["candle_halves"]["Time"][i]) + "\t" + str(EMAs_wPM[i - start_wPM]) + "\tEMA_wPM")

    #market hours
    short_ind = 0
    consol_ind = 0
    for i in range(0, len(self.moves[s]["RH"]["candle_halves"]["Time"])):
        for cat in sorted(self.moves[s]["RH"]["candle_halves"]):
            if cat != "Time" and cat != "Time_wall" and cat != "Price_noconsollow" and cat != "Price_nohighs":
                self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"][cat][i]) + "\t" + cat)
        self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(vwmas[i]) + "\tVWMA")
        
        if i >= start:
            self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(EMAs[i - start]) + "\tEMA")
            
        if i >= ign_time:
            self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(vwma_consol[i-ign_time]) + "\tVWMA_consol")

        #if i >= consol_low_ind:
        #    self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(vwma_cd[i-consol_low_ind]) + "\tVWMA_cd")


        #short EMA
        if i >= (len(self.moves[s]["RH"]["candle_halves"]["Time"]) - len(EMAs_short)):
            self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(EMAs_short[short_ind]) + "\tEMA_short")
            short_ind += 1
    
        #consol low to consol high EMA
        #if i >= (len(self.moves[s]["RH"]["candle_halves"]["Time"]) - len(EMAs_consol)):
        #    self.Debug(str(self.moves[s]["RH"]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.moves[s]["RH"]["candle_halves"]["Time"][i]) + "\t" + str(EMAs_consol[consol_ind]) + "\tEMA_consol")
        #    consol_ind += 1
        
        
#print out half candles, so can plot in R
def printCandleHalvesCurr(self, s):
        
    #VWMAs        
    vwma_cd, vp_cd, v_cd = calculate.VWMA(self, s, self.movesCurr[s]["candle_halves"]["Volume"], self.movesCurr[s]["candle_halves"]["Price"], "cd_curr")
    
    #VWMAs bc
    #vwma_bc, vp_bc, v_bc = calculate.VWMA(self, s, self.movesCurr[s]["candle_halves"]["Volume"], self.movesCurr[s]["candle_halves"]["Price"], "bc_curr")

    #VWMAs bc not Curr
    vwma_bc_nc, vp_bc_nc, v_bc_nc = calculate.VWMA(self, s, self.moves[s]["RH"]["candle_halves"]["Volume"], self.moves[s]["RH"]["candle_halves"]["Price"], "consol")

    #VWMAs breakout
    vwmas_break, vp_break, v_break = calculate.VWMA(self, s, self.movesCurr[s]["candle_halves"]["Volume"], self.movesCurr[s]["candle_halves"]["Price"], "breakout")

    #VWMAs d
    #vwmas_d, vp_d, v_d = calculate.VWMA(self, s, self.movesCurr[s]["candle_halves"]["Volume"], self.movesCurr[s]["candle_halves"]["Price"], "d")


    #EMAs
    currEMA, EMAs, start = calculate.calc_CD_EMA_postBreak(self, s, self.movesCurr[s]["candle_halves"]["Price"], self.movesCurr[s]["moving_stop"])



    #ign time and time to consol low
    #ign_ind = calculate.ign_high_ind(self, self.movesCurr[s]["candle_halves"]["Price"], self.movesCurr[s]["high"])
    consol_low_ind = calculate.get_consol_low_ind(self, self.movesCurr[s]["candle_halves"]["Price"], self.movesCurr[s]["high"], self.movesCurr[s]["consol_low"])
    ign_ind_ncurr = calculate.ign_high_ind(self, self.moves[s]["RH"]["candle_halves"]["Price"], self.moves[s]["RH"]["high"])
    breakout_ind = calculate.get_breakout_ind(self, s, self.movesCurr[s]["candle_halves"]["Price"])
    #curr_high_ind = calculate.get_currhigh_ind(self, self.movesCurr[s]["candle_halves"]["Price"])
        
    #self.Debug(ign_ind_ncurr)
        
    #AB EMA, in position
    currEMA_inpos, EMAs_inpos, start_inpos = calculate.calc_longEMA_general(self, s, "ab_inpos", self.movesCurr[s]["candle_halves"]["Price"]) 
        
    ######print
    self.Debug("Time_wall\tTime\tValue\tCategory")

    #market hours
    short_ind = 0
    consol_ind = 0
    for i in range(0, len(self.movesCurr[s]["candle_halves"]["Time"])):
        for cat in sorted(self.movesCurr[s]["candle_halves"]):
            if cat != "Time" and cat != "Time_wall" and cat != "Price_noconsollow" and cat != "Price_nohighs":
                self.Debug(str(self.movesCurr[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.movesCurr[s]["candle_halves"]["Time"][i]) + "\t" + str(self.movesCurr[s]["candle_halves"][cat][i]) + "\t" + cat)

        if i >= start:
            self.Debug(str(self.movesCurr[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.movesCurr[s]["candle_halves"]["Time"][i]) + "\t" + str(EMAs[i - start]) + "\tEMA_movingStop")
            
        if i >= consol_low_ind:
            self.Debug(str(self.movesCurr[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.movesCurr[s]["candle_halves"]["Time"][i]) + "\t" + str(vwma_cd[i-consol_low_ind]) + "\tVWMA_cd")

        if i >= start_inpos:
            self.Debug(str(self.movesCurr[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.movesCurr[s]["candle_halves"]["Time"][i]) + "\t" + str(EMAs_inpos[i-start_inpos]) + "\tEMA_AB")
            
        if i >= breakout_ind: 
            self.Debug(str(self.movesCurr[s]["candle_halves"]["Time_wall"][i]) + "\t" + str(self.movesCurr[s]["candle_halves"]["Time"][i]) + "\t" + str(vwmas_break[i-breakout_ind]) + "\tVWMA_breakout")
            
    return
    
def printEverPosition(self):
    #Symbol [each category] Return
    self.Debug("Symbol\tReturn\tEntry_time_in_min\tPM_vol\tPM_nonZeroOneMinCandles\tR:R_lastTrade\tProp_of_pred_range_last_trade\tN_entries")
    for s in self.everPosition:
        time = self.timeInMin(str(self.everPosition[s]["time"]).split()[1])
        #self.Debug(s.Value + "\t" + str(self.Portfolio[s].NetProfit) + "\t" + str(time) + "\t" + str(self.everPosition[s]["pmvol"]) + "\t" + str(self.everPosition[s]["pm_nonzero"]) + "\t" + str(self.everPosition[s]["R:R"]) + "\t" + str(self.everPosition[s]["prop_of_pred_range"]) + "\t" + str(self.everPosition[s]["N_entries"]))
        self.Debug(s.Value + "\t" + str(self.Portfolio[s].LastTradeProfit) + "\t" + str(time) + "\t" + str(self.everPosition[s]["pmvol"]) + "\t" + str(self.everPosition[s]["pm_nonzero"]) + "\t" + str(self.everPosition[s]["R:R"]) + "\t" + str(self.everPosition[s]["prop_of_pred_range"]) + "\t" + str(self.everPosition[s]["N_entries"]))

    return


def print_got_to(self, got_to, got_to_time):
    if got_to_time != "":
        hour, minute = self.got_to_time.split(":")
        if minute == "00":
            minute = "0"
        #self.Debug(str(self.Time.minute))

        #minute = minute.lstrip("0")
        if hour == str(self.Time.hour) and minute == str(self.Time.minute):
            self.Debug(self.Time)
            self.Debug(got_to)
    return