mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-06-27 16:10:07 +08:00
This commit is contained in:
@@ -119,6 +119,7 @@ pandas_ta/_wrapper.py
|
||||
AlphaVantageAPI/
|
||||
|
||||
data/datas.csv
|
||||
data/f500.csv
|
||||
data/GLD_D_tv.csv
|
||||
data/SPY_5min.csv
|
||||
data/SPY_1min.csv
|
||||
|
||||
@@ -16,16 +16,16 @@ init:
|
||||
pip install -r requirements.txt
|
||||
|
||||
test_ext:
|
||||
python -m unittest -v tests/test_ext_indicator_*.py
|
||||
python -m unittest -v -f tests/test_ext_indicator_*.py
|
||||
|
||||
test_metrics:
|
||||
python -m unittest -v tests/test_utils_metrics.py
|
||||
python -m unittest -v -f tests/test_utils_metrics.py
|
||||
|
||||
test_strats:
|
||||
python -m unittest -v tests/test_strategy.py
|
||||
python -m unittest -v -f tests/test_strategy.py
|
||||
|
||||
test_ta:
|
||||
python -m unittest -v tests/test_indicator_*.py
|
||||
python -m unittest -v -f tests/test_indicator_*.py
|
||||
|
||||
test_utils:
|
||||
python -m unittest -v tests/test_utils.py
|
||||
python -m unittest -v -f tests/test_utils.py
|
||||
@@ -39,11 +39,12 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
|
||||
* [Utility](#utility-5)
|
||||
* [Volatility](#volatility-13)
|
||||
* [Volume](#volume-13)
|
||||
* [Performance Metrics](#performance-metrics)
|
||||
* [Changes](#changes)
|
||||
* [Recent](#recent)
|
||||
* [Breaking](#breaking)
|
||||
* [New](#new)
|
||||
* [Updated](#updated)
|
||||
* [General](#general)
|
||||
* [Breaking Indicators](#breaking-indicators)
|
||||
* [New Indicators](#new-indicators)
|
||||
* [Updated Indicators](#updated-indicators)
|
||||
<!--te-->
|
||||
|
||||
<!-- * [Specifying Strategies in **Pandas TA**](#specifying-strategies-in-pandas-ta) -->
|
||||
@@ -56,9 +57,11 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
|
||||
|
||||
* Has 120+ indicators and utility functions.
|
||||
* Indicators are tightly correlated with the de facto [TA Lib](https://mrjbq7.github.io/ta-lib/) if they share common indicators.
|
||||
* Have the need for speed? By using the _strategy_ method, you get **multiprocessing** for free!
|
||||
* Have the need for speed? By using the DataFrame _strategy_ method, you get **multiprocessing** for free!
|
||||
* Easily add _prefixes_ or _suffixes_ or both to columns names. Useful for Custom Chained Strategies.
|
||||
* Example Jupyter Notebooks under the [examples](https://github.com/twopirllc/pandas-ta/tree/master/examples) directory, including how to create Custom Strategies using the new [__Strategy__ Class](https://github.com/twopirllc/pandas-ta/tree/master/examples/PandaTA_Strategy_Examples.ipynb)
|
||||
* **NEW** Performance Metrics
|
||||
<!-- * **Performance Metrics** These metrics return a _float_ and are _not_ part of the _DataFrame_ Extension. They are called conventionally. Included Metrics: **cagr**, **calmar_ratio**, **downside_deviation**, **jensens_alpha**, **log_max_drawdown**, **max_drawdown**, **pure_profit_score**, **sharpe_ratio**, **sortino_ratio**, **volatility**. Example: -->
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -160,7 +163,7 @@ Thanks for trying **Pandas TA**!
|
||||
|
||||
_Thank you for your contributions!_
|
||||
|
||||
[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [codesutras](https://github.com/codesutras) | [daikts](https://github.com/daikts) | [DrPaprikaa](https://github.com/DrPaprikaa) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [maxdignan](https://github.com/maxdignan) | [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [YuvalWein](https://github.com/YuvalWein)
|
||||
[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [codesutras](https://github.com/codesutras) | [daikts](https://github.com/daikts) | [DrPaprikaa](https://github.com/DrPaprikaa) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [maxdignan](https://github.com/maxdignan) | [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [YuvalWein](https://github.com/YuvalWein)
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -174,21 +177,21 @@ _Conventional_
|
||||
You explicitly define the input columns and take care of the output.
|
||||
|
||||
* ```sma10 = ta.sma(df["Close"], length=10)```
|
||||
* Returns a series with name: ```SMA_10```
|
||||
* Returns a Series with name: ```SMA_10```
|
||||
* ```donchiandf = ta.donchian(df["HIGH"], df["low"], lower_length=10, upper_length=15)```
|
||||
* Returns a DataFrame named ```DC_10_15``` and column names: ```DCL_10_15, DCM_10_15, DCU_10_15```
|
||||
* ```ema10_ohlc4 = ta.ema(ta.ohlc4(df["Open"], df["High"], df["Low"], df["Close"]), length=10)```
|
||||
* Conventional Chaining is possible but more explicit.
|
||||
* Since it returns a series named ```EMA_10```. If needed, you may need to uniquely name it.
|
||||
* Since it returns a Series named ```EMA_10```. If needed, you may need to uniquely name it.
|
||||
|
||||
_Pandas TA DataFrame Extension_
|
||||
====================
|
||||
|
||||
Calling ```df.ta``` will automatically lowercase _OHLCVA_ to _ohlcva_: _open, high, low, close, volume_, _adj_close_. By default, ```df.ta``` will use the _ohlcva_ for the indicator arguments removing the need to specify input columns directly.
|
||||
* ```sma10 = df.ta.sma(length=10)```
|
||||
* Returns a series with name: ```SMA_10```
|
||||
* Returns a Series with name: ```SMA_10```
|
||||
* ```ema10_ohlc4 = df.ta.ema(close=df.ta.ohlc4(), length=10, suffix="OHLC4")```
|
||||
* Returns a series with name: ```EMA_10_OHLC4```
|
||||
* Returns a Series with name: ```EMA_10_OHLC4```
|
||||
* Chaining Indicators _require_ specifying the input like: ```close=df.ta.ohlc4()```.
|
||||
* ```donchiandf = df.ta.donchian(lower_length=10, upper_length=15)```
|
||||
* Returns a DataFrame named ```DC_10_15``` and column names: ```DCL_10_15, DCM_10_15, DCU_10_15```
|
||||
@@ -356,18 +359,18 @@ df.ta.strategy(NonMPStrategy)
|
||||
## **adjusted**
|
||||
|
||||
```python
|
||||
# Set ta to default to an adjusted column, 'adj_close', overriding default 'close'
|
||||
# Set ta to default to an adjusted column, 'adj_close', overriding default 'close'.
|
||||
df.ta.adjusted = "adj_close"
|
||||
df.ta.sma(length=10, append=True)
|
||||
|
||||
# To reset back to 'close', set adjusted back to None
|
||||
# To reset back to 'close', set adjusted back to None.
|
||||
df.ta.adjusted = None
|
||||
```
|
||||
|
||||
## **categories**
|
||||
|
||||
```python
|
||||
# List of Pandas TA categories
|
||||
# List of Pandas TA categories.
|
||||
df.ta.categories
|
||||
```
|
||||
|
||||
@@ -375,7 +378,7 @@ df.ta.categories
|
||||
|
||||
```python
|
||||
# Set the number of cores to use for strategy multiprocessing
|
||||
# Defaults to the number of cpus you have
|
||||
# Defaults to the number of cpus you have.
|
||||
df.ta.cores = 4
|
||||
|
||||
# Returns the number of cores you set or your default number of cpus.
|
||||
@@ -386,36 +389,31 @@ df.ta.cores
|
||||
|
||||
```python
|
||||
# The 'datetime_ordered' property returns True if the DataFrame
|
||||
# index is of Pandas datetime64 and df.index[0] < df.index[-1]
|
||||
# Otherwise it returns False
|
||||
# index is of Pandas datetime64 and df.index[0] < df.index[-1].
|
||||
# Otherwise it returns False.
|
||||
df.ta.datetime_ordered
|
||||
```
|
||||
|
||||
## **reverse**
|
||||
|
||||
```python
|
||||
# The 'datetime_ordered' property returns True if the DataFrame
|
||||
# index is of Pandas datetime64 and df.index[0] < df.index[-1]
|
||||
# Otherwise it returns False
|
||||
df.ta.datetime_ordered
|
||||
|
||||
# The 'reverse' is a helper property that returns the DataFrame
|
||||
# in reverse order
|
||||
# in reverse order.
|
||||
df.ta.reverse
|
||||
```
|
||||
|
||||
## **prefix & suffix**
|
||||
|
||||
```python
|
||||
# Applying a prefix to the name of an indicator
|
||||
# Applying a prefix to the name of an indicator.
|
||||
prehl2 = df.ta.hl2(prefix="pre")
|
||||
print(prehl2.name) # "pre_HL2"
|
||||
|
||||
# Applying a suffix to the name of an indicator
|
||||
# Applying a suffix to the name of an indicator.
|
||||
endhl2 = df.ta.hl2(suffix="post")
|
||||
print(endhl2.name) # "HL2_post"
|
||||
|
||||
# Applying a prefix and suffix to the name of an indicator
|
||||
# Applying a prefix and suffix to the name of an indicator.
|
||||
bothhl2 = df.ta.hl2(prefix="pre", suffix="post")
|
||||
print(bothhl2.name) # "pre_HL2_post"
|
||||
```
|
||||
@@ -613,22 +611,45 @@ Use parameter: cumulative=**True** for cumulative results.
|
||||
|:--------:|
|
||||
|  |
|
||||
|
||||
<br/><br/>
|
||||
|
||||
# **Performance Metrics**
|
||||
_Performance Metrics_ are a **new** addition to the package. These metrics return a _float_ and are _not_ part of the _DataFrame_ Extension. They are called conventionally. For Example:
|
||||
```python
|
||||
import pandas_ta as ta
|
||||
result = ta.cagr(df.close)
|
||||
```
|
||||
|
||||
### Available Metrics
|
||||
* _Compounded Annual Growth Rate_: **cagr**
|
||||
* _Calmar Ratio_: **calmar_ratio**
|
||||
* _Downside Deviation_: **downside_deviation**
|
||||
* _Jensen's Alpha_: **jensens_alpha**
|
||||
* _Log Max Drawdown_: **log_max_drawdown**
|
||||
* _Max Drawdown_: **max_drawdown**
|
||||
* _Pure Profit Score_: **pure_profit_score**
|
||||
* _Sharpe Ratio_: **sharpe_ratio**
|
||||
* _Sortino Ratio_: **sortino_ratio**
|
||||
* _Volatility_: **volatility**
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
# **Changes**
|
||||
## **Recent**
|
||||
## **General**
|
||||
* A __Strategy__ Class to help name and group your favorite indicators.
|
||||
* Some indicators have had their ```mamode``` _kwarg_ updated with more _moving average_ choices with the **Moving Average Utility** function ```ta.ma()```. For simplicity, all _choices_ are single source _moving averages_. This is primarily an internal utility used by indicators that have a ```mamode``` _kwarg_. This includes indicators: _accbands_, _amat_, _aobv_, _atr_, _bbands_, _bias_, _efi_, _hilo_, _kc_, _natr_, _qqe_, _rvi_, and _thermo_; the default ```mamode``` parameters have not changed. However, ```ta.ma()``` can be used by the user as well if needed. For more information: ```help(ta.ma)```
|
||||
* **Moving Average Choices**: dema, ema, fwma, hma, linreg, midpoint, pwma, rma, sinwma, sma, swma, t3, tema, trima, vidya, wma, zlma.
|
||||
* An _experimental_ and independent __Watchlist__ Class located in the [Examples](https://github.com/twopirllc/pandas-ta/tree/master/examples/watchlist.py) Directory that can be used in conjunction with the new __Strategy__ Class.
|
||||
* _Linear Regression_ (**linear_regression**) is a new utility method for Simple Linear Regression using _Numpy_ or _Scikit Learn_'s implementation.
|
||||
|
||||
<br />
|
||||
|
||||
## **Breaking**
|
||||
## **Breaking Indicators**
|
||||
* _Bollinger Bands_ (**bbands**): New column 'bandwidth' appended to the returning DataFrame. See: ```help(ta.bbands)```
|
||||
|
||||
|
||||
## **New**
|
||||
## **New Indicators**
|
||||
* _Drawdown_ (**drawdown**) It is a peak-to-trough decline during a specific period for an investment,
|
||||
trading account, or fund. See: ```help(ta.drawdown)```
|
||||
* _Gann High-Low Activator_ (**hilo**) The Gann High Low Activator Indicator was created by Robert Krausz in a 1998. See: ```help(ta.hilo)```
|
||||
@@ -638,10 +659,13 @@ trading account, or fund. See: ```help(ta.drawdown)```
|
||||
* _TTM Trend_ (**ttm_trend**). A trend indicator inspired from John Carter's book "Mastering the Trade" issue of Stocks & Commodities Magazine. It is a moving average based trend indicator consisting of two different simple moving averages. See: ```help(ta.ttm_trend)```
|
||||
* _Variable Index Dynamic Average_ (**vidya**) A popular Dynamic Moving Average created by Tushar Chande. See: ```help(ta.vidya)```
|
||||
|
||||
## **Updated**
|
||||
## **Updated Indicators**
|
||||
* _Average True Range_ (**atr**): The default ```mamode``` is now "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.atr)```.
|
||||
* _Decreasing_ (**decreasing**): New argument ```strict``` checks if the series is continuously decreasing over period ```length```. Default: ```False```. See ```help(ta.decreasing)```.
|
||||
* _Increasing_ (**increasing**): New argument ```strict``` checks if the series is continuously increasing over period ```length```. Default: ```False```. See ```help(ta.increasing)```.
|
||||
* _Trend Return_ (**trend_return**): Returns a DataFrame now instead of Series with pertinenet trade info for a _trend_. An example can be found in the [AI Example Notebook](https://github.com/twopirllc/pandas-ta/tree/master/examples/AIExample.ipynb). The notebook is still a work in progress and open to colloboration.
|
||||
|
||||
<br />
|
||||
|
||||
# **Sources**
|
||||
* [Original TA-LIB](http://ta-lib.org/)
|
||||
|
||||
+9
-9
@@ -185,17 +185,17 @@ class AnalysisIndicators(BasePandasObject):
|
||||
>>> ichimoku, span = ta.ichimoku(df["High"], df["Low"], df["Close"])
|
||||
|
||||
Args:
|
||||
kind (str, optional): Default: None. Kind is the 'name' of the indicator.
|
||||
kind (str, optional): Default: None. Kind is the 'name' of the indicator.
|
||||
It converts kind to lowercase before calling.
|
||||
timed (bool, optional): Default: False. Curious about the execution
|
||||
timed (bool, optional): Default: False. Curious about the execution
|
||||
speed?
|
||||
kwargs: Extension specific modifiers.
|
||||
append (bool, optional): Default: False. When True, it appends the
|
||||
append (bool, optional): Default: False. When True, it appends the
|
||||
resultant column(s) to the DataFrame.
|
||||
|
||||
Returns:
|
||||
Most Indicators will return a Pandas Series. Others like MACD, BBANDS,
|
||||
KC, et al will return a Pandas DataFrame. Ichimoku on the other hand
|
||||
Most Indicators will return a Pandas Series. Others like MACD, BBANDS,
|
||||
KC, et al will return a Pandas DataFrame. Ichimoku on the other hand
|
||||
will return two DataFrames, the Ichimoku DataFrame for the known period
|
||||
and a Span DataFrame for the future of the Span values.
|
||||
|
||||
@@ -1239,9 +1239,9 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = decay(close=close, length=length, mode=mode, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def decreasing(self, length=None, asint=True, offset=None, **kwargs):
|
||||
def decreasing(self, length=None, strict=None, asint=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = decreasing(close=close, length=length, asint=asint, offset=offset, **kwargs)
|
||||
result = decreasing(close=close, length=length, strict=strict, asint=asint, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def dpo(self, length=None, centered=True, offset=None, **kwargs):
|
||||
@@ -1249,9 +1249,9 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = dpo(close=close, length=length, centered=centered, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def increasing(self, length=None, asint=True, offset=None, **kwargs):
|
||||
def increasing(self, length=None, strict=None, asint=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = increasing(close=close, length=length, asint=asint, offset=offset, **kwargs)
|
||||
result = increasing(close=close, length=length, strict=strict, asint=asint, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def long_run(self, fast=None, slow=None, length=None, offset=None, **kwargs):
|
||||
|
||||
@@ -14,7 +14,6 @@ def ppo(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw
|
||||
scalar = float(scalar) if scalar else 100
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else fast
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
|
||||
@@ -7,7 +7,6 @@ def fwma(close, length=None, asc=None, offset=None, **kwargs):
|
||||
# Validate Arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 10
|
||||
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
|
||||
asc = asc if asc else True
|
||||
offset = get_offset(offset)
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ def linreg(close, length=None, offset=None, **kwargs):
|
||||
# Validate arguments
|
||||
close = verify_series(close)
|
||||
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
|
||||
offset = get_offset(offset)
|
||||
angle = kwargs.pop("angle", False)
|
||||
intercept = kwargs.pop("intercept", False)
|
||||
|
||||
@@ -45,9 +45,9 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 10
|
||||
base (float): Logarithmic Base. Default: 2
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 10
|
||||
base (float): Logarithmic Base. Default: 2
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -36,8 +36,8 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -41,8 +41,8 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -39,8 +39,8 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -37,9 +37,9 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
q (float): The quantile. Default: 0.5
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 30
|
||||
q (float): The quantile. Default: 0.5
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -42,8 +42,8 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 30
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -39,11 +39,11 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
length (int): It's period. Default: 30
|
||||
ddof (int): Delta Degrees of Freedom.
|
||||
The divisor used in calculations is N - ddof,
|
||||
where N represents the number of elements. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -38,11 +38,11 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
length (int): It's period. Default: 30
|
||||
ddof (int): Delta Degrees of Freedom.
|
||||
The divisor used in calculations is N - ddof,
|
||||
where N represents the number of elements. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -44,9 +44,9 @@ Calculation:
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 30
|
||||
std (float): It's period. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 30
|
||||
std (float): It's period. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -2,18 +2,27 @@
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
|
||||
def decreasing(close, length=None, asint=True, strictly=False, offset=None, **kwargs):
|
||||
def decreasing(close, length=None, strict=None, asint=None, offset=None, **kwargs):
|
||||
"""Indicator: Decreasing"""
|
||||
# Validate Arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 1
|
||||
strict = strict if isinstance(strict, bool) else False
|
||||
asint = asint if isinstance(asint, bool) else True
|
||||
offset = get_offset(offset)
|
||||
|
||||
def stricly_decreasing(series, n):
|
||||
return all([i > j for i,j in zip(series[-n:], series[1:])])
|
||||
|
||||
# Calculate Result
|
||||
if strictly:
|
||||
decreasing = all(i > j for i, j in zip(close[-length:], close[1:]))
|
||||
if strict:
|
||||
# Returns value as float64? Have to cast to bool
|
||||
decreasing = close.rolling(length, min_periods=length).apply(stricly_decreasing, args=(length,), raw=False)
|
||||
decreasing.fillna(0, inplace=True)
|
||||
decreasing = decreasing.astype(bool)
|
||||
else:
|
||||
decreasing = close.diff(length) < 0
|
||||
|
||||
if asint:
|
||||
decreasing = decreasing.astype(int)
|
||||
|
||||
@@ -28,7 +37,7 @@ def decreasing(close, length=None, asint=True, strictly=False, offset=None, **kw
|
||||
decreasing.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
decreasing.name = f"DEC_{length}"
|
||||
decreasing.name = f"{'S' if strict else ''}DEC_{length}"
|
||||
decreasing.category = "trend"
|
||||
|
||||
return decreasing
|
||||
@@ -37,22 +46,23 @@ def decreasing(close, length=None, asint=True, strictly=False, offset=None, **kw
|
||||
decreasing.__doc__ = \
|
||||
"""Decreasing
|
||||
|
||||
Returns True or False if the series is decreasing over a periods. By default,
|
||||
it returns True and False as 1 and 0 respectively with kwarg 'asint'.
|
||||
|
||||
Sources:
|
||||
Returns True if the series is decreasing over a period, False otherwise. If the kwarg 'strict' is True, it returns True if it is continuously decreasing over the period. When using the kwarg 'asint', then it returns 1 for True or 0 for False.
|
||||
|
||||
Calculation:
|
||||
decreasing = close.diff(length) < 0
|
||||
if strict:
|
||||
decreasing = all(i > j for i, j in zip(close[-length:], close[1:]))
|
||||
else:
|
||||
decreasing = close.diff(length) < 0
|
||||
|
||||
if asint:
|
||||
decreasing = decreasing.astype(int)
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 1
|
||||
asint (bool): Returns as binary. Default: True
|
||||
strictly (bool): If True check for strictly continuous decreasing Default: False
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): It's period. Default: 1
|
||||
asint (bool): Returns as binary. Default: True
|
||||
strict (bool): If True, checks if the series is continuously decreasing over the period. Default: False
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
@@ -2,22 +2,30 @@
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
|
||||
def increasing(close, length=None, asint=True, strictly=False, offset=None, **kwargs):
|
||||
def increasing(close, length=None, strict=None, asint=None, offset=None, **kwargs):
|
||||
"""Indicator: Increasing"""
|
||||
# Validate Arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 1
|
||||
strict = strict if isinstance(strict, bool) else False
|
||||
asint = asint if isinstance(asint, bool) else True
|
||||
offset = get_offset(offset)
|
||||
|
||||
|
||||
def stricly_increasing(series, n):
|
||||
return all([i < j for i,j in zip(series[-n:], series[1:])])
|
||||
|
||||
# Calculate Result
|
||||
if strictly:
|
||||
increasing = all(i < j for i, j in zip(close[-length:], close[1:]))
|
||||
if strict:
|
||||
# Returns value as float64? Have to cast to bool
|
||||
increasing = close.rolling(length, min_periods=length).apply(stricly_increasing, args=(length,), raw=False)
|
||||
increasing.fillna(0, inplace=True)
|
||||
increasing = increasing.astype(bool)
|
||||
else:
|
||||
increasing = close.diff(length) > 0
|
||||
|
||||
|
||||
if asint:
|
||||
increasing = increasing.astype(int)
|
||||
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
increasing = increasing.shift(offset)
|
||||
@@ -29,35 +37,37 @@ def increasing(close, length=None, asint=True, strictly=False, offset=None, **kw
|
||||
increasing.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
increasing.name = f"INC_{length}"
|
||||
increasing.name = f"{'S' if strict else ''}INC_{length}"
|
||||
increasing.category = "trend"
|
||||
|
||||
return increasing
|
||||
|
||||
|
||||
increasing.__doc__ = """Increasing
|
||||
increasing.__doc__ = \
|
||||
"""Increasing
|
||||
|
||||
Returns True or False if the series is increasing over a periods. By default,
|
||||
it returns True and False as 1 and 0 respectively with kwarg 'asint'.
|
||||
|
||||
Sources:
|
||||
|
||||
Calculation:
|
||||
Returns True if the series is increasing over a period, False otherwise. If the kwarg 'strict' is True, it returns True if it is continuously increasing over the period. When using the kwarg 'asint', then it returns 1 for True or 0 for False.
|
||||
|
||||
Calculation:
|
||||
if strict:
|
||||
increasing = all(i < j for i, j in zip(close[-length:], close[1:]))
|
||||
else:
|
||||
increasing = close.diff(length) > 0
|
||||
if asint:
|
||||
increasing = increasing.astype(int)
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 1
|
||||
asint (bool): Returns as binary. Default: True
|
||||
strictly (bool): If True check for strictly continuous increasing Default: False
|
||||
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.
|
||||
"""
|
||||
|
||||
if asint:
|
||||
increasing = increasing.astype(int)
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 1
|
||||
asint (bool): Returns as binary. Default: True
|
||||
strict (bool): If True, checks if the series is continuously increasing over the period. Default: False
|
||||
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.
|
||||
"""
|
||||
|
||||
+99
-20
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import arange as npArange
|
||||
# from numpy import arange as npArange
|
||||
from numpy import log as npLog
|
||||
from numpy import sqrt as npSqrt
|
||||
from pandas import DataFrame, Series, Timedelta
|
||||
@@ -11,15 +11,32 @@ from pandas_ta.performance import drawdown, log_return, percent_return
|
||||
|
||||
|
||||
def cagr(close: Series) -> float:
|
||||
"""Compounded Annual Growth Rate"""
|
||||
"""Compounded Annual Growth Rate
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
|
||||
>>> result = ta.cagr(df.close)
|
||||
"""
|
||||
close = verify_series(close)
|
||||
start, end = close.iloc[0], close.iloc[-1]
|
||||
return ((end / start) ** (1 / total_time(close))) - 1
|
||||
|
||||
|
||||
def calmar_ratio(close: Series, method: str = "percent", years: int = 3, log: bool = False) -> float:
|
||||
def calmar_ratio(close: Series, method: str = "percent", years: int = 3) -> float:
|
||||
"""The Calmar Ratio is the percent Max Drawdown Ratio 'typically' over
|
||||
the past three years."""
|
||||
the past three years.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
method (str): Max DD calculation options: 'dollar', 'percent', 'log'. Default: 'dollar'
|
||||
years (int): The positive number of years to use. Default: 3
|
||||
|
||||
>>> result = ta.calmar_ratio(close, method="percent", years=3)
|
||||
"""
|
||||
if years <= 0:
|
||||
print(f"[!] calmar_ratio 'years' argument must be greater than zero.")
|
||||
return
|
||||
close = verify_series(close)
|
||||
|
||||
n_years_ago = close.index[-1] - Timedelta(days=365.25 * years)
|
||||
@@ -28,10 +45,18 @@ def calmar_ratio(close: Series, method: str = "percent", years: int = 3, log: bo
|
||||
return cagr(close) / max_drawdown(close, method=method)
|
||||
|
||||
|
||||
def downside_deviation(returns: Series, benchmark_rate: float = 0.0, log: bool = False, tf: str = "years") -> float:
|
||||
def downside_deviation(returns: Series, benchmark_rate: float = 0.0, tf: str = "years") -> float:
|
||||
"""Downside Deviation for the Sortino ratio.
|
||||
Benchmark rate is assumed to be annualized. Adjusted according for the
|
||||
number of periods per year seen in the data."""
|
||||
number of periods per year seen in the data.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
benchmark_rate (float): Benchmark Rate to use. Default: 0.0
|
||||
tf (str): Time Frame options: 'days', 'weeks', 'months', and 'years'. Default: 'years'
|
||||
|
||||
>>> result = ta.downside_deviation(returns, benchmark_rate=0.0, tf="years")
|
||||
"""
|
||||
# For both de-annualizing the benchmark rate and annualizing result
|
||||
returns = verify_series(returns)
|
||||
days_per_year = returns.shape[0] / total_time(returns, tf)
|
||||
@@ -44,8 +69,15 @@ def downside_deviation(returns: Series, benchmark_rate: float = 0.0, log: bool =
|
||||
return downside_deviation * npSqrt(days_per_year)
|
||||
|
||||
|
||||
def jensens_alpha(returns:Series, benchmark_returns:Series) -> float:
|
||||
"""Jensen's 'Alpha' of a series and a benchmark."""
|
||||
def jensens_alpha(returns: Series, benchmark_returns: Series) -> float:
|
||||
"""Jensen's 'Alpha' of a series and a benchmark.
|
||||
|
||||
Args:
|
||||
returns (pd.Series): Series of 'returns's
|
||||
benchmark_returns (pd.Series): Series of 'benchmark_returns's
|
||||
|
||||
>>> result = ta.jensens_alpha(returns, benchmark_returns)
|
||||
"""
|
||||
returns = verify_series(returns)
|
||||
benchmark_returns = verify_series(benchmark_returns)
|
||||
|
||||
@@ -53,15 +85,29 @@ def jensens_alpha(returns:Series, benchmark_returns:Series) -> float:
|
||||
return linear_regression(benchmark_returns, returns)["a"]
|
||||
|
||||
|
||||
def log_max_drawdown(close:Series):
|
||||
"""Log Max Drawdown of a series."""
|
||||
def log_max_drawdown(close: Series) -> float:
|
||||
"""Log Max Drawdown of a series.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
|
||||
>>> result = ta.log_max_drawdown(close)
|
||||
"""
|
||||
close = verify_series(close)
|
||||
log_return = npLog(close.iloc[-1]) - npLog(close.iloc[0])
|
||||
return log_return - max_drawdown(close, method="log")
|
||||
|
||||
|
||||
def max_drawdown(close: Series, method:str = None, all:bool = False) -> float:
|
||||
"""Maximum Drawdown from close. Defaults to 'dollar'. """
|
||||
"""Maximum Drawdown from close. Default: 'dollar'.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
method (str): Max DD calculation options: 'dollar', 'percent', 'log'. Default: 'dollar'
|
||||
all (bool): If True, it returns all three methods as a dict. Default: False
|
||||
|
||||
>>> result = ta.max_drawdown(close, method="dollar", all=False)
|
||||
"""
|
||||
close = verify_series(close)
|
||||
max_dd = drawdown(close).max()
|
||||
|
||||
@@ -77,9 +123,15 @@ def max_drawdown(close: Series, method:str = None, all:bool = False) -> float:
|
||||
return max_dd_["dollar"]
|
||||
|
||||
|
||||
def pure_profit_score(close:Series) -> float:
|
||||
"""Pure Profit Score of a series."""
|
||||
from sklearn.linear_model import LinearRegression
|
||||
def pure_profit_score(close: Series) -> float:
|
||||
"""Pure Profit Score of a series.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
|
||||
>>> result = ta.pure_profit_score(df.close)
|
||||
"""
|
||||
# from sklearn.linear_model import LinearRegression
|
||||
close = verify_series(close)
|
||||
close_index = Series(0, index=close.reset_index().index)
|
||||
|
||||
@@ -87,8 +139,16 @@ def pure_profit_score(close:Series) -> float:
|
||||
return r * cagr(close)
|
||||
|
||||
|
||||
def sharpe_ratio(close:Series, benchmark_rate:float = 0.0, log:bool = False) -> float:
|
||||
"""Sharpe Ratio of a series."""
|
||||
def sharpe_ratio(close: Series, benchmark_rate: float = 0.0, log: bool = False) -> float:
|
||||
"""Sharpe Ratio of a series.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
benchmark_rate (float): Benchmark Rate to use. Default: 0.0
|
||||
log (bool): If True, calculates log_return. Otherwise it returns percent_return. Default: False
|
||||
|
||||
>>> result = ta.sharpe_ratio(close, benchmark_rate=0.0, log=False)
|
||||
"""
|
||||
close = verify_series(close)
|
||||
returns = percent_return(close=close) if not log else log_return(close=close)
|
||||
|
||||
@@ -97,8 +157,16 @@ def sharpe_ratio(close:Series, benchmark_rate:float = 0.0, log:bool = False) ->
|
||||
return result
|
||||
|
||||
|
||||
def sortino_ratio(close:Series, benchmark_rate:float = 0.0, log:bool = False) -> float:
|
||||
"""Sortino Ratio of a series."""
|
||||
def sortino_ratio(close: Series, benchmark_rate: float = 0.0, log: bool = False) -> float:
|
||||
"""Sortino Ratio of a series.
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
benchmark_rate (float): Benchmark Rate to use. Default: 0.0
|
||||
log (bool): If True, calculates log_return. Otherwise it returns percent_return. Default: False
|
||||
|
||||
>>> result = ta.sortino_ratio(close, benchmark_rate=0.0, log=False)
|
||||
"""
|
||||
close = verify_series(close)
|
||||
returns = percent_return(close=close) if not log else log_return(close=close)
|
||||
|
||||
@@ -107,12 +175,23 @@ def sortino_ratio(close:Series, benchmark_rate:float = 0.0, log:bool = False) ->
|
||||
return result
|
||||
|
||||
|
||||
def volatility(close: Series, tf:str = "years", returns:bool = False, log: bool = False, **kwargs) -> float:
|
||||
"""Volatility of a series. Default: 'years'"""
|
||||
def volatility(close: Series, tf: str = "years", returns: bool = False, log: bool = False, **kwargs) -> float:
|
||||
"""Volatility of a series. Default: 'years'
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
tf (str): Time Frame options: 'days', 'weeks', 'months', and 'years'. Default: 'years'
|
||||
returns (bool): If True, then it replace the close Series with the user defined Series; typically user generated returns or percent returns or log returns. Default: False
|
||||
log (bool): If True, calculates log_return. Otherwise it calculates percent_return. Default: False
|
||||
|
||||
>>> result = ta.volatility(close, tf="years", returns=False, log=False, **kwargs)
|
||||
"""
|
||||
close = verify_series(close)
|
||||
|
||||
if not returns:
|
||||
returns = percent_return(close=close) if not log else log_return(close=close)
|
||||
else:
|
||||
returns = close
|
||||
|
||||
factor = returns.shape[0] / total_time(returns, tf)
|
||||
if kwargs.pop("nearest_day", False) and tf.lower() == "years":
|
||||
|
||||
@@ -17,7 +17,7 @@ setup(
|
||||
"pandas_ta.volatility",
|
||||
"pandas_ta.volume"
|
||||
],
|
||||
version=".".join(("0", "2", "29b")),
|
||||
version=".".join(("0", "2", "30b")),
|
||||
description=long_description,
|
||||
long_description=long_description,
|
||||
author="Kevin Johnson",
|
||||
|
||||
@@ -57,6 +57,10 @@ class TestTrendExtension(TestCase):
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "DEC_1")
|
||||
|
||||
self.data.ta.decreasing(length=3, strict=True, append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "SDEC_3")
|
||||
|
||||
def test_dpo_ext(self):
|
||||
self.data.ta.dpo(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
@@ -67,6 +71,10 @@ class TestTrendExtension(TestCase):
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "INC_1")
|
||||
|
||||
self.data.ta.increasing(length=3, strict=True, append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "SINC_3")
|
||||
|
||||
def test_long_run_ext(self):
|
||||
# Nothing passed, return self
|
||||
self.assertEqual(self.data.ta.long_run(append=True).shape, self.data.shape)
|
||||
|
||||
@@ -113,6 +113,10 @@ class TestTrend(TestCase):
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "DEC_1")
|
||||
|
||||
result = pandas_ta.decreasing(self.close, length=3, strict=True)
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "SDEC_3")
|
||||
|
||||
def test_dpo(self):
|
||||
result = pandas_ta.dpo(self.close)
|
||||
self.assertIsInstance(result, Series)
|
||||
@@ -123,6 +127,10 @@ class TestTrend(TestCase):
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "INC_1")
|
||||
|
||||
result = pandas_ta.increasing(self.close, length=3, strict=True)
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "SINC_3")
|
||||
|
||||
def test_long_run(self):
|
||||
result = pandas_ta.long_run(self.close, self.open)
|
||||
self.assertIsInstance(result, Series)
|
||||
|
||||
@@ -36,6 +36,12 @@ class TestUtilityMetrics(TestCase):
|
||||
self.assertIsInstance(result, float)
|
||||
self.assertGreaterEqual(result, 0)
|
||||
|
||||
result = pandas_ta.calmar_ratio(self.close, years=0)
|
||||
self.assertIsNone(result)
|
||||
|
||||
result = pandas_ta.calmar_ratio(self.close, years=-2)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_downside_deviation(self):
|
||||
result = pandas_ta.downside_deviation(self.pctret)
|
||||
self.assertIsInstance(result, float)
|
||||
@@ -101,6 +107,11 @@ class TestUtilityMetrics(TestCase):
|
||||
self.assertGreaterEqual(result, 0)
|
||||
|
||||
def test_volatility(self):
|
||||
returns_ = pandas_ta.percent_return(self.close)
|
||||
result = pandas_ta.utils.volatility(returns_, returns=True)
|
||||
self.assertIsInstance(result, float)
|
||||
self.assertGreaterEqual(result, 0)
|
||||
|
||||
for tf in ["years", "months", "weeks", "days", "hours", "minutes", "seconds"]:
|
||||
result = pandas_ta.utils.volatility(self.close, tf)
|
||||
self.assertIsInstance(result, float)
|
||||
|
||||
Reference in New Issue
Block a user