Files
pandas-ta/examples/PandasTA_Study_Examples.ipynb
T

218 KiB
Raw Blame History

Pandas TA (pandas_ta) Studies for Custom Technical Analysis

Topics

  • What is a Pandas TA Study?
    • Builtin Studies: AllStudy and CommonStudy
    • Creating Studies
  • Watchlist Class
    • Study Management and Execution
    • NOTE: The watchlist module is independent of Pandas TA. To easily use it, copy it from your local pandas_ta installation directory into your project directory.
  • Indicator Composition/Chaining for more Complex Studies
    • Comprehensive Example: MACD and RSI Momo with BBANDS and SMAs 50 & 200 and Cumulative Log Returns
In [1]:
%matplotlib inline
import datetime as dt

from tqdm import tqdm

import pandas as pd
import pandas_ta as ta
from alphaVantageAPI.alphavantage import AlphaVantage  # pip install alphaVantage-api

from watchlist import Watchlist # Is this failing? If so, copy it locally. See above.

print(f"\nPandas TA v{ta.version}\nTo install the Latest Version:\n$ pip install -U git+https://github.com/twopirllc/pandas-ta\n")
%pylab inline
Pandas TA v0.3.32b0
To install the Latest Version:
$ pip install -U git+https://github.com/twopirllc/pandas-ta

Populating the interactive namespace from numpy and matplotlib

What is a Pandas TA Study?

A Study is a simple way to name and group TA indicators. Technically, a Study is a simple Data Class to contain list of indicators and their parameters. Note: Study is experimental and subject to change. Pandas TA comes with two basic Studies: AllStudy and CommonStudy.

Study Requirements:

  • name: Some short memorable string. Note: Case-insensitive "All" is reserved.
  • ta: A list of dicts containing keyword arguments to identify the indicator and the indicator's arguments

Optional Requirements:

  • description: A more detailed description of what the Study tries to capture. Default: None
  • created: At datetime string of when it was created. Default: Automatically generated.

Things to note:

  • A Study will fail when consumed by Pandas TA if there is no {"kind": "indicator name"} attribute.

Builtin Examples

All

Default Values

In [2]:
AllStudy = ta.AllStudy
print("name =", AllStudy.name)
print("description =", AllStudy.description)
print("created =", AllStudy.created)
print("ta =", AllStudy.ta)
name = All
description = All the indicators with their default settings. Pandas TA default.
created = Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)
ta = None

Common

Default Values

