Advanced Integrated Data Visualization (AIDV) in Python – 1. Stock Technical Indicators

Featured Photo by Monstera on Pexels.

  • In this post, we will put forward advanced integrated data visualization (AIDV) in the stock trading decisions and stock price prediction. The objective is to implement and visualize most popular stock technical indicators that are commonly used in technical analysis.
  • From the point of view of algo trading, this study proves the credibility and advantages of AIDV in Python for the stock trading decisions and stock price prediction.
  • Our final goal is to provide the trader with a dynamically changing and interactive UI using the technical analysis libraries available for Python and Plotly’s interactive AIDV tools.

In this project, we will implement the following Technical Indicators in Python:

  • RSI, Volume (plain), Bollinger Bands, Aroon, Price Volume Trend, acceleration bands
  • Stochastic, Chaikin Money Flow, Parabolic SAR, Rate of Change, Volume weighted average Price, momentum
  • Commodity Channel Index, On Balance Volume, Keltner Channels, Triple Exponential Moving Average, Normalized Average True Range , directional movement indicators
  • MACD, Money Flow index , Ichimoku, William %R, Volume MINMAX, adaptive moving average.

Conventionally, we will look at the following three main groups of technical indicators:

  1. Trend indicators — Simple Moving Average(SMA), Exponential Moving Average (EMA), Average Directional Movement Index (ADX), etc.
  2. Momentum indicators — Moving Average Convergence Divergence (MACD), Relative Strength Index (RSI), etc.
  3. Volatility indicators — e.g. Bollinger Bands.

Input Stock Data

Let’s set the working directory VIZ

import os
os.chdir(‘VIZ’)
os. getcwd()

and import the key libraries

import datetime as dt
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

import random
import copy

plt.style.use(‘fivethirtyeight’)
plt.rcParams[‘figure.figsize’] = (20,10)

Let’s download the stock data

def download_stock_data(ticker,timestamp_start,timestamp_end):
url=f”https://query1.finance.yahoo.com/v7/finance/download/{ticker}?period1={timestamp_start}&period2={timestamp_end}&interval\
=1d&events=history&includeAdjustedClose=true”
df = pd.read_csv(url)
return df

datetime_start=dt.datetime(2022, 1, 1, 7, 35, 51)
datetime_end=dt.datetime.today()

timestamp_start=int(datetime_start.timestamp())
timestamp_end=int(datetime_end.timestamp())

ticklist=[‘XOM’,’O’,’AZN’,’MO’,’COST’,’SBUX’,’AAPL’,’LMT’]
datac = []
for tick in ticklist:
df = download_stock_data(tick,timestamp_start,timestamp_end)
df = df.set_index(‘Date’)
df[‘Label’] = tick
datac.append(df)
print (datac)

