augment_bbands

augment_bbands(
    data,
    date_column,
    close_column,
    periods=20,
    std_dev=2,
    reduce_memory=False,
    engine='auto',
)

Calculate Bollinger Bands for pandas or polars data.

Parameters

Name Type Description Default
data DataFrame or GroupBy(pandas or polars) Input financial data. Grouped inputs are processed per group before the bands are appended. required
date_column str or ColumnSelector Name/selector for the column containing date information. Supports tidy selectors such as contains("date"). required
close_column str, ColumnSelector, or list Column(s) containing the prices used to compute the moving average and standard deviation. Selectors or lists must resolve to a single column. required
periods int, tuple, or list Rolling window lengths. An integer adds a single window, a tuple (start, end) expands to every integer in the inclusive range, and a list provides explicit windows. Defaults to 20. 20
std_dev float, int, or list Number(s) of standard deviations used when constructing the upper and lower bands. Integers are converted to floats. Defaults to 2. 2
reduce_memory bool Attempt to reduce memory usage when operating on pandas data. If a polars input is supplied a warning is emitted and no conversion occurs. False
engine (auto, pandas, polars) Execution engine. "auto" (default) infers the backend from the input data while allowing explicit overrides. "auto"

Returns

Name Type Description
DataFrame DataFrame with middle/upper/lower band columns appended for each period and std_dev combination. The return type matches the input backend (pandas or polars).

Notes

The middle band is the rolling mean of close_column. The upper band is the middle band plus std_dev times the rolling standard deviation, and the lower band subtracts the same quantity. Rolling statistics are calculated with a minimum window equal to period which matches the behaviour of the pandas implementation.

Examples

import pandas as pd
import polars as pl
import pytimetk as tk

df = tk.load_dataset("stocks_daily", parse_dates=["date"])

df
symbol date open high low close volume adjusted
0 META 2013-01-02 27.440001 28.180000 27.420000 28.000000 69846400 28.000000
1 META 2013-01-03 27.879999 28.469999 27.590000 27.770000 63140600 27.770000
2 META 2013-01-04 28.010000 28.930000 27.830000 28.760000 72715400 28.760000
3 META 2013-01-07 28.690001 29.790001 28.650000 29.420000 83781800 29.420000
4 META 2013-01-08 29.510000 29.600000 28.860001 29.059999 45871300 29.059999
... ... ... ... ... ... ... ... ...
16189 GOOG 2023-09-15 138.800003 139.360001 137.179993 138.300003 48947600 138.300003
16190 GOOG 2023-09-18 137.630005 139.929993 137.630005 138.960007 16233600 138.960007
16191 GOOG 2023-09-19 138.250000 139.175003 137.500000 138.830002 15479100 138.830002
16192 GOOG 2023-09-20 138.830002 138.839996 134.520004 134.589996 21473500 134.589996
16193 GOOG 2023-09-21 132.389999 133.190002 131.089996 131.360001 22042700 131.360001

16194 rows Γ— 8 columns

# Bollinger Bands - pandas engine
bbands_df = (
    df
    .groupby("symbol")
    .augment_bbands(
        date_column="date",
        close_column="close",
        periods=[20, 40],
        std_dev=[1.5, 2.0],
    )
)