In [3]:
CommonStudy = ta.CommonStudy
print("name =", CommonStudy.name)
print("description =", CommonStudy.description)
print("created =", CommonStudy.created)
print("ta =", CommonStudy.ta)
name = Common Price and Volume SMAs
description = Common Price SMAs: 10, 20, 50, 200 and Volume SMA: 20.
created = Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)
ta = [{'kind': 'sma', 'length': 10}, {'kind': 'sma', 'length': 20}, {'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}, {'kind': 'sma', 'close': 'volume', 'length': 20, 'prefix': 'VOL'}]
In [ ]:

Creating Studies

Studies require a name and an array of dicts containing the "kind" of indicator ("sma") and other potential parameters for ta.

Simple Study A

In [4]:
custom_a = ta.Study(name="A", ta=[{"kind": "sma", "length": 50}, {"kind": "sma", "length": 200}])
custom_a
Out [4]:
Study(name='A', ta=[{'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')

Simple Study B

In [5]:
custom_b = ta.Study(name="B", ta=[{"kind": "ema", "length": 8}, {"kind": "ema", "length": 21}, {"kind": "log_return", "cumulative": True}, {"kind": "rsi"}, {"kind": "supertrend"}])
custom_b
Out [5]:
Study(name='B', ta=[{'kind': 'ema', 'length': 8}, {'kind': 'ema', 'length': 21}, {'kind': 'log_return', 'cumulative': True}, {'kind': 'rsi'}, {'kind': 'supertrend'}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')

Bad Study. (Misspelled Indicator)

In [6]:
# Misspelled indicator, will fail later when ran with Pandas TA
custom_run_failure = ta.Study(name="Runtime Failure", ta=[{"kind": "peret_return"}])
custom_run_failure
Out [6]:
Study(name='Runtime Failure', ta=[{'kind': 'peret_return'}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [ ]:

Study Management and Execution with Watchlist

Initialize AlphaVantage Data Source

In [7]:
AV = AlphaVantage(
    api_key="YOUR API KEY", premium=False,
    output_size='full', clean=True,
    export_path=".", export=True
)
AV
Out [7]:
AlphaVantage(
  end_point:str = https://www.alphavantage.co/query,
  api_key:str = YOUR API KEY,
  export:bool = True,
  export_path:str = .,
  output_size:str = full,
  output:str = csv,
  datatype:str = json,
  clean:bool = True,
  proxy:dict = {}
)

Create Watchlist and set it's 'ds' to AlphaVantage

In [8]:
data_source = "av" # Default
data_source = "yahoo"
watch = Watchlist(["SPY", "IWM"], ds_name=data_source, timed=False)

Info about the Watchlist. Note, the default Study is "All"

In [9]:
watch
Out [9]:
Watch(name='Watch: SPY, IWM', ds_name='yahoo', tickers[2]='SPY, IWM', tf='D', study[5]='Common Price and Volume SMAs')

Help about Watchlist

In [10]:
help(Watchlist)
Help on class Watchlist in module watchlist:

class Watchlist(builtins.object)
 |  Watchlist(tickers: list, tf: str = None, name: str = None, study: pandas_ta.utils._study.Study = None, ds_name: str = 'av', **kwargs)
 |  
 |  # Watchlist Class (** This is subject to change! **)
 |  A simple Class to load/download financial market data and automatically
 |  apply Technical Analysis indicators with a Pandas TA Study.
 |  
 |  Default Study: pandas_ta.CommonStudy
 |  
 |  ## Package Support:
 |  ### Data Source (Default: AlphaVantage)
 |  - AlphaVantage (pip install alphaVantage-api).
 |  - Python Binance (pip install python-binance). # Future Support
 |  - Yahoo Finance (pip install yfinance). # Almost Supported
 |  
 |  # Technical Analysis:
 |  - Pandas TA (pip install pandas_ta)
 |  
 |  ## Required Arguments:
 |  - tickers: A list of strings containing tickers. Example: ["SPY", "AAPL"]
 |  
 |  Methods defined here:
 |  
 |  __init__(self, tickers: list, tf: str = None, name: str = None, study: pandas_ta.utils._study.Study = None, ds_name: str = 'av', **kwargs)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __repr__(self) -> str
 |      Return repr(self).
 |  
 |  indicators(self, *args, **kwargs) -> <built-in function any>
 |      Returns the list of indicators that are available with Pandas Ta.
 |  
 |  load(self, ticker: str = None, tf: str = None, index: str = 'date', drop: list = [], plot: bool = False, **kwargs) -> pandas.core.frame.DataFrame
 |      Loads or Downloads (if a local csv does not exist) the data from the
 |      Data Source. When successful, it returns a Data Frame for the requested
 |      ticker. If no tickers are given, it loads all the tickers.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  data
 |      When not None, it contains a dictionary of DataFrames keyed by ticker. data = {"SPY": pd.DataFrame, ...}
 |  
 |  name
 |      The name of the Watchlist. Default: "Watchlist: {Watchlist.tickers}".
 |  
 |  strategy
 |      Sets a valid Strategy. Default: pandas_ta.CommonStrategy
 |  
 |  study
 |      Sets a valid Study. Default: pandas_ta.CommonStudy
 |  
 |  tf
 |      Alias for timeframe. Default: 'D'
 |  
 |  tickers
 |      tickers
 |      
 |      If a string, it it converted to a list. Example: "AAPL" -> ["AAPL"]
 |          * Does not accept, comma seperated strings.
 |      If a list, checks if it is a list of strings.
 |  
 |  verbose
 |      Toggle the verbose property. Default: False

Default Study is "Common"

In [11]:
# No arguments loads all the tickers and applies the Study to each ticker.
# The result can be accessed with Watchlist's 'data' property which returns a 
# dictionary keyed by ticker and DataFrames as values 
watch.load(verbose=True)
[!] Loading All: SPY, IWM
[+] Downloading[yahoo]: SPY[D]
[+] Saving: /Users/kj/av_data/SPY_D.csv
[+] Study: Common Price and Volume SMAs
[i] Indicator arguments: {'timed': False, 'append': True}
[i] Multiprocessing 5 indicators with 7 chunks and 8/8 cpus.
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 66.43it/s]
[i] Total indicators: 5
[i] Columns added: 5
[i] Last Run: Sunday January 23, 2022, NYSE: 11:36:11, Local: 15:36:11 PST, Day 23/365 (6.00%)
[+] Downloading[yahoo]: IWM[D]
[+] Saving: /Users/kj/av_data/IWM_D.csv
[+] Study: Common Price and Volume SMAs
[i] Indicator arguments: {'timed': False, 'append': True}
[i] Multiprocessing 5 indicators with 7 chunks and 8/8 cpus.
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 62.67it/s]
[i] Total indicators: 5
[i] Columns added: 5
[i] Last Run: Sunday January 23, 2022, NYSE: 11:36:15, Local: 15:36:15 PST, Day 23/365 (6.00%)
In [12]:
", ".join([f"{t}: {d.shape}" for t,d in watch.data.items()])
Out [12]:
'SPY: (7299, 12), IWM: (5449, 12)'
In [13]:
watch.data["SPY"]
Out [13]:
open high low close volume dividends stock splits SMA_10 SMA_20 SMA_50 SMA_200 VOL_SMA_20
date
1993-01-29 25.645575 25.645575 25.517985 25.627348 1003200 0.0 0 NaN NaN NaN NaN NaN
1993-02-01 25.645562 25.809607 25.645562 25.809607 480500 0.0 0 NaN NaN NaN NaN NaN
1993-02-02 25.791391 25.882527 25.736710 25.864300 201300 0.0 0 NaN NaN NaN NaN NaN
1993-02-03 25.900745 26.155924 25.882517 26.137697 529400 0.0 0 NaN NaN NaN NaN NaN
1993-02-04 26.228839 26.301748 25.937205 26.247066 531500 0.0 0 NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ...
2022-01-14 461.190002 465.089996 459.899994 464.720001 95849600 0.0 0 469.319998 469.606500 465.989207 438.476059 78776895.0
2022-01-18 459.739990 459.959991 455.309998 456.489990 109709100 0.0 0 467.197998 469.437500 465.813499 438.746869 77486770.0
2022-01-19 458.130005 459.609985 451.459991 451.750000 109357600 0.0 0 464.617999 469.275999 465.510704 438.995167 77597910.0
2022-01-20 453.750000 458.739990 444.500000 446.750000 122379700 0.0 0 462.454999 468.460500 465.099938 439.216139 80226580.0
2022-01-21 445.559998 448.059998 437.950012 437.980011 201913500 0.0 0 459.459000 466.975000 464.544664 439.383706 87377745.0

7299 rows × 12 columns

In [ ]:
In [14]:
watch.load("SPY", plot=True, mas=True)
Out [14]:
[i] Loaded SPY[D]: SPY_D.csv
open high low close volume dividends stock splits SMA_10 SMA_20 SMA_50 SMA_200 VOL_SMA_20
date
1993-01-29 25.645575 25.645575 25.517985 25.627348 1003200 0.0 0 NaN NaN NaN NaN NaN
1993-02-01 25.645562 25.809607 25.645562 25.809607 480500 0.0 0 NaN NaN NaN NaN NaN
1993-02-02 25.791391 25.882527 25.736710 25.864300 201300 0.0 0 NaN NaN NaN NaN NaN
1993-02-03 25.900745 26.155924 25.882517 26.137697 529400 0.0 0 NaN NaN NaN NaN NaN
1993-02-04 26.228839 26.301748 25.937205 26.247066 531500 0.0 0 NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ...
2022-01-14 461.190002 465.089996 459.899994 464.720001 95849600 0.0 0 469.319998 469.606500 465.989207 438.476059 78776895.0
2022-01-18 459.739990 459.959991 455.309998 456.489990 109709100 0.0 0 467.197998 469.437500 465.813499 438.746869 77486770.0
2022-01-19 458.130005 459.609985 451.459991 451.750000 109357600 0.0 0 464.617999 469.275999 465.510704 438.995167 77597910.0
2022-01-20 453.750000 458.739990 444.500000 446.750000 122379700 0.0 0 462.454999 468.460500 465.099938 439.216139 80226580.0
2022-01-21 445.559998 448.059998 437.950012 437.980011 201913500 0.0 0 459.459000 466.975000 464.544664 439.383706 87377745.0

7299 rows × 12 columns

In [ ]:

Easy to swap Studies and run them

Running Simple Study A

In [15]:
# Load custom_a into Watchlist and verify
watch.study = custom_a
watch.study
Out [15]:
Study(name='A', ta=[{'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [16]:
watch.load("IWM")
Out [16]:
[i] Loaded IWM[D]: IWM_D.csv
open high low close volume dividends stock splits SMA_50 SMA_200
date
2000-05-26 34.332574 34.473957 34.167627 34.473957 74800 0.0 0.0 NaN NaN
2000-05-30 34.968787 35.746395 34.968787 35.746395 57600 0.0 0.0 NaN NaN
2000-05-31 35.864233 36.335510 35.864233 35.876015 36000 0.0 0.0 NaN NaN
2000-06-01 36.612390 36.688972 36.612390 36.688972 7000 0.0 0.0 NaN NaN
2000-06-02 38.350224 38.597645 38.350224 38.597645 29400 0.0 0.0 NaN NaN
... ... ... ... ... ... ... ... ... ...
2022-01-14 211.990005 214.399994 210.580002 214.309998 42004100 0.0 0.0 224.026839 222.766286
2022-01-18 212.199997 212.440002 207.529999 207.830002 49434400 0.0 0.0 223.426888 222.689057
2022-01-19 208.809998 209.460007 204.380005 204.449997 46209100 0.0 0.0 222.694334 222.598203
2022-01-20 205.380005 208.990005 200.330002 200.750000 50466000 0.0 0.0 221.872826 222.506812
2022-01-21 199.759995 203.020004 196.990005 196.990005 84702700 0.0 0.0 221.004233 222.387342

5449 rows × 9 columns

Running Simple Study B

In [17]:
# Load custom_b into Watchlist and verify
watch.study = custom_b
watch.study
Out [17]:
Study(name='B', ta=[{'kind': 'ema', 'length': 8}, {'kind': 'ema', 'length': 21}, {'kind': 'log_return', 'cumulative': True}, {'kind': 'rsi'}, {'kind': 'supertrend'}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [18]:
watch.load("IWM")
Out [18]:
[i] Loaded IWM[D]: IWM_D.csv
open high low close volume dividends stock splits EMA_8 EMA_21 CUMLOGRET_1 RSI_14 SUPERT_7_3.0 SUPERTd_7_3.0 SUPERTl_7_3.0 SUPERTs_7_3.0
date
2000-05-26 34.332574 34.473957 34.167627 34.473957 74800 0.0 0.0 NaN NaN 0.000000 NaN 0.000000 1 NaN NaN
2000-05-30 34.968787 35.746395 34.968787 35.746395 57600 0.0 0.0 NaN NaN 0.036245 NaN NaN 1 NaN NaN
2000-05-31 35.864233 36.335510 35.864233 35.876015 36000 0.0 0.0 NaN NaN 0.039865 NaN NaN 1 NaN NaN
2000-06-01 36.612390 36.688972 36.612390 36.688972 7000 0.0 0.0 NaN NaN 0.062272 NaN NaN 1 NaN NaN
2000-06-02 38.350224 38.597645 38.350224 38.597645 29400 0.0 0.0 NaN NaN 0.112987 NaN NaN 1 NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2022-01-14 211.990005 214.399994 210.580002 214.309998 42004100 0.0 0.0 216.510909 218.695431 1.827219 40.838119 226.149780 -1 NaN 226.149780
2022-01-18 212.199997 212.440002 207.529999 207.830002 49434400 0.0 0.0 214.581819 217.707665 1.796516 33.120092 224.599099 -1 NaN 224.599099
2022-01-19 208.809998 209.460007 204.380005 204.449997 46209100 0.0 0.0 212.330303 216.502422 1.780119 29.941457 221.623519 -1 NaN 221.623519
2022-01-20 205.380005 208.990005 200.330002 200.750000 50466000 0.0 0.0 209.756902 215.070384 1.761856 26.898184 220.974446 -1 NaN 220.974446
2022-01-21 199.759995 203.020004 196.990005 196.990005 84702700 0.0 0.0 206.919814 213.426713 1.742949 24.205683 216.573097 -1 NaN 216.573097

5449 rows × 15 columns

Running Bad Study. (Misspelled indicator)

In [19]:
# Load custom_run_failure into Watchlist and verify
watch.study = custom_run_failure
watch.study
Out [19]:
Study(name='Runtime Failure', ta=[{'kind': 'peret_return'}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [20]:
try:
    iwm = watch.load("IWM")
except AttributeError as error:
    print(f"[X] Oops! {error}")
[i] Loaded IWM[D]: IWM_D.csv
[X] Oops! 'AnalysisIndicators' object has no attribute 'peret_return'
In [ ]:

Indicator Composition/Chaining

  • When you need an indicator to depend on the value of a prior indicator
  • Utilitze prefix or suffix to help identify unique columns or avoid column name clashes.

Volume MAs and MA chains

In [21]:
# Set EMA's and SMA's 'close' to 'volume' to create Volume MAs, prefix 'volume' MAs with 'VOLUME' so easy to identify the column
# Take a price EMA and apply LINREG from EMA's output
volmas_price_ma_chain = [
    {"kind":"ema", "close": "volume", "length": 10, "prefix": "VOLUME"},
    {"kind":"sma", "close": "volume", "length": 20, "prefix": "VOLUME"},
    {"kind":"ema", "length": 5},
    {"kind":"linreg", "close": "EMA_5", "length": 8, "prefix": "EMA_5"},
]
vp_ma_chain_ta = ta.Study("Volume MAs and Price MA chain", volmas_price_ma_chain)
vp_ma_chain_ta
Out [21]:
Study(name='Volume MAs and Price MA chain', ta=[{'kind': 'ema', 'close': 'volume', 'length': 10, 'prefix': 'VOLUME'}, {'kind': 'sma', 'close': 'volume', 'length': 20, 'prefix': 'VOLUME'}, {'kind': 'ema', 'length': 5}, {'kind': 'linreg', 'close': 'EMA_5', 'length': 8, 'prefix': 'EMA_5'}], description='', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [22]:
# Update the Watchlist
watch.study = vp_ma_chain_ta
watch.study.name
Out [22]:
'Volume MAs and Price MA chain'
In [23]:
spy = watch.load("SPY")
spy
Out [23]:
[i] Loaded SPY[D]: SPY_D.csv
open high low close volume dividends stock splits VOLUME_EMA_10 VOLUME_SMA_20 EMA_5 EMA_5_LR_8
date
1993-01-29 25.645575 25.645575 25.517985 25.627348 1003200 0.0 0 NaN NaN NaN NaN
1993-02-01 25.645562 25.809607 25.645562 25.809607 480500 0.0 0 NaN NaN NaN NaN
1993-02-02 25.791391 25.882527 25.736710 25.864300 201300 0.0 0 NaN NaN NaN NaN
1993-02-03 25.900745 26.155924 25.882517 26.137697 529400 0.0 0 NaN NaN NaN NaN
1993-02-04 26.228839 26.301748 25.937205 26.247066 531500 0.0 0 NaN NaN 25.937204 NaN
... ... ... ... ... ... ... ... ... ... ... ...
2022-01-14 461.190002 465.089996 459.899994 464.720001 95849600 0.0 0 8.524857e+07 78776895.0 466.839058 466.795420
2022-01-18 459.739990 459.959991 455.309998 456.489990 109709100 0.0 0 8.969594e+07 77486770.0 463.389369 465.217500
2022-01-19 458.130005 459.609985 451.459991 451.750000 109357600 0.0 0 9.327079e+07 77597910.0 459.509579 462.402221
2022-01-20 453.750000 458.739990 444.500000 446.750000 122379700 0.0 0 9.856332e+07 80226580.0 455.256386 458.363146
2022-01-21 445.559998 448.059998 437.950012 437.980011 201913500 0.0 0 1.173543e+08 87377745.0 449.497594 452.779043

7299 rows × 11 columns

In [ ]:

MACD BBANDS

In [24]:
# MACD is the initial indicator that BBANDS depends on.
# Set BBANDS's 'close' to MACD's main signal, in this case 'MACD_12_26_9' and add a prefix (or suffix) so it's easier to identify
macd_bands_ta = [
    {"kind":"macd"},
    {"kind":"bbands", "close": "MACD_12_26_9", "length": 20, "ddof": 0, "prefix": "MACD"}
]
macd_bands_ta = ta.Study("MACD BBands", macd_bands_ta, f"BBANDS_{macd_bands_ta[1]['length']} applied to MACD")
macd_bands_ta
Out [24]:
Study(name='MACD BBands', ta=[{'kind': 'macd'}, {'kind': 'bbands', 'close': 'MACD_12_26_9', 'length': 20, 'ddof': 0, 'prefix': 'MACD'}], description='BBANDS_20 applied to MACD', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [25]:
# Update the Watchlist
watch.study = macd_bands_ta
watch.study.name
Out [25]:
'MACD BBands'
In [26]:
spy = watch.load("SPY")
spy
Out [26]:
[i] Loaded SPY[D]: SPY_D.csv
open high low close volume dividends stock splits MACD_12_26_9 MACDh_12_26_9 MACDs_12_26_9 MACD_BBL_20_2.0 MACD_BBM_20_2.0 MACD_BBU_20_2.0 MACD_BBB_20_2.0 MACD_BBP_20_2.0
date
1993-01-29 25.645575 25.645575 25.517985 25.627348 1003200 0.0 0 NaN NaN NaN NaN NaN NaN NaN NaN
1993-02-01 25.645562 25.809607 25.645562 25.809607 480500 0.0 0 NaN NaN NaN NaN NaN NaN NaN NaN
1993-02-02 25.791391 25.882527 25.736710 25.864300 201300 0.0 0 NaN NaN NaN NaN NaN NaN NaN NaN
1993-02-03 25.900745 26.155924 25.882517 26.137697 529400 0.0 0 NaN NaN NaN NaN NaN NaN NaN NaN
1993-02-04 26.228839 26.301748 25.937205 26.247066 531500 0.0 0 NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2022-01-14 461.190002 465.089996 459.899994 464.720001 95849600 0.0 0 0.667763 -1.252266 1.920029 -0.122515 2.439251 5.001017 210.045326 0.154245
2022-01-18 459.739990 459.959991 455.309998 456.489990 109709100 0.0 0 -0.342005 -1.809627 1.467622 -0.465015 2.346428 5.157870 239.635954 0.021877
2022-01-19 458.130005 459.609985 451.459991 451.750000 109357600 0.0 0 -1.507355 -2.379982 0.872627 -0.976476 2.234080 5.444636 287.416349 -0.082677
2022-01-20 453.750000 458.739990 444.500000 446.750000 122379700 0.0 0 -2.802061 -2.939750 0.137689 -1.794548 2.055545 5.905638 374.605587 -0.130843
2022-01-21 445.559998 448.059998 437.950012 437.980011 201913500 0.0 0 -4.484100 -3.697431 -0.786669 -3.011202 1.773740 6.558682 539.531303 -0.153910

7299 rows × 15 columns

In [ ]:

Comprehensive Study

MACD and RSI Momentum with BBANDS and SMAs and Cumulative Log Returns

In [27]:
momo_bands_sma_ta = [
    {"kind":"sma", "length": 50},
    {"kind":"sma", "length": 200},
    {"kind":"bbands", "length": 20, "ddof": 0},
    {"kind":"macd"},
    {"kind":"rsi"},
    {"kind":"log_return", "cumulative": True},
    {"kind":"sma", "close": "CUMLOGRET_1", "length": 5, "suffix": "CUMLOGRET"},
]
momo_bands_sma_Study = ta.Study(
    "Momo, Bands and SMAs and Cumulative Log Returns", # name
    momo_bands_sma_ta, # ta
    "MACD and RSI Momo with BBANDS and SMAs 50 & 200 and Cumulative Log Returns" # description
)
momo_bands_sma_Study
Out [27]:
Study(name='Momo, Bands and SMAs and Cumulative Log Returns', ta=[{'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}, {'kind': 'bbands', 'length': 20, 'ddof': 0}, {'kind': 'macd'}, {'kind': 'rsi'}, {'kind': 'log_return', 'cumulative': True}, {'kind': 'sma', 'close': 'CUMLOGRET_1', 'length': 5, 'suffix': 'CUMLOGRET'}], description='MACD and RSI Momo with BBANDS and SMAs 50 & 200 and Cumulative Log Returns', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [28]:
# Update the Watchlist
watch.study = momo_bands_sma_Study
watch.study.name
Out [28]:
'Momo, Bands and SMAs and Cumulative Log Returns'
In [29]:
spy = watch.load("SPY")
# Apply constants to the DataFrame for indicators
spy.ta.constants(True, [0, 30, 70])
spy.tail()
Out [29]:
[i] Loaded SPY[D]: SPY_D.csv
open high low close volume dividends stock splits SMA_50 SMA_200 BBL_20_2.0 ... BBP_20_2.0 MACD_12_26_9 MACDh_12_26_9 MACDs_12_26_9 RSI_14 CUMLOGRET_1 SMA_5_CUMLOGRET 0 30 70
date
2022-01-14 461.190002 465.089996 459.899994 464.720001 95849600 0.0 0 465.989207 438.476059 456.838988 ... 0.308635 0.667763 -1.252266 1.920029 46.269081 2.897775 2.902879 0 30 70
2022-01-18 459.739990 459.959991 455.309998 456.489990 109709100 0.0 0 465.813499 438.746869 456.082958 ... 0.015239 -0.342005 -1.809627 1.467622 38.451767 2.879907 2.898966 0 30 70
2022-01-19 458.130005 459.609985 451.459991 451.750000 109357600 0.0 0 465.510704 438.995167 455.169080 ... -0.121184 -1.507355 -2.379982 0.872627 34.804529 2.869469 2.891151 0 30 70
2022-01-20 453.750000 458.739990 444.500000 446.750000 122379700 0.0 0 465.099938 439.216139 451.428136 ... -0.137331 -2.802061 -2.939750 0.137689 31.419064 2.858339 2.880571 0 30 70
2022-01-21 445.559998 448.059998 437.950012 437.980011 201913500 0.0 0 464.544664 439.383706 445.365560 ... -0.170887 -4.484100 -3.697431 -0.786669 26.542270 2.838513 2.868801 0 30 70

5 rows × 23 columns

In [ ]:

Additional Study Options

The params keyword takes a tuple as a shorthand to the parameter arguments in order.

  • Note: If the indicator arguments change, so will results. Breaking Changes will always be posted on the README.

The col_numbers keyword takes a tuple specifying which column to return if the result is a DataFrame.

In [30]:
params_ta = [
    {"kind":"ema", "params": (10,)},
    # params sets MACD's keyword arguments: fast=9, slow=19, signal=10
    # and returning the 2nd column: histogram
    {"kind":"macd", "params": (9, 19, 10), "col_numbers": (1,)},
    # Selects the Lower and Upper Bands and renames them LB and UB, ignoring the MB
    {"kind":"bbands", "col_numbers": (0,2), "col_names": ("LB", "UB")},
    {"kind":"log_return", "params": (5, False)},
]
params_ta_Study = ta.Study(
    "EMA, MACD History, Outter BBands, Log Returns", # name
    params_ta, # ta
    "EMA, MACD History, BBands(LB, UB), and Log Returns Study" # description
)
params_ta_Study
Out [30]:
Study(name='EMA, MACD History, Outter BBands, Log Returns', ta=[{'kind': 'ema', 'params': (10,)}, {'kind': 'macd', 'params': (9, 19, 10), 'col_numbers': (1,)}, {'kind': 'bbands', 'col_numbers': (0, 2), 'col_names': ('LB', 'UB')}, {'kind': 'log_return', 'params': (5, False)}], description='EMA, MACD History, BBands(LB, UB), and Log Returns Study', created='Sunday January 23, 2022, NYSE: 11:36:06, Local: 15:36:06 PST, Day 23/365 (6.00%)')
In [31]:
# Update the Watchlist
watch.study = params_ta_Study
watch.study.name
Out [31]:
'EMA, MACD History, Outter BBands, Log Returns'
In [32]:
spy = watch.load("SPY")
spy.tail()
Out [32]:
[i] Loaded SPY[D]: SPY_D.csv
open high low close volume dividends stock splits EMA_10 MACDh_9_19_10 LB UB LOGRET_5
date
2022-01-14 461.190002 465.089996 459.899994 464.720001 95849600 0.0 0 468.286877 -1.449058 461.651753 472.560246 -0.002944
2022-01-18 459.739990 459.959991 455.309998 456.489990 109709100 0.0 0 466.141989 -2.102017 455.062217 475.541774 -0.019567
2022-01-19 458.130005 459.609985 451.459991 451.750000 109357600 0.0 0 463.525264 -2.742434 448.133262 475.270730 -0.039072
2022-01-20 453.750000 458.739990 444.500000 446.750000 122379700 0.0 0 460.475216 -3.343681 442.732223 470.963773 -0.052901
2022-01-21 445.559998 448.059998 437.950012 437.980011 201913500 0.0 0 456.385178 -4.177700 433.536305 469.539696 -0.058853
In [ ]:

Disclaimer

  • All investments involve risk, and the past performance of a security, industry, sector, market, financial product, trading Study, or individuals trading does not guarantee future results or returns. Investors are fully responsible for any investment decisions they make. Such decisions should be based solely on an evaluation of their financial circumstances, investment objectives, risk tolerance, and liquidity needs.

  • Any opinions, news, research, analyses, prices, or other information offered is provided as general market commentary, and does not constitute investment advice. I will not accept liability for any loss or damage, including without limitation any loss of profit, which may arise directly or indirectly from use of or reliance on such information.