[                  Open        High         Low       Close   Adj Close  \
Date                                                                     
2022-01-03   61.240002   63.599998   61.209999   63.540001   60.648853   
2022-01-04   64.129997   66.190002   64.099998   65.930000   62.930103   
2022-01-05   66.500000   67.610001   66.480003   66.750000   63.712791   
2022-01-06   68.000000   68.480003   67.070000   68.320000   65.211357   
2022-01-07   68.519997   69.180000   67.980003   68.879997   65.745872   
...                ...         ...         ...         ...         ...   
2023-03-30  109.550003  109.570000  108.519997  109.489998  109.489998   
2023-03-31  109.680000  110.169998  109.050003  109.660004  109.660004   
2023-04-03  113.389999  116.849998  113.120003  116.129997  116.129997   
2023-04-04  116.260002  116.699997  114.169998  115.019997  115.019997   
2023-04-05  115.349998  117.000000  114.309998  116.989998  116.989998   

              Volume Label  
Date                        
2022-01-03  24282400   XOM  
2022-01-04  38584000   XOM  
2022-01-05  34033300   XOM  
2022-01-06  30668500   XOM  
2022-01-07  23985400   XOM  
...              ...   ...  
2023-03-30  11578200   XOM  
2023-03-31  14416800   XOM  
2023-04-03  28087700   XOM  
2023-04-04  16365500   XOM  
2023-04-05  16475200   XOM  

[316 rows x 7 columns],                  Open       High        Low      Close  Adj Close   Volume  \
Date                                                                         
2022-01-03  71.730003  71.809998  70.099998  71.199997  67.311935  3110500   
2022-01-04  71.150002  72.480003  71.120003  72.250000  68.304596  3410700   
2022-01-05  72.120003  72.480003  70.889999  71.080002  67.198494  3237600   
2022-01-06  71.360001  71.870003  70.889999  71.410004  67.510460  2869800   
2022-01-07  71.129997  71.540001  70.709999  71.410004  67.510460  3108900   
...               ...        ...        ...        ...        ...      ...   
2023-03-30  62.430000  62.860001  62.349998  62.610001  62.355000  3008000   
2023-03-31  62.520000  63.360001  62.470001  63.320000  63.320000  4141500   
2023-04-03  62.950001  63.400002  62.389999  62.869999  62.869999  5758400   
2023-04-04  62.830002  62.990002  62.389999  62.840000  62.840000  2832400   
2023-04-05  62.959999  63.110001  62.470001  62.709999  62.709999  4000600   

           Label  
Date              
2022-01-03     O  
2022-01-04     O  
2022-01-05     O  
2022-01-06     O  
2022-01-07     O  
...          ...  
2023-03-30     O  
2023-03-31     O  
2023-04-03     O  
2023-04-04     O  
2023-04-05     O  

[316 rows x 7 columns],                  Open       High        Low      Close  Adj Close   Volume  \
Date                                                                         
2022-01-03  58.270000  58.369999  57.750000  58.310001  56.144096  3321000   
2022-01-04  57.160000  57.700001  57.070000  57.270000  55.142727  4646600   
2022-01-05  57.240002  57.730000  56.849998  56.880001  54.767216  4804400   
2022-01-06  56.810001  57.040001  56.110001  56.669998  54.565006  6196400   
2022-01-07  56.650002  57.549999  56.529999  57.480000  55.344921  4594800   
...               ...        ...        ...        ...        ...      ...   
2023-03-30  69.050003  69.220001  68.629997  69.199997  69.199997  4648100   
2023-03-31  69.879997  69.930000  69.239998  69.410004  69.410004  3500300   
2023-04-03  69.529999  69.949997  69.360001  69.910004  69.910004  4749200   
2023-04-04  69.980003  70.570000  69.809998  70.250000  70.250000  4383400   
2023-04-05  72.000000  72.480003  71.800003  72.050003  72.050003  5873200   

           Label  
Date              
2022-01-03   AZN  
2022-01-04   AZN  
2022-01-05   AZN  
2022-01-06   AZN  
2022-01-07   AZN  
...          ...  
2023-03-30   AZN  
2023-03-31   AZN  
2023-04-03   AZN  
2023-04-04   AZN  
2023-04-05   AZN  

[316 rows x 7 columns],                  Open       High        Low      Close  Adj Close    Volume  \
Date                                                                          
2022-01-03  47.369999  48.000000  47.180000  47.970001  43.408066  10308100   
2022-01-04  48.000000  49.340000  47.980000  49.029999  44.367256  11647900   
2022-01-05  48.549999  49.270000  48.330002  48.639999  44.014351  11506500   
2022-01-06  49.180000  49.720001  48.869999  49.209999  44.530140  10134100   
2022-01-07  49.200001  50.000000  49.099998  49.770000  45.036888   8098600   
...               ...        ...        ...        ...        ...       ...   
2023-03-30  44.639999  44.830002  44.349998  44.500000  44.500000   6862400   
2023-03-31  44.630001  44.720001  44.430000  44.619999  44.619999   7710000   
2023-04-03  44.720001  45.330002  44.599998  44.980000  44.980000   8385800   
2023-04-04  44.880001  44.910000  44.240002  44.450001  44.450001   7379600   
2023-04-05  44.459999  44.700001  44.189999  44.430000  44.430000   7865000   

           Label  
Date              
2022-01-03    MO  
2022-01-04    MO  
2022-01-05    MO  
2022-01-06    MO  
2022-01-07    MO  
...          ...  
2023-03-30    MO  
2023-03-31    MO  
2023-04-03    MO  
2023-04-04    MO  
2023-04-05    MO  

[316 rows x 7 columns],                   Open        High         Low       Close   Adj Close  \
Date                                                                     
2022-01-03  565.030029  567.469971  555.510010  566.710022  561.965271   
2022-01-04  564.229980  568.719971  561.789978  564.229980  559.506042   
2022-01-05  563.690002  565.049988  549.770020  549.919983  545.315857   
2022-01-06  546.200012  553.520020  543.549988  549.799988  545.196899   
2022-01-07  547.549988  548.369995  534.239990  536.179993  531.690857   
...                ...         ...         ...         ...         ...   
2023-03-30  493.000000  495.739990  491.000000  491.480011  491.480011   
2023-03-31  495.000000  498.359985  493.940002  496.869995  496.869995   
2023-04-03  496.500000  499.200012  495.000000  497.029999  497.029999   
2023-04-04  496.500000  502.579987  495.500000  497.730011  497.730011   
2023-04-05  499.000000  504.130005  495.160004  497.130005  497.130005   

             Volume Label  
Date                       
2022-01-03  2714100  COST  
2022-01-04  2097500  COST  
2022-01-05  2887500  COST  
2022-01-06  2503100  COST  
2022-01-07  2323900  COST  
...             ...   ...  
2023-03-30  1545500  COST  
2023-03-31  2081300  COST  
2023-04-03  1804700  COST  
2023-04-04  1913300  COST  
2023-04-05  1930600  COST  

[316 rows x 7 columns],                   Open        High         Low       Close   Adj Close  \
Date                                                                     
2022-01-03  116.470001  117.800003  114.779999  116.680000  113.403084   
2022-01-04  116.900002  117.050003  114.169998  114.239998  111.031593   
2022-01-05  114.400002  114.959999  110.400002  110.440002  107.338318   
2022-01-06  110.000000  111.879997  109.989998  111.139999  108.018661   
2022-01-07  108.220001  109.709999  107.480003  107.570000  104.548920   
...                ...         ...         ...         ...         ...   
2023-03-30  101.440002  101.699997  100.650002  101.320000  101.320000   
2023-03-31  101.839996  104.279999  101.839996  104.129997  104.129997   
2023-04-03  104.059998  104.940002  103.669998  104.849998  104.849998   
2023-04-04  104.849998  105.010002  103.349998  104.000000  104.000000   
2023-04-05  103.980003  105.699997  103.930000  104.900002  104.900002   

              Volume Label  
Date                        
2022-01-03   5475700  SBUX  
2022-01-04   8367600  SBUX  
2022-01-05   8662300  SBUX  
2022-01-06   6099900  SBUX  
2022-01-07  11266400  SBUX  
...              ...   ...  
2023-03-30   4082600  SBUX  
2023-03-31   6899300  SBUX  
2023-04-03   3855400  SBUX  
2023-04-04   3854400  SBUX  
2023-04-05   5169900  SBUX  

[316 rows x 7 columns],                   Open        High         Low       Close   Adj Close  \
Date                                                                     
2022-01-03  177.830002  182.880005  177.710007  182.009995  180.683868   
2022-01-04  182.630005  182.940002  179.119995  179.699997  178.390701   
2022-01-05  179.610001  180.169998  174.639999  174.919998  173.645538   
2022-01-06  172.699997  175.300003  171.639999  172.000000  170.746826   
2022-01-07  172.889999  174.139999  171.029999  172.169998  170.915588   
...                ...         ...         ...         ...         ...   
2023-03-30  161.529999  162.470001  161.270004  162.360001  162.360001   
2023-03-31  162.440002  165.000000  161.910004  164.899994  164.899994   
2023-04-03  164.270004  166.289993  164.220001  166.169998  166.169998   
2023-04-04  166.600006  166.839996  165.110001  165.630005  165.630005   
2023-04-05  164.740005  165.050003  161.800003  163.759995  163.759995   

               Volume Label  
Date                         
2022-01-03  104487900  AAPL  
2022-01-04   99310400  AAPL  
2022-01-05   94537600  AAPL  
2022-01-06   96904000  AAPL  
2022-01-07   86709100  AAPL  
...               ...   ...  
2023-03-30   49501700  AAPL  
2023-03-31   68694700  AAPL  
2023-04-03   56976200  AAPL  
2023-04-04   46278300  AAPL  
2023-04-05   51457200  AAPL  

[316 rows x 7 columns],                   Open        High         Low       Close   Adj Close  \
Date                                                                     
2022-01-03  354.679993  356.589996  353.029999  354.359985  343.132660   
2022-01-04  355.529999  363.540009  355.209991  361.989990  350.520935   
2022-01-05  363.000000  364.000000  357.869995  358.140015  346.792938   
2022-01-06  360.000000  361.239990  357.549988  358.000000  346.657349   
2022-01-07  359.079987  362.989990  358.149994  360.140015  348.729553   
...                ...         ...         ...         ...         ...   
2023-03-30  474.540009  475.799988  471.730011  473.179993  473.179993   
2023-03-31  474.190002  475.350006  471.029999  472.730011  472.730011   
2023-04-03  473.000000  487.899994  472.750000  486.619995  486.619995   
2023-04-04  485.589996  490.630005  484.750000  488.540009  488.540009   
2023-04-05  488.000000  493.829987  487.029999  489.989990  489.989990   

             Volume Label  
Date                       
2022-01-03  1205700   LMT  
2022-01-04  1361100   LMT  
2022-01-05  1682200   LMT  
2022-01-06  1368800   LMT  
2022-01-07  1634600   LMT  
...             ...   ...  
2023-03-30   950300   LMT  
2023-03-31  1409600   LMT  
2023-04-03  1656700   LMT  
2023-04-04  1081100   LMT  
2023-04-05  1305500   LMT  

[316 rows x 7 columns]]

TechIndicator = copy.deepcopy(data)

