mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-08-16 11:25:01 +08:00
Merge branch 'pr/465' into development
This commit is contained in:
@@ -59,6 +59,7 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
|
||||
* [Overlap](#overlap-36)
|
||||
* [Performance](#performance-3)
|
||||
* [Statistics](#statistics-11)
|
||||
* [Transform](#transform-3)
|
||||
* [Trend](#trend-19)
|
||||
* [Utility](#utility-5)
|
||||
* [Volatility](#volatility-14)
|
||||
@@ -81,11 +82,11 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
|
||||
|
||||
# **Features**
|
||||
|
||||
* Over 140 indicators and utility functions.
|
||||
* Over 140+ indicators and utility functions.
|
||||
* **TA Lib** indicators (```pip install ta-lib```).
|
||||
* TA Lib's 63 Chart Patterns
|
||||
* Python Indicators are tightly correlated with the _de facto_ [TA Lib](https://github.com/mrjbq7/ta-lib).
|
||||
* TA Lib computations are by default **enabled**. They can be disabled disabled per indicator by using the argument ```talib=False```.
|
||||
* TA Lib computations are by default **enabled**. They can be disabled per indicator by using the argument ```talib=False```.
|
||||
* For example to disable TA Lib calculation for **stdev**: ```ta.stdev(df["close"], length=30, talib=False)```.
|
||||
* **Stochastic Sample Realizations** with the [stochastic](https://github.com/crflynn/stochastic) package (```pip install stochastic```). See the [Stochastic Samples](#stochastic-samples) section below.
|
||||
* **External Custom Indicators Directory** independent of the builtin Pandas TA indicators. For more information, see ```import_dir``` documentation under ```/pandas_ta/custom.py```.
|
||||
@@ -298,7 +299,7 @@ df.ta.study(MyStudy, **kwargs)
|
||||
|
||||
<br/>
|
||||
|
||||
The _Study_ Class is a simple way to name and group your favorite TA Indicators by using a _Data Class_. **Pandas TA** comes with two prebuilt basic Studies to help you get started: __AllStudy__ and __CommonStudy__. A _Study_ can be as simple as the __CommonStudy__ or as complex as needed using Composition/Chaining.
|
||||
The _Study_ Class is a simple way to name and group your favorite TA Indicators by using a _Data Class_. **Pandas TA** comes with two prebuilt basic Studies to help you get started: __AllStudy__ and __CommonStudy__. A _Study_ can be as simple as the __CommonStudy__ or as complex as needed using Composition/Chaining.
|
||||
|
||||
* When using the _study_ method, **all** indicators will be automatically appended to the DataFrame ```df```.
|
||||
* You are using a Chained Study when you have the output of one indicator as input into one or more indicators in the same _Study_.
|
||||
@@ -856,6 +857,14 @@ Use parameter: cumulative=**True** for cumulative results.
|
||||
|
||||
<br/>
|
||||
|
||||
### **Transform** (3)
|
||||
|
||||
* _Cube Transform_: **cube**
|
||||
* _Inverse Fisher Transform_: **ifisher**
|
||||
* _ReMap_: **remap**
|
||||
|
||||
<br/>
|
||||
|
||||
### **Trend** (19)
|
||||
|
||||
* _Average Directional Movement Index_: **adx**
|
||||
@@ -961,7 +970,7 @@ import vectorbt as vbt
|
||||
|
||||
df = pd.DataFrame().ta.ticker("AAPL") # requires 'yfinance' installed
|
||||
|
||||
# Create the "Golden Cross"
|
||||
# Create the "Golden Cross"
|
||||
df["GC"] = df.ta.sma(50, append=True) > df.ta.sma(200, append=True)
|
||||
|
||||
# Create boolean Signals(TS_Entries, TS_Exits) for vectorbt
|
||||
@@ -1005,7 +1014,7 @@ result = ta.cagr(df.close)
|
||||
# **Stochastic Samples** _BETA_
|
||||
Pandas TA can utilize the [stochastic](https://github.com/crflynn/stochastic) package (```pip install stochastic```) to Generate Sample Processes. For arguments and features, see ```help(ta.sample)```
|
||||
|
||||
In short, when you create a Stochastic Sample,
|
||||
In short, when you create a Stochastic Sample,
|
||||
|
||||
```python
|
||||
# Returns a Sample Realization Object
|
||||
@@ -1091,11 +1100,10 @@ help(ta.sample)
|
||||
# **Support**
|
||||
|
||||
Feeling generous, like the package or want to see it become more a mature package?
|
||||
* Donations help cover data and API costs so platform indicataors (like [TradingView](https://github.com/tradingview/)) are accurate.
|
||||
* Donations help cover data and API costs so platform indicators (like [TradingView](https://github.com/tradingview/)) are accurate.
|
||||
* I appreciate **ALL** of those that have bought me Coffee/Beer/Wine et al. I greatly appreciate it! 😎
|
||||
|
||||
<br/>
|
||||
|
||||
### Consider
|
||||
[](https://www.buymeacoffee.com/twopirllc)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ name = "pandas_ta"
|
||||
"""
|
||||
.. moduleauthor:: Kevin Johnson
|
||||
"""
|
||||
|
||||
# Dictionaries and version
|
||||
from pandas_ta.maps import EXCHANGE_TZ, RATE, Category, Imports, version
|
||||
from pandas_ta.utils import *
|
||||
@@ -28,4 +29,4 @@ from pandas_ta.custom import create_dir, import_dir
|
||||
|
||||
# Empty DataFrame Alias. Example:
|
||||
# >> ta.df.ta.ticker("spy")
|
||||
df = DataFrame()
|
||||
df = DataFrame()
|
||||
|
||||
+17
-2
@@ -12,9 +12,8 @@ from pandas.core.base import PandasObject
|
||||
from pandas.errors import PerformanceWarning
|
||||
from pandas import DataFrame, Series
|
||||
|
||||
|
||||
from pandas_ta import *
|
||||
from pandas_ta.utils import *
|
||||
# from pandas_ta.utils import *
|
||||
|
||||
|
||||
# Base Class for extending a Pandas DataFrame
|
||||
@@ -1428,6 +1427,22 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = zscore(close=close, length=length, std=std, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
# Transform
|
||||
def cube(self, cubing_exponent=None, signal_offset=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = cube(close=close, cubing_exponent=cubing_exponent, signal_offset=signal_offset, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def ifisher(self, amplifying_factor=None, signal_offset=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = ifisher(close=close, amplifying_factor=amplifying_factor, signal_offset=signal_offset, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def remap(self, from_min=None, from_max=None, to_min=None, to_max=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = remap(close=close, from_min=from_min, from_max=from_max, to_min=to_min, to_max=to_max, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
# Trend
|
||||
def adx(self, length=None, lensig=None, mamode=None, scalar=None, drift=None, offset=None, **kwargs):
|
||||
high = self._get_column(kwargs.pop("high", "high"))
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .cube import cube
|
||||
from .ifisher import ifisher
|
||||
from .remap import remap
|
||||
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
|
||||
def cube(close: Series, cubing_exponent: float = None, signal_offset: int = None, offset: int = None, **kwargs) -> DataFrame:
|
||||
"""
|
||||
Indicator: Cube Transform
|
||||
|
||||
John Ehlers describes this indicator to be useful in compressing signals near zero for a normalized oscillator
|
||||
like the Inverse Fisher Transform. In conjunction to that, values close to -1 and 1 are nearly unchanged,
|
||||
whereas the ones near zero are reduced regarding their amplitude.
|
||||
From the input data the effects of spectral dilation should have been removed (i.e. roofing filter).
|
||||
|
||||
Sources:
|
||||
Book: Cycle Analytics for Traders, 2014, written by John Ehlers, page 200
|
||||
Implemented by rengel8 for Pandas TA based on code of Markus K. (cryptocoinserver)
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
cubing_exponent (float): Use this exponent 'wisely' to increase the impact of the soft limiter. Default: 3
|
||||
signal_offset (int): Offset the signal line. Default: -1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: New feature generated.
|
||||
"""
|
||||
|
||||
# Validate arguments
|
||||
close = verify_series(close)
|
||||
cubing_exponent = float(cubing_exponent) if cubing_exponent and cubing_exponent >= 3.0 else 3.0
|
||||
signal_offset = int(signal_offset) if signal_offset and signal_offset > 0 else 1
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
result = close ** cubing_exponent
|
||||
|
||||
cube_transform = Series(result, index=close.index)
|
||||
cube_transform_signal = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cube_transform = cube_transform.shift(offset)
|
||||
cube_transform_signal = cube_transform_signal.shift(offset)
|
||||
if signal_offset != 0:
|
||||
cube_transform_signal = cube_transform_signal.shift(signal_offset)
|
||||
|
||||
# Handle fills
|
||||
if "fillna" in kwargs:
|
||||
cube_transform.fillna(kwargs["fillna"], inplace=True)
|
||||
cube_transform_signal.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
cube_transform.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
cube_transform_signal.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
cube_transform.name = f"CUBE"
|
||||
cube_transform_signal.name = f"CUBE_SIGNAL"
|
||||
cube_transform.category = cube_transform_signal.category = "transform"
|
||||
|
||||
# Prepare DataFrame to return
|
||||
data = {cube_transform.name: cube_transform, cube_transform_signal.name: cube_transform_signal}
|
||||
df = DataFrame(data)
|
||||
df.name = f"CUBE_TRANSFORM"
|
||||
df.category = cube_transform.category
|
||||
|
||||
return df
|
||||
@@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import exp as npExp
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
|
||||
def ifisher(close: Series, amplifying_factor: float = None, signal_offset: int = None, offset: int = None,
|
||||
**kwargs) -> DataFrame:
|
||||
"""
|
||||
Indicator: Inverse Fisher Transform
|
||||
|
||||
John Ehlers describes this indicator as a tool to change the "Probability Distribution Function (PDF)" for
|
||||
the results of known oscillator-indicators (time series) to receive clearer signals.
|
||||
Its input needs to be normalized into the range from -1 to 1. Input data in the range of -0.5 to 0.5
|
||||
would not have a significant impact. Ehlers note's as an important fact that larger values will be transformed
|
||||
or compressed stronger to the underlying unity of -1 to 1.
|
||||
|
||||
Preparation Examples (or use 'remap'-indicator for this preparation):
|
||||
(RSI - 50) * 0.1 RSI [0 to 100] -> -5 to 5
|
||||
(RSI - 50) * 0.02 RSI [0 to 100] -> -1 to 1, use amplifying_factor of 5 to match input of example above
|
||||
|
||||
Sources:
|
||||
https://www.mesasoftware.com/papers/TheInverseFisherTransform.pdf,
|
||||
Book: Cycle Analytics for Traders, 2014, written by John Ehlers, page 198
|
||||
Implemented by rengel8 for Pandas TA based on code of Markus K. (cryptocoinserver)
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
amplifying_factor (float): Use this factor to increase the impact of the soft limiter. Default: 1
|
||||
signal_offset (int): Offset the signal line. Default: -1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: New feature generated.
|
||||
"""
|
||||
|
||||
# Validate arguments
|
||||
close = verify_series(close)
|
||||
amplifying_factor = float(amplifying_factor) if amplifying_factor and amplifying_factor != 0 else 1.0
|
||||
signal_offset = int(signal_offset) if signal_offset and signal_offset > 0 else 1
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
series = close.to_numpy()
|
||||
result = (npExp(amplifying_factor * series) - 1) / (npExp(amplifying_factor * series) + 1)
|
||||
|
||||
# Series
|
||||
inv_fisher = Series(result, index=close.index)
|
||||
inv_fisher_signal = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
inv_fisher = inv_fisher.shift(offset)
|
||||
inv_fisher_signal = inv_fisher_signal.shift(offset)
|
||||
if signal_offset != 0:
|
||||
inv_fisher_signal = inv_fisher_signal.shift(signal_offset) # !!!!
|
||||
|
||||
# Handle fills
|
||||
if "fillna" in kwargs:
|
||||
inv_fisher.fillna(kwargs["fillna"], inplace=True)
|
||||
inv_fisher_signal.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
inv_fisher.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
inv_fisher_signal.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
inv_fisher.name = f"INV_FISHER"
|
||||
inv_fisher_signal.name = f"INV_FISHER_SIGNAL"
|
||||
inv_fisher.category = inv_fisher_signal.category = "transform"
|
||||
|
||||
# Prepare DataFrame to return
|
||||
data = {inv_fisher.name: inv_fisher, inv_fisher_signal.name: inv_fisher_signal}
|
||||
df = DataFrame(data)
|
||||
df.name = f"INVERSE_FISHER_TRANSFORM"
|
||||
df.category = inv_fisher.category
|
||||
|
||||
return df
|
||||
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
|
||||
def remap(close: Series, from_min: float = None, from_max: float = None, to_min: float = None, to_max: float = None,
|
||||
offset: int = None, **kwargs) -> Series:
|
||||
"""
|
||||
Indicator: ReMap (REMAP)
|
||||
|
||||
Basically a static normalizer, which maps the input min and max to a given output range. Many range bound
|
||||
oscillators move between 0 and 100, but there are also other variants. Refer to the example below or add more the
|
||||
list.
|
||||
|
||||
Examples:
|
||||
RSI -> IFISHER from_min=0, from_max=100, to_min=-1, to_max=1.0
|
||||
|
||||
Sources:
|
||||
rengel8 for Pandas TA
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
from_min (float): Input minimum. Default: 0
|
||||
from_max (float): Input maximum. Default: 100
|
||||
to_min (float): Output minimum. Default: 0
|
||||
to_max (float): Output maximum. Default: 100
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.Series: New feature generated.
|
||||
"""
|
||||
|
||||
# Validate arguments
|
||||
close = verify_series(close)
|
||||
from_min = float(from_min) if from_min and from_min != 0.0 else 0.0
|
||||
from_max = float(from_max) if from_max and from_max != 0.0 else 100.0
|
||||
to_min = float(to_min) if to_min and to_min != 0.0 else -1.0
|
||||
to_max = float(to_max) if to_max and to_max != 0.0 else 1.0
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
result = ((close - from_min) / (from_max - from_min)) * (to_max - to_min) + to_min
|
||||
|
||||
# get Series
|
||||
result = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
result = result.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if "fillna" in kwargs:
|
||||
result.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
result.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
result.name = f"REMAP_{from_min}_{from_max}_{to_min}_{to_max}"
|
||||
result.category = "transform"
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user