augment_ewma_volatility

augment_ewma_volatility(
    data,
    date_column,
    close_column,
    decay_factor=0.94,
    window=20,
    reduce_memory=False,
    engine='pandas',
)

Calculate Exponentially Weighted Moving Average (EWMA) volatility for a financial time series.

Parameters

Name Type Description Default
data Union[pd.DataFrame, pd.core.groupby.generic.DataFrameGroupBy] Input pandas DataFrame or GroupBy object with time series data. required
date_column str Column name containing dates or timestamps. required
close_column str Column name with closing prices to calculate volatility. required
decay_factor float Smoothing factor (lambda) for EWMA, between 0 and 1. Higher values give more weight to past data. Default is 0.94 (RiskMetrics standard). 0.94
window Union[int, Tuple[int, int], List[int]] Size of the rolling window to initialize EWMA calculation. For each window value the EWMA volatility is only computed when at least that many observations are available. You may provide a single integer or multiple values (via tuple or list). Default is 20. 20
reduce_memory bool If True, reduces memory usage before calculation. Default is False. False
engine str Computation engine: ‘pandas’ or ‘polars’. Default is ‘pandas’. 'pandas'

Returns

Name Type Description
pd.DataFrame DataFrame with added columns: - {close_column}ewma_vol{window}_{decay_factor}: EWMA volatility calculated using a minimum number of periods equal to each specified window.

Notes

EWMA volatility emphasizes recent price movements and is computed recursively as:

σ²_t = (1 - λ) * r²_t + λ * σ²_{t-1}

where r_t is the log return. By using the min_periods (set to the provided window value) we ensure that the EWMA is only calculated after enough observations have accumulated.

References:

  • https://www.investopedia.com/articles/07/ewma.asp

Examples

import pandas as pd
import pytimetk as tk

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

# Example 1 - Calculate EWMA volatility for a single stock

df.query("symbol == 'AAPL'").augment_ewma_volatility(
    date_column='date',
    close_column='close',
    decay_factor=0.94,
    window=[20, 50]
).glimpse()
<class 'pandas.core.frame.DataFrame'>: 2699 rows of 10 columns
symbol:                  object            ['AAPL', 'AAPL', 'AAPL', 'AAP ...
date:                    datetime64[ns]    [Timestamp('2013-01-02 00:00: ...
open:                    float64           [19.779285430908203, 19.56714 ...
high:                    float64           [19.821428298950195, 19.63107 ...
low:                     float64           [19.343929290771484, 19.32142 ...
close:                   float64           [19.608213424682617, 19.36071 ...
volume:                  int64             [560518000, 352965200, 594333 ...
adjusted:                float64           [16.791179656982422, 16.57924 ...
close_ewma_vol_20_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
close_ewma_vol_50_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
# Example 2 - Calculate EWMA volatility for multiple stocks
df.groupby('symbol').augment_ewma_volatility(
    date_column='date',
    close_column='close',
    decay_factor=0.94,
    window=[20, 50]
).glimpse()
<class 'pandas.core.frame.DataFrame'>: 16194 rows of 10 columns
symbol:                  object            ['META', 'META', 'META', 'MET ...
date:                    datetime64[ns]    [Timestamp('2013-01-02 00:00: ...
open:                    float64           [27.440000534057617, 27.87999 ...
high:                    float64           [28.18000030517578, 28.469999 ...
low:                     float64           [27.420000076293945, 27.59000 ...
close:                   float64           [28.0, 27.770000457763672, 28 ...
volume:                  int64             [69846400, 63140600, 72715400 ...
adjusted:                float64           [28.0, 27.770000457763672, 28 ...
close_ewma_vol_20_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
close_ewma_vol_50_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
# Example 3 - Calculate EWMA volatility using Polars engine
df.query("symbol == 'AAPL'").augment_ewma_volatility(
    date_column='date',
    close_column='close',
    decay_factor=0.94,
    window=[20, 50],
    engine='polars'
).glimpse()
<class 'pandas.core.frame.DataFrame'>: 2699 rows of 10 columns
symbol:                  object            ['AAPL', 'AAPL', 'AAPL', 'AAP ...
date:                    datetime64[ns]    [Timestamp('2013-01-02 00:00: ...
open:                    float64           [19.779285430908203, 19.56714 ...
high:                    float64           [19.821428298950195, 19.63107 ...
low:                     float64           [19.343929290771484, 19.32142 ...
close:                   float64           [19.608213424682617, 19.36071 ...
volume:                  int64             [560518000, 352965200, 594333 ...
adjusted:                float64           [16.791179656982422, 16.57924 ...
close_ewma_vol_20_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
close_ewma_vol_50_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
# Example 4 - Calculate EWMA volatility for multiple stocks using Polars engine

df.groupby('symbol').augment_ewma_volatility(
    date_column='date',
    close_column='close',
    decay_factor=0.94,
    window=[20, 50],
    engine='polars'
).glimpse()
<class 'pandas.core.frame.DataFrame'>: 16194 rows of 10 columns
symbol:                  object            ['META', 'META', 'META', 'MET ...
date:                    datetime64[ns]    [Timestamp('2013-01-02 00:00: ...
open:                    float64           [27.440000534057617, 27.87999 ...
high:                    float64           [28.18000030517578, 28.469999 ...
low:                     float64           [27.420000076293945, 27.59000 ...
close:                   float64           [28.0, 27.770000457763672, 28 ...
volume:                  int64             [69846400, 63140600, 72715400 ...
adjusted:                float64           [28.0, 27.770000457763672, 28 ...
close_ewma_vol_20_0.94:  float64           [nan, nan, nan, nan, nan, nan ...
close_ewma_vol_50_0.94:  float64           [nan, nan, nan, nan, nan, nan ...