Relative Strength Index (RSI)

  • The relative strength index (RSI) is a momentum indicator used in technical analysis. RSI measures the speed and magnitude of a security’s recent price changes to evaluate overvalued or undervalued conditions in the price of that security.
  • The RSI is displayed as an oscillator (a line graph) on a scale of zero to 100.
  • An asset is usually considered overbought when the RSI is above 70 and oversold when it is below 30.

def rsi(values):
up = values[values>0].mean()
down = -1*values[values<0].mean()
return 100 * up / (up + down)

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘Momentum_1D’] = (TechIndicator[stock][‘Close’]-TechIndicator[stock][‘Close’].shift(1)).fillna(0)
TechIndicator[stock][‘RSI_14D’] = TechIndicator[stock][‘Momentum_1D’].rolling(center=False, window=14).apply(rsi).fillna(0)
TechIndicator[0].tail(5)

Volume

  • Trading volume is a measure of how much a given financial asset has traded in a period of time. For stocks, volume is measured in the number of shares traded. For futures and options, volume is based on how many contracts have changed hands. Traders look to volume to determine liquidity and combine changes in volume with technical indicators to make trading decisions.
  • Volume measures the number of shares traded in a stock or contracts traded in futures or options.
  • Volume can indicate market strength, as rising markets on increasing volume are typically viewed as strong and healthy.
  • When prices fall on increasing volume, the trend is gathering strength to the downside.
  • When prices reach new highs (or no lows) on decreasing volume, watch out—a reversal might be taking shape.
  • On-balance volume (OBV) and the Klinger oscillator are examples of charting tools that are based on volume.

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘Volume_plain’] = TechIndicator[stock][‘Volume’].fillna(0)
TechIndicator[0].tail()

Bollinger Bands (BB)

  • Bollinger Bands® is a technical analysis tool to generate oversold or overbought signals and was developed by John Bollinger.
  • Three lines compose Bollinger Bands: A simple moving average, or the middle band, and an upper and lower band.
  • The upper and lower bands are typically 2 standard deviations +/- from a 20-day simple moving average and can be modified.
  • When the price continually touches the upper Bollinger Band, it can indicate an overbought signal.
  • If the price continually touches the lower band it can indicate an oversold signal.

def bbands(price, length=30, numsd=2):
“”” returns average, upper band, and lower band”””
#ave = pd.stats.moments.rolling_mean(price,length)
ave = price.rolling(window = length, center = False).mean()
#sd = pd.stats.moments.rolling_std(price,length)
sd = price.rolling(window = length, center = False).std()
upband = ave + (sdnumsd) dnband = ave – (sdnumsd)
return np.round(ave,3), np.round(upband,3), np.round(dnband,3)

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘BB_Middle_Band’], TechIndicator[stock][‘BB_Upper_Band’], TechIndicator[stock][‘BB_Lower_Band’] = bbands(TechIndicator[stock][‘Close’], length=20, numsd=1)
TechIndicator[stock][‘BB_Middle_Band’] = TechIndicator[stock][‘BB_Middle_Band’].fillna(0)
TechIndicator[stock][‘BB_Upper_Band’] = TechIndicator[stock][‘BB_Upper_Band’].fillna(0)
TechIndicator[stock][‘BB_Lower_Band’] = TechIndicator[stock][‘BB_Lower_Band’].fillna(0)
TechIndicator[0].tail()

Aroon Oscillator (AO)

The Aroon indicator is a technical indicator that is used to identify trend changes in the price of an asset, as well as the strength of that trend. 

  • The Aroon indicator is composed of two lines. An up line which measures the number of periods since a High, and a down line which measures the number of periods since a Low.
  • The indicator is typically applied to 25 periods of data, so the indicator is showing how many periods it has been since a 25-period high or low.
  • When the Aroon Up is above the Aroon Down, it indicates bullish price behavior.
  • When the Aroon Down is above the Aroon Up, it signals bearish price behavior.
  • Crossovers of the two lines can signal trend changes. For example, when Aroon Up crosses above Aroon Down it may mean a new uptrend is starting.
  • The indicator moves between zero and 100.

def aroon(df, tf=25):
aroonup = []
aroondown = []
x = tf
while x< len(df.index):
aroon_up = ((df[‘High’][x-tf:x].tolist().index(max(df[‘High’][x-tf:x])))/float(tf))100 aroon_down = ((df[‘Low’][x-tf:x].tolist().index(min(df[‘Low’][x-tf:x])))/float(tf))100
aroonup.append(aroon_up)
aroondown.append(aroon_down)
x+=1
return aroonup, aroondown

for stock in range(len(TechIndicator)):
listofzeros = [0] * 25
up, down = aroon(TechIndicator[stock])
aroon_list = [x – y for x, y in zip(up,down)]
if len(aroon_list)==0:
aroon_list = [0] * TechIndicator[stock].shape[0]
TechIndicator[stock][‘Aroon_Oscillator’] = aroon_list
else:
TechIndicator[stock][‘Aroon_Oscillator’] = listofzeros+aroon_list

Price Volume Trend (PVT)

The PVT indicator helps determine a security’s price direction and strength of price change. The indicator consists of a cumulative volume line that adds or subtracts a multiple of the percentage change in a share prices’ trend and current volume, depending upon the security’s upward or downward movements.

for stock in range(len(TechIndicator)):
TechIndicator[stock][“PVT”] = (TechIndicator[stock][‘Momentum_1D’]/ TechIndicator[stock][‘Close’].shift(1))*TechIndicator[stock][‘Volume’]
TechIndicator[stock][“PVT”] = TechIndicator[stock][“PVT”]-TechIndicator[stock][“PVT”].shift(1)
TechIndicator[stock][“PVT”] = TechIndicator[stock][“PVT”].fillna(0)
TechIndicator[0].tail()

Acceleration Bands (AB)

The Acceleration Bands measure volatility over a user-defined number of bars (default is often the past 20 bars). They are plotted using a simple moving average as the midpoint, with the upper and lower bands being of equal distance from the midpoint, similar to Bollinger Bands.

def abands(df):
#df[‘AB_Middle_Band’] = pd.rolling_mean(df[‘Close’], 20)
df[‘AB_Middle_Band’] = df[‘Close’].rolling(window = 20, center=False).mean()
# High * ( 1 + 4 * (High – Low) / (High + Low))
df[‘aupband’] = df[‘High’] * (1 + 4 * (df[‘High’]-df[‘Low’])/(df[‘High’]+df[‘Low’]))
df[‘AB_Upper_Band’] = df[‘aupband’].rolling(window=20, center=False).mean()
# Low *(1 – 4 * (High – Low)/ (High + Low))
df[‘adownband’] = df[‘Low’] * (1 – 4 * (df[‘High’]-df[‘Low’])/(df[‘High’]+df[‘Low’]))
df[‘AB_Lower_Band’] = df[‘adownband’].rolling(window=20, center=False).mean()

for stock in range(len(TechIndicator)):
abands(TechIndicator[stock])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[0].tail()

columns2Drop = [‘Momentum_1D’, ‘aupband’, ‘adownband’]
for stock in range(len(TechIndicator)):
TechIndicator[stock] = TechIndicator[stock].drop(labels = columns2Drop, axis=1)
TechIndicator[0].head()

Stochastic Oscillator (%K and %D)

