mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-08-02 12:50:22 +08:00
BUG Avoidable NaNs Issue #37
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user