bbands_df.glimpse()
<class 'pandas.core.frame.DataFrame'>: 16194 rows of 20 columns
symbol:                     object            ['META', 'META', 'META', ' ...
date:                       datetime64[ns]    [Timestamp('2013-01-02 00: ...
open:                       float64           [27.440000534057617, 27.87 ...
high:                       float64           [28.18000030517578, 28.469 ...
low:                        float64           [27.420000076293945, 27.59 ...
close:                      float64           [28.0, 27.770000457763672, ...
volume:                     int64             [69846400, 63140600, 72715 ...
adjusted:                   float64           [28.0, 27.770000457763672, ...
close_bband_middle_20_1.5:  float64           [nan, nan, nan, nan, nan,  ...
close_bband_upper_20_1.5:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_lower_20_1.5:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_middle_20_2.0:  float64           [nan, nan, nan, nan, nan,  ...
close_bband_upper_20_2.0:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_lower_20_2.0:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_middle_40_1.5:  float64           [nan, nan, nan, nan, nan,  ...
close_bband_upper_40_1.5:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_lower_40_1.5:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_middle_40_2.0:  float64           [nan, nan, nan, nan, nan,  ...
close_bband_upper_40_2.0:   float64           [nan, nan, nan, nan, nan,  ...
close_bband_lower_40_2.0:   float64           [nan, nan, nan, nan, nan,  ...
# Bollinger Bands - polars engine
pl_df = pl.from_pandas(df.query("symbol == 'AAPL'"))
bbands_pl = (
    pl_df
    .tk.augment_bbands(
        date_column="date",
        close_column="close",
        periods=(10, 15),
        std_dev=2,
    )
)

bbands_pl.glimpse()
Rows: 2699
Columns: 26
$ symbol                             <str> 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL'
$ date                      <datetime[ns]> 2013-01-02 00:00:00, 2013-01-03 00:00:00, 2013-01-04 00:00:00, 2013-01-07 00:00:00, 2013-01-08 00:00:00, 2013-01-09 00:00:00, 2013-01-10 00:00:00, 2013-01-11 00:00:00, 2013-01-14 00:00:00, 2013-01-15 00:00:00
$ open                               <f64> 19.779285430908203, 19.567142486572266, 19.177499771118164, 18.64285659790039, 18.90035629272461, 18.66071319580078, 18.876785278320312, 18.60714340209961, 17.952856063842773, 17.796428680419922
$ high                               <f64> 19.821428298950195, 19.63107109069824, 19.236785888671875, 18.9035701751709, 18.996070861816406, 18.750356674194336, 18.882856369018555, 18.761428833007812, 18.125, 17.82107162475586
$ low                                <f64> 19.343929290771484, 19.321428298950195, 18.77964210510254, 18.399999618530273, 18.616071701049805, 18.428213119506836, 18.41142845153809, 18.53642845153809, 17.80392837524414, 17.26357078552246
$ close                              <f64> 19.608213424682617, 19.36071395874023, 18.821428298950195, 18.71071434020996, 18.761070251464844, 18.467857360839844, 18.696786880493164, 18.582143783569336, 17.91964340209961, 17.354286193847656
$ volume                             <i64> 560518000, 352965200, 594333600, 484156400, 458707200, 407604400, 601146000, 350506800, 734207600, 876772400
$ adjusted                           <f64> 16.791179656982422, 16.579240798950195, 16.1174373626709, 16.02262306213379, 16.065746307373047, 15.814659118652344, 16.010698318481445, 15.912524223327637, 15.345203399658203, 14.86106777191162
$ close_bband_middle_10_2.0          <f64> None, None, None, None, None, None, None, None, None, 18.628285789489745
$ close_bband_upper_10_2.0           <f64> None, None, None, None, None, None, None, None, None, 19.913457143287992
$ close_bband_lower_10_2.0           <f64> None, None, None, None, None, None, None, None, None, 17.343114435691497
$ close_bband_middle_11_2.0          <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_upper_11_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_lower_11_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_middle_12_2.0          <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_upper_12_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_lower_12_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_middle_13_2.0          <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_upper_13_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_lower_13_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_middle_14_2.0          <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_upper_14_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_lower_14_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_middle_15_2.0          <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_upper_15_2.0           <f64> None, None, None, None, None, None, None, None, None, None
$ close_bband_lower_15_2.0           <f64> None, None, None, None, None, None, None, None, None, None
from pytimetk.utils.selection import contains

selector_demo = (
    df
    .augment_bbands(
        date_column=contains("dat"),
        close_column=contains("clos"),
        periods=20,
        std_dev=2,
    )
)

selector_demo.glimpse()
<class 'pandas.core.frame.DataFrame'>: 16194 rows of 11 columns
symbol:                     object            ['META', 'META', 'META', ' ...
date:                       datetime64[ns]    [Timestamp('2013-01-02 00: ...
open:                       float64           [27.440000534057617, 27.87 ...
high:                       float64           [28.18000030517578, 28.469 ...
low:                        float64           [27.420000076293945, 27.59 ...
close:                      float64           [28.0, 27.770000457763672, ...
volume:                     int64             [69846400, 63140600, 72715 ...
adjusted:                   float64           [28.0, 27.770000457763672, ...
close_bband_middle_20_2.0:  float64           [nan, nan, nan, 15.9840752 ...
close_bband_upper_20_2.0:   float64           [nan, nan, nan, 31.0152697 ...
close_bband_lower_20_2.0:   float64           [nan, nan, nan, 0.95288072 ...