0

would appreciate if you guys can help with a function that takes in a pandas df, a function name, input columns needed and argument/kwargs

import talib

The df is of the form:

                  Open        High         Low       Close     Volume 
Date                                                                          
1993-01-29   43.970001   43.970001   43.750000   43.939999    1003200   
1993-02-01   43.970001   44.250000   43.970001   44.250000     480500
1993-02-02   44.220001   44.380001   44.130001   44.340000     201300

This following code is ok:

def ApplyIndicator(df, data_col, indicator_func,period):
    df_copy = df.copy()
    col_name = indicator_func.__name__
    df_copy[col_name]=df_copy[data_col].apply(lambda x:indicator_func(x,period))

    return df_copy

Sample:

new_df = ApplyIndicator(df,['Close'],talib.SMA,10)

However, if I want a general ApplyIndicator which could take different columns, for example, talib.STOCH, it takes more than 1 arguments and need different columns:

slowk, slowd = STOCH(input_arrays, 5, 3, 0, 3, 0, prices=['high', 'low', 'open'])

For this case, how can I do a general ApplyIndicator function that do it on general talib function assuming all required columns are in df already.

Thank you.

More details on the two functions:

SMA(real[, timeperiod=?])

and

STOCH(high, low, close[, fastk_period=?, slowk_period=?, slowk_matype=?, slowd_period=?, slowd_matype=?])
lrh09
  • 557
  • 4
  • 13
  • why not to make a lambda wrapper around `indicator_func` before passing it to `ApplyIndicator`? – Marat Mar 23 '18 at 16:38
  • @Marat do you mind showing me that? See the additional details for the functions. I don't really know how to deal with "real[," also – lrh09 Mar 23 '18 at 17:12

1 Answers1

0

With the original ApplyIndicator, it can be be done like this:

def slowk(arr, per):
    return STOCH(arr, 5, 3, 0, 3, 0, prices=['high', 'low', 'open'])[0]

new_df = ApplyIndicator(df,['Close'], slowk, None)

Lambda won't work here because it its name is always "", but with some smarter column naming they should be fine too.

To make it slightly more elegant, we can let arbitrary number of attributes:

def ApplyIndicator(df, indicator_func, *args):
    col_name = indicator_func.__name__
    df[col_name] = df.apply(lambda x:indicator_func(x, *args))
    return df

new_df = ApplyIndicator(df[['Close']], talib.SMA, 10)
new_df = ApplyIndicator(df[...], STOCH, 5, 3, 0, 3, 0, ['high', 'low', 'open'])

But in fact, the whole function is so trivial it might be easier to replace it with a single call like this:

df[['slowk', 'slowd']] = df.apply(
    lambda idx, row: STOCH(row, 5, 3, 0, 3, 0, ['high', 'low', 'open']))
Marat
  • 15,215
  • 2
  • 39
  • 48