Files
pandas-ta/examples/PandasTA_Strategy_Examples.ipynb
T

208 KiB
Raw Blame History

Pandas TA (pandas_ta) Strategies for Custom Technical Analysis

Topics

  • What is a Pandas TA Strategy?
    • Builtin Strategies: AllStrategy and CommonStrategy
    • Creating Strategies
  • Watchlist Class
    • Strategy 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 Strategies
    • Comprehensive Example: MACD and RSI Momo with BBANDS and SMAs 50 & 200 and Cumulative Log Returns
In [1]:
%matplotlib inline
import datetime as dt

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.2.64b0
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 Strategy?

A Strategy is a simple way to name and group your favorite TA indicators. Technically, a Strategy is a simple Data Class to contain list of indicators and their parameters. Note: Strategy is experimental and subject to change. Pandas TA comes with two basic Strategies: AllStrategy and CommonStrategy.

Strategy 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 Strategy tries to capture. Default: None
  • created: At datetime string of when it was created. Default: Automatically generated.

Things to note:

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

Builtin Examples

All

In [2]:
AllStrategy = ta.AllStrategy
print("name =", AllStrategy.name)
print("description =", AllStrategy.description)
print("created =", AllStrategy.created)
print("ta =", AllStrategy.ta)
name = All
description = All the indicators with their default settings. Pandas TA default.
created = Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)
ta = None

Common

In [3]:
CommonStrategy = ta.CommonStrategy
print("name =", CommonStrategy.name)
print("description =", CommonStrategy.description)
print("created =", CommonStrategy.created)
print("ta =", CommonStrategy.ta)
name = Common Price and Volume SMAs
description = Common Price SMAs: 10, 20, 50, 200 and Volume SMA: 20.
created = Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)
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 Strategies

Simple Strategy A