A stochastic oscillator is a momentum indicator comparing a particular closing price of a security to a range of its prices over a certain period of time. The sensitivity of the oscillator to market movements is reducible by adjusting that time period or by taking a moving average of the result. It is used to generate overbought and oversold trading signals, utilizing a 0–100 bounded range of values.

  • Stochastics are a favored technical indicator because they are easy to understand and have a relatively high degree of accuracy.
  • It falls into the class of technical indicators known as oscillators.
  • The indicator provides buy and sell signals for traders to enter or exit positions based on momentum.
  • Stochastics are used to show when a stock has moved into an overbought or oversold position.
  • it is beneficial to use stochastics in conjunction with other tools like the relative strength index (RSI) to confirm a signal.

def STOK(df, n):
df[‘STOK’] = ((df[‘Close’] – df[‘Low’].rolling(window=n, center=False).mean()) / (df[‘High’].rolling(window=n, center=False).max() – df[‘Low’].rolling(window=n, center=False).min())) * 100
df[‘STOD’] = df[‘STOK’].rolling(window = 3, center=False).mean()

for stock in range(len(TechIndicator)):
STOK(TechIndicator[stock], 4)
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[0].tail()

Chaikin Money Flow (CMFlow)

  • The Chaikin Indicator applies MACD to the accumulation-distribution line rather than to the closing price.
  • It is an oscillator technical indicator for spotting trends and reversals.
  • A cross above the accumulation-distribution line indicates that market players are accumulating shares, securities, or contracts, which is typically bullish.

To calculate the Chaikin oscillator, subtract a 10-day exponential moving average (EMA) of the accumulation-distribution line from a 3-day EMA of the accumulation-distribution line. This measures momentum predicted by oscillations around the accumulation-distribution line.

def CMFlow(df, tf):
CHMF = []
MFMs = []
MFVs = []
x = tf

while x < len(df.index):
    PeriodVolume = 0
    volRange = df['Volume'][x-tf:x]
    for eachVol in volRange:
        PeriodVolume += eachVol

    MFM = ((df['Close'][x] - df['Low'][x]) - (df['High'][x] - df['Close'][x])) / (df['High'][x] - df['Low'][x])
    MFV = MFM*PeriodVolume

    MFMs.append(MFM)
    MFVs.append(MFV)
    x+=1

y = tf
while y < len(MFVs):
    PeriodVolume = 0
    volRange = df['Volume'][x-tf:x]
    for eachVol in volRange:
        PeriodVolume += eachVol
    consider = MFVs[y-tf:y]
    tfsMFV = 0

    for eachMFV in consider:
        tfsMFV += eachMFV

    tfsCMF = tfsMFV/PeriodVolume
    CHMF.append(tfsCMF)
    y+=1
return CHMF

for stock in range(len(TechIndicator)):
listofzeros = [0] * 40
CHMF = CMFlow(TechIndicator[stock], 20)
if len(CHMF)==0:
CHMF = [0] * TechIndicator[stock].shape[0]
TechIndicator[stock][‘Chaikin_MF’] = CHMF
else:
TechIndicator[stock][‘Chaikin_MF’] = listofzeros+CHMF
TechIndicator[0].tail()

Parabolic SAR (PSAR)

  • The parabolic SAR indicator appears on a chart as a series of dots, either above or below an asset’s price, depending on the direction the price is moving. A dot is placed below the price when it is trending upward, and above the price when it is trending downward.
  • A reversal occurs when these dots flip, but a reversal signal in the SAR does not necessarily mean a reversal in the price. A PSAR reversal only means that the price and indicator have crossed.

def psar(df, iaf = 0.02, maxaf = 0.2):
length = len(df)
dates = (df.index)
high = (df[‘High’])
low = (df[‘Low’])
close = (df[‘Close’])
psar = df[‘Close’][0:len(df[‘Close’])]
psarbull = [None] * length
psarbear = [None] * length
bull = True
af = iaf
ep = df[‘Low’][0]
hp = df[‘High’][0]
lp = df[‘Low’][0]
for i in range(2,length):
if bull:
psar[i] = psar[i – 1] + af * (hp – psar[i – 1])
else:
psar[i] = psar[i – 1] + af * (lp – psar[i – 1])
reverse = False
if bull:
if df[‘Low’][i] < psar[i]: bull = False reverse = True psar[i] = hp lp = df[‘Low’][i] af = iaf else: if df[‘High’][i] > psar[i]:
bull = True
reverse = True
psar[i] = lp
hp = df[‘High’][i]
af = iaf
if not reverse:
if bull:
if df[‘High’][i] > hp:
hp = df[‘High’][i]
af = min(af + iaf, maxaf)
if df[‘Low’][i – 1] < psar[i]: psar[i] = df[‘Low’][i – 1] if df[‘Low’][i – 2] < psar[i]: psar[i] = df[‘Low’][i – 2] else: if df[‘Low’][i] < lp: lp = df[‘Low’][i] af = min(af + iaf, maxaf) if df[‘High’][i – 1] > psar[i]:
psar[i] = df[‘High’][i – 1]
if df[‘High’][i – 2] > psar[i]:
psar[i] = df[‘High’][i – 2]
if bull:
psarbull[i] = psar[i]
else:
psarbear[i] = psar[i]

df[‘psar’] = psar

for stock in range(len(TechIndicator)):
psar(TechIndicator[stock])

TechIndicator[0].tail()

Price Rate of Change (ROC)

The Price Rate of Change (ROC) is a momentum-based technical indicator that measures the percentage change in price between the current price and the price a certain number of periods ago. The ROC indicator is plotted against zero, with the indicator moving upwards into positive territory if price changes are to the upside, and moving into negative territory if price changes are to the downside.

  • The Price Rate of Change (ROC) oscillator is an unbounded momentum indicator used in technical analysis set against a zero-level midpoint.
  • A rising ROC above zero typically confirms an uptrend while a falling ROC below zero indicates a downtrend.
  • When the price is consolidating, the ROC will hover near zero. In this case, it is important traders watch the overall price trend since the ROC will provide little insight except for confirming the consolidation.

# ROC = [(Close – Close n periods ago) / (Close n periods ago)] * 100

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘ROC’] = ((TechIndicator[stock][‘Close’] – TechIndicator[stock][‘Close’].shift(12))/(TechIndicator[stock][‘Close’].shift(12)))*100
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[0].tail()

Volume Weighted Average Price (VWAP)

  • The VWAP is a technical analysis indicator used on intraday charts that resets at the start of every new trading session.
  • It’s a trading benchmark that represents the average price a security has traded at throughout the day, based on both volume and price.
  • VWAP appears as a single line on intraday charts.
  • It looks similar to a moving average line, but smoother.
  • VWAP represents a view of price action throughout a single day’s trading session.
  • Retail and professional traders may use VWAP to help them determine intraday price trends.
  • VWAP typically is most useful to short-term traders.

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘VWAP’] = np.cumsum(TechIndicator[stock][‘Volume’] * (TechIndicator[stock][‘High’] + TechIndicator[stock][‘Low’])/2) / np.cumsum(TechIndicator[stock][‘Volume’])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[0].tail()

Momentum

