Skip to content

Commit

Permalink
Merge branch 'development' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
twopirllc committed Jul 28, 2021
2 parents e44ff1b + 0d9c5b9 commit bc3b292
Show file tree
Hide file tree
Showing 90 changed files with 1,182 additions and 350 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ AlphaVantageAPI/

# Data & NB Exclusions
*.csv
jnb/*.ipynb
data/datas.csv
data/f500.csv
data/GLD_D_tv.csv
Expand All @@ -142,4 +141,6 @@ data/SPY_D_TV2.csv
data/SPY_D_TV3.csv
data/TV_5min.csv
data/tulip.csv
examples/*.csv
examples/*.csv
jnb/*.ipynb
jnb/*.txt
56 changes: 40 additions & 16 deletions README.md

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions examples/ni.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
from pandas_ta.overlap import sma
from pandas_ta.utils import get_offset, verify_series

# - Standard definition of your custom indicator function (including docs)-

def ni(close, length=None, centered=False, offset=None, **kwargs):
"""
Example indicator ni
"""
# Validate Arguments
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)

ni = close - ma.shift(t)
if centered:
ni = (close.shift(t) - ma).shift(-t)

# Offset
if offset != 0:
ni = ni.shift(offset)

# Handle fills
if "fillna" in kwargs:
ni.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
ni.fillna(method=kwargs["fill_method"], inplace=True)

# Name and Categorize it
ni.name = f"ni_{length}"
ni.category = "trend"

return ni

ni.__doc__ = \
"""Example indicator (NI)
Is an indicator provided solely as an example
Sources:
https://github.com/twopirllc/pandas-ta/issues/264
Calculation:
Default Inputs:
length=20, centered=False
SMA = Simple Moving Average
t = int(0.5 * length) + 1
ni = close.shift(t) - SMA(close, length)
if centered:
ni = ni.shift(-t)
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 20
centered (bool): Shift the ni back by int(0.5 * length) + 1. Default: False
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
pd.Series: New feature generated.
"""

# - Define a matching class method --------------------------------------------

def ni_method(self, length=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = ni(close=close, length=length, offset=offset, **kwargs)
return self._post_process(result, **kwargs)
6 changes: 3 additions & 3 deletions pandas_ta/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
# Overlap
"overlap": [
"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"
"jma", "kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4",
"pwma", "rma", "sinwma", "sma", "ssf", "supertrend", "swma", "t3",
"tema", "trima", "vidya", "vwap", "vwma", "wcp", "wma", "zlma"
],
# Performance
"performance": ["log_return", "percent_return"],
Expand Down
68 changes: 38 additions & 30 deletions pandas_ta/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pathlib import Path
from time import perf_counter
from typing import List, Tuple
from warnings import simplefilter

import pandas as pd
from numpy import log10 as npLog10
Expand Down Expand Up @@ -250,15 +251,15 @@ class AnalysisIndicators(BasePandasObject):
_time_range = "years"
_last_run = get_time(_exchange, to_string=True)

# def __init__(self, pandas_obj):
# # self._validate(pandas_obj)
# self._df = pandas_obj
# self._last_run = get_time(self._exchange, to_string=True)
def __init__(self, pandas_obj):
self._validate(pandas_obj)
self._df = pandas_obj
self._last_run = get_time(self._exchange, to_string=True)

# @staticmethod
# def _validate(df: Tuple[pd.DataFrame, pd.Series]):
# if isinstance(df, pd.Series) or isinstance(df, pd.DataFrame):
# raise AttributeError("[X] Must be either a Pandas Series or DataFrame.")
@staticmethod
def _validate(obj: Tuple[pd.DataFrame, pd.Series]):
if not isinstance(obj, pd.DataFrame) and not isinstance(obj, pd.Series):
raise AttributeError("[X] Must be either a Pandas Series or DataFrame.")

# DataFrame Behavioral Methods
def __call__(
Expand Down Expand Up @@ -400,8 +401,9 @@ def _append(self, result=None, **kwargs) -> None:
df = self._df
if df is None or result is None: return
else:
simplefilter(action="ignore", category=pd.errors.PerformanceWarning)
if "col_names" in kwargs and not isinstance(kwargs["col_names"], tuple):
kwargs["col_names"] = (kwargs["col_names"],)
kwargs["col_names"] = (kwargs["col_names"],) # Note: tuple(kwargs["col_names"]) doesn't work

if isinstance(result, pd.DataFrame):
# If specified in kwargs, rename the columns.
Expand Down Expand Up @@ -761,10 +763,10 @@ def strategy(self, *args, **kwargs):
else:
# Without multiprocessing:
if verbose:
_col_msg = f"[i] No mulitproccessing (cores = 0)."
if has_col_names:
print(f"[i] No mulitproccessing support for 'col_names' option.")
else:
print(f"[i] No mulitproccessing (cores = 0).")
_col_msg = f"[i] No mulitproccessing support for 'col_names' option."
print(_col_msg)

if mode["custom"]:
if Imports["tqdm"] and verbose:
Expand All @@ -784,6 +786,7 @@ def strategy(self, *args, **kwargs):
else:
for ind in ta:
getattr(self, ind)(*tuple(), **kwargs)
self._last_run = get_time(self.exchange, to_string=True)

# Apply prefixes/suffixes and appends indicator results to the DataFrame
[self._post_process(r, **kwargs) for r in results]
Expand Down Expand Up @@ -900,9 +903,9 @@ def ao(self, fast=None, slow=None, offset=None, **kwargs):
result = ao(high=high, low=low, fast=fast, slow=slow, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def apo(self, fast=None, slow=None, offset=None, **kwargs):
def apo(self, fast=None, slow=None, mamode=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = apo(close=close, fast=fast, slow=slow, offset=offset, **kwargs)
result = apo(close=close, fast=fast, slow=slow, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def bias(self, length=None, mamode=None, offset=None, **kwargs):
Expand Down Expand Up @@ -958,10 +961,10 @@ def cti(self, length=None, offset=None, **kwargs):
result = cti(close=close, length=length, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def dm(self, drift=None, offset=None, **kwargs):
def dm(self, drift=None, offset=None, mamode=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
result = dm(high=high, low=low, drift=drift, offset=offset, **kwargs)
result = dm(high=high, low=low, drift=drift, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def er(self, length=None, drift=None, offset=None, **kwargs):
Expand Down Expand Up @@ -1078,37 +1081,37 @@ def smi(self, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwa
result = smi(close=close, fast=fast, slow=slow, signal=signal, scalar=scalar, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def squeeze(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs):
def squeeze(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar=None, mom_length=None, mom_smooth=None, use_tr=None, mamode=None, offset=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
close = self._get_column(kwargs.pop("close", "close"))
result = squeeze(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar=kc_scalar, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, offset=offset, **kwargs)
result = squeeze(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar=kc_scalar, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def squeeze_pro(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar_wide=None, kc_scalar_normal=None, kc_scalar_narrow=None, mom_length=None, mom_smooth=None, use_tr=None, offset=None, **kwargs):
def squeeze_pro(self, bb_length=None, bb_std=None, kc_length=None, kc_scalar_wide=None, kc_scalar_normal=None, kc_scalar_narrow=None, mom_length=None, mom_smooth=None, use_tr=None, mamode=None, offset=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
close = self._get_column(kwargs.pop("close", "close"))
result = squeeze_pro(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar_wide=kc_scalar_wide, kc_scalar_normal=kc_scalar_normal, kc_scalar_narrow=kc_scalar_narrow, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, offset=offset, **kwargs)
result = squeeze_pro(high=high, low=low, close=close, bb_length=bb_length, bb_std=bb_std, kc_length=kc_length, kc_scalar_wide=kc_scalar_wide, kc_scalar_normal=kc_scalar_normal, kc_scalar_narrow=kc_scalar_narrow, mom_length=mom_length, mom_smooth=mom_smooth, use_tr=use_tr, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def stc(self, ma1=None, ma2=None, osc=None, tclength=None, fast=None, slow=None, factor=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = stc(close=close, ma1=ma1, ma2=ma2, osc=osc, tclength=tclength, fast=fast, slow=slow, factor=factor, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def stoch(self, fast_k=None, slow_k=None, slow_d=None, offset=None, **kwargs):
def stoch(self, fast_k=None, slow_k=None, slow_d=None, mamode=None, offset=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
close = self._get_column(kwargs.pop("close", "close"))
result = stoch(high=high, low=low, close=close, fast_k=fast_k, slow_k=slow_k, slow_d=slow_d, offset=offset, **kwargs)
result = stoch(high=high, low=low, close=close, fast_k=fast_k, slow_k=slow_k, slow_d=slow_d, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def stochrsi(self, length=None, rsi_length=None, k=None, d=None, offset=None, **kwargs):
def stochrsi(self, length=None, rsi_length=None, k=None, d=None, mamode=None, offset=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
close = self._get_column(kwargs.pop("close", "close"))
result = stochrsi(high=high, low=low, close=close, length=length, rsi_length=rsi_length, k=k, d=d, offset=offset, **kwargs)
result = stochrsi(high=high, low=low, close=close, length=length, rsi_length=rsi_length, k=k, d=d, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def td_seq(self, asint=None, offset=None, show_all=None, **kwargs):
Expand All @@ -1121,9 +1124,9 @@ def trix(self, length=None, signal=None, scalar=None, drift=None, offset=None, *
result = trix(close=close, length=length, signal=signal, scalar=scalar, drift=drift, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def tsi(self, fast=None, slow=None, drift=None, offset=None, **kwargs):
def tsi(self, fast=None, slow=None, drift=None, mamode=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = tsi(close=close, fast=fast, slow=slow, drift=drift, offset=offset, **kwargs)
result = tsi(close=close, fast=fast, slow=slow, drift=drift, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def uo(self, fast=None, medium=None, slow=None, fast_w=None, medium_w=None, slow_w=None, drift=None, offset=None, **kwargs):
Expand Down Expand Up @@ -1191,16 +1194,21 @@ def hwma(self, na=None, nb=None, nc=None, offset=None, **kwargs):
result = hwma(close=close, na=na, nb=nb, nc=nc, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def jma(self, length=None, phase=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = jma(close=close, length=length, phase=phase, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def kama(self, length=None, fast=None, slow=None, offset=None, **kwargs):
close = self._get_column(kwargs.pop("close", "close"))
result = kama(close=close, length=length, fast=fast, slow=slow, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def ichimoku(self, tenkan=None, kijun=None, senkou=None, offset=None, **kwargs):
def ichimoku(self, tenkan=None, kijun=None, senkou=None, include_chikou=True, offset=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
close = self._get_column(kwargs.pop("close", "close"))
result, span = ichimoku(high=high, low=low, close=close, tenkan=tenkan, kijun=kijun, senkou=senkou, offset=offset, **kwargs)
result, span = ichimoku(high=high, low=low, close=close, tenkan=tenkan, kijun=kijun, senkou=senkou, include_chikou=include_chikou, offset=offset, **kwargs)
self._add_prefix_suffix(result, **kwargs)
self._add_prefix_suffix(span, **kwargs)
self._append(result, **kwargs)
Expand Down Expand Up @@ -1416,11 +1424,11 @@ def chop(self, length=None, atr_length=None, scalar=None, drift=None, offset=Non
result = chop(high=high, low=low, close=close, length=length, atr_length=atr_length, scalar=scalar, drift=drift, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def cksp(self, p=None, x=None, q=None, offset=None, **kwargs):
def cksp(self, p=None, x=None, q=None, mamode=None, offset=None, **kwargs):
high = self._get_column(kwargs.pop("high", "high"))
low = self._get_column(kwargs.pop("low", "low"))
close = self._get_column(kwargs.pop("close", "close"))
result = cksp(high=high, low=low, close=close, p=p, x=x, q=q, offset=offset, **kwargs)
result = cksp(high=high, low=low, close=close, p=p, x=x, q=q, mamode=mamode, offset=offset, **kwargs)
return self._post_process(result, **kwargs)

def decay(self, length=None, mode=None, offset=None, **kwargs):
Expand Down
Loading

0 comments on commit bc3b292

Please sign in to comment.