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.49b0
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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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 over 8/8 cpus.
[i] Total indicators: 5
[i] Columns added: 5
[i] Last Run: Saturday March 20, 2021, NYSE: 13:13:13, Local: 17:13:13 PDT, Day 79/365 (22.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 over 8/8 cpus.
[i] Total indicators: 5
[i] Columns added: 5
[i] Last Run: Saturday March 20, 2021, NYSE: 13:13:30, Local: 17:13:30 PDT, Day 79/365 (22.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-03-15  394.3300  396.6850  392.0300  396.4100   73592302.0  387.076   
 2021-03-16  397.0700  397.8300  395.0800  395.9100   73722506.0  388.013   
 2021-03-17  394.5300  398.1200  393.3000  397.2600   97959265.0  389.597   
 2021-03-18  394.4750  396.7200  390.7500  391.4800  115349101.0  391.075   
 2021-03-19  389.8800  391.5690  387.1500  389.4800  113624490.0  391.660   
 
               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-03-15  387.7385  383.6352  349.25675  9.988408e+07  
 2021-03-16  387.9190  384.0758  349.71470  1.010216e+08  
 2021-03-17  388.1625  384.6452  350.17325  1.033322e+08  
 2021-03-18  388.2005  385.0482  350.59025  1.061140e+08  
 2021-03-19  388.1730  385.3668  350.97675  1.076332e+08  
 
 [5380 rows x 10 columns],
 'IWM':               open    high     low   close      volume   SMA_10    SMA_20  \
 date                                                                        
 2000-05-26   91.06   91.44   90.63   91.44     37400.0      NaN       NaN   
 2000-05-30   92.75   94.81   92.75   94.81     28800.0      NaN       NaN   
 2000-05-31   95.13   96.38   95.13   95.75     18000.0      NaN       NaN   
 2000-06-01   97.11   97.31   97.11   97.31      3500.0      NaN       NaN   
 2000-06-02  101.70  102.40  101.70  102.40     14700.0      NaN       NaN   
 ...            ...     ...     ...     ...         ...      ...       ...   
 2021-03-15  233.34  234.53  231.91  234.42  21543170.0  224.147  223.6310   
 2021-03-16  234.02  234.09  229.12  230.50  24675008.0  225.025  223.8645   
 2021-03-17  228.97  232.82  227.36  232.31  29422584.0  226.324  224.2770   
 2021-03-18  230.80  232.93  224.61  225.24  35726301.0  227.529  224.5095   
 2021-03-19  224.57  228.60  222.95  226.94  40855626.0  228.452  224.5970   
 
               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-03-15  217.0930  173.82090  33326068.35  
 2021-03-16  217.7818  174.27890  33409843.35  
 2021-03-17  218.5580  174.73930  33633447.20  
 2021-03-18  219.1330  175.15855  34194686.80  
 2021-03-19  219.5812  175.56925  34675560.35  
 
 [5236 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-03-15 394.3300 396.6850 392.0300 396.4100 73592302.0 387.076 387.7385 383.6352 349.25675 9.988408e+07
2021-03-16 397.0700 397.8300 395.0800 395.9100 73722506.0 388.013 387.9190 384.0758 349.71470 1.010216e+08
2021-03-17 394.5300 398.1200 393.3000 397.2600 97959265.0 389.597 388.1625 384.6452 350.17325 1.033322e+08
2021-03-18 394.4750 396.7200 390.7500 391.4800 115349101.0 391.075 388.2005 385.0482 350.59025 1.061140e+08
2021-03-19 389.8800 391.5690 387.1500 389.4800 113624490.0 391.660 388.1730 385.3668 350.97675 1.076332e+08

5380 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-03-15 394.3300 396.6850 392.0300 396.4100 73592302.0 387.076 387.7385 383.6352 349.25675 9.988408e+07
2021-03-16 397.0700 397.8300 395.0800 395.9100 73722506.0 388.013 387.9190 384.0758 349.71470 1.010216e+08
2021-03-17 394.5300 398.1200 393.3000 397.2600 97959265.0 389.597 388.1625 384.6452 350.17325 1.033322e+08
2021-03-18 394.4750 396.7200 390.7500 391.4800 115349101.0 391.075 388.2005 385.0482 350.59025 1.061140e+08
2021-03-19 389.8800 391.5690 387.1500 389.4800 113624490.0 391.660 388.1730 385.3668 350.97675 1.076332e+08

5380 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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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.44 90.63 91.44 37400.0 NaN NaN
2000-05-30 92.75 94.81 92.75 94.81 28800.0 NaN NaN
2000-05-31 95.13 96.38 95.13 95.75 18000.0 NaN NaN
2000-06-01 97.11 97.31 97.11 97.31 3500.0 NaN NaN
2000-06-02 101.70 102.40 101.70 102.40 14700.0 NaN NaN
... ... ... ... ... ... ... ...
2021-03-15 233.34 234.53 231.91 234.42 21543170.0 217.0930 173.82090
2021-03-16 234.02 234.09 229.12 230.50 24675008.0 217.7818 174.27890
2021-03-17 228.97 232.82 227.36 232.31 29422584.0 218.5580 174.73930
2021-03-18 230.80 232.93 224.61 225.24 35726301.0 219.1330 175.15855
2021-03-19 224.57 228.60 222.95 226.94 40855626.0 219.5812 175.56925

5236 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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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-03-15 394.3300 396.6850 392.0300 396.4100 73592302.0 390.405499 387.590872 1.073016 61.444065 398.910421 -1 NaN 398.910421
2021-03-16 397.0700 397.8300 395.0800 395.9100 73722506.0 391.628722 388.347156 1.071754 60.730184 398.910421 -1 NaN 398.910421
2021-03-17 394.5300 398.1200 393.3000 397.2600 97959265.0 392.880117 389.157415 1.075158 62.013471 398.910421 -1 NaN 398.910421
2021-03-18 394.4750 396.7200 390.7500 391.4800 115349101.0 392.568980 389.368559 1.060502 53.893084 398.910421 -1 NaN 398.910421
2021-03-19 389.8800 391.5690 387.1500 389.4800 113624490.0 391.882540 389.378690 1.055380 51.385705 398.910421 -1 NaN 398.910421

5380 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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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-03-15 394.3300 396.6850 392.0300 396.4100 73592302.0 9.820634e+07 9.988408e+07 392.322958 389.839335
2021-03-16 397.0700 397.8300 395.0800 395.9100 73722506.0 9.375474e+07 1.010216e+08 393.518638 391.802334
2021-03-17 394.5300 398.1200 393.3000 397.2600 97959265.0 9.451920e+07 1.033322e+08 394.765759 393.574453
2021-03-18 394.4750 396.7200 390.7500 391.4800 115349101.0 9.830645e+07 1.061140e+08 393.670506 394.215707
2021-03-19 389.8800 391.5690 387.1500 389.4800 113624490.0 1.010915e+08 1.076332e+08 392.273671 393.946701

5380 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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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-03-15 394.3300 396.6850 392.0300 396.4100 73592302.0 2.268812 0.874720 1.394091 -0.900289 2.241715 5.383720 280.321462
2021-03-16 397.0700 397.8300 395.0800 395.9100 73722506.0 2.643863 0.999818 1.644046 -0.810546 2.142097 5.094740 275.677819
2021-03-17 394.5300 398.1200 393.3000 397.2600 97959265.0 3.015270 1.096979 1.918291 -0.690283 2.059061 4.808406 267.048329
2021-03-18 394.4750 396.7200 390.7500 391.4800 115349101.0 2.810813 0.714018 2.096795 -0.562339 1.973571 4.509482 256.986903
2021-03-19 389.8800 391.5690 387.1500 389.4800 113624490.0 2.459050 0.289804 2.169246 -0.435212 1.881908 4.199027 246.252186

5380 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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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-03-15 394.330 396.685 392.03 396.41 73592302.0 383.6352 349.25675 377.450608 387.7385 398.026392 5.306614 2.268812 0.874720 1.394091 61.444065 1.073016 1.062176 0 30 70
2021-03-16 397.070 397.830 395.08 395.91 73722506.0 384.0758 349.71470 377.199689 387.9190 398.638311 5.526572 2.643863 0.999818 1.644046 60.730184 1.071754 1.066640 0 30 70
2021-03-17 394.530 398.120 393.30 397.26 97959265.0 384.6452 350.17325 376.843518 388.1625 399.481482 5.832084 3.015270 1.096979 1.918291 62.013471 1.075158 1.070545 0 30 70
2021-03-18 394.475 396.720 390.75 391.48 115349101.0 385.0482 350.59025 376.842394 388.2005 399.558606 5.851670 2.810813 0.714018 2.096795 53.893084 1.060502 1.069500 0 30 70
2021-03-19 389.880 391.569 387.15 389.48 113624490.0 385.3668 350.97675 376.830092 388.1730 399.515908 5.844254 2.459050 0.289804 2.169246 51.385705 1.055380 1.067162 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 March 20, 2021, NYSE: 13:13:10, Local: 17:13:10 PDT, Day 79/365 (22.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-03-15 394.330 396.685 392.03 396.41 73592302.0 389.640175 1.360361 385.510398 398.789602 0.037762
2021-03-16 397.070 397.830 395.08 395.91 73722506.0 390.780143 1.425897 389.067672 398.728328 0.022323
2021-03-17 394.530 398.120 393.30 397.26 97959265.0 391.958299 1.461750 392.601825 398.266175 0.019522
2021-03-18 394.475 396.720 390.75 391.48 115349101.0 391.871336 0.889025 390.906241 399.141759 -0.005223
2021-03-19 389.880 391.569 387.15 389.48 113624490.0 391.436547 0.302361 387.988766 400.227234 -0.011691
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.