Momentum measures the rate of the rise or fall in stock prices. For trending analysis, momentum is a useful indicator of strength or weakness in the issue’s price. History has shown that momentum is far more useful during rising markets than falling markets because markets rise more often than they fall.

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘Momentum’] = TechIndicator[stock][‘Close’] – TechIndicator[stock][‘Close’].shift(4)
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[0].tail()

Commodity Channel Index (CCI)

  • The Commodity Channel Index (CCI) is a technical indicator that measures the difference between the current price and the historical average price.
  • When the CCI is above zero, it indicates the price is above the historic average. Conversely, when the CCI is below zero, the price is below the historic average.
  • The CCI is an unbounded oscillator, meaning it can go higher or lower indefinitely. For this reason, overbought and oversold levels are typically determined for each individual asset by looking at historical extreme CCI levels where the price reversed from.

def CCI(df, n, constant):
TP = (df[‘High’] + df[‘Low’] + df[‘Close’]) / 3
CCI = pd.Series((TP – TP.rolling(window=n, center=False).mean()) / (constant * TP.rolling(window=n, center=False).std())) #, name = ‘CCI_’ + str(n))
return CCI

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘CCI’] = CCI(TechIndicator[stock], 20, 0.015)
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[0].tail()

On Balance Volume (OBV)

On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict changes in stock price. 

  • OBV shows crowd sentiment that can predict a bullish or bearish outcome.
  • Comparing relative action between price bars and OBV generates more actionable signals than the green or red volume histograms commonly found at the bottom of price charts. 

for stock in range(len(TechIndicator)):
new = (TechIndicator[stock][‘Volume’] * (~TechIndicator[stock][‘Close’].diff().le(0) * 2 -1)).cumsum()
TechIndicator[stock][‘OBV’] = new
TechIndicator[5].tail()

Keltner Channels (KCH)

  • Keltner Channels are volatility-based bands that are placed on either side of an asset’s price and can aid in determining the direction of a trend.
  • The exponential moving average (EMA) of a Keltner Channel is typically 20 periods, although this can be adjusted if desired.
  • The upper and lower bands are typically set two times the average true range (ATR) above and below the EMA, although the multiplier can also be adjusted based on personal preference.
  • Price reaching the upper Keltner Channel band is bullish, while reaching the lower band is bearish.
  • The angle of the Keltner Channel also aids in identifying the trend direction. The price may also oscillate between the upper and lower Keltner Channel bands, which can be interpreted as resistance and support levels.

def KELCH(df, n):
KelChM = pd.Series(((df[‘High’] + df[‘Low’] + df[‘Close’]) / 3).rolling(window =n, center=False).mean(), name = ‘KelChM_’ + str(n))
KelChU = pd.Series(((4 * df[‘High’] – 2 * df[‘Low’] + df[‘Close’]) / 3).rolling(window =n, center=False).mean(), name = ‘KelChU_’ + str(n))
KelChD = pd.Series(((-2 * df[‘High’] + 4 * df[‘Low’] + df[‘Close’]) / 3).rolling(window =n, center=False).mean(), name = ‘KelChD_’ + str(n))
return KelChM, KelChD, KelChU

for stock in range(len(TechIndicator)):
KelchM, KelchD, KelchU = KELCH(TechIndicator[stock], 14)
TechIndicator[stock][‘Kelch_Upper’] = KelchU
TechIndicator[stock][‘Kelch_Middle’] = KelchM
TechIndicator[stock][‘Kelch_Down’] = KelchD
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[5].tail()

Triple Exponential Moving Average (TEMA)

  • The triple exponential moving average (TEMA) uses multiple EMA calculations and subtracts out the lag to create a trend following indicator that reacts quickly to price changes.
  • The TEMA indicator can help identify trend direction, signal potential short-term trend changes or pullbacks, and provide support or resistance.
  • When the price is above the TEMA it helps confirm an uptrend; when the price is below the TEMA it helps confirm a downtrend.

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘EMA’] = TechIndicator[stock][‘Close’].ewm(span=3,min_periods=0,adjust=True,ignore_na=False).mean()

TechIndicator[stock] = TechIndicator[stock].fillna(0)

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘TEMA’] = (3 * TechIndicator[stock][‘EMA’] – 3 * TechIndicator[stock][‘EMA’] * TechIndicator[stock][‘EMA’]) + (TechIndicator[stock][‘EMA’]TechIndicator[stock][‘EMA’]TechIndicator[stock][‘EMA’])
TechIndicator[5].tail()

Normalized Average True Range (NATR)

  • The average true range (ATR) is a market volatility indicator used in technical analysis.
  • It is typically derived from the 14-day simple moving average of a series of true range indicators.
  • The ATR was initially developed for use in commodities markets but has since been applied to all types of securities.
  • ATR shows investors the average range prices swing for an investment over a specified period.
  • True Range = Highest of (HIgh – low, abs(High – previous close), abs(low – previous close))
  • Average True Range = 14 day MA of True Range
  • Normalized Average True Range = ATR / Close * 100

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘HL’] = TechIndicator[stock][‘High’] – TechIndicator[stock][‘Low’]
TechIndicator[stock][‘absHC’] = abs(TechIndicator[stock][‘High’] – TechIndicator[stock][‘Close’].shift(1))
TechIndicator[stock][‘absLC’] = abs(TechIndicator[stock][‘Low’] – TechIndicator[stock][‘Close’].shift(1))
TechIndicator[stock][‘TR’] = TechIndicator[stock][[‘HL’,’absHC’,’absLC’]].max(axis=1)
TechIndicator[stock][‘ATR’] = TechIndicator[stock][‘TR’].rolling(window=14).mean()
TechIndicator[stock][‘NATR’] = (TechIndicator[stock][‘ATR’] / TechIndicator[stock][‘Close’]) *100
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[5].tail()

Average Directional Movement Index (ADX)

The average directional index (ADX) helps traders see the trend direction as well as the strength of that trend. The Positive Directional Indicator (+DI) is one of the lines in the Average Directional Index (ADX) indicator and is used to measure the presence of an uptrend.

  • The ADX is now used in several markets by technical traders to judge the strength of a trend.
  • The ADX makes use of a positive (+DI) and negative (-DI) directional indicator in addition to the trendline.
  • The trend has strength when ADX is above 25; the trend is weak or the price is trendless when ADX is below 20, according to Wilder.
  • Non-trending doesn’t mean the price isn’t moving. It may not be, but the price could also be making a trend change or is too volatile for a clear direction to be present.

def DMI(df, period):
df[‘UpMove’] = df[‘High’] – df[‘High’].shift(1)
df[‘DownMove’] = df[‘Low’].shift(1) – df[‘Low’]
df[‘Zero’] = 0

df['PlusDM'] = np.where((df['UpMove'] > df['DownMove']) & (df['UpMove'] > df['Zero']), df['UpMove'], 0)
df['MinusDM'] = np.where((df['UpMove'] < df['DownMove']) & (df['DownMove'] > df['Zero']), df['DownMove'], 0)

