pythonpandas

How to on a rolling window pass two column vectors instead of one?


I'm computing technical indicators on a rolling basis to avoid any look-ahead bias, for example, for model training and back-testing. To that end I would like to compute the indicator ForceIndexIndicator using the TA Python project. However this needs two inputs instead of one: close and volume, and I can't get hold of both on my rolling - apply pipeline:

import pandas as pd
import ta

...
df.columns = ['close', 'volume']
df['force_index_close'] = (
    df.rolling(window=window)
    .apply(
        lambda x: ta.volume.ForceIndexIndicator(
            close=x['close'],
            volume=x['volume'],
            window=13,
            fillna=True)
        .force_index().iloc[-1]))

I get the error KeyError: 'close' because apply gets one column at a time and not both simultaneously as needed.


Solution

  • I found two ways to do it, but one of them using numba and rolling method='table' doesn't work because numba is a bit obscure and doesn't understand the outside context of the callback function.

    However, the solution based on this answer works perfectly:

    df['force_index_close'] = df['close'].rolling(window=window).\
        apply(args=(df['volume'],), 
              func=lambda close, dfv: ta.volume.ForceIndexIndicator(close=close, volume=dfv.loc[close.index], window=13, fillna=True).force_index().iloc[-1])
    print(df['force_index_close'])
    df['force_index_close'].plot()
    

    this is what's happening:

    1. I perform the rolling on a single column close, otherwise the apply is computed twice, i.e. once per column
    2. apply gets an additional context args with the series made of the other column volume, if your use-case would require additional columns then they could be injected here into the apply
    3. in the apply func I simply narrow the context volume series to align to the close index