Overall Statistics |
Total Trades 1234 Average Win 0.41% Average Loss -0.24% Compounding Annual Return -15.746% Drawdown 35.500% Expectancy -0.124 Net Profit -19.684% Sharpe Ratio -0.557 Probabilistic Sharpe Ratio 2.299% Loss Rate 67% Win Rate 33% Profit-Loss Ratio 1.69 Alpha -0.123 Beta 0.065 Annual Standard Deviation 0.204 Annual Variance 0.042 Information Ratio -1.03 Tracking Error 0.25 Treynor Ratio -1.762 Total Fees $1786638.08 Estimated Strategy Capacity $42000.00 |
# from BankingIndustryStocks import BankingIndustryStocks from custom_sp500 import QC500UniverseSelectionModel_V2 from datetime import datetime, timedelta from numpy import sum from gid_func import * from collections import deque class EqualWeightingPortfolioConstructionModel_V2(PortfolioConstructionModel): '''Provides an implementation of IPortfolioConstructionModel that gives equal weighting to all securities. The target percent holdings of each security is 1/N where N is the number of securities. For insights of direction InsightDirection.Up, long targets are returned and for insights of direction InsightDirection.Down, short targets are returned.''' def __init__(self, rebalance = timedelta(days=7), portfolioBias = PortfolioBias.LongShort): '''Initialize a new instance of EqualWeightingPortfolioConstructionModel Args: rebalance: Rebalancing parameter. If it is a timedelta, date rules or Resolution, it will be converted into a function. If None will be ignored. The function returns the next expected rebalance time for a given algorithm UTC DateTime. The function returns null if unknown, in which case the function will be called again in the next loop. Returning current time will trigger rebalance. portfolioBias: Specifies the bias of the portfolio (Short, Long/Short, Long)''' self.portfolioBias = portfolioBias # If the argument is an instance of Resolution or Timedelta # Redefine rebalancingFunc rebalancingFunc = rebalance if isinstance(rebalance, int): rebalance = Extensions.ToTimeSpan(rebalance) if isinstance(rebalance, timedelta): rebalancingFunc = lambda dt: dt + rebalance if rebalancingFunc: self.SetRebalancingFunc(rebalancingFunc) def DetermineTargetPercent(self, activeInsights): '''Will determine the target percent for each insight Args: activeInsights: The active insights to generate a target for''' result = {} # give equal weighting to each security count = sum(x.Direction != InsightDirection.Flat and self.RespectPortfolioBias(x) for x in activeInsights) percent = 0 if count == 0 else 1.0 / count for insight in activeInsights: result[insight] = (insight.Direction if self.RespectPortfolioBias(insight) else InsightDirection.Flat) * percent return result def RespectPortfolioBias(self, insight): '''Method that will determine if a given insight respects the portfolio bias Args: insight: The insight to create a target for ''' return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == self.portfolioBias class CalibratedParticleAtmosphericScrubbers(QCAlgorithm): def Initialize(self): self.SetStartDate(2010, 1, 1) # Set Start Date self.SetEndDate(2011, 4, 12) # Set End Date self.SetCash(21000000) # Set Strategy Cash self.UniverseSettings.Resolution = Resolution.Daily # self.SetPortfolioConstruction( EqualWeightingPortfolioConstructionModel() ) # self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(self.DateRules.Every(DayOfWeek.Wednesday))) #https://www.quantconnect.com/forum/discussion/4361/rebalancing-monthly-using-portfolioconstructionmodel-algorithm-framework/p1 #https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/PortfolioRebalanceOnCustomFuncRegressionAlgorithm.py#L50 # self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(self.DateRules.MonthStart()))#https://www.quantconnect.com/docs/algorithm-reference/scheduled-events self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel_V2()) self.SetExecution( ImmediateExecutionModel() ) self.SetRiskManagement(MaximumDrawdownPercentPortfolio()) # Add QC500 Universe self.SetUniverseSelection(QC500UniverseSelectionModel_V2()) # self.SetUniverseSelection(BankingIndustryStocks()) MAX_REDRAW = self.GetParameter("MAX_REDRAW_LENGTH") BLUE_DEG = self.GetParameter("blue_deg") GREEN_DEG = self.GetParameter("green_deg") self.SetAlpha(Grid_indicator("Grid", MAX_REDRAW, BLUE_DEG, GREEN_DEG)) class Grid_indicator(AlphaModel): def __init__(self, name, MAX_REDRAW, BLUE_DEG, GREEN_DEG): self.symbolDataBySymbol = {} self.HIGH_HIST = {} self.LOW_HIST = {} self.TIME_HIST = {} self.CHART_HIGH = {} self.CHART_LOW = {} self.SOFT_HIST_HIGH = {} self.SOFT_HIST_LOW = {} self.SOFT_CHART_HIGH = {} self.SOFT_CHART_LOW = {} self.Name = name self.Time = datetime.min self.Value = 0 self.dfdf = {} self.mean_HIGH = {} self.STD_four = {} self.High_value = {} self.MAX_REDRAW = float(MAX_REDRAW) # Since the Algorithm Parameter is a string we must convert it to a float self.BLUE_DEG = float(BLUE_DEG) self.GREEN_DEG = float(GREEN_DEG) def Update(self, algorithm, data): insights = [] for symbol, item in self.symbolDataBySymbol.items(): ''' Error checking past 122 high bars 6 standard diviations of the mean + mean if high ''' if data.ContainsKey(item.Symbol) and data[item.Symbol] is not None : self.SOFT_HIST_HIGH[item.Symbol] = list(self.SOFT_HIST_HIGH[item.Symbol]) self.SOFT_HIST_LOW[item.Symbol] = list(self.SOFT_HIST_LOW[item.Symbol]) self.mean_HIGH[item.Symbol] = round(np.mean(self.SOFT_HIST_HIGH[item.Symbol][-122:]),2) self.STD_four[item.Symbol] = round((np.std(self.SOFT_HIST_HIGH[item.Symbol][-122:]) * 6),4) if data[item.Symbol].High > self.mean_HIGH[item.Symbol] + self.STD_four[item.Symbol]: # print("here") algorithm.Debug(f"{item.Symbol.Value} SKIP THIS DAY!!!!!!!!!!!!!!! High_value: {data[item.Symbol].High}, mean_{item.Symbol.Value}: {self.mean_HIGH[item.Symbol]} STD_{item.Symbol.Value}_4: {self.STD_four[item.Symbol]}") self.SOFT_HIST_HIGH[item.Symbol].append(data[item.Symbol].High) self.SOFT_HIST_LOW[item.Symbol].append(data[item.Symbol].Low) continue # return insights #can redraw if in trade #close out trade first if item.BASE_series_index >= self.MAX_REDRAW and not algorithm.Portfolio[item.Symbol].Invested:# for mod in list(self.symbolDataBySymbol.values()): if symbol == mod.Symbol and data.ContainsKey(item.Symbol) and data[item.Symbol] is not None: algorithm.Debug(f"{mod.Symbol.Value} HIT max grid length {self.MAX_REDRAW} for BASE_series_index of {item.BASE_series_index}, HARD RESET HERE") self.symbolDataBySymbol[item.Symbol].PAUSED = True data_IN = {'Open' : data[item.Symbol].Open, 'High' : data[item.Symbol].High, 'Low' : data[item.Symbol].Low, 'Close' : data[item.Symbol].Close, 'EndTime': algorithm.Time } algorithm.Debug(data_IN) ##This resets the dict with the latest grid for the specific symbol self.symbolDataBySymbol[item.Symbol] = SymbolData(item.Symbol, data_IN, algorithm, self.Name, self.BLUE_DEG, self.GREEN_DEG) self.symbolDataBySymbol[item.Symbol].REBUILD_CHECK = data[item.Symbol].High self.symbolDataBySymbol[item.Symbol].HAS_RESET = True self.symbolDataBySymbol[item.Symbol].HAS_BEEN_STOPPED_OUT = False #Set CONFIRMING_GRID to true #This means the next three bars are used to see if the lows are greater than blue 0 self.symbolDataBySymbol[item.Symbol].CONFIRMING_GRID = True #This gets the low of the bar that the potential OP is set on #This is used to compare if any of HIGH's the next 3 bars are less than this VALUE #IF a high is LOWER then the grid fails self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE = data[item.Symbol].Low item.BASE_series_index = 0 item.series_index = 0 item.UNDERNEATH_LIST = [] ''' crude 5% stop loss ''' if data.ContainsKey(item.Symbol) and data[item.Symbol] is not None : if round((algorithm.Portfolio[item.Symbol].UnrealizedProfitPercent*100),3) < -5: algorithm.EmitInsights(Insight.Price(item.Symbol, timedelta(100000), InsightDirection.Flat)) # algorithm.SetHoldings(item.Symbol, 0, False, f"{item.Symbol.Value} THIS IS WHERE WE WOULD STOP OUT BASED ON RISK_MANAGMENT ALONE") item.TRADE_INITIATED = True # return insights continue ''' soft reset logic SOFT reset - OP set at chart low ''' if data.ContainsKey(item.Symbol) and data[item.Symbol] is not None: if item.TRADE_INITIATED and data.ContainsKey(item.Symbol) and data[item.Symbol] is not None: algorithm.Debug(f"{item.Symbol.Value} LastTradeProfit: ${round(algorithm.Portfolio[item.Symbol].LastTradeProfit,2)}") item.TRADE_INITIATED = False #make lists of the arrays self.SOFT_HIST_HIGH[item.Symbol] = list(self.SOFT_HIST_HIGH[item.Symbol]) self.SOFT_HIST_LOW[item.Symbol] = list(self.SOFT_HIST_LOW[item.Symbol]) self.SOFT_HIST_HIGH[item.Symbol].append(data[item.Symbol].High) self.SOFT_HIST_LOW[item.Symbol].append(data[item.Symbol].Low) self.SOFT_CHART_HIGH[item.Symbol] = max(self.SOFT_HIST_HIGH[item.Symbol][-12:]) self.SOFT_CHART_LOW[item.Symbol] = min(self.SOFT_HIST_LOW[item.Symbol][-12:]) self.HIGH_HIST[item.Symbol].append(data[item.Symbol].High) self.LOW_HIST[item.Symbol].append(data[item.Symbol].Low) self.TIME_HIST[item.Symbol].append(algorithm.Time) self.CHART_HIGH[item.Symbol] = max(self.HIGH_HIST[item.Symbol]) self.CHART_LOW[item.Symbol] = min(self.LOW_HIST[item.Symbol]) algorithm.Debug(f"{item.Symbol.Value} 12 day Low: {round(self.SOFT_CHART_LOW[item.Symbol],2)} Current Low: {round(data[item.Symbol].Low,2)} Current Open: {round(data[item.Symbol].Open,2)} blue_zero @ Index: {item.series_index}: {round(item.blue_zero.values[item.series_index][0],2)}") #Here is where we check if the low of the stock is lower than the 12 day low #if so then set grid if data[item.Symbol].Low <= self.SOFT_CHART_LOW[item.Symbol] : algorithm.Debug(f"12 day LOW for {item.Symbol.Value}: {round(self.SOFT_CHART_LOW[item.Symbol],2)}: is today ") algorithm.Debug(f"Setting the grid for {item.Symbol.Value}: {round(self.SOFT_CHART_LOW[item.Symbol],2)}") data_IN = { 'Open' : data[item.Symbol].Open, 'High' : data[item.Symbol].High, 'Low' : data[item.Symbol].Low, 'Close' : data[item.Symbol].Close, 'EndTime': algorithm.Time } algorithm.Debug(data_IN) ##This resets the dict with the latest grid for the specific symbol self.symbolDataBySymbol[item.Symbol] = SymbolData(item.Symbol, data_IN, algorithm, self.Name, self.BLUE_DEG, self.GREEN_DEG) self.symbolDataBySymbol[item.Symbol].REBUILD_CHECK = data[item.Symbol].High self.symbolDataBySymbol[item.Symbol].HAS_RESET = True self.symbolDataBySymbol[item.Symbol].HAS_BEEN_STOPPED_OUT = False #This gets the low of the bar that the potential OP is set on #This is used to compare if any of HIGH's the next 3 bars are less than this VALUE #IF a high is LOWER then the grid fails self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE = data[item.Symbol].Low #Set CONFIRMING_GRID to true #This means the next three bars are used to see if the lows are greater than blue 0 self.symbolDataBySymbol[item.Symbol].CONFIRMING_GRID = True #NOW JUST COPIED OVER STUFF FROM MAIN RUN, SO AS TO NOT MISS THE DATA ADDITIONS self.HIGH_HIST[item.Symbol].append(data[item.Symbol].High) self.LOW_HIST[item.Symbol].append(data[item.Symbol].Low) self.TIME_HIST[item.Symbol].append(algorithm.Time) self.CHART_HIGH[item.Symbol] = max(self.HIGH_HIST[item.Symbol]) self.CHART_LOW[item.Symbol] = min(self.LOW_HIST[item.Symbol]) item.BASE_series_index = 0 item.series_index = 0 item.UNDERNEATH_LIST = [] ''' HERE is where we do the confirming - 3 bars go by which must be above the BLUE angle 0 ''' if data[item.Symbol].High >= self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE and self.symbolDataBySymbol[item.Symbol].PRINTED_CONFORMATION == False: self.symbolDataBySymbol[item.Symbol].CONFIRMED_DAYS += 1 algorithm.Debug(f"{item.Symbol.Value}: High {round(data[item.Symbol].High, 2)} is ABOVE LOW_OF_RANGE {round(self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE, 2)} PASS: {self.symbolDataBySymbol[item.Symbol].CONFIRMED_DAYS}") if self.symbolDataBySymbol[item.Symbol].CONFIRMED_DAYS == 2: self.symbolDataBySymbol[item.Symbol].SECOND_BAR_HIGH = round(data[item.Symbol].High,2) algorithm.Debug(f"{item.Symbol.Value} GET HIGH {round(data[item.Symbol].High,2)} OF THIS BAR (2nd) TO USE WHEN COMPARING TO 3rd BAR") if data[item.Symbol].High < self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE: algorithm.Debug(f"{item.Symbol.Value}: High {round(data[item.Symbol].High, 2)} is BELOW LOW_OF_RANGE {round(self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE, 2)} FAIL: REDRAW GRID WITH LOWEST LOW SINCE OP") self.symbolDataBySymbol[item.Symbol].CONFIRMING_GRID = False data_IN = {'Open' : data[item.Symbol].Open, 'High' : data[item.Symbol].High, 'Low' : data[item.Symbol].Low, 'Close' : data[item.Symbol].Close, 'EndTime': algorithm.Time } algorithm.Debug(data_IN) ##This resets the dict with the latest grid for the specific symbol self.symbolDataBySymbol[item.Symbol] = SymbolData(item.Symbol, data_IN, algorithm, self.Name, self.BLUE_DEG, self.GREEN_DEG) self.symbolDataBySymbol[item.Symbol].REBUILD_CHECK = data[item.Symbol].High self.symbolDataBySymbol[item.Symbol].HAS_RESET = True self.symbolDataBySymbol[item.Symbol].HAS_BEEN_STOPPED_OUT = False #This gets the low of the bar that the potential OP is set on #This is used to compare if any of HIGH's the next 3 bars are less than this VALUE #IF a high is LOWER then the grid fails self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE = data[symbol].Low #Set CONFIRMING_GRID to true #This means the next three bars are used to see if the lows are greater than blue 0 self.symbolDataBySymbol[item.Symbol].CONFIRMING_GRID = True #NOW JUST COPIED OVER STUFF FROM MAIN RUN, SO AS TO NOT MISS THE DATA ADDITIONS self.HIGH_HIST[item.Symbol].append(data[item.Symbol].High) self.LOW_HIST[item.Symbol].append(data[item.Symbol].Low) self.TIME_HIST[item.Symbol].append(algorithm.Time) self.CHART_HIGH[item.Symbol] = max(self.HIGH_HIST[item.Symbol]) self.CHART_LOW[item.Symbol] = min(self.LOW_HIST[item.Symbol]) item.BASE_series_index = 0 item.series_index = 0 item.UNDERNEATH_LIST = [] if self.symbolDataBySymbol[item.Symbol].CONFIRMED_DAYS >= 3 and self.symbolDataBySymbol[item.Symbol].HAS_BEEN_STOPPED_OUT == False and self.symbolDataBySymbol[item.Symbol].PRINTED_CONFORMATION == False: algorithm.Debug(f"{item.Symbol.Value} TIME TO COMPARE 3rd BAR {round(data[item.Symbol].High,2)} to 2nd BAR {self.symbolDataBySymbol[item.Symbol].SECOND_BAR_HIGH}") if round(data[item.Symbol].High,2) > self.symbolDataBySymbol[item.Symbol].SECOND_BAR_HIGH : algorithm.Debug(f"{item.Symbol.Value} GRID CONFIRMED - OP point {item.Time}") self.symbolDataBySymbol[item.Symbol].CONFIRMED = True self.symbolDataBySymbol[item.Symbol].PAUSED = False self.symbolDataBySymbol[item.Symbol].PRINTED_CONFORMATION = True else: algorithm.Debug(f"{item.Symbol.Value} GRID FAILED 3rd bar HIGH was lower than 2nd HIGH - REDRAW GRID WITH LOWEST LOW SINCE OP") self.symbolDataBySymbol[item.Symbol].CONFIRMING_GRID = False data_IN = {'Open' : data[item.Symbol].Open, 'High' : data[item.Symbol].High, 'Low' : data[item.Symbol].Low, 'Close' : data[item.Symbol].Close, 'EndTime': algorithm.Time } algorithm.Debug(data_IN) ##This resets the dict with the latest grid for the specific symbol self.symbolDataBySymbol[item.Symbol] = SymbolData(item.Symbol, data_IN, algorithm, self.Name, self.BLUE_DEG, self.GREEN_DEG) self.symbolDataBySymbol[item.Symbol].REBUILD_CHECK = data[item.Symbol].High self.symbolDataBySymbol[item.Symbol].HAS_RESET = True self.symbolDataBySymbol[item.Symbol].HAS_BEEN_STOPPED_OUT = False #This gets the low of the bar that the potential OP is set on #This is used to compare if any of HIGH's the next 3 bars are less than this VALUE #IF a high is LOWER then the grid fails self.symbolDataBySymbol[item.Symbol].LOW_OF_RANGE = data[item.Symbol].Low #Set CONFIRMING_GRID to true #This means the next three bars are used to see if the lows are greater than blue 0 self.symbolDataBySymbol[item.Symbol].CONFIRMING_GRID = True #NOW JUST COPIED OVER STUFF FROM MAIN RUN, SO AS TO NOT MISS THE DATA ADDITIONS self.HIGH_HIST[item.Symbol].append(data[item.Symbol].High) self.LOW_HIST[item.Symbol].append(data[item.Symbol].Low) self.TIME_HIST[item.Symbol].append(algorithm.Time) self.CHART_HIGH[item.Symbol] = max(self.HIGH_HIST[item.Symbol]) self.CHART_LOW[item.Symbol] = min(self.LOW_HIST[item.Symbol]) item.BASE_series_index = 0 item.series_index = 0 item.UNDERNEATH_LIST = [] ''' Here is the trading logic as we have a confirmed grid OP ''' if data.ContainsKey(item.Symbol) and data[item.Symbol] is not None and self.symbolDataBySymbol[item.Symbol].CONFIRMED and not algorithm.Portfolio[item.Symbol].Invested and self.symbolDataBySymbol[item.Symbol].PAUSED == False and item.TRADE_INITIATED==False: if data[item.Symbol].Open <= item.blue_zero.values[item.series_index][0] or data[item.Symbol].Low <= item.blue_zero.values[item.series_index][0]: algorithm.Debug(f"{item.Symbol.Value} - BUY POINT - Enter Long trade - OP {item.Time}") algorithm.EmitInsights(Insight.Price(item.Symbol, timedelta(100000), InsightDirection.Up)) item.TRADE_INITIATED = True ''' 6 Stoping out due to logic ''' if data.ContainsKey(item.Symbol) and data[item.Symbol] is not None and algorithm.Portfolio[item.Symbol].Invested and self.symbolDataBySymbol[item.Symbol].PAUSED == False and item.TRADE_INITIATED==False: if data[item.Symbol].High <= item.blue_pos_two.values[item.series_index][0]: #2 bars needing to be under blue pos 2 to stop out the position self.symbolDataBySymbol[item.Symbol].BARS_BELOW_BLUE_ZERO += 1 if self.symbolDataBySymbol[item.Symbol].BARS_BELOW_BLUE_ZERO >=2: algorithm.Debug(f"{item.Symbol.Value} - SELL POINT - Stopped out logic - Close Long trade - OP {item.Time}") algorithm.EmitInsights(Insight.Price(item.Symbol, timedelta(100000), InsightDirection.Flat)) item.TRADE_INITIATED = True self.symbolDataBySymbol[item.Symbol].CONFIRMED = False self.symbolDataBySymbol[item.Symbol].HAS_BEEN_STOPPED_OUT = True item.series_index += 1 item.BASE_series_index += 1 return insights def OnSecuritiesChanged(self, algorithm, changes): for removed in changes.RemovedSecurities: self.symbolDataBySymbol.pop(removed.Symbol, None) algorithm.Debug(f"REMOVED Symbol in OnSecuritiesChanged: {removed.Symbol.Value}") algorithm.EmitInsights(Insight.Price(removed.Symbol, timedelta(100000), InsightDirection.Flat)) for added in changes.AddedSecurities: if added.Symbol not in self.symbolDataBySymbol: algorithm.Debug(f"Added Symbol in OnSecuritiesChanged: {added.Symbol.Value}") self.dfdf[added.Symbol] = algorithm.History(added.Symbol, 99) time_out = [] for index, row in self.dfdf[added.Symbol].loc[added.Symbol].iterrows(): time_out.append(index) #Log the highs and lows of the past 99 days self.SOFT_HIST_HIGH[added.Symbol] = self.dfdf[added.Symbol].high.values self.SOFT_HIST_LOW[added.Symbol] = self.dfdf[added.Symbol].low.values self.df = algorithm.History(added.Symbol, 1) data_IN = {'Open' : self.df.open[0], 'High' : self.df.high[0], 'Low' : self.df.low[0], 'Close' : self.df.close[0], 'EndTime': algorithm.Time } algorithm.Debug(data_IN) ##This resets the dict with the latest grid for the specific symbol self.symbolDataBySymbol[added.Symbol] = SymbolData(added.Symbol, data_IN, algorithm, self.Name, self.BLUE_DEG, self.GREEN_DEG) self.symbolDataBySymbol[added.Symbol].REBUILD_CHECK = self.df.high[0] self.symbolDataBySymbol[added.Symbol].HAS_RESET = True self.symbolDataBySymbol[added.Symbol].HAS_BEEN_STOPPED_OUT = False #NOW JUST COPIED OVER STUFF FROM MAIN RUN, SO AS TO NOT MISS THE DATA ADDITIONS self.HIGH_HIST[added.Symbol] = [self.df.high[0]] self.LOW_HIST[added.Symbol] = [self.df.low[0]] self.TIME_HIST[added.Symbol] = [algorithm.Time] #This gets the low of the bar that the potential OP is set on #This is used to compare if any of HIGH's the next 3 bars are less than this VALUE #IF a high is LOWER then the grid fails self.symbolDataBySymbol[added.Symbol].LOW_OF_RANGE = self.df.low[0] #Set CONFIRMING_GRID to true #This means the next three bars are used to see if the lows are greater than blue 0 self.symbolDataBySymbol[added.Symbol].CONFIRMING_GRID = True self.CHART_HIGH[added.Symbol] = max(self.HIGH_HIST[added.Symbol]) self.CHART_LOW[added.Symbol] = min(self.LOW_HIST[added.Symbol]) class SymbolData: def __init__(self, symbol, data_IN, algorithm, name, BLUE_DEG, GREEN_DEG): self.Symbol = symbol self.Name = name self.Time = data_IN["EndTime"] self.Value = 0 self.BLUE_DEG = float(BLUE_DEG) self.GREEN_DEG = float(GREEN_DEG) self.PAUSED = True self.CONFIRMING_GRID = False self.CONFIRMED_DAYS = 0 self.CONFIRMED = False self.HAS_BEEN_STOPPED_OUT = False self.BARS_BELOW_BLUE_ZERO = 0 self.PRINTED_CONFORMATION = False self.TRADE_INITIATED = False self.REBUILD_CHECK = 0 self.HAS_RESET = False self.blue_zero = None self.blue_neg_one = None self.blue_neg_two = None self.blue_neg_three = None self.blue_neg_four = None self.blue_neg_five = None self.blue_neg_six = None self.blue_neg_severn = None self.blue_neg_eight = None self.blue_neg_nine = None self.blue_neg_ten = None self.blue_neg_eleven = None self.blue_neg_twelve = None self.blue_neg_thirteen = None self.blue_neg_fourteen = None self.blue_neg_fifteen = None self.blue_pos_one = None self.blue_pos_two = None self.blue_pos_three = None self.blue_pos_four = None self.blue_pos_five = None self.blue_pos_six = None self.blue_pos_severn = None self.blue_pos_eight = None self.blue_pos_nine = None self.blue_pos_ten = None self.blue_pos_eleven = None self.blue_pos_twelve = None self.blue_pos_thirteen = None self.blue_pos_fourteen = None self.blue_pos_fifteen = None self.green_zero = None self.green_neg_one = None self.green_neg_two = None self.green_neg_three = None self.green_neg_four = None self.green_neg_five = None self.green_neg_six = None self.green_neg_severn = None self.green_neg_eight = None self.green_neg_nine = None self.green_neg_ten = None self.green_neg_eleven = None self.green_neg_twelve = None self.green_neg_thirteen = None self.green_neg_fourteen = None self.green_neg_fifteen = None self.green_pos_one = None self.green_pos_two = None self.green_pos_three = None self.green_pos_four = None self.green_pos_five = None self.green_pos_six = None self.green_pos_severn = None self.green_pos_eight = None self.green_pos_nine = None self.green_pos_ten = None self.green_pos_eleven = None self.green_pos_twelve = None self.green_pos_thirteen = None self.green_pos_fourteen = None self.green_pos_fifteen = None self.UNDERNEATH_LIST = [] self.series_index = 0 self.BASE_series_index = 0 self.indicator = self.makeIndicator(symbol, data_IN) def makeIndicator(self, symbol, data_IN): self.LOW_series = get_price_series(price_point="Low", interval="1d", data=data_IN, csv_records = 222, blue_deg = self.BLUE_DEG, green_deg = self.GREEN_DEG) self.blue_zero = self.LOW_series['blue 0'] self.blue_neg_one = self.LOW_series['blue neg1'] self.blue_neg_two = self.LOW_series['blue neg2'] self.blue_neg_three = self.LOW_series['blue neg3'] self.blue_neg_four = self.LOW_series['blue neg4'] self.blue_neg_five = self.LOW_series['blue neg5'] self.blue_neg_six = self.LOW_series['blue neg6'] self.blue_neg_severn = self.LOW_series['blue neg7'] self.blue_neg_eight = self.LOW_series['blue neg8'] self.blue_neg_nine = self.LOW_series['blue neg9'] self.blue_neg_ten = self.LOW_series['blue neg10'] self.blue_neg_eleven = self.LOW_series['blue neg11'] self.blue_neg_twelve = self.LOW_series['blue neg12'] self.blue_neg_thirteen = self.LOW_series['blue neg13'] self.blue_neg_fourteen = self.LOW_series['blue neg14'] self.blue_neg_fifteen = self.LOW_series['blue neg15'] self.blue_pos_one = self.LOW_series['blue pos1'] self.blue_pos_two = self.LOW_series['blue pos2'] self.blue_pos_three = self.LOW_series['blue pos3'] self.blue_pos_four = self.LOW_series['blue pos4'] self.blue_pos_five = self.LOW_series['blue pos5'] self.blue_pos_six = self.LOW_series['blue pos6'] self.blue_pos_severn = self.LOW_series['blue pos7'] self.blue_pos_eight = self.LOW_series['blue pos8'] self.blue_pos_nine = self.LOW_series['blue pos9'] self.blue_pos_ten = self.LOW_series['blue pos10'] self.blue_pos_eleven = self.LOW_series['blue pos11'] self.blue_pos_twelve = self.LOW_series['blue pos12'] self.blue_pos_thirteen = self.LOW_series['blue pos13'] self.blue_pos_fourteen = self.LOW_series['blue pos14'] self.blue_pos_fifteen = self.LOW_series['blue pos15'] self.green_zero = self.LOW_series['green 0'] self.green_neg_one = self.LOW_series['green neg1'] self.green_neg_two = self.LOW_series['green neg2'] self.green_neg_three = self.LOW_series['green neg3'] self.green_neg_four = self.LOW_series['green neg4'] self.green_neg_five = self.LOW_series['green neg5'] self.green_neg_six = self.LOW_series['green neg6'] self.green_neg_severn = self.LOW_series['green neg7'] self.green_neg_eight = self.LOW_series['green neg8'] self.green_neg_nine = self.LOW_series['green neg9'] self.green_neg_ten = self.LOW_series['green neg10'] self.green_neg_eleven = self.LOW_series['green neg11'] self.green_neg_twelve = self.LOW_series['green neg12'] self.green_neg_thirteen = self.LOW_series['green neg13'] self.green_neg_fourteen = self.LOW_series['green neg14'] self.green_neg_fifteen = self.LOW_series['green neg15'] self.green_pos_one = self.LOW_series['green pos1'] self.green_pos_two = self.LOW_series['green pos2'] self.green_pos_three = self.LOW_series['green pos3'] self.green_pos_four = self.LOW_series['green pos4'] self.green_pos_five = self.LOW_series['green pos5'] self.green_pos_six = self.LOW_series['green pos6'] self.green_pos_severn = self.LOW_series['green pos7'] self.green_pos_eight = self.LOW_series['green pos8'] self.green_pos_nine = self.LOW_series['green pos9'] self.green_pos_ten = self.LOW_series['green pos1'] self.green_pos_eleven = self.LOW_series['green pos11'] self.green_pos_twelve = self.LOW_series['green pos12'] self.green_pos_thirteen = self.LOW_series['green pos13'] self.green_pos_fourteen = self.LOW_series['green pos14'] self.green_pos_fifteen = self.LOW_series['green pos15'] self.Value = self.blue_zero.iloc[0].values[0] #This check does not seem to do anything return len(self.blue_zero) == 150
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel class BankingIndustryStocks(FundamentalUniverseSelectionModel): ''' This module selects the most liquid stocks listed on the Nasdaq Stock Exchange. ''' def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None): '''Initializes a new default instance of the TechnologyUniverseModule''' super().__init__(filterFineData, universeSettings, securityInitializer) self.numberOfSymbolsCoarse = 1000 self.numberOfSymbolsFine = 100 self.dollarVolumeBySymbol = {} self.lastMonth = -1 def SelectCoarse(self, algorithm, coarse): ''' Performs a coarse selection: -The stock must have fundamental data -The stock must have positive previous-day close price -The stock must have positive volume on the previous trading day ''' if algorithm.Time.month == self.lastMonth: return Universe.Unchanged sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.Volume > 0 and x.Price > 0], key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse] self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume} # If no security has met the QC500 criteria, the universe is unchanged. if len(self.dollarVolumeBySymbol) == 0: return Universe.Unchanged return list(self.dollarVolumeBySymbol.keys()) def SelectFine(self, algorithm, fine): ''' Performs a fine selection for companies in the Morningstar Banking Sector ''' # Filter stocks and sort on dollar volume sortedByDollarVolume = sorted([x for x in fine if x.AssetClassification.MorningstarIndustryGroupCode == MorningstarIndustryGroupCode.Banks], key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True) if len(sortedByDollarVolume) == 0: return Universe.Unchanged self.lastMonth = algorithm.Time.month return [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]]#[:5]
import matplotlib import pandas as pd import numpy as np import re from math import * import os def get_price_series(price_point: str, interval: str = "1d", csv_records: int = 125, data=None, blue_deg: int = 39, green_deg: int = 141.2): class Line: slope = 0.0 intercept = 0.0 point = (0, 0) color = "" def __init__(self, slope: float, intercept: float, color: str, point: tuple, label: str): self.slope = slope self.intercept = intercept self.label = label self.point = point self.color = color def get_y(self, x: float): return self.slope * float(x) + self.intercept lines = [] date_price_series = {} grid_lines = [] col = price_point blue_d = 73.2 green_d = 76.1 blue_deg = blue_deg green_deg = green_deg const_blue_d = 1.06 const_green_d = 0.67 const_blue_angle = 1.3800000000000001 const_green_angle = 1.1300000000000001 xminratio = -1.2826428983835214 xmaxratio = 117.42191299143596 yminratio = 0.6681857061381054 ymaxratio = 1.0065736915744727 xpx = 2095.351999999999 dpi = 100.0 # We will be using x_y_angle everywhere since it is in radians blue_angle = radians(blue_deg) green_angle = radians(green_deg) frequency_unit = re.findall(r'[A-Za-z]+|\d+', interval)[1] frequency = re.findall(r'[A-Za-z]+|\d+', interval)[0] interval = frequency + frequency_unit if interval != "1d": matplotlib.rcParams['timezone'] = 'US/Eastern' else: matplotlib.rcParams['timezone'] = 'UTC' global stock # tmp_data = yf.download(stock, dataStart, dataEnd, interval) if isinstance(data["High"], float): leny = abs(data["High"] - data["Low"]) xmin = xminratio #* len(data) xmax = xmaxratio #* len(data) ymin = yminratio * data["Low"] ymax = ymaxratio * data["High"] xp = 0.0 yp = data[col] else: leny = abs(data["High"][0] - data["Low"][0]) xmin = xminratio #* len(data) xmax = xmaxratio #* len(data) ymin = yminratio * data["Low"][0] ymax = ymaxratio * data["High"][0] xp = 0.0 yp = data[col][int(xp)] ratio = (ymax - ymin) / (xmax - xmin) xpx = xpx / abs(xmax - xmin) point = (xp, yp) y_line_slope = 1.0 / tan(green_angle * const_green_angle) * ratio y_line_intercept = yp - y_line_slope * xp x_line_slope = tan(blue_angle * const_blue_angle) * ratio x_line_intercept = yp - x_line_slope * xp lines.append(Line(x_line_slope, x_line_intercept, 'blue', point, "blue 0")) lines.append(Line(y_line_slope, y_line_intercept, "green", point, "green 0")) for line in lines: if line.color == "green": g_d_inches = green_d / 25.4 inches = g_d_inches / sin(green_angle - pi / 2.0) xp = inches * dpi / xpx * const_green_d else: b_d_inches = blue_d / 25.4 inches = b_d_inches / sin(blue_angle) xp = inches * dpi / xpx * const_blue_d for direction in (-1.0, 1.0): intercept = float(line.intercept) for x in range(15): yp = float(intercept) intercept = yp + abs(line.slope) * xp * direction point = (xp, yp) if direction == 1: # going up pos = "pos" + str(x + 1) else: # going down pos = "neg" + str(x + 1) label = line.color + " " + pos li = Line(line.slope, intercept, line.color, point, label) grid_lines.append(li) all_lines = lines + grid_lines xp = lines[0].point[0] for line in all_lines: new_intercept = xp * float(line.slope) + float(line.intercept) prices = [] for x in range(csv_records): price = round(float(line.slope) * x + new_intercept, 8) prices.append(price) df = {col: prices} df = pd.DataFrame(df) df.index.name = "Date" date_price_series[line.label] = df return date_price_series
#https://github.com/QuantConnect/Lean/blob/master/Algorithm.Framework/Selection/QC500UniverseSelectionModel.py from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm.Framework") from QuantConnect.Data.UniverseSelection import * from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel from itertools import groupby from math import ceil class QC500UniverseSelectionModel_V2(FundamentalUniverseSelectionModel): '''Defines the QC500 universe as a universe selection model for framework algorithm For details: https://github.com/QuantConnect/Lean/pull/1663''' def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None): '''Initializes a new default instance of the QC500UniverseSelectionModel''' super().__init__(filterFineData, universeSettings, securityInitializer) self.numberOfSymbolsCoarse = 1000 self.numberOfSymbolsFine = 500 self.dollarVolumeBySymbol = {} self.lastMonth = -1 def SelectCoarse(self, algorithm, coarse): '''Performs coarse selection for the QC500 constituents. The stocks must have fundamental data The stock must have positive previous-day close price The stock must have positive volume on the previous trading day''' if algorithm.Time.month == self.lastMonth: return Universe.Unchanged sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.Volume > 0 and x.Price > 0], key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse] self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume} # If no security has met the QC500 criteria, the universe is unchanged. # A new selection will be attempted on the next trading day as self.lastMonth is not updated if len(self.dollarVolumeBySymbol) == 0: return Universe.Unchanged # return the symbol objects our sorted collection return list(self.dollarVolumeBySymbol.keys()) def SelectFine(self, algorithm, fine): '''Performs fine selection for the QC500 constituents The company's headquarter must in the U.S. The stock must be traded on either the NYSE or NASDAQ At least half a year since its initial public offering The stock's market cap must be greater than 500 million''' sortedBySector = sorted([x for x in fine if x.CompanyReference.CountryId == "USA" and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"] and (algorithm.Time - x.SecurityReference.IPODate).days > 180 and x.MarketCap > 5e8], key = lambda x: x.CompanyReference.IndustryTemplateCode) count = len(sortedBySector) # If no security has met the QC500 criteria, the universe is unchanged. # A new selection will be attempted on the next trading day as self.lastMonth is not updated if count == 0: return Universe.Unchanged # Update self.lastMonth after all QC500 criteria checks passed self.lastMonth = algorithm.Time.month percent = self.numberOfSymbolsFine / count sortedByDollarVolume = [] # select stocks with top dollar volume in every single sector for code, g in groupby(sortedBySector, lambda x: x.CompanyReference.IndustryTemplateCode): y = sorted(g, key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse = True) c = ceil(len(y) * percent) sortedByDollarVolume.extend(y[:c]) sortedByDollarVolume = sorted(sortedByDollarVolume, key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True) return [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]][475:]