df['plusDI'] = 100 * (df['PlusDM']/df['ATR']).ewm(span=period,min_periods=0,adjust=True,ignore_na=False).mean()
df['minusDI'] = 100 * (df['MinusDM']/df['ATR']).ewm(span=period,min_periods=0,adjust=True,ignore_na=False).mean()

df['ADX'] = 100 * (abs((df['plusDI'] - df['minusDI'])/(df['plusDI'] + df['minusDI']))).ewm(span=period,min_periods=0,adjust=True,ignore_na=False).mean()

for stock in range(len(TechIndicator)):
DMI(TechIndicator[stock], 14)
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[5].tail()

columns2Drop = [‘UpMove’, ‘DownMove’, ‘ATR’, ‘PlusDM’, ‘MinusDM’, ‘Zero’, ‘EMA’, ‘HL’, ‘absHC’, ‘absLC’, ‘TR’]
for stock in range(len(TechIndicator)):
TechIndicator[stock] = TechIndicator[stock].drop(labels = columns2Drop, axis=1)
TechIndicator[2].head()

MACD

  • The result of that calculation is the MACD line. A nine-day EMA of the MACD line is called the signal line, which is then plotted on top of the MACD line, which can function as a trigger for buy or sell signals.
  • Traders may buy the security when the MACD line crosses above the signal line and sell—or short—the security when the MACD line crosses below the signal line. MACD indicators can be interpreted in several ways, but the more common methods are crossoversdivergences, and rapid rises/falls.
  • MACD is best used with daily periods, where the traditional settings of 26/12/9 days is the norm.
  • MACD triggers technical signals when the MACD line crosses above the signal line (to buy) or falls below it (to sell).
  • MACD can help gauge whether a security is overbought or oversold, alerting traders to the strength of a directional move, and warning of a potential price reversal.
  • MACD can also alert investors to bullish/bearish divergences (e.g., when a new high in price is not confirmed by a new high in MACD, and vice versa), suggesting a potential failure and reversal.
  • After a signal line crossover, it is recommended to wait for three or four days to confirm that it is not a false move.

for stock in range(len(TechIndicator)):
TechIndicator[stock][’26_ema’] = TechIndicator[stock][‘Close’].ewm(span=26,min_periods=0,adjust=True,ignore_na=False).mean()
TechIndicator[stock][’12_ema’] = TechIndicator[stock][‘Close’].ewm(span=12,min_periods=0,adjust=True,ignore_na=False).mean()
TechIndicator[stock][‘MACD’] = TechIndicator[stock][’12_ema’] – TechIndicator[stock][’26_ema’]
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[2].tail()

Money Flow Index (MFI)

Money flow is calculated by averaging the high, low and closing prices, and multiplying by the daily volume. Comparing that result with the number for the previous day tells traders whether money flow was positive or negative for the current day. Positive money flow indicates that prices are likely to move higher, while negative money flow suggests prices are about to fall. 

Typical Price = (High + Low + Close)/3

Raw Money Flow = Typical Price x Volume

The money flow is divided into positive and negative money flow.

  • Positive money flow is calculated by adding the money flow of all the days where the typical price is higher than the previous day’s typical price.
  • Negative money flow is calculated by adding the money flow of all the days where the typical price is lower than the previous day’s typical price.
  • If typical price is unchanged then that day is discarded.
  • Money Flow Ratio = (14-period Positive Money Flow)/(14-period Negative Money Flow)
  • Money Flow Index = 100 – 100/(1 + Money Flow Ratio)

def MFI(df):
# typical price
df[‘tp’] = (df[‘High’]+df[‘Low’]+df[‘Close’])/3
#raw money flow
df[‘rmf’] = df[‘tp’] * df[‘Volume’]

# positive and negative money flow
df['pmf'] = np.where(df['tp'] > df['tp'].shift(1), df['tp'], 0)
df['nmf'] = np.where(df['tp'] < df['tp'].shift(1), df['tp'], 0)

# money flow ratio
df['mfr'] = df['pmf'].rolling(window=14,center=False).sum()/df['nmf'].rolling(window=14,center=False).sum()
df['Money_Flow_Index'] = 100 - 100 / (1 + df['mfr'])

for stock in range(len(TechIndicator)):
MFI(TechIndicator[stock])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[2].tail()

Ichimoku Cloud

  • The Ichimoku Cloud is a collection of technical indicators that show support and resistance levels, as well as momentum and trend direction. It does this by taking multiple averages and plotting them on a chart. It also uses these figures to compute a “cloud” that attempts to forecast where the price may find support or resistance in the future.
  • The Ichimoku Cloud is composed of five lines or calculations, two of which comprise a cloud where the difference between the two lines is shaded in.
  • The lines include a nine-period average, a 26-period average, an average of those two averages, a 52-period average, and a lagging closing price line.
  • The cloud is a key part of the indicator. When the price is below the cloud, the trend is down. When the price is above the cloud, the trend is up.
  • The above trend signals are strengthened if the cloud is moving in the same direction as the price. For example, during an uptrend, the top of the cloud is moving up, or during a downtrend, the bottom of the cloud is moving down.
  • Turning Line = ( Highest High + Lowest Low ) / 2, for the past 9 days
  • Standard Line = ( Highest High + Lowest Low ) / 2, for the past 26 days
  • Leading Span 1 = ( Standard Line + Turning Line ) / 2, plotted 26 days ahead of today
  • Leading Span 2 = ( Highest High + Lowest Low ) / 2, for the past 52 days, plotted 26 days ahead of today
  • Cloud = Shaded Area between Span 1 and Span 2

def ichimoku(df):
# Turning Line
period9_high = df[‘High’].rolling(window=9,center=False).max()
period9_low = df[‘Low’].rolling(window=9,center=False).min()
df[‘turning_line’] = (period9_high + period9_low) / 2

# Standard Line
period26_high = df['High'].rolling(window=26,center=False).max()
period26_low = df['Low'].rolling(window=26,center=False).min()
df['standard_line'] = (period26_high + period26_low) / 2

# Leading Span 1
df['ichimoku_span1'] = ((df['turning_line'] + df['standard_line']) / 2).shift(26)

# Leading Span 2
period52_high = df['High'].rolling(window=52,center=False).max()
period52_low = df['Low'].rolling(window=52,center=False).min()
df['ichimoku_span2'] = ((period52_high + period52_low) / 2).shift(26)

# The most current closing price plotted 22 time periods behind (optional)
df['chikou_span'] = df['Close'].shift(-22) # 22 according to investopedia

for stock in range(len(TechIndicator)):
ichimoku(TechIndicator[stock])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[2].tail()

William %R (WillR)

Williams %R, also known as the Williams Percent Range, is a type of momentum indicator that moves between 0 and -100 and measures overbought and oversold levels. The Williams %R may be used to find entry and exit points in the market. The indicator is very similar to the Stochastic oscillator and is used in the same way.

  • Williams %R moves between zero and -100.
  • A reading above -20 is overbought.
  • A reading below -80 is oversold.
  • An overbought or oversold reading doesn’t mean the price will reverse. Overbought simply means the price is near the highs of its recent range, and oversold means the price is in the lower end of its recent range.
  • Can be used to generate trade signals when the price and the indicator move out of overbought or oversold territory.
  • %R = -100 * ( ( Highest High – Close) / ( Highest High – Lowest Low ) )

