Merge pull request #3 from twopirllc/master

Up to date
This commit is contained in:
rengel8
2021-04-03 22:20:27 +02:00
committed by GitHub
149 changed files with 3781 additions and 1956 deletions
+1
View File
@@ -124,6 +124,7 @@ reqs.txt
requirements.txt
driver.py
qd.py
tdseq.py
# Local package installs
ta-lib/
+146 -36
View File
@@ -11,10 +11,11 @@ Pandas TA - A Technical Analysis Library in Python 3
[![PyPi Version](https://img.shields.io/pypi/v/pandas_ta.svg)](https://pypi.org/project/pandas_ta/)
[![Package Status](https://img.shields.io/pypi/status/pandas_ta.svg)](https://pypi.org/project/pandas_ta/)
[![Downloads](https://img.shields.io/pypi/dm/pandas_ta.svg?style=flat)](https://pypistats.org/packages/pandas_ta)
[![Contributors](https://img.shields.io/badge/contributors-19-orange.svg?style=flat)](#contributors-)
![Example Chart](/images/TA_Chart.png)
_Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that leverages the Pandas library with more than 120 Indicators and Utility functions. Many commonly used indicators are included, such as: _Simple Moving Average_ (**sma**) _Moving Average Convergence Divergence_ (**macd**), _Hull Exponential Moving Average_ (**hma**), _Bollinger Bands_ (**bbands**), _On-Balance Volume_ (**obv**), _Aroon & Aroon Oscillator_ (**aroon**), _Squeeze_ (**squeeze**) and **_many more_**.
_Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that leverages the Pandas library with more than 130 Indicators and Utility functions. Many commonly used indicators are included, such as: _Simple Moving Average_ (**sma**) _Moving Average Convergence Divergence_ (**macd**), _Hull Exponential Moving Average_ (**hma**), _Bollinger Bands_ (**bbands**), _On-Balance Volume_ (**obv**), _Aroon & Aroon Oscillator_ (**aroon**), _Squeeze_ (**squeeze**) and **_many more_**.
<br/>
@@ -33,16 +34,18 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
* [Pandas TA Strategies](#pandas-ta-strategies)
* [Types of Strategies](#types-of-strategies)
* [DataFrame Properties](#dataframe-properties)
* [DataFrame Methods](#dataframe-methods)
* [Indicators by Category](#indicators-by-category)
* [Candles](#candles-3)
* [Momentum](#momentum-35)
* [Overlap](#overlap-29)
* [Cycles](#cycles-1)
* [Momentum](#momentum-37)
* [Overlap](#overlap-31)
* [Performance](#performance-4)
* [Statistics](#statistics-9)
* [Trend](#trend-15)
* [Utility](#utility-5)
* [Volatility](#volatility-13)
* [Volume](#volume-13)
* [Volume](#volume-14)
* [Performance Metrics](#performance-metrics)
* [Changes](#changes)
* [General](#general)
@@ -59,13 +62,14 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
# **Features**
* Has 120+ indicators and utility functions.
* Has 130+ 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 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)
* Potential Data Leaks: **ichimoku** and **dpo**. See indicator list below for details.
* **UNDER DEVELOPMENT:** Performance Metrics
* **UNDER DEVELOPMENT:** Easy Downloading of _ohlcv_ data using [yfinance](https://github.com/ranaroussi/yfinance). See ```help(ta.ticker)``` and ```help(ta.yf)```
<br/>
@@ -74,14 +78,14 @@ _Pandas Technical Analysis_ (**Pandas TA**) is an easy to use library that lever
Stable
------
The ```pip``` version is the last most stable release.
The ```pip``` version is the last most stable release. Version: *0.2.45b*
```sh
$ pip install pandas_ta
```
Latest Version
--------------
Best choice!
Best choice! Version: *0.2.62b*
```sh
$ pip install -U git+https://github.com/twopirllc/pandas-ta
```
@@ -100,8 +104,12 @@ $ pip install -U git+https://github.com/twopirllc/pandas-ta.git@development
import pandas as pd
import pandas_ta as ta
df = pd.DataFrame() # Empty DataFrame
# Load data
df = pd.read_csv("path/to/symbol.csv", sep=",")
# OR if you have yfinance installed
df = df.ta.ticker("aapl")
# VWAP requires the DataFrame index to be a DatetimeIndex.
# Replace "datetime" with the appropriate column from your DataFrame
@@ -136,8 +144,8 @@ help(df.ta)
# List of all indicators
df.ta.indicators()
# Help about the log_return indicator
help(ta.log_return)
# Help about an indicator such as bbands
help(ta.bbands)
```
<br/>
@@ -175,7 +183,7 @@ Thanks for using **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) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rengel8](https://github.com/rengel8) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [whubsch](https://github.com/whubsch) | [YuvalWein](https://github.com/YuvalWein)
[alexonab](https://github.com/alexonab) | [allahyarzadeh](https://github.com/allahyarzadeh) | [codesutras](https://github.com/codesutras) | [DrPaprikaa](https://github.com/DrPaprikaa) | [daikts](https://github.com/daikts) | [dorren](https://github.com/dorren) | [edwardwang1](https://github.com/edwardwang1) | [ffhirata](https://github.com/ffhirata) | [FGU1](https://github.com/FGU1) | [lluissalord](https://github.com/lluissalord) | [M6stafa](https://github.com/M6stafa) | [maxdignan](https://github.com/maxdignan) | [moritzgun](https://github.com/moritzgun) | [NkosenhleDuma](https://github.com/NkosenhleDuma) | [pbrumblay](https://github.com/pbrumblay) | [RajeshDhalange](https://github.com/RajeshDhalange) | [rengel8](https://github.com/rengel8) | [rluong003](https://github.com/rluong003) | [SoftDevDanial](https://github.com/SoftDevDanial) | [tg12](https://github.com/tg12) | [twrobel](https://github.com/twrobel) | [whubsch](https://github.com/whubsch) | [witokondoria](https://github.com/witokondoria) | [wouldayajustlookatit](https://github.com/wouldayajustlookatit) | [YuvalWein](https://github.com/YuvalWein)
<br/>
@@ -341,6 +349,7 @@ df.ta.strategy(verbose=True)
df.ta.strategy(timed=True)
# Choose the number of cores to use. Default is all available cores.
# For no multiprocessing, set this value to 0.
df.ta.cores = 4
# Maybe you do not want certain indicators.
@@ -405,6 +414,9 @@ df.ta.categories
# Defaults to the number of cpus you have.
df.ta.cores = 4
# Set the number of cores to 0 for no multiprocessing.
df.ta.cores = 0
# Returns the number of cores you set or your default number of cpus.
df.ta.cores
```
@@ -418,6 +430,24 @@ df.ta.cores
df.ta.datetime_ordered
```
## **exchange**
```python
# Sets the Exchange to use when calculating the last_run property. Default: "NYSE"
df.ta.exchange
# Set the Exchange to use.
# Available Exchanges: "ASX", "BMF", "DIFX", "FWB", "HKE", "JSE", "LSE", "NSE", "NYSE", "NZSX", "RTS", "SGX", "SSE", "TSE", "TSX"
df.ta.exchange = "LSE"
```
## **last_run**
```python
# Returns the time Pandas TA was last run as a string.
df.ta.last_run
```
## **reverse**
```python
@@ -442,6 +472,85 @@ bothhl2 = df.ta.hl2(prefix="pre", suffix="post")
print(bothhl2.name) # "pre_HL2_post"
```
## **time_range**
```python
# Returns the time range of the DataFrame as a float.
# By default, it returns the time in "years"
df.ta.time_range
# Available time_ranges include: "years", "months", "weeks", "days", "hours", "minutes". "seconds"
df.ta.time_range = "days"
df.ta.time_range # prints DataFrame time in "days" as float
```
## **to_utc**
```python
# Sets the DataFrame index to UTC format.
df.ta.to_utc
```
<br/><br/>
# **DataFrame Methods**
## **constants**
```python
import numpy as np
# Add constant '1' to the DataFrame
df.ta.constants(True, [1])
# Remove constant '1' to the DataFrame
df.ta.constants(False, [1])
# Adding constants for charting
import numpy as np
chart_lines = np.append(np.arange(-4, 5, 1), np.arange(-100, 110, 10))
df.ta.constants(True, chart_lines)
# Removing some constants from the DataFrame
df.ta.constants(False, np.array([-60, -40, 40, 60]))
```
## **indicators**
```python
# Prints the indicators and utility functions
df.ta.indicators()
# Returns a list of indicators and utility functions
ind_list = df.ta.indicators(as_list=True)
# Prints the indicators and utility functions that are not in the excluded list
df.ta.indicators(exclude=["cg", "pgo", "ui"])
# Returns a list of the indicators and utility functions that are not in the excluded list
smaller_list = df.ta.indicators(exclude=["cg", "pgo", "ui"], as_list=True)
```
## **ticker**
```python
# Download Chart history using yfinance. (pip install yfinance) https://github.com/ranaroussi/yfinance
# It uses the same keyword arguments as yfinance (excluding start and end)
df = df.ta.ticker("aapl") # Default ticker is "SPY"
# Period is used instead of start/end
# Valid periods: 1d,5d,1mo,3mo,6mo,1y,2y,5y,10y,ytd,max
# Default: "max"
df = df.ta.ticker("aapl", period="1y") # Gets this past year
# History by Interval by interval (including intraday if period < 60 days)
# Valid intervals: 1m,2m,5m,15m,30m,60m,90m,1h,1d,5d,1wk,1mo,3mo
# Default: "1d"
df = df.ta.ticker("aapl", period="1y", interval="1wk") # Gets this past year in weeks
df = df.ta.ticker("aapl", period="1mo", interval="1h") # Gets this past month in hours
# BUT WAIT!! THERE'S MORE!!
help(ta.yf)
```
<br/><br/>
# **Indicators** (_by Category_)
@@ -450,8 +559,15 @@ print(bothhl2.name) # "pre_HL2_post"
* _Doji_: **cdl_doji**
* _Inside Bar_: **cdl_inside**
* _Heikin-Ashi_: **ha**
<br/>
### **Momentum** (36)
### **Cycles** (1)
* _Even Better Sinewave_: **ebsw**
<br/>
### **Momentum** (37)
* _Awesome Oscillator_: **ao**
* _Absolute Price Oscillator_: **apo**
@@ -486,6 +602,8 @@ print(bothhl2.name) # "pre_HL2_post"
* Default is John Carter's. Enable Lazybear's with ```lazybear=True```
* _Stochastic Oscillator_: **stoch**
* _Stochastic RSI_: **stochrsi**
* _TD Sequential_: **td_seq**
* Excluded from ```df.ta.strategy()```.
* _Trix_: **trix**
* _True strength index_: **tsi**
* _Ultimate Oscillator_: **uo**
@@ -495,9 +613,11 @@ print(bothhl2.name) # "pre_HL2_post"
| _Moving Average Convergence Divergence_ (MACD) |
|:--------:|
| ![Example MACD](/images/SPY_MACD.png) |
<br/>
### **Overlap** (30)
### **Overlap** (31)
* _Arnaud Legoux Moving Average_: **alma**
* _Double Exponential Moving Average_: **dema**
* _Exponential Moving Average_: **ema**
* _Fibonacci's Weighted Moving Average_: **fwma**
@@ -506,6 +626,7 @@ print(bothhl2.name) # "pre_HL2_post"
* _High-Low-Close Average_: **hlc3**
* Commonly known as 'Typical Price' in Technical Analysis literature
* _Hull Exponential Moving Average_: **hma**
* _Holt-Winter Moving Average_: **hwma**
* _Ichimoku Kinkō Hyō_: **ichimoku**
* Use: help(ta.ichimoku). Returns two DataFrames.
* Drop the Chikou Span Column, the final column of the first resultant DataFrame, remove potential data leak.
@@ -536,6 +657,7 @@ print(bothhl2.name) # "pre_HL2_post"
| _Simple Moving Averages_ (SMA) and _Bollinger Bands_ (BBANDS) |
|:--------:|
| ![Example Chart](/images/TA_Chart.png) |
<br/>
### **Performance** (4)
@@ -550,7 +672,7 @@ Use parameter: cumulative=**True** for cumulative results.
| _Percent Return_ (Cumulative) with _Simple Moving Average_ (SMA) |
|:--------:|
| ![Example Cumulative Percent Return](/images/SPY_CumulativePercentReturn.png) |
<br/>
### **Statistics** (9)
@@ -567,10 +689,12 @@ Use parameter: cumulative=**True** for cumulative results.
| _Z Score_ |
|:--------:|
| ![Example Z Score](/images/SPY_ZScore.png) |
<br/>
### **Trend** (15)
* _Average Directional Movement Index_: **adx**
* Also includes **dmp** and **dmn** in the resultant DataFrame.
* _Archer Moving Averages Trends_: **amat**
* _Aroon & Aroon Oscillator_: **aroon**
* _Choppiness Index_: **chop**
@@ -643,7 +767,7 @@ Use parameter: cumulative=**True** for cumulative results.
<br/><br/>
# **Performance Metrics** (BETA)
# **Performance Metrics** &nbsp; _BETA_
_Performance Metrics_ are a **new** addition to the package and consequentially are likely unreliable. **Use at your own risk.** These metrics return a _float_ and are _not_ part of the _DataFrame_ Extension. They are called the Standard way. For Example:
```python
@@ -673,31 +797,21 @@ result = ta.cagr(df.close)
* **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.
* Added utility/convience function, ```to_utc```, to convert the DataFrame index to UTC. See: ```help(ta.to_utc)```
* Added utility/convience function, ```to_utc```, to convert the DataFrame index to UTC. See: ```help(ta.to_utc)``` **Now** as a Pandas TA DataFrame Property to easily convert the DataFrame index to UTC.
<br />
## **Breaking Indicators**
* _Bollinger Bands_ (**bbands**): New column 'bandwidth' appended to the returning DataFrame. See: ```help(ta.bbands)```
* _Volume Weighted Average Price_ (**vwap**): **Requires** the DataFrame index to be a DatetimeIndex.
## **New Indicators**
* _Drawdown_ (**drawdown**) shows the peak-to-trough decline during a specific period for an investment,
* _Arnaud Legoux Moving Average_ (**alma**) uses the curve of the Normal (Gauss) distribution to allow regulating the smoothness and high sensitivity of the indicator. See: ```help(ta.alma)```
trading account, or fund. See: ```help(ta.drawdown)```
* _Gann High-Low Activator_ (**hilo**) was created by Robert Krausz in a 1998. See: ```help(ta.hilo)```
* _McGinley Dynamic_ (**mcgd**) is an overlap indicator developed by John R. McGinley, a Certified Market Technician. See: ```help(ta.mcgd)```
* _Price Volume Rank_ (**pvr**) was created by Anthony J. Macek. See: ```help(ta.pvr)```
* _Quantitative Qualitative Estimation_ (**qqe**) is like SuperTrend for a Smoothed RSI. See: ```help(ta.qqe)```
article in the June, 1994 issue of Technical Analysis of Stocks & Commodities Magazine. See: ```help(ta.pvr)```
* _Relative Strength Xtra_ (**rsx**) is based on the popular RSI indicator and inspired by the work Jurik Research. See: ```help(ta.rsx)```
* _Ehler's Super Smoother Filter_ (**ssf**). Ehler's solution to reduce lag and remove aliasing noise compared to other common moving average indicators. See: ```help(ta.ssf)```
* _Elder's Thermometer_ (**thermo**) measures price volatility. See: ```help(ta.thermo)```
* _TTM Trend_ (**ttm_trend**) is 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**) is a popular Dynamic Moving Average created by Tushar Chande. See: ```help(ta.vidya)```
* _Even Better Sinewave_ (**ebsw**) measures market cycles and uses a low pass filter to remove noise. See: ```help(ta.ebsw)```
* _Tom DeMark's Sequential_ (**td_seq**) attempts to identify a price point where an uptrend or a downtrend exhausts itself and reverses. Currently exlcuded from ```df.ta.strategy()``` for performance reasons. See: ```help(ta.td_seq)```
<br/>
## **Updated Indicators**
* _ADX_ (**adx**): Added ```mamode``` with default "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.adx)```.
* _Average True Range_ (**atr**): The default ```mamode``` is now "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.atr)```.
* _Bollinger Bands_ (**bbands**): New argument ```ddoff``` to control the Degrees of Freedom. Default is 0. See ```help(ta.bbands)```.
* _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.
@@ -706,8 +820,4 @@ article in the June, 1994 issue of Technical Analysis of Stocks & Commodities Ma
<br />
# **Sources**
* [Original TA-LIB](http://ta-lib.org/)
* [TradingView](http://www.tradingview.com)
* [Sierra Chart](https://search.sierrachart.com/?Query=indicators&submitted=true)
* [FM Labs](https://www.fmlabs.com/reference/default.htm)
* [User 42](https://user42.tuxfamily.org/chart/manual/index.html)
[Original TA-LIB](http://ta-lib.org/) | [TradingView](http://www.tradingview.com) | [Sierra Chart](https://search.sierrachart.com/?Query=indicators&submitted=true) | [MQL5](https://www.mql5.com) | [FM Labs](https://www.fmlabs.com/reference/default.htm) | [Pro Real Code](https://www.prorealcode.com/prorealtime-indicators) | [User 42](https://user42.tuxfamily.org/chart/manual/index.html)
+331 -282
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+132 -156
View File
File diff suppressed because one or more lines are too long
+56 -52
View File
@@ -3,11 +3,13 @@ import datetime as dt
from pathlib import Path
from random import random
from typing import Tuple
import pandas as pd # pip install pandas
from pandas_datareader import data as pdr
import yfinance as yf
# yf.pdr_override() # <== that's all it takes :-)
yf.pdr_override() # <== that's all it takes :-)
from numpy import arange as npArange
from numpy import append as npAppend
@@ -72,14 +74,9 @@ class Watchlist(object):
- tickers: A list of strings containing tickers. Example: ["SPY", "AAPL"]
"""
def __init__(
self,
tickers: list,
tf: str = None,
name: str = None,
strategy: ta.Strategy = None,
ds: object = None,
**kwargs,
def __init__(self,
tickers: list, tf: str = None, name: str = None,
strategy: ta.Strategy = None, ds_name: str = "av", **kwargs,
):
self.verbose = kwargs.pop("verbose", False)
self.debug = kwargs.pop("debug", False)
@@ -92,24 +89,25 @@ class Watchlist(object):
self.kwargs = kwargs
self.strategy = strategy
self._init_data_source(ds)
self._init_data_source(ds_name)
def _init_data_source(self, ds: object):
if ds is not None:
self.ds = ds
elif isinstance(ds, str) and ds.lower() == "yahoo":
def _init_data_source(self, ds: str) -> None:
self.ds_name = ds.lower() if isinstance(ds, str) else "av"
# Default: AlphaVantage
AVkwargs = {"api_key": "YOUR API KEY", "clean": True, "export": True, "output_size": "full", "premium": False}
self.av_kwargs = self.kwargs.pop("av_kwargs", AVkwargs)
self.ds = AV.AlphaVantage(**self.av_kwargs)
self.file_path = self.ds.export_path
if self.ds_name == "yahoo":
self.ds = yf
else:
AVkwargs = {"api_key": "YOUR API KEY", "clean": True, "export": True, "output_size": "full", "premium": False}
self.av_kwargs = self.kwargs.pop("av_kwargs", AVkwargs)
self.ds = AV.AlphaVantage(**self.av_kwargs)
self.file_path = self.ds.export_path
def _drop_columns(
self,
df: pd.DataFrame,
cols: list = ["Unnamed: 0", "date", "split_coefficient", "dividend"],
):
def _drop_columns(self, df: pd.DataFrame, cols: list = None) -> pd.DataFrame:
if cols is None or not isinstance(cols, list):
cols = ["Unnamed: 0", "date", "split_coefficient", "dividend"]
else: cols
"""Helper methods to drop columns silently."""
df_columns = list(df.columns)
if any(_ in df_columns for _ in cols):
@@ -123,12 +121,10 @@ class Watchlist(object):
keyed by ticker."""
if (self.tickers is not None and isinstance(self.tickers, list) and
len(self.tickers)):
self.data = {
ticker: self.load(ticker, **kwargs) for ticker in self.tickers
}
self.data = {ticker: self.load(ticker, **kwargs) for ticker in self.tickers}
return self.data
def _plot(self, df, mas:bool = True, constants:bool = True, **kwargs) -> None:
def _plot(self, df, mas:bool = True, constants:bool = False, **kwargs) -> None:
if constants:
chart_lines = npAppend(npArange(-5, 6, 1), npArange(-100, 110, 10))
@@ -145,22 +141,25 @@ class Watchlist(object):
_grid = kwargs.pop("grid", True)
_alpha = kwargs.pop("alpha", 1)
_last = kwargs.pop("last", 252)
_title = kwargs.pop("title", f"{df.ticker} {_time}")
_title = kwargs.pop("title", f"{df.ticker} {_time} [{self.ds_name}]")
col = kwargs.pop("close", "close")
price = df[[col, "SMA_10", "SMA_20", "SMA_50", "SMA_200"]] if mas else df[col]
if mas:
# df.ta.strategy(self.strategy, append=True)
price = df[[col, "SMA_10", "SMA_20", "SMA_50", "SMA_200"]]
else:
price = df[col]
price.tail(_last).plot(figsize=_figsize, color=_colors, linewidth=2, title=_title, grid=_grid, alpha=_alpha)
if _kind is None:
price.tail(_last).plot(figsize=_figsize, color=_colors, linewidth=2, title=_title, grid=_grid, alpha=_alpha)
else:
print(f"[X] Plot kind not implemented")
return
def load(
self,
ticker: str = None,
tf: str = None,
index: str = "date",
drop: list = [],
plot: bool = False,
**kwargs
def load(self,
ticker: str = None, tf: str = None, index: str = "date",
drop: list = [], plot: bool = False, **kwargs
) -> pd.DataFrame:
"""Loads or Downloads (if a local csv does not exist) the data from the
Data Source. When successful, it returns a Data Frame for the requested
@@ -179,22 +178,28 @@ class Watchlist(object):
# Load local or from Data Source
if current_file.exists():
df = pd.read_csv(current_file, index_col=index)
if not df.ta.datetime_ordered:
df = df.set_index(pd.DatetimeIndex(df.index))
print(f"[i] Loaded['{tf}']: {filename_}")
file_loaded = f"[i] Loaded {ticker}[{tf}]: {filename_}"
# if self.ds_name == "av":
if self.ds_name in ["av", "yahoo"]:
df = pd.read_csv(current_file, index_col=0)
if not df.ta.datetime_ordered:
df = df.set_index(pd.DatetimeIndex(df.index))
print(file_loaded)
else:
print(f"[X] {filename_} not found in {Path(self.file_path)}")
return
else:
print(f"[+] Downloading['{tf}']: {ticker}")
if isinstance(self.ds, AV.AlphaVantage):
print(f"[+] Downloading[{self.ds_name}]: {ticker}[{tf}]")
if self.ds_name == "av":
df = self.ds.data(ticker, tf)
if not df.ta.datetime_ordered:
df = df.set_index(pd.DatetimeIndex(df[index]))
elif isinstance(self.ds, yfinance):
print("[!] In Development")
if self.ds_name == "yahoo":
yf_data = self.ds.Ticker(ticker)
df = yf_data.history(period="max")
print(yf_data.info)
print(df)
to_save = f"{self.file_path}/{ticker}_{tf}.csv"
print(f"[+] Saving: {to_save}")
df.to_csv(to_save)
# Remove select columns
df = self._drop_columns(df, drop)
@@ -207,7 +212,6 @@ class Watchlist(object):
df.tf = tf
if plot: self._plot(df, **kwargs)
return df
@property
@@ -273,7 +277,7 @@ class Watchlist(object):
return self._tickers
@tickers.setter
def tickers(self, value: (list, str)) -> None:
def tickers(self, value: Tuple[list, str]) -> None:
if value is None:
print(f"[X] {value} is not a value in Watchlist ticker.")
return
@@ -300,7 +304,7 @@ class Watchlist(object):
pd.DataFrame().ta.indicators(*args, **kwargs)
def __repr__(self) -> str:
s = f"Watch(name='{self.name}', tickers[{len(self.tickers)}]='{', '.join(self.tickers)}', tf='{self.tf}', strategy[{self.strategy.total_ta()}]='{self.strategy.name}'"
s = f"Watch(name='{self.name}', ds_name='{self.ds_name}', tickers[{len(self.tickers)}]='{', '.join(self.tickers)}', tf='{self.tf}', strategy[{self.strategy.total_ta()}]='{self.strategy.name}'"
if self.data is not None:
s += f", data[{len(self.data.keys())}])"
return s
+7 -4
View File
@@ -25,9 +25,10 @@ Imports = {
"scipy": find_spec("scipy") is not None,
"sklearn": find_spec("sklearn") is not None,
"statsmodels": find_spec("statsmodels") is not None,
"stochastic": find_spec("stochastic") is not None,
"matplotlib": find_spec("matplotlib") is not None,
"mplfinance": find_spec("mplfinance") is not None,
"alphaVantage-api ": find_spec("alphaVantageAPI") is not None,
"alphaVantage-api": find_spec("alphaVantageAPI") is not None,
"yfinance": find_spec("yfinance") is not None,
"talib": find_spec("talib") is not None,
}
@@ -39,17 +40,19 @@ Category = {
"candles": [
"cdl_doji", "cdl_inside", "ha"
],
# Cycles
"cycles": ["ebsw"],
# Momentum
"momentum": [
"ao", "apo", "bias", "bop", "brar", "cci", "cfo", "cg", "cmo",
"coppock", "er", "eri", "fisher", "inertia", "kdj", "kst", "macd",
"mom", "pgo", "ppo", "psl", "pvo", "qqe", "roc", "rsi", "rsx", "rvgi",
"slope", "smi", "squeeze", "stoch", "stochrsi", "trix", "tsi", "uo",
"slope", "smi", "squeeze", "stoch", "stochrsi", "td_seq", "trix", "tsi", "uo",
"willr"
],
# Overlap
"overlap": [
"dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku",
"alma", "dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku",
"kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4", "pwma", "rma",
"sinwma", "sma", "ssf", "supertrend", "swma", "t3", "tema", "trima",
"vidya", "vwap", "vwma", "wcp", "wma", "zlma"
@@ -69,7 +72,7 @@ Category = {
],
# Volatility
"volatility": [
"aberration", "accbands", "atr", "bbands", "donchian", "kc", "massi",
"aberration", "accbands", "atr", "bbands", "donchian", "hwc", "kc", "massi",
"natr", "pdist", "rvi", "thermo", "true_range", "ui"
],
+10 -7
View File
@@ -1,22 +1,24 @@
# -*- coding: utf-8 -*-
from pandas_ta.overlap import sma
from pandas_ta.utils import get_offset, high_low_range, is_percent
from pandas_ta.utils import non_zero_range, real_body, verify_series
from pandas_ta.utils import real_body, verify_series
def cdl_doji( open_, high, low, close, length=None, factor=None, scalar=None, asint=True, offset=None, **kwargs):
def cdl_doji(open_, high, low, close, length=None, factor=None, scalar=None, asint=True, offset=None, **kwargs):
"""Candle Type: Doji"""
# Validate Arguments
open_ = verify_series(open_)
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 10
factor = float(factor) if is_percent(factor) else 10
scalar = float(scalar) if scalar else 100
open_ = verify_series(open_, length)
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
offset = get_offset(offset)
naive = kwargs.pop("naive", False)
if open_ is None or high is None or low is None or close is None: return
# Calculate Result
body = real_body(open_, close).abs()
hl_range = high_low_range(high, low).abs()
@@ -77,7 +79,8 @@ Args:
Kwargs:
naive (bool, optional): If True, prefills potential Doji less than
the length if less than a percentage of it's high-low range. Default: False
the length if less than a percentage of it's high-low range.
Default: False
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
+2 -3
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame, set_option
from pandas_ta.utils import candle_color, get_drift, get_offset
from pandas_ta.utils import non_zero_range, real_body, verify_series
from pandas_ta.utils import candle_color, get_offset
from pandas_ta.utils import verify_series
def cdl_inside(open_, high, low, close, asbool=False, offset=None, **kwargs):
-1
View File
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
import numpy as np
from pandas import DataFrame
from pandas_ta.utils import get_offset, verify_series
+281 -191
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from .ebsw import ebsw
+115
View File
@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
from numpy import cos as npCos
from numpy import exp as npExp
from numpy import NaN as npNaN
from numpy import pi as npPi
from numpy import sin as npSin
from numpy import sqrt as npSqrt
from pandas import Series
from pandas_ta.utils import get_offset, verify_series
def ebsw(close, length=None, bars=None, offset=None, **kwargs):
"""Indicator: Even Better SineWave (EBSW)"""
# Validate arguments
length = int(length) if length and length > 38 else 40
bars = int(bars) if bars and bars > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# variables
alpha1 = HP = 0 # alpha and HighPass
a1 = b1 = c1 = c2 = c3 = 0
Filt = Pwr = Wave = 0
lastClose = lastHP = 0
FilterHist = [0, 0] # Filter history
# Calculate Result
m = close.size
result = [npNaN for _ in range(0, length - 1)] + [0]
for i in range(length, m):
# HighPass filter cyclic components whose periods are shorter than Duration input
alpha1 = (1 - npSin(360 / length)) / npCos(360 / length)
HP = 0.5 * (1 + alpha1) * (close[i] - lastClose) + alpha1 * lastHP
# Smooth with a Super Smoother Filter from equation 3-3
a1 = npExp(-npSqrt(2) * npPi / bars)
b1 = 2 * a1 * npCos(npSqrt(2) * 180 / bars)
c2 = b1
c3 = -1 * a1 * a1
c1 = 1 - c2 - c3
Filt = c1 * (HP + lastHP) / 2 + c2 * FilterHist[1] + c3 * FilterHist[0]
# Filt = float("{:.8f}".format(float(Filt))) # to fix for small scientific notations, the big ones fail
# 3 Bar average of Wave amplitude and power
Wave = (Filt + FilterHist[1] + FilterHist[0]) / 3
Pwr = (Filt * Filt + FilterHist[1] * FilterHist[1] + FilterHist[0] * FilterHist[0]) / 3
# Normalize the Average Wave to Square Root of the Average Power
Wave = Wave / npSqrt(Pwr)
# update storage, result
FilterHist.append(Filt) # append new Filt value
FilterHist.pop(0) # remove first element of list (left) -> updating/trim
lastHP = HP
lastClose = close[i]
result.append(Wave)
ebsw = Series(result, index=close.index)
# Offset
if offset != 0:
ebsw = ebsw.shift(offset)
# Handle fills
if "fillna" in kwargs:
ebsw.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
ebsw.fillna(method=kwargs["fill_method"], inplace=True)
# Name and Categorize it
ebsw.name = f"EBSW_{length}_{bars}"
ebsw.category = "cycles"
return ebsw
ebsw.__doc__ = \
"""Even Better SineWave (EBSW) *beta*
This indicator measures market cycles and uses a low pass filter to remove noise.
Its output is bound signal between -1 and 1 and the maximum length of a detected
trend is limited by its length input.
Written by rengel8 for Pandas TA based on a publication at 'prorealcode.com' and
a book by J.F.Ehlers.
* This implementation seems to be logically limited. It would make sense to
implement exactly the version from prorealcode and compare the behaviour.
Sources:
https://www.prorealcode.com/prorealtime-indicators/even-better-sinewave/
J.F.Ehlers 'Cycle Analytics for Traders', 2014
Calculation:
refer to 'sources' or implementation
Args:
close (pd.Series): Series of 'close's
length (int): It's max cycle/trend period. Values between 40-48 work like
expected with minimum value: 39. Default: 40.
bars (int): Period of low pass filtering. Default: 10
drift (int): The difference period. 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.Series: New feature generated.
"""
+1
View File
@@ -31,6 +31,7 @@ from .smi import smi
from .squeeze import squeeze
from .stoch import stoch
from .stochrsi import stochrsi
from .td_seq import td_seq
from .trix import trix
from .tsi import tsi
from .uo import uo
+8 -5
View File
@@ -6,14 +6,17 @@ from pandas_ta.utils import get_offset, verify_series
def ao(high, low, fast=None, slow=None, offset=None, **kwargs):
"""Indicator: Awesome Oscillator (AO)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
fast = int(fast) if fast and fast > 0 else 5
slow = int(slow) if slow and slow > 0 else 34
if slow < fast:
fast, slow = slow, fast
_length = max(fast, slow)
high = verify_series(high, _length)
low = verify_series(low, _length)
offset = get_offset(offset)
if high is None or low is None: return
# Calculate Result
median_price = 0.5 * (high + low)
fast_sma = sma(median_price, fast)
@@ -57,9 +60,9 @@ Calculation:
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
fast (int): The short period. Default: 5
slow (int): The long period. Default: 34
offset (int): How many periods to offset the result. Default: 0
fast (int): The short period. Default: 5
slow (int): The long period. Default: 34
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -5
View File
@@ -6,13 +6,15 @@ from pandas_ta.utils import get_offset, verify_series
def apo(close, fast=None, slow=None, offset=None, **kwargs):
"""Indicator: Absolute Price Oscillator (APO)"""
# Validate Arguments
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 12
slow = int(slow) if slow and slow > 0 else 26
if slow < fast:
fast, slow = slow, fast
close = verify_series(close, max(fast, slow))
offset = get_offset(offset)
if close is None: return
# Calculate Result
fastma = sma(close, length=fast)
slowma = sma(close, length=slow)
@@ -40,7 +42,7 @@ apo.__doc__ = \
The Absolute Price Oscillator is an indicator used to measure a security's
momentum. It is simply the difference of two Exponential Moving Averages
(EMA) of two different periods. Note: APO and MACD lines are equivalent.
(EMA) of two different periods. Note: APO and MACD lines are equivalent.
Sources:
https://www.tradingtechnologies.com/xtrader-help/x-study/technical-indicator-definitions/absolute-price-oscillator-apo/
@@ -53,9 +55,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
offset (int): How many periods to offset the result. Default: 0
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -5
View File
@@ -6,11 +6,13 @@ from pandas_ta.utils import get_offset, verify_series
def bias(close, length=None, mamode=None, offset=None, **kwargs):
"""Indicator: Bias (BIAS)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 26
mamode = mamode if isinstance(mamode, str) else "sma"
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
bma = ma(mamode, close, length=length, **kwargs)
bias = (close / bma) - 1
@@ -50,10 +52,10 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): The period. Default: 26
mamode (str): Options: 'ema', 'hma', 'rma', 'sma', 'wma'. Default: 'sma'
drift (int): The short period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): The period. Default: 26
mamode (str): Options: 'ema', 'hma', 'rma', 'sma', 'wma'. Default: 'sma'
drift (int): The short period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+10 -8
View File
@@ -6,17 +6,19 @@ from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
def brar(open_, high, low, close, length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: BRAR (BRAR)"""
# Validate Arguments
open_ = verify_series(open_)
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 26
scalar = float(scalar) if scalar else 100
high_open_range = non_zero_range(high, open_)
open_low_range = non_zero_range(open_, low)
open_ = verify_series(open_, length)
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if open_ is None or high is None or low is None or close is None: return
# Calculate Result
hcy = non_zero_range(high, close.shift(drift))
cyl = non_zero_range(close.shift(drift), low)
@@ -85,10 +87,10 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): The period. Default: 26
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): The period. Default: 26
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+8 -6
View File
@@ -7,13 +7,15 @@ from pandas_ta.utils import get_offset, verify_series
def cci(high, low, close, length=None, c=None, offset=None, **kwargs):
"""Indicator: Commodity Channel Index (CCI)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 14
c = float(c) if c and c > 0 else 0.015
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
typical_price = hlc3(high=high, low=low, close=close)
mean_typical_price = sma(typical_price, length=length)
@@ -62,9 +64,9 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
c (float): Scaling Constant. Default: 0.015
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 14
c (float): Scaling Constant. Default: 0.015
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+3 -1
View File
@@ -6,12 +6,14 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Chande Forcast Oscillator (CFO)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 9
scalar = float(scalar) if scalar else 100
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Finding linear regression of Series
cfo = scalar * (close - linreg(close, length=length, tsf=True))
cfo /= close
+5 -3
View File
@@ -5,10 +5,12 @@ from pandas_ta.utils import get_offset, verify_series, weights
def cg(close, length=None, offset=None, **kwargs):
"""Indicator: Center of Gravity (CG)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
coefficients = [length - i for i in range(0, length)]
numerator = -close.rolling(length).apply(weights(coefficients), raw=True)
@@ -46,8 +48,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): The length of the period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): The length of the period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+4 -2
View File
@@ -6,18 +6,20 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def cmo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Chande Momentum Oscillator (CMO)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
scalar = float(scalar) if scalar else 100
talib = kwargs.pop("talib", True)
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Calculate Result
mom = close.diff(drift)
positive = mom.copy().clip(lower=0)
negative = mom.copy().clip(upper=0).abs()
talib = kwargs.pop("talib", True)
if talib:
pos_ = rma(positive, length)
neg_ = rma(negative, length)
+7 -5
View File
@@ -7,12 +7,14 @@ from pandas_ta.utils import get_offset, verify_series
def coppock(close, length=None, fast=None, slow=None, offset=None, **kwargs):
"""Indicator: Coppock Curve (COPC)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
fast = int(fast) if fast and fast > 0 else 11
slow = int(slow) if slow and slow > 0 else 14
close = verify_series(close, max(length, fast, slow))
offset = get_offset(offset)
if close is None: return
# Calculate Result
total_roc = roc(close, fast) + roc(close, slow)
coppock = wma(total_roc, length)
@@ -58,10 +60,10 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): WMA period. Default: 10
fast (int): Fast ROC period. Default: 11
slow (int): Slow ROC period. Default: 14
offset (int): How many periods to offset the result. Default: 0
length (int): WMA period. Default: 10
fast (int): Fast ROC period. Default: 11
slow (int): Slow ROC period. Default: 14
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+5 -3
View File
@@ -6,11 +6,13 @@ from pandas_ta.utils import get_drift, get_offset, verify_series, signals
def er(close, length=None, drift=None, offset=None, **kwargs):
"""Indicator: Efficiency Ratio (ER)"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
drift = get_drift(drift)
if close is None: return
# Calculate Result
abs_diff = close.diff(length).abs()
abs_volatility = close.diff(drift).abs()
@@ -79,8 +81,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -5
View File
@@ -7,12 +7,14 @@ from pandas_ta.utils import get_offset, verify_series
def eri(high, low, close, length=None, offset=None, **kwargs):
"""Indicator: Elder Ray Index (ERI)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 13
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
ema_ = ema(close, length)
bull = high - ema_
@@ -73,8 +75,8 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 14
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+9 -6
View File
@@ -9,12 +9,15 @@ from pandas_ta.utils import get_offset, high_low_range, verify_series, zero
def fisher(high, low, length=None, signal=None, offset=None, **kwargs):
"""Indicator: Fisher Transform (FISHT)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
length = int(length) if length and length > 0 else 9
signal = int(signal) if signal and signal > 0 else 1
_length = max(length, signal)
high = verify_series(high, _length)
low = verify_series(low, _length)
offset = get_offset(offset)
if high is None or low is None: return
# Calculate Result
hl2_ = hl2(high, low)
highest_hl2 = hl2_.rolling(length).max()
@@ -29,7 +32,7 @@ def fisher(high, low, length=None, signal=None, offset=None, **kwargs):
m = high.size
result = [npNaN for _ in range(0, length - 1)] + [0]
for i in range(length, m):
v = 0.66 * position[i] + 0.67 * v
v = 0.66 * position.iloc[i] + 0.67 * v
if v < -0.99:
v = -0.999
if v > 0.99:
@@ -102,9 +105,9 @@ Calculation:
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
length (int): Fisher period. Default: 9
signal (int): Fisher Signal period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): Fisher period. Default: 9
signal (int): Fisher Signal period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+12 -8
View File
@@ -1,25 +1,29 @@
# -*- coding: utf-8 -*-
from pandas_ta.overlap import linreg
from pandas_ta.volatility import rvi
from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
from pandas_ta.utils import get_drift, get_offset, verify_series
def inertia(close=None, high=None, low=None, length=None, rvi_length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: Inertia (INERTIA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 20
rvi_length = int(rvi_length) if rvi_length and rvi_length > 0 else 14
scalar = float(scalar) if scalar and scalar > 0 else 100
refined = False if refined is None else True
thirds = False if thirds is None else True
mamode = mamode if isinstance(mamode, str) else "ema"
_length = max(length, rvi_length)
close = verify_series(close, _length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
if refined or thirds:
high = verify_series(high)
low = verify_series(low)
high = verify_series(high, _length)
low = verify_series(low, _length)
if high is None or low is None: return
# Calculate Result
if refined:
@@ -75,10 +79,10 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 20
rvi_length (int): RVI period. Default: 14
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 20
rvi_length (int): RVI period. Default: 14
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -4
View File
@@ -7,13 +7,16 @@ from pandas_ta.utils import get_offset, non_zero_range, verify_series
def kdj(high=None, low=None, close=None, length=None, signal=None, offset=None, **kwargs):
"""Indicator: KDJ (KDJ)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 9
signal = int(signal) if signal and signal > 0 else 3
_length = max(length, signal)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
highest_high = high.rolling(length).max()
lowest_low = low.rolling(length).min()
@@ -86,7 +89,7 @@ Args:
close (pd.Series): Series of 'close's
length (int): Default: 9
signal (int): Default: 3
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)
+15 -12
View File
@@ -7,7 +7,6 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def kst(close, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None, sma3=None, sma4=None, signal=None, drift=None, offset=None, **kwargs):
"""Indicator: 'Know Sure Thing' (KST)"""
# Validate arguments
close = verify_series(close)
roc1 = int(roc1) if roc1 and roc1 > 0 else 10
roc2 = int(roc2) if roc2 and roc2 > 0 else 15
roc3 = int(roc3) if roc3 and roc3 > 0 else 20
@@ -19,9 +18,13 @@ def kst(close, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None,
sma4 = int(sma4) if sma4 and sma4 > 0 else 15
signal = int(signal) if signal and signal > 0 else 9
_length = max(roc1, roc2, roc3, roc4, sma1, sma2, sma3, sma4, signal)
close = verify_series(close, _length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Calculate Result
rocma1 = roc(close, roc1).rolling(sma1).mean()
rocma2 = roc(close, roc2).rolling(sma2).mean()
@@ -83,17 +86,17 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
roc1 (int): ROC 1 period. Default: 10
roc2 (int): ROC 2 period. Default: 15
roc3 (int): ROC 3 period. Default: 20
roc4 (int): ROC 4 period. Default: 30
sma1 (int): SMA 1 period. Default: 10
sma2 (int): SMA 2 period. Default: 10
sma3 (int): SMA 3 period. Default: 10
sma4 (int): SMA 4 period. Default: 15
signal (int): It's period. Default: 9
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
roc1 (int): ROC 1 period. Default: 10
roc2 (int): ROC 2 period. Default: 15
roc3 (int): ROC 3 period. Default: 20
roc4 (int): ROC 4 period. Default: 30
sma1 (int): SMA 1 period. Default: 10
sma2 (int): SMA 2 period. Default: 10
sma3 (int): SMA 3 period. Default: 10
sma4 (int): SMA 4 period. Default: 15
signal (int): It's period. Default: 9
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+9 -7
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame, concat
from pandas import concat, DataFrame
from pandas_ta.overlap import ema
from pandas_ta.utils import get_offset, verify_series, signals
@@ -7,14 +7,16 @@ from pandas_ta.utils import get_offset, verify_series, signals
def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
"""Indicator: Moving Average, Convergence/Divergence (MACD)"""
# Validate arguments
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 12
slow = int(slow) if slow and slow > 0 else 26
signal = int(signal) if signal and signal > 0 else 9
if slow < fast:
fast, slow = slow, fast
close = verify_series(close, max(fast, slow, signal))
offset = get_offset(offset)
if close is None: return
# Calculate Result
fastma = ema(close, length=fast)
slowma = ema(close, length=slow)
@@ -93,7 +95,7 @@ macd.__doc__ = \
The MACD is a popular indicator to that is used to identify a security's trend.
While APO and MACD are the same calculation, MACD also returns two more series
called Signal and Histogram. The Signal is an EMA of MACD and the Histogram is
called Signal and Histogram. The Signal is an EMA of MACD and the Histogram is
the difference of MACD and Signal.
Sources:
@@ -109,10 +111,10 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
signal (int): The signal period. Default: 9
offset (int): How many periods to offset the result. Default: 0
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
signal (int): The signal period. Default: 9
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+5 -3
View File
@@ -5,10 +5,12 @@ from pandas_ta.utils import get_offset, verify_series
def mom(close, length=None, offset=None, **kwargs):
"""Indicator: Momentum (MOM)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
mom = close.diff(length)
@@ -45,8 +47,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -5
View File
@@ -7,12 +7,14 @@ from pandas_ta.utils import get_offset, verify_series
def pgo(high, low, close, length=None, offset=None, **kwargs):
"""Indicator: Pretty Good Oscillator (PGO)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 14
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
pgo = close - sma(close, length)
pgo /= ema(atr(high, low, close, length), length)
@@ -57,8 +59,8 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 14
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+8 -6
View File
@@ -7,15 +7,17 @@ from pandas_ta.utils import get_offset, verify_series
def ppo(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs):
"""Indicator: Percentage Price Oscillator (PPO)"""
# Validate Arguments
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 12
slow = int(slow) if slow and slow > 0 else 26
signal = int(signal) if signal and signal > 0 else 9
scalar = float(scalar) if scalar else 100
if slow < fast:
fast, slow = slow, fast
close = verify_series(close, max(fast, slow, signal))
offset = get_offset(offset)
if close is None: return
# Calculate Result
fastma = sma(close, length=fast)
slowma = sma(close, length=slow)
@@ -78,11 +80,11 @@ Calculation:
Args:
close(pandas.Series): Series of 'close's
fast(int): The short period. Default: 12
slow(int): The long period. Default: 26
signal(int): The signal period. Default: 9
scalar (float): How much to magnify. Default: 100
offset(int): How many periods to offset the result. Default: 0
fast(int): The short period. Default: 12
slow(int): The long period. Default: 26
signal(int): The signal period. Default: 9
scalar (float): How much to magnify. Default: 100
offset(int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -5
View File
@@ -6,12 +6,14 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def psl(close, open_=None, length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Psychological Line (PSL)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 12
scalar = float(scalar) if scalar and scalar > 0 else 100
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Calculate Result
if open_ is not None:
open_ = verify_series(open_)
@@ -71,10 +73,10 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
open_ (pd.Series, optional): Series of 'open's
length (int): It's period. Default: 12
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 12
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+8 -6
View File
@@ -7,15 +7,17 @@ from pandas_ta.utils import get_offset, verify_series
def pvo(volume, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs):
"""Indicator: Percentage Volume Oscillator (PVO)"""
# Validate Arguments
volume = verify_series(volume)
fast = int(fast) if fast and fast > 0 else 12
slow = int(slow) if slow and slow > 0 else 26
signal = int(signal) if signal and signal > 0 else 9
scalar = float(scalar) if scalar else 100
if slow < fast:
fast, slow = slow, fast
volume = verify_series(volume, max(fast, slow, signal))
offset = get_offset(offset)
if volume is None: return
# Calculate Result
fastma = ema(volume, length=fast)
slowma = ema(volume, length=slow)
@@ -76,11 +78,11 @@ Calculation:
Args:
volume (pd.Series): Series of 'volume's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
signal (int): The signal period. Default: 9
scalar (float): How much to magnify. Default: 100
offset (int): How many periods to offset the result. Default: 0
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
signal (int): The signal period. Default: 9
scalar (float): How much to magnify. Default: 100
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+6 -4
View File
@@ -12,14 +12,17 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def qqe(close, length=None, smooth=None, factor=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: Quantitative Qualitative Estimation (QQE)"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
smooth = int(smooth) if smooth and smooth > 0 else 5
factor = float(factor) if factor else 4.236
wilders_length = 2 * length - 1
mamode = mamode if isinstance(mamode, str) else "ema"
close = verify_series(close, max(length, smooth, wilders_length))
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Calculate Result
rsi_ = rsi(close, length)
_mode = mamode.lower()[0] if mamode != "ema" else ""
@@ -30,7 +33,6 @@ def qqe(close, length=None, smooth=None, factor=None, mamode=None, drift=None, o
# Double Smooth the RSI MA True Range using Wilder's Length with a default
# width of 4.236.
wilders_length = 2 * length - 1
smoothed_rsi_tr_ma = ma("ema", rsi_ma_tr, length=wilders_length)
dar = factor * ma("ema", smoothed_rsi_tr_ma, length=wilders_length)
@@ -131,7 +133,6 @@ Sources:
https://www.tradingview.com/script/IYfA9R2k-QQE-MT4/
https://www.tradingpedia.com/forex-trading-indicators/quantitative-qualitative-estimation
https://www.prorealcode.com/prorealtime-indicators/qqe-quantitative-qualitative-estimation/
Calculation:
Default Inputs:
@@ -142,7 +143,8 @@ Args:
length (int): RSI period. Default: 14
smooth (int): RSI smoothing period. Default: 5
factor (float): QQE Factor. Default: 4.236
mamode (str): Smoothing MA type: "ema", "hma", "rma", "sma" or "wma". Default: "ema"
mamode (str): Smoothing MA type: "ema", "hma", "rma", "sma" or "wma".
Default: "ema"
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
+5 -3
View File
@@ -6,10 +6,12 @@ from pandas_ta.utils import get_offset, verify_series
def roc(close, length=None, offset=None, **kwargs):
"""Indicator: Rate of Change (ROC)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
roc = 100 * mom(close=close, length=length) / close.shift(length)
@@ -48,8 +50,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+3 -1
View File
@@ -7,12 +7,14 @@ from pandas_ta.utils import get_drift, get_offset, verify_series, signals
def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Relative Strength Index (RSI)"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
scalar = float(scalar) if scalar else 100
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Calculate Result
negative = close.diff(drift)
positive = negative.copy()
+7 -4
View File
@@ -1,16 +1,19 @@
# -*- coding: utf-8 -*-
from numpy import NaN as npNaN
from pandas import DataFrame, Series, concat
from pandas import concat, DataFrame, Series
from pandas_ta.utils import get_drift, get_offset, verify_series, signals
def rsx(close, length=None, drift=None, offset=None, **kwargs):
"""Indicator: Relative Strength Xtra (inspired by Jurik RSX)"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# variables
vC, v1C = 0, 0
v4, v8, v10, v14, v18, v20 = 0, 0, 0, 0, 0, 0
@@ -30,7 +33,7 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs):
f88 = length - 1.0
else:
f88 = 5.0
f8 = 100.0 * close[i]
f8 = 100.0 * close.iloc[i]
f18 = 3.0 / (length + 2.0)
f20 = 1.0 - f18
else:
@@ -39,7 +42,7 @@ def rsx(close, length=None, drift=None, offset=None, **kwargs):
else:
f90 = f90 + 1
f10 = f8
f8 = 100 * close[i]
f8 = 100 * close.iloc[i]
v8 = f8 - f10
f28 = f20 * f28 + f18 * v8
f30 = f18 * f28 + f20 * f30
+10 -7
View File
@@ -7,16 +7,19 @@ from pandas_ta.utils import get_offset, non_zero_range, verify_series
def rvgi(open_, high, low, close, length=None, swma_length=None, offset=None, **kwargs):
"""Indicator: Relative Vigor Index (RVGI)"""
# Validate Arguments
open_ = verify_series(open_)
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
_length = max(length, swma_length)
open_ = verify_series(open_, _length)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if open_ is None or high is None or low is None or close is None: return
# Calculate Result
numerator = swma(close_open_range, length=swma_length).rolling(length).sum()
denominator = swma(high_low_range, length=swma_length).rolling(length).sum()
@@ -74,9 +77,9 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
swma_length (int): It's period. Default: 4
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 14
swma_length (int): It's period. Default: 4
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+9 -5
View File
@@ -1,23 +1,26 @@
# -*- coding: utf-8 -*-
from math import atan, pi
from numpy import arctan as npAtan
from numpy import pi as npPi
from pandas_ta.utils import get_offset, verify_series
def slope( close, length=None, as_angle=None, to_degrees=None, vertical=None, offset=None, **kwargs):
"""Indicator: Slope"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 1
as_angle = True if isinstance(as_angle, bool) else False
to_degrees = True if isinstance(to_degrees, bool) else False
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
slope = close.diff(length) / length
if as_angle:
slope = slope.apply(atan)
slope = slope.apply(npAtan)
if to_degrees:
slope *= 180 / pi
slope *= 180 / npPi
# Offset
if offset != 0:
@@ -39,7 +42,8 @@ def slope( close, length=None, as_angle=None, to_degrees=None, vertical=None, of
slope.__doc__ = \
"""Slope
Returns the slope of a series of length n. Can convert the slope to angle. Default: slope.
Returns the slope of a series of length n. Can convert the slope to angle.
Default: slope.
Sources: Algebra I
+5 -3
View File
@@ -1,22 +1,24 @@
# -*- coding: utf-8 -*-
from pandas import concat, DataFrame
from pandas import DataFrame
from .tsi import tsi
from pandas_ta.overlap import ema
from pandas_ta.utils import get_offset, verify_series, signals
from pandas_ta.utils import get_offset, verify_series
def smi(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs):
"""Indicator: SMI Ergodic Indicator (SMIIO)"""
# Validate arguments
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 5
slow = int(slow) if slow and slow > 0 else 20
signal = int(signal) if signal and signal > 0 else 5
if slow < fast:
fast, slow = slow, fast
scalar = float(scalar) if scalar else 1
close = verify_series(close, max(fast, slow, signal))
offset = get_offset(offset)
if close is None: return
# Calculate Result
smi = tsi(close, fast=fast, slow=slow, scalar=scalar)
signalma = ema(smi, signal)
+8 -7
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from numpy import NaN as npNaN
from pandas import DataFrame
from pandas_ta.momentum import mom
from pandas_ta.overlap import ema, linreg, sma
from pandas_ta.trend import decreasing, increasing
@@ -13,17 +12,19 @@ from pandas_ta.utils import unsigned_differences, verify_series
def squeeze(high, low, close, bb_length=None, bb_std=None, kc_length=None, kc_scalar=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs):
"""Indicator: Squeeze Momentum (SQZ)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
offset = get_offset(offset)
bb_length = int(bb_length) if bb_length and bb_length > 0 else 20
bb_std = float(bb_std) if bb_std and bb_std > 0 else 2.0
kc_length = int(kc_length) if kc_length and kc_length > 0 else 20
kc_scalar = float(kc_scalar) if kc_scalar and kc_scalar > 0 else 1.5
mom_length = int(mom_length) if mom_length and mom_length > 0 else 12
mom_smooth = int(mom_smooth) if mom_smooth and mom_smooth > 0 else 6
_length = max(bb_length, kc_length, mom_length, mom_smooth)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
use_tr = kwargs.setdefault("tr", True)
asint = kwargs.pop("asint", True)
@@ -203,7 +204,7 @@ Args:
mom_length (int): Momentum Period. Default: 12
mom_smooth (int): Smoothing Period of Momentum. Default: 6
mamode (str): Only "ema" or "sma". Default: "sma"
offset (int): How many periods to offset the result. Default: 0
offset (int): How many periods to offset the result. Default: 0
Kwargs:
tr (value, optional): Use True Range for Keltner Channels. Default: True
+7 -4
View File
@@ -7,14 +7,17 @@ from pandas_ta.utils import get_offset, non_zero_range, verify_series
def stoch(high, low, close, k=None, d=None, smooth_k=None, offset=None, **kwargs):
"""Indicator: Stochastic Oscillator (STOCH)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
k = k if k and k > 0 else 14
d = d if d and d > 0 else 3
smooth_k = smooth_k if smooth_k and smooth_k > 0 else 3
_length = max(k, d, smooth_k)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
lowest_low = low.rolling(k).min()
highest_high = high.rolling(k).max()
@@ -88,7 +91,7 @@ Args:
k (int): The Fast %K period. Default: 14
d (int): The Slow %K period. Default: 3
smooth_k (int): The Slow %D period. Default: 3
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)
+4 -2
View File
@@ -8,13 +8,15 @@ from pandas_ta.utils import get_offset, non_zero_range, verify_series
def stochrsi(close, length=None, rsi_length=None, k=None, d=None, offset=None, **kwargs):
"""Indicator: Stochastic RSI Oscillator (STOCHRSI)"""
# Validate arguments
close = verify_series(close)
length = length if length and length > 0 else 14
rsi_length = rsi_length if rsi_length and rsi_length > 0 else 14
k = k if k and k > 0 else 3
d = d if d and d > 0 else 3
close = verify_series(close, max(length, rsi_length, k, d))
offset = get_offset(offset)
if close is None: return
# Calculate Result
rsi_ = rsi(close, length=rsi_length)
lowest_rsi = rsi_.rolling(length).min()
@@ -90,7 +92,7 @@ Args:
rsi_length (int): RSI period. Default: 14
k (int): The Fast %K period. Default: 3
d (int): The Slow %K period. Default: 3
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)
+105
View File
@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# import numpy as np
from numpy import where as npWhere
from pandas import DataFrame, Series
from pandas_ta.utils import get_offset, verify_series
def td_seq(close, asint=None, offset=None, **kwargs):
"""Indicator: Tom Demark Sequential (TD_SEQ)"""
# Validate arguments
close = verify_series(close)
offset = get_offset(offset)
asint = asint if isinstance(asint, bool) else False
show_all = kwargs.setdefault("show_all", True)
def true_sequence_count(series: Series):
index = series.where(series == False).last_valid_index()
if index is None:
return series.count()
else:
s = series[series.index > index]
return s.count()
def calc_td(series: Series, direction: str, show_all: bool):
td_bool = series.diff(4) > 0 if direction=="up" else series.diff(4) < 0
td_num = npWhere(
td_bool, td_bool.rolling(13, min_periods=0).apply(true_sequence_count), 0
)
td_num = Series(td_num)
if show_all:
td_num = td_num.mask(td_num == 0)
else:
td_num = td_num.mask(~td_num.between(6,9))
return td_num
up_seq = calc_td(close, "up", show_all)
down_seq = calc_td(close, "down", show_all)
if asint:
if up_seq.hasnans and down_seq.hasnans:
up_seq.fillna(0, inplace=True)
down_seq.fillna(0, inplace=True)
up_seq = up_seq.astype(int)
down_seq = down_seq.astype(int)
# Offset
if offset != 0:
up_seq = up_seq.shift(offset)
down_seq = down_seq.shift(offset)
# Handle fills
if "fillna" in kwargs:
up_seq.fillna(kwargs["fillna"], inplace=True)
down_seq.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
up_seq.fillna(method=kwargs["fill_method"], inplace=True)
down_seq.fillna(method=kwargs["fill_method"], inplace=True)
# Name & Category
up_seq.name = f"TD_SEQ_UPa" if show_all else f"TD_SEQ_UP"
down_seq.name = f"TD_SEQ_DNa" if show_all else f"TD_SEQ_DN"
up_seq.category = down_seq.category = "momentum"
# Prepare Dataframe to return
data = {
up_seq.name: up_seq,
down_seq.name: down_seq
}
df = DataFrame(data)
df.name = "TD_SEQ"
df.category = up_seq.category
return df
td_seq.__doc__ = \
"""TD Sequential (TD_SEQ)
Tom DeMark's Sequential indicator attempts to identify a price point where an
uptrend or a downtrend exhausts itself and reverses.
Sources:
https://tradetrekker.wordpress.com/tdsequential/
Calculation:
Compare current close price with 4 days ago price, up to 13 days. For the
consecutive ascending or descending price sequence, display 6th to 9th day
value.
Args:
close (pd.Series): Series of 'close's
asint (bool): If True, fillnas with 0 and change type to int. Default: False
offset (int): How many periods to offset the result. Default: 0
Kwargs:
show_all (bool): Show 1 - 13. If set to False, show 6 - 9. Default: True
fillna (value, optional): pd.DataFrame.fillna(value)
Returns:
pd.DataFrame: New feature generated.
"""
+8 -6
View File
@@ -7,13 +7,15 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def trix(close, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Trix (TRIX)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
signal = int(signal) if signal and signal > 0 else 9
scalar = float(scalar) if scalar else 100
close = verify_series(close, max(length, signal))
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
# Calculate Result
ema1 = ema(close=close, length=length, **kwargs)
ema2 = ema(close=ema1, length=length, **kwargs)
@@ -68,11 +70,11 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 18
signal (int): It's period. Default: 9
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 18
signal (int): It's period. Default: 9
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+5 -2
View File
@@ -6,14 +6,17 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: True Strength Index (TSI)"""
# Validate Arguments
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 13
slow = int(slow) if slow and slow > 0 else 25
# if slow < fast:
# fast, slow = slow, fast
scalar = float(scalar) if scalar else 100
close = verify_series(close, max(fast, slow))
drift = get_drift(drift)
offset = get_offset(offset)
if "length" in kwargs: kwargs.pop("length")
if close is None: return
# Calculate Result
diff = close.diff(drift)
@@ -73,7 +76,7 @@ Args:
slow (int): The long period. Default: 25
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. 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)
+19 -19
View File
@@ -6,20 +6,20 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def uo(high, low, close, fast=None, medium=None, slow=None, fast_w=None, medium_w=None, slow_w=None, drift=None, offset=None, **kwargs):
"""Indicator: Ultimate Oscillator (UO)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 7
fast_w = float(fast_w) if fast_w and fast_w > 0 else 4.0
medium = int(medium) if medium and medium > 0 else 14
medium_w = float(medium_w) if medium_w and medium_w > 0 else 2.0
slow = int(slow) if slow and slow > 0 else 28
slow_w = float(slow_w) if slow_w and slow_w > 0 else 1.0
_length = max(fast, medium, slow)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
drift = get_drift(drift)
offset = get_offset(offset)
fast = int(fast) if fast and fast > 0 else 7
fast_w = float(fast_w) if fast_w and fast_w > 0 else 4.0
medium = int(medium) if medium and medium > 0 else 14
medium_w = float(medium_w) if medium_w and medium_w > 0 else 2.0
slow = int(slow) if slow and slow > 0 else 28
slow_w = float(slow_w) if slow_w and slow_w > 0 else 1.0
if high is None or low is None or close is None: return
# Calculate Result
tdf = DataFrame({
@@ -90,14 +90,14 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
fast (int): The Fast %K period. Default: 7
medium (int): The Slow %K period. Default: 14
slow (int): The Slow %D period. Default: 28
fast_w (float): The Fast %K period. Default: 4.0
medium_w (float): The Slow %K period. Default: 2.0
slow_w (float): The Slow %D period. Default: 1.0
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
fast (int): The Fast %K period. Default: 7
medium (int): The Slow %K period. Default: 14
slow (int): The Slow %D period. Default: 28
fast_w (float): The Fast %K period. Default: 4.0
medium_w (float): The Slow %K period. Default: 2.0
slow_w (float): The Slow %D period. Default: 1.0
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+9 -6
View File
@@ -1,17 +1,20 @@
# -*- coding: utf-8 -*-
from pandas_ta.utils import get_drift, get_offset, verify_series
from pandas_ta.utils import get_offset, verify_series
def willr(high, low, close, length=None, offset=None, **kwargs):
"""Indicator: William's Percent R (WILLR)"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
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
_length = max(length, min_periods)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
lowest_low = low.rolling(length, min_periods=min_periods).min()
highest_high = high.rolling(length, min_periods=min_periods).max()
@@ -56,8 +59,8 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 14
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+2
View File
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from .alma import alma
from .dema import dema
from .ema import ema
from .fwma import fwma
@@ -6,6 +7,7 @@ from .hilo import hilo
from .hl2 import hl2
from .hlc3 import hlc3
from .hma import hma
from .hwma import hwma
from .kama import kama
from .ichimoku import ichimoku
from .linreg import linreg
+89
View File
@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
from numpy import exp as npExp
from numpy import NaN as npNaN
from pandas import Series
from pandas_ta.utils import get_offset, verify_series
def alma(close, length=None, sigma=None, distribution_offset=None, offset=None, **kwargs):
"""Indicator: Arnaud Legoux Moving Average (ALMA)"""
# Validate Arguments
length = int(length) if length and length > 0 else 10
sigma = float(sigma) if sigma and sigma > 0 else 6.0
distribution_offset = float(distribution_offset) if distribution_offset and distribution_offset > 0 else 0.85
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Pre-Calculations
m = distribution_offset * (length - 1)
s = length / sigma
wtd = list(range(length))
for i in range(0, length):
wtd[i] = npExp(-1 * ((i - m) * (i - m)) / (2 * s * s))
# Calculate Result
result = [npNaN for _ in range(0, length - 1)] + [0]
for i in range(length, close.size):
window_sum = 0
cum_sum = 0
for j in range(0, length):
# wtd = math.exp(-1 * ((j - m) * (j - m)) / (2 * s * s)) # moved to pre-calc for efficiency
window_sum = window_sum + wtd[j] * close.iloc[i - j]
cum_sum = cum_sum + wtd[j]
almean = window_sum / cum_sum
result.append(npNaN) if i == length else result.append(almean)
alma = Series(result, index=close.index)
# Offset
if offset != 0:
alma = alma.shift(offset)
# Handle fills
if "fillna" in kwargs:
alma.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
alma.fillna(method=kwargs["fill_method"], inplace=True)
# Name & Category
alma.name = f"ALMA_{length}_{sigma}_{distribution_offset}"
alma.category = "overlap"
return alma
alma.__doc__ = \
"""Arnaud Legoux Moving Average (ALMA)
The ALMA moving average uses the curve of the Normal (Gauss) distribution, which
can be shifted from 0 to 1. This allows regulating the smoothness and high
sensitivity of the indicator. Sigma is another parameter that is responsible for
the shape of the curve coefficients. This moving average reduces lag of the data
in conjunction with smoothing to reduce noise.
Implemented for Pandas TA by rengel8 based on the source provided below.
Sources:
https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/
Calculation:
refer to provided source
Args:
close (pd.Series): Series of 'close's
length (int): It's period, window size. Default: 10
sigma (float): Smoothing value. Default 6.0
distribution_offset (float): Value to offset the distribution min 0
(smoother), max 1 (more responsive). Default 0.85
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.
"""
+5 -3
View File
@@ -6,10 +6,12 @@ from pandas_ta.utils import get_offset, verify_series
def dema(close, length=None, offset=None, **kwargs):
"""Indicator: Double Exponential Moving Average (DEMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
ema1 = ema(close=close, length=length)
ema2 = ema(close=ema1, length=length)
@@ -46,8 +48,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+5 -3
View File
@@ -6,12 +6,14 @@ from pandas_ta.utils import get_offset, verify_series
def ema(close, length=None, offset=None, **kwargs):
"""Indicator: Exponential Moving Average (EMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
adjust = kwargs.pop("adjust", False)
sma = kwargs.pop("sma", True)
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
if sma:
close = close.copy()
@@ -55,8 +57,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
adjust (bool, optional): Default: False
+6 -4
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import fibonacci, get_offset, verify_series, weights
def fwma(close, length=None, asc=None, offset=None, **kwargs):
"""Indicator: Fibonacci's Weighted Moving Average (FWMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
asc = asc if asc else True
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
fibs = fibonacci(n=length, weighted=True)
fwma = close.rolling(length, min_periods=length).apply(weights(fibs), raw=True)
@@ -47,9 +49,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+8 -6
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from numpy import NaN as npNaN
from pandas import DataFrame, Series
# from pandas_ta.overlap.ma import ma
from .ma import ma
from pandas_ta.utils import get_offset, verify_series
@@ -9,14 +8,17 @@ from pandas_ta.utils import get_offset, verify_series
def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offset=None, **kwargs):
"""Indicator: Gann HiLo (HiLo)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
high_length = int(high_length) if high_length and high_length > 0 else 13
low_length = int(low_length) if low_length and low_length > 0 else 21
mamode = mamode.lower() if isinstance(mamode, str) else "sma"
_length = max(high_length, low_length)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
m = close.size
hilo = Series(npNaN, index=close.index)
@@ -113,8 +115,8 @@ Args:
close (pd.Series): Series of 'close's
high_length (int): It's period. Default: 13
low_length (int): It's period. Default: 21
mamode (str): Options: 'sma' or 'ema'. Default: 'sma'
offset (int): How many periods to offset the result. Default: 0
mamode (str): Options: 'sma' or 'ema'. Default: 'sma'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
adjust (bool): Default: True
+8 -6
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from math import sqrt
from numpy import sqrt as npSqrt
from .wma import wma
from pandas_ta.utils import get_offset, verify_series
@@ -7,13 +7,15 @@ from pandas_ta.utils import get_offset, verify_series
def hma(close, length=None, offset=None, **kwargs):
"""Indicator: Hull Moving Average (HMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
half_length = int(length / 2)
sqrt_length = int(sqrt(length))
sqrt_length = int(npSqrt(length))
wmaf = wma(close=close, length=half_length)
wmas = wma(close=close, length=length)
@@ -44,7 +46,7 @@ Calculation:
length=10
WMA = Weighted Moving Average
half_length = int(0.5 * length)
sqrt_length = int(math.sqrt(length))
sqrt_length = int(sqrt(length))
wmaf = WMA(close, half_length)
wmas = WMA(close, length)
@@ -52,8 +54,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+82
View File
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
from pandas import Series
from pandas_ta.utils import get_offset, verify_series
def hwma(close, na=None, nb=None, nc=None, offset=None, **kwargs):
"""Indicator: Holt-Winter Moving Average"""
# Validate Arguments
na = float(na) if na and na > 0 and na < 1 else 0.2
nb = float(nb) if nb and nb > 0 and nb < 1 else 0.1
nc = float(nc) if nc and nc > 0 and nc < 1 else 0.1
close = verify_series(close)
offset = get_offset(offset)
# Calculate Result
last_a = last_v = 0
last_f = close.iloc[0]
result = []
m = close.size
for i in range(m):
F = (1.0 - na) * (last_f + last_v + 0.5 * last_a) + na * close.iloc[i]
V = (1.0 - nb) * (last_v + last_a) + nb * (F - last_f)
A = (1.0 - nc) * last_a + nc * (V - last_v)
result.append((F + V + 0.5 * A))
last_a, last_f, last_v = A, F, V # update values
hwma = Series(result, index=close.index)
# Offset
if offset != 0:
hwma = hwma.shift(offset)
# Handle fills
if "fillna" in kwargs:
hwma.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
hwma.fillna(method=kwargs["fill_method"], inplace=True)
# Name & Category
suffix = f"{na}_{nb}_{nc}"
hwma.name = f"HWMA_{suffix}"
hwma.category = "overlap"
return hwma
hwma.__doc__ = \
"""HWMA (Holt-Winter Moving Average)
Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving average
by the Holt-Winter method; the three parameters should be selected to obtain a
forecast.
This version has been implemented for Pandas TA by rengel8 based
on a publication for MetaTrader 5.
Sources:
https://www.mql5.com/en/code/20856
Calculation:
HWMA[i] = F[i] + V[i] + 0.5 * A[i]
where..
F[i] = (1-na) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + na * Price[i]
V[i] = (1-nb) * (V[i-1] + A[i-1]) + nb * (F[i] - F[i-1])
A[i] = (1-nc) * A[i-1] + nc * (V[i] - V[i-1])
Args:
close (pd.Series): Series of 'close's
na (float): Smoothed series parameter (from 0 to 1). Default: 0.2
nb (float): Trend parameter (from 0 to 1). Default: 0.1
nc (float): Seasonality parameter (from 0 to 1). Default: 0.1
close (pd.Series): Series of 'close's
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
pd.Series: hwma
"""
+10 -7
View File
@@ -6,14 +6,17 @@ from pandas_ta.utils import get_offset, verify_series
def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, offset=None, **kwargs):
"""Indicator: Ichimoku Kinkō Hyō (Ichimoku)"""
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
tenkan = int(tenkan) if tenkan and tenkan > 0 else 9
kijun = int(kijun) if kijun and kijun > 0 else 26
senkou = int(senkou) if senkou and senkou > 0 else 52
_length = max(tenkan, kijun, senkou)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return None, None
# Calculate Result
tenkan_sen = midprice(high=high, low=low, length=tenkan)
kijun_sen = midprice(high=high, low=low, length=kijun)
@@ -115,10 +118,10 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
tenkan (int): Tenkan period. Default: 9
kijun (int): Kijun period. Default: 26
senkou (int): Senkou period. Default: 52
offset (int): How many periods to offset the result. Default: 0
tenkan (int): Tenkan period. Default: 9
kijun (int): Kijun period. Default: 26
senkou (int): Senkou period. Default: 52
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+12 -11
View File
@@ -1,22 +1,22 @@
# -*- coding: utf-8 -*-
from numpy import NaN as npNaN
from pandas import Series, DataFrame
from pandas import Series
from pandas_ta.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)"""
"""Indicator: Kaufman's Adaptive Moving Average (KAMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
fast = int(fast) if fast and fast > 0 else 2
slow = int(slow) if slow and slow > 0 else 30
close = verify_series(close, max(fast, slow, length))
drift = get_drift(drift)
offset = get_offset(offset)
# Calculate Result
m = close.size
if close is None: return
# Calculate Result
def weight(length: int) -> float:
return 2 / (length + 1)
@@ -30,9 +30,10 @@ def kama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kw
x = er * (fr - sr) + sr
sc = x * x
m = close.size
result = [npNaN for _ in range(0, length - 1)] + [0]
for i in range(length, m):
result.append(sc[i] * close[i] + (1 - sc[i]) * result[i - 1])
result.append(sc.iloc[i] * close.iloc[i] + (1 - sc.iloc[i]) * result[i - 1])
kama = Series(result, index=close.index)
@@ -66,11 +67,11 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
fast (int): Fast MA period. Default: 2
slow (int): Slow MA period. Default: 30
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
fast (int): Fast MA period. Default: 2
slow (int): Slow MA period. Default: 30
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+18 -10
View File
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
import math
from numpy import arctan as npAtan
from numpy import pi as npPi
from numpy import sqrt as npSqrt
from pandas_ta.utils import get_offset, verify_series
def linreg(close, length=None, offset=None, **kwargs):
"""Indicator: Linear Regression"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
close = verify_series(close, length)
offset = get_offset(offset)
angle = kwargs.pop("angle", False)
intercept = kwargs.pop("intercept", False)
@@ -16,6 +18,8 @@ def linreg(close, length=None, offset=None, **kwargs):
slope = kwargs.pop("slope", False)
tsf = kwargs.pop("tsf", False)
if close is None: return
# Calculate Result
x = range(1, length + 1) # [1, 2, ..., n] from 1 to n keeps Sum(xy) low
x_sum = 0.5 * length * (length + 1)
@@ -34,15 +38,15 @@ def linreg(close, length=None, offset=None, **kwargs):
return b
if angle:
theta = math.atan(m)
theta = npAtan(m)
if degrees:
theta *= 180 / math.pi
theta *= 180 / npPi
return theta
if r:
y2_sum = (series * series).sum()
rn = length * xy_sum - x_sum * y_sum
rd = math.sqrt(divisor * (length * y2_sum - y_sum * y_sum))
rd = npSqrt(divisor * (length * y2_sum - y_sum * y_sum))
return rn / rd
return m * length + b if tsf else m * (length - 1) + b
@@ -105,12 +109,16 @@ Args:
offset (int): How many periods to offset the result. Default: 0
Kwargs:
angle (bool, optional): If True, returns the angle of the slope in radians. Default: False.
degrees (bool, optional): If True, returns the angle of the slope in degrees. Default: False.
intercept (bool, optional): If True, returns the angle of the slope in radians. Default: False.
r (bool, optional): If True, returns it's correlation 'r'. Default: False.
angle (bool, optional): If True, returns the angle of the slope in radians.
Default: False.
degrees (bool, optional): If True, returns the angle of the slope in
degrees. Default: False.
intercept (bool, optional): If True, returns the angle of the slope in
radians. Default: False.
r (bool, optional): If True, returns it's correlation 'r'. Default: False.
slope (bool, optional): If True, returns the slope. Default: False.
tsf (bool, optional): If True, returns the Time Series Forecast value. Default: False.
tsf (bool, optional): If True, returns the Time Series Forecast value.
Default: False.
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
+3 -1
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import get_offset, verify_series
def mcgd(close, length=None, offset=None, c=None, **kwargs):
"""Indicator: McGinley Dynamic Indicator"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
c = float(c) if c and 0 < c <= 1 else 1
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
close = close.copy()
+3 -1
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import get_offset, verify_series
def midpoint(close, length=None, offset=None, **kwargs):
"""Indicator: Midpoint"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 2
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
lowest = close.rolling(length, min_periods=min_periods).min()
highest = close.rolling(length, min_periods=min_periods).max()
+5 -2
View File
@@ -5,12 +5,15 @@ from pandas_ta.utils import get_offset, verify_series
def midprice(high, low, length=None, offset=None, **kwargs):
"""Indicator: Midprice"""
# Validate arguments
high = verify_series(high)
low = verify_series(low)
length = int(length) if length and length > 0 else 2
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
_length = max(length, min_periods)
high = verify_series(high, _length)
low = verify_series(low, _length)
offset = get_offset(offset)
if high is None or low is None: return
# Calculate Result
lowest_low = low.rolling(length, min_periods=min_periods).min()
highest_high = high.rolling(length, min_periods=min_periods).max()
+7 -6
View File
@@ -5,12 +5,13 @@ from pandas_ta.utils import get_offset, pascals_triangle, verify_series, weights
def pwma(close, length=None, asc=None, offset=None, **kwargs):
"""Indicator: Pascals Weighted Moving Average (PWMA)"""
# 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
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
triangle = pascals_triangle(n=length - 1, weighted=True)
pwma = close.rolling(length, min_periods=length).apply(weights(triangle), raw=True)
@@ -29,8 +30,8 @@ def pwma(close, length=None, asc=None, offset=None, **kwargs):
pwma.__doc__ = \
"""Pascal's Weighted Moving Average (PWMA)
Pascal's Weighted Moving Average is similar to a symmetric triangular
window except PWMA's weights are based on Pascal's Triangle.
Pascal's Weighted Moving Average is similar to a symmetric triangular window
except PWMA's weights are based on Pascal's Triangle.
Source: Kevin Johnson
@@ -49,8 +50,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+8 -5
View File
@@ -5,10 +5,12 @@ from pandas_ta.utils import get_offset, verify_series
def rma(close, length=None, offset=None, **kwargs):
"""Indicator: wildeR's Moving Average (RMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
offset = get_offset(offset)
alpha = (1.0 / length) if length > 0 else 0.5
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
rma = close.ewm(alpha=alpha, min_periods=length).mean()
@@ -27,7 +29,8 @@ def rma(close, length=None, offset=None, **kwargs):
rma.__doc__ = \
"""wildeR's Moving Average (RMA)
The WildeR's Moving Average is simply an Exponential Moving Average (EMA) with a modified alpha = 1 / length.
The WildeR's Moving Average is simply an Exponential Moving Average (EMA) with
a modified alpha = 1 / length.
Sources:
https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing
@@ -42,8 +45,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+10 -8
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from math import pi
from math import sin
from numpy import pi as npPi
from numpy import sin as npSin
from pandas import Series
from pandas_ta.utils import get_offset, verify_series, weights
@@ -8,12 +8,14 @@ from pandas_ta.utils import get_offset, verify_series, weights
def sinwma(close, length=None, offset=None, **kwargs):
"""Indicator: Sine Weighted Moving Average (SINWMA) by Everget of TradingView"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
sines = Series([sin((i + 1) * pi / (length + 1)) for i in range(0, length)])
sines = Series([npSin((i + 1) * npPi / (length + 1)) for i in range(0, length)])
w = sines / sines.sum()
sinwma = close.rolling(length, min_periods=length).apply(weights(w), raw=True)
@@ -32,8 +34,8 @@ def sinwma(close, length=None, offset=None, **kwargs):
sinwma.__doc__ = \
"""Sine Weighted Moving Average (SWMA)
A weighted average using sine cycles. The middle term(s) of the average have the highest
weight(s).
A weighted average using sine cycles. The middle term(s) of the average have the
highest weight(s).
Source:
https://www.tradingview.com/script/6MWFvnPO-Sine-Weighted-Moving-Average/
@@ -54,8 +56,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+5 -3
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import get_offset, verify_series
def sma(close, length=None, offset=None, **kwargs):
"""Indicator: Simple Moving Average (SMA)"""
# 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
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
sma = close.rolling(length, min_periods=min_periods).mean()
@@ -46,8 +48,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
adjust (bool): Default: True
+3 -2
View File
@@ -3,18 +3,19 @@ from numpy import cos as npCos
from numpy import exp as npExp
from numpy import pi as npPi
from numpy import sqrt as npSqrt
from pandas import Series
from pandas_ta.utils import get_offset, verify_series
def ssf(close, length=None, poles=None, offset=None, **kwargs):
"""Indicator: Ehler's Super Smoother Filter (SSF)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
poles = int(poles) if poles in [2, 3] else 2
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
m = close.size
ssf = close.copy()
+8 -5
View File
@@ -9,13 +9,15 @@ from pandas_ta.utils import get_offset, verify_series
def supertrend(high, low, close, length=None, multiplier=None, offset=None, **kwargs):
"""Indicator: Supertrend"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 7
multiplier = float(multiplier) if multiplier and multiplier > 0 else 3.0
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Results
m = close.size
dir_, trend = [1] * m, [0] * m
@@ -109,8 +111,9 @@ Args:
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int) : length for ATR calculation. Default: 7
multiplier (float): Coefficient for upper and lower band distance to midrange. Default: 3.0
offset (int): How many periods to offset the result. Default: 0
multiplier (float): Coefficient for upper and lower band distance to
midrange. Default: 3.0
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+11 -7
View File
@@ -5,15 +5,18 @@ from pandas_ta.utils import get_offset, symmetric_triangle, verify_series, weigh
def swma(close, length=None, asc=None, offset=None, **kwargs):
"""Indicator: Symmetric Weighted Moving Average (SWMA)"""
# 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
# 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
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
triangle = symmetric_triangle(length, weighted=True)
swma = close.rolling(length, min_periods=length).apply(weights(triangle), raw=True)
# swma = close.rolling(length).apply(weights(triangle), raw=True)
# Offset
if offset != 0:
@@ -30,8 +33,9 @@ swma.__doc__ = \
"""Symmetric Weighted Moving Average (SWMA)
Symmetric Weighted Moving Average where weights are based on a symmetric
triangle. For example: n=3 -> [1, 2, 1], n=4 -> [1, 2, 2, 1], etc... This moving
average has variable length in contrast to TradingView's fixed length of 4.
triangle. For example: n=3 -> [1, 2, 1], n=4 -> [1, 2, 2, 1], etc...
This moving average has variable length in contrast to TradingView's fixed
length of 4.
Source:
https://www.tradingview.com/study-script-reference/#fun_swma
@@ -50,9 +54,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+6 -4
View File
@@ -6,11 +6,13 @@ from pandas_ta.utils import get_offset, verify_series
def t3(close, length=None, a=None, offset=None, **kwargs):
"""Indicator: T3"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
a = float(a) if a and a > 0 and a < 1 else 0.7
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
c1 = -a * a**2
c2 = 3 * a**2 + 3 * a**3
@@ -62,9 +64,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
a (float): 0 < a < 1. Default: 0.7
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
a (float): 0 < a < 1. Default: 0.7
offset (int): How many periods to offset the result. Default: 0
Kwargs:
adjust (bool): Default: True
+5 -3
View File
@@ -6,10 +6,12 @@ from pandas_ta.utils import get_offset, verify_series
def tema(close, length=None, offset=None, **kwargs):
"""Indicator: Triple Exponential Moving Average (TEMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
ema1 = ema(close=close, length=length, **kwargs)
ema2 = ema(close=ema1, length=length, **kwargs)
@@ -46,8 +48,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
adjust (bool): Default: True
+6 -4
View File
@@ -6,10 +6,12 @@ from pandas_ta.utils import get_offset, verify_series
def trima(close, length=None, offset=None, **kwargs):
"""Indicator: Triangular Moving Average (TRIMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
half_length = round(0.5 * (length + 1))
sma1 = sma(close, length=half_length)
@@ -41,14 +43,14 @@ Calculation:
Default Inputs:
length=10
SMA = Simple Moving Average
half_length = math.round(0.5 * (length + 1))
half_length = round(0.5 * (length + 1))
SMA1 = SMA(close, half_length)
TRIMA = SMA(SMA1, half_length)
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
adjust (bool): Default: True
+3 -1
View File
@@ -7,11 +7,13 @@ from pandas_ta.utils import get_drift, get_offset, verify_series
def vidya(close, length=None, drift=None, offset=None, **kwargs):
"""Indicator: Variable Index Dynamic Average (VIDYA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 14
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if close is None: return
def _cmo(source: Series, n:int , d: int):
"""Chande Momentum Oscillator (CMO) Patch
For some reason: from pandas_ta.momentum import cmo causes
+6 -4
View File
@@ -6,11 +6,13 @@ from pandas_ta.utils import get_offset, verify_series
def vwma(close, volume, length=None, offset=None, **kwargs):
"""Indicator: Volume Weighted Moving Average (VWMA)"""
# Validate Arguments
close = verify_series(close)
volume = verify_series(volume)
length = int(length) if length and length > 0 else 10
close = verify_series(close, length)
volume = verify_series(volume, length)
offset = get_offset(offset)
if close is None or volume is None: return
# Calculate Result
pv = close * volume
vwma = sma(close=pv, length=length) / sma(close=volume, length=length)
@@ -44,8 +46,8 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+1 -1
View File
@@ -40,7 +40,7 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
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)
+6 -4
View File
@@ -8,11 +8,13 @@ from pandas_ta.utils import get_offset, verify_series
def wma(close, length=None, asc=None, offset=None, **kwargs):
"""Indicator: Weighted Moving Average (WMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
asc = asc if asc else True
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
total_weight = 0.5 * length * (length + 1)
weights_ = Series(npArange(1, length + 1))
@@ -62,9 +64,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
asc (bool): Recent values weigh more. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+7 -5
View File
@@ -8,10 +8,12 @@ from pandas_ta.utils import get_offset, verify_series
def zlma(close, length=None, mamode=None, offset=None, **kwargs):
"""Indicator: Zero Lag Moving Average (ZLMA)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
offset = get_offset(offset)
mamode = mamode.lower() if isinstance(mamode, str) else "ema"
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
lag = int(0.5 * (length - 1))
@@ -60,9 +62,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
mamode (str): Options: 'ema', 'hma', 'sma', 'wma'. Default: 'ema'
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 10
mamode (str): Options: 'ema', 'hma', 'sma', 'wma'. Default: 'ema'
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+6 -4
View File
@@ -6,10 +6,12 @@ from pandas_ta.utils import get_offset, verify_series
def log_return(close, length=None, cumulative=False, offset=None, **kwargs):
"""Indicator: Log Return"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 1
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
log_return = nplog(close).diff(periods=length)
@@ -50,9 +52,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 20
cumulative (bool): If True, returns the cumulative returns. Default: False
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 20
cumulative (bool): If True, returns the cumulative returns. Default: False
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+6 -4
View File
@@ -5,10 +5,12 @@ from pandas_ta.utils import get_offset, verify_series
def percent_return(close, length=None, cumulative=False, offset=None, **kwargs):
"""Indicator: Percent Return"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 1
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
pct_return = close.pct_change(length)
@@ -43,9 +45,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 20
cumulative (bool): If True, returns the cumulative returns. Default: False
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 20
cumulative (bool): If True, returns the cumulative returns. Default: False
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+3 -2
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame, Series
from pandas import DataFrame
from .log_return import log_return
from .percent_return import percent_return
from pandas_ta.utils import get_offset, verify_series, zero
@@ -12,7 +12,8 @@ def trend_return(close, trend, log=True, cumulative=None, trend_reset=0, trade_o
trend = verify_series(trend)
cumulative = cumulative if cumulative is not None and isinstance(cumulative, bool) else False
trend_reset = int(trend_reset) if trend_reset and isinstance(trend_reset, int) else 0
trade_offset = int(trade_offset) if trade_offset and isinstance(trade_offset, int) else -1
if trade_offset !=0:
trade_offset = int(trade_offset) if trade_offset and isinstance(trade_offset, int) else -1
offset = get_offset(offset)
# Calculate Result
+3 -1
View File
@@ -6,11 +6,13 @@ from pandas_ta.utils import get_offset, verify_series
def entropy(close, length=None, base=None, offset=None, **kwargs):
"""Indicator: Entropy (ENTP)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 10
base = float(base) if base and base > 0 else 2.0
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
p = close / close.rolling(length).sum()
entropy = (-p * npLog(p) / npLog(base)).rolling(length).sum()
+3 -1
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import get_offset, verify_series
def kurtosis(close, length=None, offset=None, **kwargs):
"""Indicator: Kurtosis"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
kurtosis = close.rolling(length, min_periods=min_periods).kurt()
+3 -1
View File
@@ -6,11 +6,13 @@ from pandas_ta.utils import get_offset, verify_series
def mad(close, length=None, offset=None, **kwargs):
"""Indicator: Mean Absolute Deviation"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
def mad_(series):
"""Mean Absolute Deviation"""
+4 -2
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import get_offset, verify_series
def median(close, length=None, offset=None, **kwargs):
"""Indicator: Median"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
median = close.rolling(length, min_periods=min_periods).median()
@@ -27,7 +29,7 @@ def median(close, length=None, offset=None, **kwargs):
median.__doc__ = \
"""Rolling Median
Rolling Median of over 'n' periods. Sibling of a Simple Moving Average.
Rolling Median of over 'n' periods. Sibling of a Simple Moving Average.
Sources:
https://www.incrediblecharts.com/indicators/median_price.php
+3 -1
View File
@@ -5,12 +5,14 @@ from pandas_ta.utils import get_offset, verify_series
def quantile(close, length=None, q=None, offset=None, **kwargs):
"""Indicator: Quantile"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
q = float(q) if q and q > 0 and q < 1 else 0.5
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
quantile = close.rolling(length, min_periods=min_periods).quantile(q)
+3 -1
View File
@@ -5,11 +5,13 @@ from pandas_ta.utils import get_offset, verify_series
def skew(close, length=None, offset=None, **kwargs):
"""Indicator: Skew"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
skew = close.rolling(length, min_periods=min_periods).skew()
+3 -1
View File
@@ -7,11 +7,13 @@ from pandas_ta.utils import get_offset, verify_series
def stdev(close, length=None, ddof=1, offset=None, **kwargs):
"""Indicator: Standard Deviation"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 30
ddof = int(ddof) if ddof >= 0 and ddof < length else 1
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
stdev = variance(close=close, length=length, ddof=ddof).apply(npsqrt)
+3 -2
View File
@@ -5,13 +5,14 @@ from pandas_ta.utils import get_offset, verify_series
def variance(close, length=None, ddof=None, offset=None, **kwargs):
"""Indicator: Variance"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 1 else 30
ddof = int(ddof) if ddof and ddof >= 0 and ddof < length else 0
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
close = verify_series(close, max(length, min_periods))
offset = get_offset(offset)
if close is None: return
# Calculate Result
variance = close.rolling(length, min_periods=min_periods).var(ddof)
+3 -1
View File
@@ -7,11 +7,13 @@ from pandas_ta.utils import get_offset, verify_series
def zscore(close, length=None, std=None, offset=None, **kwargs):
"""Indicator: Z Score"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 1 else 30
std = float(std) if std and std > 1 else 1
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
std *= stdev(close=close, length=length, **kwargs)
mean = sma(close=close, length=length, **kwargs)
+11 -8
View File
@@ -1,21 +1,24 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from pandas_ta.overlap import rma
from pandas_ta.overlap import ma
from pandas_ta.volatility import atr
from pandas_ta.utils import get_drift, get_offset, verify_series, zero
def adx(high, low, close, length=None, scalar=None, drift=None, offset=None, **kwargs):
def adx(high, low, close, length=None, scalar=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: ADX"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = length if length and length > 0 else 14
mamode = mamode if isinstance(mamode, str) else "rma"
scalar = float(scalar) if scalar else 100
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
atr_ = atr(high=high, low=low, close=close, length=length)
@@ -29,11 +32,11 @@ def adx(high, low, close, length=None, scalar=None, drift=None, offset=None, **k
neg = neg.apply(zero)
k = scalar / atr_
dmp = k * rma(close=pos, length=length)
dmn = k * rma(close=neg, length=length)
dmp = k * ma(mamode, pos, length=length)
dmn = k * ma(mamode, neg, length=length)
dx = scalar * (dmp - dmn).abs() / (dmp + dmn)
adx = rma(close=dx, length=length)
adx = ma(mamode, dx, length=length)
# Offset
if offset != 0:
+8 -6
View File
@@ -6,15 +6,18 @@ from pandas_ta.overlap import ma
from pandas_ta.utils import get_offset, verify_series
def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, offset=None, **kwargs):
def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, slope_length=None, offset=None, **kwargs):
"""Indicator: Archer Moving Averages Trends (AMAT)"""
# Validate Arguments
close = verify_series(close)
fast = int(fast) if fast and fast > 0 else 8
slow = int(slow) if slow and slow > 0 else 21
lookback = int(lookback) if lookback and lookback > 0 else 2
mamode = mamode if isinstance(mamode, str) else "ema"
mamode = mamode.lower() if isinstance(mamode, str) else "ema"
close = verify_series(close, max(fast, slow, lookback))
offset = get_offset(offset)
if "length" in kwargs: kwargs.pop("length")
if close is None: return
# # Calculate Result
fast_ma = ma(mamode, close, length=fast, **kwargs)
@@ -38,10 +41,9 @@ def amat(close=None, fast=None, slow=None, mamode=None, lookback=None, offset=No
mas_short.fillna(method=kwargs["fill_method"], inplace=True)
# Prepare DataFrame to return
_lmode = mamode.lower()[0]
amatdf = DataFrame({
f"AMAT{_lmode}_{mas_long.name}": mas_long,
f"AMAT{_lmode}_{mas_short.name}": mas_short
f"AMAT{mamode[0]}_{mas_long.name}": mas_long,
f"AMAT{mamode[0]}_{mas_short.name}": mas_short
})
# Name and Categorize it
+4 -2
View File
@@ -7,12 +7,14 @@ from pandas_ta.utils import recent_maximum_index, recent_minimum_index
def aroon(high, low, length=None, scalar=None, offset=None, **kwargs):
"""Indicator: Aroon & Aroon Oscillator"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
length = length if length and length > 0 else 14
scalar = float(scalar) if scalar else 100
high = verify_series(high, length)
low = verify_series(low, length)
offset = get_offset(offset)
if high is None or low is None: return
# Calculate Result
periods_from_hh = high.rolling(length + 1).apply(recent_maximum_index, raw=True)
periods_from_ll = low.rolling(length + 1).apply(recent_minimum_index, raw=True)
+11 -11
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from numpy import log10 as npLog10
from pandas import DataFrame
from pandas_ta.volatility import atr
from pandas_ta.utils import get_offset, get_drift, verify_series
@@ -8,16 +7,17 @@ from pandas_ta.utils import get_offset, get_drift, verify_series
def chop(high, low, close, length=None, atr_length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Choppiness Index (CHOP)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
length = int(length) if length and length > 0 else 14
atr_length = int(
atr_length) if atr_length is not None and atr_length > 0 else 1
atr_length = int(atr_length) if atr_length is not None and atr_length > 0 else 1
scalar = float(scalar) if scalar else 100
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
drift = get_drift(drift)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
diff = high.rolling(length).max() - low.rolling(length).min()
@@ -71,11 +71,11 @@ Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
atr_length (int): Length for ATR. Default: 1
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 14
atr_length (int): Length for ATR. Default: 1
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+13 -11
View File
@@ -7,14 +7,17 @@ from pandas_ta.utils import get_offset, verify_series
def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs):
"""Indicator: Chande Kroll Stop (CKSP)"""
# Validate Arguments
high = verify_series(high)
low = verify_series(low)
close = verify_series(close)
p = int(p) if p and p > 0 else 10
x = float(x) if x and x > 0 else 1
q = int(q) if q and q > 0 else 9
_length = max(p, q, x)
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
offset = get_offset(offset)
if high is None or low is None or close is None: return
# Calculate Result
atr_ = atr(high=high, low=low, close=close, length=p)
@@ -54,10 +57,9 @@ def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs):
cksp.__doc__ = \
"""Chande Kroll Stop (CKSP)
The Tushar Chande and Stanley Kroll in their book
“The New Technical Trader”. It is a trend-following indicator,
identifying your stop by calculating the average true range of
the recent market volatility.
The Tushar Chande and Stanley Kroll in their book “The New Technical Trader”.
It is a trend-following indicator, identifying your stop by calculating the
average true range of the recent market volatility.
Sources:
https://www.multicharts.com/discussion/viewtopic.php?t=48914
@@ -75,10 +77,10 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
p (int): ATR and first stop period. Default: 10
x (float): ATR scalar. Default: 1
q (int): Second stop period. Default: 9
offset (int): How many periods to offset the result. Default: 0
p (int): ATR and first stop period. Default: 10
x (float): ATR scalar. Default: 1
q (int): Second stop period. Default: 9
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+5 -3
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from math import exp
from numpy import exp as npExp
from pandas import DataFrame
from pandas_ta.utils import get_offset, verify_series
@@ -7,16 +7,18 @@ from pandas_ta.utils import get_offset, verify_series
def decay(close, kind=None, length=None, mode=None, offset=None, **kwargs):
"""Indicator: Decay"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 5
mode = mode.lower() if isinstance(mode, str) else "linear"
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
_mode = "L"
if mode == "exp" or kind == "exponential":
_mode = "EXP"
diff = close.shift(1) - exp(-length)
diff = close.shift(1) - npExp(-length)
else: # "linear"
diff = close.shift(1) - (1 / length)
diff[0] = close[0]
+9 -3
View File
@@ -5,19 +5,22 @@ from pandas_ta.utils import get_offset, verify_series
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
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
def stricly_decreasing(series, n):
return all([i > j for i,j in zip(series[-n:], series[1:])])
# Calculate Result
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 = close.rolling(length, min_periods=length) \
.apply(stricly_decreasing, args=(length,), raw=False)
decreasing.fillna(0, inplace=True)
decreasing = decreasing.astype(bool)
else:
@@ -46,7 +49,10 @@ def decreasing(close, length=None, strict=None, asint=None, offset=None, **kwarg
decreasing.__doc__ = \
"""Decreasing
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.
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:
if strict:
+6 -4
View File
@@ -6,10 +6,12 @@ from pandas_ta.utils import get_offset, verify_series
def dpo(close, length=None, centered=True, offset=None, **kwargs):
"""Indicator: Detrend Price Oscillator (DPO)"""
# Validate Arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 20
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
# Calculate Result
t = int(0.5 * length) + 1
ma = sma(close, length)
@@ -58,9 +60,9 @@ Calculation:
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 1
centered (bool): Shift the dpo back by int(0.5 * length) + 1. Default: True
offset (int): How many periods to offset the result. Default: 0
length (int): It's period. Default: 1
centered (bool): Shift the dpo back by int(0.5 * length) + 1. Default: True
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
+9 -3
View File
@@ -5,19 +5,22 @@ from pandas_ta.utils import get_offset, verify_series
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
close = verify_series(close, length)
offset = get_offset(offset)
if close is None: return
def stricly_increasing(series, n):
return all([i < j for i,j in zip(series[-n:], series[1:])])
# Calculate Result
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 = close.rolling(length, min_periods=length) \
.apply(stricly_increasing, args=(length,), raw=False)
increasing.fillna(0, inplace=True)
increasing = increasing.astype(bool)
else:
@@ -46,7 +49,10 @@ def increasing(close, length=None, strict=None, asint=None, offset=None, **kwarg
increasing.__doc__ = \
"""Increasing
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.
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:

Some files were not shown because too many files have changed in this diff Show More