diff --git a/README.md b/README.md
index 0678f06..456c6fa 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Pandas TA - A Technical Analysis Library in Python 3
[](https://pypistats.org/packages/pandas_ta)
[](#stars)
[](#forks)
-[](#usedby)
+[](#usedby)
[](#contributors)
[](#issues)
[](#closed-issues)
@@ -43,6 +43,9 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* [Help](#help)
* [Issues and Contributions](#issues-and-contributions)
* [Programming Conventions](#programming-conventions)
+ * [Standard](#standard)
+ * [Pandas TA DataFrame Extension](#pandas-ta-dataframe-extension)
+ * [Pandas TA Strategy](#pandas-ta-strategy)
* [Pandas TA Strategies](#pandas-ta-strategies)
* [Types of Strategies](#types-of-strategies)
* [DataFrame Properties](#dataframe-properties)
@@ -50,7 +53,7 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* [Indicators by Category](#indicators-by-category)
* [Candles](#candles-64)
* [Cycles](#cycles-1)
- * [Momentum](#momentum-39)
+ * [Momentum](#momentum-40)
* [Overlap](#overlap-32)
* [Performance](#performance-3)
* [Statistics](#statistics-9)
@@ -107,7 +110,7 @@ $ pip install pandas_ta
Latest Version
--------------
-Best choice! Version: *0.2.88b*
+Best choice! Version: *0.2.89b*
```sh
$ pip install -U git+https://github.com/twopirllc/pandas-ta
```
@@ -195,7 +198,7 @@ Thanks for using **Pandas TA**!
* The indicator does not match another website, library, broker platform, language, et al.
* Do you have correlation analysis to back your claim?
* Can you contribute?
- * You will be asked to fill out an Issue even if you email my personal email address.
+ * You **will** be asked to fill out an Issue even if you email my personally.
@@ -203,9 +206,9 @@ Thanks for using **Pandas TA**!
**Contributors**
================
-_Thank you for your contributions!_
+_Thank you for your contributions!_
-[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [CMobley7](https://github.com/CMobley7) | [codesutras](https://github.com/codesutras) | [DrPaprikaa](https://github.com/DrPaprikaa) | [daikts](https://github.com/daikts) | [dorren](https://github.com/dorren) | [edwardwang1](https://github.com/edwardwang1) | [ffhirata](https://github.com/ffhirata) | [FGU1](https://github.com/FGU1) | [floatinghotpot](https://github.com/floatinghotpot) | [GSlinger](https://github.com/gslinger) | [JoeSchr](https://github.com/JoeSchr) | [lluissalord](https://github.com/lluissalord) | [luisbarrancos](https://github.com/luisbarrancos) | [M6stafa](https://github.com/M6stafa) | [maxdignan](https://github.com/maxdignan) | [mchant](https://github.com/mchant) | [moritzgun](https://github.com/moritzgun) | [nicoloridulfo](https://github.com/nicoloridulfo) [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rengel8](https://github.com/rengel8) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [WellMaybeItIs](https://github.com/WellMaybeItIs) | [whubsch](https://github.com/whubsch) | [witokondoria](https://github.com/witokondoria) | [wouldayajustlookatit](https://github.com/wouldayajustlookatit) | [YuvalWein](https://github.com/YuvalWein)
+[AbyssAlora](https://github.com/AbyssAlora) | [alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [CMobley7](https://github.com/CMobley7) | [codesutras](https://github.com/codesutras) | [DrPaprikaa](https://github.com/DrPaprikaa) | [daikts](https://github.com/daikts) | [dorren](https://github.com/dorren) | [edwardwang1](https://github.com/edwardwang1) | [ffhirata](https://github.com/ffhirata) | [FGU1](https://github.com/FGU1) | [floatinghotpot](https://github.com/floatinghotpot) | [GSlinger](https://github.com/gslinger) | [JoeSchr](https://github.com/JoeSchr) | [lluissalord](https://github.com/lluissalord) | [luisbarrancos](https://github.com/luisbarrancos) | [M6stafa](https://github.com/M6stafa) | [maxdignan](https://github.com/maxdignan) | [mchant](https://github.com/mchant) | [moritzgun](https://github.com/moritzgun) | [nicoloridulfo](https://github.com/nicoloridulfo) [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rengel8](https://github.com/rengel8) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [WellMaybeItIs](https://github.com/WellMaybeItIs) | [whubsch](https://github.com/whubsch) | [witokondoria](https://github.com/witokondoria) | [wouldayajustlookatit](https://github.com/wouldayajustlookatit) | [YuvalWein](https://github.com/YuvalWein)
@@ -661,7 +664,7 @@ df = df.ta.cdl_pattern(name=["doji", "inside"])
-### **Momentum** (39)
+### **Momentum** (40)
* _Awesome Oscillator_: **ao**
* _Absolute Price Oscillator_: **apo**
* _Bias_: **bias**
@@ -674,6 +677,7 @@ df = df.ta.cdl_pattern(name=["doji", "inside"])
* _Coppock Curve_: **coppock**
* _Correlation Trend Indicator_: **cti**
* A wrapper for ```ta.linreg(series, r=True)```
+* _Directional Movement_: **dm**
* _Efficiency Ratio_: **er**
* _Elder Ray Index_: **eri**
* _Fisher Transform_: **fisher**
@@ -725,7 +729,7 @@ df = df.ta.cdl_pattern(name=["doji", "inside"])
* _Hull Exponential Moving Average_: **hma**
* _Holt-Winter Moving Average_: **hwma**
* _Ichimoku Kinkō Hyō_: **ichimoku**
- * Use: help(ta.ichimoku). Returns two DataFrames.
+ * Returns two DataFrames. For more information: ```help(ta.ichimoku)```.
* Drop the Chikou Span Column, the final column of the first resultant DataFrame, remove potential data leak.
* _Kaufman's Adaptive Moving Average_: **kama**
* _Linear Regression_: **linreg**
@@ -942,7 +946,7 @@ print(pf.returns_stats())
-## **Breaking Indicators**
+## **Breaking / Depreciated Indicators**
* _Trend Return_ (**trend_return**) has been removed and replaced with **tsignals**. When given a trend Series like ```close > sma(close, 50)``` it returns the Trend, Trade Entries and Trade Exits of that trend to make it compatible with [**vectorbt**](https://github.com/polakowo/vectorbt) by setting ```asbool=True``` to get boolean Trade Entries and Exits. See: ```help(ta.tsignals)```
@@ -954,10 +958,10 @@ trading account, or fund. See: ```help(ta.drawdown)```
* _Candle Z Score_ (**cdl_z**) normalizes OHLC Candles with a rolling Z Score. See: ```help(ta.cdl_z)```
* _Correlation Trend Indicator_ (**cti**) is an oscillator created by John Ehler in 2020. See: ```help(ta.cti)```
* _Cross Signals_ (**xsignals**) was created by Kevin Johnson. It is a wrapper of Trade Signals that returns Trends, Trades, Entries and Exits. Cross Signals are commonly used for **bbands**, **rsi**, **zscore** crossing some value either above or below two values at different times. See: ```help(ta.xsignals)```
+* _Directional Movement_ (**dm**) developed by J. Welles Wilder in 1978 attempts to determine which direction the price of an asset is moving. See: ```help(ta.dm)```
* _Even Better Sinewave_ (**ebsw**) measures market cycles and uses a low pass filter to remove noise. See: ```help(ta.ebsw)```
* _Klinger Volume Oscillator_ (**kvo**) was developed by Stephen J. Klinger. It is designed to predict price reversals in a market by comparing volume to price.. See: ```help(ta.kvo)```
-* _Schaff Trend Cycle_ (**stc**) is an evolution of the popular MACD incorportating two
-cascaded stochastic calculations with additional smoothing. See: ```help(ta.stc)```
+* _Schaff Trend Cycle_ (**stc**) is an evolution of the popular MACD incorportating two cascaded stochastic calculations with additional smoothing. See: ```help(ta.stc)```
* _Tom DeMark's Sequential_ (**td_seq**) attempts to identify a price point where an uptrend or a downtrend exhausts itself and reverses. Currently exlcuded from ```df.ta.strategy()``` for performance reasons. See: ```help(ta.td_seq)```
* _Vertical Horizontal Filter_ (**vhf**) was created by Adam White to identify trending and ranging markets.. See: ```help(ta.vhf)```
@@ -972,7 +976,7 @@ cascaded stochastic calculations with additional smoothing. See: ```help(ta.stc)
* _Chande Kroll Stop_ (**cksp**): Added ```tvmode``` with default ```True```. When ```tvmode=False```, **cksp** implements “The New Technical Trader” with default values. See ```help(ta.cksp)```.
* _Decreasing_ (**decreasing**): New argument ```strict``` checks if the series is continuously decreasing over period ```length``` with a faster calculation. Default: ```False```. The ```percent``` argument has also been added with default None. See ```help(ta.decreasing)```.
* _Increasing_ (**increasing**): New argument ```strict``` checks if the series is continuously increasing over period ```length``` with a faster calculation. Default: ```False```. The ```percent``` argument has also been added with default None. See ```help(ta.increasing)```.
-* _Parabolic Stop and Reverse_ (**psar**): New argument ```af0``` to initialize the Acceleration Factor. ```help(ta.psar)```.
+* _Parabolic Stop and Reverse_ (**psar**): Bug fix and adjustment to match TradingView's ```sar```. New argument ```af0``` to initialize the Acceleration Factor. ```help(ta.psar)```.
* _Volume Weighted Average Price_ (**vwap**): Added a new parameter called ```anchor```. Default: "D" for "Daily". See [Timeseries Offset Aliases](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-offset-aliases) for additional options. **Requires** the DataFrame index to be a DatetimeIndex
* _Z Score_ (**zscore**): Changed return column name from ```Z_length``` to ```ZS_length```.
diff --git a/pandas_ta/cycles/ebsw.py b/pandas_ta/cycles/ebsw.py
index 01bfb51..6fc008b 100644
--- a/pandas_ta/cycles/ebsw.py
+++ b/pandas_ta/cycles/ebsw.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from numpy import cos as npCos
from numpy import exp as npExp
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from numpy import pi as npPi
from numpy import sin as npSin
from numpy import sqrt as npSqrt
diff --git a/pandas_ta/momentum/dm.py b/pandas_ta/momentum/dm.py
index 657152b..68ddb49 100644
--- a/pandas_ta/momentum/dm.py
+++ b/pandas_ta/momentum/dm.py
@@ -1,12 +1,16 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame
+from pandas_ta import Imports
+from pandas_ta.overlap import ma
from pandas_ta.utils import get_offset, verify_series, get_drift, zero
-def dm(high, low, drift=None, offset=None, **kwargs):
+def dm(high, low, length=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: DM"""
# Validate Arguments
+ length = int(length) if length and length > 0 else 14
+ mamode = mamode.lower() if mamode and isinstance(mamode, str) else "rma"
high = verify_series(high)
low = verify_series(low)
drift = get_drift(drift)
@@ -15,27 +19,37 @@ def dm(high, low, drift=None, offset=None, **kwargs):
if high is None or low is None:
return
- up = high - high.shift(drift)
- dn = low.shift(drift) - low
+ if Imports["talib"]:
+ from talib import MINUS_DM, PLUS_DM
+ pos, neg = PLUS_DM(high, low), MINUS_DM(high, low)
+ else:
+ up = high - high.shift(drift)
+ dn = low.shift(drift) - low
- pos = ((up > dn) & (up > 0)) * up
- neg = ((dn > up) & (dn > 0)) * dn
+ pos_ = ((up > dn) & (up > 0)) * up
+ neg_ = ((dn > up) & (dn > 0)) * dn
- pos = pos.apply(zero)
- neg = neg.apply(zero)
+ pos_ = pos_.apply(zero)
+ neg_ = neg_.apply(zero)
+
+ # Not the same values as TA Lib's -+DM (Good First Issue)
+ pos = ma(mamode, pos_, length=length)
+ neg = ma(mamode, neg_, length=length)
# Offset
if offset != 0:
pos = pos.shift(offset)
neg = neg.shift(offset)
- _params = f"_{drift}"
+ _params = f"_{length}"
data = {
- f"+DM{_params}": pos,
- f"-DM{_params}": neg,
+ f"DMP{_params}": pos,
+ f"DMN{_params}": neg,
}
dmdf = DataFrame(data)
+ # print(dmdf.head(20))
+ # print()
dmdf.name = f"DM{_params}"
dmdf.category = "trend"
@@ -43,9 +57,31 @@ def dm(high, low, drift=None, offset=None, **kwargs):
dm.__doc__ = \
- """Directional Movement (DM)
+"""Directional Movement (DM)
-Directional Movement
+The Directional Movement was developed by J. Welles Wilder in 1978 attempts to
+determine which direction the price of an asset is moving. It compares prior
+highs and lows to yield to two series +DM and -DM.
+
+Sources:
+ https://www.tradingview.com/pine-script-reference/#fun_dmi
+ https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=24&Name=Directional_Movement_Index
+
+Calculation:
+ Default Inputs:
+ length=14, mamode="rma", drift=1
+ up = high - high.shift(drift)
+ dn = low.shift(drift) - low
+
+ pos_ = ((up > dn) & (up > 0)) * up
+ neg_ = ((dn > up) & (dn > 0)) * dn
+
+ pos_ = pos_.apply(zero)
+ neg_ = neg_.apply(zero)
+
+ # Not the same values as TA Lib's -+DM
+ pos = ma(mamode, pos_, length=length)
+ neg = ma(mamode, neg_, length=length)
Args:
high (pd.Series): Series of 'high's
@@ -54,5 +90,5 @@ Args:
offset (int): How many periods to offset the result. Default: 0
Returns:
- pd.DataFrame: +DM and -DM columns.
+ pd.DataFrame: DMP (+DM) and DMN (-DM) columns.
"""
diff --git a/pandas_ta/momentum/fisher.py b/pandas_ta/momentum/fisher.py
index f097637..7c0f133 100644
--- a/pandas_ta/momentum/fisher.py
+++ b/pandas_ta/momentum/fisher.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from numpy import log as nplog
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame, Series
from pandas_ta.overlap import ema, hl2
from pandas_ta.utils import get_offset, high_low_range, verify_series, zero
diff --git a/pandas_ta/momentum/rsx.py b/pandas_ta/momentum/rsx.py
index 4ae6dbd..6ee5be1 100644
--- a/pandas_ta/momentum/rsx.py
+++ b/pandas_ta/momentum/rsx.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import concat, DataFrame, Series
from pandas_ta.utils import get_drift, get_offset, verify_series, signals
diff --git a/pandas_ta/momentum/squeeze.py b/pandas_ta/momentum/squeeze.py
index 64e6197..514d149 100644
--- a/pandas_ta/momentum/squeeze.py
+++ b/pandas_ta/momentum/squeeze.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame
from pandas_ta.momentum import mom
from pandas_ta.overlap import ema, linreg, sma
diff --git a/pandas_ta/overlap/alma.py b/pandas_ta/overlap/alma.py
index a98eed6..2107831 100644
--- a/pandas_ta/overlap/alma.py
+++ b/pandas_ta/overlap/alma.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from numpy import exp as npExp
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import Series
from pandas_ta.utils import get_offset, verify_series
diff --git a/pandas_ta/overlap/ema.py b/pandas_ta/overlap/ema.py
index a6e3c7b..105f856 100644
--- a/pandas_ta/overlap/ema.py
+++ b/pandas_ta/overlap/ema.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas_ta import Imports
from pandas_ta.utils import get_offset, verify_series
diff --git a/pandas_ta/overlap/hilo.py b/pandas_ta/overlap/hilo.py
index bfd7471..5c7250a 100644
--- a/pandas_ta/overlap/hilo.py
+++ b/pandas_ta/overlap/hilo.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame, Series
from .ma import ma
from pandas_ta.utils import get_offset, verify_series
diff --git a/pandas_ta/overlap/kama.py b/pandas_ta/overlap/kama.py
index ab5ec8c..4248459 100644
--- a/pandas_ta/overlap/kama.py
+++ b/pandas_ta/overlap/kama.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import Series
from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
diff --git a/pandas_ta/overlap/linreg.py b/pandas_ta/overlap/linreg.py
index e9d4eb4..00f943b 100644
--- a/pandas_ta/overlap/linreg.py
+++ b/pandas_ta/overlap/linreg.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from numpy import array as npArray
from numpy import arctan as npAtan
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from numpy import pi as npPi
from numpy.lib.stride_tricks import sliding_window_view
from pandas import Series
diff --git a/pandas_ta/overlap/supertrend.py b/pandas_ta/overlap/supertrend.py
index 5fd0f47..644bfbb 100644
--- a/pandas_ta/overlap/supertrend.py
+++ b/pandas_ta/overlap/supertrend.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame
from pandas_ta.overlap import hl2
from pandas_ta.volatility import atr
diff --git a/pandas_ta/trend/psar.py b/pandas_ta/trend/psar.py
index 76ff73b..18fe263 100644
--- a/pandas_ta/trend/psar.py
+++ b/pandas_ta/trend/psar.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame, Series
-from pandas_ta.utils import get_offset, verify_series
from pandas_ta.momentum import dm
+from pandas_ta.utils import get_offset, verify_series, zero
def psar(high, low, close=None, af0=None, af=None, max_af=None, offset=None, **kwargs):
@@ -15,9 +15,16 @@ def psar(high, low, close=None, af0=None, af=None, max_af=None, offset=None, **k
max_af = float(max_af) if max_af and max_af > 0 else 0.2
offset = get_offset(offset)
- _dm = dm(high, low, close)
+ def _falling(high, low, drift:int=1):
+ """Returns the last -DM value"""
+ # Not to be confused with ta.falling()
+ up = high - high.shift(drift)
+ dn = low.shift(drift) - low
+ _dmn = (((dn > up) & (dn > 0)) * dn).apply(zero)[-1]
+ return _dmn > 0
- falling = _dm["-DM_1"].iloc[1] > 0
+ # Falling if the first NaN -DM is positive
+ falling = _falling(high.iloc[:2], low.iloc[:2])
if falling:
sar = high.iloc[0]
ep = low.iloc[0]
@@ -33,50 +40,46 @@ def psar(high, low, close=None, af0=None, af=None, max_af=None, offset=None, **k
short = long.copy()
reversal = Series(False, index=high.index)
_af = long.copy()
- _af.iloc[0:1] = af0
-
- m = high.shape[0]
+ _af.iloc[0:2] = af0
# Calculate Result
+ m = high.shape[0]
for row in range(1, m):
- HIGH = high.iloc[row]
- LOW = low.iloc[row]
+ high_ = high.iloc[row]
+ low_ = low.iloc[row]
if falling:
- new_sar = sar + af * (ep - sar)
- reverse = HIGH > new_sar
+ _sar = sar + af * (ep - sar)
+ reverse = high_ > _sar
- if LOW < ep:
- ep = LOW
+ if low_ < ep:
+ ep = low_
af = min(af + af0, max_af)
- new_sar = max(high.iloc[row - 1], high.iloc[row - 2], new_sar)
+ _sar = max(high.iloc[row - 1], high.iloc[row - 2], _sar)
else:
- new_sar = sar + af * (ep - sar)
- reverse = LOW < new_sar
+ _sar = sar + af * (ep - sar)
+ reverse = low_ < _sar
- if HIGH > ep:
- ep = HIGH
+ if high_ > ep:
+ ep = high_
af = min(af + af0, max_af)
- new_sar = min(low.iloc[row - 1], low.iloc[row - 2], new_sar)
+ _sar = min(low.iloc[row - 1], low.iloc[row - 2], _sar)
if reverse:
- new_sar = ep
+ _sar = ep
af = af0
- falling = not falling
+ falling = not falling # Must come before next line
+ ep = low_ if falling else high_
- if falling:
- ep = LOW
- else:
- ep = HIGH
+ sar = _sar # Update SAR
- sar = new_sar
-
- if not falling:
- long.iloc[row] = sar
- else:
+ # Seperate long/short sar based on falling
+ if falling:
short.iloc[row] = sar
+ else:
+ long.iloc[row] = sar
_af.iloc[row] = af
reversal.iloc[row] = reverse
@@ -118,12 +121,26 @@ def psar(high, low, close=None, af0=None, af=None, max_af=None, offset=None, **k
psar.__doc__ = \
"""Parabolic Stop and Reverse (psar)
-Parabolic Stop and Reverse
+Parabolic Stop and Reverse (PSAR) was developed by J. Wells Wilder, that is used
+to determine trend direction and it's potential reversals in price. PSAR uses a
+trailing stop and reverse method called "SAR," or stop and reverse, to identify
+possible entries and exits. It is also known as SAR.
+
+PSAR indicator typically appears on a chart as a series of dots, either above or
+below an asset's price, depending on the direction the price is moving. A dot is
+placed below the price when it is trending upward, and above the price when it
+is trending downward.
+
+Sources:
+ https://www.tradingview.com/pine-script-reference/#fun_sar
+ https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=66&Name=Parabolic
Calculation:
Default Inputs:
af0=0.02, af=0.02, max_af=0.2
+ See Source links
+
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
diff --git a/pandas_ta/trend/xsignals.py b/pandas_ta/trend/xsignals.py
index 7c08f3a..cf707fb 100644
--- a/pandas_ta/trend/xsignals.py
+++ b/pandas_ta/trend/xsignals.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame
from .tsignals import tsignals
from pandas_ta.utils._signals import cross_value
diff --git a/pandas_ta/utils/_core.py b/pandas_ta/utils/_core.py
index 7fca158..0324689 100644
--- a/pandas_ta/utils/_core.py
+++ b/pandas_ta/utils/_core.py
@@ -4,7 +4,7 @@ from pathlib import Path
from sys import float_info as sflt
from numpy import argmax, argmin
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import DataFrame, Series
from pandas.api.types import is_datetime64_any_dtype
diff --git a/pandas_ta/utils/_math.py b/pandas_ta/utils/_math.py
index e48918d..5bdbdcc 100644
--- a/pandas_ta/utils/_math.py
+++ b/pandas_ta/utils/_math.py
@@ -15,7 +15,7 @@ from numpy import fabs as npFabs
from numpy import floor as npFloor
from numpy import exp as npExp
from numpy import log as npLog
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from numpy import ndarray as npNdArray
from numpy import seterr
from numpy import sqrt as npSqrt
diff --git a/pandas_ta/utils/_metrics.py b/pandas_ta/utils/_metrics.py
index 511e995..f1fbe97 100644
--- a/pandas_ta/utils/_metrics.py
+++ b/pandas_ta/utils/_metrics.py
@@ -2,7 +2,7 @@
from typing import Tuple
from numpy import log as npLog
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from numpy import sqrt as npSqrt
from pandas import Series, Timedelta
diff --git a/pandas_ta/volatility/true_range.py b/pandas_ta/volatility/true_range.py
index 4521517..687b630 100644
--- a/pandas_ta/volatility/true_range.py
+++ b/pandas_ta/volatility/true_range.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from numpy import NaN as npNaN
+from numpy import nan as npNaN
from pandas import concat
from pandas_ta import Imports
from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
diff --git a/setup.py b/setup.py
index e181535..f9feba5 100644
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,7 @@ setup(
"pandas_ta.volatility",
"pandas_ta.volume"
],
- version=".".join(("0", "2", "88b")),
+ version=".".join(("0", "2", "89b")),
description=long_description,
long_description=long_description,
author="Kevin Johnson",
diff --git a/tests/test_indicator_momentum.py b/tests/test_indicator_momentum.py
index 7fbfad3..885eba1 100644
--- a/tests/test_indicator_momentum.py
+++ b/tests/test_indicator_momentum.py
@@ -159,6 +159,29 @@ class TestMomentum(TestCase):
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "ER_10")
+ def test_dm(self):
+ result = pandas_ta.dm(self.high, self.low)
+ self.assertIsInstance(result, DataFrame)
+ self.assertEqual(result.name, "DM_14")
+
+ try:
+ expected_pos = tal.PLUS_DM(self.high, self.low)
+ expected_neg = tal.MINUS_DM(self.high, self.low)
+ expecteddf = DataFrame({"DMP_14": expected_pos, "DMN_14": expected_neg})
+ pdt.assert_frame_equal(result, expecteddf)
+ except AssertionError as ae:
+ try:
+ dmp = pandas_ta.utils.df_error_analysis(result.iloc[:,0], expecteddf.iloc[:,0], col=CORRELATION)
+ self.assertGreater(dmp, CORRELATION_THRESHOLD)
+ except Exception as ex:
+ error_analysis(result, CORRELATION, ex)
+
+ try:
+ dmn = pandas_ta.utils.df_error_analysis(result.iloc[:,1], expecteddf.iloc[:,1], col=CORRELATION)
+ self.assertGreater(dmn, CORRELATION_THRESHOLD)
+ except Exception as ex:
+ error_analysis(result, CORRELATION, ex)
+
def test_eri(self):
result = pandas_ta.eri(self.high, self.low, self.close)
self.assertIsInstance(result, DataFrame)