diff --git a/Makefile b/Makefile index 1beef46f..dd20077d 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ init: test_metrics: pytest -vv -s -l --cache-clear tests/test_metrics.py +test_numba: + pytest -vv -s -l --cache-clear tests/test_numba.py + test_studies: pytest -vv -s -l --cache-clear tests/test_studies.py diff --git a/README.md b/README.md index 902819ec..e879c782 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ $ pip install pandas_ta[full] Development Version ------------------- -The _development_ version, _0.3.95b_, includes _numerous_ bug fixes, speed improvements and better documentation since release, _0.3.14b_. +The _development_ version, _0.3.96b_, includes _numerous_ bug fixes, speed improvements and better documentation since release, _0.3.14b_. ```sh $ pip install -U git+https://github.com/twopirllc/pandas-ta.git@development ``` @@ -538,7 +538,7 @@ df.ta.cores df.ta.ds # Set the Data Source (ds) so that df.ta.ticker() can download ohlcv data. -# Available Data Sources: "yf", "polgon" +# Available Data Sources: "yf", "polygon" df.ta.ds = "yf" ``` diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 9ce4a7a0..9776c572 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -1260,10 +1260,7 @@ def pivots(self, method=None, anchor=None, **kwargs: DictLike): high = self._get_column(kwargs.pop("high", "high")) low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = pivots( - open_=open_, high=high, low=low, close=close, - method=method, anchor=anchor, **kwargs, - ) + result = pivots(open_=open_, high=high, low=low, close=close, method=method, anchor=anchor, **kwargs) return self._post_process(result, **kwargs) def pwma(self, length=None, offset=None, **kwargs: DictLike): diff --git a/pandas_ta/overlap/pivots.py b/pandas_ta/overlap/pivots.py index 0fdf405c..9c95dd02 100644 --- a/pandas_ta/overlap/pivots.py +++ b/pandas_ta/overlap/pivots.py @@ -165,13 +165,14 @@ def pivots( ] method = v_str(method, methods[0]) - dt_index = close.index - if dt_index.size < 3: + if close.index.size < 3: return # Emergency Break if not v_datetime_ordered(close): - dt_index = to_datetime(close.index, unit="ms") + print("[!] Pivots requires a datetime ordered index.") + return + dt_index = close.index freq = infer_freq(dt_index) if anchor and isinstance(anchor, str) and len(anchor) >= 1: @@ -189,6 +190,7 @@ def pivots( "close": close.resample(anchor).last() } ) + df.dropna(inplace=True) else: df = DataFrame( data={"open": open_, "high": high, "low": low, "close": close}, diff --git a/pandas_ta/overlap/sma.py b/pandas_ta/overlap/sma.py index 9814677d..eb607ba9 100644 --- a/pandas_ta/overlap/sma.py +++ b/pandas_ta/overlap/sma.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from numpy import convolve, ndarray, ones +from numpy import convolve, ones from numba import njit from pandas import Series from pandas_ta._typing import Array, DictLike, Int diff --git a/pandas_ta/utils/_core.py b/pandas_ta/utils/_core.py index f98dcdd4..2617ca61 100644 --- a/pandas_ta/utils/_core.py +++ b/pandas_ta/utils/_core.py @@ -168,6 +168,9 @@ def _speed_group( result = [] for i in group: r = df.ta(i, talib=talib, timed=True) + if r is None: + print(f"[S] {i} skipped due to returning None") + continue # ta.pivots() sometimes returns None ms = float(r.timed.split(" ")[0].split(" ")[0]) result.append({index_name: i, "ms": ms, "secs": ms2secs(ms, p)}) return result diff --git a/pandas_ta/utils/_numba.py b/pandas_ta/utils/_numba.py index 08020eb1..7636bb5c 100644 --- a/pandas_ta/utils/_numba.py +++ b/pandas_ta/utils/_numba.py @@ -5,13 +5,22 @@ from pandas_ta._typing import Array, Int, IntFloat __all__ = [ + "np_prenan", "np_prepend", "np_rolling", "np_shift", ] -# Utilities +@njit(cache=True) +def np_prenan(x: Array, n: Int, value: IntFloat = nan) -> Array: + """Prepend n values, typically np.nan, to array x.""" + if n > 0: + x[:n - 1] = value + return x + return x + + @njit(cache=True) def np_prepend(x: Array, n: Int, value: IntFloat = nan) -> Array: """Prepend n values, typically np.nan, to array x.""" diff --git a/pandas_ta/volatility/natr.py b/pandas_ta/volatility/natr.py index 8cfc0226..e4d16098 100644 --- a/pandas_ta/volatility/natr.py +++ b/pandas_ta/volatility/natr.py @@ -66,8 +66,8 @@ def natr( from talib import NATR natr = NATR(high, low, close, length) else: - natr = scalar / close - natr *= atr( + natr = (scalar / close) * \ + atr( high=high, low=low, close=close, length=length, mamode=mamode, drift=drift, talib=mode_tal, offset=offset, **kwargs diff --git a/setup.py b/setup.py index 311f247d..702c9d5f 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ "pandas_ta.volatility", "pandas_ta.volume" ], - version=".".join(("0", "3", "95b")), + version=".".join(("0", "3", "96b")), description=long_description, long_description=long_description, author="Kevin Johnson", diff --git a/tests/test_numba.py b/tests/test_numba.py new file mode 100644 index 00000000..63513237 --- /dev/null +++ b/tests/test_numba.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +import numpy as np +import pandas_ta as ta + +from pytest import mark + + +@mark.parametrize("array,n,result", [ + (np.ones(5), 2, np.array([np.nan, 1.0, 1.0, 1.0, 1.0])), + (np.ones(5), -2, np.ones(5)) +]) +def test_np_prenan(array, n, result): + np.testing.assert_array_equal(ta.np_prenan(array, n), result) + + +@mark.parametrize("array,n,result", [ + (np.ones(5), 2, np.array([np.nan, np.nan, 1.0, 1.0, 1.0, 1.0, 1.0])), + (np.ones(5), -2, np.ones(5)) +]) +def test_np_prepend(array, n, result): + np.testing.assert_array_equal(ta.np_prepend(array, n), result) + + +@mark.parametrize("array,n,fn,result", [(np.ones(5), 2, None, np.ones(5))]) +def test_np_rolling(array, n, fn, result): + np.testing.assert_array_equal(ta.np_rolling(array, n, fn), result) + + +@mark.parametrize("array,n,result", [ + (np.ones(5), 2, np.array([np.nan, np.nan, 1.0, 1.0, 1.0])), + (np.ones(5), -2, np.array([1.0, 1.0, 1.0, np.nan, np.nan])) +]) +def test_np_shift(array, n, result): + np.testing.assert_array_equal(ta.np_shift(array, n), result) diff --git a/tests/test_utils.py b/tests/test_utils.py index 4d940ad0..6c472973 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -277,27 +277,6 @@ def test_inv_norm_value(value, result): assert ta.utils.inv_norm(value) == result -@mark.parametrize("array,window,result", [ - (np.ones(5), 2, np.array([np.nan, np.nan, 1.0, 1.0, 1.0, 1.0, 1.0])), - (np.ones(5), -2, np.ones(5)) -]) -def test_np_prepend(array, window, result): - np.testing.assert_array_equal(ta.np_prepend(array, window), result) - - -@mark.parametrize("array,window,fn,result", [(np.ones(5), 2, None, np.ones(5))]) -def test_np_rolling(array, window, fn, result): - np.testing.assert_array_equal(ta.np_rolling(array, window, fn), result) - - -@mark.parametrize("array,window,result", [ - (np.ones(5), 2, np.array([np.nan, np.nan, 1.0, 1.0, 1.0])), - (np.ones(5), -2, np.array([1.0, 1.0, 1.0, np.nan, np.nan])) -]) -def test_np_shift(array, window, result): - np.testing.assert_array_equal(ta.np_shift(array, window), result) - - def test_symmetric_triangle(): np.testing.assert_array_equal(ta.utils.symmetric_triangle(), np.array([1,1])) np.testing.assert_array_equal(ta.utils.symmetric_triangle(weighted=True), np.array([0.5, 0.5])) @@ -399,5 +378,5 @@ def test_zero(value, result): @mark.parametrize("talib", [False, True]) @mark.parametrize("verbose", [False, True]) def test_indicator_speed_talib_verbose(df, talib, verbose): - resultdf =ta.speed_test(df, talib=talib, verbose=verbose) + resultdf = ta.speed_test(df, talib=talib, verbose=verbose) assert isinstance(resultdf, DataFrame) \ No newline at end of file