From 6fd65a032e385a861c1ea7c91777e21fde41c0ac Mon Sep 17 00:00:00 2001 From: mario4tier Date: Tue, 28 Jul 2026 22:54:27 -0400 Subject: [PATCH] feat: support TA-Lib C 0.8.1 TA-Lib C 0.8.1 is now the minimum required version. - Bind the seven new functions: CMF, CMOU, HMA, NVI, PVI, PVO, VWMA (declarations in _ta_lib.pxd, regenerated _func.pxi/_stream.pxi, added to __function_groups__ and to both type stubs). - Add MA_Type.HMA and MA_Type.DISABLED. - abstract: __get_flags() raised KeyError on flag bits added after this wrapper was written. 0.8.1 sets TA_FUNC_FLG_STREAM, which made abstract.Function() unusable and left tests/test_abstract.py and tests/test_polars.py uncollectable. Unknown bits are now ignored, and the known new bits (streaming API, path-dependent, nullable output) are named. - tools/generate_func.py, tools/generate_stream.py: skip TA-Lib C's own streaming API (TA__Open/_OpenAndFill/_Update/_Peek/_Close), which the header parser could not handle. - Building against an older ta-lib still links: a shared object may keep undefined symbols, so the failure only appears when the extension is loaded, as "undefined symbol: TA_CMF_Lookback". Catch that at import and say what is actually wrong. - Bump the pinned TALIB_C_VER in the wheel workflow and the three build scripts to 0.8.1. - Tests: APO/PPO now default matype to EMA and BBANDS timeperiod to 20 per TA-Lib C 0.8.1; version is 0.8.1 and the function count is 168. Added a smoke test per new function and an MA(HMA) == HMA check. --- .github/workflows/wheels.yml | 2 +- CHANGELOG | 15 +++ talib/__init__.py | 41 +++++-- talib/_abstract.pxi | 17 ++- talib/_common.pxi | 4 +- talib/_func.pxi | 217 ++++++++++++++++++++++++++++----- talib/_stream.pxi | 221 ++++++++++++++++++++++++++++------ talib/_ta_lib.pxd | 14 +++ talib/_ta_lib.pyi | 92 +++++++++++++- talib/abstract.pyi | 109 +++++++++++++++-- tests/test_abstract.py | 7 +- tests/test_func.py | 37 +++++- tools/build_talib_linux.sh | 2 +- tools/build_talib_macos.sh | 2 +- tools/build_talib_windows.cmd | 2 +- tools/generate_func.py | 7 ++ tools/generate_stream.py | 7 ++ 17 files changed, 691 insertions(+), 105 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 585187e4a..3a2aaae13 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: env: - TALIB_C_VER: 0.7.1 + TALIB_C_VER: 0.8.1 PIP_NO_VERIFY: 0 PIP_VERBOSE: 1 CIBW_BEFORE_BUILD: pip install -U setuptools Cython wheel meson-python ninja && pip install -U numpy diff --git a/CHANGELOG b/CHANGELOG index 56676df11..b16a3b45b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,18 @@ +0.8.0 +===== + +- [NEW]: Support TA-Lib C 0.8.1, which is now the minimum required version. + +- [NEW]: New functions from TA-Lib C 0.8.1: CMF, CMOU, HMA, NVI, PVI, PVO, VWMA. + +- [NEW]: New moving averages ``MA_Type.HMA`` and ``MA_Type.DISABLED``. + +- [FIX]: ``abstract`` raised ``KeyError`` on function and output flags added + after this wrapper was written; unknown flag bits are now ignored. + +- [CHANGE]: ``APO`` and ``PPO`` now default ``matype`` to EMA, and ``BBANDS`` + defaults ``timeperiod`` to 20, following TA-Lib C 0.8.1. + 0.7.1 ===== diff --git a/talib/__init__.py b/talib/__init__.py index 63ac18cc9..2edf20352 100644 --- a/talib/__init__.py +++ b/talib/__init__.py @@ -106,14 +106,30 @@ def wrapper(*args, **kwds): _wrapper = lambda x: x -from ._ta_lib import ( - _ta_initialize, _ta_shutdown, MA_Type, __ta_version__, - _ta_set_unstable_period as set_unstable_period, - _ta_get_unstable_period as get_unstable_period, - _ta_set_compatibility as set_compatibility, - _ta_get_compatibility as get_compatibility, - __TA_FUNCTION_NAMES__ -) +# The TA-Lib C library this wrapper is built against +TA_LIB_C_REQUIRED = '0.8.1' + +try: + from ._ta_lib import ( + _ta_initialize, _ta_shutdown, MA_Type, __ta_version__, + _ta_set_unstable_period as set_unstable_period, + _ta_get_unstable_period as get_unstable_period, + _ta_set_compatibility as set_compatibility, + _ta_get_compatibility as get_compatibility, + __TA_FUNCTION_NAMES__ + ) +except ImportError as error: + # Loading the extension resolves its symbols against whatever TA-Lib C is + # installed. Linking never catches a too-old library -- a shared object may + # keep undefined symbols -- so a missing function shows up here instead, as + # "undefined symbol: TA_CMF_Lookback" or the macOS/Windows equivalent. + raise ImportError( + '%s\n\n' + 'talib could not load its extension module. This build requires the ' + 'TA-Lib C library %s or later; an older one is missing functions this ' + 'wrapper calls. See https://ta-lib.org/install/' + % (error, TA_LIB_C_REQUIRED) + ) from error # import all the func and stream functions from ._ta_lib import * @@ -191,6 +207,7 @@ def wrapper(*args, **kwds): 'BOP', 'CCI', 'CMO', + 'CMOU', 'DX', 'IMI', 'MACD', @@ -220,6 +237,7 @@ def wrapper(*args, **kwds): 'BBANDS', 'DEMA', 'EMA', + 'HMA', 'HT_TRENDLINE', 'KAMA', 'MA', @@ -233,6 +251,7 @@ def wrapper(*args, **kwds): 'T3', 'TEMA', 'TRIMA', + 'VWMA', 'WMA', ], 'Pattern Recognition': [ @@ -324,7 +343,11 @@ def wrapper(*args, **kwds): 'Volume Indicators': [ 'AD', 'ADOSC', - 'OBV' + 'CMF', + 'NVI', + 'OBV', + 'PVI', + 'PVO', ], } diff --git a/talib/_abstract.pxi b/talib/_abstract.pxi index 6989ab80d..57caaabba 100644 --- a/talib/_abstract.pxi +++ b/talib/_abstract.pxi @@ -599,23 +599,29 @@ def __get_flags(int flag, dict flags_lookup_dict): max_int = int(math.log(max(value_range), 2)) # if the flag we got is out-of-range, it just means no extra info provided - if flag < 1 or flag > 2**max_int: + if flag < 1: return None # In this loop, i is essentially the bit-position, which represents an # input from flags_lookup_dict. We loop through as many flags_lookup_dict # bit-positions as we need to check, bitwise-ANDing each with flag for a hit. + # A bit we have no description for means the installed ta-lib is newer than + # this build knows about; skip it rather than raising. ret = [] - for i in xrange(min_int, max_int+1): + for i in xrange(min_int, max(max_int, int(math.log(flag, 2))) + 1): if 2**i & flag: - ret.append(flags_lookup_dict[2**i]) + description = flags_lookup_dict.get(2**i) + if description is not None: + ret.append(description) return ret TA_FUNC_FLAGS = { 16777216: 'Output scale same as input', + 33554432: 'Function has a streaming API', 67108864: 'Output is over volume', 134217728: 'Function has an unstable period', - 268435456: 'Output is a candlestick' + 268435456: 'Output is a candlestick', + 536870912: 'Output is path-dependent', } # when flag is 0, the function (should) work on any reasonable input ndarray @@ -642,7 +648,8 @@ TA_OUTPUT_FLAGS = { 512: 'Output can be negative', 1024: 'Output can be zero', 2048: 'Values represent an upper limit', - 4096: 'Values represent a lower limit' + 4096: 'Values represent a lower limit', + 8192: 'Output is optional (nullable)', } def _ta_getFuncInfo(char *function_name): diff --git a/talib/_common.pxi b/talib/_common.pxi index 8c508d577..9ec8ccd1d 100644 --- a/talib/_common.pxi +++ b/talib/_common.pxi @@ -60,7 +60,7 @@ def _ta_shutdown(): _ta_check_success('TA_Shutdown', ret_code) class MA_Type(object): - SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3 = range(9) + SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, MAMA, T3, HMA, DISABLED = range(11) def __init__(self): self._lookup = { @@ -73,6 +73,8 @@ class MA_Type(object): MA_Type.KAMA: 'Kaufman Adaptive Moving Average', MA_Type.MAMA: 'MESA Adaptive Moving Average', MA_Type.T3: 'Triple Generalized Double Exponential Moving Average', + MA_Type.HMA: 'Hull Moving Average', + MA_Type.DISABLED: 'No Moving Average (identity)', } def __getitem__(self, type_): diff --git a/talib/_func.pxi b/talib/_func.pxi index c4555a42c..49a82afd3 100644 --- a/talib/_func.pxi +++ b/talib/_func.pxi @@ -373,7 +373,7 @@ def ADXR( np.ndarray high not None , np.ndarray low not None , np.ndarray close @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function -def APO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=0 ): +def APO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=1 ): """ APO(real[, fastperiod=?, slowperiod=?, matype=?]) Absolute Price Oscillator (Momentum Indicators) @@ -383,7 +383,7 @@ def APO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**3 Parameters: fastperiod: 12 slowperiod: 26 - matype: 0 (Simple Moving Average) + matype: 1 (Exponential Moving Average) Outputs: real """ @@ -564,13 +564,15 @@ def ATR( np.ndarray high not None , np.ndarray low not None , np.ndarray close n @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function -def AVGPRICE( np.ndarray open not None , np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): - """ AVGPRICE(open, high, low, close) +def AVGDEV( np.ndarray real not None , int timeperiod=-2**31 ): + """ AVGDEV(real[, timeperiod=?]) - Average Price (Price Transform) + Average Deviation (Price Transform) Inputs: - prices: ['open', 'high', 'low', 'close'] + real: (any ndarray) + Parameters: + timeperiod: 14 Outputs: real """ @@ -581,30 +583,25 @@ def AVGPRICE( np.ndarray open not None , np.ndarray high not None , np.ndarray l int outbegidx int outnbelement np.ndarray outreal - open = check_array(open) - high = check_array(high) - low = check_array(low) - close = check_array(close) - length = check_length4(open, high, low, close) - begidx = check_begidx4(length, (open.data), (high.data), (low.data), (close.data)) + real = check_array(real) + length = real.shape[0] + begidx = check_begidx1(length, (real.data)) endidx = length - begidx - 1 - lookback = begidx + lib.TA_AVGPRICE_Lookback( ) + lookback = begidx + lib.TA_AVGDEV_Lookback( timeperiod ) outreal = make_double_array(length, lookback) - retCode = lib.TA_AVGPRICE( 0 , endidx , (open.data)+begidx , (high.data)+begidx , (low.data)+begidx , (close.data)+begidx , &outbegidx , &outnbelement , (outreal.data)+lookback ) - _ta_check_success("TA_AVGPRICE", retCode) + retCode = lib.TA_AVGDEV( 0 , endidx , (real.data)+begidx , timeperiod , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_AVGDEV", retCode) return outreal @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function -def AVGDEV( np.ndarray real not None , int timeperiod=-2**31 ): - """ AVGDEV(real[, timeperiod=?]) +def AVGPRICE( np.ndarray open not None , np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): + """ AVGPRICE(open, high, low, close) - Average Deviation (Price Transform) + Average Price (Price Transform) Inputs: - real: (any ndarray) - Parameters: - timeperiod: 14 + prices: ['open', 'high', 'low', 'close'] Outputs: real """ @@ -615,14 +612,17 @@ def AVGDEV( np.ndarray real not None , int timeperiod=-2**31 ): int outbegidx int outnbelement np.ndarray outreal - real = check_array(real) - length = real.shape[0] - begidx = check_begidx1(length, (real.data)) + open = check_array(open) + high = check_array(high) + low = check_array(low) + close = check_array(close) + length = check_length4(open, high, low, close) + begidx = check_begidx4(length, (open.data), (high.data), (low.data), (close.data)) endidx = length - begidx - 1 - lookback = begidx + lib.TA_AVGDEV_Lookback( timeperiod ) + lookback = begidx + lib.TA_AVGPRICE_Lookback( ) outreal = make_double_array(length, lookback) - retCode = lib.TA_AVGDEV( 0 , endidx , (real.data)+begidx , timeperiod , &outbegidx , &outnbelement , (outreal.data)+lookback ) - _ta_check_success("TA_AVGDEV", retCode) + retCode = lib.TA_AVGPRICE( 0 , endidx , (open.data)+begidx , (high.data)+begidx , (low.data)+begidx , (close.data)+begidx , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_AVGPRICE", retCode) return outreal @wraparound(False) # turn off relative indexing from end of lists @@ -635,7 +635,7 @@ def BBANDS( np.ndarray real not None , int timeperiod=-2**31 , double nbdevup=-4 Inputs: real: (any ndarray) Parameters: - timeperiod: 5 + timeperiod: 20 nbdevup: 2.0 nbdevdn: 2.0 matype: 0 (Simple Moving Average) @@ -864,7 +864,7 @@ def CDL3INSIDE( np.ndarray open not None , np.ndarray high not None , np.ndarray def CDL3LINESTRIKE( np.ndarray open not None , np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): """ CDL3LINESTRIKE(open, high, low, close) - Three-Line Strike (Pattern Recognition) + Three-Line Strike (Pattern Recognition) Inputs: prices: ['open', 'high', 'low', 'close'] @@ -2758,6 +2758,30 @@ def CEIL( np.ndarray real not None ): _ta_check_success("TA_CEIL", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def CMF( np.ndarray high not None , np.ndarray low not None , np.ndarray close not None , np.ndarray volume not None , int timeperiod=-2**31 ): + """ CMF(high, low, close, volume[, timeperiod=?])""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + high = check_array(high) + low = check_array(low) + close = check_array(close) + volume = check_array(volume) + length = check_length4(high, low, close, volume) + begidx = check_begidx4(length, (high.data), (low.data), (close.data), (volume.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_CMF_Lookback( timeperiod ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_CMF( 0 , endidx , (high.data)+begidx , (low.data)+begidx , (close.data)+begidx , (volume.data)+begidx , timeperiod , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_CMF", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def CMO( np.ndarray real not None , int timeperiod=-2**31 ): @@ -2789,6 +2813,27 @@ def CMO( np.ndarray real not None , int timeperiod=-2**31 ): _ta_check_success("TA_CMO", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def CMOU( np.ndarray real not None , int timeperiod=-2**31 ): + """ CMOU(real[, timeperiod=?])""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + real = check_array(real) + length = real.shape[0] + begidx = check_begidx1(length, (real.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_CMOU_Lookback( timeperiod ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_CMOU( 0 , endidx , (real.data)+begidx , timeperiod , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_CMOU", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def CORREL( np.ndarray real0 not None , np.ndarray real1 not None , int timeperiod=-2**31 ): @@ -3064,6 +3109,27 @@ def FLOOR( np.ndarray real not None ): _ta_check_success("TA_FLOOR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def HMA( np.ndarray real not None , int timeperiod=-2**31 ): + """ HMA(real[, timeperiod=?])""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + real = check_array(real) + length = real.shape[0] + begidx = check_begidx1(length, (real.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_HMA_Lookback( timeperiod ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_HMA( 0 , endidx , (real.data)+begidx , timeperiod , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_HMA", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def HT_DCPERIOD( np.ndarray real not None ): @@ -4200,6 +4266,28 @@ def NATR( np.ndarray high not None , np.ndarray low not None , np.ndarray close _ta_check_success("TA_NATR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def NVI( np.ndarray close not None , np.ndarray volume not None ): + """ NVI(close, volume)""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + close = check_array(close) + volume = check_array(volume) + length = check_length2(close, volume) + begidx = check_begidx2(length, (close.data), (volume.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_NVI_Lookback( ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_NVI( 0 , endidx , (close.data)+begidx , (volume.data)+begidx , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_NVI", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def OBV( np.ndarray real not None , np.ndarray volume not None ): @@ -4298,7 +4386,7 @@ def PLUS_DM( np.ndarray high not None , np.ndarray low not None , int timeperiod @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function -def PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=0 ): +def PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=1 ): """ PPO(real[, fastperiod=?, slowperiod=?, matype=?]) Percentage Price Oscillator (Momentum Indicators) @@ -4308,7 +4396,7 @@ def PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**3 Parameters: fastperiod: 12 slowperiod: 26 - matype: 0 (Simple Moving Average) + matype: 1 (Exponential Moving Average) Outputs: real """ @@ -4329,6 +4417,49 @@ def PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**3 _ta_check_success("TA_PPO", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def PVI( np.ndarray close not None , np.ndarray volume not None ): + """ PVI(close, volume)""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + close = check_array(close) + volume = check_array(volume) + length = check_length2(close, volume) + begidx = check_begidx2(length, (close.data), (volume.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_PVI_Lookback( ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_PVI( 0 , endidx , (close.data)+begidx , (volume.data)+begidx , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_PVI", retCode) + return outreal + +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def PVO( np.ndarray volume not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=0 ): + """ PVO(volume[, fastperiod=?, slowperiod=?, matype=?])""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + volume = check_array(volume) + length = volume.shape[0] + begidx = check_begidx1(length, (volume.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_PVO_Lookback( fastperiod , slowperiod , matype ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_PVO( 0 , endidx , (volume.data)+begidx , fastperiod , slowperiod , matype , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_PVO", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def ROC( np.ndarray real not None , int timeperiod=-2**31 ): @@ -5226,6 +5357,28 @@ def VAR( np.ndarray real not None , int timeperiod=-2**31 , double nbdev=-4e37 ) _ta_check_success("TA_VAR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def VWMA( np.ndarray real not None , np.ndarray volume not None , int timeperiod=-2**31 ): + """ VWMA(real, volume[, timeperiod=?])""" + cdef: + np.npy_intp length + int begidx, endidx, lookback + TA_RetCode retCode + int outbegidx + int outnbelement + np.ndarray outreal + real = check_array(real) + volume = check_array(volume) + length = check_length2(real, volume) + begidx = check_begidx2(length, (real.data), (volume.data)) + endidx = length - begidx - 1 + lookback = begidx + lib.TA_VWMA_Lookback( timeperiod ) + outreal = make_double_array(length, lookback) + retCode = lib.TA_VWMA( 0 , endidx , (real.data)+begidx , (volume.data)+begidx , timeperiod , &outbegidx , &outnbelement , (outreal.data)+lookback ) + _ta_check_success("TA_VWMA", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def WCLPRICE( np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): @@ -5321,4 +5474,4 @@ def WMA( np.ndarray real not None , int timeperiod=-2**31 ): _ta_check_success("TA_WMA", retCode) return outreal -__TA_FUNCTION_NAMES__ = ["ACCBANDS","ACOS","AD","ADD","ADOSC","ADX","ADXR","APO","AROON","AROONOSC","ASIN","ATAN","ATR","AVGPRICE","AVGDEV","BBANDS","BETA","BOP","CCI","CDL2CROWS","CDL3BLACKCROWS","CDL3INSIDE","CDL3LINESTRIKE","CDL3OUTSIDE","CDL3STARSINSOUTH","CDL3WHITESOLDIERS","CDLABANDONEDBABY","CDLADVANCEBLOCK","CDLBELTHOLD","CDLBREAKAWAY","CDLCLOSINGMARUBOZU","CDLCONCEALBABYSWALL","CDLCOUNTERATTACK","CDLDARKCLOUDCOVER","CDLDOJI","CDLDOJISTAR","CDLDRAGONFLYDOJI","CDLENGULFING","CDLEVENINGDOJISTAR","CDLEVENINGSTAR","CDLGAPSIDESIDEWHITE","CDLGRAVESTONEDOJI","CDLHAMMER","CDLHANGINGMAN","CDLHARAMI","CDLHARAMICROSS","CDLHIGHWAVE","CDLHIKKAKE","CDLHIKKAKEMOD","CDLHOMINGPIGEON","CDLIDENTICAL3CROWS","CDLINNECK","CDLINVERTEDHAMMER","CDLKICKING","CDLKICKINGBYLENGTH","CDLLADDERBOTTOM","CDLLONGLEGGEDDOJI","CDLLONGLINE","CDLMARUBOZU","CDLMATCHINGLOW","CDLMATHOLD","CDLMORNINGDOJISTAR","CDLMORNINGSTAR","CDLONNECK","CDLPIERCING","CDLRICKSHAWMAN","CDLRISEFALL3METHODS","CDLSEPARATINGLINES","CDLSHOOTINGSTAR","CDLSHORTLINE","CDLSPINNINGTOP","CDLSTALLEDPATTERN","CDLSTICKSANDWICH","CDLTAKURI","CDLTASUKIGAP","CDLTHRUSTING","CDLTRISTAR","CDLUNIQUE3RIVER","CDLUPSIDEGAP2CROWS","CDLXSIDEGAP3METHODS","CEIL","CMO","CORREL","COS","COSH","DEMA","DIV","DX","EMA","EXP","FLOOR","HT_DCPERIOD","HT_DCPHASE","HT_PHASOR","HT_SINE","HT_TRENDLINE","HT_TRENDMODE","IMI","KAMA","LINEARREG","LINEARREG_ANGLE","LINEARREG_INTERCEPT","LINEARREG_SLOPE","LN","LOG10","MA","MACD","MACDEXT","MACDFIX","MAMA","MAVP","MAX","MAXINDEX","MEDPRICE","MFI","MIDPOINT","MIDPRICE","MIN","MININDEX","MINMAX","MINMAXINDEX","MINUS_DI","MINUS_DM","MOM","MULT","NATR","OBV","PLUS_DI","PLUS_DM","PPO","ROC","ROCP","ROCR","ROCR100","RSI","SAR","SAREXT","SIN","SINH","SMA","SQRT","STDDEV","STOCH","STOCHF","STOCHRSI","SUB","SUM","T3","TAN","TANH","TEMA","TRANGE","TRIMA","TRIX","TSF","TYPPRICE","ULTOSC","VAR","WCLPRICE","WILLR","WMA"] +__TA_FUNCTION_NAMES__ = ["ACCBANDS","ACOS","AD","ADD","ADOSC","ADX","ADXR","APO","AROON","AROONOSC","ASIN","ATAN","ATR","AVGDEV","AVGPRICE","BBANDS","BETA","BOP","CCI","CDL2CROWS","CDL3BLACKCROWS","CDL3INSIDE","CDL3LINESTRIKE","CDL3OUTSIDE","CDL3STARSINSOUTH","CDL3WHITESOLDIERS","CDLABANDONEDBABY","CDLADVANCEBLOCK","CDLBELTHOLD","CDLBREAKAWAY","CDLCLOSINGMARUBOZU","CDLCONCEALBABYSWALL","CDLCOUNTERATTACK","CDLDARKCLOUDCOVER","CDLDOJI","CDLDOJISTAR","CDLDRAGONFLYDOJI","CDLENGULFING","CDLEVENINGDOJISTAR","CDLEVENINGSTAR","CDLGAPSIDESIDEWHITE","CDLGRAVESTONEDOJI","CDLHAMMER","CDLHANGINGMAN","CDLHARAMI","CDLHARAMICROSS","CDLHIGHWAVE","CDLHIKKAKE","CDLHIKKAKEMOD","CDLHOMINGPIGEON","CDLIDENTICAL3CROWS","CDLINNECK","CDLINVERTEDHAMMER","CDLKICKING","CDLKICKINGBYLENGTH","CDLLADDERBOTTOM","CDLLONGLEGGEDDOJI","CDLLONGLINE","CDLMARUBOZU","CDLMATCHINGLOW","CDLMATHOLD","CDLMORNINGDOJISTAR","CDLMORNINGSTAR","CDLONNECK","CDLPIERCING","CDLRICKSHAWMAN","CDLRISEFALL3METHODS","CDLSEPARATINGLINES","CDLSHOOTINGSTAR","CDLSHORTLINE","CDLSPINNINGTOP","CDLSTALLEDPATTERN","CDLSTICKSANDWICH","CDLTAKURI","CDLTASUKIGAP","CDLTHRUSTING","CDLTRISTAR","CDLUNIQUE3RIVER","CDLUPSIDEGAP2CROWS","CDLXSIDEGAP3METHODS","CEIL","CMF","CMO","CMOU","CORREL","COS","COSH","DEMA","DIV","DX","EMA","EXP","FLOOR","HMA","HT_DCPERIOD","HT_DCPHASE","HT_PHASOR","HT_SINE","HT_TRENDLINE","HT_TRENDMODE","IMI","KAMA","LINEARREG","LINEARREG_ANGLE","LINEARREG_INTERCEPT","LINEARREG_SLOPE","LN","LOG10","MA","MACD","MACDEXT","MACDFIX","MAMA","MAVP","MAX","MAXINDEX","MEDPRICE","MFI","MIDPOINT","MIDPRICE","MIN","MININDEX","MINMAX","MINMAXINDEX","MINUS_DI","MINUS_DM","MOM","MULT","NATR","NVI","OBV","PLUS_DI","PLUS_DM","PPO","PVI","PVO","ROC","ROCP","ROCR","ROCR100","RSI","SAR","SAREXT","SIN","SINH","SMA","SQRT","STDDEV","STOCH","STOCHF","STOCHRSI","SUB","SUM","T3","TAN","TANH","TEMA","TRANGE","TRIMA","TRIX","TSF","TYPPRICE","ULTOSC","VAR","VWMA","WCLPRICE","WILLR","WMA"] diff --git a/talib/_stream.pxi b/talib/_stream.pxi index b1575b2cc..747d14a8b 100644 --- a/talib/_stream.pxi +++ b/talib/_stream.pxi @@ -252,7 +252,7 @@ def stream_ADXR( np.ndarray high not None , np.ndarray low not None , np.ndarray @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function -def stream_APO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=0 ): +def stream_APO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=1 ): """ APO(real[, fastperiod=?, slowperiod=?, matype=?]) Absolute Price Oscillator (Momentum Indicators) @@ -262,7 +262,7 @@ def stream_APO( np.ndarray real not None , int fastperiod=-2**31 , int slowperio Parameters: fastperiod: 12 slowperiod: 26 - matype: 0 (Simple Moving Average) + matype: 1 (Exponential Moving Average) Outputs: real """ @@ -437,6 +437,35 @@ def stream_ATR( np.ndarray high not None , np.ndarray low not None , np.ndarray _ta_check_success("TA_ATR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_AVGDEV( np.ndarray real not None , int timeperiod=-2**31 ): + """ AVGDEV(real[, timeperiod=?]) + + Average Deviation (Price Transform) + + Inputs: + real: (any ndarray) + Parameters: + timeperiod: 14 + Outputs: + real + """ + cdef: + np.npy_intp length + TA_RetCode retCode + double* real_data + int outbegidx + int outnbelement + double outreal + real = check_array(real) + real_data = real.data + length = real.shape[0] + outreal = NaN + retCode = lib.TA_AVGDEV( (length) - 1 , (length) - 1 , real_data , timeperiod , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_AVGDEV", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_AVGPRICE( np.ndarray open not None , np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): @@ -473,35 +502,6 @@ def stream_AVGPRICE( np.ndarray open not None , np.ndarray high not None , np.nd _ta_check_success("TA_AVGPRICE", retCode) return outreal -@wraparound(False) # turn off relative indexing from end of lists -@boundscheck(False) # turn off bounds-checking for entire function -def stream_AVGDEV( np.ndarray real not None , int timeperiod=-2**31 ): - """ AVGDEV(real[, timeperiod=?]) - - Average Deviation (Price Transform) - - Inputs: - real: (any ndarray) - Parameters: - timeperiod: 14 - Outputs: - real - """ - cdef: - np.npy_intp length - TA_RetCode retCode - double* real_data - int outbegidx - int outnbelement - double outreal - real = check_array(real) - real_data = real.data - length = real.shape[0] - outreal = NaN - retCode = lib.TA_AVGDEV( (length) - 1 , (length) - 1 , real_data , timeperiod , &outbegidx , &outnbelement , &outreal ) - _ta_check_success("TA_AVGDEV", retCode) - return outreal - @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_BBANDS( np.ndarray real not None , int timeperiod=-2**31 , double nbdevup=-4e37 , double nbdevdn=-4e37 , int matype=0 ): @@ -512,7 +512,7 @@ def stream_BBANDS( np.ndarray real not None , int timeperiod=-2**31 , double nbd Inputs: real: (any ndarray) Parameters: - timeperiod: 5 + timeperiod: 20 nbdevup: 2.0 nbdevdn: 2.0 matype: 0 (Simple Moving Average) @@ -757,7 +757,7 @@ def stream_CDL3INSIDE( np.ndarray open not None , np.ndarray high not None , np. def stream_CDL3LINESTRIKE( np.ndarray open not None , np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): """ CDL3LINESTRIKE(open, high, low, close) - Three-Line Strike (Pattern Recognition) + Three-Line Strike (Pattern Recognition) Inputs: prices: ['open', 'high', 'low', 'close'] @@ -2881,6 +2881,34 @@ def stream_CEIL( np.ndarray real not None ): _ta_check_success("TA_CEIL", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_CMF( np.ndarray high not None , np.ndarray low not None , np.ndarray close not None , np.ndarray volume not None , int timeperiod=-2**31 ): + """ CMF(high, low, close, volume[, timeperiod=?])""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* high_data + double* low_data + double* close_data + double* volume_data + int outbegidx + int outnbelement + double outreal + high = check_array(high) + high_data = high.data + low = check_array(low) + low_data = low.data + close = check_array(close) + close_data = close.data + volume = check_array(volume) + volume_data = volume.data + length = check_length4(high, low, close, volume) + outreal = NaN + retCode = lib.TA_CMF( (length) - 1 , (length) - 1 , high_data , low_data , close_data , volume_data , timeperiod , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_CMF", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_CMO( np.ndarray real not None , int timeperiod=-2**31 ): @@ -2910,6 +2938,25 @@ def stream_CMO( np.ndarray real not None , int timeperiod=-2**31 ): _ta_check_success("TA_CMO", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_CMOU( np.ndarray real not None , int timeperiod=-2**31 ): + """ CMOU(real[, timeperiod=?])""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* real_data + int outbegidx + int outnbelement + double outreal + real = check_array(real) + real_data = real.data + length = real.shape[0] + outreal = NaN + retCode = lib.TA_CMOU( (length) - 1 , (length) - 1 , real_data , timeperiod , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_CMOU", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_CORREL( np.ndarray real0 not None , np.ndarray real1 not None , int timeperiod=-2**31 ): @@ -3175,6 +3222,25 @@ def stream_FLOOR( np.ndarray real not None ): _ta_check_success("TA_FLOOR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_HMA( np.ndarray real not None , int timeperiod=-2**31 ): + """ HMA(real[, timeperiod=?])""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* real_data + int outbegidx + int outnbelement + double outreal + real = check_array(real) + real_data = real.data + length = real.shape[0] + outreal = NaN + retCode = lib.TA_HMA( (length) - 1 , (length) - 1 , real_data , timeperiod , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_HMA", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_HT_DCPERIOD( np.ndarray real not None ): @@ -4255,6 +4321,28 @@ def stream_NATR( np.ndarray high not None , np.ndarray low not None , np.ndarray _ta_check_success("TA_NATR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_NVI( np.ndarray close not None , np.ndarray volume not None ): + """ NVI(close, volume)""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* close_data + double* volume_data + int outbegidx + int outnbelement + double outreal + close = check_array(close) + close_data = close.data + volume = check_array(volume) + volume_data = volume.data + length = check_length2(close, volume) + outreal = NaN + retCode = lib.TA_NVI( (length) - 1 , (length) - 1 , close_data , volume_data , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_NVI", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_OBV( np.ndarray real not None , np.ndarray volume not None ): @@ -4355,7 +4443,7 @@ def stream_PLUS_DM( np.ndarray high not None , np.ndarray low not None , int tim @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function -def stream_PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=0 ): +def stream_PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=1 ): """ PPO(real[, fastperiod=?, slowperiod=?, matype=?]) Percentage Price Oscillator (Momentum Indicators) @@ -4365,7 +4453,7 @@ def stream_PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperio Parameters: fastperiod: 12 slowperiod: 26 - matype: 0 (Simple Moving Average) + matype: 1 (Exponential Moving Average) Outputs: real """ @@ -4384,6 +4472,47 @@ def stream_PPO( np.ndarray real not None , int fastperiod=-2**31 , int slowperio _ta_check_success("TA_PPO", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_PVI( np.ndarray close not None , np.ndarray volume not None ): + """ PVI(close, volume)""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* close_data + double* volume_data + int outbegidx + int outnbelement + double outreal + close = check_array(close) + close_data = close.data + volume = check_array(volume) + volume_data = volume.data + length = check_length2(close, volume) + outreal = NaN + retCode = lib.TA_PVI( (length) - 1 , (length) - 1 , close_data , volume_data , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_PVI", retCode) + return outreal + +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_PVO( np.ndarray volume not None , int fastperiod=-2**31 , int slowperiod=-2**31 , int matype=0 ): + """ PVO(volume[, fastperiod=?, slowperiod=?, matype=?])""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* volume_data + int outbegidx + int outnbelement + double outreal + volume = check_array(volume) + volume_data = volume.data + length = volume.shape[0] + outreal = NaN + retCode = lib.TA_PVO( (length) - 1 , (length) - 1 , volume_data , fastperiod , slowperiod , matype , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_PVO", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_ROC( np.ndarray real not None , int timeperiod=-2**31 ): @@ -5251,6 +5380,28 @@ def stream_VAR( np.ndarray real not None , int timeperiod=-2**31 , double nbdev= _ta_check_success("TA_VAR", retCode) return outreal +@wraparound(False) # turn off relative indexing from end of lists +@boundscheck(False) # turn off bounds-checking for entire function +def stream_VWMA( np.ndarray real not None , np.ndarray volume not None , int timeperiod=-2**31 ): + """ VWMA(real, volume[, timeperiod=?])""" + cdef: + np.npy_intp length + TA_RetCode retCode + double* real_data + double* volume_data + int outbegidx + int outnbelement + double outreal + real = check_array(real) + real_data = real.data + volume = check_array(volume) + volume_data = volume.data + length = check_length2(real, volume) + outreal = NaN + retCode = lib.TA_VWMA( (length) - 1 , (length) - 1 , real_data , volume_data , timeperiod , &outbegidx , &outnbelement , &outreal ) + _ta_check_success("TA_VWMA", retCode) + return outreal + @wraparound(False) # turn off relative indexing from end of lists @boundscheck(False) # turn off bounds-checking for entire function def stream_WCLPRICE( np.ndarray high not None , np.ndarray low not None , np.ndarray close not None ): diff --git a/talib/_ta_lib.pxd b/talib/_ta_lib.pxd index 03e015e6c..75ed55487 100644 --- a/talib/_ta_lib.pxd +++ b/talib/_ta_lib.pxd @@ -355,8 +355,12 @@ cdef extern from "ta-lib/ta_func.h": int TA_CDLXSIDEGAP3METHODS_Lookback() TA_RetCode TA_CEIL(int startIdx, int endIdx, const double inReal[], int *outBegIdx, int *outNBElement, double outReal[]) int TA_CEIL_Lookback() + TA_RetCode TA_CMF(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], const double inVolume[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) + int TA_CMF_Lookback(int optInTimePeriod) TA_RetCode TA_CMO(int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) int TA_CMO_Lookback(int optInTimePeriod) + TA_RetCode TA_CMOU(int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) + int TA_CMOU_Lookback(int optInTimePeriod) TA_RetCode TA_CORREL(int startIdx, int endIdx, const double inReal0[], const double inReal1[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) int TA_CORREL_Lookback(int optInTimePeriod) TA_RetCode TA_COS(int startIdx, int endIdx, const double inReal[], int *outBegIdx, int *outNBElement, double outReal[]) @@ -375,6 +379,8 @@ cdef extern from "ta-lib/ta_func.h": int TA_EXP_Lookback() TA_RetCode TA_FLOOR(int startIdx, int endIdx, const double inReal[], int *outBegIdx, int *outNBElement, double outReal[]) int TA_FLOOR_Lookback() + TA_RetCode TA_HMA(int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) + int TA_HMA_Lookback(int optInTimePeriod) TA_RetCode TA_HT_DCPERIOD(int startIdx, int endIdx, const double inReal[], int *outBegIdx, int *outNBElement, double outReal[]) int TA_HT_DCPERIOD_Lookback() TA_RetCode TA_HT_DCPHASE(int startIdx, int endIdx, const double inReal[], int *outBegIdx, int *outNBElement, double outReal[]) @@ -445,12 +451,18 @@ cdef extern from "ta-lib/ta_func.h": int TA_MULT_Lookback() TA_RetCode TA_NATR(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) int TA_NATR_Lookback(int optInTimePeriod) + TA_RetCode TA_NVI(int startIdx, int endIdx, const double inClose[], const double inVolume[], int *outBegIdx, int *outNBElement, double outReal[]) + int TA_NVI_Lookback() TA_RetCode TA_OBV(int startIdx, int endIdx, const double inReal[], const double inVolume[], int *outBegIdx, int *outNBElement, double outReal[]) int TA_OBV_Lookback() TA_RetCode TA_PLUS_DI(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) int TA_PLUS_DI_Lookback(int optInTimePeriod) TA_RetCode TA_PLUS_DM(int startIdx, int endIdx, const double inHigh[], const double inLow[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) int TA_PLUS_DM_Lookback(int optInTimePeriod) + TA_RetCode TA_PVI(int startIdx, int endIdx, const double inClose[], const double inVolume[], int *outBegIdx, int *outNBElement, double outReal[]) + int TA_PVI_Lookback() + TA_RetCode TA_PVO(int startIdx, int endIdx, const double inVolume[], int optInFastPeriod, int optInSlowPeriod, TA_MAType optInMAType, int *outBegIdx, int *outNBElement, double outReal[]) + int TA_PVO_Lookback(int optInFastPeriod, int optInSlowPeriod, TA_MAType optInMAType) TA_RetCode TA_PPO(int startIdx, int endIdx, const double inReal[], int optInFastPeriod, int optInSlowPeriod, TA_MAType optInMAType, int *outBegIdx, int *outNBElement, double outReal[]) int TA_PPO_Lookback(int optInFastPeriod, int optInSlowPeriod, TA_MAType optInMAType) TA_RetCode TA_ROC(int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) @@ -509,6 +521,8 @@ cdef extern from "ta-lib/ta_func.h": int TA_ULTOSC_Lookback(int optInTimePeriod1, int optInTimePeriod2, int optInTimePeriod3) TA_RetCode TA_VAR(int startIdx, int endIdx, const double inReal[], int optInTimePeriod, double optInNbDev, int *outBegIdx, int *outNBElement, double outReal[]) int TA_VAR_Lookback(int optInTimePeriod, double optInNbDev) + TA_RetCode TA_VWMA(int startIdx, int endIdx, const double inReal[], const double inVolume[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) + int TA_VWMA_Lookback(int optInTimePeriod) TA_RetCode TA_WCLPRICE(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], int *outBegIdx, int *outNBElement, double outReal[]) int TA_WCLPRICE_Lookback() TA_RetCode TA_WILLR(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[]) diff --git a/talib/_ta_lib.pyi b/talib/_ta_lib.pyi index 4356269ff..d657e495f 100644 --- a/talib/_ta_lib.pyi +++ b/talib/_ta_lib.pyi @@ -13,6 +13,8 @@ class MA_Type(Enum): KAMA = 6 MAMA = 7 T3 = 8 + HMA = 9 + DISABLED = 10 #Overlap Studies Functions @@ -34,6 +36,11 @@ def EMA( timeperiod: int= 30 )-> NDArray[np.float64]: ... +def HMA( + real: NDArray[np.float64], + timeperiod: int= 20 + )-> NDArray[np.float64]: ... + def HT_TRENDLINE(real: NDArray[np.float64])-> NDArray[np.float64]: ... def KAMA( @@ -113,6 +120,12 @@ def TRIMA( timeperiod: int= 30 )-> NDArray[np.float64]: ... +def VWMA( + real: NDArray[np.float64], + volume: NDArray[np.float64], + timeperiod: int= 30 + )-> NDArray[np.float64]: ... + def WMA( real: NDArray[np.float64], timeperiod: int= 30 @@ -138,7 +151,7 @@ def APO( real: NDArray[np.float64], fastperiod: int= 12, slowperiod: int= 26, - matype: MA_Type = MA_Type.SMA + matype: MA_Type = MA_Type.EMA )-> NDArray[np.float64]: ... def AROON( @@ -172,6 +185,11 @@ def CMO( timeperiod: int= 14 )-> NDArray[np.float64]: ... +def CMOU( + real: NDArray[np.float64], + timeperiod: int= 14 + )-> NDArray[np.float64]: ... + def DX( high: NDArray[np.float64], low: NDArray[np.float64], @@ -244,7 +262,7 @@ def PPO( real: NDArray[np.float64], fastperiod: int= 12, slowperiod: int= 26, - matype: MA_Type = MA_Type.SMA + matype: MA_Type = MA_Type.EMA )-> NDArray[np.float64]: ... def ROC( @@ -339,11 +357,36 @@ def ADOSC( slowperiod: int= 10 )-> NDArray[np.float64]: ... +def CMF( + high: NDArray[np.float64], + low: NDArray[np.float64], + close: NDArray[np.float64], + volume: NDArray[np.float64], + timeperiod: int= 20 + )-> NDArray[np.float64]: ... + +def NVI( + close: NDArray[np.float64], + volume: NDArray[np.float64] + )-> NDArray[np.float64]: ... + def OBV( close: NDArray[np.float64], volume: NDArray[np.float64] )-> NDArray[np.float64]: ... +def PVI( + close: NDArray[np.float64], + volume: NDArray[np.float64] + )-> NDArray[np.float64]: ... + +def PVO( + volume: NDArray[np.float64], + fastperiod: int= 12, + slowperiod: int= 26, + matype: int= 1 + )-> NDArray[np.float64]: ... + #Volatility Indicator Functions def ATR( @@ -1018,6 +1061,11 @@ def stream_EMA( timeperiod: int= 30 )-> NDArray[np.float64]: ... +def stream_HMA( + real: NDArray[np.float64], + timeperiod: int= 20 + )-> NDArray[np.float64]: ... + def stream_HT_TRENDLINE(real: NDArray[np.float64])-> NDArray[np.float64]: ... def stream_KAMA( @@ -1097,6 +1145,12 @@ def stream_TRIMA( timeperiod: int= 30 )-> NDArray[np.float64]: ... +def stream_VWMA( + real: NDArray[np.float64], + volume: NDArray[np.float64], + timeperiod: int= 30 + )-> NDArray[np.float64]: ... + def stream_WMA( real: NDArray[np.float64], timeperiod: int= 30 @@ -1122,7 +1176,7 @@ def stream_APO( real: NDArray[np.float64], fastperiod: int= 12, slowperiod: int= 26, - matype: MA_Type = MA_Type.SMA + matype: MA_Type = MA_Type.EMA )-> NDArray[np.float64]: ... def stream_AROON( @@ -1156,6 +1210,11 @@ def stream_CMO( timeperiod: int= 14 )-> NDArray[np.float64]: ... +def stream_CMOU( + real: NDArray[np.float64], + timeperiod: int= 14 + )-> NDArray[np.float64]: ... + def stream_DX( high: NDArray[np.float64], low: NDArray[np.float64], @@ -1228,7 +1287,7 @@ def stream_PPO( real: NDArray[np.float64], fastperiod: int= 12, slowperiod: int= 26, - matype: MA_Type = MA_Type.SMA + matype: MA_Type = MA_Type.EMA )-> NDArray[np.float64]: ... def stream_ROC( @@ -1323,11 +1382,36 @@ def stream_ADOSC( slowperiod: int= 10 )-> NDArray[np.float64]: ... +def stream_CMF( + high: NDArray[np.float64], + low: NDArray[np.float64], + close: NDArray[np.float64], + volume: NDArray[np.float64], + timeperiod: int= 20 + )-> NDArray[np.float64]: ... + +def stream_NVI( + close: NDArray[np.float64], + volume: NDArray[np.float64] + )-> NDArray[np.float64]: ... + def stream_OBV( close: NDArray[np.float64], volume: NDArray[np.float64] )-> NDArray[np.float64]: ... +def stream_PVI( + close: NDArray[np.float64], + volume: NDArray[np.float64] + )-> NDArray[np.float64]: ... + +def stream_PVO( + volume: NDArray[np.float64], + fastperiod: int= 12, + slowperiod: int= 26, + matype: int= 1 + )-> NDArray[np.float64]: ... + #Volatility Indicator Functions def stream_ATR( diff --git a/talib/abstract.pyi b/talib/abstract.pyi index ef6c7da26..53d5abb8f 100644 --- a/talib/abstract.pyi +++ b/talib/abstract.pyi @@ -467,13 +467,13 @@ Inputs: Parameters: fastperiod: 12 slowperiod: 26 - matype: 0 (Simple Moving Average) + matype: 1 (Exponential Moving Average) Outputs: real""" @overload -def APO(real: Union[pd.Series, np.ndarray], fastperiod=12, slowperiod=26, matype=0) -> np.ndarray: ... +def APO(real: Union[pd.Series, np.ndarray], fastperiod=12, slowperiod=26, matype=1) -> np.ndarray: ... @overload -def APO(real: pd.DataFrame, fastperiod=12, slowperiod=26, matype=0) -> pd.Series: ... +def APO(real: pd.DataFrame, fastperiod=12, slowperiod=26, matype=1) -> pd.Series: ... """AROON(high, low[, timeperiod=?]) @@ -549,6 +549,12 @@ def CMO(real: Union[pd.Series, np.ndarray], timeperiod=14) -> np.ndarray: ... @overload def CMO(real: pd.DataFrame, timeperiod=14) -> pd.Series: ... +"""CMOU(real[, timeperiod=?])""" +@overload +def CMOU(real: Union[pd.Series, np.ndarray], timeperiod=14) -> np.ndarray: ... +@overload +def CMOU(real: pd.DataFrame, timeperiod=14) -> pd.Series: ... + """DX(high, low, close[, timeperiod=?]) Directional Movement Index (Momentum Indicators) @@ -564,6 +570,21 @@ def DX(real: Union[pd.Series, np.ndarray], timeperiod=14) -> np.ndarray: ... @overload def DX(real: pd.DataFrame, timeperiod=14) -> pd.Series: ... +"""IMI(open, close[, timeperiod=?]) + +Intraday Momentum Index (Momentum Indicators) + +Inputs: + prices: ['open', 'close'] +Parameters: + timeperiod: 14 +Outputs: + real""" +@overload +def IMI(real: Union[pd.Series, np.ndarray], timeperiod=14) -> np.ndarray: ... +@overload +def IMI(real: pd.DataFrame, timeperiod=14) -> pd.Series: ... + """MACD(real[, fastperiod=?, slowperiod=?, signalperiod=?]) Moving Average Convergence/Divergence (Momentum Indicators) @@ -721,13 +742,13 @@ Inputs: Parameters: fastperiod: 12 slowperiod: 26 - matype: 0 (Simple Moving Average) + matype: 1 (Exponential Moving Average) Outputs: real""" @overload -def PPO(real: Union[pd.Series, np.ndarray], fastperiod=12, slowperiod=26, matype=0) -> np.ndarray: ... +def PPO(real: Union[pd.Series, np.ndarray], fastperiod=12, slowperiod=26, matype=1) -> np.ndarray: ... @overload -def PPO(real: pd.DataFrame, fastperiod=12, slowperiod=26, matype=0) -> pd.Series: ... +def PPO(real: pd.DataFrame, fastperiod=12, slowperiod=26, matype=1) -> pd.Series: ... """ROC(real[, timeperiod=?]) @@ -908,6 +929,23 @@ def WILLR(real: Union[pd.Series, np.ndarray], timeperiod=14) -> np.ndarray: ... @overload def WILLR(real: pd.DataFrame, timeperiod=14) -> pd.Series: ... +"""ACCBANDS(high, low, close[, timeperiod=?]) + +Acceleration Bands (Overlap Studies) + +Inputs: + prices: ['high', 'low', 'close'] +Parameters: + timeperiod: 20 +Outputs: + upperband + middleband + lowerband""" +@overload +def ACCBANDS(real: Union[pd.Series, np.ndarray], timeperiod=20) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: ... +@overload +def ACCBANDS(real: pd.DataFrame, timeperiod=20) -> pd.DataFrame: ... + """BBANDS(real[, timeperiod=?, nbdevup=?, nbdevdn=?, matype=?]) Bollinger Bands (Overlap Studies) @@ -915,7 +953,7 @@ Bollinger Bands (Overlap Studies) Inputs: real: (any ndarray) Parameters: - timeperiod: 5 + timeperiod: 20 nbdevup: 2.0 nbdevdn: 2.0 matype: 0 (Simple Moving Average) @@ -924,9 +962,9 @@ Outputs: middleband lowerband""" @overload -def BBANDS(real: Union[pd.Series, np.ndarray], timeperiod=5, nbdevup=2.0, nbdevdn=2.0, matype=0) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: ... +def BBANDS(real: Union[pd.Series, np.ndarray], timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: ... @overload -def BBANDS(real: pd.DataFrame, timeperiod=5, nbdevup=2.0, nbdevdn=2.0, matype=0) -> pd.DataFrame: ... +def BBANDS(real: pd.DataFrame, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0) -> pd.DataFrame: ... """DEMA(real[, timeperiod=?]) @@ -958,6 +996,12 @@ def EMA(real: Union[pd.Series, np.ndarray], timeperiod=30) -> np.ndarray: ... @overload def EMA(real: pd.DataFrame, timeperiod=30) -> pd.Series: ... +"""HMA(real[, timeperiod=?])""" +@overload +def HMA(real: Union[pd.Series, np.ndarray], timeperiod=20) -> np.ndarray: ... +@overload +def HMA(real: pd.DataFrame, timeperiod=20) -> pd.Series: ... + """HT_TRENDLINE(real) Hilbert Transform - Instantaneous Trendline (Overlap Studies) @@ -1166,6 +1210,12 @@ def TRIMA(real: Union[pd.Series, np.ndarray], timeperiod=30) -> np.ndarray: ... @overload def TRIMA(real: pd.DataFrame, timeperiod=30) -> pd.Series: ... +"""VWMA(real, volume[, timeperiod=?])""" +@overload +def VWMA(real: Union[pd.Series, np.ndarray], timeperiod=30) -> np.ndarray: ... +@overload +def VWMA(real: pd.DataFrame, timeperiod=30) -> pd.Series: ... + """WMA(real[, timeperiod=?]) Weighted Moving Average (Overlap Studies) @@ -1222,7 +1272,7 @@ def CDL3INSIDE(real: pd.DataFrame) -> pd.Series: ... """CDL3LINESTRIKE(open, high, low, close) -Three-Line Strike (Pattern Recognition) +Three-Line Strike (Pattern Recognition) Inputs: prices: ['open', 'high', 'low', 'close'] @@ -1988,6 +2038,21 @@ def CDLXSIDEGAP3METHODS(real: Union[pd.Series, np.ndarray]) -> np.ndarray: ... @overload def CDLXSIDEGAP3METHODS(real: pd.DataFrame) -> pd.Series: ... +"""AVGDEV(real[, timeperiod=?]) + +Average Deviation (Price Transform) + +Inputs: + real: (any ndarray) +Parameters: + timeperiod: 14 +Outputs: + real""" +@overload +def AVGDEV(real: Union[pd.Series, np.ndarray], timeperiod=14) -> np.ndarray: ... +@overload +def AVGDEV(real: pd.DataFrame, timeperiod=14) -> pd.Series: ... + """AVGPRICE(open, high, low, close) Average Price (Price Transform) @@ -2251,6 +2316,18 @@ def ADOSC(real: Union[pd.Series, np.ndarray], fastperiod=3, slowperiod=10) -> np @overload def ADOSC(real: pd.DataFrame, fastperiod=3, slowperiod=10) -> pd.Series: ... +"""CMF(high, low, close, volume[, timeperiod=?])""" +@overload +def CMF(real: Union[pd.Series, np.ndarray], timeperiod=20) -> np.ndarray: ... +@overload +def CMF(real: pd.DataFrame, timeperiod=20) -> pd.Series: ... + +"""NVI(close, volume)""" +@overload +def NVI(real: Union[pd.Series, np.ndarray]) -> np.ndarray: ... +@overload +def NVI(real: pd.DataFrame) -> pd.Series: ... + """OBV(real, volume) On Balance Volume (Volume Indicators) @@ -2265,3 +2342,15 @@ def OBV(real: Union[pd.Series, np.ndarray]) -> np.ndarray: ... @overload def OBV(real: pd.DataFrame) -> pd.Series: ... +"""PVI(close, volume)""" +@overload +def PVI(real: Union[pd.Series, np.ndarray]) -> np.ndarray: ... +@overload +def PVI(real: pd.DataFrame) -> pd.Series: ... + +"""PVO(volume[, fastperiod=?, slowperiod=?, matype=?])""" +@overload +def PVO(real: Union[pd.Series, np.ndarray], fastperiod=12, slowperiod=26, matype=1) -> np.ndarray: ... +@overload +def PVO(real: pd.DataFrame, fastperiod=12, slowperiod=26, matype=1) -> pd.Series: ... + diff --git a/tests/test_abstract.py b/tests/test_abstract.py index c7440e58c..f78ed1bdf 100644 --- a/tests/test_abstract.py +++ b/tests/test_abstract.py @@ -134,7 +134,7 @@ def test_info(): stochrsi.parameters = {'fastd_matype': talib.MA_Type.EMA} expected = { 'display_name': 'Stochastic Relative Strength Index', - 'function_flags': ['Function has an unstable period'], + 'function_flags': ['Function has a streaming API'], 'group': 'Momentum Indicators', 'input_names': OrderedDict([('price', 'open')]), 'name': 'STOCHRSI', @@ -154,7 +154,8 @@ def test_info(): expected = { 'display_name': 'Bollinger Bands', - 'function_flags': ['Output scale same as input'], + 'function_flags': ['Output scale same as input', + 'Function has a streaming API'], 'group': 'Overlap Studies', 'input_names': OrderedDict([('price', 'close')]), 'name': 'BBANDS', @@ -165,7 +166,7 @@ def test_info(): ]), 'output_names': ['upperband', 'middleband', 'lowerband'], 'parameters': OrderedDict([ - ('timeperiod', 5), + ('timeperiod', 20), ('nbdevup', 2), ('nbdevdn', 2), ('matype', 0), diff --git a/tests/test_func.py b/tests/test_func.py index cde20baa7..2057273fa 100644 --- a/tests/test_func.py +++ b/tests/test_func.py @@ -7,11 +7,11 @@ def test_talib_version(): - assert talib.__ta_version__[:5] == b'0.7.1' + assert talib.__ta_version__[:5] == b'0.8.1' def test_num_functions(): - assert len(talib.get_functions()) == 161 + assert len(talib.get_functions()) == 168 def test_input_wrong_type(): @@ -293,3 +293,36 @@ def test_MAXINDEX(): d = np.array([1., 2, 3]) e = func.MAXINDEX(d, 10) assert_array_equal(e, [0,0,0]) + + +# Functions added in TA-Lib C 0.8.1. Just a smoke test: shape, dtype and a +# plausible lookback, so a wiring mistake in _func.pxi/_ta_lib.pxd is caught. +@pytest.mark.parametrize('name,args,kwargs', [ + ('CMF', ('high', 'low', 'close', 'volume'), {}), + ('CMOU', ('real',), {}), + ('HMA', ('real',), {}), + ('NVI', ('close', 'volume'), {}), + ('PVI', ('close', 'volume'), {}), + ('PVO', ('volume',), {}), + ('VWMA', ('real', 'volume'), {}), +]) +def test_0_8_1_functions(name, args, kwargs): + n = 200 + rs = np.random.RandomState(2) + series = { + 'real': np.cumsum(rs.randn(n)) + 100.0, + 'volume': rs.rand(n) * 1e6 + 1e5, + } + series['close'] = series['real'] + series['high'] = series['real'] + 1.0 + series['low'] = series['real'] - 1.0 + result = getattr(func, name)(*[series[a] for a in args], **kwargs) + assert result.dtype == np.float64 + assert len(result) == n + assert np.isfinite(result[-1]) + + +def test_MA_HMA(): + # TA_MAType_HMA (9) is new in TA-Lib C 0.8.1 + a = np.cumsum(np.random.RandomState(3).randn(200)) + 100.0 + assert_array_equal(func.MA(a, 20, talib.MA_Type.HMA), func.HMA(a, 20)) diff --git a/tools/build_talib_linux.sh b/tools/build_talib_linux.sh index 361519c34..fd00a2201 100644 --- a/tools/build_talib_linux.sh +++ b/tools/build_talib_linux.sh @@ -1,6 +1,6 @@ #!/bin/bash -TALIB_C_VER="${TALIB_C_VER:=0.7.1}" +TALIB_C_VER="${TALIB_C_VER:=0.8.1}" CMAKE_GENERATOR="Unix Makefiles" CMAKE_BUILD_TYPE=Release CMAKE_CONFIGURATION_TYPES=Release diff --git a/tools/build_talib_macos.sh b/tools/build_talib_macos.sh index 361519c34..fd00a2201 100644 --- a/tools/build_talib_macos.sh +++ b/tools/build_talib_macos.sh @@ -1,6 +1,6 @@ #!/bin/bash -TALIB_C_VER="${TALIB_C_VER:=0.7.1}" +TALIB_C_VER="${TALIB_C_VER:=0.8.1}" CMAKE_GENERATOR="Unix Makefiles" CMAKE_BUILD_TYPE=Release CMAKE_CONFIGURATION_TYPES=Release diff --git a/tools/build_talib_windows.cmd b/tools/build_talib_windows.cmd index 187009e75..4efc18df4 100644 --- a/tools/build_talib_windows.cmd +++ b/tools/build_talib_windows.cmd @@ -1,7 +1,7 @@ :: Download and build TA-Lib @echo on -if not defined TALIB_C_VER set TALIB_C_VER=0.7.1 +if not defined TALIB_C_VER set TALIB_C_VER=0.8.1 set CMAKE_GENERATOR=NMake Makefiles set CMAKE_BUILD_TYPE=Release diff --git a/tools/generate_func.py b/tools/generate_func.py index 6dbb4b100..121a3cc55 100644 --- a/tools/generate_func.py +++ b/tools/generate_func.py @@ -61,6 +61,13 @@ functions = [s for s in functions if not s.startswith('TA_RetCode TA_Set')] functions = [s for s in functions if not s.startswith('TA_RetCode TA_Restore')] +# strip TA-Lib C's own streaming API (ta-lib >= 0.8.1), which declares +# TA__Open/_OpenAndFill/_Update/_Peek/_Close taking an opaque stream +# handle. talib's stream_* wrappers are generated from the batch functions +# instead, so these declarations are not usable here. +functions = [s for s in functions + if not re.match(r'TA_RetCode TA_\w+_(Open|OpenAndFill|Update|Peek|Close)\s*\(', s)] + # print headers print("""\ cimport numpy as np diff --git a/tools/generate_stream.py b/tools/generate_stream.py index 7d6af3f68..fc5c2e632 100644 --- a/tools/generate_stream.py +++ b/tools/generate_stream.py @@ -61,6 +61,13 @@ functions = [s for s in functions if not s.startswith('TA_RetCode TA_Set')] functions = [s for s in functions if not s.startswith('TA_RetCode TA_Restore')] +# strip TA-Lib C's own streaming API (ta-lib >= 0.8.1), which declares +# TA__Open/_OpenAndFill/_Update/_Peek/_Close taking an opaque stream +# handle. talib's stream_* wrappers are generated from the batch functions +# instead, so these declarations are not usable here. +functions = [s for s in functions + if not re.match(r'TA_RetCode TA_\w+_(Open|OpenAndFill|Update|Peek|Close)\s*\(', s)] + # print headers print("""\ cimport numpy as np