python - How to on a rolling window pass two column vectors instead of one? - Stack Overflow

admin2025-04-27  3

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.

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.

Share Improve this question edited Jan 11 at 19:59 wjandrea 33.3k10 gold badges69 silver badges98 bronze badges asked Jan 11 at 13:22 SkyWalkerSkyWalker 14.4k20 gold badges102 silver badges211 bronze badges 2
  • The ForceIndex indicator already uses a moving average of the past days so the df.rolling is not needed, isn't it? moreover after rolling we use an aggregate function like sum, mean, ... And what is force_index() ? – rehaqds Commented Jan 11 at 18:14
  • thanks but I am nevertheless curious how this use-case is covered in pandas ... – SkyWalker Commented Jan 11 at 18:48
Add a comment  | 

2 Answers 2

Reset to default 1

The apply method has a raw argument:

 raw:bool, default False

        False : passes each row or column as a Series to the function.

        True : the passed function will receive ndarray objects instead. If you are just applying a NumPy reduction function this will achieve much better performance.

So using raw=True should pass all the data you need to the function.

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
转载请注明原文地址:http://anycun.com/QandA/1745709979a91141.html