mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-06-27 16:10:07 +08:00
@@ -114,7 +114,7 @@ $ pip install pandas_ta
|
||||
|
||||
Latest Version
|
||||
--------------
|
||||
Best choice! Version: *0.3.05b*
|
||||
Best choice! Version: *0.3.06b*
|
||||
* Includes all fixes and updates between **pypi** and what is covered in this README.
|
||||
```sh
|
||||
$ pip install -U git+https://github.com/twopirllc/pandas-ta
|
||||
@@ -987,11 +987,13 @@ of the last bars defined by the length parameter. See ```help(ta.tos_stdevall)``
|
||||
* _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)```.
|
||||
* _Klinger Volume Oscillator_ (**kvo**): Implements TradingView's Klinger Volume Oscillator verion. See ```help(ta.kvo)```.
|
||||
* _Moving Average Convergence Divergence_ (**macd**): New argument ```asmode``` enables AS version of MACD. Default is False. See ```help(ta.macd)```.
|
||||
* _Parabolic Stop and Reverse_ (**psar**): Bug fix and adjustment to match TradingView's ```sar```. New argument ```af0``` to initialize the Acceleration Factor. See ```help(ta.psar)```.
|
||||
* _Percentage Price Oscillator_ (**ppo**): Included new argument ```mamode``` as an option. Default is **sma** to match TA Lib. See ```help(ta.ppo)```.
|
||||
* _Volume Profile_ (**vp**): Calculation improvements. See [Pull Request #320](https://github.com/twopirllc/pandas-ta/pull/320) See ```help(ta.vp)```.
|
||||
* _Volume Weighted Moving Average_ (**vwma**): Fixed bug in DataFrame Extension call. See ```help(ta.vwma)```.
|
||||
* _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. See ```help(ta.vwap)```.
|
||||
* _Volume Weighted Moving Average_ (**vwma**): Fixed bug in DataFrame Extension call. See ```help(ta.vwma)```.
|
||||
* _Z Score_ (**zscore**): Changed return column name from ```Z_length``` to ```ZS_length```. See ```help(ta.zscore)```.
|
||||
|
||||
<br />
|
||||
|
||||
@@ -18,6 +18,8 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
|
||||
|
||||
if close is None: return
|
||||
|
||||
as_mode = kwargs.setdefault("asmode", False)
|
||||
|
||||
# Calculate Result
|
||||
if Imports["talib"]:
|
||||
from talib import MACD
|
||||
@@ -30,6 +32,11 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
|
||||
signalma = ema(close=macd.loc[macd.first_valid_index():,], length=signal)
|
||||
histogram = macd - signalma
|
||||
|
||||
if as_mode:
|
||||
macd = macd - signalma
|
||||
signalma = ema(close=macd.loc[macd.first_valid_index():,], length=signal)
|
||||
histogram = macd - signalma
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
macd = macd.shift(offset)
|
||||
@@ -47,16 +54,17 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
|
||||
signalma.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
_asmode = "AS" if as_mode else ""
|
||||
_props = f"_{fast}_{slow}_{signal}"
|
||||
macd.name = f"MACD{_props}"
|
||||
histogram.name = f"MACDh{_props}"
|
||||
signalma.name = f"MACDs{_props}"
|
||||
macd.name = f"MACD{_asmode}{_props}"
|
||||
histogram.name = f"MACD{_asmode}h{_props}"
|
||||
signalma.name = f"MACD{_asmode}s{_props}"
|
||||
macd.category = histogram.category = signalma.category = "momentum"
|
||||
|
||||
# Prepare DataFrame to return
|
||||
data = {macd.name: macd, histogram.name: histogram, signalma.name: signalma}
|
||||
df = DataFrame(data)
|
||||
df.name = f"MACD{_props}"
|
||||
df.name = f"MACD{_asmode}{_props}"
|
||||
df.category = macd.category
|
||||
|
||||
signal_indicators = kwargs.pop("signal_indicators", False)
|
||||
@@ -105,6 +113,7 @@ the difference of MACD and Signal.
|
||||
|
||||
Sources:
|
||||
https://www.tradingview.com/wiki/MACD_(Moving_Average_Convergence/Divergence)
|
||||
AS Mode: https://tr.tradingview.com/script/YFlKXHnP/
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
@@ -114,6 +123,11 @@ Calculation:
|
||||
Signal = EMA(MACD, signal)
|
||||
Histogram = MACD - Signal
|
||||
|
||||
if asmode:
|
||||
MACD = MACD - Signal
|
||||
Signal = EMA(MACD, signal)
|
||||
Histogram = MACD - Signal
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
fast (int): The short period. Default: 12
|
||||
@@ -122,6 +136,8 @@ Args:
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
asmode (value, optional): When True, enables AS version of MACD.
|
||||
Default: False
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
|
||||
@@ -87,7 +87,14 @@ def yf(ticker: str, **kwargs):
|
||||
|
||||
# Ticker Info & Chart History
|
||||
yfd = yfra.Ticker(ticker)
|
||||
df = yfd.history(period=period, interval=interval, proxy=proxy, **kwargs)
|
||||
|
||||
try:
|
||||
df = yfd.history(period=period, interval=interval, proxy=proxy, **kwargs)
|
||||
except:
|
||||
if yfra.__version__ == "0.1.60":
|
||||
print(f"[!] If history is not downloading, see yfinance Issue #760 by user djl0.")
|
||||
print(f"[!] https://github.com/ranaroussi/yfinance/issues/760#issuecomment-877355832")
|
||||
return
|
||||
|
||||
if df.empty: return
|
||||
df.name = ticker
|
||||
|
||||
+22
-37
@@ -1,18 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import where as npWhere
|
||||
from pandas import DataFrame
|
||||
from pandas_ta.overlap import hlc3, ma
|
||||
from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
|
||||
from pandas_ta.utils import get_drift, get_offset, signed_series, verify_series
|
||||
|
||||
|
||||
def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=None, drift=None, offset=None, **kwargs):
|
||||
def kvo(high, low, close, volume, fast=None, slow=None, signal=None, mamode=None, drift=None, offset=None, **kwargs):
|
||||
"""Indicator: Klinger Volume Oscillator (KVO)"""
|
||||
# Validate arguments
|
||||
fast = int(fast) if fast and fast > 0 else 34
|
||||
slow = int(slow) if slow and slow > 0 else 55
|
||||
length_sig = int(length_sig) if length_sig and length_sig > 0 else 13
|
||||
signal = int(signal) if signal and signal > 0 else 13
|
||||
mamode = mamode.lower() if mamode and isinstance(mamode, str) else "ema"
|
||||
_length = max(fast, slow, length_sig)
|
||||
_length = max(fast, slow, signal)
|
||||
high = verify_series(high, _length)
|
||||
low = verify_series(low, _length)
|
||||
close = verify_series(close, _length)
|
||||
@@ -23,19 +22,10 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
|
||||
if high is None or low is None or close is None or volume is None: return
|
||||
|
||||
# Calculate Result
|
||||
mom = hlc3(high, low, close).diff(drift)
|
||||
trend = npWhere(mom > 0, 1, 0) + npWhere(mom < 0, -1, 0)
|
||||
dm = non_zero_range(high, low)
|
||||
|
||||
m = high.size
|
||||
cm = [0] * m
|
||||
for i in range(1, m):
|
||||
cm[i] = (cm[i - 1] + dm[i]) if trend[i] == trend[i - 1] else (dm[i - 1] + dm[i])
|
||||
|
||||
vf = 100 * volume * trend * abs(2 * dm / cm - 1)
|
||||
|
||||
kvo = ma(mamode, vf, length=fast) - ma(mamode, vf, length=slow)
|
||||
kvo_signal = ma(mamode, kvo, length=length_sig)
|
||||
signed_volume = volume * signed_series(hlc3(high, low, close), 1)
|
||||
sv = signed_volume.loc[signed_volume.first_valid_index():,]
|
||||
kvo = ma(mamode, sv, length=fast) - ma(mamode, sv, length=slow)
|
||||
kvo_signal = ma(mamode, kvo.loc[kvo.first_valid_index():,], length=signal)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
@@ -51,17 +41,18 @@ def kvo(high, low, close, volume, fast=None, slow=None, length_sig=None, mamode=
|
||||
kvo_signal.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
kvo.name = f"KVO_{fast}_{slow}"
|
||||
kvo_signal.name = f"KVOSig_{length_sig}"
|
||||
_props = f"_{fast}_{slow}_{signal}"
|
||||
kvo.name = f"KVO{_props}"
|
||||
kvo_signal.name = f"KVOs{_props}"
|
||||
kvo.category = kvo_signal.category = "volume"
|
||||
|
||||
# Prepare DataFrame to return
|
||||
data = {kvo.name: kvo, kvo_signal.name: kvo_signal}
|
||||
kvoandsig = DataFrame(data)
|
||||
kvoandsig.name = f"KVO_{fast}_{slow}_{length_sig}"
|
||||
kvoandsig.category = kvo.category
|
||||
df = DataFrame(data)
|
||||
df.name = f"KVO{_props}"
|
||||
df.category = kvo.category
|
||||
|
||||
return kvoandsig
|
||||
return df
|
||||
|
||||
|
||||
kvo.__doc__ = \
|
||||
@@ -71,23 +62,17 @@ This indicator was developed by Stephen J. Klinger. It is designed to predict
|
||||
price reversals in a market by comparing volume to price.
|
||||
|
||||
Sources:
|
||||
https://www.tradingview.com/script/Qnn7ymRK-Klinger-Volume-Oscillator/
|
||||
https://www.investopedia.com/terms/k/klingeroscillator.asp
|
||||
https://www.daytrading.com/klinger-volume-oscillator
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
fast=34, slow=55, length_sig=13, drift=1
|
||||
MOM = HLC3.diff(drift)
|
||||
NEG_TREND = -1 if MOM < 0 else 0
|
||||
POS_TREND = 1 if MOM > 0 else 0
|
||||
TREND = POS_TREND + NEG_TREND
|
||||
DM = high - low
|
||||
CM = [CMt-1 + DMt if TRENDt == TRENDt-1 else DMt-1 + DMt]
|
||||
|
||||
vf = 100 * volume * TREND * abs(2 * dm / cm - 1)
|
||||
kvo = ema(vf, fast) - ema(vf, slow)
|
||||
kvo_signal = ema(kvo, length_sig)
|
||||
fast=34, slow=55, signal=13, drift=1
|
||||
EMA = Exponential Moving Average
|
||||
|
||||
SV = volume * signed_series(HLC3, 1)
|
||||
KVO = EMA(SV, fast) - EMA(SV, slow)
|
||||
Signal = EMA(KVO, signal)
|
||||
|
||||
Args:
|
||||
high (pd.Series): Series of 'high's
|
||||
@@ -105,5 +90,5 @@ Kwargs:
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: kvo and kvo_signal columns.
|
||||
pd.DataFrame: KVO and Signal columns.
|
||||
"""
|
||||
|
||||
@@ -17,7 +17,7 @@ def nvi(close, volume, length=None, initial=None, offset=None, **kwargs):
|
||||
|
||||
# Calculate Result
|
||||
roc_ = roc(close=close, length=length)
|
||||
signed_volume = signed_series(volume, initial=1)
|
||||
signed_volume = signed_series(volume, 1)
|
||||
nvi = signed_volume[signed_volume < 0].abs() * roc_
|
||||
nvi.fillna(0, inplace=True)
|
||||
nvi.iloc[0] = initial
|
||||
|
||||
@@ -16,9 +16,8 @@ def pvi(close, volume, length=None, initial=None, offset=None, **kwargs):
|
||||
if close is None or volume is None: return
|
||||
|
||||
# Calculate Result
|
||||
roc_ = roc(close=close, length=length)
|
||||
signed_volume = signed_series(volume, initial=1)
|
||||
pvi = signed_volume[signed_volume > 0].abs() * roc_
|
||||
signed_volume = signed_series(volume, 1)
|
||||
pvi = roc(close=close, length=length) * signed_volume[signed_volume > 0].abs()
|
||||
pvi.fillna(0, inplace=True)
|
||||
pvi.iloc[0] = initial
|
||||
pvi = pvi.cumsum()
|
||||
|
||||
@@ -11,10 +11,9 @@ def pvol(close, volume, offset=None, **kwargs):
|
||||
signed = kwargs.pop("signed", False)
|
||||
|
||||
# Calculate Result
|
||||
pvol = close * volume
|
||||
if signed:
|
||||
pvol = signed_series(close, 1) * close * volume
|
||||
else:
|
||||
pvol = close * volume
|
||||
pvol *= signed_series(close, 1)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
|
||||
@@ -16,10 +16,10 @@ def vp(close, volume, width=None, **kwargs):
|
||||
if close is None or volume is None: return
|
||||
|
||||
# Setup
|
||||
signed_price = signed_series(close, initial=1)
|
||||
pos_volume = signed_price[signed_price > 0] * volume
|
||||
signed_price = signed_series(close, 1)
|
||||
pos_volume = volume * signed_price[signed_price > 0]
|
||||
pos_volume.name = volume.name
|
||||
neg_volume = signed_price[signed_price < 0] * -volume
|
||||
neg_volume = -volume * signed_price[signed_price < 0]
|
||||
neg_volume.name = volume.name
|
||||
vp = concat([close, pos_volume, neg_volume], axis=1)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ setup(
|
||||
"pandas_ta.volatility",
|
||||
"pandas_ta.volume"
|
||||
],
|
||||
version=".".join(("0", "3", "05b")),
|
||||
version=".".join(("0", "3", "06b")),
|
||||
description=long_description,
|
||||
long_description=long_description,
|
||||
author="Kevin Johnson",
|
||||
|
||||
@@ -63,7 +63,7 @@ class TestVolumeExtension(TestCase):
|
||||
def test_kvo_ext(self):
|
||||
self.data.ta.kvo(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "KVOSig_13")
|
||||
self.assertEqual(list(self.data.columns[-2:]), ["KVO_34_55_13", "KVOs_34_55_13"])
|
||||
|
||||
def test_mfi_ext(self):
|
||||
self.data.ta.mfi(append=True)
|
||||
|
||||
@@ -243,6 +243,11 @@ class TestMomentum(TestCase):
|
||||
except Exception as ex:
|
||||
error_analysis(result.iloc[:, 2], CORRELATION, ex, newline=False)
|
||||
|
||||
def test_macdas(self):
|
||||
result = pandas_ta.macd(self.close, asmode=True)
|
||||
self.assertIsInstance(result, DataFrame)
|
||||
self.assertEqual(result.name, "MACDAS_12_26_9")
|
||||
|
||||
def test_mom(self):
|
||||
result = pandas_ta.mom(self.close)
|
||||
self.assertIsInstance(result, Series)
|
||||
|
||||
Reference in New Issue
Block a user