BUG Avoidable NaNs Issue #37

This commit is contained in:
Kevin Johnson
2020-04-20 13:50:14 -07:00
parent a1dac5922f
commit 1866016b7b
13 changed files with 53 additions and 37 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def bop(open_, high, low, close, offset=None, **kwargs):
"""Indicator: Balance of Power (BOP)"""
@@ -8,11 +8,11 @@ def bop(open_, high, low, close, offset=None, **kwargs):
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
high_low_range = non_zero_range(high, low)
close_open_range = non_zero_range(close, open_)
offset = get_offset(offset)
# Calculate Result
close_open_range = close - open_
high_low_range = high - low
bop = close_open_range / high_low_range
# Offset
+5 -3
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from ..overlap.swma import swma
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def rvi(open_, high, low, close, length=None, swma_length=None, offset=None, **kwargs):
"""Indicator: RVI"""
@@ -10,13 +10,15 @@ def rvi(open_, high, low, close, length=None, swma_length=None, offset=None, **k
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
high_low_range = non_zero_range(high, low)
close_open_range = non_zero_range(close, open_)
length = int(length) if length and length > 0 else 14
swma_length = int(swma_length) if swma_length and swma_length > 0 else 4
offset = get_offset(offset)
# Calculate Result
numerator = swma(close - open_, length=swma_length).rolling(length).sum()
denominator = swma(high - low, length=swma_length).rolling(length).sum()
numerator = swma(close_open_range, length=swma_length).rolling(length).sum()
denominator = swma(high_low_range, length=swma_length).rolling(length).sum()
rvi = numerator / denominator
signal = swma(rvi, length=swma_length)
+5 -5
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from numpy import NaN as npNaN
from pandas import Series
from ..utils import get_drift, get_offset, verify_series
from pandas import Series, DataFrame
from ..utils import get_drift, get_offset, non_zero_range, verify_series
def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kwargs):
"""Indicator: Kaufman's Adaptive Moving Average (HMA)"""
@@ -17,9 +17,9 @@ def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kw
m = close.size
fr = 2 / (fast + 1)
sr = 2 / (slow + 1)
abs_diff = close.diff(length).abs()
peer_diff = close.diff(drift).abs()
abs_diff = non_zero_range(close, close.shift(length)).abs()
peer_diff = non_zero_range(close, close.shift(drift)).abs()
peer_diff_sum = peer_diff.rolling(length).sum()
er = abs_diff / peer_diff_sum
x = er * (fr - sr) + sr
+2 -2
View File
@@ -4,7 +4,7 @@ from ..overlap.ema import ema
from ..overlap.hma import hma
from ..overlap.rma import rma
from ..overlap.sma import sma
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def qstick(open_, close, length=None, offset=None, **kwargs):
"""Indicator: Q Stick"""
@@ -16,7 +16,7 @@ def qstick(open_, close, length=None, offset=None, **kwargs):
ma = kwargs.pop('ma', 'sma') if 'ma' in kwargs else 'sma'
# Calculate Result
diff = close - open_
diff = non_zero_range(close, open_)
if ma in [None, 'sma']: qstick = sma(diff, length=length)
if ma == 'dema': qstick = dema(diff, length=length, **kwargs)
+11
View File
@@ -117,6 +117,17 @@ def get_offset(x:int):
return int(x) if x else 0
def non_zero_range(high:pd.Series, low:pd.Series):
"""Returns the difference of two series and adds epsilon if
to any zero values. This occurs commonly in crypto data when
high = low.
"""
diff = high - low
if diff.eq(0).any().any():
diff += sflt.epsilon
return diff
def pascals_triangle(n:int =None, **kwargs):
"""Pascal's Triangle
+3 -2
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from ..utils import get_drift, get_offset, verify_series
from ..utils import get_drift, get_offset, non_zero_range, verify_series
def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, offset=None, **kwargs):
"""Indicator: Acceleration Bands (ACCBANDS)"""
@@ -8,6 +8,7 @@ def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, off
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
high_low_range = non_zero_range(high, low)
length = int(length) if length and length > 0 else 20
c = float(c) if c and c > 0 else 4
min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length
@@ -16,7 +17,7 @@ def accbands(high, low, close, length=None, c=None, drift=None, mamode=None, off
offset = get_offset(offset)
# Calculate Result
hl_ratio = (high - low) / (high + low)
hl_ratio = high_low_range / (high + low)
hl_ratio *= c
_lower = low * (1 - hl_ratio)
_upper = high * (1 + hl_ratio)
+2 -2
View File
@@ -4,7 +4,7 @@ from pandas import DataFrame
from .atr import atr
from ..overlap.hlc3 import hlc3
from ..statistics.variance import variance
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **kwargs):
@@ -26,7 +26,7 @@ def kc(high, low, close, length=None, scalar=None, mamode=None, offset=None, **k
basis = close.ewm(span=length, min_periods=min_periods).mean()
band = atr(high=high, low=low, close=close)
else:
hl_range = high - low
hl_range = non_zero_range(high, low)
typical_price = hlc3(high=high, low=low, close=close)
basis = typical_price.rolling(length, min_periods=min_periods).mean()
band = hl_range.rolling(length, min_periods=min_periods).mean()
+3 -3
View File
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
from ..overlap.ema import ema
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def massi(high, low, fast=None, slow=None, offset=None, **kwargs):
"""Indicator: Mass Index (MASSI)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
high_low_range = non_zero_range(high, low)
fast = int(fast) if fast and fast > 0 else 9
slow = int(slow) if slow and slow > 0 else 25
if slow < fast:
@@ -15,8 +16,7 @@ def massi(high, low, fast=None, slow=None, offset=None, **kwargs):
offset = get_offset(offset)
# Calculate Result
hl_range = high - low
hl_ema1 = ema(close=hl_range, length=fast, **kwargs)
hl_ema1 = ema(close=high_low_range, length=fast, **kwargs)
hl_ema2 = ema(close=hl_ema1, length=fast, **kwargs)
hl_ratio = hl_ema1 / hl_ema2
+3 -2
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from ..utils import get_drift, get_offset, verify_series
from ..utils import get_drift, get_offset, non_zero_range, verify_series
def true_range(high, low, close, drift=None, offset=None, **kwargs):
"""Indicator: True Range"""
@@ -8,12 +8,13 @@ def true_range(high, low, close, drift=None, offset=None, **kwargs):
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
high_low_range = non_zero_range(high, low)
drift = get_drift(drift)
offset = get_offset(offset)
# Calculate Result
prev_close = close.shift(drift)
ranges = [high - low, high - prev_close, prev_close - low]
ranges = [high_low_range, high - prev_close, prev_close - low]
true_range = DataFrame(ranges).T
true_range = true_range.abs().max(axis=1)
+7 -7
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def ad(high, low, close, volume, open_=None, offset=None, **kwargs):
"""Indicator: Accumulation/Distribution (AD)"""
@@ -8,17 +8,17 @@ def ad(high, low, close, volume, open_=None, offset=None, **kwargs):
low = verify_series(low)
close = verify_series(close)
volume = verify_series(volume)
high_low_range = non_zero_range(high, low)
offset = get_offset(offset)
# Calculate Result
if open_ is not None:
open_ = verify_series(open_)
ad = close - open_ # AD with Open
else:
ad = 2 * close - high - low # AD with High, Low, Close
hl_range = high - low
ad *= volume / hl_range
ad = non_zero_range(close, open_) # AD with Open
else:
ad = 2 * close - (high + low) # AD with High, Low, Close
ad *= volume / high_low_range
ad = ad.cumsum()
# Offset
+5 -4
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from ..utils import get_offset, verify_series
from ..utils import get_offset, non_zero_range, verify_series
def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs):
"""Indicator: Chaikin Money Flow (CMF)"""
@@ -8,6 +8,7 @@ def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs
low = verify_series(low)
close = verify_series(close)
volume = verify_series(volume)
high_low_range = non_zero_range(high, low)
length = int(length) if length and length > 0 else 20
min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length
offset = get_offset(offset)
@@ -15,11 +16,11 @@ def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs
# Calculate Result
if open_ is not None:
open_ = verify_series(open_)
ad = close - open_ # AD with Open
ad = non_zero_range(close, open_) # AD with Open
else:
ad = 2 * close - high - low # AD with High, Low, Close
ad = 2 * close - (high + low) # AD with High, Low, Close
hl_range = high - low
hl_range = high_low_range
ad *= volume / hl_range
cmf = ad.rolling(length, min_periods=min_periods).sum() / volume.rolling(length, min_periods=min_periods).sum()
+3 -3
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from ..overlap.hl2 import hl2
from ..utils import get_drift, get_offset, verify_series
from ..utils import get_drift, get_offset, non_zero_range, verify_series
def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset=None, **kwargs):
"""Indicator: Ease of Movement (EOM)"""
@@ -9,6 +9,7 @@ def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset=
low = verify_series(low)
close = verify_series(close)
volume = verify_series(volume)
high_low_range = non_zero_range(high, low)
length = int(length) if length and length > 0 else 14
min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length
divisor = divisor if divisor and divisor > 0 else 100000000
@@ -16,9 +17,8 @@ def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset=
offset = get_offset(offset)
# Calculate Result
hl_range = high - low
distance = hl2(high=high, low=low) - hl2(high=high.shift(drift), low=low.shift(drift))
box_ratio = (volume / divisor) / hl_range
box_ratio = (volume / divisor) / high_low_range
eom = distance / box_ratio
eom = eom.rolling(length, min_periods=min_periods).mean()
+1 -1
View File
@@ -6,7 +6,7 @@ long_description = "An easy to use Python 3 Pandas Extension with 80+ Technical
setup(
name ="pandas_ta",
packages =['pandas_ta', 'pandas_ta.momentum', 'pandas_ta.overlap', 'pandas_ta.performance', 'pandas_ta.statistics', 'pandas_ta.trend', 'pandas_ta.volatility', 'pandas_ta.volume'],
version ="0.1.38b",
version ="0.1.39b",
description =long_description,
long_description =long_description,
author ="Kevin Johnson",