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