def WillR(df):
highest_high = df[‘High’].rolling(window=14,center=False).max()
lowest_low = df[‘Low’].rolling(window=14,center=False).min()
df[‘WillR’] = (-100) * ((highest_high – df[‘Close’]) / (highest_high – lowest_low))

for stock in range(len(TechIndicator)):
WillR(TechIndicator[stock])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[2].tail()

MINMAX

def MINMAX(df):
df[‘MIN_Volume’] = df[‘Volume’].rolling(window=14,center=False).min()
df[‘MAX_Volume’] = df[‘Volume’].rolling(window=14,center=False).max()

for stock in range(len(TechIndicator)):
MINMAX(TechIndicator[stock])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[2].tail()

Adaptive Moving Average (KAMA)

Developed by Perry Kaufman, Kaufman’s Adaptive Moving Average (KAMA) is a moving average designed to account for market noise or volatility. KAMA will closely follow prices when the price swings are relatively small and the noise is low. KAMA will adjust when the price swings widen and follow prices from a greater distance. This trend-following indicator can be used to identify the overall trend, time turning points and filter price movements.

def KAMA(price, n=10, pow1=2, pow2=30):
”’ kama indicator ”’
”’ accepts pandas dataframe of prices ”’

absDiffx = abs(price - price.shift(1) )  

ER_num = abs( price - price.shift(n) )
ER_den = absDiffx.rolling(window=n,center=False).sum()
ER = ER_num / ER_den

sc = ( ER*(2.0/(pow1+1)-2.0/(pow2+1.0))+2/(pow2+1.0) ) ** 2.0


answer = np.zeros(sc.size)
N = len(answer)
first_value = True

for i in range(N):
    if sc[i] != sc[i]:
        answer[i] = np.nan
    else:
        if first_value:
            answer[i] = price[i]
            first_value = False
        else:
            answer[i] = answer[i-1] + sc[i] * (price[i] - answer[i-1])
return answer

for stock in range(len(TechIndicator)):
TechIndicator[stock][‘KAMA’] = KAMA(TechIndicator[stock][‘Close’])
TechIndicator[stock] = TechIndicator[stock].fillna(0)
TechIndicator[4].tail()

columns2Drop = [’26_ema’, ’12_ema’,’tp’,’rmf’,’pmf’,’nmf’,’mfr’]
for stock in range(len(TechIndicator)):
TechIndicator[stock] = TechIndicator[stock].drop(labels = columns2Drop, axis=1)
TechIndicator[2].head()

Visualization of Technical Indicators

%matplotlib inline
from matplotlib.dates import DateFormatter

Relative Strength Index

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
TechIndicator[i][‘mydate’]=pd.to_datetime(TechIndicator[i].index)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘RSI_14D’])
ax.set_title(str(TechIndicator[i][‘Label’][0]))
ax.set_xlabel(“Date”)
ax.set_ylabel(“Relative Strength Index”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizrsiplot.png’)

RSI plot

Volume Plain

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(8,1,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Volume_plain’], ‘b’)
ax.set_title(str(TechIndicator[i][‘Label’][0]))
ax.set_xlabel(“Date”)
ax.set_ylabel(“Volume”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizvolumeplain.png’)

Volume plain

Bollinger Bands

plt.style.use(‘fivethirtyeight’)

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.fill_between(TechIndicator[i][‘mydate’], TechIndicator[i][‘BB_Upper_Band’], TechIndicator[i][‘BB_Lower_Band’], color=’grey’, label=”Band Range”)
# Plot Adjust Closing Price and Moving Averages
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], color=’red’, lw=2, label=”Close”)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘BB_Middle_Band’], color=’black’, lw=2, label=”Middle Band”)
ax.set_title(“Bollinger Bands for ” + str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Prices”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizbollingerbands.png’)

Bollinger Bands

Aroon Oscillator

plt.style.use(‘seaborn-whitegrid’)
fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.fill(TechIndicator[i][‘mydate’], TechIndicator[i][‘Aroon_Oscillator’],’g’, alpha = 0.5, label = “Aroon Oscillator”)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], ‘r’, label=”Close”)
ax.set_title(“Aroon Oscillator for ” +str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Prices”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizaroonoscillator.png’)

Summary

Aroon Oscillator

Price Volume Trend

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(8,1,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘PVT’], ‘black’)
ax.set_title(“Price Volume Trend of ” +str(TechIndicator[i][‘Label’][0]))
ax.set_xlabel(“Date”)
ax.set_ylabel(“Price Volume trend”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizpricevolumetrend.png’)

Price Volume trend

Acceleration Band

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.fill_between(TechIndicator[i][‘mydate’], TechIndicator[i][‘AB_Upper_Band’], TechIndicator[i][‘AB_Lower_Band’], color=’grey’, label = “Band-Range”)
# Plot Adjust Closing Price and Moving Averages
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], color=’red’, lw=2, label = “Close”)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘AB_Middle_Band’], color=’black’, lw=2, label=”Middle_Band”)
ax.set_title(“Acceleration Bands for ” + str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Prices”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizaccelerationband.png’)

Acceleration Bands

Stochastic Oscillator

plt.style.use(‘seaborn-whitegrid’)
fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘STOK’], ‘blue’, label=”%K”)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘STOD’], ‘red’, label=”%D”)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], color=’black’, lw=2, label = “Close”)
ax.set_title(“Stochastic Oscillators of ” +str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Price”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizstochasticoscillator.png’)

Stochastic Oscillators

Chaikin Money Flow

import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(25,40))
outer = gridspec.GridSpec(4, 2, wspace=0.2, hspace=0.2)

for i in range(8):
inner = gridspec.GridSpecFromSubplotSpec(2, 1,
subplot_spec=outer[i], wspace=0.1, hspace=0.1)

for j in range(2):
    ax = plt.Subplot(fig, inner[j])
    if j==0:
        t = ax.fill(TechIndicator[i]['mydate'], TechIndicator[i]['Chaikin_MF'],'b', alpha = 0.5, label = "Chaikin MF")
        ax.set_title("Chaikin Money Flow for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("Money Flow")
    else:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['Close'], 'r', label="Close")
        t = ax.set_ylabel("Close")
    ax.legend()
    ax.set_xlabel("Date")

    fig.add_subplot(ax)

fig.tight_layout()
plt.savefig(‘vizchaikinmoneyflow.png’)

Chaikin Money Flow

Parabolic SAR, Rate of Change, Momentum and VWAP

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘psar’], ‘blue’, label=”PSAR”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘ROC’], ‘red’, label=”ROC”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Momentum’], ‘green’, label=”Momentum”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘VWAP’], ‘cyan’, label=”VWAP”, alpha = 0.5)
ax.set_title(“PSAR, ROC, Momentum and VWAP of ” +str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Price”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizpsar.png’)

Parabolic SAR, Rate of Change, Momentum and VWAP

Commodity Channel Index, Triple Exponential Moving Average On Balance Volume

fig = plt.figure(figsize=(25,80))
outer = gridspec.GridSpec(4, 2, wspace=0.2, hspace=0.2)