In [4]:
custom_a = ta.Strategy(name="A", ta=[{"kind": "sma", "length": 50}, {"kind": "sma", "length": 200}])
custom_a
Out [4]:
Strategy(name='A', ta=[{'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}], description='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')

Simple Strategy B

In [5]:
custom_b = ta.Strategy(name="B", ta=[{"kind": "ema", "length": 8}, {"kind": "ema", "length": 21}, {"kind": "log_return", "cumulative": True}, {"kind": "rsi"}, {"kind": "supertrend"}])
custom_b
Out [5]:
Strategy(name='B', ta=[{'kind': 'ema', 'length': 8}, {'kind': 'ema', 'length': 21}, {'kind': 'log_return', 'cumulative': True}, {'kind': 'rsi'}, {'kind': 'supertrend'}], description='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')

Bad Strategy. (Misspelled Indicator)

In [6]:
# Misspelled indicator, will fail later when ran with Pandas TA
custom_run_failure = ta.Strategy(name="Runtime Failure", ta=[{"kind": "percet_return"}])
custom_run_failure
Out [6]:
Strategy(name='Runtime Failure', ta=[{'kind': 'percet_return'}], description='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [ ]:

Strategy 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 Strategy is "All"

In [9]:
watch
Out [9]:
Watch(name='Watch: SPY, IWM', ds_name='av', tickers[2]='SPY, IWM', tf='D', strategy[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, strategy: pandas_ta.core.Strategy = 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 Strategy.
 |  
 |  Default Strategy: pandas_ta.CommonStrategy
 |  
 |  ## 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, strategy: pandas_ta.core.Strategy = 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
 |  
 |  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 Strategy is "Common"

In [11]:
# No arguments loads all the tickers and applies the Strategy 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[av]: SPY[D]
[+] Strategy: Common Price and Volume SMAs
[i] Indicator arguments: {'timed': False, 'append': True}
[i] Multiprocessing 5 indicators with 7 chunks and 8/8 cpus.
[i] Total indicators: 5
[i] Columns added: 5
[i] Last Run: Saturday April 10, 2021, NYSE: 5:39:04, Local: 9:39:04 PDT, Day 100/365 (27.0%)
[+] Downloading[av]: IWM[D]
[+] Strategy: Common Price and Volume SMAs
[i] Indicator arguments: {'timed': False, 'append': True}
[i] Multiprocessing 5 indicators with 7 chunks and 8/8 cpus.
[i] Total indicators: 5
[i] Columns added: 5
[i] Last Run: Saturday April 10, 2021, NYSE: 5:39:21, Local: 9:39:21 PDT, Day 100/365 (27.0%)
In [12]:
watch.data
Out [12]:
{'SPY':                 open      high       low     close      volume   SMA_10  \
 date                                                                      
 1999-11-01  136.5000  137.0000  135.5625  135.5625   4006500.0      NaN   
 1999-11-02  135.9687  137.2500  134.5937  134.5937   6516900.0      NaN   
 1999-11-03  136.0000  136.3750  135.1250  135.5000   7222300.0      NaN   
 1999-11-04  136.7500  137.3593  135.7656  136.5312   7907500.0      NaN   
 1999-11-05  138.6250  139.1093  136.7812  137.8750   7431500.0      NaN   
 ...              ...       ...       ...       ...         ...      ...   
 2021-04-05  403.4600  406.9400  403.3800  406.3600  91684764.0  394.910   
 2021-04-06  405.7600  407.2400  405.4000  406.1200  62020953.0  396.263   
 2021-04-07  405.9400  406.9600  405.4500  406.5900  55836280.0  397.972   
 2021-04-08  407.9300  408.5800  406.9300  408.5200  57863114.0  400.072   
 2021-04-09  408.3900  411.6700  408.2600  411.4900  61104559.0  402.251   
 
              SMA_20    SMA_50    SMA_200   VOL_SMA_20  
 date                                                   
 1999-11-01      NaN       NaN        NaN          NaN  
 1999-11-02      NaN       NaN        NaN          NaN  
 1999-11-03      NaN       NaN        NaN          NaN  
 1999-11-04      NaN       NaN        NaN          NaN  
 1999-11-05      NaN       NaN        NaN          NaN  
 ...             ...       ...        ...          ...  
 2021-04-05  393.285  388.3778  355.07135  97644589.35  
 2021-04-06  394.505  388.8426  355.54305  94588174.75  
 2021-04-07  395.476  389.2866  356.03280  91698310.95  
 2021-04-08  396.423  389.7812  356.52230  89096496.15  
 2021-04-09  397.321  390.5228  357.01950  87839472.10  
 
 [5394 rows x 10 columns],
 'IWM':               open     high     low   close      volume   SMA_10    SMA_20  \
 date                                                                         
 2000-05-26   91.06   91.440   90.63   91.44     37400.0      NaN       NaN   
 2000-05-30   92.75   94.810   92.75   94.81     28800.0      NaN       NaN   
 2000-05-31   95.13   96.380   95.13   95.75     18000.0      NaN       NaN   
 2000-06-01   97.11   97.310   97.11   97.31      3500.0      NaN       NaN   
 2000-06-02  101.70  102.400  101.70  102.40     14700.0      NaN       NaN   
 ...            ...      ...     ...     ...         ...      ...       ...   
 2021-04-05  226.40  226.535  223.57  224.97  27826550.0  219.366  223.9090   
 2021-04-06  225.00  226.690  223.84  224.31  24907760.0  219.274  224.1875   
 2021-04-07  224.23  224.370  219.94  220.69  26233700.0  219.637  224.0550   
 2021-04-08  221.84  222.820  219.39  222.56  23989440.0  220.689  223.8220   
 2021-04-09  222.49  223.090  221.24  222.59  23267373.0  221.282  223.3405   
 
               SMA_50    SMA_200   VOL_SMA_20  
 date                                          
 2000-05-26       NaN        NaN          NaN  
 2000-05-30       NaN        NaN          NaN  
 2000-05-31       NaN        NaN          NaN  
 2000-06-01       NaN        NaN          NaN  
 2000-06-02       NaN        NaN          NaN  
 ...              ...        ...          ...  
 2021-04-05  221.2644  179.31385  34417859.25  
 2021-04-06  221.4506  179.72680  33632261.05  
 2021-04-07  221.5686  180.12530  33331582.25  
 2021-04-08  221.7538  180.52610  32690454.25  
 2021-04-09  222.0178  180.92405  32590989.45  
 
 [5250 rows x 10 columns]}
In [13]:
watch.data["SPY"]
Out [13]:
open high low close volume SMA_10 SMA_20 SMA_50 SMA_200 VOL_SMA_20
date
1999-11-01 136.5000 137.0000 135.5625 135.5625 4006500.0 NaN NaN NaN NaN NaN
1999-11-02 135.9687 137.2500 134.5937 134.5937 6516900.0 NaN NaN NaN NaN NaN
1999-11-03 136.0000 136.3750 135.1250 135.5000 7222300.0 NaN NaN NaN NaN NaN
1999-11-04 136.7500 137.3593 135.7656 136.5312 7907500.0 NaN NaN NaN NaN NaN
1999-11-05 138.6250 139.1093 136.7812 137.8750 7431500.0 NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ...
2021-04-05 403.4600 406.9400 403.3800 406.3600 91684764.0 394.910 393.285 388.3778 355.07135 97644589.35
2021-04-06 405.7600 407.2400 405.4000 406.1200 62020953.0 396.263 394.505 388.8426 355.54305 94588174.75
2021-04-07 405.9400 406.9600 405.4500 406.5900 55836280.0 397.972 395.476 389.2866 356.03280 91698310.95
2021-04-08 407.9300 408.5800 406.9300 408.5200 57863114.0 400.072 396.423 389.7812 356.52230 89096496.15
2021-04-09 408.3900 411.6700 408.2600 411.4900 61104559.0 402.251 397.321 390.5228 357.01950 87839472.10

5394 rows × 10 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 SMA_10 SMA_20 SMA_50 SMA_200 VOL_SMA_20
date
1999-11-01 136.5000 137.0000 135.5625 135.5625 4006500.0 NaN NaN NaN NaN NaN
1999-11-02 135.9687 137.2500 134.5937 134.5937 6516900.0 NaN NaN NaN NaN NaN
1999-11-03 136.0000 136.3750 135.1250 135.5000 7222300.0 NaN NaN NaN NaN NaN
1999-11-04 136.7500 137.3593 135.7656 136.5312 7907500.0 NaN NaN NaN NaN NaN
1999-11-05 138.6250 139.1093 136.7812 137.8750 7431500.0 NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ...
2021-04-05 403.4600 406.9400 403.3800 406.3600 91684764.0 394.910 393.285 388.3778 355.07135 97644589.35
2021-04-06 405.7600 407.2400 405.4000 406.1200 62020953.0 396.263 394.505 388.8426 355.54305 94588174.75
2021-04-07 405.9400 406.9600 405.4500 406.5900 55836280.0 397.972 395.476 389.2866 356.03280 91698310.95
2021-04-08 407.9300 408.5800 406.9300 408.5200 57863114.0 400.072 396.423 389.7812 356.52230 89096496.15
2021-04-09 408.3900 411.6700 408.2600 411.4900 61104559.0 402.251 397.321 390.5228 357.01950 87839472.10

5394 rows × 10 columns

In [ ]:

Easy to swap Strategies and run them

Running Simple Strategy A

In [15]:
# Load custom_a into Watchlist and verify
watch.strategy = custom_a
# watch.debug = True
watch.strategy
Out [15]:
Strategy(name='A', ta=[{'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}], description='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [16]:
watch.load("IWM")
Out [16]:
[i] Loaded IWM[D]: IWM_D.csv
open high low close volume SMA_50 SMA_200
date
2000-05-26 91.06 91.440 90.63 91.44 37400.0 NaN NaN
2000-05-30 92.75 94.810 92.75 94.81 28800.0 NaN NaN
2000-05-31 95.13 96.380 95.13 95.75 18000.0 NaN NaN
2000-06-01 97.11 97.310 97.11 97.31 3500.0 NaN NaN
2000-06-02 101.70 102.400 101.70 102.40 14700.0 NaN NaN
... ... ... ... ... ... ... ...
2021-04-05 226.40 226.535 223.57 224.97 27826550.0 221.2644 179.31385
2021-04-06 225.00 226.690 223.84 224.31 24907760.0 221.4506 179.72680
2021-04-07 224.23 224.370 219.94 220.69 26233700.0 221.5686 180.12530
2021-04-08 221.84 222.820 219.39 222.56 23989440.0 221.7538 180.52610
2021-04-09 222.49 223.090 221.24 222.59 23267373.0 222.0178 180.92405

5250 rows × 7 columns

Running Simple Strategy B

In [17]:
# Load custom_b into Watchlist and verify
watch.strategy = custom_b
watch.strategy
Out [17]:
Strategy(name='B', ta=[{'kind': 'ema', 'length': 8}, {'kind': 'ema', 'length': 21}, {'kind': 'log_return', 'cumulative': True}, {'kind': 'rsi'}, {'kind': 'supertrend'}], description='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [18]:
watch.load("SPY")
Out [18]:
[i] Loaded SPY[D]: SPY_D.csv
open high low close volume 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
1999-11-01 136.5000 137.0000 135.5625 135.5625 4006500.0 NaN NaN NaN NaN 0.000000 1 NaN NaN
1999-11-02 135.9687 137.2500 134.5937 134.5937 6516900.0 NaN NaN -0.007172 NaN NaN 1 NaN NaN
1999-11-03 136.0000 136.3750 135.1250 135.5000 7222300.0 NaN NaN -0.000461 NaN NaN 1 NaN NaN
1999-11-04 136.7500 137.3593 135.7656 136.5312 7907500.0 NaN NaN 0.007120 NaN NaN 1 NaN NaN
1999-11-05 138.6250 139.1093 136.7812 137.8750 7431500.0 NaN NaN 0.016915 NaN NaN 1 NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2021-04-05 403.4600 406.9400 403.3800 406.3600 91684764.0 397.751097 393.567248 1.097807 67.670567 390.310373 1 390.310373 NaN
2021-04-06 405.7600 407.2400 405.4000 406.1200 62020953.0 399.610853 394.708407 1.097216 67.264341 392.803177 1 392.803177 NaN
2021-04-07 405.9400 406.9600 405.4500 406.5900 55836280.0 401.161775 395.788552 1.098373 67.673599 393.972009 1 393.972009 NaN
2021-04-08 407.9300 408.5800 406.9300 408.5200 57863114.0 402.796936 396.945956 1.103108 69.367185 396.416722 1 396.416722 NaN
2021-04-09 408.3900 411.6700 408.2600 411.4900 61104559.0 404.728728 398.268142 1.110352 71.814343 398.785047 1 398.785047 NaN

5394 rows × 13 columns

Running Bad Strategy. (Misspelled indicator)

In [19]:
# Load custom_run_failure into Watchlist and verify
watch.strategy = custom_run_failure
watch.strategy
Out [19]:
Strategy(name='Runtime Failure', ta=[{'kind': 'percet_return'}], description='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
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 'percet_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.Strategy("Volume MAs and Price MA chain", volmas_price_ma_chain)
vp_ma_chain_ta
Out [21]:
Strategy(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='TA Description', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [22]:
# Update the Watchlist
watch.strategy = vp_ma_chain_ta
watch.strategy.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 VOLUME_EMA_10 VOLUME_SMA_20 EMA_5 EMA_5_LR_8
date
1999-11-01 136.5000 137.0000 135.5625 135.5625 4006500.0 NaN NaN NaN NaN
1999-11-02 135.9687 137.2500 134.5937 134.5937 6516900.0 NaN NaN NaN NaN
1999-11-03 136.0000 136.3750 135.1250 135.5000 7222300.0 NaN NaN NaN NaN
1999-11-04 136.7500 137.3593 135.7656 136.5312 7907500.0 NaN NaN NaN NaN
1999-11-05 138.6250 139.1093 136.7812 137.8750 7431500.0 NaN NaN 136.012480 NaN
... ... ... ... ... ... ... ... ... ...
2021-04-05 403.4600 406.9400 403.3800 406.3600 91684764.0 9.904359e+07 97644589.35 399.857343 397.030535
2021-04-06 405.7600 407.2400 405.4000 406.1200 62020953.0 9.231221e+07 94588174.75 401.944895 399.235555
2021-04-07 405.9400 406.9600 405.4500 406.5900 55836280.0 8.568022e+07 91698310.95 403.493264 401.232830
2021-04-08 407.9300 408.5800 406.9300 408.5200 57863114.0 8.062256e+07 89096496.15 405.168842 403.269982
2021-04-09 408.3900 411.6700 408.2600 411.4900 61104559.0 7.707384e+07 87839472.10 407.275895 405.405385

5394 rows × 9 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, "prefix": "MACD"}
]
macd_bands_ta = ta.Strategy("MACD BBands", macd_bands_ta, f"BBANDS_{macd_bands_ta[1]['length']} applied to MACD")
macd_bands_ta
Out [24]:
Strategy(name='MACD BBands', ta=[{'kind': 'macd'}, {'kind': 'bbands', 'close': 'MACD_12_26_9', 'length': 20, 'prefix': 'MACD'}], description='BBANDS_20 applied to MACD', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [25]:
# Update the Watchlist
watch.strategy = macd_bands_ta
watch.strategy.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 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
date
1999-11-01 136.5000 137.0000 135.5625 135.5625 4006500.0 NaN NaN NaN NaN NaN NaN NaN
1999-11-02 135.9687 137.2500 134.5937 134.5937 6516900.0 NaN NaN NaN NaN NaN NaN NaN
1999-11-03 136.0000 136.3750 135.1250 135.5000 7222300.0 NaN NaN NaN NaN NaN NaN NaN
1999-11-04 136.7500 137.3593 135.7656 136.5312 7907500.0 NaN NaN NaN NaN NaN NaN NaN
1999-11-05 138.6250 139.1093 136.7812 137.8750 7431500.0 NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ...
2021-04-05 403.4600 406.9400 403.3800 406.3600 91684764.0 3.496649 1.051942 2.444707 0.173035 1.949555 3.726075 182.248798
2021-04-06 405.7600 407.2400 405.4000 406.1200 62020953.0 4.043917 1.279368 2.764549 0.396500 2.153128 3.909756 163.169877
2021-04-07 405.9400 406.9600 405.4500 406.5900 55836280.0 4.464097 1.359638 3.104459 0.570354 2.365544 4.160734 151.778160
2021-04-08 407.9300 408.5800 406.9300 408.5200 57863114.0 4.896384 1.433541 3.462844 0.658913 2.580554 4.502194 148.932443
2021-04-09 408.3900 411.6700 408.2600 411.4900 61104559.0 5.416195 1.562681 3.853514 0.613266 2.791236 4.969206 156.057773

5394 rows × 12 columns

In [ ]:

Comprehensive Strategy

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},
    {"kind":"macd"},
    {"kind":"rsi"},
    {"kind":"log_return", "cumulative": True},
    {"kind":"sma", "close": "CUMLOGRET_1", "length": 5, "suffix": "CUMLOGRET"},
]
momo_bands_sma_strategy = ta.Strategy(
    "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_strategy
Out [27]:
Strategy(name='Momo, Bands and SMAs and Cumulative Log Returns', ta=[{'kind': 'sma', 'length': 50}, {'kind': 'sma', 'length': 200}, {'kind': 'bbands', 'length': 20}, {'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='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [28]:
# Update the Watchlist
watch.strategy = momo_bands_sma_strategy
watch.strategy.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 SMA_50 SMA_200 BBL_20_2.0 BBM_20_2.0 BBU_20_2.0 BBB_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
2021-04-05 403.46 406.94 403.38 406.36 91684764.0 388.3778 355.07135 382.834363 393.285 403.735637 5.314536 3.496649 1.051942 2.444707 67.670567 1.097807 1.078874 0 30 70
2021-04-06 405.76 407.24 405.40 406.12 62020953.0 388.8426 355.54305 384.042695 394.505 404.967305 5.304016 4.043917 1.279368 2.764549 67.264341 1.097216 1.084032 0 30 70
2021-04-07 405.94 406.96 405.45 406.59 55836280.0 389.2866 356.03280 384.334301 395.476 406.617699 5.634577 4.464097 1.359638 3.104459 67.673599 1.098373 1.089953 0 30 70
2021-04-08 407.93 408.58 406.93 408.52 57863114.0 389.7812 356.52230 384.272821 396.423 408.573179 6.129906 4.896384 1.433541 3.462844 69.367185 1.103108 1.096012 0 30 70
2021-04-09 408.39 411.67 408.26 411.49 61104559.0 390.5228 357.01950 383.604942 397.321 411.037058 6.904270 5.416195 1.562681 3.853514 71.814343 1.110352 1.101371 0 30 70
In [ ]:

Additional Strategy 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_strategy = ta.Strategy(
    "EMA, MACD History, Outter BBands, Log Returns", # name
    params_ta, # ta
    "EMA, MACD History, BBands(LB, UB), and Log Returns Strategy" # description
)
params_ta_strategy
Out [30]:
Strategy(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 Strategy', created='Saturday April 10, 2021, NYSE: 5:39:01, Local: 9:39:01 PDT, Day 100/365 (27.0%)')
In [31]:
# Update the Watchlist
watch.strategy = params_ta_strategy
watch.strategy.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 EMA_10 MACDh_9_19_10 LB UB LOGRET_5
date
2021-04-05 403.46 406.94 403.38 406.36 91684764.0 396.789148 1.302704 390.173232 407.350768 0.025876
2021-04-06 405.76 407.24 405.40 406.12 62020953.0 398.485666 1.529192 391.193677 410.466323 0.025790
2021-04-07 405.94 406.96 405.45 406.59 55836280.0 399.959181 1.561328 395.008877 411.395123 0.029603
2021-04-08 407.93 408.58 406.93 408.52 57863114.0 401.515694 1.590588 400.329889 410.950111 0.030294
2021-04-09 408.39 411.67 408.26 411.49 61104559.0 403.329204 1.695492 403.766969 411.865031 0.026796
In [ ]:

Disclaimer

  • All investments involve risk, and the past performance of a security, industry, sector, market, financial product, trading strategy, 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.