Overall Statistics |
Total Trades 735 Average Win 2.26% Average Loss -0.96% Compounding Annual Return 31.548% Drawdown 24.300% Expectancy 1.553 Net Profit 5008.488% Sharpe Ratio 1.643 Probabilistic Sharpe Ratio 98.855% Loss Rate 24% Win Rate 76% Profit-Loss Ratio 2.35 Alpha 0.199 Beta 0.252 Annual Standard Deviation 0.133 Annual Variance 0.018 Information Ratio 0.772 Tracking Error 0.178 Treynor Ratio 0.871 Total Fees $1822.76 Estimated Strategy Capacity $6000000.00 Lowest Capacity Asset FDN TJPMW3BHNMUD |
#region imports from AlgorithmImports import * #endregion from pykalman import KalmanFilter import statistics class KalmanFilterIndicator(PythonIndicator): def __init__(self,name, period, selector=Field.Close, transition_matrices = [1], observation_matrices = [1], initial_state_mean = 0, initial_state_covariance = 1, observation_covariance=1, transition_covariance=.01): self.Name = name self.period = period self.Value = 0 self.barCalc = selector self.transition_matrices = transition_matrices self.observation_matrices = observation_matrices self.initial_state_mean = initial_state_mean self.initial_state_covariance = initial_state_covariance self.observation_covariance = observation_covariance self.transition_covariance = transition_covariance self.rollingWindow = RollingWindow[float](self.period) # --------------------------------- def Update(self, inputBar): effectiveBarValue = self.barCalc(inputBar) # round(float(statistics.median([Field.Open(inputBar), Field.High(inputBar), Field.Low(inputBar), Field.Close(inputBar)])), 4)# self.barCalc(inputBar) self.rollingWindow.Add(effectiveBarValue) if(not self.rollingWindow.IsReady): return False else: basisValue = np.flipud(np.array([self.rollingWindow[i] for i in range(self.period)])) self.kf = KalmanFilter( transition_matrices = self.transition_matrices, observation_matrices = self.observation_matrices, initial_state_mean = self.initial_state_mean, initial_state_covariance = self.initial_state_covariance, observation_covariance = self.observation_covariance, transition_covariance = self.transition_covariance) #self.kf = self.kf.em(basisValue, n_iter=5) kf,_ = self.kf.filter(basisValue) # self.kf.smooth(basisValue) currKalman = kf[-1] self.Value = float(currKalman) return True ################################################################################ # # LaguerreFilterIndicator # ============================== # Laguerre Filter as defined by John F. Ehlers in `Cybernetic Analysis for # Stock and Futures`, 2004, published by Wiley. `ISBN: 978-0-471-46307-8 # https://www.mt5users.com/wp-content/uploads/2020/01/timewarp.pdf # # Copied from @vladimir's implementation # https://www.quantconnect.com/forum/discussion/11788/another-digital-filter-laguerre-filter/p1/comment-34897 # ################################################################################ class LaguerreFilterIndicator(PythonIndicator): def __init__(self, name, gamma ): self.Name = name self.gamma = gamma self.prices = np.array([]) self.Value = 0 self.L0 = 0.0; self.L1 = 0.0; self.L2 = 0.0; self.L3 = 0.0 def Update(self, input): mp = (input.High + input.Low)/2 self.prices = np.append(self.prices, mp)[-4:] if len(self.prices) <= 1: self.L0 = mp; self.L1 = mp; self.L2 = mp; self.L3 = mp; if len(self.prices) != 4 : return L01 = self.L0; L11 = self.L1; L21 = self.L2; L31 = self.L3; g = self.gamma self.L0 = (1 - g)*mp + g*L01 self.L1 = L01 - g*self.L0 + g*L11 self.L2 = L11 - g*self.L1 + g*L21 self.L3 = L21 - g*self.L2 + g*L31 if len(self.prices) != 4 : self.Value = mp return False self.Value = (self.L0 + (2*self.L1) + 2*(self.L2) + self.L3) / 6 return True
#region imports from AlgorithmImports import * #endregion ################################################### # # Smart Rolling window # ======================== # Convenience object to build on RollingWindow functionality # # Methods: # ------------------------- # mySmartWindow.IsRising() # mySmartWindow.IsFalling() # mySmartWindow.crossedAboveValue(value) # mySmartWindow.crossedBelowValue(value) # mySmartWindow.crossedAbove(otherWindow) # mySmartWindow.crossedBelow(otherWindow) # mySmartWindow.IsFlat(decimalPrecision) # mySmartWindow.hasAtLeastThisMany(value) # ################################################### class SmartRollingWindow(): def __init__(self, windowType, windowLength): self.window = None self.winLength = windowLength if (windowType is "int"):self.window = RollingWindow[int](windowLength) elif (windowType is "bool"):self.window = RollingWindow[bool](windowLength) elif (windowType is "float"):self.window = RollingWindow[float](windowLength) elif (windowType is "TradeBar"):self.window = RollingWindow[TradeBar](windowLength) def crossedAboveValue(self, value): return (self.window[1] <= value < self.window[0]) def crossedBelowValue(self, value): return (self.window[1] >= value > self.window[0]) def crossedAbove(self, series): return (any(self.window[i+1] <= series[i+1] and self.window[i] > series[i] for i in range(0, self.winLength-1))) def crossedBelow(self, series): return (any(self.window[i+1] >= series[i+1] and self.window[i] < series[i] for i in range(0, self.winLength-1))) def isAbove(self, series): return (self.window[0] > series[0]) def isBelow(self, series): return (self.window[0] < series[0]) def isFlat(self): return (self.window[1] == self.window[0]) def isFalling(self): return (self.window[1] > self.window[0]) def isRising(self): return (self.window[1] < self.window[0]) def Add(self,value): self.window.Add(value) def IsReady(self): return (self.window is not None) and \ (self.window.Count >= self.winLength) ## TODO: just use rw.IsReady? def __getitem__(self, index): return self.window[index]
from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * import tweepy, statistics, json from datetime import datetime, timedelta, date import numpy as np from scipy import stats from AlgorithmImports import * from sklearn.linear_model import LinearRegression, LogisticRegression from sklearn.tree import ExtraTreeRegressor, ExtraTreeClassifier from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn import metrics from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error from sklearn import preprocessing from sklearn.preprocessing import MinMaxScaler from keras.models import Sequential from keras.layers import Dense, LSTM from helpers import myTrailingStopRiskManagementModel from SmartRollingWindow import * class DualMomentumWithOutDaysAlphaModel(AlphaModel): def __init__(self, algorithm, VOLA = 126, BASE_RET = 83, resolution = Resolution.Daily, *args, **kwargs): super().__init__() self.VOLA = VOLA self.BASE_RET = BASE_RET self.resolution = Resolution.Daily # resolution self.MKT = algorithm.AddEquity('SPY', resolution).Symbol self.SLV = algorithm.AddEquity('SLV', resolution).Symbol self.GLD = algorithm.AddEquity('GLD', resolution).Symbol self.XLI = algorithm.AddEquity('XLI', resolution).Symbol self.XLU = algorithm.AddEquity('XLU', resolution).Symbol self.DBB = algorithm.AddEquity('DBB', resolution).Symbol self.UUP = algorithm.AddEquity('UUP', resolution).Symbol self.MKT_MOMP = algorithm.MOMP(self.MKT, 2, Resolution.Daily) self.count = self.BASE_RET self.outday = 5 pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP] for symbol in pairs: self.consolidator = TradeBarConsolidator(timedelta(days=1)) self.consolidator.DataConsolidated += self.consolidation_handler algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator) self.history = np.log(algorithm.History(pairs, self.VOLA + 1, self.resolution)) #self.history = self.history['close'].unstack(level=0).dropna() self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), 1) resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = f"{self.__class__.__name__}({resolutionString})" # Force alpha to only produce insights Daily at 11.10am self.set_flag = False algorithm.Schedule.On(algorithm.DateRules.EveryDay(), algorithm.TimeRules.AfterMarketOpen('SPY', 100), self.SetFlag) self.algorithm = algorithm self._mag = 0.00 self._mag_actual = 0.00 self.in_out = 0 algorithm.Schedule.On(algorithm.DateRules.Every(DayOfWeek.Saturday), algorithm.TimeRules.At(2, 00), self.ml_model) def SetFlag(self): self.set_flag = True def consolidation_handler(self, sender, consolidated): self.history.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close self.history = self.history.iloc[-(self.VOLA + 1):] def Update(self, algorithm, _data): if algorithm.IsWarmingUp or not self.set_flag: return [] self.set_flag = False insights = [] # Volatility vola = self.history[self.MKT].pct_change().std() * np.sqrt(252) wait_days = int(vola * self.BASE_RET) period = int((1.0 - vola) * self.BASE_RET) r = self.history.pct_change(period).iloc[-1] exit_market = r[self.SLV] < r[self.GLD] and r[self.XLI] < r[self.XLU] and r[self.DBB] < r[self.UUP] # # ML Model # pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP] # data = self.history # data['vola'] = data[self.MKT].pct_change().rolling(246).std() * np.sqrt(252) # data['wait_days'] = data['vola'].map(lambda x: int(int(x)*self.BASE_RET), na_action='ignore') # data['period'] = data['vola'].map(lambda x: int((1.0 - int(x)) * self.BASE_RET), na_action='ignore') # market_signals = list() # for i in range(0, len(data['period'])): # if 'na' not in str(data['period'][i]): # count = int(i) # period = int(data['period'][i]) # r = data[count:count+246].pct_change(period).iloc[-1] # exit_market = (r[self.SLV] < r[self.GLD] and r[self.XLI] < r[self.XLU] and r[self.DBB] < r[self.UUP]) # market_signals.append(exit_market) # else: # market_signals.append('na') # data['market_signals'] = market_signals # del market_signals # data['Market_Change'] = data[self.MKT].pct_change() # # # Load LabelEncoder to process string variables # le = preprocessing.LabelEncoder() # ml_data = data.dropna() # pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP, 'vola', 'wait_days', 'period', 'Market_Change'] # X = ml_data.drop(['market_signals'], axis=1) # y = np.ravel(ml_data[['market_signals']].astype(str).apply(le.fit_transform)) # algorithm.Debug(str(X.shape) + ";" + str(y.shape)) # X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Prepare Data # pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP] # df = algorithm.History(pairs, 252, Resolution.Daily).close # returns = df.unstack(level=1).transpose().dropna() # returns["Volatility"] = np.nan # returns["Wait_Days"] = np.nan # returns["Period"] = np.nan # returns["Exit_Market"] = np.nan # vola_list = [np.nan] * 126 # wait_list = [np.nan] * 126 # period_list = [np.nan] * 126 # exit_market_list = [np.nan] * 126 # for i in range(len(returns)-126): # temp_df = returns.iloc[i:i+126] # vola = temp_df[self.MKT].pct_change().std() * np.sqrt(252) # wait_days = int(vola * self.BASE_RET) # period = int((1.0 - vola) * self.BASE_RET) # r = temp_df.pct_change(period).iloc[-1] # exit_market = r[self.SLV] < r[self.GLD] and r[self.XLI] < r[self.XLU] and r[self.DBB] < r[self.UUP] # vola_list.append(vola) # wait_list.append(wait_days) # period_list.append(period) # exit_market_list.append(exit_market) # returns["Volatility"] = vola_list # returns["Wait_Days"] = wait_list # returns["Period"] = period_list # returns["Exit_Market"] = exit_market # X = returns.dropna() # y = returns[self.MKT].iloc[126:] # X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1990) # # Initialize instance of Random Forest Regressor # regressor = RandomForestRegressor(n_estimators=500, criterion = "mse", min_samples_split=5, random_state = 1990) # # Fit regressor # regressor.fit(X_train, y_train) # # Get long-only predictions # weights = regressor.feature_importances_ # symbols = X.columns[np.where(weights)] # selected = zip(symbols, weights) # y_pred = regressor.predict(X_test) # algorithm.Plot("MKT Price", "Actual", float(y_test[-1])) # algorithm.Plot("MKT Price", "Predicted", float(y_pred[-1])) # algorithm.Plot("Model Accuracy", "100%", float(regressor.score(X_test, y_test)*100)) # algorithm.Plot("Error", 'Mean Absolute Error', metrics.mean_absolute_error(y_test, y_pred)) # algorithm.Plot("Error", 'Mean Squared Error', metrics.mean_squared_error(y_test, y_pred, squared=True)) # algorithm.Plot("Error", 'Root Mean Squared Error', np.sqrt(metrics.mean_squared_error(y_test, y_pred, squared=False))) direction = InsightDirection.Down if (exit_market): algorithm.Plot("In vs Out", "Market", -1) direction = InsightDirection.Down self.outday = self.count elif (self.count >= wait_days + self.outday): algorithm.Plot("In vs Out", "Market", 1) direction = InsightDirection.Up else: direciton = InsightDirection.Flat algorithm.Plot("In vs Out", "Market", 0) self.count += 1 # algorithm.Plot("Wait Days", "Actual", self.count) # algorithm.Plot("Wait Days", "Expected", float(wait_days + self.outday)) # algorithm.Plot("Market Volatility", str(self.MKT), float(vola)) # if direction == InsightDirection.Down: # val = -1.0 # elif direction == InsightDirection.Up: # val = 1.0 # else: # val = 0.0 # algorithm.Plot("IN vs Out", "Before", float(val)) if self.MKT_MOMP.Current.Value > 0: val = 1 elif self.MKT_MOMP.Current.Value < 0: val = -1 else: val = 0 algorithm.Plot("In vs Out", "MKT_MOMP", float(val)) if self.in_out: algorithm.Plot("In vs Out", "MKT_RandomForest", float(-1)) elif not self.in_out: algorithm.Plot("In vs Out", "MKT_RandomForest", float(1)) algorithm.Plot("Magnitude", "MKT_MOMP", float(self.MKT_MOMP.Current.Value)) algorithm.Plot("Magnitude", "MKT_RandomForest", float(self._mag)) algorithm.Plot("Magnitude", "MKT_Actual", float(self._mag_actual)) insights.append(Insight.Price(self.MKT, self.predictionInterval, direction, self._mag, None)) # if self.in_out: # bull = False # bear = True # else: # bull = True # bear = False # payload = json.dumps({"Predicted SPY % Change": self._mag, # "Bull Market": bull, # "Bear Market": bear # }) # algorithm.Notify.Web("https://discordapp.com/api/webhooks/955625600750587924/WrhQbKDBWnUTwYoB74M_2ujJVuEnu7nRjLYxT5g-gYhwaRTrkTzVUsNxGVuRGeMmmE2L", payload) return insights def ml_model(self): # # ML Model # pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP] # data = self.history # data['vola'] = data[self.MKT].pct_change().rolling(246).std() * np.sqrt(252) # data['wait_days'] = data['vola'].map(lambda x: int(int(x)*self.BASE_RET), na_action='ignore') # data['period'] = data['vola'].map(lambda x: int((1.0 - int(x)) * self.BASE_RET), na_action='ignore') # market_signals = list() # for i in range(0, len(data['period'])): # if 'na' not in str(data['period'][i]): # count = int(i) # period = int(data['period'][i]) # r = data[count:count+246].pct_change(period).iloc[-1] # exit_market = (r[self.SLV] < r[self.GLD] and r[self.XLI] < r[self.XLU] and r[self.DBB] < r[self.UUP]) # market_signals.append(exit_market) # else: # market_signals.append('na') # data['market_signals'] = market_signals # del market_signals # data['Market_Change'] = data[self.MKT].pct_change() # # # Load LabelEncoder to process string variables # le = preprocessing.LabelEncoder() # ml_data = data.dropna() # pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP, 'vola', 'wait_days', 'period', 'Market_Change'] # X = ml_data.drop(['market_signals'], axis=1) # y = np.ravel(ml_data[['market_signals']].astype(str).apply(le.fit_transform)) # algorithm.Debug(str(X.shape) + ";" + str(y.shape)) # X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Prepare Data pairs = [self.MKT, self.SLV, self.GLD, self.XLI, self.XLU, self.DBB, self.UUP] df = self.algorithm.History(pairs, 252, Resolution.Daily).close # Prepare Data returns = df.unstack(level=1).transpose().dropna() returns["Volatility"] = np.nan returns["Wait_Days"] = np.nan returns["Period"] = np.nan returns["Exit_Market"] = np.nan vola_list = [np.nan] * 126 wait_list = [np.nan] * 126 period_list = [np.nan] * 126 exit_market_list = [np.nan] * 126 for i in range(len(returns)-126): temp_df = returns.iloc[i:i+126] vola = temp_df[self.MKT].pct_change().std() * np.sqrt(252) wait_days = int(vola * self.BASE_RET) period = int((1.0 - vola) * self.BASE_RET) r = temp_df.pct_change(period).iloc[-1] exit_market = r[self.SLV] < r[self.GLD] and r[self.XLI] < r[self.XLU] and r[self.DBB] < r[self.UUP] vola_list.append(vola) wait_list.append(wait_days) period_list.append(period) exit_market_list.append(exit_market) returns["Volatility"] = vola_list returns["Wait_Days"] = wait_list returns["Period"] = period_list returns["Exit_Market"] = exit_market_list returns = returns.dropna().iloc[-126:] # y data le = preprocessing.LabelEncoder() y_clf = le.fit_transform(returns["Exit_Market"]) y = returns[self.MKT] X = returns self.algorithm.Debug(str(X.shape)+","+str(y.shape)+","+str(y_clf.shape)) # Train Split Data X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1990) X_train, X_test, y_train_clf, y_test_clf = train_test_split(X, y_clf, test_size = 0.2, random_state = 1990) # Initialize instance of Random Forest Regressor and Classifier self.regressor = RandomForestRegressor(n_estimators=500, criterion="mse", min_samples_split=5, random_state=1990) self.classifier = RandomForestClassifier(n_estimators=500, criterion="gini", min_samples_split=5, random_state=1990) # Fit regressor and classifier self.regressor.fit(X_train, y_train) self.classifier.fit(X_train, y_train_clf) # Get long-only predictions weights = self.regressor.feature_importances_ symbols = X.columns[np.where(weights)] selected = zip(symbols, weights) y_pred = self.regressor.predict(X_test) y_pred_clf = self.classifier.predict(X_test) self._mag_actual = 100*float(y_test[-1] - y_test[-2]) / y_test[-2] self._mag = 100*float(y_pred[-1] - y_pred[-2]) / y_pred[-2] self.in_out = le.inverse_transform(y_pred_clf)[-1] self.algorithm.Plot("MKT Price", "Actual", float(y_test[-1])) self.algorithm.Plot("MKT Price", "Predicted", float(y_pred[-1])) self.algorithm.Plot("Model Accuracy", "Regression", float(self.regressor.score(X_test, y_test)*100)) self.algorithm.Plot("Model Accuracy", "Classification", float(self.classifier.score(X_test, y_test_clf)*100)) self.algorithm.Plot("Error", 'Mean Absolute Error', metrics.mean_absolute_error(y_test, y_pred)) self.algorithm.Plot("Error", 'Mean Squared Error', metrics.mean_squared_error(y_test, y_pred, squared=True)) self.algorithm.Plot("Error", 'Root Mean Squared Error', np.sqrt(metrics.mean_squared_error(y_test, y_pred, squared=False)))
#region imports from AlgorithmImports import * #endregion import pandas as pd import numpy as np from scipy.optimize import minimize class myTrailingStopRiskManagementModel: ''' Credit goes to: Alex Catarino and many of his friends at QuantConnect https://github.com/QuantConnect/Lean/blob/master/Algorithm.Framework/Risk/TrailingStopRiskManagementModel.py Description: Limits the maximum possible loss measured from the highest unrealized profit ''' def __init__(self, maximumDrawdownPercent = 0.08): '''initializes the class Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown ''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.trailingHighs = dict() def setDD(self, maximumDrawdownPercent = 0.08): '''allows to change the drawdown Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown ''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) def setWTtoZeroIfDDtooHigh(self, algorithm, targets=None): '''If drawdown is too high, set wt[symbol] to zero algo.wt[symbol] = weights which will be set to 0 in case drawdown exceeds the maximum ''' for kvp in algorithm.Securities: symbol = kvp.Key security = kvp.Value # Remove from trailingHighs dict if not invested if not security.Invested: self.trailingHighs.pop(symbol, None) continue # Add newly invested securities to trailingHighs dict if symbol not in self.trailingHighs: self.trailingHighs[symbol] = security.Holdings.AveragePrice continue # Check for new highs and update trailingHighs dict if self.trailingHighs[symbol] < security.High: self.trailingHighs[symbol] = security.High continue # Calc the drawdown securityHigh = self.trailingHighs[symbol] drawdown = (security.Low / securityHigh) - 1 # If drawdown is too high, set symbol weight to zero if drawdown < self.maximumDrawdownPercent: algorithm.wt[symbol] = 0 return class myPortfolioOptimizer: ''' Credit goes to: Emilio Freire / InnoQuantivity https://innoquantivity.com/blogs/inno-blog/portfolio-optimization-quantconnect-research-algorithm https://www.quantconnect.com/forum/discussion/8128/portfolio-optimization-research-amp-algorithm-for-better-workflows/p1/comment-22952 Description: Implementation of a custom optimizer that calculates the weights for each asset to optimize a given objective function Details: Optimization can be: - Equal Weighting - Maximize Portfolio Return - Minimize Portfolio Standard Deviation - Mean-Variance (minimize Standard Deviation given a target return) - Maximize Portfolio Sharpe Ratio - Maximize Portfolio Sortino Ratio - Risk Parity Portfolio Constraints: - Weights must be between some given boundaries - Weights must sum to 1 ''' def __init__(self, minWeight = 0, maxWeight = 1): ''' Description: Initialize the CustomPortfolioOptimizer Args: minWeight(float): The lower bound on portfolio weights maxWeight(float): The upper bound on portfolio weights ''' self.minWeight = minWeight self.maxWeight = maxWeight def CalcWeights(self, algorithm, symbols, objectiveFunction='riskParity', lookback=63, targetReturn=None): ''' Description: Calculate weights from daily returns, return a pandas Series ''' history = np.log10(algorithm.History(symbols, lookback, Resolution.Daily)['close'].unstack(level = 0)) returnsDf = history.pct_change().dropna() returnsDf.columns = [algorithm.AddEquity(i).Symbol.Value for i in list(returnsDf.columns)] weights = self.Optimize(objectiveFunction, returnsDf, targetReturn) return pd.Series(weights, index=returnsDf.columns, name='weights') def Optimize(self, objFunction, dailyReturnsDf, targetReturn = None): ''' Description: Perform portfolio optimization given a series of returns Args: objFunction: The objective function to optimize (equalWeighting, maxReturn, minVariance, meanVariance, maxSharpe, maxSortino, riskParity) dailyReturnsDf: DataFrame of historical daily arithmetic returns Returns: Array of double with the portfolio weights (size: K x 1) ''' # initial weights: equally weighted size = dailyReturnsDf.columns.size # K x 1 self.initWeights = np.array(size * [1. / size]) # get sample covariance matrix covariance = dailyReturnsDf.cov() # get the sample covariance matrix of only negative returns for sortino ratio negativeReturnsDf = dailyReturnsDf[dailyReturnsDf < 0] covarianceNegativeReturns = negativeReturnsDf.cov() if objFunction == 'equalWeighting': return self.initWeights bounds = tuple((self.minWeight, self.maxWeight) for x in range(size)) constraints = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1.0}] if objFunction == 'meanVariance': # if no target return is provided, use the resulting from equal weighting if targetReturn is None: targetReturn = self.CalculateAnnualizedPortfolioReturn(dailyReturnsDf, self.initWeights) constraints.append( {'type': 'eq', 'fun': lambda weights: self.CalculateAnnualizedPortfolioReturn(dailyReturnsDf, weights) - targetReturn} ) opt = minimize(lambda weights: self.ObjectiveFunction(objFunction, dailyReturnsDf, covariance, covarianceNegativeReturns, weights), x0 = self.initWeights, bounds = bounds, constraints = constraints, method = 'SLSQP') return opt['x'] def ObjectiveFunction(self, objFunction, dailyReturnsDf, covariance, covarianceNegativeReturns, weights): ''' Description: Compute the objective function Args: objFunction: The objective function to optimize (equalWeighting, maxReturn, minVariance, meanVariance, maxSharpe, maxSortino, riskParity) dailyReturnsDf: DataFrame of historical daily returns covariance: Sample covariance covarianceNegativeReturns: Sample covariance matrix of only negative returns weights: Portfolio weights ''' if objFunction == 'maxReturn': f = self.CalculateAnnualizedPortfolioReturn(dailyReturnsDf, weights) return -f # convert to negative to be minimized elif objFunction == 'minVariance': f = self.CalculateAnnualizedPortfolioStd(covariance, weights) return f elif objFunction == 'meanVariance': f = self.CalculateAnnualizedPortfolioStd(covariance, weights) return f elif objFunction == 'maxSharpe': f = self.CalculateAnnualizedPortfolioSharpeRatio(dailyReturnsDf, covariance, weights) return -f # convert to negative to be minimized elif objFunction == 'maxSortino': f = self.CalculateAnnualizedPortfolioSortinoRatio(dailyReturnsDf, covarianceNegativeReturns, weights) return -f # convert to negative to be minimized elif objFunction == 'riskParity': f = self.CalculateRiskParityFunction(covariance, weights) return f else: raise ValueError(f'PortfolioOptimizer.ObjectiveFunction: objFunction input has to be one of equalWeighting,' + ' maxReturn, minVariance, meanVariance, maxSharpe, maxSortino or riskParity') def CalculateAnnualizedPortfolioReturn(self, dailyReturnsDf, weights): annualizedPortfolioReturns = np.sum( ((1 + dailyReturnsDf.mean())**252 - 1) * weights ) return annualizedPortfolioReturns def CalculateAnnualizedPortfolioStd(self, covariance, weights): annualizedPortfolioStd = np.sqrt( np.dot(weights.T, np.dot(covariance * 252, weights)) ) if annualizedPortfolioStd == 0: raise ValueError(f'PortfolioOptimizer.CalculateAnnualizedPortfolioStd: annualizedPortfolioStd cannot be zero. Weights: {weights}') return annualizedPortfolioStd def CalculateAnnualizedPortfolioNegativeStd(self, covarianceNegativeReturns, weights): annualizedPortfolioNegativeStd = np.sqrt( np.dot(weights.T, np.dot(covarianceNegativeReturns * 252, weights)) ) if annualizedPortfolioNegativeStd == 0: raise ValueError(f'PortfolioOptimizer.CalculateAnnualizedPortfolioNegativeStd: annualizedPortfolioNegativeStd cannot be zero. Weights: {weights}') return annualizedPortfolioNegativeStd def CalculateAnnualizedPortfolioSharpeRatio(self, dailyReturnsDf, covariance, weights): annualizedPortfolioReturn = self.CalculateAnnualizedPortfolioReturn(dailyReturnsDf, weights) annualizedPortfolioStd = self.CalculateAnnualizedPortfolioStd(covariance, weights) annualizedPortfolioSharpeRatio = annualizedPortfolioReturn / annualizedPortfolioStd return annualizedPortfolioSharpeRatio def CalculateAnnualizedPortfolioSortinoRatio(self, dailyReturnsDf, covarianceNegativeReturns, weights): annualizedPortfolioReturn = self.CalculateAnnualizedPortfolioReturn(dailyReturnsDf, weights) annualizedPortfolioNegativeStd = self.CalculateAnnualizedPortfolioNegativeStd(covarianceNegativeReturns, weights) annualizedPortfolioSortinoRatio = annualizedPortfolioReturn / annualizedPortfolioNegativeStd return annualizedPortfolioSortinoRatio def CalculateRiskParityFunction(self, covariance, weights): ''' Spinu formulation for risk parity portfolio ''' assetsRiskBudget = self.initWeights portfolioVolatility = self.CalculateAnnualizedPortfolioStd(covariance, weights) x = weights / portfolioVolatility riskParity = (np.dot(x.T, np.dot(covariance, x)) / 2) - np.dot(assetsRiskBudget.T, np.log(x)) return riskParity
#region imports from AlgorithmImports import * #endregion import math class SupportResistance: # Get the S&R's for the last 2 weeks. def __init__(self, algorithm, ticker): self.Ticker = ticker self.Algorithm = algorithm self.Daily = RollingWindow[TradeBar](7); self.Min = algorithm.MIN(self.Ticker, 390, Resolution.Minute) # Range of today; breaking out of new highs/lows self.Max = algorithm.MAX(self.Ticker, 390, Resolution.Minute) algorithm.Consolidate(self.Ticker, Resolution.Daily, self.SaveDailyBars) def NextSupport(self): support = [] price = self.Algorithm.Securities[self.Ticker].Price # Rounded Price to $1 support.append( round(price) ) # Rounded Price to $10 support.append( int(math.floor(price / 10.0)) * 10 ) # Yesterday's OHLC Price support.append( self.Daily[0].Close ) support.append( self.Daily[0].Low ) # Append 7 day Low: support.append( min([bar.Low for bar in self.Daily]) ) support = sorted(support, reverse=True) return support[0] def NextResistance(self): resistance = [] price = self.Algorithm.Securities[self.Ticker].Price # Round Price Up to $1 resistance.append( math.ceil(price) ) # Rounded Price Up to $10 resistance.append( int(math.ceil(price / 10.0)) * 10 ) # Yesterday's Close, High resistance.append( self.Daily[0].Close ) resistance.append( self.Daily[0].High ) # Append 7 Day High resistance.append( max([bar.High for bar in self.Daily]) ) # Take the lowest value on the list resistance = sorted(resistance) return resistance[0] # Build a 14 day historical rolling window of underlying prices. def SaveDailyBars(self, bar): self.Daily.Add(bar) # Reset any "daily" indicators def Reset(self): self.Min.Reset() self.Max.Reset()
#region imports from AlgorithmImports import * #endregion from itertools import groupby import tweepy from datetime import datetime, timedelta, date import time import pandas as pd import numpy as np import re, math import scipy from math import ceil from collections import deque from itertools import chain from pytz import timezone import statistics from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * from QuantConnect.Data.Market import TradeBar from QuantConnect.Algorithm.Framework.Alphas import EmaCrossAlphaModel, RsiAlphaModel from QuantConnect.Algorithm.Framework.Execution import StandardDeviationExecutionModel, VolumeWeightedAveragePriceExecutionModel from QuantConnect.Algorithm.Framework.Risk import MaximumDrawdownPercentPortfolio, MaximumUnrealizedProfitPercentPerSecurity, MaximumDrawdownPercentPerSecurity, TrailingStopRiskManagementModel from dual_momentum_with_out_days_alpha import DualMomentumWithOutDaysAlphaModel from portfolio_management import PortfolioManagementModel from trade_execution import ScheduledExecutionModel from manage_risk import CustomRiskModel from symbol_data_functions import SymbolData from market_profile import Market_Profile VOLA = 126; BASE_RET = 83; RET = 252; EXCL = 21; LEV = 1.00; class HorizontalQuantumCoil(QCAlgorithm): def Initialize(self): self.Portfolio.MarginCallModel = MarginCallModel.Null self.EnableAutomaticIndicatorWarmUp = True self.SetStartDate(2008, 1, 1) #self.SetEndDate(2013, 8, 1) self.SetCash(10000) self.added_cash = 115 self.upkeep = 28 self.simulate_live = False self.SetWarmUp(timedelta(252)) self.Settings.FreePortfolioValuePercentage = 0.05 # self.SetBrokerageModel(BrokerageName.AlphaStreams) self.SetAlpha(DualMomentumWithOutDaysAlphaModel(self, VOLA, BASE_RET, Resolution.Daily)) stonks = ['FDN', 'QQQ', 'IWM', 'SPY', 'VTI', 'DIA', 'IWF', 'TLT', 'TLH', 'IEI', 'IEF'] # , 'SPDN' # 'IYW', 'IVV', #lev_stonks = ['TQQQ', 'URTY', 'SPXL', 'TMF']# , 'AGQ', 'UGL'] symbols = [] # stonks = stonks + lev_stonks for stonk in stonks: val = Symbol.Create(stonk, SecurityType.Equity, Market.USA) symbols.append(val) self.SetUniverseSelection(ManualUniverseSelectionModel(symbols)) self.UniverseSettings.Resolution = Resolution.Daily self.SetPortfolioConstruction(PortfolioManagementModel(self, RET, EXCL, LEV, Resolution.Daily, portfolioBias = PortfolioBias.Long)) self.SetExecution(ScheduledExecutionModel(self)) self.SetRiskManagement(CustomRiskModel(self, maximumDrawdownPercent = 0.025, maximumUnrealizedProfitPercent = 0.175, resolution = Resolution.Daily)) # self.market_profile = Market_Profile() # self.optionsData = dict() # self.ASSETS = list() # for symbol in stonks: # self.optionsData[symbol] = dict() # sec = self.AddEquity(symbol) # self.ASSETS.append(symbol) # sec.SetDataNormalizationMode(DataNormalizationMode.Raw) # option = self.AddOption(symbol) # option.SetFilter(self.OptionFilterUniverse) # _Trade = TradeManagement(self, symbol, option.Symbol) # _SupportResistance = SupportResistance(self, symbol) # _mean = self.EMA(symbol, 5, Resolution.Hour) # self.optionsData[symbol]["Trade"] = _Trade # self.optionsData[symbol]["RS"] = _SupportResistance # self.optionsData[symbol]["mean"] = _mean # # self.consolidator = TradeBarConsolidator(timedelta(minutes=24*60)) # # self.consolidator.DataConsolidated += self.consolidation_handler # # self.SubscriptionManager.AddConsolidator(symbol, self.consolidator) # self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.At(0, 0), self.market_profile.GetMarketProfile(self, 21, self.ASSETS)) # self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", -1), self.MarketClose) self.createPlots("SPY") for time in range(55, 295, 30): self.Schedule.On(self.DateRules.EveryDay("SPY"), \ self.TimeRules.AfterMarketOpen("SPY", time), \ self.UpdateTickets) if self.simulate_live: self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), \ self.TimeRules.BeforeMarketClose("SPY", 0), \ self.AddCash) self.Schedule.On(self.DateRules.MonthStart("SPY"), \ self.TimeRules.BeforeMarketClose("SPY", 0), \ self.UpKeep) # def consolidation_handler(self, sender, consolidated): # self.history.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close # self.history = self.history.iloc[-(21):] def createPlots(self, benchmark): self.__benchmark = benchmark self.__plot_every_n_days = 5 self.__plot_every_n_days_i = 0 plot = Chart('Performance') plot.AddSeries(Series(self.__benchmark, SeriesType.Line, 0, '%')) plot.AddSeries(Series("Algorithm", SeriesType.Line, 0, '%')) self.AddChart(plot) self.ResetPlot() def ResetPlot(self): self.year = self.Time.year self.__cost_portfolio = None self.__cost_benchmark = None def CalculateBenchmarkPerformance(self): price = self.Securities[self.__benchmark].Price if self.__cost_benchmark == None: self.__cost_benchmark = price return 100.0 * ((price / self.__cost_benchmark) - 1.0) def CalculatePortfolioPerformance(self): if self.__cost_portfolio == None: self.__cost_portfolio = self.Portfolio.TotalPortfolioValue return 100.0 * ((self.Portfolio.TotalPortfolioValue / self.__cost_portfolio) - 1.0) # def CloseTo(self, x, y, delta): # return abs(x-y) < delta # def OnData(self, data): # for sec in self.optionsData.keys(): # _Trade = self.optionsData.get(sec).get("Trade") # _SupportResistance = self.optionsData.get(sec).get("RS") # _mean = self.optionsData.get(sec).get("mean") # _Trade.ManageOpenPositions() # price = sec.Price # support = _SupportResistance.NextSupport() # resistance = _SupportResistance.NextResistance() # mean = _mean.Current.Value # if (self.CloseTo(price, support, 0.1) and (mean > support)) and self.Portfolio[sec].Invested: # t = _Trade.Create(OrderDirection.Buy) # self.Log(f"{self.Time} LONG: Price {price} Support {support}") # if (self.CloseTo(price, resistance, 0.1) and (mean < resistance)) and self.Portfolio[sec].Invested: # t = _Trade.Create(OrderDirection.Sell) # self.Log(f"{self.Time} SHORT: Price {price} Resistance {resistance}") def OnEndOfDay(self): if self.IsWarmingUp or not self.Securities[self.__benchmark].HasData: return openOrders = self.Transactions.GetOpenOrders() openLimitOrders = [order for order in openOrders if (order.Type == OrderType.Limit) or (order.Type == OrderType.StopMarket)] if len(openLimitOrders)> 0: for x in openLimitOrders: self.Transactions.CancelOrder(x.Id) if self.Time.year != self.year: self.ResetPlot() self.__plot_every_n_days_i == -1 self.__plot_every_n_days_i += 1 if self.__plot_every_n_days_i % self.__plot_every_n_days != 0: return self.Plot('Performance', self.__benchmark, self.CalculateBenchmarkPerformance()) self.Plot('Performance', "Algorithm", self.CalculatePortfolioPerformance()) # self.Plot(f"Cash", "Remaining", self.Portfolio.Cash) # total_unrealized_pct = 0 # for kvp in self.Portfolio: # security_holding = kvp.Value # sec = security_holding.Symbol.Value # if self.Portfolio[sec].Invested: # self.Plot(f"UnrealizedProfitPercent", str(sec), self.Portfolio[sec].UnrealizedProfitPercent) # total_unrealized_pct += self.Portfolio[sec].UnrealizedProfitPercent # # security_holding = round(float(self.Portfolio[sec].AveragePrice*self.Portfolio[sec].Quantity), 3) # # if security_holding >= int(self.Portfolio.Cash*0.4): # # self.Plot(f"UnrealizedProfitPercent", str(sec)+"_at 0.5 bp", self.Portfolio[sec].UnrealizedProfitPercent) # # elif security_holding >= int(self.Portfolio.Cash*0.1): # # self.Plot(f"UnrealizedProfitPercent", str(sec)+"_at 0.1 bp", self.Portfolio[sec].UnrealizedProfitPercent) # # self.Plot(f"Cash", str(sec), round(self.Portfolio[sec].AveragePrice*self.Portfolio[sec].Quantity, 4)) # self.Plot(f"UnrealizedProfitPercent", "Total", total_unrealized_pct) def MarketOpen(self): return self.Time.hour != 0 and self.Time.minute == 1 # def MarketClose(self): # for sec in self.optionsData.keys(): # _SupportResistance = self.optionsData.get(sec).get("RS") # _SupportResistance.Reset() def UpdateTickets(self): openOrders = self.Transactions.GetOpenOrders() openLimitOrders = [order for order in openOrders if (order.Type == OrderType.Limit) or (order.Type == OrderType.StopMarket)] if len(openLimitOrders)> 0: for x in openLimitOrders: self.Transactions.CancelOrder(x.Id) invested = [x.Key for x in self.Portfolio if x.Value.Invested] for symbol in invested: security_holding = self.Portfolio[symbol] quantity = security_holding.Quantity price = security_holding.AveragePrice unrealized_profit_pct = self.Portfolio[symbol].UnrealizedProfitPercent security_holding = round(float(self.Portfolio[symbol].AveragePrice*self.Portfolio[symbol].Quantity), 3) if security_holding >= int(self.Portfolio.Cash*0.4): if self.Securities[symbol].Price > round(self.Portfolio[symbol].AveragePrice*1.1, 3): stopPrice = self.Securities[symbol].Price * 0.9725 limitPrice = self.Securities[symbol].Price * 1.0375 self.StopMarketOrder(symbol, -quantity, stopPrice) self.LimitOrder(symbol, -quantity, limitPrice) elif security_holding <= int(self.Portfolio.Cash*0.25): if self.Securities[symbol].Price > round(self.Portfolio[symbol].AveragePrice*1.1, 3): stopPrice = self.Securities[symbol].Price * 0.97 limitPrice = self.Securities[symbol].Price * 1.05 self.StopMarketOrder(symbol, -quantity, stopPrice) self.LimitOrder(symbol, -quantity, limitPrice) def AddCash(self): self.Portfolio.SetCash(self.Portfolio.Cash + self.added_cash) def UpKeep(self): self.Portfolio.SetCash(self.Portfolio.Cash - self.upkeep) # #### Scratch # def OptionFilterUniverse(self, universe): # # Select puts 2-3 strikes OOM, expiring at least 2 days out; but no more than 7 # return universe.IncludeWeeklys().Strikes(-3, 3).Expiration(2, 7)
from AlgorithmImports import * from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * from QuantConnect.Data.Market import TradeBar from QuantConnect.Indicators.CandlestickPatterns import * import pandas as pd import numpy as np from scipy import stats import statistics from operator import itemgetter from functools import reduce from symbol_data_functions import SymbolData class CustomRiskModel(RiskManagementModel): def __init__(self, algorithm, maximumDrawdownPercent = 0.025, maximumUnrealizedProfitPercent = 0.175, resolution = Resolution.Daily, *args, **kwargs): super().__init__() '''Initializes a new instance class with various risk management systems Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown maximumUnrealizedProfitPercent: The maximum percentage unrealized profit allowed for any single security holding, defaults to 5% drawdown per security''' self.resolution = resolution self.maximumUnrealizedProfitPercent = abs(maximumUnrealizedProfitPercent) self.TotalmaximumUnrealizedProfitPercent = abs(maximumUnrealizedProfitPercent) * 1.5 self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.TotalmaximumDrawdownPercent = -abs(maximumDrawdownPercent) * 1.5 self.Liquidate_all = False self.total_unrealized_profit_pct = 0.0 self.total_drawdown_pct = 0.0 self.trailing = dict() def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance targets: The current portfolio targets to be assessed for risk''' targets = [] for kvp in algorithm.Securities: symbol = kvp.Key security = kvp.Value # # Remove if not invested # if not security.Invested: # self.trailing.pop(symbol, None) # continue unrealized_profit_pct = security.Holdings.UnrealizedProfitPercent # # Add newly invested securities # value = self.trailing.get(symbol) # if value == None: # newValue = unrealized_profit_pct if unrealized_profit_pct > 0 else 0 # self.trailing[symbol] = newValue # continue # # Check for new high and update # if value < unrealized_profit_pct: # self.trailing[symbol] = unrealized_profit_pct # continue # self.total_unrealized_profit_pct += unrealized_profit_pct # # Liquidate if Drawdown from MaximumUnrealizedProfitPercent is reached: # pnl = self.GetDrawdownPercent(unrealized_profit_pct, symbol) # if len(targets) != 0: # unreal_pct = self.maximumUnrealizedProfitPercent # if unreal_pct > 0.175: # if pnl < float(self.maximumDrawdownPercent - 2.0): # targets.append(PortfolioTarget(security.Symbol, 0)) # elif unreal_pct > 0.15: # if pnl < float(self.maximumDrawdownPercent - 2.0): # targets.append(PortfolioTarget(security.Symbol, 0)) # elif unreal_pct > 0.1: # if pnl < float(self.maximumDrawdownPercent - 2.0): # targets.append(PortfolioTarget(security.Symbol, 0)) # elif unreal_pct <= -0.04: # if pnl < float(self.maximumDrawdownPercent - 0.0): # targets.append(PortfolioTarget(security.Symbol, 0)) # self.total_drawdown_pct += pnl # If maximum unrealized profit percent reached, liquidate if unrealized_profit_pct > self.maximumUnrealizedProfitPercent: targets.append(PortfolioTarget(security.Symbol, 0)) # # If Total Porfolio Drawdown Percent is Met # if len(targets) != 0: # total_unreal_pct = self.TotalmaximumUnrealizedProfitPercent # if total_unreal_pct > 0.225: # if self.total_drawdown_pct < float(self.TotalmaximumDrawdownPercent - 4.0): # self.Liquidate_all = True # elif total_unreal_pct > 0.2: # if self.total_drawdown_pct < float(self.TotalmaximumDrawdownPercent - 4.0): # self.Liquidate_all = True # elif total_unreal_pct > 0.18: # if self.total_drawdown_pct < float(self.TotalmaximumDrawdownPercent - 4.0): # self.Liquidate_all = True # elif total_unreal_pct <= -0.8: # if self.total_drawdown_pct < float(self.TotalmaximumDrawdownPercent - 0.0): # self.Liquidate_all = True # If Total Porfolio Unrealized Profit Percent is Met # if self.total_unrealized_profit_pct > self.TotalmaximumUnrealizedProfitPercent: # self.Liquidate_all = True # if self.Liquidate_all is True: # targets = [ PortfolioTarget(target.Symbol, 0) for target in targets ] # if algorithm.Time.hour == 16 and algorithm.Time.minute == 0.00: # self.total_unrealized_profit_pct = 0.0 #self.total_drawdown_pct = 0.0 return targets # def GetDrawdownPercent(self, unrealized_profit_pct, symbol): # max_holding_pct = self.trailing.get(symbol) # cur_holding_pct = unrealized_profit_pct # return float(cur_holding_pct) - float(max_holding_pct)
#region imports from AlgorithmImports import * #endregion import scipy as sp from sklearn.linear_model import LinearRegression import numpy as np class Market_Profile: def __init__(self): # Define lists, dictionaries needed for storing values self.slope_dict = {} self.ranked_ra = {} self.volume_profiles = {} self.val = {} self.vah = {} self.pct_change = {} self.top_stocks = {} 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 ''' if self.Time.hour == 10 and self.Time.minute == 30: for key, value in self.ranked_ra.items(): if data.ContainsKey(key) and data[key] is not None: self.pct_change[key] = data[key].Price # some calculation with price at 10:30 AM; resulting value is stored in a dictionary as value with according key pair (I removed the calculation on purpose) self.pct_change = dict(sorted(self.pct_change.items(), key=lambda x: x[1], reverse=True)) ranked_pct_change = {item:index for index, item in enumerate(self.pct_change,1)} #Combine ranking of both ranked_ra & val_pct_change; Data is pulled from dictionaries stored in Initialize and they according was generated with DataGenerator-Function for key, value in self.ranked_ra.items(): if key not in ranked_pct_change: continue value_2 = ranked_pct_change[key] self.top_stocks[key] = value + value_2 #Rank stocks according to total rank self.top_stocks = dict(sorted(self.top_stocks.items(), key=lambda x: x[1], reverse=False)) def CalcMarketProfile(self, algorithm, timeframe, symbols): # Clear all the data from the past before starting the calculation for this day again self.slope_dict.clear() self.ranked_ra.clear() self.volume_profiles.clear() self.val.clear() self.vah.clear() history = algorithm.History(symbols, timeframe, Resolution.Daily) if history.empty or 'close' not in history.columns: return for symbol in symbols: price_data = history.loc[str(symbol)]["close"].iloc[-len(history):] y = np.log(price_data) x = np.arange(len(y)) slope, intercept, r_value, p_value, std_err = sp.stats.linregress(x,y) self.slope_dict[str(symbol)] = {"Slope":slope, "R²":r_value**2} self.slope_dict = dict(sorted(self.slope_dict.items(), key=lambda x: x[1]["R²"], reverse=True)) self.ranked_ra = {} for index, (key, item) in enumerate(self.slope_dict.items(),1): #if index >= len(self.slope_dict.keys())*0.1: # break self.ranked_ra[key] = index slices_vp = algorithm.History(list(self.ranked_ra.keys()), int(timeframe*8), Resolution.Hour) # timeframe*60 #Code to create volume profiles for all requested stocks for i in self.ranked_ra.keys(): #create stock keys in volume profile self.volume_profiles[str(i)] = {} low = round(min(slices_vp.loc[str(i)]["close"]), 2) high = round(max(slices_vp.loc[str(i)]["close"]), 2) price_range = high - low total_volume = sum(slices_vp.loc[str(i)]["volume"]) #create volume profile for every stock in keys for row in slices_vp.loc[str(i)].itertuples(): if row.volume > 0: key = round(row.close, 2) volume_per_level = row.volume if key not in self.volume_profiles[str(i)].keys(): self.volume_profiles[str(i)][str(key)] = volume_per_level else: self.volume_profiles[str(i)][str(key)] += volume_per_level # Set target volume - 70% of daily volume target_vol = sum(self.volume_profiles[str(i)].values()) * 0.7 # Get the price level that had the largest volume max_vol_price = max(self.volume_profiles[str(i)], key=self.volume_profiles[str(i)].get) # Setup a window to capture the POC, centered at the most liquid level curr_max_price = float(max_vol_price) curr_min_price = float(max_vol_price) curr_vol = self.volume_profiles[str(i)][max_vol_price] price_levels = sorted([float(price_level) for price_level, vol in self.volume_profiles[str(i)].items() if vol > 0]) # Grow window bounds until we have 70% of the day's volume captured while curr_vol < target_vol: # Price one level up price_up = None price_up_vol = 0 up_prices = [price for price in price_levels if price > curr_max_price] if len(up_prices) > 0: price_up = up_prices[0] price_up_vol = self.volume_profiles[str(i)][str(price_up)] # Price one level down price_down = None price_down_vol = 0 down_prices = [price for price in price_levels if price < curr_min_price] if len(down_prices) > 0: price_down = down_prices[-1] price_down_vol = self.volume_profiles[str(i)][str(price_down)] #Grow windows in the direction of more volume if price_up is not None and (price_up_vol > price_down_vol): curr_max_price = round(price_up, 2) curr_vol += price_up_vol else: curr_min_price = round(price_down, 2) curr_vol += price_down_vol # Save VAL, value area low & VAH, value area high for each stock self.val[str(i)] = curr_min_price self.vah[str(i)] = curr_max_price for key, value in self.ranked_ra.items(): self.pct_change[key] = algorithm.Securities[key].Price # some calculation with price at 10:30 AM; resulting value is stored in a dictionary as value with according key pair (I removed the calculation on purpose) self.pct_change = dict(sorted(self.pct_change.items(), key=lambda x: x[1], reverse=True)) ranked_pct_change = {item:index for index, item in enumerate(self.pct_change,1)} #Combine ranking of both ranked_ra & val_pct_change; Data is pulled from dictionaries stored in Initialize and they according was generated with DataGenerator-Function for key, value in self.ranked_ra.items(): if key not in ranked_pct_change: continue value_2 = ranked_pct_change[key] self.top_stocks[key] = value + value_2 #Rank stocks according to total rank self.top_stocks = dict(sorted(self.top_stocks.items(), key=lambda x: x[1], reverse=False)[:2]) return self.volume_profiles, self.val, self.vah, self.ranked_ra, self.top_stocks def GetMarketProfile(self, algorithm, symbol): return self.volume_profiles, self.val.get(str(symbol)), self.vah.get(str(symbol)), self.ranked_ra.get(str(symbol)), self.top_stocks
#region imports from AlgorithmImports import * #endregion from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * from QuantConnect.Data.Market import TradeBar from QuantConnect.Indicators.CandlestickPatterns import * import pandas as pd import numpy as np from scipy import stats from scipy.signal import argrelextrema import statistics import datetime as dt from operator import itemgetter from functools import reduce from helpers import myPortfolioOptimizer from symbol_data_functions import SymbolData from FilterIndicators import * from SmartRollingWindow import * from pykalman import KalmanFilter from market_profile import Market_Profile from trade import * from levels import * import scipy as sp from sklearn.linear_model import LinearRegression class PortfolioManagementModel(PortfolioConstructionModel): def __init__(self, algorithm, RET=252, EXCL=21, LEV=1.00, resolution = Resolution.Daily, portfolioBias = PortfolioBias.Long, *args, **kwargs): super().__init__() algorithm.PortfolioBias = portfolioBias self.resolution = resolution self.RET = RET self.EXCL = EXCL self.LEV = LEV self.VOLA = 126 self.STK1 = algorithm.AddEquity('SPY', self.resolution).Symbol # SPXL/SPY self.STK2 = algorithm.AddEquity('QQQ', self.resolution).Symbol # TQQQ/QQQ self.STK3 = algorithm.AddEquity('DIA', self.resolution).Symbol # DIA self.STK4 = algorithm.AddEquity('IWM', self.resolution).Symbol # URTY/IWM self.STK5 = algorithm.AddEquity('VTI', self.resolution).Symbol # AGQ/VTI self.STK6 = algorithm.AddEquity('FDN', self.resolution).Symbol # AGQ/VTI self.STK7 = algorithm.AddEquity('IWF', self.resolution).Symbol # AGQ/VTI self.BND1 = algorithm.AddEquity('TLH', self.resolution).Symbol # TMF/TLH self.BND2 = algorithm.AddEquity('TLT', self.resolution).Symbol # UGL/TLT self.BND3 = algorithm.AddEquity('IEI', self.resolution).Symbol # TMF/TLH self.BND4 = algorithm.AddEquity('IEF', self.resolution).Symbol # UGL/TLT #self.ALT1 = algorithm.AddEquity('XLE', self.resolution).Symbol # UGL/TLT #self.ALT2 = algorithm.AddEquity('GLD', self.resolution).Symbol # UGL/TLT # self.LEV1 = algorithm.AddEquity('SPXL', self.resolution).Symbol # self.LEV2 = algorithm.AddEquity('TQQQ', self.resolution).Symbol # self.LEV3 = algorithm.AddEquity('URTY', self.resolution).Symbol # self.LEV4 = algorithm.AddEquity('TMF', self.resolution).Symbol self.STOCKS = [self.STK1, self.STK2, self.STK3, self.STK4, self.STK5, self.STK6, self.STK7] #self.STOCKS_LEV = [self.LEV1, self.LEV2, self.LEV3] self.BONDS = [self.BND1, self.BND2, self.BND3, self.BND4] #self.BONDS_LEV = [self.LEV4] self.ASSETS = self.STOCKS + self.BONDS #+ self.STOCKS_LEV + self.BONDS_LEV #self.ASSETS_OPTIONS = dict() self.data = dict() # self.datafourHour = dict() # self.datathirtyMin = dict() self.market_profile = Market_Profile() self.QQQ_price = RollingWindow[float](5) self.QQQ_volume = RollingWindow[float](5) for symbol in self.ASSETS: self.consolidator = TradeBarConsolidator(timedelta(days=1)) self.consolidator.DataConsolidated += self.consolidation_handler algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator) # self.fourHour_consolidator = TradeBarConsolidator(timedelta(minutes=60*4)) # self.fourHour_consolidator.DataConsolidated += self.fourHour_consolidation_handler # algorithm.SubscriptionManager.AddConsolidator(symbol, self.fourHour_consolidator) # self.thirtyMinute_consolidator = TradeBarConsolidator(timedelta(minutes=30)) # self.thirtyMinute_consolidator.DataConsolidated += self.thirtyMinute_consolidation_handler # algorithm.SubscriptionManager.AddConsolidator(symbol, self.thirtyMinute_consolidator) self.history = np.log(algorithm.History(self.ASSETS, self.VOLA + 1, Resolution.Daily)) # self.historyHour = np.log(algorithm.History(self.ASSETS, (90*6), Resolution.Hour)) # self.historyMinute = np.log(algorithm.History(self.ASSETS, (15*24*2), Resolution.Minute)) self.pfo = myPortfolioOptimizer(minWeight=0, maxWeight=1) for symbol in self.ASSETS: algorithm.Securities[symbol].SetLeverage(1) # for symbol in self.ASSETS: # symbol.SetDataNormalizationMode(DataNormalizationMode.Raw) # self.ASSETS_OPTIONS[symbol] = dict() # _option = self.AddOption(symbol) # _option.SetFilter(self.OptionFilterUniverse) # _trade = TradeManagement(self, symbol, _option.Symbol) # _RS = SupportResistance(self, symbol) # self.ASSETS_OPTIONS[symbol]["Trade"] = _trade # self.ASSETS_OPTIONS[symbol]["option"] = _option # self.ASSETS_OPTIONS[symbol]["RS"] = _RS def consolidation_handler(self, sender, consolidated): self.history.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close self.history = self.history.iloc[-(self.VOLA + 1):] # def fourHour_consolidation_handler(self, sender, consolidated): # self.historyHour.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close # self.historyHour = self.historyHour.iloc[-(90*6):] # def thirtyMinute_consolidation_handler(self, sender, consolidated): # self.historyMinute.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close # self.historyMinute = self.historyMinute.iloc[-(15*24*2):] def OnSecuritiesChanged(self, algorithm, changes): addedSymbols = [] for security in changes.AddedSecurities: addedSymbols.append(security.Symbol) if security.Symbol not in self.data: self.data[security.Symbol] = SymbolData(algorithm, security.Symbol, Resolution.Daily) # self.datafourHour[security.Symbol] = SymbolData(algorithm, security.Symbol, Resolution.Hour) # self.datathirtyMin[security.Symbol] = SymbolData(algorithm, security.Symbol, Resolution.Minute) if len(addedSymbols) > 0: history = algorithm.History(addedSymbols, self.VOLA + 1, Resolution.Daily).loc[addedSymbols] for symbol in addedSymbols: try: history = np.log(history) self.data[symbol].Warmup(history.loc[symbol]) except: algorithm.Debug(str(symbol)) continue # # Four Hour # history = algorithm.History(addedSymbols, (90*6), Resolution.Hour).loc[addedSymbols] # for symbol in addedSymbols: # try: # history = np.log(history) # self.datafourHour[symbol].Warmup(history.loc[symbol]) # except: # algorithm.Debug(str(symbol)) # continue # # Thirty Minute # history = algorithm.History(addedSymbols, (15*24*2), Resolution.Minute).loc[addedSymbols] # for symbol in addedSymbols: # try: # history = np.log(history) # self.datathirtyMin[symbol].Warmup(history.loc[symbol]) # except: # algorithm.Debug(str(symbol)) # continue def calc_cndl_score(self, asset, res = "Daily"): if res == "Daily": cndl_coef = sum([x.Current.Value for x in self.data[asset].candles]) return cndl_coef def custom_filter(self, algorithm, symbol, filter_type = 'both'): data_list = [self.data]# [self.datathirtyMin, self.datafourHour, self.data] count = 0 for _dict in data_list: slope_cond = (_dict[symbol].roc_slope > 0.00) and (_dict[symbol].vol_slope > 0.00) slope_down = (_dict[symbol].roc_slope > 0.00) and (_dict[symbol].vol_slope > 0.00) signals = (_dict[symbol].breakout or (_dict[symbol].vpnIndicator and (_dict[symbol].is_uptrend and _dict[symbol].trix_uptrend or (_dict[symbol].roc_vol_signal_up and _dict[symbol].entry_signal and _dict[symbol].kal_entry_signal and _dict[symbol].rsi_entry_signal and _dict[symbol].macd_entry_signal and _dict[symbol].williams_entry_signal))) or (_dict[symbol].macd_uptrend and _dict[symbol].rsi_uptrend)) quick_signals = (_dict[symbol].vpnIndicator and (_dict[symbol].breakout or _dict[symbol].entry_signal or _dict[symbol].kal_entry_signal or _dict[symbol].rsi_entry_signal or _dict[symbol].macd_entry_signal or _dict[symbol].williams_entry_signal or _dict[symbol].quick_up)) down_signals = (_dict[symbol].breakdown or ((not _dict[symbol].vpnIndicator) and (_dict[symbol].is_downtrend and _dict[symbol].trix_downtrend or (_dict[symbol].roc_vol_signal_down and _dict[symbol].exit_signal and _dict[symbol].kal_exit_signal and _dict[symbol].rsi_exit_signal and _dict[symbol].macd_exit_signal and _dict[symbol].williams_exit_signal))) or (_dict[symbol].macd_downtrend and _dict[symbol].rsi_downtrend)) hh_cond = _dict[symbol].hh_all and _dict[symbol].hh_sum ll_cond = _dict[symbol].ll_all and _dict[symbol].ll_sum market_uptrend = (_dict[symbol].mp_entry_signal or _dict[symbol].mp_uptrend) and _dict[symbol].roc_vol_signal_up market_downtrend = (_dict[symbol].mp_exit_signal or _dict[symbol].mp_downtrend) and _dict[symbol].roc_vol_signal_down if filter_type == 'both': if (slope_cond) and (signals): count += 1 if filter_type == 'either': if (slope_cond) or (signals): count += 1 if filter_type == 'quick': if quick_signals and market_uptrend: count += 1 if filter_type == 'pullback': if (slope_cond) and (down_signals) and market_downtrend: count += 1 if filter_type == 'lev': if (slope_cond) and (_dict[symbol].median_roc_momentum >= 0.005) and (signals): count += 1 if count == len(data_list): return True else: return False def calc_vola(self, algorithm, sec): prices = np.log(algorithm.History(sec, TimeSpan.FromDays(126), self.resolution).close) volatility = prices.pct_change().std() * np.sqrt(252) return volatility def CreateTargets(self, algorithm, insights): # if algorithm.Time.hour == 00 and algorithm.Time.minute == 00: # for sec in self.ASSET_OPTIONS.keys(): # rs = self.ASSET_OPTIONS.get(sec) # rc.Reset() if algorithm.IsWarmingUp: return [] #if algorithm.Time.month == 1: return [] targets = [] # We expect at most only one active insight since we only # generate insights for one equity. assert len(insights) <= 1 if len(insights) == 1: insight = insights[0] if insight.Direction != InsightDirection.Flat: williams_fast = ((self.data[self.STK1].williamsPR.Current.Value >= -95.00) and (self.data[self.STK2].williamsPR.Current.Value >= -95.00)) williams_slow = ((self.data[self.STK1].williamsPR_slow.Current.Value >= -95.00) and (self.data[self.STK2].williamsPR_slow.Current.Value >= -95.00)) williams_median = ((self.data[self.STK1].williams_median >= -80.00) and (self.data[self.STK2].williams_median >= -80.00)) williams = williams_fast and williams_slow and williams_median market_uptrend = all(self.custom_filter(algorithm, symbol, filter_type = 'both') for symbol in [self.STK1, self.STK2, self.STK3, self.STK4]) and all(self.data[symbol].trix_uptrend for symbol in [self.STK1, self.STK2, self.STK3, self.STK4]) and all(self.data[symbol].mp_uptrend for symbol in [self.STK1, self.STK2, self.STK3, self.STK4]) bond_uptrend = all(self.custom_filter(algorithm, symbol, filter_type = 'both') for symbol in self.BONDS) and all(self.data[symbol].trix_uptrend for symbol in self.BONDS) and all(self.data[symbol].mp_uptrend for symbol in self.BONDS) if insight.Direction == InsightDirection.Down and williams and (not market_uptrend): self.bull = False elif not bond_uptrend: self.bull = True #self.market_profile.CalcMarketProfile(algorithm, 21, self.ASSETS) #top = [*e] #algorithm.Debug("top"+"_"+ str(len(top))+ "_"+str(top)) # for sec in [self.STK2]: # #algorithm.Debug("mp_"+str(a)) # #algorithm.Debug("val_"+str(b)) # #algorithm.Debug("vah_"+str(c)) # #algorithm.Debug("%change_"+str(d)) # #algorithm.Debug("top"+ str(len(e)) +"_"+str(e)) # # a, b, c, d, e = self.market_profile.GetMarketProfile(algorithm, sec) # # a = a.get(str(sec)) # # poc = float(max(a, key=a.get)) # # algorithm.Plot("Market Profile", str(sec)+"_POC", poc) # # algorithm.Plot("Market Profile", str(sec)+"_VAL", b) # # algorithm.Plot("Market Profile", str(sec)+"_VAH", c) # # #algorithm.Plot("Market Profile", str(sec)+"_%change", d) # # median_price = statistics.median([algorithm.Securities[sec].Open, algorithm.Securities[sec].High, algorithm.Securities[sec].Low, algorithm.Securities[sec].Close]) # # algorithm.Plot("Market Profile", str(sec)+"_MedianPrice", median_price) # # _50 = self.data[sec].vwap_fst.Current.Value # # _100 = self.data[sec].vwap_med.Current.Value # # #_150 = self.data[sec].vwap_mlng.Current.Value # # _200 = self.data[sec].vwap_lng.Current.Value # # algorithm.Plot("Market Profile", str(sec)+"_50", _50) # # algorithm.Plot("Market Profile", str(sec)+"_100", _100) # # #algorithm.Plot("Market Profile", str(sec)+"_150", _150) # # algorithm.Plot("Market Profile", str(sec)+"_200", _200) # # val = float(stats.sem([poc, b, c, median_price], axis=0)) # # algorithm.Plot("Standard Error Mean", str(sec), val) # # val_vwap = float(stats.sem([poc, b, c, median_price, _50, _100, _200], axis=0)) # # algorithm.Plot("Standard Error Mean", str(sec)+"_with_vwaps", val_vwap) # algorithm.Plot("UnrealizedProfitPercent", str(sec), algorithm.Portfolio[sec].UnrealizedProfitPercent) # holdings_pct = round(float(algorithm.Portfolio[sec].HoldingsValue)/algorithm.Portfolio.TotalPortfolioValue, 4) # roc = round(statistics.median([self.data[sec].roc.Current.Value, self.data[sec].roc_fast.Current.Value, self.data[sec].roc_med.Current.Value, self.data[sec].roc_long.Current.Value]), 4) # vol = round(statistics.median([self.data[sec].vol_roc.Current.Value, self.data[sec].vol_roc_fast.Current.Value, self.data[sec].vol_roc_med.Current.Value, self.data[sec].vol_roc_long.Current.Value]), 4) # self.QQQ_price.Add(roc) # self.QQQ_volume.Add(vol) # def calc_divergence(obj): # x = np.array(list(obj)) # local_maxima = argrelextrema(x, np.greater)[0] # local_minima = argrelextrema(x, np.less)[0] # if x[-1] > x[-2]: # x = np.append(x, len(x) - 1) # elif x[-1] > x[-2]: # x = np.append(x, len(x) - 1) # hh_all = all(x[local_maxima][i] < x[local_maxima][i+1] for i in range(len(local_maxima)-1)) # ll_all = all(x[local_minima][i] > x[local_minima][i+1] for i in range(len(local_minima)-1)) # return hh_all, ll_all # if self.QQQ_price.IsReady and self.QQQ_volume.IsReady: # algorithm.Plot("ROC", str(sec)+"price", float(sum(list(self.QQQ_price)))/5) # hh, ll = calc_divergence(list(self.QQQ_price)) # algorithm.Plot("Divergence", str(sec)+"_price_hh", float(int(hh))) # algorithm.Plot("Divergence", str(sec)+"_price_ll", float(int(ll))) # algorithm.Plot("ROC", str(sec)+"volume", float(sum(list(self.QQQ_volume)))/5) # hh, ll = calc_divergence(list(self.QQQ_volume)) # algorithm.Plot("Divergence", str(sec)+"_volume_hh", float(int(hh))) # algorithm.Plot("Divergence", str(sec)+"_volume_ll", float(int(ll))) # holdings_pct = round(float(algorithm.Portfolio[sec].HoldingsValue)/algorithm.Portfolio.TotalPortfolioValue, 4) # # if holdings_pct > 0.4: # # algorithm.Plot("UnrealizedProfitPercent", str(sec)+"_at 0.5 bp", algorithm.Portfolio[sec].UnrealizedProfitPercent) # # elif holdings_pct > 0.2: # # algorithm.Plot("UnrealizedProfitPercent", str(sec)+"_at 0.25 bp", algorithm.Portfolio[sec].UnrealizedProfitPercent) # # elif holdings_pct >= 0.1*0.9: # # algorithm.Plot("UnrealizedProfitPercent", str(sec)+"_at 0.1 bp", algorithm.Portfolio[sec].UnrealizedProfitPercent) # # else: # # algorithm.Plot("UnrealizedProfitPercent", str(sec)+"_at 0.0 bp", algorithm.Portfolio[sec].UnrealizedProfitPercent) # algorithm.Plot(f"Holdings Value %", str(sec), holdings_pct) # if insight.Direction == InsightDirection.Flat: # _dir = 0 # elif insight.Direction == InsightDirection.Up: # _dir = 1 # else: # _dir = -1 # algorithm.Plot("Bull vs Bear", "Market_Before", float(_dir)) # if not self.bull: # _dir = -1 # else: # _dir = 1 # algorithm.Plot("Bull vs Bear", "Market_After", float(_dir)) # _out = (median_price <= _200) and (median_price <= poc) and (holdings_pct >= 0.4) # algorithm.Plot(f"Trade Behavior", str(sec), float(int(_out))) selected = list() if self.bull: stocks = [(symbol, self.data[symbol].median_roc, self.data[symbol].volatility) for symbol in self.STOCKS if self.custom_filter(algorithm, symbol, filter_type = 'both')] stocks.sort(key=itemgetter(1, 2), reverse=True) for sec, roc, vola in stocks: if (len(selected) < 2): selected.append(sec) if len(selected) < 2: stocks = [(symbol, self.data[symbol].median_roc, self.data[symbol].volatility) for symbol in self.STOCKS if self.custom_filter(algorithm, symbol, filter_type = 'either')] stocks.sort(key=itemgetter(1, 2), reverse=True) for sec, roc, vola in stocks: if (len(selected) < 2) and (sec not in selected): selected.append(sec) elif not self.bull: bonds = [(symbol, self.data[symbol].median_roc, self.data[symbol].volatility) for symbol in self.BONDS if self.custom_filter(algorithm, symbol, filter_type = 'both')] bonds.sort(key=itemgetter(1, 2), reverse=True) for sec, roc, vola in bonds: if (len(selected) < 2): selected.append(sec) if len(selected) < 2: bonds = [(symbol, self.data[symbol].median_roc, self.data[symbol].volatility) for symbol in self.BONDS if self.custom_filter(algorithm, symbol, filter_type = 'either')] bonds.sort(key=itemgetter(1, 2), reverse=True) for sec, roc, vola in bonds: if (len(selected) < 2) and (sec not in selected): selected.append(sec) if insight.Direction == InsightDirection.Flat: return [] # self.asset_weights = self.pfo.CalcWeights(algorithm, selected, 'riskParity', lookback=21) # self.asset_weights_max = self.pfo.CalcWeights(algorithm, selected, 'maxReturn', lookback=21) # self.asset_weights_max_two = self.pfo.CalcWeights(algorithm, selected, 'maxReturn', lookback=42) #self.market_profile.CalcMarketProfile(algorithm, 21, self.ASSETS) for asset in self.ASSETS: cond_both = self.custom_filter(algorithm, asset, filter_type = 'both') cond_either = self.custom_filter(algorithm, asset, filter_type = 'either') cond_pullback = self.custom_filter(algorithm, asset, filter_type = 'pullback') median_price = statistics.median([algorithm.Securities[asset].Open, algorithm.Securities[asset].High, algorithm.Securities[asset].Low, algorithm.Securities[asset].Close]) profit_pct_cond = algorithm.Portfolio[asset].UnrealizedProfitPercent <= -0.05 holdings_pct = round(float(algorithm.Portfolio[asset].HoldingsValue)/algorithm.Portfolio.TotalPortfolioValue, 4) rocsignal = all(x > 0.0 for x in [self.data[asset].rocSignal_quick.Current.Value, self.data[asset].rocSignal_fast.Current.Value, self.data[asset].rocSignal_med.Current.Value, self.data[asset].rocSignal_long.Current.Value]) volsignal = all(x > 0.0 for x in [self.data[asset].volSignal_quick.Current.Value, self.data[asset].volSignal_fast.Current.Value, self.data[asset].volSignal_med.Current.Value, self.data[asset].volSignal_long.Current.Value]) roc_vol_signal = rocsignal and volsignal cond1 = ((all((self.calc_cndl_score(asset, res = tf) > 0) for tf in ["Daily"])) and cond_both) cond2 = ((all((self.calc_cndl_score(asset, res = tf) >= -2) for tf in ["Daily"])) or (cond_both and self.data[asset].cndl_uptrend)) cond3 = ((all((self.calc_cndl_score(asset, res = tf) >= -2) for tf in ["Daily"])) or (cond_either and self.data[asset].cndl_uptrend)) if (asset in selected) and (not cond_pullback): # weight = self.asset_weights[self.asset_weights.index == str(asset.Value)][0] # weight_max = self.asset_weights_max_two[self.asset_weights_max_two.index == str(asset.Value)][0] if ((algorithm.Portfolio[asset].Invested and (cond2 or cond3)) or cond1): if cond_pullback and ((profit_pct_cond) and (holdings_pct >= 0.1)): targets.append(PortfolioTarget.Percent(algorithm, asset, 0.0)) else: targets.append(PortfolioTarget.Percent(algorithm, asset, 0.5)) elif not algorithm.Portfolio[asset].Invested and (cond2 or cond3): if cond_pullback: targets.append(PortfolioTarget.Percent(algorithm, asset, 0.0)) elif roc_vol_signal: targets.append(PortfolioTarget.Percent(algorithm, asset, 0.25)) else: targets.append(PortfolioTarget.Percent(algorithm, asset, 0.1)) else: targets.append(PortfolioTarget.Percent(algorithm, asset, 0.0)) return targets # def ExecuteOptionsTrade(self, symbol): # _trade = self.ASSETS_OPTIONS.get(symbol).get("Trade") # _rs = self.ASSETS_OPTIONS.get(symbol).get("Trade") # def OptionFilterUniverse(self, universe): # # Select puts 2-3 strikes OOM, expiring at least 2 days out; but no more than 7 # return universe.IncludeWeeklys().Strikes(-3, 3).Expiration(2, 7)
from AlgorithmImports import * from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * from QuantConnect.Data.Market import TradeBar from QuantConnect.Indicators.CandlestickPatterns import * import inspect import pandas as pd import numpy as np from scipy import stats from scipy.signal import argrelextrema import statistics from operator import itemgetter from functools import reduce from FilterIndicators import * from SmartRollingWindow import * from pykalman import KalmanFilter from levels import * from market_profile import Market_Profile class SymbolData(object): def __init__(self, algorithm, symbol, resolution = Resolution.Daily, *args, **kwargs): super().__init__() self.Symbol = symbol self.res = Resolution.Daily if self.res == Resolution.Daily: consolidator = TradeBarConsolidator(timedelta(days=1)) # algorithm.ResolveConsolidator(symbol, self.res) tf_coef = 1 res = Resolution.Daily multi = 1 if self.res == Resolution.Hour: consolidator = TradeBarConsolidator(timedelta(minutes=60*4)) # algorithm.ResolveConsolidator(symbol, self.res) tf_coef = 2 res = Resolution.Hour multi = 1.25 if self.res == Resolution.Minute: consolidator = TradeBarConsolidator(timedelta(minutes=30)) # minutes=240 tf_coef = 6 res = Resolution.Minute multi = 1.5 self.lookback = 20 self.ceiling = 30 self.floor = 10 self.long = False self.short = False self.breakout = False self.breakdown = False self.quick_up = False self.quick_down = False self.hh_all = False self.ll_all = False self.hh_sum = False self.ll_sum = False self.EXCL = 21 self.scale = 0.00 self.volatility = 0.00 self.PriceIsFavorable = False self.vwap = IntradayVwap() self.SpreadIsFavorable = False self.tol = 0.98 self.acceptingSpreadPercent = 0.001 self.vol_slope = 0.00 self.vol_fast_slope = 0.00 self.roc_slope = 0.00 self.roc_fast_slope = 0.00 self.median_roc = 0.00 self.median_roc_hh = False self.median_roc_ll = False self.median_vol = 0.00 # Support Resistance self.long = False self.short = False self.Daily = RollingWindow[TradeBar](21) ### Market Profile self.market_profile = Market_Profile() self.mp_uptrend = False self.mp_downtrend = False self.mp_entry_signal = False self.mp_exit_signal = False self.poc_Win = RollingWindow[float](5) self.pocWin = SmartRollingWindow("float", 5) self.val_Win = RollingWindow[float](5) self.valWin = SmartRollingWindow("float", 5) self.vah_Win = RollingWindow[float](5) self.vahWin = SmartRollingWindow("float", 5) self.price_Win = RollingWindow[float](5) self.priceWin = SmartRollingWindow("float", 5) self.medpri_Win = RollingWindow[float](5) self.medpriWin = SmartRollingWindow("float", 5) self.vwap_fst = VolumeWeightedAveragePriceIndicator(50) self.vwap_med = VolumeWeightedAveragePriceIndicator(100) self.vwap_mlng = VolumeWeightedAveragePriceIndicator(150) self.vwap_lng = VolumeWeightedAveragePriceIndicator(200) self.vwap_fst_Win = RollingWindow[float](5) self.vwap_fstWin = SmartRollingWindow("float", 5) self.vwap_med_Win = RollingWindow[float](5) self.vwap_medWin = SmartRollingWindow("float", 5) self.vwap_lng_Win = RollingWindow[float](5) self.vwap_lngWin = SmartRollingWindow("float", 5) self.dont_buy = False self.is_uptrend = False self.is_downtrend = False self.entry_signal = False self.exit_signal = False self.stochasticFast = Stochastic(14, 3, 3) self.fast = ExponentialMovingAverage(8) self.fast_Win = RollingWindow[float](int(41*multi)) self.fastVwapWin = SmartRollingWindow("float", 5) self.stochasticSlow = Stochastic(21, 3, 3) self.slow = ExponentialMovingAverage(14) self.slow_Win = RollingWindow[float](int(41*multi)) self.slowVwapWin = SmartRollingWindow("float", 5) self.roc = RateOfChange(int(5*1.0)) self.roc_fast = RateOfChange(int(3*1.0)) self.roc_med = RateOfChange(int(8*1.0)) self.roc_long = RateOfChange(int(14*1.0)) self.vol_roc = RateOfChange(int(5*1.0)) self.vol_roc_fast = RateOfChange(int(3*1.0)) self.vol_roc_med = RateOfChange(int(8*1.0)) self.vol_roc_long = RateOfChange(int(14*1.0)) self.roc_Win = RollingWindow[float](int(5*multi)) self.roclen_Win = RollingWindow[float](int(5*multi)) self.rocSum_Win = RollingWindow[float](int(5*multi)) self.vol_Win = RollingWindow[float](int(5*multi)) self.prices_Win = RollingWindow[float](int(31*multi)) self.low_Win = RollingWindow[float](int(41*multi)) self.high_Win = RollingWindow[float](int(41*multi)) self.roc_prices_Win = RollingWindow[float](int(41*multi)) self.roc_prices_lev_Win = RollingWindow[float](int(10*multi)) self.roc_volume_Win = RollingWindow[float](int(41*multi)) self.stochasticMACD = Stochastic(34, 3, 3) self.macd = MovingAverageConvergenceDivergence(12, 26, 9, MovingAverageType.Exponential) self.macd_stochfast_Win = RollingWindow[float](int(5*multi)) self.macdStochFastWin = SmartRollingWindow("float", 5) self.macd_stochk_Win = RollingWindow[float](int(5*multi)) self.macdStochKWin = SmartRollingWindow("float", 5) self.macd_stochd_Win = RollingWindow[float](int(5*multi)) self.macdStochDWin = SmartRollingWindow("float", 5) self.macd_Win = RollingWindow[float](int(5*multi)) self.macdHist_Win = RollingWindow[float](int(5*multi)) self.macdFast_Win = RollingWindow[float](int(5*multi)) self.macdSlow_Win = RollingWindow[float](int(5*multi)) self.macdSignal_Win = RollingWindow[float](int(5*multi)) self.macdDelta_Win = RollingWindow[float](int(5*multi)) self.macd_uptrend = False self.macd_downtrend = False self.macd_entry_signal = False self.macd_exit_signal = False self.stochasticRSI = Stochastic(21, 3, 3) self.rsi = RelativeStrengthIndex(14, MovingAverageType.Wilders) self.rsi_Win = RollingWindow[float](int(5*multi)) self.rsiWin = SmartRollingWindow("float", 5) self.rsiFastStoch_Win = RollingWindow[float](int(5*multi)) self.rsiStochFastWin = SmartRollingWindow("float", 5) self.rsiStochK_Win = RollingWindow[float](int(5*multi)) self.rsiStochKWin = SmartRollingWindow("float", 5) self.rsiStochD_Win = RollingWindow[float](int(5*multi)) self.rsiStochDWin = SmartRollingWindow("float", 5) self.rsi_uptrend = False self.rsi_downtrend = False self.rsi_entry_signal = False self.rsi_exit_signal = False self.williamsPR = WilliamsPercentR(14) self.williamsPR_slow = WilliamsPercentR(21) self.williamsWin = RollingWindow[float](int(5*multi)) self.williamsPR_Win = RollingWindow[float](int(5*multi)) self.williamsPRWin = SmartRollingWindow("float", 5) self.williamsPR_slow_Win = RollingWindow[float](int(5*multi)) self.williamsPR_slowWin = SmartRollingWindow("float", 5) self.williams_median_roc = 0.00 self.williams_median = 0.00 self.williams_uptrend = False self.williams_downtrend = False self.vpnIndicator = False self.vpnScale = 0.00 self.vpn_period = 10 self.atr = AverageTrueRange(self.vpn_period, MovingAverageType.Exponential) self.vpn_vol_Win = RollingWindow[float](self.vpn_period) self.vpn_hlc_Win = RollingWindow[float](self.vpn_period) self.vpn_lst = RollingWindow[float](int(6*multi)) self.stochasticTrix = Stochastic(21, 3, 3) self.trix = Trix(9) self.trix_slow = Trix(18) self.trixFastStoch_Win = RollingWindow[float](int(5*multi)) self.trixStochFastWin = SmartRollingWindow("float", 5) self.trixStochK_Win = RollingWindow[float](int(5*multi)) self.trixStochKWin = SmartRollingWindow("float", 5) self.trixStochD_Win = RollingWindow[float](int(5*multi)) self.trixStochDWin = SmartRollingWindow("float", 5) self.trix_uptrend = False self.trix_downtrend = False self.trix_entry_signal = False self.trix_exit_signal = False self.rocSignal_quick = IndicatorExtensions.Over(self.roc_fast, self.roc_med) self.volSignal_quick = IndicatorExtensions.Over(self.vol_roc_fast, self.vol_roc_med) self.rocSignal_fast = IndicatorExtensions.Over(self.roc_fast, self.roc) self.volSignal_fast = IndicatorExtensions.Over(self.vol_roc_fast, self.vol_roc) self.rocSignal_med = IndicatorExtensions.Over(self.roc, self.roc_med) self.volSignal_med = IndicatorExtensions.Over(self.vol_roc, self.vol_roc_med) self.rocSignal_long = IndicatorExtensions.Over(self.roc_med, self.roc_long) self.volSignal_long = IndicatorExtensions.Over(self.vol_roc_med, self.vol_roc_long) self.rocvolSignal_Win = RollingWindow[float](int(5*multi)) self.rocvolSignal_median = 0.00 self.kalFilter = KalmanFilterIndicator(name='Kalman', period=5, selector=Field.Close) self.kalFilterLow = KalmanFilterIndicator(name='Kalman', period=5, selector=Field.Low) self.kalFilterHigh = KalmanFilterIndicator(name='Kalman', period=5, selector=Field.High) self.kalFilterOpen = KalmanFilterIndicator(name='Kalman', period=5, selector=Field.Open) self.kalWin = SmartRollingWindow("float", 5) self.kalWindowLow = SmartRollingWindow("float", 5) self.kalWindowHigh = SmartRollingWindow("float", 5) self.priceWin = SmartRollingWindow("float", 5) self.priceWindowLow = SmartRollingWindow("float", 5) self.priceWindowHigh = SmartRollingWindow("float", 5) self.kal_exit_signal = False self.kal_entry_signal = False # Candles self.cndl_abandonedbaby = AbandonedBaby() self.cndl_advanceblock = AdvanceBlock() self.cndl_belthold = BeltHold() self.cndl_breakway = Breakaway() self.cndl_closingmarubozu = ClosingMarubozu() self.cndl_concealedbabyswallow = ConcealedBabySwallow() self.cndl_counterattack = Counterattack() self.cndl_darkcloudcover = DarkCloudCover() self.cndl_doji = Doji() self.cndl_dojistar = DojiStar() self.cndl_dragonflydoji = DragonflyDoji() self.cndl_engulfing = Engulfing() self.cndl_eveningdojistar = EveningDojiStar() self.cndl_eveningstar = EveningStar() self.cndl_gapsidebysidewhite = GapSideBySideWhite() self.cndl_gravestonedoji = GravestoneDoji() self.cndl_hammer = Hammer() self.cndl_hangingman = HangingMan() self.cndl_harami = Harami() self.cndl_haramicross = HaramiCross() self.cndl_highwavecandle = HighWaveCandle() self.cndl_hikkake = Hikkake() self.cndl_hikkakemodified = HikkakeModified() self.cndl_homingpigeon = HomingPigeon() self.cndl_identicalthreecrows = IdenticalThreeCrows() self.cndl_inneck = InNeck() self.cndl_invertedhammer = InvertedHammer() self.cndl_kicking = Kicking() self.cndl_kickingbylength = KickingByLength() self.cndl_ladderbottom = LadderBottom() self.cndl_longleggeddoji = LongLeggedDoji() self.cndl_longlinecandle = LongLineCandle() self.cndl_marubozu = Marubozu() self.cndl_mathold = MatHold() self.cndl_matchinglow = MatchingLow() self.cndl_morningdojistar = MorningDojiStar() self.cndl_morningstar = MorningStar() self.cndl_onneck = OnNeck() self.cndl_pierce = Piercing() self.cndl_rickshawman = RickshawMan() self.cndl_risefallthreemethods = RiseFallThreeMethods() self.cndl_separatinglines = SeparatingLines() self.cndl_shootingstar = ShootingStar() self.cndl_shortlinecandle = ShortLineCandle() self.cndl_spinningtop = SpinningTop() self.cndl_stalledpattern = StalledPattern() self.cndl_sticksandwich = StickSandwich() self.cndl_takuri = Takuri() self.cndl_tasukigap = TasukiGap() self.cndl_threeblackcrows = ThreeBlackCrows() self.cndl_threeinside = ThreeInside() self.cndl_threelinest = ThreeLineStrike() self.cndl_threeoutside = ThreeOutside() self.cndl_threestarsinsouth = ThreeStarsInSouth() self.cndl_threewhitesoldiers = ThreeWhiteSoldiers() self.cndl_thrusting = Thrusting() self.cndl_tristar = Tristar() self.cndl_twocrows = TwoCrows() self.cndl_uniquethreeriver = UniqueThreeRiver() self.cndl_updowngapthreemethods = UpDownGapThreeMethods() self.cndl_upsidegaptwocrows = UpsideGapTwoCrows() self.candleWin = SmartRollingWindow("float", 5) self.candleavgWin = SmartRollingWindow("float", 5) self.candleContainer = RollingWindow[float](2) self.cndl_uptrend = False self.cndl_downtrend = False self.candlescore = 0.00 self.indicators = [self.roc, self.roc_fast, self.roc_med, self.roc_long, self.vwap_fst, self.vwap_med, self.vwap_lng, self.vwap_mlng, self.vol_roc, self.vol_roc_fast, self.vol_roc_med, self.vol_roc_long, self.vwap, self.fast, self.stochasticFast, self.slow, self.stochasticSlow, self.macd, self.stochasticMACD, self.rsi, self.stochasticRSI, self.williamsPR, self.williamsPR_slow, self.atr, self.stochasticTrix, self.trix, self.trix_slow, self.kalFilter, self.kalFilterOpen, self.kalFilterLow, self.kalFilterHigh] self.candles = [self.cndl_abandonedbaby, self.cndl_advanceblock, self.cndl_belthold, self.cndl_breakway, self.cndl_closingmarubozu, self.cndl_concealedbabyswallow, self.cndl_counterattack, self.cndl_darkcloudcover, self.cndl_doji, self.cndl_dojistar, self.cndl_dragonflydoji, self.cndl_engulfing, self.cndl_eveningdojistar, self.cndl_eveningstar, self.cndl_gapsidebysidewhite, self.cndl_gravestonedoji, self.cndl_hammer, self.cndl_hangingman, self.cndl_harami, self.cndl_haramicross, self.cndl_highwavecandle, self.cndl_hikkake, self.cndl_hikkakemodified, self.cndl_homingpigeon, self.cndl_identicalthreecrows, self.cndl_inneck, self.cndl_invertedhammer, self.cndl_kicking, self.cndl_kickingbylength, self.cndl_ladderbottom, self.cndl_longleggeddoji, self.cndl_longlinecandle, self.cndl_marubozu, self.cndl_mathold, self.cndl_matchinglow, self.cndl_morningdojistar, self.cndl_morningstar, self.cndl_onneck, self.cndl_pierce, self.cndl_rickshawman, self.cndl_risefallthreemethods, self.cndl_separatinglines, self.cndl_shootingstar, self.cndl_shortlinecandle, self.cndl_spinningtop, self.cndl_stalledpattern, self.cndl_sticksandwich, self.cndl_takuri, self.cndl_tasukigap, self.cndl_threeblackcrows, self.cndl_threeinside, self.cndl_threelinest, self.cndl_threeoutside, self.cndl_threestarsinsouth, self.cndl_threewhitesoldiers, self.cndl_thrusting, self.cndl_tristar, self.cndl_twocrows, self.cndl_uniquethreeriver, self.cndl_updowngapthreemethods, self.cndl_upsidegaptwocrows] self.indicators = self.indicators + self.candles for indicator in self.indicators: consolidator = algorithm.ResolveConsolidator(symbol, res) algorithm.RegisterIndicator(symbol, indicator, consolidator) # Warm up history = algorithm.History(symbol, int(126*tf_coef), res) if history.empty or 'close' not in history.columns: return for tuple in history.loc[symbol].itertuples(): tradeBar = TradeBar(tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume) median_price = round(float(statistics.median([tuple.open, tuple.high, tuple.low, tuple.close])), 4) tradeBar = TradeBar(self.kalFilterOpen.Value, self.kalFilterHigh.Value, self.kalFilterLow.Value, self.kalFilter.Value, tuple.volume) self.vwap_fst.Update(tradeBar) self.vwap_med.Update(tradeBar) self.vwap_mlng.Update(tradeBar) self.vwap_lng.Update(tradeBar) self.roc.Update(tuple.Index, median_price) self.roc_fast.Update(tuple.Index, median_price) self.roc_med.Update(tuple.Index, median_price) self.roc_long.Update(tuple.Index, median_price) self.rocSignal_quick.Update(tuple.Index, median_price) self.rocSignal_fast.Update(tuple.Index, median_price) self.rocSignal_med.Update(tuple.Index, median_price) self.rocSignal_long.Update(tuple.Index, median_price) self.vol_roc.Update(tuple.Index, tuple.volume) self.vol_roc_fast.Update(tuple.Index, tuple.volume) self.vol_roc_med.Update(tuple.Index, tuple.volume) self.vol_roc_long.Update(tuple.Index, tuple.volume) self.volSignal_quick.Update(tuple.Index, tuple.volume) self.volSignal_fast.Update(tuple.Index, tuple.volume) self.volSignal_med.Update(tuple.Index, tuple.volume) self.volSignal_long.Update(tuple.Index, tuple.volume) self.atr.Update(tradeBar) self.macd.Update(tuple.Index, median_price) self.fast.Update(tuple.Index, median_price) self.slow.Update(tuple.Index, median_price) self.williamsPR.Update(tradeBar) self.williamsPR_slow.Update(tradeBar) self.rsi.Update(tuple.Index, median_price) self.trix.Update(tuple.Index, median_price) self.trix_slow.Update(tuple.Index, median_price) # candles self.cndl_abandonedbaby.Update(tradeBar) self.cndl_advanceblock.Update(tradeBar) self.cndl_belthold.Update(tradeBar) self.cndl_breakway.Update(tradeBar) self.cndl_closingmarubozu.Update(tradeBar) self.cndl_concealedbabyswallow.Update(tradeBar) self.cndl_counterattack.Update(tradeBar) self.cndl_darkcloudcover.Update(tradeBar) self.cndl_doji.Update(tradeBar) self.cndl_dojistar.Update(tradeBar) self.cndl_dragonflydoji.Update(tradeBar) self.cndl_engulfing.Update(tradeBar) self.cndl_eveningdojistar.Update(tradeBar) self.cndl_eveningstar.Update(tradeBar) self.cndl_gapsidebysidewhite.Update(tradeBar) self.cndl_gravestonedoji.Update(tradeBar) self.cndl_hammer.Update(tradeBar) self.cndl_hangingman.Update(tradeBar) self.cndl_harami.Update(tradeBar) self.cndl_haramicross.Update(tradeBar) self.cndl_highwavecandle.Update(tradeBar) self.cndl_hikkake.Update(tradeBar) self.cndl_hikkakemodified.Update(tradeBar) self.cndl_homingpigeon.Update(tradeBar) self.cndl_identicalthreecrows.Update(tradeBar) self.cndl_inneck.Update(tradeBar) self.cndl_invertedhammer.Update(tradeBar) self.cndl_kicking.Update(tradeBar) self.cndl_kickingbylength.Update(tradeBar) self.cndl_ladderbottom.Update(tradeBar) self.cndl_longleggeddoji.Update(tradeBar) self.cndl_longlinecandle.Update(tradeBar) self.cndl_marubozu.Update(tradeBar) self.cndl_mathold.Update(tradeBar) self.cndl_matchinglow.Update(tradeBar) self.cndl_morningdojistar.Update(tradeBar) self.cndl_morningstar.Update(tradeBar) self.cndl_onneck.Update(tradeBar) self.cndl_pierce.Update(tradeBar) self.cndl_rickshawman.Update(tradeBar) self.cndl_risefallthreemethods.Update(tradeBar) self.cndl_separatinglines.Update(tradeBar) self.cndl_shootingstar.Update(tradeBar) self.cndl_shortlinecandle.Update(tradeBar) self.cndl_spinningtop.Update(tradeBar) self.cndl_stalledpattern.Update(tradeBar) self.cndl_sticksandwich.Update(tradeBar) self.cndl_takuri.Update(tradeBar) self.cndl_tasukigap.Update(tradeBar) self.cndl_threeblackcrows.Update(tradeBar) self.cndl_threeinside.Update(tradeBar) self.cndl_threelinest.Update(tradeBar) self.cndl_threeoutside.Update(tradeBar) self.cndl_threestarsinsouth.Update(tradeBar) self.cndl_threewhitesoldiers.Update(tradeBar) self.cndl_thrusting.Update(tradeBar) self.cndl_tristar.Update(tradeBar) self.cndl_twocrows.Update(tradeBar) self.cndl_uniquethreeriver.Update(tradeBar) self.cndl_updowngapthreemethods.Update(tradeBar) self.cndl_upsidegaptwocrows.Update(tradeBar) # Support Resistance def CloseTo(x, y, delta): return abs(x-y) < delta def Next_RS(self, algorithm, symbol): s, r = [], [] price = algorithm.Securities[symbol].Price # Rounded Price to $1 s.append(round(price)) r.append(math.ceil(price)) # Rounded Price to $10 s.append(int(math.floor(price / 10.0)) * 10) # Rounded Price Up to $10 r.append(int(math.ceil(price / 10.0)) * 10) # Yesterday's OHLC Price s.append( self.Daily[0].Close) s.append( self.Daily[0].Low ) r.append( self.Daily[0].Close) r.append( self.Daily[0].High) # Append 7 day Low: s.append( min([bar.Low for bar in self.Daily]) ) r.append( max([bar.High for bar in self.Daily]) ) s = sorted(s, reverse=True) r = sorted(r) return s[0], r[0] self.Daily.Add(tradeBar) if self.Daily.IsReady: support, resistance = Next_RS(self, algorithm, symbol) price = algorithm.Securities[symbol].Price mean = self.slow.Current.Value if CloseTo(price, support, 0.10) and mean > support*self.tol: self.long = True if CloseTo(price, resistance, 0.10) and mean < resistance*self.tol: self.short = True def roc_calc(obj): obj_lst = list(obj) output_lst = list() for i in range(-1, -len(obj_lst)+1, -1): if obj_lst[i-1] != 0: val = round((obj_lst[i] - obj_lst[i-1])/obj_lst[i-1], 4) else: val = 0 output_lst.append(val) return output_lst self.roc_Win.Add(round(float(statistics.median([self.roc.Current.Value, self.roc_fast.Current.Value, self.roc_med.Current.Value, self.roc_long.Current.Value])), 4)) if self.roc_Win.IsReady: roc_lst = list(self.roc_Win) roc_sum, roc_len = sum(roc_lst), len(roc_lst) self.roc_slope = round(float(roc_sum)/roc_len, 4) vol_sum, vol_len = sum(list(self.roc_Win)[-3:-1]), len(list(self.roc_Win)[-3:-1]) self.roc_fast_slope = round(float(vol_sum)/vol_len, 4) self.quick_up = all(x > 0.0 for x in [self.roc_fast_slope, self.volSignal_quick.Current.Value]) self.quick_down = all(x < 0.0 for x in [self.roc_fast_slope, self.volSignal_quick.Current.Value]) def calc_divergence(obj): x = np.array(list(obj)) local_maxima = argrelextrema(x, np.greater)[0] local_minima = argrelextrema(x, np.less)[0] if x[-1] > x[-2]: x = np.append(x, len(x) - 1) elif x[-1] > x[-2]: x = np.append(x, len(x) - 1) hh_all = all(x[local_maxima][i] < x[local_maxima][i+1] for i in range(len(local_maxima)-1)) ll_all = all(x[local_minima][i] > x[local_minima][i+1] for i in range(len(local_minima)-1)) return hh_all, ll_all self.rocSum_Win.Add(round(float(sum([self.roc.Current.Value, self.roc_fast.Current.Value, self.roc_med.Current.Value, self.roc_long.Current.Value])), 4)) self.roclen_Win.Add(round(float(statistics.median([self.roc.Current.Value, self.roc_fast.Current.Value, self.roc_med.Current.Value, self.roc_long.Current.Value])), 4)) if self.rocSum_Win.IsReady: self.hh_all, self.ll_all = calc_divergence(self.roclen_Win) self.hh_sum, self.ll_sum = calc_divergence(self.rocSum_Win) self.vol_Win.Add(round(float(statistics.median([self.vol_roc.Current.Value, self.vol_roc_fast.Current.Value, self.vol_roc_med.Current.Value, self.vol_roc_long.Current.Value])), 4)) if self.vol_Win.IsReady: vol_lst = list(self.vol_Win) vol_sum, vol_len = sum(vol_lst), len(vol_lst) self.vol_slope = round(float(vol_sum)/vol_len, 4) vol_sum, vol_len = sum(list(self.vol_Win)[-3:-1]), len(list(self.vol_Win)[-3:-1]) self.vol_fast_slope = round(float(vol_sum)/vol_len, 4) self.vol_hh, self.vol_ll = calc_divergence(self.vol_Win) self.roc_prices_Win.Add(round(statistics.median([self.roc.Current.Value, self.roc_fast.Current.Value, self.roc_med.Current.Value, self.roc_long.Current.Value]), 4)) self.roc_prices_lev_Win.Add(round(statistics.median([self.roc.Current.Value, self.roc_fast.Current.Value, self.roc_med.Current.Value]), 4)) self.roc_volume_Win.Add(round(statistics.median([self.vol_roc.Current.Value, self.vol_roc_fast.Current.Value, self.vol_roc_med.Current.Value, self.vol_roc_long.Current.Value]), 4)) self.prices_Win.Add(tuple.close) if self.prices_Win.IsReady: prices = list(self.roc_prices_Win) volumes = list(self.roc_volume_Win) frames = [i for i in range(-2, -21, -2)] frames_ = [i for i in range(-1, -21, -1)] prices_lev = list(self.roc_prices_lev_Win) _frames = [i for i in range(-1, -3, -1)] v1 = round(statistics.median([round(float(prices[i] - prices[i-5]/ prices[i-5]), 4) if prices[i-5] != 0 else 0 for i in frames]), 4) v11 = round(statistics.median([round(float(prices[i] - prices[i-5]/ prices[i-5]), 4) if prices[i-5] != 0 else 0 for i in frames_]), 4) v1_mom = round(statistics.median([round(float(prices_lev[i] - prices_lev[i-1]/ abs(abs(i)+(i-1))), 4) if abs(abs(i)+(i-1)) != 0 else 0 for i in _frames]), 4) self.median_roc = v1 if (v1 > v11) else -1 self.median_roc_momentum = v1_mom self.median_vol = round(statistics.median([round(float(volumes[i] - volumes[i-5]/ volumes[i-5]), 4) if volumes[i-5] != 0 else 0 for i in frames]), 4) self.median_roc_hh, self.median_roc_ll = calc_divergence(roc_calc(prices)) self.median_vol_hh, self.median_vol_ll = calc_divergence(roc_calc(volumes)) C = list(self.prices_Win) avg = sum(list(self.prices_Win))/len(list(self.prices_Win)) self.volatility = float(np.sqrt(252)*reduce(lambda a,b:a+abs(avg-b),C,0)/len(C))/C[-1] self.hh, self.ll = calc_divergence(self.prices_Win) rocSignal_lst = [self.rocSignal_quick.Current.Value, self.rocSignal_fast.Current.Value, self.rocSignal_med.Current.Value, self.rocSignal_long.Current.Value] volSignal_lst = [self.volSignal_quick.Current.Value, self.volSignal_fast.Current.Value, self.volSignal_med.Current.Value, self.volSignal_long.Current.Value] rocsignal_up = all(x > 0.0 for x in rocSignal_lst) rocsignal_down = all(x < 0.0 for x in rocSignal_lst) volsignal = all(x > 0.0 for x in volSignal_lst) self.roc_vol_signal_up = rocsignal_up and volsignal self.roc_vol_signal_down = rocsignal_down and volsignal # Stochastic RSI if self.rsi.IsReady: rsi = self.rsi.Current.Value trade_bar = TradeBar(tuple.Index, rsi, rsi, rsi, rsi, 0) self.stochasticRSI.Update(trade_bar) if self.stochasticRSI.IsReady: self.rsi_Win.Add(rsi) self.rsiWin.Add(rsi) self.rsiFastStoch_Win.Add(self.stochasticRSI.FastStoch.Current.Value) self.rsiStochFastWin.Add(self.stochasticRSI.FastStoch.Current.Value) self.rsiStochK_Win.Add(self.stochasticRSI.StochK.Current.Value) self.rsiStochKWin.Add(self.stochasticRSI.StochK.Current.Value) self.rsiStochD_Win.Add(self.stochasticRSI.StochD.Current.Value) self.rsiStochDWin.Add(self.stochasticRSI.StochD.Current.Value) if self.rsi_Win.IsReady: rsi_lst = list(self.rsi_Win) rsifast_lst = list(self.rsiFastStoch_Win) rsistochk_lst = list(self.rsiStochK_Win) rsistochd_lst = list(self.rsiStochD_Win) cur_rsi, pre_rsi, lst_rsi = rsi_lst[-1], rsi_lst[-2], rsi_lst[-3] cur_fast, pre_fast, lst_fast = rsifast_lst[-1], rsifast_lst[-2], rsifast_lst[-3] cur_stochk, pre_stochk, lst_stochk = rsistochk_lst[-1], rsistochk_lst[-2], rsistochk_lst[-3] cur_stochd, pre_stochd, lst_stochd = rsistochd_lst[-1], rsistochd_lst[-2], rsistochd_lst[-3] cond1 = (cur_fast >= cur_stochk*self.tol) and (cur_fast >= cur_stochd*self.tol) and (cur_stochk >= cur_stochd*self.tol) cond2 = (cur_rsi >= pre_rsi*self.tol) and (cur_fast >= pre_fast*self.tol) and (cur_stochk >= pre_stochk*self.tol) and (cur_stochd >= pre_stochd*self.tol) cond3 = (pre_rsi >= lst_rsi*self.tol) and (pre_fast >= lst_fast*self.tol) and (pre_stochk >= lst_stochk*self.tol) and (pre_stochd >= lst_stochd*self.tol) cond4 = (cur_fast <= cur_stochk*self.tol) and (cur_fast <= cur_stochd*self.tol) and (cur_stochk <= cur_stochd*self.tol) cond5 = (cur_rsi <= pre_rsi*self.tol) and (cur_fast <= pre_fast*self.tol) and (cur_stochk <= pre_stochk*self.tol) and (cur_stochd <= pre_stochd*self.tol) cond6 = (pre_rsi <= lst_rsi*self.tol) and (pre_fast <= lst_fast*self.tol) and (pre_stochk <= lst_stochk*self.tol) and (pre_stochd <= lst_stochd*self.tol) hh_rsi, ll_rsi = calc_divergence(rsi_lst) hh_rsifast, ll_rsifast = calc_divergence(rsifast_lst) hh_rsik, ll_rsik = calc_divergence(rsistochk_lst) hh_rsid, ll_rsid = calc_divergence(rsistochd_lst) cond7 = hh_rsi, hh_rsifast, hh_rsik, hh_rsid cond8 = ll_rsi, ll_rsifast, ll_rsik, ll_rsid if (cond1 and cond7) and (cond2 and cond3): self.rsi_uptrend = True if (cond4 and cond8) and (cond5 and cond6): self.rsi_downtrend = True exit = self.rsiStochFastWin.crossedBelow(self.rsiWin) and self.rsiStochFastWin.crossedBelow(self.rsiStochKWin) and self.rsiStochKWin.crossedBelow(self.rsiStochDWin) entry = self.rsiStochFastWin.crossedAbove(self.rsiWin) and self.rsiStochFastWin.crossedAbove(self.rsiStochKWin) and self.rsiStochKWin.crossedAbove(self.rsiStochDWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.rsi_exit_signal = True else: self.rsi_exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.rsi_entry_signal = True else: self.rsi_entry_signal = False # MACD Trend if self.macd.IsReady: macd = self.macd.Current.Value trade_bar = TradeBar(tuple.Index, macd, macd, macd, macd, 0) self.stochasticMACD.Update(trade_bar) if self.stochasticMACD.IsReady: macd = self.macd.Current.Value macd_fast = self.macd.Fast.Current.Value macd_slow = self.macd.Slow.Current.Value macd_hist = self.macd.Histogram.Current.Value signal = self.macd.Signal.Current.Value delta = (macd - signal)/macd_fast macd_stochfast = self.stochasticMACD.FastStoch.Current.Value macd_stochk = self.stochasticMACD.StochK.Current.Value macd_stochd = self.stochasticMACD.StochD.Current.Value self.macd_Win.Add(macd) self.macdFast_Win.Add(macd_fast) self.macdSlow_Win.Add(macd_slow) self.macdHist_Win.Add(macd_hist) self.macdSignal_Win.Add(signal) self.macdDelta_Win.Add(delta) self.macd_stochfast_Win.Add(macd_stochfast) self.macdStochFastWin.Add(macd_stochfast) self.macd_stochk_Win.Add(macd_stochk) self.macdStochKWin.Add(macd_stochk) self.macd_stochd_Win.Add(macd_stochd) self.macdStochDWin.Add(macd_stochd) if self.macd_Win.IsReady: macd_lst = list(self.macd_Win) macdhist_lst = list(self.macdHist_Win) macdfast_lst = list(self.macdFast_Win) macdslow_lst = list(self.macdSlow_Win) macdsignal_lst = list(self.macdSignal_Win) macddelta_lst = list(self.macdDelta_Win) macdstochfast_lst = list(self.macd_stochfast_Win) macdstochk_lst = list(self.macd_stochk_Win) macdstochd_lst = list(self.macd_stochd_Win) cur_macd, pre_macd, lst_macd = macd_lst[-1], macd_lst[-2], macd_lst[-3] cur_macd_fast, pre_macd_fast, lst_macd_fast = macdfast_lst[-1], macdfast_lst[-2], macdfast_lst[-3] cur_macd_slow, pre_macd_slow, lst_macd_slow = macdslow_lst[-1], macdslow_lst[-2], macdslow_lst[-3] cur_macd_hist, pre_macd_hist, lst_macd_hist = macdhist_lst[-1], macdhist_lst[-2], macdhist_lst[-3] cur_signal, pre_signal, lst_signal = macdsignal_lst[-1], macdsignal_lst[-2], macdsignal_lst[-3] cur_delta, pre_delta, lst_delta = macddelta_lst[-1], macddelta_lst[-2], macddelta_lst[-3] cur_macdstochfast, pre_macdstochfast, lst_macdstochfast = macdstochfast_lst[-1], macdstochfast_lst[-2], macdstochfast_lst[-3] cur_macdstochk, pre_macdstochk, lst_macdstochk = macdstochk_lst[-1], macdstochk_lst[-2], macdstochk_lst[-3] cur_macdstochd, pre_macdstochd, lst_macdstochd = macdstochd_lst[-1], macdstochd_lst[-2], macdstochd_lst[-3] cond1 = ((cur_macd_hist-cur_delta)>=0.0025) and (cur_macd >= cur_signal*self.tol) and (cur_macdstochfast >= cur_macdstochk*self.tol) and (cur_macdstochk >= cur_macdstochd*self.tol) cond2 = (cur_macd >= pre_macd*self.tol) and (cur_macd_fast >= pre_macd_fast*self.tol) and (cur_macd_hist >= pre_macd_hist*self.tol) and (cur_signal >= pre_signal*self.tol) cond3 = (pre_macd >= lst_macd*self.tol) and (pre_macd_fast >= lst_macd_fast*self.tol) and (pre_macd_hist >= lst_macd_hist*self.tol) and (pre_signal >= lst_signal*self.tol) cond4 = ((cur_macd_hist-cur_delta) <= -0.0025) and (cur_macd <= cur_signal*self.tol) and (cur_macdstochfast <= cur_macdstochk*self.tol) and (cur_macdstochk <= cur_macdstochd*self.tol) cond5 = (cur_macd <= pre_macd*self.tol) and (cur_macd_fast <= pre_macd_fast*self.tol) and (cur_macd_hist <= pre_macd_hist*self.tol) and (cur_signal <= pre_signal*self.tol) cond6 = (pre_macd <= lst_macd*self.tol) and (pre_macd_fast <= lst_macd_fast*self.tol) and (pre_macd_hist <= lst_macd_hist*self.tol) and (pre_signal <= lst_signal*self.tol) hh_macd, ll_macd = calc_divergence(macd_lst) hh_macdhist, ll_macdhist = calc_divergence(macdhist_lst) hh_macdfast, ll_macdfast = calc_divergence(macdfast_lst) hh_macdslow, ll_macdslow = calc_divergence(macdslow_lst) hh_macdsignal, ll_macdsignal = calc_divergence(macdsignal_lst) hh_macdstochfast, ll_macdstochfast = calc_divergence(macdstochfast_lst) hh_macdstochk, ll_macdstochk = calc_divergence(macdstochk_lst) hh_macdstochd, ll_macdstochd = calc_divergence(macdstochd_lst) cond7 = hh_macd, hh_macdhist, hh_macdfast, hh_macdslow, hh_macdsignal, hh_macdstochfast, hh_macdstochk, hh_macdstochd cond8 = ll_macd, ll_macdhist, ll_macdfast, ll_macdslow, ll_macdsignal, ll_macdstochfast, ll_macdstochk, ll_macdstochd if (cond1 and cond7) and (cond2 and cond3): self.macd_uptrend = True if (cond4 and cond8) and (cond5 and cond6): self.macd_downtrend = True exit = self.macdStochFastWin.crossedBelow(self.macdStochKWin) and self.macdStochKWin.crossedBelow(self.macdStochDWin) entry = self.macdStochFastWin.crossedAbove(self.macdStochKWin) and self.macdStochKWin.crossedAbove(self.macdStochDWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.macd_exit_signal = True else: self.macd_exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.macd_entry_signal = True else: self.macd_entry_signal = False self.williamsWin.Add(round(statistics.median([self.williamsPR.Current.Value, self.williamsPR_slow.Current.Value]), 4)) if self.williamsWin.IsReady: williams = list(self.williamsWin) w_length = len(williams) frames = [i for i in range(-1, (w_length*-1)+1, -1)] self.williams_median_roc = round(statistics.median([round(float(williams[i] - williams[i-1]/ williams[i-1]), 4) if williams[i-1] != 0 else 0 for i in frames]), 4) self.williams_median = round(statistics.median(williams), 4) if self.williamsPR.IsReady and self.williamsPR_slow.IsReady: self.williamsPR_Win.Add(self.williamsPR.Current.Value) self.williamsPRWin.Add(self.williamsPR.Current.Value) self.williamsPR_slow_Win.Add(self.williamsPR_slow.Current.Value) self.williamsPR_slowWin.Add(self.williamsPR_slow.Current.Value) if self.williamsPR_Win.IsReady: wills_lst = list(self.williamsPR_Win) willss_lst = list(self.williamsPR_slow_Win) cur_wills, pre_wills, lst_wills = wills_lst[-1], wills_lst[-2], wills_lst[-3] cur_willss, pre_willss, lst_willss = willss_lst[-1], willss_lst[-2], willss_lst[-3] cond1 = (cur_wills >= cur_willss*self.tol) cond2 = (cur_wills >= pre_wills*self.tol) and (cur_willss >= pre_willss*self.tol) cond3 = (pre_wills >= lst_wills*self.tol) and (pre_willss >= lst_willss*self.tol) cond4 = (cur_wills <= cur_willss*self.tol) cond5 = (cur_wills <= pre_wills*self.tol) and (cur_willss <= pre_willss*self.tol) cond6 = (pre_wills <= lst_wills*self.tol) and (pre_willss <= lst_willss*self.tol) hh_wills, ll_wills = calc_divergence(wills_lst) hh_willss, ll_willss = calc_divergence(willss_lst) cond7 = hh_wills, hh_willss cond8 = ll_wills, ll_willss if (cond1 and cond7) and (cond2 and cond3): self.williams_uptrend = True if (cond4 and cond8) and (cond5 and cond6): self.williams_downtrend = True exit = self.williamsPRWin.crossedBelow(self.williamsPR_slowWin) entry = self.williamsPRWin.crossedAbove(self.williamsPR_slowWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.williams_exit_signal = True else: self.williams_exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.williams_entry_signal = True else: self.williams_entry_signal = False self.high_Win.Add(tuple.high) self.low_Win.Add(tuple.low) if self.high_Win.IsReady: close = list(self.prices_Win) todayvol = np.std(close[1:31]) yesterdayvol = np.std(close[0:30]) deltavol = (todayvol - yesterdayvol) / todayvol self.lookback = round(self.lookback * (1 + deltavol)) # Account for upper/lower limit of lockback length if self.lookback > self.ceiling: self.lookback = self.ceiling elif self.lookback < self.floor: self.lookback = self.floor high = list(self.high_Win) low = list(self.low_Win) # Buy in case of breakout entry = (algorithm.Securities[symbol].Price >= max(high[:-1])) if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.breakout = True exit = (algorithm.Securities[symbol].Price <= min(low[:-1])) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.breakdown = True fast = self.fast.Current.Value self.fastVwapWin.Add(fast) slow = self.slow.Current.Value self.slowVwapWin.Add(slow) fastBar = TradeBar(tuple.Index, fast, fast, fast, fast, 0) self.stochasticFast.Update(fastBar) slowBar = TradeBar(tuple.Index, slow, slow, slow, slow, 0) self.stochasticSlow.Update(slowBar) if self.stochasticFast.IsReady and self.stochasticSlow.IsReady: fast_stoch = self.stochasticFast.FastStoch.Current.Value fast_stochk = self.stochasticFast.StochK.Current.Value fast_stochd = self.stochasticFast.StochD.Current.Value slow_stoch = self.stochasticSlow.FastStoch.Current.Value slow_stochk = self.stochasticSlow.StochK.Current.Value slow_stochd = self.stochasticSlow.StochD.Current.Value fast_cond = ((fast >= fast_stochk*self.tol) and (fast_stoch >= fast_stochk*self.tol) and (fast_stochk >= fast_stochd*self.tol)) slow_cond = ((slow >= slow_stochk*self.tol) and (slow_stoch >= slow_stochk*self.tol) and (slow_stochk >= slow_stochd*self.tol)) self.is_uptrend = ((fast) >= slow*self.tol) and (tuple.close >= slow*self.tol) and fast_cond and slow_cond fast_cond = ((fast <= fast_stochk*self.tol) and (fast_stoch <= fast_stochk*self.tol) and (fast_stochk <= fast_stochd*self.tol)) slow_cond = ((slow <= slow_stochk*self.tol) and (slow_stoch <= slow_stochk*self.tol) and (slow_stochk <= slow_stochd*self.tol)) self.is_downtrend = ((fast) <= slow*self.tol) and (tuple.close <= slow*self.tol) and fast_cond and slow_cond exit = self.fastVwapWin.crossedBelow(self.slowVwapWin) entry = self.fastVwapWin.crossedAbove(self.slowVwapWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.exit_signal = True else: self.exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.entry_signal = True else: self.entry_signal = False if self.is_uptrend: # triangle formula # base * height * 0.5 self.scale = round(float(fast - slow) / ((fast+slow)/2.0), 4) if (fast+slow) != 0.0 else 0 else: self.scale = 0.00 if self.trix.IsReady: trix = self.trix.Current.Value trixBar = TradeBar(tuple.Index, trix, trix, trix, trix, 0) self.stochasticTrix.Update(trixBar) if self.stochasticTrix.IsReady: self.trixFastStoch_Win.Add(self.stochasticTrix.FastStoch.Current.Value) self.trixStochFastWin.Add(self.stochasticTrix.FastStoch.Current.Value) self.trixStochK_Win.Add(self.stochasticTrix.StochK.Current.Value) self.trixStochKWin.Add(self.stochasticTrix.StochK.Current.Value) self.trixStochD_Win.Add(self.stochasticTrix.StochD.Current.Value) self.trixStochDWin.Add(self.stochasticTrix.StochD.Current.Value) if self.trixFastStoch_Win.IsReady: trix_lst = list(self.trixFastStoch_Win) trixfast_lst = list(self.trixFastStoch_Win) trixstochk_lst = list(self.trixStochK_Win) trixstochd_lst = list(self.trixStochD_Win) cur_trix, pre_trix, lst_trix = trix_lst[-1], trix_lst[-2], trix_lst[-3] cur_fast, pre_fast, lst_fast = trixfast_lst[-1], trixfast_lst[-2], trixfast_lst[-3] cur_stochk, pre_stochk, lst_stochk = trixstochk_lst[-1], trixstochk_lst[-2], trixstochk_lst[-3] cur_stochd, pre_stochd, lst_stochd = trixstochd_lst[-1], trixstochd_lst[-2], trixstochd_lst[-3] cond1 = (cur_trix >= cur_stochk*self.tol) and (cur_fast >= cur_stochk*self.tol) and (cur_stochk >= cur_stochd*self.tol) cond2 = (cur_trix >= pre_trix*self.tol) and (cur_fast >= pre_fast*self.tol) and (cur_stochk >= pre_stochk*self.tol) and (cur_stochd >= pre_stochd*self.tol) cond3 = (pre_trix >= lst_trix*self.tol) and (pre_fast >= lst_fast*self.tol) and (pre_stochk >= lst_stochk*self.tol) and (pre_stochd >= lst_stochd*self.tol) cond4 = (cur_trix <= cur_stochk*self.tol) and (cur_fast <= cur_stochk*self.tol) and (cur_stochk <= cur_stochd*self.tol) cond5 = (cur_trix <= pre_trix*self.tol) and (cur_fast <= pre_fast*self.tol) and (cur_stochk <= pre_stochk*self.tol) and (cur_stochd <= pre_stochd*self.tol) cond6 = (pre_trix <= lst_trix*self.tol) and (pre_fast <= lst_fast*self.tol) and (pre_stochk <= lst_stochk*self.tol) and (pre_stochd <= lst_stochd*self.tol) hh_trix, ll_trix = calc_divergence(trix_lst) hh_trixfast, ll_trixfast = calc_divergence(trixfast_lst) hh_trixk, ll_trixk = calc_divergence(trixstochk_lst) hh_trixd, ll_trixd = calc_divergence(trixstochd_lst) cond7 = hh_trix, hh_trixfast, hh_trixk, hh_trixd cond8 = ll_trix, ll_trixfast, ll_trixk, ll_rsid if (cond1 and cond7) and (cond2 and cond3): self.trix_uptrend = True if (cond4 and cond8) and (cond5 and cond6): self.trix_downtrend = True exit = self.trixStochFastWin.crossedBelow(self.trixStochKWin) and self.trixStochKWin.crossedBelow(self.trixStochDWin) entry = self.trixStochFastWin.crossedAbove(self.trixStochKWin) and self.trixStochKWin.crossedAbove(self.trixStochDWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.trix_exit_signal = True else: self.trix_exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.trix_entry_signal = True else: self.trix_entry_signal = False self.kalWin.Add(self.kalFilter.Value) self.kalWindowLow.Add(self.kalFilterLow.Value) self.kalWindowHigh.Add(self.kalFilterHigh.Value) self.priceWin.Add(median_price) self.priceWindowLow.Add(tuple.low) self.priceWindowHigh.Add(tuple.high) if self.kalFilterLow.IsReady: exit = self.priceWindowLow.crossedBelow(self.kalWindowLow) and self.priceWindowHigh.crossedBelow(self.kalWindowHigh) and self.priceWin.crossedBelow(self.kalWin) entry = self.priceWindowLow.crossedAbove(self.kalWindowLow) and self.priceWindowHigh.crossedAbove(self.kalWindowHigh) and self.priceWin.crossedAbove(self.kalWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.kal_exit_signal = True else: self.kal_exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.kal_entry_signal = True else: self.kal_entry_signal = False # VPN Indicator iATR = 0.1 ema_smooth = 3 vp = 0.0 vn = 0.0 vtot = 0.0 dist = self.atr.Current.Value * iATR self.vpn_vol_Win.Add(tuple.volume) self.vpn_hlc_Win.Add(round(statistics.median([tuple.high, tuple.low, tuple.close]), 4)) if self.vpn_vol_Win.IsReady and self.vpn_hlc_Win.IsReady: vpn_vol_Win = list(self.vpn_vol_Win) vpn_hlc_Win = list(self.vpn_hlc_Win) for i in range(-1, -self.vpn_period, -1): if (vpn_hlc_window[i] >= vpn_hlc_window[i-1] + dist): vp += vpn_vol_window[i] elif (vpn_hlc_window[i] <= vpn_hlc_window[i-1] - dist): vn += vpn_vol_window[i] vtot += vpn_vol_window[i] vpn_val = (((vp - vn) / (vtot/self.vpn_period)) / self.vpn_period) * 100 self.vpn_lst.Add(vpn_val) if self.vpn_lst.IsReady: vpn_ema = pd.DataFrame(list(self.vpn_lst)).ewm(span=ema_smooth, adjust=False).mean().iloc[-1][0] vpn_scale = self.vpn_lst[-1] vpnIndicator = ((vpn_scale) >= (vpn_ema*self.tol)) and ((vpn_scale) >= (self.vpn_lst[-2]*self.tol)) hh_vpn, ll_vpn = calc_divergence(self.vpn_lst) self.vpnIndicator = vpnIndicator and hh_vpn and (not ll_vpn) if self.vpnIndicator: cur_vpn, cur_vpn_ema = vpn_scale, vpn_ema low_vpn, low_vpn_ema = min(self.vpn_lst), min(pd.DataFrame(list(self.vpn_lst)).ewm(span=ema_smooth, adjust=False).mean().iloc[-1]) vpnScale = round(float(cur_vpn - cur_vpn_ema) / ((low_vpn + low_vpn_ema) / 2.0), 4) self.vpnScale = vpnScale else: self.vpnScale = 0.00 # Candles cndl_coef = float(sum([x.Current.Value for x in self.candles])) self.candleContainer.Add(cndl_coef) self.candleWin.Add(cndl_coef) if self.candleContainer.IsReady and self.candleWin.IsReady: cndl_avg = statistics.median(list(self.candleContainer)) self.candleavgWin.Add(cndl_avg) if self.candleWin.IsReady and self.candleavgWin.IsReady: exit = self.candleWin.crossedBelow(self.candleavgWin) entry = self.candleWin.crossedAbove(self.candleavgWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.cndl_downtrend = True if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.cndl_uptrend = True # Price is Favorable if (algorithm.Securities[symbol].BidPrice < self.VWAP): self.PriceIsFavorable = True elif (algorithm.Securities[symbol].AskPrice > self.VWAP): self.PriceIsFavorable = True else: self.PriceIsFavorable = False # Market Profile if self.vwap_lng.IsReady: self.market_profile.CalcMarketProfile(algorithm, 21, [symbol]) a, val, vah, d = self.market_profile.GetMarketProfile(algorithm, symbol) poc = float(max(a, key=a.get)) self.poc_Win.Add(poc) self.pocWin.Add(poc) self.val_Win.Add(val) self.valWin.Add(val) self.vah_Win.Add(vah) self.vahWin.Add(vah) self.price_Win.Add(algorithm.Securities[symbol].Price) self.priceWin.Add(algorithm.Securities[symbol].Price) self.medpri_Win.Add(median_price) self.medpriWin.Add(median_price) mp_fst = self.vwap_fst.Current.Value mp_med = self.vwap_med.Current.Value mp_lng = self.vwap_lng.Current.Value self.vwap_fst_Win.Add(mp_fst) self.vwap_fstWin.Add(mp_fst) self.vwap_med_Win.Add(mp_med) self.vwap_medWin.Add(mp_med) self.vwap_lng_Win.Add(mp_lng) self.vwap_lngWin.Add(mp_lng) if self.poc_Win.IsReady: poc_lst = list(self.poc_Win) val_lst = list(self.val_Win) vah_lst = list(self.vah_Win) pri_lst = list(self.price_Win) medp_lst = list(self.medpri_Win) fst_lst = list(self.vwap_fst_Win) med_lst = list(self.vwap_med_Win) lng_lst = list(self.vwap_lng_Win) cur_poc, pre_poc, lst_poc = poc_lst[-1], poc_lst[-2], poc_lst[-3] cur_val, pre_val, lst_val = val_lst[-1], val_lst[-2], val_lst[-3] cur_vah, pre_vah, lst_vah = vah_lst[-1], vah_lst[-2], vah_lst[-3] cur_pri, pre_pri, lst_pri = pri_lst[-1], pri_lst[-2], pri_lst[-3] cur_medp, pre_medp, lst_medp = medp_lst[-1], medp_lst[-2], medp_lst[-3] cur_fst, pre_fst, lst_fst = fst_lst[-1], fst_lst[-2], fst_lst[-3] cur_med, pre_med, lst_med = med_lst[-1], med_lst[-2], med_lst[-3] cur_lng, pre_lng, lst_lng = lng_lst[-1], lng_lst[-2], lng_lst[-3] cond1 = (cur_pri >= cur_poc*self.tol) and (cur_pri >= cur_medp*self.tol) and (cur_fst >= cur_med*self.tol) and (cur_med >= cur_lng*self.tol) cond2 = (cur_pri >= pre_pri*self.tol) and (cur_medp >= pre_medp*self.tol) and (cur_poc >= pre_poc*self.tol) and (cur_val >= pre_val*self.tol) and (cur_vah >= pre_vah*self.tol) and (cur_fst >= pre_fst*self.tol) and (cur_med >= pre_med*self.tol) and (cur_lng >= pre_lng*self.tol) cond3 = (pre_pri >= lst_pri*self.tol) and (pre_medp >= lst_medp*self.tol) and (pre_poc >= lst_poc*self.tol) and (pre_val >= lst_val*self.tol) and (pre_vah >= lst_vah*self.tol) and (pre_fst >= lst_fst*self.tol) and (pre_med >= lst_med*self.tol) and (pre_lng >= lst_lng*self.tol) cond4 = (cur_pri <= cur_poc*self.tol) and (cur_pri <= cur_medp*self.tol) and (cur_fst <= cur_med*self.tol) and (cur_med <= cur_lng*self.tol) cond5 = (cur_pri <= pre_pri*self.tol) and (cur_medp <= pre_medp*self.tol) and (cur_poc <= pre_poc*self.tol) and (cur_val <= pre_val*self.tol) and (cur_vah <= pre_vah*self.tol) and (cur_fst <= pre_fst*self.tol) and (cur_med <= pre_med*self.tol) and (cur_lng <= pre_lng*self.tol) cond6 = (pre_pri <= lst_pri*self.tol) and (pre_medp <= lst_medp*self.tol) and (pre_poc <= lst_poc*self.tol) and (pre_val <= lst_val*self.tol) and (pre_vah <= lst_vah*self.tol) and (pre_fst <= lst_fst*self.tol) and (pre_med <= lst_med*self.tol) and (pre_lng <= lst_lng*self.tol) hh_poc, ll_poc = calc_divergence(poc_lst) hh_val, ll_val = calc_divergence(val_lst) hh_vah, ll_vah = calc_divergence(vah_lst) hh_pri, ll_pri = calc_divergence(pri_lst) hh_mpr, ll_mpr = calc_divergence(medp_lst) hh_fst, ll_fst = calc_divergence(fst_lng) hh_med, ll_med = calc_divergence(med_lng) hh_long, ll_long = calc_divergence(lng_lst) cond7 = hh_poc, hh_val, hh_vah, hh_pri, hh_mpr, hh_fst, hh_med, hh_long cond8 = ll_poc, ll_val, ll_vah, ll_pri, hh_mpr, ll_fst, ll_med, ll_long if (cond1 and cond7) and (cond2 and cond3): self.mp_uptrend = True if (cond4 and cond8) and (cond5 and cond6): self.mp_downtrend = True exit = self.valWin.crossedBelow(self.vwap_medWin) and self.valWin.crossedBelow(self.vwap_mlngWin) and self.valWin.crossedBelow(self.medpriWin) entry = self.valWin.crossedAbove(self.vwap_medWin) and self.valWin.crossedAbove(self.vwap_mlngWin) and self.valWin.crossedAbove(self.medpriWin) if algorithm.Portfolio[symbol].Invested: if exit and self.short: self.mp_exit_signal = True else: self.mp_exit_signal = False if not algorithm.Portfolio[symbol].Invested: if entry and self.long: self.mp_entry_signal = True else: self.mp_entry_signal = False # if algorithm.Portfolio[symbol].Invested: # if self.pocWin.crossedBelow(self.vwap_lngWin): #and self.medpriWin.crossedBelow(self.vwap_medWin) and self.valWin.crossedBelow(self.vwap_mlngWin) and self.valWin.crossedBelow(self.vwap_lngWin): # self.dont_buy = True # else: # self.dont_buy = False # if not algorithm.Portfolio[symbol].Invested: # if all(self.medpriWin[0] < x[0] for x in [self.vwap_lngWin]): # self.dont_buy = True # else: # self.dont_buy = False behavior = poc < mp_lng if behavior: self.dont_buy = True else: self.dont_buy = False @property def VWAP(self): return self.vwap.Value class IntradayVwap: '''Defines the canonical intraday VWAP indicator''' def __init__(self): self.Value = 0.0 self.lastDate = datetime.min self.sumOfVolume = 0.0 self.sumOfPriceTimesVolume = 0.0 @property def IsReady(self): return self.sumOfVolume > 0.0 def Update(self, input): '''Computes the new VWAP''' success, volume, averagePrice = self.GetVolumeAndAveragePrice(input) if not success: return self.IsReady # reset vwap on daily boundaries if self.lastDate != input.EndTime.date(): self.sumOfVolume = 0.0 self.sumOfPriceTimesVolume = 0.0 self.lastDate = input.EndTime.date() # running totals for Σ PiVi / Σ Vi self.sumOfVolume += volume self.sumOfPriceTimesVolume += averagePrice * volume if self.sumOfVolume == 0.0: # if we have no trade volume then use the current price as VWAP self.Value = input.Value return self.IsReady self.Value = self.sumOfPriceTimesVolume / self.sumOfVolume return self.IsReady def GetVolumeAndAveragePrice(self, input): '''Determines the volume and price to be used for the current input in the VWAP computation''' if type(input) is Tick: if input.TickType == TickType.Trade: return True, float(input.Quantity), float(input.LastPrice) if type(input) is TradeBar: if not input.IsFillForward: averagePrice = round(float(statistics.mean([input.Open, input.High, input.Low, input.Close])), 4) return True, float(input.Volume), averagePrice return False, 0.0, 0.0
#region imports from AlgorithmImports import * #endregion import random import string import math class TradeManagement: def __init__(self, algorithm, ticker, optionSymbol): self.Trades = {} self.Algorithm = algorithm self.Ticker = ticker self.OptionSymbol = optionSymbol # Volatility indicators for position sizing self.atr = self.Algorithm.ATR(self.Ticker, 3, MovingAverageType.Simple, Resolution.Hour) self.stddev = self.Algorithm.STD(self.Ticker, 6, Resolution.Hour) # Manage Open Positions def ManageOpenPositions(self): for t in self.OpenTrades(): # Scan for Profit-Loss if t.UnrealizedProfit() > t.Target: self.Close(t, "Profit") elif t.UnrealizedProfit() < -t.Target: self.Close(t, "Loss") # Stop Assignment if t.ExpiringSoon(): self.Close(t, "Expiring") # Base target contract count on the number of contracts to hit the profit assuming 2SD move. def ContractSizing(self, targetProfit): expectedDollarMovement = 2 * self.stddev.Current.Value * 100 # At least 1 contract contracts = min(5, math.ceil(targetProfit / expectedDollarMovement)) return int(contracts) # Base target profit per position on the volatility of the last few days. def TargetProfitEstimate(self): return round(self.atr.Current.Value * 100) def OpenTrades(self): return [t for t in self.Trades.values() if t.IsOpen()] # Place a trade in the direction signalled def Create(self, direction): symbol = self.SelectOptionContract(direction) if symbol is None: return # If we already hold; skip alreadyOpen = [c for c in self.OpenTrades() if c.Symbol == symbol] if len(alreadyOpen) > 0: return # If today's the expiry don't trade # if (symbol.ID.Date < self.Algorithm.Time): # return targetProfit = self.TargetProfitEstimate() size = self.ContractSizing(targetProfit) price = self.Algorithm.Securities[symbol].Price asset = self.Algorithm.Securities[self.Ticker].Price tag = f"Asset: {asset} | Opened | Target of ${targetProfit} at ${price}" ticket = self.Algorithm.MarketOrder(symbol, size, False, tag) trade = Trade(self.Algorithm, self.Algorithm.Securities[symbol], ticket, targetProfit) self.Trades[trade.Id] = trade return trade def Close(self, trade, reason): trade.Close(reason) if trade.Id in self.Trades: del self.Trades[trade.Id] # Select OOM Option Contract with Given Bias def SelectOptionContract(self, direction): if direction == OrderDirection.Buy: right = OptionRight.Call else: right = OptionRight.Put chain = self.Algorithm.CurrentSlice.OptionChains.GetValue(self.OptionSymbol) if chain is None: self.Algorithm.Log(f"{self.Algorithm.Time} - No option chains with {self.OptionSymbol}. Missing data for Mar-2nd.") return None # Select contracts expirying tomorrow at least. chain = [x for x in chain if (x.Right == right and x.Expiry > self.Algorithm.Time)] reverseSort = right == OptionRight.Call # Reverse sort of a call contracts = sorted(sorted(chain, key = lambda x: abs(x.Strike), reverse=reverseSort), key = lambda x: x.Expiry) # No contracts found if len(contracts) == 0: return None; return contracts[0].Symbol class Trade: def __init__(self, algorithm, contract, ticket, target): self.Id = ''.join(random.choice(string.ascii_lowercase) for i in range(10)) self.Ticket = ticket self.Contract = contract self.Symbol = contract.Symbol self.Algorithm = algorithm self.Open = True self.Target = target def ExpiringSoon(self): expiry = self.Symbol.ID.Date + timedelta(hours=16) if ( (expiry - self.Algorithm.Time) < timedelta(minutes=10)): self.Algorithm.Log(f"{self.Symbol} Close to Expiry: {expiry} - {self.Algorithm.Time} < 10min" ) return True else: return False def UnrealizedProfitPercent(self): return (self.Contract.Holdings.Price - self.Ticket.AverageFillPrice) / self.Contract.Holdings.Price def UnrealizedProfit(self): return 100*(self.Contract.Holdings.Price - self.Ticket.AverageFillPrice) * self.Ticket.Quantity def IsOpen(self): return self.Open def Close(self, reason): self.Open = False tag = f"Close | {reason} | {self.UnrealizedProfit()} Net" self.Algorithm.Liquidate(self.Symbol, tag)
#region imports from AlgorithmImports import * #endregion from System import * from QuantConnect import * from QuantConnect.Indicators import * from QuantConnect.Data import * from QuantConnect.Data.Market import * from QuantConnect.Orders import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Execution import * from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Indicators.CandlestickPatterns import * import numpy as np from scipy import stats import tweepy import statistics from pykalman import KalmanFilter from FilterIndicators import * from SmartRollingWindow import * from symbol_data_functions import SymbolData # import datetime from datetime import timedelta, datetime class ScheduledExecutionModel(ExecutionModel): '''Execution model that submits orders while the current market price is more favorable that the current volume weighted average price.''' def __init__(self, algorithm, *args, **kwargs): super().__init__() '''Initializes a new instance of the VolumeWeightedAveragePriceExecutionModel class''' self.targetsCollection = PortfolioTargetCollection() self.deviations = 2 self.symbolData = {} self.data = {} # self.datafourHour = dict() # self.datathirtyMin = dict() # Gets or sets the maximum order quantity as a percentage of the current bar's volume. # This defaults to 0.01m = 1%. For example, if the current bar's volume is 100, # then the maximum order size would equal 1 share. self.MaximumOrderQuantityPercentVolume = 0.1 # Gets or sets the maximum spread compare to current price in percentage. self.acceptingSpreadPercent = 0.001 def Execute(self, algorithm, targets): '''Executes market orders if the standard deviation of price is more than the configured number of deviations in the favorable direction. Args: algorithm: The algorithm instance targets: The portfolio targets''' # update the complete set of portfolio targets with the new targets self.targetsCollection.AddRange(targets) # for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call if self.targetsCollection.Count > 0: for target in self.targetsCollection.OrderByMarginImpact(algorithm): symbol = target.Symbol # calculate remaining quantity to be ordered unorderedQuantity = OrderSizing.GetUnorderedQuantity(algorithm, target) # fetch our symbol data containing our VWAP indicator data = self.symbolData.get(symbol, None) if data is None: return # check order entry conditions if self.PriceIsFavorable(data, unorderedQuantity): # adjust order size to respect maximum order size based on a percentage of current volume orderSize = OrderSizing.GetOrderSizeForPercentVolume(data.Security, self.MaximumOrderQuantityPercentVolume, unorderedQuantity) if (data.Security.BidPrice < data.VWAP): price_est = round(statistics.median([data.VWAP, data.Security.BidPrice]), 4) elif (data.Security.AskPrice > data.VWAP): price_est = round(statistics.median([data.VWAP, data.Security.AskPrice]), 4) max_quantity = algorithm.CalculateOrderQuantity(symbol, 0.95) # suggested amount divided by the total possible amount try: order_percent = round(float(orderSize/max_quantity), 4) except: if max_quantity == 0: order_percent = 0.0 else: cash = algorithm.Portfolio.Cash max_quantity = int(cash/price_est) order_percent = round(float(orderSize/max_quantity), 4) if ((orderSize != 0) and (abs(order_percent) >= 0.1)): coef = abs(order_percent) * 0.5 if algorithm.Portfolio[symbol].Invested: if coef <= 0.25: coef = int(abs(float(order_percent))/0.025)*10 else: rocsignal = all(x > 0.0 for x in [self.data[symbol].rocSignal_quick.Current.Value, self.data[symbol].rocSignal_fast.Current.Value, self.data[symbol].rocSignal_med.Current.Value, self.data[symbol].rocSignal_long.Current.Value]) volsignal = all(x > 0.0 for x in [self.data[symbol].volSignal_quick.Current.Value, self.data[symbol].volSignal_fast.Current.Value, self.data[symbol].volSignal_med.Current.Value, self.data[symbol].volSignal_long.Current.Value]) roc_vol_signal = rocsignal and volsignal coef = int(abs(float(order_percent))/0.025)*5 signals = (self.data[symbol].breakout or (self.data[symbol].vpnIndicator and (self.data[symbol].is_uptrend and self.data[symbol].trix_uptrend or (self.data[symbol].roc_vol_signal_up and self.data[symbol].entry_signal and self.data[symbol].kal_entry_signal and self.data[symbol].rsi_entry_signal and self.data[symbol].macd_entry_signal and self.data[symbol].williams_entry_signal))) or (self.data[symbol].macd_uptrend and self.data[symbol].rsi_uptrend)) slope_cond = (self.data[symbol].roc_slope > 0.00) and (self.data[symbol].vol_slope > 0.00) down_signals = ((self.data[symbol].breakdown or ((not self.data[symbol].vpnIndicator) and (self.data[symbol].is_downtrend and self.data[symbol].trix_downtrend) or (self.data[symbol].roc_vol_signal_down and self.data[symbol].exit_signal and self.data[symbol].kal_exit_signal and self.data[symbol].rsi_exit_signal and self.data[symbol].macd_exit_signal and self.data[symbol].williams_exit_signal and self.data[symbol].trix_exit_signal))) or (self.data[symbol].macd_downtrend and self.data[symbol].rsi_downtrend)) slope_down = (self.data[symbol].roc_slope > 0.00) and (self.data[symbol].vol_slope > 0.00) if (slope_cond) and (signals): if self.data[symbol].breakout or self.data[symbol].breakdown: coef = coef * 30+10 else: coef = coef * 30 elif (slope_cond) or (signals): if self.data[symbol].breakout or self.data[symbol].breakdown: coef = coef * 10+10 else: coef = coef * 10 elif (slope_down) and (down_signals): coef = 0 orderSize = OrderSizing.GetOrderSizeForPercentVolume(data.Security, self.MaximumOrderQuantityPercentVolume*coef, unorderedQuantity) projected_cost = round(price_est * orderSize, 4) * 1.0 if (algorithm.Portfolio.Cash > projected_cost) and (orderSize != 0): algorithm.MarketOrder(symbol, orderSize) self.targetsCollection.ClearFulfilled(algorithm) def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' for removed in changes.RemovedSecurities: # clean up removed security data if removed.Symbol in self.symbolData: if self.IsSafeToRemove(algorithm, removed.Symbol): data = self.symbolData.pop(removed.Symbol) algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) if removed.Symbol in self.data: if self.IsSafeToRemove(algorithm, removed.Symbol): data = self.data.pop(removed.Symbol) algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) # if removed.Symbol in self.datafourHour: # if self.IsSafeToRemove(algorithm, removed.Symbol): # data = self.datafourHour.pop(removed.Symbol) # algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) # if removed.Symbol in self.datathirtyMin: # if self.IsSafeToRemove(algorithm, removed.Symbol): # data = self.datathirtyMin.pop(removed.Symbol) # algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) for added in changes.AddedSecurities: if added.Symbol not in self.symbolData: self.symbolData[added.Symbol] = SymbolDataExecuteModel(algorithm, added) if added.Symbol not in self.data: self.data[added.Symbol] = SymbolData(algorithm, added.Symbol, Resolution.Daily) # if added.Symbol not in self.datafourHour: # self.datafourHour[added.Symbol] = SymbolData(algorithm, added.Symbol, Resolution.Hour) # if added.Symbol not in self.datathirtyMin: # self.datathirtyMin[added.Symbol] = SymbolData(algorithm, added.Symbol, Resolution.Minute) def PriceIsFavorable(self, data, unorderedQuantity): '''Determines if the current price is favorable in the favorable direction.''' sma = data.SMA.Current.Value deviations = self.deviations * data.STD.Current.Value sto = ((data.STO.StochK.Current.Value >= data.STO.StochD.Current.Value) and (data.STO_Med.StochK.Current.Value >= data.STO_Med.StochD.Current.Value)) or ((data.KWindow.crossedAbove(data.DWindow) and (data.KWindow_Med.crossedAbove(data.DWindow_Med)))) if unorderedQuantity > 0: if (data.Security.BidPrice < data.VWAP) or (data.Security.BidPrice < sma - deviations) and sto: return True else: if (data.Security.AskPrice > data.VWAP) or (data.Security.AskPrice > sma + deviations) and sto: return True return False def SpreadIsFavorable(self, data): '''Determines if the spread is in desirable range.''' # Price has to be larger than zero to avoid zero division error, or negative price causing the spread percentage < 0 by error # Has to be in opening hours of exchange to avoid extreme spread in OTC period return data.Security.Price > 0 and data.Security.AskPrice > 0 and data.Security.BidPrice > 0 \ and (data.Security.AskPrice - data.Security.BidPrice) / data.Security.Price <= self.acceptingSpreadPercent def IsSafeToRemove(self, algorithm, symbol): '''Determines if it's safe to remove the associated symbol data''' # confirm the security isn't currently a member of any universe return not any([kvp.Value.ContainsMember(symbol) for kvp in algorithm.UniverseManager]) class SymbolDataExecuteModel: def __init__(self, algorithm, security): self.Security = security self.period = 21 self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, security.Resolution) # TradeBarConsolidator(timedelta(hours=4)) # name = algorithm.CreateIndicatorName(security.Symbol, "VWAP", security.Resolution) self.vwap = IntradayVwap(name) algorithm.RegisterIndicator(security.Symbol, self.vwap, self.Consolidator) # VolumeWeightedAveragePriceIndicator(int(8*1.0)) smaName = algorithm.CreateIndicatorName(security.Symbol, f"SMA{self.period}", security.Resolution) self.SMA = SimpleMovingAverage(smaName, self.period) algorithm.RegisterIndicator(security.Symbol, self.SMA, self.Consolidator) smaName_med = algorithm.CreateIndicatorName(security.Symbol, f"SMA{self.period+13}", security.Resolution) self.SMA_Med = SimpleMovingAverage(smaName_med, self.period+13) algorithm.RegisterIndicator(security.Symbol, self.SMA_Med, self.Consolidator) stoName = algorithm.CreateIndicatorName(security.Symbol, f"STO{self.period}", security.Resolution) self.STO = Stochastic(smaName, self.period, 3, 3) algorithm.RegisterIndicator(security.Symbol, self.STO, self.Consolidator) self.DWindow = SmartRollingWindow("float", 5) self.KWindow = SmartRollingWindow("float", 5) stoName_med = algorithm.CreateIndicatorName(security.Symbol, f"STO{self.period+13}", security.Resolution) self.STO_Med = Stochastic(smaName_med, self.period+13, 3, 3) algorithm.RegisterIndicator(security.Symbol, self.STO_Med, self.Consolidator) self.DWindow_Med = SmartRollingWindow("float", 5) self.KWindow_Med = SmartRollingWindow("float", 5) stdName = algorithm.CreateIndicatorName(security.Symbol, f"STD{self.period}", security.Resolution) self.STD = StandardDeviation(stdName, self.period) algorithm.RegisterIndicator(security.Symbol, self.STD, self.Consolidator) # warmup our indicators by pushing history through the indicators history = algorithm.History(security.Symbol, 84, security.Resolution) if 'close' in history: for index, row in history.loc[security.Symbol].iterrows(): tradeBar = TradeBar(index, row['open'], row['high'], row['low'], row['close'], row['volume']) median_price = round(float(statistics.median([row['open'], row['high'], row['low'], row['close']])), 4) self.SMA.Update(index, median_price) self.SMA_Med.Update(index, median_price) self.STD.Update(index, median_price) sma = self.SMA.Current.Value sma_bar = TradeBar(index, sma, sma, sma, sma, 0) self.STO.Update(sma_bar) if self.STO.IsReady: self.KWindow.Add(self.STO.StochK.Current.Value) self.DWindow.Add(self.STO.StochD.Current.Value) sma = self.SMA_Med.Current.Value sma_bar = TradeBar(index, sma, sma, sma, sma, 0) self.STO_Med.Update(sma_bar) if self.STO_Med.IsReady: self.KWindow_Med.Add(self.STO_Med.StochK.Current.Value) self.DWindow_Med.Add(self.STO_Med.StochD.Current.Value) @property def VWAP(self): return self.vwap.Value def dispose(self, algorithm): algorithm.SubscriptionManager.RemoveConsolidator(security.Symbol, self.consolidator) class IntradayVwap: '''Defines the canonical intraday VWAP indicator''' def __init__(self, name): self.Name = name self.Value = 0.0 self.lastDate = datetime.min self.sumOfVolume = 0.0 self.sumOfPriceTimesVolume = 0.0 @property def IsReady(self): return self.sumOfVolume > 0.0 def Update(self, input): '''Computes the new VWAP''' success, volume, averagePrice = self.GetVolumeAndAveragePrice(input) if not success: return self.IsReady # reset vwap on daily boundaries if self.lastDate != input.EndTime.date(): self.sumOfVolume = 0.0 self.sumOfPriceTimesVolume = 0.0 self.lastDate = input.EndTime.date() # running totals for Σ PiVi / Σ Vi self.sumOfVolume += volume self.sumOfPriceTimesVolume += averagePrice * volume if self.sumOfVolume == 0.0: # if we have no trade volume then use the current price as VWAP self.Value = input.Value return self.IsReady self.Value = self.sumOfPriceTimesVolume / self.sumOfVolume return self.IsReady def GetVolumeAndAveragePrice(self, input): '''Determines the volume and price to be used for the current input in the VWAP computation''' if type(input) is Tick: if input.TickType == TickType.Trade: return True, float(input.Quantity), float(input.LastPrice) if type(input) is TradeBar: if not input.IsFillForward: averagePrice = round(float(statistics.mean([input.Open, input.High, input.Low, input.Close])), 4) return True, float(input.Volume), averagePrice return False, 0.0, 0.0
#region imports from AlgorithmImports import * #endregion from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * import sys import tweepy from tweepy import OAuthHandler from time import sleep import json # Important - Don't name file 'tweepy.py' # Used below to supress problems and continue instead of try/except/continue from contextlib import suppress # --- # --------------------------------------------------------------------- # --- # # --- # --------------------------------------------------------------------- # --- # # Set True to follow a defined list of twitter users. # Set False to stream from all accounts based on defined keywords. FollowerMode = True # --- # --------------------------------------------------------------------- # --- # # --- # --------------------------------------------------------------------- # --- # # --- # ---------------------------------- # --- # # --- # ---- Follower Mode Dictionary ---- # --- # # --- # ---------------------------------- # --- # # Lookup Twitter ID's here http://gettwitterid.com/ by entering the accounts @Usernamehandle (without the @) # It doesn't care what you name them. The names are only displayed to the console. idsdict = {'TT3Private'} # --- # --------------------------------------------------------------------- # --- # # --- # --------------------------------------------------------------------- # --- # # --- # ------------------------------ # --- # # --- # ---- Search Mode Keywords ---- # --- # # --- # ------------------------------ # --- # # --- # ----------------- # --- # # --- # SEARCH BY KEYWORD # --- # # --- # ----------------- # --- # # Example # search = ['breaking news'] # --- # ---------- # --- # # --- # SEARCH ALL # --- # # --- # ---------- # --- # # [' '] and [''] yields no results. The only way to truly stream all of the tweets (unfiltered) # requires a connection to the firehose(https://developer.twitter.com/en/docs/tweets/sample-realtime/overview/decahose.html), # which is granted only in specific use enterprise cases by Twitter. search = ['.','a','@','\'','this','to',':(','?','!','$', 'h','+','_','-','#','b','you', 'c',',','the', 'i','/','lol','at','this','need','and','RT', 'if','1', 'd','e','f','g'] # Feel free to expand on this. I believe there's a limit on how much you can add. # --- # -------------------- # --- # # --- # SEARCH BY USER INPUT # --- # # --- # -------------------- # --- # # search = [input('Enter keyword\n\n')] # --- # -------------------------------------------------------------- # --- # # --- # -------------------------------------------------------------- # --- # # --- # ---------------------- # --- # # --- # --- AUTHENTICATION --- # --- # # --- # ---------------------- # --- # consumer_key = self.GetParameter("Consumer_Api") consumer_secret = self.GetParameter("Consumer_Api_Secret") access_token = self.GetParameter("Access_Token") access_token_secret = self.GetParameter("Access_Token_Secret") auth = tweepy.OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) api = tweepy.API(auth) # --- # -------------------------------------------------------------- # --- # # --- # -------------------------------------------------------------- # --- # print('Listening for tweets...\n') if FollowerMode == True: # gets all IDs from 'idsdict' and converts them to strings ids = [str(i) for i in list(idsdict.values())] # Main Stream Listener Class class MyStreamListener(tweepy.StreamListener): global ids global FollowerMode tweets = 0 # on_status is a built in tweepy method to fetch tweets. # on_data is another one and shows more detailed information for analytical reasons, # but be aware that you will have to parse the json manually like data['text'], data['user']['location'], etc. # print out status or data(if using on_data) and run the script to fetch the full JSON to see everything that it can do. # You can find a good example of that here https://github.com/varadhbhatnagar/Emoyto def on_status(self, status): """ # Use this if you plan to use the json functionality below. # If you use this, tab the rest of this class below over by one indent(4 spaces) # with open ('tweets.json', 'a', encoding='utf-8') as f: # Supress errors so if that specific tweet has an issue for whatever reason, it will skip it. Similar to try/except. # Don't use this if you want to debug/look for issues. """ with suppress(Exception): userid = str(status.user.id) # "userid in ids" mentioned below removes all of the mentions and retweets and makes sure it only comes from the original account. # Tweepy has no built in way to exclude that to my knowledge based on stackoverflow answers. if FollowerMode == True and userid in ids: # You can do this for example - " if status.place.country == 'United States': ", # but most people don't have their country listed. status.user.location often shows 'state' or 'city, state' and/or country, # but their location is user set so it can really be something made up like 'outer space'. If it's that important, # you could always try and use an API to see if it's a valid location. print('-' * 80) # Prints the name for this ID that's defined in 'idsdict' with suppress(Exception): print(list(idsdict.keys())[list(idsdict.values()).index(int(userid))]) print('User: ' + status.user.screen_name) # Attempt to display location and/or country if it exists with suppress(Exception): if status.user.location != None and status.user.location != 'None': print('Location: ' + status.user.location) with suppress(Exception): print('Country: ' + status.place.country) # Checks to see if tweet is 'extended'/long. If it is, it will display the full tweet. try: text = status.extended_tweet['full_text'] except AttributeError: text = status.text print('Tweet: ' + text) sleep(0.015) elif FollowerMode == False: print('-' * 80) print('User: ' + status.user.screen_name) with suppress(Exception): if status.user.location != None and status.user.location != 'None': print('Location: ' + status.user.location) with suppress(Exception): print('Country: ' + status.place.country) try: text = status.extended_tweet['full_text'] except AttributeError: text = status.text print('Tweet: ' + text) # Prevents the display from hiccups and keeps the scrolling smooth when scanning all sleep(0.016) # --- # --------------------------------------------------------------------- # --- # # --- # --------------------------------------------------------------------- # --- # # Optional - Write tweet into json file. You can store just tweets for example # Make sure to un-comment the 'with f.open' above and tab the rest of the class below it. #json_str = json.dumps(status._json) #f.write(status.text + '\n') # --- # --------------------------------------------------------------------- # --- # # --- # --------------------------------------------------------------------- # --- # # # Optional - Print something out every certain number of tweets to show how many tweets have came through. # MyStreamListener.tweets += 1 # if MyStreamListener.tweets % 1000 == 0: # print(str(MyStreamListener.tweets) + ' Tweets') # for i in range(15): # print(f'|||||||||||||||||||||||||||||||||||----- {MyStreamListener.tweets} ------||||||||||||||||||||||||||||||||||||||| \n') # sleep(1) # Define the listener listener = MyStreamListener() stream = tweepy.Stream(auth, listener) if FollowerMode == True: stream.filter(follow=ids) else: stream.filter(languages=["en"], track = search )