for i in range(8):
inner = gridspec.GridSpecFromSubplotSpec(3, 1,
subplot_spec=outer[i], wspace=0.3, hspace=0.3)

for j in range(3):
    ax = plt.Subplot(fig, inner[j])
    if j==0:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['CCI'], 'green', label="CCI")
        t = ax.set_title("CCI for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("Commodity Channel Index")
    elif j == 1:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['TEMA'], 'blue', label="TEMA")
        t = ax.set_title("TEMA for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("TripleExponentiaL MA")
    else:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['OBV'], 'red', label="OBV")
        t = ax.set_title("OBV for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("On Balance Volume")
    ax.legend()

    ax.set_xlabel("Date")

    fig.add_subplot(ax)

fig.tight_layout()
plt.savefig(‘vizccitema.png’)

CCI & TEMA for XOM & O
CCI & TEMA for MO
OBV for MO
CCI & TEMA for COST & SBUX
OBV for COST & SBUX
CCI & TEMA for AAPl & LMT
TEMA & OBV for AAPL & LMT

Normalized Average True Range (NATR)

plt.style.use(‘ggplot’)
fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘NATR’], ‘red’, label=”NATR”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], ‘cyan’, label=”Close”, alpha = 0.5)
ax.set_title(“NATR of ” +str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Price”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘viznatr.png’)

NATR

Keltner Channels

fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.fill_between(TechIndicator[i][‘mydate’], TechIndicator[i][‘Kelch_Upper’], TechIndicator[i][‘Kelch_Down’],
color=’blue’, label = “Band-Range”, alpha = 0.5)
# Plot Adjust Closing Price and Moving Averages
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], color=’red’, label = “Close”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Kelch_Middle’], color=’black’, label=”Middle_Band”, alpha = 0.5)
ax.set_title(“Keltner Channels for ” + str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Close Prices”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizkeltner.png’)

Keltner Channels

Average Directional Index

plt.style.use(‘seaborn-whitegrid’)
fig = plt.figure(figsize=(30,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘plusDI’], ‘green’, label=”+DI”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘minusDI’], ‘cyan’, label=”-DI”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘ADX’], ‘red’, label=”ADX”, alpha = 0.5)
ax.set_title(“Average Directional Index of ” +str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Price”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizadi.png’)

ADI

MACD vs KAMA

plt.style.use(‘seaborn-whitegrid’)
fig = plt.figure(figsize=(20,25))
for i in range(8):
ax = plt.subplot(4,2,i+1)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘MACD’], ‘green’, label=”MACD”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘KAMA’], ‘blue’, label=”AMA”, alpha = 0.5)
ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘Close’], ‘red’, label=”Close”, alpha = 0.5)
ax.set_title(“MACD and KAMA of ” +str(TechIndicator[i][‘Label’][0]))
ax.legend()
ax.set_xlabel(“Date”)
ax.set_ylabel(“Price”)
plt.xticks(rotation=30)
fig.tight_layout()
plt.savefig(‘vizmacdkama.png’)

MACD and KAMA

William %R, Money Flow

fig = plt.figure(figsize=(25,50))
outer = gridspec.GridSpec(4, 2, wspace=0.2, hspace=0.2)

for i in range(8):
inner = gridspec.GridSpecFromSubplotSpec(3, 1,
subplot_spec=outer[i], wspace=0.2, hspace=0.2)

for j in range(3):
    ax = plt.Subplot(fig, inner[j])
    if j==0:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['WillR'], 'green', label="William %R")
        t = ax.set_title("William %R for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("Will%R")
    elif j ==1:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['Money_Flow_Index'], 'red', label="Money Flow Index")

        t = ax.set_title("Money Flow Index for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("MFI")
    else:
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['Volume'], 'blue', label="Volume", alpha = 0.5)
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['MIN_Volume'], 'pink', label="MIN_Volume", alpha = 0.5)
        t = ax.plot(TechIndicator[i]['mydate'], TechIndicator[i]['MAX_Volume'], 'lightgreen', label="MAXVolume",  alpha = 0.5)
        t = ax.set_title("MINMAX Volume for " +str(TechIndicator[i]['Label'][0]))
        t = ax.set_ylabel("Volume")
    ax.legend()
    #ax.set_title("CCI, TEMA, OBV for " +str(techindi2[i]['Label'][0]))
    ax.set_xlabel("Date")

    fig.add_subplot(ax)

fig.tight_layout()
plt.savefig(‘vizwilr.png’)

William %R, Money Flow, and MINMAX for XO and O
William %R, Money Flow, and MINMAX for AZN and MO
William %R, Money Flow, and MINMAX for COST and SBUX
William %R, Money Flow, and MINMAX for AAPL and LMT.

Ichimoku Cloud

fig = plt.figure(figsize=(20,25)) for i in range(8): ax = plt.subplot(4,2,i+1) ax.fill_between(TechIndicator[i][‘mydate’], TechIndicator[i][‘ichimoku_span1’], TechIndicator[i][‘ichimoku_span2′], color=’blue’, label = “ichimoku cloud”, alpha = 0.5) # Plot Adjust Closing Price and Moving Averages ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘turning_line’], color=’red’, label = “Tenkan-sen”, alpha = 0.4) ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘standard_line’], color=’cyan’, label=”Kijun-sen”, alpha = 0.3) ax.plot(TechIndicator[i][‘mydate’], TechIndicator[i][‘chikou_span’], color=’green’, label=”Chikou-span”, alpha = 0.2) ax.set_title(“Ichimoku for ” + str(TechIndicator[i][‘Label’][0])) ax.legend() ax.set_xlabel(“Date”) ax.set_ylabel(“Prices”) plt.xticks(rotation=30) fig.tight_layout() plt.savefig(‘vizishimoku.png’)

Ichimoku Cloud

Summary

  • In general, technical indicators fit into five categories: trend, mean reversion, relative strength, volume, and momentum.
  • Leading indicators attempt to predict where the price is headed while lagging indicators offer a historical report of background conditions that resulted in the current price being where it is.
  • Most popular technical indicators include simple moving averages (SMAs), exponential moving averages (EMAs), bollinger bands, stochastics, and on-balance volume (OBV).
  • Seven of the best indicators for day trading are:
  • On-balance volume (OBV)
  • Accumulation/distribution line
  • Average directional index
  • Aroon oscillator
  • Moving average convergence divergence (MACD)
  • Relative strength index (RSI)
  • Stochastic oscillator

Bottom Line: The most experienced traders are those that have a strong understanding of technical stock indicators, which makes them better equipped to navigate complex and fast-paced financial markets. 

Internal Links

Continue Exploring

Infographic

MO stock price
Selected stocks' change of value
20 selected stocks
AAPL Aroon 25
Donchian channels for MO
Energy sector heatmap

Embed Socials


One-Time
Monthly
Yearly

Make a one-time donation

Make a monthly donation

Make a yearly donation

Choose an amount

$5.00
$15.00
$100.00
$5.00
$15.00
$100.00
$5.00
$15.00
$100.00

Or enter a custom amount

$

Your contribution is appreciated.

Your contribution is appreciated.

Your contribution is appreciated.

DonateDonate monthlyDonate yearly
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: