| Overall Statistics |
|
Total Trades 695 Average Win 1.69% Average Loss -0.78% Compounding Annual Return 22.448% Drawdown 14.100% Expectancy 1.439 Net Profit 1664.974% Sharpe Ratio 1.5 Probabilistic Sharpe Ratio 96.835% Loss Rate 23% Win Rate 77% Profit-Loss Ratio 2.17 Alpha 0.139 Beta 0.209 Annual Standard Deviation 0.104 Annual Variance 0.011 Information Ratio 0.443 Tracking Error 0.165 Treynor Ratio 0.746 Total Fees $885.00 Estimated Strategy Capacity $130000000.00 Lowest Capacity Asset IEF SGNKIKYGE9NP |
#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)
elif (windowType is "QuoteBar"):self.window = RollingWindow[QuoteBar](windowLength)
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 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]#region imports
from AlgorithmImports import *
#endregion
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
import tweepy, statistics
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.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
from sklearn import preprocessing
from helpers import myTrailingStopRiskManagementModel
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.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)
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)
# model = ExtraTreeClassifier(max_depth = 40,
# max_features = 'sqrt',
# criterion = 'gini',
# class_weight = 'balanced',
# random_state = 42)
# model.fit(X_train, y_train)
# y_pred = model.predict(X_test)
# algorithm.Plot("Model Score", "Score", model.score(X_test, y_test))
# algorithm.Plot("MAE:", "Mae", mean_absolute_error(y_test, y_pred))
# algorithm.Plot("Coef of Determination:", "r-squared", r2_score(y_test, y_pred))
# algorithm.Plot("Actual vs Pred", "Actual", r2_score(y_test, y_pred))
# clf_results = metrics.precision_recall_fscore_support(y_test, y_pred)
# algorithm.Plot("Confusion_Matrix", "Precision", clf_results[0].round(2))
# algorithm.Plot("Confusion_Matrix", "Recall", clf_results[1].round(2))
# algorithm.Plot("Confusion_Matrix", "f1-score", clf_results[2].round(2))
# algorithm.Plot("Confusion_Matrix", "Support", clf_results[3].round(2))
# signal_actual = np.log(self.history[self.MKT]).iloc[-1]
# signal_pred = model.predict(np.ravel(np.log(self.history[pairs]).iloc[-1]).reshape(1, -1))
# prev = np.log(self.history[self.MKT]).iloc[-2]
# signal_actual = 1 if signal_actual > prev else -1
# signal_pred = 1 if signal_pred > prev else -1
# agreement= 1 if signal_actual == signal_pred else -1
# algorithm.Plot("Actual vs Pred", "Actual", float(signal_actual))
# algorithm.Plot("Actual vs Pred", "Pred", float(signal_pred))
# algorithm.Plot("Actual vs Pred", "Agreement", float(agreement))
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))
insights.append(Insight.Price(self.MKT, self.predictionInterval, direction))
return insights
def returns_custom(self, symbol, timeframe, algorithm):
frames = [i for i in range(-1, -11, -2)]
prices = algorithm.History(symbol, TimeSpan.FromDays(timeframe), self.resolution).close.pct_change()
return round(statistics.median([round(float(prices[i] - min(prices[i-9:i])/ min(prices[i-9:i])), 4) if min(prices[i-9:i]) != 0 else 0 for i in frames]), 4)
#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.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
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(2022, 3, 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'] # IWY, SH, SQQQ
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.SetRiskManagement(MaximumUnrealizedProfitPercentPerSecurity(maximumUnrealizedProfitPercent = 0.15)) # 0.15
#self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(maximumDrawdownPercent = 0.025))
#self.SetRiskManagement(MaximumDrawdownPercentPortfolio(maximumDrawdownPercent = 0.04, isTrailing = True))
#self.SetRiskManagement(TrailingStopRiskManagementModel(maximumDrawdownPercent = 0.04))
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 AddCash(self):
self.Portfolio.SetCash(self.Portfolio.Cash + self.added_cash)
def UpKeep(self):
self.Portfolio.SetCash(self.Portfolio.Cash - self.upkeep)
def consolidation_handler(self, sender, consolidated):
self.history.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close
self.history = self.history.iloc[-(VOLA + 1):]
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 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)
# for kvp in self.Portfolio:
# security_holding = kvp.Value
# sec = security_holding.Symbol.Value
# if self.Portfolio[sec].Invested:
# 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"UnrealizedProfitPercent", str(sec), self.Portfolio[sec].UnrealizedProfitPercent)
# self.Plot(f"Cash", str(sec), round(self.Portfolio[sec].AveragePrice*self.Portfolio[sec].Quantity, 4))
def MarketOpen(self):
return self.Time.hour != 0 and self.Time.minute == 1
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)
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) + 0.075
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
import statistics
from operator import itemgetter
from functools import reduce
from helpers import myPortfolioOptimizer
from symbol_data_functions import SymbolData
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('IWM', self.resolution).Symbol # URTY/IWM
self.STK4 = algorithm.AddEquity('DIA', self.resolution).Symbol # FDN/FDN
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.SHT1 = algorithm.AddEquity('SQQQ', self.resolution).Symbol # UGL/TLT
#self.SHT2 = algorithm.AddEquity('SH', 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.ASSETS = self.STOCKS + self.BONDS #+ self.STOCKS_LEV + self.BONDS_LEV
self.data = dict()
for symbol in self.ASSETS:
self.consolidator = TradeBarConsolidator(timedelta(days=1))
self.consolidator.DataConsolidated += self.consolidation_handler
algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
self.history = np.log(algorithm.History(self.ASSETS, self.VOLA + 1, self.resolution))
self.pfo = myPortfolioOptimizer(minWeight=0, maxWeight=1)
for symbol in self.ASSETS:
algorithm.Securities[symbol].SetLeverage(1)
def consolidation_handler(self, sender, consolidated):
self.history.loc[consolidated.EndTime, consolidated.Symbol] = consolidated.Close
self.history = self.history.iloc[-(self.VOLA + 1):]
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)
if len(addedSymbols) > 0:
history = algorithm.History(addedSymbols, self.VOLA + 1, self.resolution).loc[addedSymbols]
for symbol in addedSymbols:
try:
history = np.log(history)
self.data[symbol].Warmup(history.loc[symbol])
except:
algorithm.Debug(str(symbol))
continue
def returns_custom(self, symbol, timeframe):
prices = np.log(algorithm.History(symbol, TimeSpan.FromDays(21), self.resolution).close)
return round((prices[-timeframe] - prices[-5]) / prices[-5], 4)
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 CreateTargets(self, algorithm, insights):
if algorithm.IsWarmingUp:
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]
# for sec in self.STOCKS:
# algorithm.Plot('CandleSticks', sec, self.calc_candle_score(sec))
# algorithm.Plot('RSI', str(self.STK2)+"_RSI", self.data[self.STK2].rsi.Current.Value)
# algorithm.Plot('RSI', str(self.STK2)+"_StochRsiFastStoch", self.data[self.STK2].stochasticRSI.FastStoch.Current.Value)
# algorithm.Plot('RSI', str(self.STK2)+"_StochRsiK", self.data[self.STK2].stochasticRSI.StochK.Current.Value)
# algorithm.Plot('RSI', str(self.STK2)+"_StochRsiD", self.data[self.STK2].stochasticRSI.StochD.Current.Value)
# algorithm.Plot('MACD', str(self.STK2)+"_MACD", self.data[self.STK2].macd.Current.Value)
# algorithm.Plot('MACD', str(self.STK2)+"_MACDHist", self.data[self.STK2].macd.Histogram.Current.Value)
# algorithm.Plot('MACD', str(self.STK2)+"_MACDSignal", self.data[self.STK2].macd.Signal.Current.Value)
# delta = round(float(self.data[self.STK2].macd.Current.Value - self.data[self.STK2].macd.Signal.Current.Value) / self.data[self.STK2].macd.Fast.Current.Value, 4)
# algorithm.Plot('MACD', str(self.STK2)+"_MACDDelta", float(delta))
# algorithm.Plot('MACD', str(self.STK2)+"_MACDStoch", self.data[self.STK2].stochasticMACD.Current.Value)
# algorithm.Plot('MACD', str(self.STK2)+"_MACDStochFast", self.data[self.STK2].stochasticMACD.FastStoch.Current.Value)
# algorithm.Plot('MACD', str(self.STK2)+"_MACDStochK", self.data[self.STK2].stochasticMACD.StochK.Current.Value)
# algorithm.Plot('MACD', str(self.STK2)+"_MACDStochD", self.data[self.STK2].stochasticMACD.StochD.Current.Value)
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
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 []
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
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, *args, **kwargs):
super().__init__()
self.Symbol = symbol
self.resolution = Resolution.Daily
self.lookback = 20
self.ceiling = 30
self.floor = 10
self.hh_all = False
self.ll_all = False
self.hh_sum = False
self.ll_sum = False
self.breakout = False
self.breakdown = False
self.fir = 0.00
self.EXCL = 21
self.scale = 0.00
self.tol = 0.98
self.is_uptrend = False
self.is_downtrend = False
self.volatility = 0.00
self.tolerance = 0.98
self.vwap = IntradayVwap()
self.vol_slope = 0.00
self.roc_slope = 0.00
self.median_roc = 0.00
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.fast = RateOfChange(int(8*1.0))
self.fast_Win = RollingWindow[float](41)
self.slow = RateOfChange(int(14*1.0))
self.slow_Win = RollingWindow[float](41)
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](5)
self.roclen_Win = RollingWindow[float](int(5))
self.rocSum_Win = RollingWindow[float](int(5))
self.vol_Win = RollingWindow[float](5)
self.prices_Win = RollingWindow[float](41)
self.low_Win = RollingWindow[float](41)
self.high_Win = RollingWindow[float](41)
self.roc_prices_Win = RollingWindow[float](41)
self.roc_prices_lev_Win = RollingWindow[float](10)
self.roc_volume_Win = RollingWindow[float](41)
self.stochasticMACD = Stochastic(30, 3, 3)
self.macd = MovingAverageConvergenceDivergence(12, 26, 9, MovingAverageType.Exponential)
self.macd_stochfast_Win = RollingWindow[float](8)
self.macdStochFastWin = SmartRollingWindow("float", 5)
self.macd_stochk_Win = RollingWindow[float](8)
self.macdStochKWin = SmartRollingWindow("float", 5)
self.macd_stochd_Win = RollingWindow[float](8)
self.macdStochDWin = SmartRollingWindow("float", 5)
self.macd_Win = RollingWindow[float](8)
self.macd_stoch_Win = RollingWindow[float](8)
self.macdHist_Win = RollingWindow[float](8)
self.macdFast_Win = RollingWindow[float](8)
self.macdSlow_Win = RollingWindow[float](8)
self.macdSignal_Win = RollingWindow[float](8)
self.macdDelta_Win = RollingWindow[float](8)
self.macd_uptrend = False
self.macd_downtrend = False
self.stochasticRSI = Stochastic(21, 3, 3)
self.rsi = RelativeStrengthIndex(14, MovingAverageType.Wilders)
self.rsi_Win = RollingWindow[float](8)
self.rsiWin = SmartRollingWindow("float", 5)
self.rsiFastStoch_Win = RollingWindow[float](8)
self.rsiFastStochWin = SmartRollingWindow("float", 5)
self.rsiStochD_Win = RollingWindow[float](5)
self.rsiStochKWin = SmartRollingWindow("float", 5)
self.rsiStochK_Win = RollingWindow[float](5)
self.rsiStochDWin = SmartRollingWindow("float", 5)
self.rsi_uptrend = False
self.rsi_downtrend = False
self.williamsPR = WilliamsPercentR(14)
self.williamsPR_slow = WilliamsPercentR(21)
self.williamsWindow = RollingWindow[float](5)
self.williams_median_roc = 0.00
self.williams_median = 0.00
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_list = RollingWindow[float](6)
self.stochasticTrix = Stochastic(21, 3, 3)
self.trix = Trix(9)
self.trix_slow = Trix(18)
self.trixFastStoch_Win = RollingWindow[float](int(5))
self.trixStochFastWin = SmartRollingWindow("float", 5)
self.trixStochK_Win = RollingWindow[float](int(5))
self.trixStochKWin = SmartRollingWindow("float", 5)
self.trixStochD_Win = RollingWindow[float](int(5))
self.trixStochDWin = SmartRollingWindow("float", 5)
self.trix_uptrend = False
self.trix_downtrend = 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](5)
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.kalWindow = SmartRollingWindow("float", 2)
self.kalWindowLow = SmartRollingWindow("float", 2)
self.kalWindowHigh = SmartRollingWindow("float", 2)
self.priceWindow = SmartRollingWindow("float", 2)
self.priceWindowLow = SmartRollingWindow("float", 2)
self.priceWindowHigh = SmartRollingWindow("float", 2)
self.exit_signal = False
self.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.candleavgWindow = SmartRollingWindow("float", 2)
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.vol_roc, self.vol_roc_fast, self.vol_roc_med, self.vol_roc_long,
self.vwap, self.fast, self.slow,
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.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, self.resolution)
algorithm.RegisterIndicator(symbol, indicator, consolidator)
# Warm up
history = algorithm.History(self.Symbol, 126, self.resolution)
if history.empty or 'close' not in history.columns:
return
for tuple in history.loc[symbol].itertuples():
tradeBar = TradeBar(tuple.Index, symbol, 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)
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_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, tuple.close)
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)
# 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 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
# Stochastic RSI
if self.rsi.IsReady:
rsi = self.rsi.Current.Value
trade_bar = TradeBar(tuple.Index, symbol, rsi, rsi, rsi, rsi, 0)
self.stochasticRSI.Update(trade_bar)
if self.stochasticRSI.IsReady:
self.rsi_Win.Add(rsi)
self.rsiFastStoch_Win.Add(self.stochasticRSI.FastStoch.Current.Value)
self.rsiStochK_Win.Add(self.stochasticRSI.StochK.Current.Value)
self.rsiStochD_Win.Add(self.stochasticRSI.StochD.Current.Value)
self.rsiWin.Add(rsi)
self.rsiFastStochWin.Add(self.stochasticRSI.FastStoch.Current.Value)
self.rsiStochKWin.Add(self.stochasticRSI.StochK.Current.Value)
self.rsiStochDWin.Add(self.stochasticRSI.StochD.Current.Value)
if self.rsi_Win.IsReady:
rsi_list = list(self.rsi_Win)
rsifast_list = list(self.rsiFastStoch_Win)
rsistochk_list = list(self.rsiStochK_Win)
rsistochd_list = list(self.rsiStochD_Win)
curr_rsi, prev_rsi, last_rsi, min_rsi, max_rsi = rsi_list[-1], rsi_list[-2], rsi_list[-3], min(rsi_list), max(rsi_list)
curr_fast, prev_fast, last_fast, min_fast, max_fast = rsifast_list[-1], rsifast_list[-2], rsifast_list[-3], min(rsifast_list), max(rsifast_list)
curr_stochk, prev_stochk, last_stochk, min_stochk, max_stochk = rsistochk_list[-1], rsistochk_list[-2], rsistochk_list[-3], min(rsistochk_list), max(rsistochk_list)
curr_stochd, prev_stochd, last_stochd, min_stochd, max_stochd = rsistochd_list[-1], rsistochd_list[-2], rsistochd_list[-3], min(rsistochd_list), max(rsistochd_list)
cond1 = (curr_fast >= curr_stochk*self.tolerance) and (curr_stochk >= curr_stochd*self.tolerance)
cond11 = (curr_rsi >= max_rsi*self.tolerance) and (curr_fast >= max_fast*self.tolerance) and (curr_stochk >= max_stochk*self.tolerance) and (curr_stochd >= max_stochd*self.tolerance)
cond2 = (curr_rsi >= prev_rsi*self.tolerance) and (curr_fast >= prev_fast*self.tolerance) and (curr_stochk >= prev_stochk*self.tolerance) and (curr_stochd >= prev_stochd*self.tolerance)
cond3 = (prev_rsi >= last_rsi*self.tolerance) and (prev_fast >= last_fast*self.tolerance) and (prev_stochk >= last_stochk*self.tolerance) and (prev_stochd >= last_stochd*self.tolerance)
cond4 = (curr_fast*self.tolerance <= curr_stochk) and (curr_stochk*self.tolerance <= curr_stochd)
cond41 = (min_rsi*self.tolerance <= curr_rsi) and (min_fast*self.tolerance <= curr_fast) and (min_stochk*self.tolerance <= curr_stochk) and (min_stochd*self.tolerance <= curr_stochd)
cond5 = (curr_rsi*self.tolerance <= prev_rsi) and (curr_fast*self.tolerance <= prev_fast) and (curr_stochk*self.tolerance <= prev_stochk) and (curr_stochd*self.tolerance <= prev_stochd)
cond6 = (prev_rsi*self.tolerance <= last_rsi) and (prev_fast*self.tolerance <= last_fast) and (prev_stochk*self.tolerance <= last_stochk) and (prev_stochd*self.tolerance <= last_stochd)
hh_rsi, ll_rsi = calc_divergence(rsi_list)
hh_rsifast, ll_rsifast = calc_divergence(rsifast_list)
hh_rsik, ll_rsik = calc_divergence(rsistochk_list)
hh_rsid, ll_rsid = calc_divergence(rsistochd_list)
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
else:
self.rsi_uptrend = False
if (cond4 and cond8) and (cond5 and cond6):
self.rsi_downtrend = True
else:
self.rsi_downtrend = False
exit = self.rsiFastStochWin.crossedBelow(self.rsiWin) and self.rsiFastStochWin.crossedBelow(self.rsiStochKWin) and self.rsiStochKWin.crossedBelow(self.rsiStochDWin)
entry = self.rsiFastStochWin.crossedAbove(self.rsiWin) and self.rsiFastStochWin.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, symbol, 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_stoch = self.stochasticMACD.Current.Value
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.macdHist_Win.Add(macd_fast)
self.macdFast_Win.Add(macd_hist)
self.macdSlow_Win.Add(macd_slow)
self.macdSignal_Win.Add(signal)
self.macdDelta_Win.Add(delta)
self.macd_stoch_Win.Add(macd_stoch)
self.macd_stochfast_Win.Add(macd_stochfast)
self.macd_stochk_Win.Add(macd_stochk)
self.macd_stochd_Win.Add(macd_stochd)
self.macdStochFastWin.Add(macd_stochfast)
self.macdStochKWin.Add(macd_stochk)
self.macdStochDWin.Add(macd_stochd)
if self.macd_Win.IsReady:
macd_list = list(self.macd_Win)
macdhist_list = list(self.macdHist_Win)
macdfast_list = list(self.macdFast_Win)
macdslow_list = list(self.macdSlow_Win)
macdsignal_list = list(self.macdSignal_Win)
macddelta_list = list(self.macdDelta_Win)
macdstoch_list = list(self.macd_stoch_Win)
macdstochfast_list = list(self.macd_stochfast_Win)
macdstochk_list = list(self.macd_stochk_Win)
macdstochd_list = list(self.macd_stochd_Win)
curr_macd, prev_macd, last_macd, min_macd, max_macd = macd_list[-1], macd_list[-2], macd_list[-3], min(macd_list), max(macd_list)
curr_macd_fast, prev_macd_fast, last_macd_fast, min_macd_fast, max_macd_fast = macdfast_list[-1], macdfast_list[-2], macdfast_list[-3], min(macdfast_list), max(macdfast_list)
curr_macd_slow, prev_macd_slow, last_macd_slow, min_macd_slow, max_macd_slow = macdslow_list[-1], macdslow_list[-2], macdslow_list[-3], min(macdslow_list), max(macdslow_list)
curr_macd_hist, prev_macd_hist, last_macd_hist, min_macd_hist, max_macd_hist = macdhist_list[-1], macdhist_list[-2], macdhist_list[-3], min(macdhist_list), max(macdhist_list)
curr_signal, prev_signal, last_signal, min_signal, max_signal = macdsignal_list[-1], macdsignal_list[-2], macdsignal_list[-3], min(macdsignal_list), max(macdsignal_list)
curr_delta, prev_delta, last_delta, min_delta, max_delta = macddelta_list[-1], macddelta_list[-2], macddelta_list[-3], min(macddelta_list), max(macddelta_list)
curr_macdstoch, prev_macdstoch, last_macdstoch, min_macdstoch, max_macdstoch = macdstoch_list[-1], macdstoch_list[-2], macdstoch_list[3], min(macdstoch_list), max(macdstoch_list)
curr_macdstochfast, prev_macdstochfast, last_macdstochfast, min_macdstochfast, max_macdstochfast = macdstochfast_list[-1], macdstochfast_list[-2], macdstochfast_list[-3], min(macdstochfast_list), max(macdstochfast_list)
curr_macdstochk, prev_macdstochk, last_macdstochk, min_macdstochk, max_macdstochk = macdstochk_list[-1], macdstochk_list[-2], macdstochk_list[-3], min(macdstochk_list), max(macdstochk_list)
curr_macdstochd, prev_macdstochd, last_macdstochd, min_macdstochd, max_macdstochd = macdstochd_list[-1], macdstochd_list[-2], macdstochd_list[-3], min(macdstochd_list), max(macdstochd_list)
cond1 = ((curr_macd_hist-curr_delta)>=0.0025) and (curr_macd >= curr_signal*self.tolerance) and (curr_macdstochfast >= curr_macdstochk*self.tolerance) and (curr_macdstochk >= curr_macdstochd*self.tolerance)
cond11 = (curr_macd >= max_macd*self.tolerance) and (curr_macdstochfast >= max_macdstochfast*self.tolerance) and (curr_macdstochk >= max_macdstochk*self.tolerance) and (curr_macdstochd >= max_macdstochd*self.tolerance)
cond2 = (curr_macd >= prev_macd*self.tolerance) and (curr_macd_fast >= prev_macd_fast*self.tolerance) and (curr_macd_hist >= prev_macd_hist*self.tolerance) and (curr_signal >= prev_signal*self.tolerance)
cond3 = (prev_macd >= last_macd*self.tolerance) and (prev_macd_fast >= last_macd_fast*self.tolerance) and (prev_macd_hist >= last_macd_hist*self.tolerance) and (prev_signal >= last_signal*self.tolerance)
cond4 = ((curr_macd_hist-curr_delta) <= -0.0025) and (curr_macd*self.tolerance <= curr_signal) and (curr_macdstochfast*self.tolerance <= curr_macdstochk) and (curr_macdstochk*self.tolerance <= curr_macdstochd)
cond41 = (min_macd*self.tolerance <= curr_macd) and (min_macdstochfast*self.tolerance <= curr_macdstochfast) and (min_macdstochk*self.tolerance <= curr_macdstochk) and (min_macdstochd*self.tolerance <= curr_macdstochd)
cond5 = (curr_macd*self.tolerance <= prev_macd) and (curr_macd_fast*self.tolerance <= prev_macd_fast) and (curr_macd_hist*self.tolerance <= prev_macd_hist) and (curr_signal*self.tolerance <= prev_signal)
cond6 = (prev_macd*self.tolerance <= last_macd) and (prev_macd_fast*self.tolerance <= last_macd_fast) and (prev_macd_hist*self.tolerance <= last_macd_hist) and (prev_signal*self.tolerance <= last_signal)
hh_macd, ll_macd = calc_divergence(macd_list)
hh_macdhist, ll_macdhist = calc_divergence(macdhist_list)
hh_macdfast, ll_macdfast = calc_divergence(macdfast_list)
hh_macdslow, ll_macdslow = calc_divergence(macdslow_list)
hh_macdsignal, ll_macdsignal = calc_divergence(macdsignal_list)
hh_macdstochfast, ll_macdstochfast = calc_divergence(macdstochfast_list)
hh_macdstochk, ll_macdstochk = calc_divergence(macdstochk_list)
hh_macdstochd, ll_macdstochd = calc_divergence(macdstochd_list)
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
else:
self.macd_uptrend = False
if (cond4 and cond8) and (cond5 and cond6):
self.macd_downtrend = True
else:
self.macd_downtrend = False
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
def roc_calc(obj):
obj_list = list(obj)
output_list = list()
for i in range(-1, -len(obj_list)+1, -1):
if obj_list[i-1] != 0:
val = round((obj_list[i] - obj_list[i-1])/obj_list[i-1], 4)
else:
val = 0
output_list.append(val)
return output_list
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:
val = statistics.median(roc_calc(self.roc_Win))
roc_sum, roc_len = sum(list(self.roc_Win)), len(list(self.roc_Win))
self.roc_slope = round(float(roc_sum)/roc_len, 4)
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:
val = statistics.median(roc_calc(self.vol_Win))
vol_sum, vol_len = sum(list(self.vol_Win)), len(list(self.vol_Win))
self.vol_slope = round(float(vol_sum)/vol_len, 4)
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 and self.roc_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)
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.williamsWindow.Add(round(statistics.median([self.williamsPR.Current.Value, self.williamsPR_slow.Current.Value]), 4))
if self.williamsWindow.IsReady:
williams = list(self.williamsWindow)
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)
self.high_Win.Add(tuple.high)
self.low_Win.Add(tuple.low)
if self.high_Win.IsReady and self.low_Win.IsReady and self.prices_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
breakout_condition1 = (algorithm.Securities[symbol].Close >= max(high[:-1]))
if breakout_condition1:
self.breakout = True
breakdown_condition1 = (algorithm.Securities[symbol].Close >= min(low[:-1]))
if breakdown_condition1:
self.breakdown = True
fast = self.fast.Current.Value
slow = self.slow.Current.Value
median_roc = round(statistics.median([self.roc.Current.Value, self.roc_fast.Current.Value, self.roc_med.Current.Value, self.roc_long.Current.Value]), 4)
self.fast_Win.Add(fast)
self.slow_Win.Add(slow)
self.is_uptrend = (((slow) >= (median_roc*self.tolerance)) and (tuple.close >= (median_roc*self.tolerance)))
self.is_downtrend = (((slow*self.tolerance) <= (median_roc)) and (tuple.close*self.tolerance <= (median_roc)))
if self.is_uptrend or self.fast_Win.IsReady:
# triangle formula
# base * height * 0.5
curr_fast, curr_slow = fast, slow
prev_fast, prev_slow = min(list(self.fast_Win)), min(list(self.slow_Win))
self.scale = round(float(fast - slow) / ((fast+slow)/2.0), 4)
else:
self.scale = 0.00
self.kalWindow.Add(self.kalFilter.Value)
self.kalWindowLow.Add(self.kalFilterLow.Value)
self.kalWindowHigh.Add(self.kalFilterHigh.Value)
self.priceWindow.Add(statistics.median([algorithm.Securities[symbol].Open, algorithm.Securities[symbol].High, algorithm.Securities[symbol].Low, algorithm.Securities[symbol].Close]))
self.priceWindowLow.Add(algorithm.Securities[symbol].Low)
self.priceWindowHigh.Add(algorithm.Securities[symbol].High)
if self.kalFilterLow.IsReady:
exit = self.priceWindowLow.crossedBelow(self.kalWindowLow) and self.priceWindowHigh.crossedBelow(self.kalWindowHigh) and self.priceWindow.crossedBelow(self.kalWindow)
entry = self.priceWindowLow.crossedAbove(self.kalWindowLow) and self.priceWindowHigh.crossedAbove(self.kalWindowHigh) and self.priceWindow.crossedAbove(self.kalWindow)
if algorithm.Portfolio[symbol].Invested:
# exit
if exit is True:
self.exit_signal = True
else:
self.exit_signal = False
elif not algorithm.Portfolio[symbol].Invested:
# entry
if entry is True:
self.entry_signal = True
else:
self.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_Win[i] >= vpn_hlc_Win[i-1] + dist):
vp += vpn_vol_Win[i]
elif (vpn_hlc_Win[i] <= vpn_hlc_Win[i-1] - dist):
vn += vpn_vol_Win[i]
vtot += vpn_vol_Win[i]
vpn_val = (((vp - vn) / (vtot/self.vpn_period)) / self.vpn_period) * 100
self.vpn_list.Add(vpn_val)
if self.vpn_list.IsReady:
vpn_ema = pd.DataFrame(list(self.vpn_list)).ewm(span=ema_smooth, adjust=False).mean().iloc[-1][0]
vpn_scale = self.vpn_list[-1]
vpnIndicator = ((vpn_scale) >= (vpn_ema*self.tolerance)) and ((vpn_scale) >= (self.vpn_list[-2]*self.tolerance))
self.vpnIndicator = vpnIndicator
if self.vpnIndicator:
curr_vpn, curr_vpn_ema = vpn_scale, vpn_ema
low_vpn, low_vpn_ema = min(self.vpn_list), min(pd.DataFrame(list(self.vpn_list)).ewm(span=ema_smooth, adjust=False).mean().iloc[-1])
vpnScale = round(float(curr_vpn - curr_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.median([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.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
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 = {}
# 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 # algorithm.Portfolio.Cash/(algorithm.Portfolio.Cash + algorithm.Portfolio.UnsettledCash)
# 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):# or self.SpreadIsFavorable(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)
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)
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[0] >= data.DWindow[0]) and (data.KWindow[1] <= data.DWindow[1])) and ((data.KWindow_Med[0] >= data.DWindow_Med[0]) and (data.KWindow_Med[0] <= data.DWindow_Med[0])))
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, unorderedQuantity):
'''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.tolerance = 0.98
self.is_uptrend = False
self.macd_uptrend = False
self.scale = 0.00
self.period = 21
self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, security.Resolution)
name = algorithm.CreateIndicatorName(security.Symbol, "VWAP", security.Resolution)
self.vwap = IntradayVwap(name)
algorithm.RegisterIndicator(security.Symbol, self.vwap, self.Consolidator)
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 = RollingWindow[float](5)
self.KWindow = RollingWindow[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 = RollingWindow[float](5)
self.KWindow_Med = RollingWindow[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)
roc_fName = algorithm.CreateIndicatorName(security.Symbol, f"ROC_F{self.period}", security.Resolution)
# warmup our indicators by pushing history through the indicators
history = algorithm.History(security.Symbol, 84, security.Resolution)
if 'close' in history:
for tuple in history.loc[security.Symbol].itertuples():
tradeBar = TradeBar(tuple.Index, security.Symbol, 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)
self.SMA.Update(tuple.Index, median_price)
self.SMA_Med.Update(tuple.Index, median_price)
self.STD.Update(tuple.Index, median_price)
sma = self.SMA.Current.Value
sma_bar = TradeBar(tuple.Index, security.Symbol, 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(tuple.Index, security.Symbol, 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