mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-08-01 12:40:12 +08:00
1511 lines
58 KiB
Python
1511 lines
58 KiB
Python
# -*- coding: utf-8 -*-
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from functools import wraps
|
|
from multiprocessing import cpu_count, Pool
|
|
from random import random
|
|
from time import perf_counter
|
|
from typing import List
|
|
|
|
import pandas as pd
|
|
from pandas_ta import categories
|
|
from pandas.core.base import PandasObject
|
|
|
|
from pandas_ta.candles import *
|
|
from pandas_ta.momentum import *
|
|
from pandas_ta.overlap import *
|
|
from pandas_ta.performance import *
|
|
from pandas_ta.statistics import *
|
|
from pandas_ta.trend import *
|
|
from pandas_ta.volatility import *
|
|
from pandas_ta.volume import *
|
|
from pandas_ta.utils import *
|
|
|
|
version = ".".join(("0", "1", "81b"))
|
|
|
|
# Dictionary of files for each category, used in df.ta.strategy()
|
|
Category = {name: category_files(name) for name in categories}
|
|
|
|
def mp_worker(args):
|
|
df, method, kwargs = args
|
|
|
|
if method != 'ichimoku':
|
|
return df.ta(kind=method, **kwargs)
|
|
else:
|
|
return df.ta(kind=method, **kwargs)[0]
|
|
|
|
|
|
def finalize(method):
|
|
@wraps(method)
|
|
def _wrapper(*class_methods, **method_kwargs):
|
|
cm = class_methods[0]
|
|
result = method(cm, **method_kwargs)
|
|
|
|
cm._add_prefix_suffix(result, **method_kwargs)
|
|
cm._append(result, **method_kwargs)
|
|
return result
|
|
return _wrapper
|
|
|
|
|
|
@dataclass
|
|
class Strategy:
|
|
"""Strategy (Data)Class
|
|
A way to name and group your favorite indicators
|
|
|
|
Args:
|
|
name (str): Some short memorable string. Note: Case-insensitive "All" is reserved.
|
|
ta (list of dicts): A list of dicts containing keyword arguments where "kind" is the indicator.
|
|
description (str): A more detailed description of what the Strategy tries to capture. Default: None
|
|
created (str): At datetime string of when it was created. Default: Automatically generated. *Subject to change*
|
|
|
|
Example TA:
|
|
ta = [
|
|
{"kind": "sma", "length": 200},
|
|
{"kind": "sma", "close": "volume", "length": 50},
|
|
{"kind": "bbands", "length": 20},
|
|
{"kind": "rsi"},
|
|
{"kind": "macd", "fast": 8, "slow": 21},
|
|
{"kind": "sma", "close": "volume", "length": 20, "prefix": "VOLUME"},
|
|
]
|
|
"""
|
|
name: str# = None # Required.
|
|
ta: List = field(default_factory=list) # Required.
|
|
description: str = None # Helpful. More descriptive version or notes or w/e.
|
|
created: str = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Optional. May change type later to datetime
|
|
last_run: str = None # Auto filled
|
|
run_time: str = None # Auto filled
|
|
|
|
def __post_init__(self):
|
|
has_name = True
|
|
is_ta = False
|
|
required_args = ["[X] Strategy requires the following argument(s):"]
|
|
|
|
name_is_str = isinstance(self.name, str)
|
|
ta_is_list = isinstance(self.ta, list)
|
|
|
|
if self.name is None or not name_is_str:
|
|
required_args.append(" - name. Must be a string. Example: \"My TA\". Note: \"all\" is reserved.")
|
|
has_name != has_name
|
|
|
|
if self.ta is None:
|
|
self.ta = None
|
|
elif self.ta is not None and ta_is_list and self.total_ta() > 0:
|
|
# Check that all elements of the list are dicts.
|
|
# Does not check if the dicts values are valid indicator kwargs
|
|
# User must check indicator documentation for all indicators args.
|
|
is_ta = all([isinstance(_, dict) and len(_.keys()) > 0 for _ in self.ta])
|
|
else:
|
|
s = " - ta. Format is a list of dicts. Example: [{'kind': 'sma', 'length': 10}]"
|
|
s += "\n Check the indicator for the correct arguments if you receive this error."
|
|
required_args.append(s)
|
|
|
|
if len(required_args) > 1:
|
|
[print(_) for _ in required_args]
|
|
return None
|
|
|
|
def total_ta(self):
|
|
return len(self.ta) if self.ta is not None else 0
|
|
|
|
# All Default Strategy
|
|
AllStrategy = Strategy(
|
|
name="All",
|
|
description="All the indicators with their default settings. Pandas TA default.",
|
|
ta=None
|
|
)
|
|
|
|
# Default (Example) Strategy.
|
|
CommonStrategy = Strategy(
|
|
name="Common Price and Volume SMAs",
|
|
description="Common Price SMAs: 10, 20, 50, 200 and Volume SMA: 20.",
|
|
ta=[
|
|
{"kind": "sma", "length": 10},
|
|
{"kind": "sma", "length": 20},
|
|
{"kind": "sma", "length": 50},
|
|
{"kind": "sma", "length": 200},
|
|
{"kind": "sma", "close": "volume", "length": 20, "prefix": "VOL"}
|
|
]
|
|
)
|
|
|
|
|
|
class BasePandasObject(PandasObject):
|
|
"""Simple PandasObject Extension
|
|
|
|
Ensures the DataFrame is not empty and has columns.
|
|
It would be a sad Panda otherwise.
|
|
|
|
Args:
|
|
df (pd.DataFrame): Extends Pandas DataFrame
|
|
"""
|
|
def __init__(self, df, **kwargs):
|
|
if df.empty: return
|
|
|
|
if len(df.columns) > 0:
|
|
self._df = df
|
|
else:
|
|
raise AttributeError(f" [X] No columns!")
|
|
|
|
def __call__(self, kind, *args, **kwargs):
|
|
raise NotImplementedError()
|
|
|
|
|
|
@pd.api.extensions.register_dataframe_accessor('ta')
|
|
class AnalysisIndicators(BasePandasObject):
|
|
"""AnalysisIndicators is a class that extends the Pandas DataFrame via
|
|
Pandas @pd.api.extensions.register_dataframe_accessor('name') decorator.
|
|
|
|
This Pandas Extension is named 'ta' for Technical Analysis that allows us
|
|
to apply technical indicators by extension. Even though 'ta' is a
|
|
Pandas DataFrame Extension, you can still call the Indicators
|
|
individually. Use help() if needed.
|
|
|
|
By default the 'ta' extension uses lower case column names: open, high,
|
|
low, close, and volume. You can override the defaults by providing the
|
|
it's replacement name when calling the indicator. For example, to call the
|
|
indicator hl2().
|
|
|
|
With 'default' columns: open, high, low, close, and volume.
|
|
>>> df.ta.hl2()
|
|
>>> df.ta(kind='hl2')
|
|
|
|
With DataFrame columns: Open, High, Low, Close, and Volume.
|
|
>>> df.ta.hl2(high='High', low='Low')
|
|
>>> df.ta(kind='hl2', high='High', low='Low')
|
|
|
|
If you do not want to use a DataFrame Extension, just call it normally.
|
|
>>> sma10 = ta.sma(df['Close']) # Default length=10
|
|
>>> sma50 = ta.sma(df['Close'], length=50)
|
|
>>> ichimoku, span = ta.ichimoku(df['High'], df['Low'], df['Close'])
|
|
|
|
Args:
|
|
kind (str, optional): Default: None. Kind is the 'name' of the indicator.
|
|
It converts kind to lowercase before calling.
|
|
timed (bool, optional): Default: False. Curious about the execution
|
|
speed?
|
|
kwargs: Extension specific modifiers.
|
|
append (bool, optional): Default: False. When True, it appends the
|
|
resultant column(s) to the DataFrame.
|
|
|
|
Returns:
|
|
Most Indicators will return a Pandas Series. Others like MACD, BBANDS,
|
|
KC, et al will return a Pandas DataFrame. Ichimoku on the other hand
|
|
will return two DataFrames, the Ichimoku DataFrame for the known period
|
|
and a Span DataFrame for the future of the Span values.
|
|
|
|
Let's get started!
|
|
|
|
1. Loading the 'ta' module:
|
|
>>> import pandas as pd
|
|
>>> import ta as ta
|
|
|
|
2. Load some data:
|
|
>>> df = pd.read_csv('AAPL.csv', index_col='date', parse_dates=True)
|
|
|
|
3. Help!
|
|
3a. General Help:
|
|
>>> help(df.ta)
|
|
>>> df.ta()
|
|
3b. Indicator Help:
|
|
>>> help(ta.apo)
|
|
3c. Indicator Extension Help:
|
|
>>> help(df.ta.apo)
|
|
|
|
4. Ways of calling an indicator.
|
|
4a. Calling just the MACD indicator without 'ta' DataFrame extension.
|
|
>>> ta.apo(df['close'])
|
|
4b. Calling just the MACD indicator with 'ta' DataFrame extension.
|
|
>>> df.ta.apo()
|
|
4c. Calling using kind.
|
|
>>> df.ta(kind='apo')
|
|
|
|
5. Working with kwargs
|
|
5a. Append the result to the working df.
|
|
>>> df.ta.apo(append=True)
|
|
5b. Timing an indicator.
|
|
>>> apo = df.ta(kind='apo', timed=True)
|
|
>>> print(apo.timed)
|
|
"""
|
|
_adjusted = None
|
|
_mp = False
|
|
|
|
def __call__(
|
|
self,
|
|
kind: str= None,
|
|
alias: str = None,
|
|
timed = False,
|
|
verbose = False,
|
|
**kwargs
|
|
):
|
|
try:
|
|
if isinstance(kind, str):
|
|
kind = kind.lower()
|
|
fn = getattr(self, kind)
|
|
|
|
if timed: stime = perf_counter()
|
|
|
|
# Run the indicator
|
|
result = fn(**kwargs) # = getattr(self, kind)(**kwargs)
|
|
|
|
if timed:
|
|
result.timed = final_time(stime)
|
|
alias_str = alias + ':' if alias is not None else ''
|
|
print(f"[+] {kind}:{alias_str} {result.timed}")
|
|
|
|
# Add an alias if passed
|
|
if alias: result.alias = f"{alias}"
|
|
|
|
return result
|
|
else:
|
|
self.help()
|
|
|
|
except: pass
|
|
|
|
@property
|
|
def adjusted(self) -> str:
|
|
"""property: df.ta.adjusted"""
|
|
return self._adjusted
|
|
|
|
@adjusted.setter
|
|
def adjusted(self, value:str) -> None:
|
|
"""property: df.ta.adjusted = 'adj_close'"""
|
|
if value is not None and isinstance(value, str):
|
|
self._adjusted = value
|
|
else:
|
|
self._adjusted = None
|
|
|
|
@property
|
|
def datetime_ordered(self) -> bool:
|
|
"""Returns True if the index is a datetime and ordered."""
|
|
return is_datetime_ordered(self._df)
|
|
|
|
@property
|
|
def mp(self) -> bool:
|
|
"""property: df.ta.mp"""
|
|
return self._mp
|
|
|
|
@mp.setter
|
|
def mp(self, value: bool) -> None:
|
|
"""property: df.ta.mp = False (Default)"""
|
|
if value is not None and isinstance(value, bool):
|
|
self._mp = value
|
|
else:
|
|
self._mp = False
|
|
|
|
@property
|
|
def reverse(self) -> pd.DataFrame:
|
|
"""Reverses the DataFrame. Simply: df.iloc[::-1]"""
|
|
return self._df.iloc[::-1]
|
|
|
|
@property
|
|
def version(self) -> str:
|
|
"""Returns the version."""
|
|
return version
|
|
|
|
def _append(self, result=None, **kwargs):
|
|
"""Appends a Pandas Series or DataFrame columns to self._df."""
|
|
if 'append' in kwargs and kwargs['append']:
|
|
df = self._df
|
|
if df is None or result is None: return
|
|
else:
|
|
if isinstance(result, pd.DataFrame):
|
|
for i, column in enumerate(result.columns):
|
|
df[column] = result.iloc[:,i]
|
|
else:
|
|
df[result.name] = result
|
|
|
|
|
|
def _add_prefix_suffix(self, result=None, **kwargs):
|
|
"""Add prefix and/or suffix to the result columns"""
|
|
if result is None: return
|
|
else:
|
|
prefix = suffix = ""
|
|
delimiter = kwargs.setdefault("delimiter", "_")
|
|
|
|
if "prefix" in kwargs: prefix = f"{kwargs['prefix']}{delimiter}"
|
|
if "suffix" in kwargs: suffix = f"{delimiter}{kwargs['suffix']}"
|
|
|
|
if isinstance(result, pd.Series):
|
|
result.name = prefix + result.name + suffix
|
|
else:
|
|
result.columns = [prefix + column + suffix for column in result.columns]
|
|
|
|
|
|
def _get_column(self, series, default):
|
|
"""Attempts to get the correct series or 'column' and return it."""
|
|
df = self._df
|
|
if df is None: return
|
|
|
|
# Explicitly passing a pd.Series to override default.
|
|
if isinstance(series, pd.Series):
|
|
return series
|
|
# Apply default if no series nor a default.
|
|
elif series is None or default is None:
|
|
return df[self.adjusted] if self.adjusted is not None else df[default]
|
|
# Ok. So it's a str.
|
|
elif isinstance(series, str):
|
|
# Return the df column since it's in there.
|
|
if series in df.columns:
|
|
return df[series]
|
|
else:
|
|
# Attempt to match the 'series' because it was likely misspelled.
|
|
matches = df.columns.str.match(series, case=False)
|
|
match = [i for i, x in enumerate(matches) if x]
|
|
# If found, awesome. Return it or return the 'series'.
|
|
cols = ', '.join(list(df.columns))
|
|
NOT_FOUND = f"[X] Ooops!!!: It's {series not in df.columns}, the series '{series}' was not found in {cols}"
|
|
return df.iloc[:,match[0]] if len(match) else print(NOT_FOUND)
|
|
|
|
|
|
def constants(self, append, lower_bound=-100, upper_bound=100, every=10):
|
|
"""Constants
|
|
|
|
Useful for creating indicator levels or if you need some constant value
|
|
easily added to your DataFrame.
|
|
|
|
Add constant '1' to the DataFrame
|
|
>>> df.ta.constants(True, 1, 1, 1)
|
|
Remove constant '1' to the DataFrame
|
|
>>> df.ta.constants(False, 1, 1, 1)
|
|
|
|
Adding constants that range of constants from -4 to 4 inclusive
|
|
>>> df.ta.constants(True, -4, 4, 1)
|
|
Removing constants that range of constants from -4 to 4 inclusive
|
|
>>> df.ta.constants(False, -4, 4, 1)
|
|
|
|
Args:
|
|
append (bool): Default: None. If True, appends the range of constants to the
|
|
working DataFrame. If False, it removes the constant range from the working
|
|
DataFrame.
|
|
lower_bound (int): Default: -100. Lowest integer for the constant range.
|
|
upper_bound (int): Default: 100. Largest integer for the constant range.
|
|
every (int): Default: 10. How often to include a new constant.
|
|
|
|
Returns:
|
|
Returns nothing to the user. Either adds or removes constant ranges from the
|
|
working DataFrame.
|
|
"""
|
|
levels = [x for x in range(lower_bound, upper_bound + 1) if x % every == 0]
|
|
if append:
|
|
for x in levels:
|
|
self._df[f'{x}'] = x
|
|
else:
|
|
for x in levels:
|
|
del self._df[f'{x}']
|
|
|
|
|
|
def indicators(self, **kwargs):
|
|
"""List of Indicators
|
|
|
|
Args:
|
|
kwargs:
|
|
as_list (bool, optional): Default: False. When True, it returns a list
|
|
of the indicators. Helpful you want to filter out what you want to run.
|
|
exclude (list, optional): Default: None. The passed in list will be
|
|
excluded from the indicators list.
|
|
|
|
Returns:
|
|
Prints the list of indicators. If as_list=True, then a list.
|
|
"""
|
|
as_list = kwargs.setdefault("as_list", False)
|
|
helper_methods = ["constants", "indicators", "strategy"] # Public non-indicator methods
|
|
ta_properties = ["adjusted", "datetime_ordered", "mp", "reverse", "version"]
|
|
exclude_methods = kwargs.setdefault("exclude", None)
|
|
ta_indicators = list((x for x in dir(pd.DataFrame().ta) if not x.startswith('_') and not x.endswith('_')))
|
|
|
|
# Remove pandas.ta methods and properties
|
|
[ta_indicators.remove(x) for x in helper_methods]
|
|
[ta_indicators.remove(x) for x in ta_properties]
|
|
|
|
# Remove user excluded indicators
|
|
if isinstance(exclude_methods, list) and len(exclude_methods) > 0:
|
|
[ta_indicators.remove(x) for x in exclude_methods]
|
|
total_indicators = len(ta_indicators)
|
|
|
|
if as_list: return ta_indicators
|
|
|
|
header = f"pandas.ta - Technical Analysis Indicators - v{self.version}"
|
|
s = f"{header}\nTotal Indicators: {total_indicators}\n"
|
|
print(f"{s}Abbreviations:\n {', '.join(ta_indicators)}") if total_indicators > 0 else print(s)
|
|
|
|
def strategy(self, *args, **kwargs):
|
|
"""Strategy Method
|
|
|
|
An experimental method that by default runs all applicable indicators.
|
|
Future implementations will allow more specific indicator generation through
|
|
a json config file.
|
|
|
|
Args:
|
|
name (str, optional): Default: 'all'
|
|
exclude (list, optional): Default: []. List of indicator names to exclude.
|
|
|
|
kwargs:
|
|
(optional) Default: {}. Any indicator argument you want to modify.
|
|
For example, length=20 or offset=-1 or high=df['High'] ...
|
|
"""
|
|
cpus = cpu_count()
|
|
kwargs["append"] = True # Ensure indicators are appended to the DataFrame
|
|
|
|
name = kwargs.pop("name", None)
|
|
# removing before sending the rest of kwargs to the indicators
|
|
ta = kwargs.pop("ta", None)
|
|
mp = kwargs.pop("mp", False)
|
|
cores = int(kwargs.pop("cores", cpus))
|
|
timed = kwargs.pop("timed", False)
|
|
verbose = kwargs.pop("verbose", False)
|
|
user_excluded = kwargs.pop("exclude", [])
|
|
|
|
# Filter if Strategy, Category or by Strategy name and TA
|
|
if len(args) and isinstance(args[0], Strategy):
|
|
name, ta = args[0].name, args[0].ta
|
|
elif name is None or name.lower() == "all":
|
|
name = "All"
|
|
elif ta is None and name.lower() in categories:
|
|
ta = Category[name.lower()]
|
|
|
|
is_all = True if name is None or name.lower() == "all" else False
|
|
has_ta = True if ta is not None else False
|
|
initial_column_count = len(self._df.columns)
|
|
|
|
excluded = []
|
|
excluded_functions = ["above", "above_value", "below", "below_value", "cross", "cross_value", "long_run", "short_run", "trend_return", "vp"]
|
|
excluded += user_excluded # Exclude user excluded ta if listed
|
|
|
|
print(f"\n[+] Strategy: {name}") if verbose else None
|
|
if name.lower() in categories or is_all:
|
|
# Exclude special functions
|
|
excluded += excluded_functions
|
|
if is_all:
|
|
ta = self.indicators(as_list=True, exclude=excluded)
|
|
else:
|
|
ta = Category[name.lower()]
|
|
else:
|
|
for kwds in ta:
|
|
kwds["append"] = True
|
|
|
|
if verbose:
|
|
print(f'[i] Indicators with the following arguments: {kwargs}')
|
|
if is_all and len(excluded) > 0:
|
|
print(f"[i] Excluded[{len(excluded)}]: {', '.join(excluded)}")
|
|
|
|
# Enable multiprocessing if user sets: mp=True
|
|
if mp: self.mp = not self.mp
|
|
|
|
if self.mp:
|
|
print(f"[i] Multiprocessing: {cores} of {cpu_count()} cores")
|
|
pool = Pool(cores)
|
|
|
|
if timed: stime = perf_counter()
|
|
result = pool.imap_unordered(
|
|
mp_worker, ((self._df, ind, kwargs) for ind in ta), cores
|
|
)
|
|
pool.close()
|
|
pool.join()
|
|
|
|
# Apply prefixes/suffixes and appends indicator result to the DataFrame
|
|
for r in result:
|
|
self._add_prefix_suffix(r, **kwargs)
|
|
self._append(r, **kwargs)
|
|
if timed: ftime = final_time(stime)
|
|
|
|
else:
|
|
# Display multiprocessing tip 10% of the time.
|
|
if random() < 0.1:
|
|
print(f"[i] Set 'df.ta.mp = True' to enable multiprocessing. This computer has {cpus} cores. Default: False")
|
|
|
|
if timed: stime = perf_counter()
|
|
if name.lower() in categories or is_all:
|
|
indicators = [getattr(self, kind) for kind in ta]
|
|
[f(**kwargs) for f in indicators]
|
|
else:
|
|
[getattr(self, kwds["kind"])(**kwds) for kwds in ta]
|
|
|
|
if timed: ftime = final_time(stime)
|
|
|
|
if verbose:
|
|
print(f"[i] Total indicators: {len(ta)}")
|
|
print(f"[i] Columns added: {len(self._df.columns) - initial_column_count}")
|
|
print(f"[i] Runtime: {ftime}") if timed else None
|
|
|
|
|
|
# Candles
|
|
@finalize
|
|
def cdl_doji(self, open_=None, high=None, low=None, close=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = cdl_doji(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def ha(self, open_=None, high=None, low=None, close=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = ha(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs)
|
|
return result
|
|
|
|
# Momentum Indicators
|
|
@finalize
|
|
def ao(self, high=None, low=None, fast=None, slow=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
result = ao(high=high, low=low, fast=fast, slow=slow, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def apo(self, close=None, fast=None, slow=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = apo(close=close, fast=fast, slow=slow, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def bias(self, close=None, length=None, mamode=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = bias(close=close, length=length, mamode=mamode, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def bop(self, open_=None, high=None, low=None, close=None, percentage=False, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = bop(open_=open_, high=high, low=low, close=close, percentage=percentage, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def brar(self, open_=None, high=None, low=None, close=None, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = brar(open_=open_, high=high, low=low, close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def cci(self, high=None, low=None, close=None, length=None, c=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = cci(high=high, low=low, close=close, length=length, c=c, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def cg(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = cg(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def cmo(self, close=None, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = cmo(close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def coppock(self, close=None, length=None, fast=None, slow=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = coppock(close=close, length=length, fast=fast, slow=slow, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def er(self, close=None, length=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = er(close=close, length=length, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def eri(self, high=None, low=None, close=None, length=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = eri(high=high, low=low, close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def fisher(self, high=None, low=None, length=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = fisher(high=high, low=low, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def inertia(self, close=None, high=None, low=None, length=None, rvi_length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
if refined is not None or thirds is not None:
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = inertia(close=close, high=high, low=low, length=length, rvi_length=rvi_length, scalar=scalar, refined=refined, thirds=thirds, mamode=mamode, drift=drift, offset=offset, **kwargs)
|
|
else:
|
|
result = inertia(close=close, length=length, rvi_length=rvi_length, scalar=scalar, refined=refined, thirds=thirds, mamode=mamode, drift=drift, offset=offset, **kwargs)
|
|
|
|
return result
|
|
|
|
@finalize
|
|
def kdj(self, high=None, low=None, close=None, length=None, signal=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = kdj(high=high, low=low, close=close, length=length, signal=signal, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def kst(self, close=None, roc1=None, roc2=None, roc3=None, roc4=None, sma1=None, sma2=None, sma3=None, sma4=None, signal=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = kst(close=close, roc1=roc1, roc2=roc2, roc3=roc3, roc4=roc4, sma1=sma1, sma2=sma2, sma3=sma3, sma4=sma4, signal=signal, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def macd(self, close=None, fast=None, slow=None, signal=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = macd(close=close, fast=fast, slow=slow, signal=signal, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def mom(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = mom(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pgo(self, high=None, low=None, close=None, length=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = pgo(high=high, low=low, close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def ppo(self, close=None, fast=None, slow=None, scalar=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = ppo(close=close, fast=fast, slow=slow, scalar=scalar, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def psl(self, close=None, open_=None, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
|
if open_ is not None:
|
|
open_ = self._get_column(open_, 'open')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = psl(close=close, open_=open_, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pvo(self, volume=None, fast=None, slow=None, signal=None, scalar=None, offset=None, **kwargs):
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = pvo(volume=volume, fast=fast, slow=slow, signal=signal, scalar=scalar, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def roc(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = roc(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def rsi(self, close=None, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = rsi(close=close, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def rvgi(self, open_=None, high=None, low=None, close=None, length=None, swma_length=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = rvgi(open_=open_, high=high, low=low, close=close, length=length, swma_length=swma_length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def slope(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = slope(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def stoch(self, high=None, low=None, close=None, fast_k=None, slow_k=None, slow_d=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(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)
|
|
return result
|
|
|
|
@finalize
|
|
def trix(self, close=None, length=None, signal=None, scalar=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = trix(close=close, length=length, signal=signal, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def tsi(self, close=None, fast=None, slow=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = tsi(close=close, fast=fast, slow=slow, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def uo(self, high=None, low=None, close=None, fast=None, medium=None, slow=None, fast_w=None, medium_w=None, slow_w=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = uo(high=high, low=low, close=close, fast=fast, medium=medium, slow=slow, fast_w=fast_w, medium_w=medium_w, slow_w=slow_w, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def willr(self, high=None, low=None, close=None, length=None, percentage=True, offset=None,**kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = willr(high=high, low=low, close=close, length=length, percentage=percentage, offset=offset, **kwargs)
|
|
return result
|
|
|
|
|
|
# Overlap Indicators
|
|
@finalize
|
|
def dema(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = dema(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def ema(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = ema(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def fwma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = fwma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def hl2(self, high=None, low=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = hl2(high=high, low=low, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def hlc3(self, high=None, low=None, close=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = hlc3(high=high, low=low, close=close, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def hma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = hma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def kama(self, close=None, length=None, fast=None, slow=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = kama(close=close, length=length, fast=fast, slow=slow, offset=offset, **kwargs)
|
|
return result
|
|
|
|
# @finalize
|
|
def ichimoku(self, high=None, low=None, close=None, tenkan=None, kijun=None, senkou=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result, span = ichimoku(high=high, low=low, close=close, tenkan=tenkan, kijun=kijun, senkou=senkou, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._add_prefix_suffix(span, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result, span
|
|
|
|
@finalize
|
|
def linreg(self, close=None, length=None, offset=None, adjust=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = linreg(close=close, length=length, offset=offset, adjust=adjust, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def midpoint(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = midpoint(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def midprice(self, high=None, low=None, length=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = midprice(high=high, low=low, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def ohlc4(self, open_=None, high=None, low=None, close=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = ohlc4(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pwma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = pwma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def rma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = rma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def sinwma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = sinwma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def sma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = sma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def supertrend(self, high=None, low=None, close=None, length=None, multiplier=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = supertrend(high=high, low=low, close=close, length=length, multiplier=multiplier, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def swma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = swma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def t3(self, close=None, length=None, a=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = t3(close=close, length=length, a=a, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def tema(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = tema(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def trima(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = trima(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def vwap(self, high=None, low=None, close=None, volume=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
# Ensure volume has a datetime ordered index
|
|
if not self.datetime_ordered:
|
|
volume.index = self._df.index
|
|
|
|
result = vwap(high=high, low=low, close=close, volume=volume, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def vwma(self, close=None, volume=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = vwma(close=close, volume=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def wcp(self, high=None, low=None, close=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = wcp(high=high, low=low, close=close, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def wma(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = wma(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def zlma(self, close=None, length=None, mamode=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = zlma(close=close, length=length, mamode=mamode, offset=offset, **kwargs)
|
|
return result
|
|
|
|
|
|
# Performance Indicators
|
|
@finalize
|
|
def log_return(self, close=None, length=None, cumulative=False, percent=False, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = log_return(close=close, length=length, cumulative=cumulative, percent=percent, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def percent_return(self, close=None, length=None, cumulative=False, percent=False, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = percent_return(close=close, length=length, cumulative=cumulative, percent=percent, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def trend_return(self, close=None, trend=None, log=True, cumulative=None, offset=None, trend_reset=None, **kwargs):
|
|
if trend is None: return self._df
|
|
else:
|
|
close = self._get_column(close, 'close')
|
|
trend = self._get_column(trend, f"{trend}")
|
|
|
|
result = trend_return(close=close, trend=trend, log=log, cumulative=cumulative, offset=offset, trend_reset=trend_reset, **kwargs)
|
|
return result
|
|
|
|
|
|
# Statistics Indicators
|
|
@finalize
|
|
def entropy(self, close=None, length=None, base=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = entropy(close=close, length=length, base=base, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def kurtosis(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = kurtosis(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def mad(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = mad(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def median(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = median(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def quantile(self, close=None, length=None, q=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = quantile(close=close, length=length, q=q, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def skew(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = skew(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def stdev(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = stdev(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def variance(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = variance(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def zscore(self, close=None, length=None, std=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = zscore(close=close, length=length, std=std, offset=offset, **kwargs)
|
|
return result
|
|
|
|
|
|
|
|
# Trend Indicators
|
|
@finalize
|
|
def adx(self, high=None, low=None, close=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = adx(high=high, low=low, close=close, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def amat(self, close=None, fast=None, slow=None, mamode=None, lookback=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = amat(close=close, fast=fast, slow=slow, mamode=mamode, lookback=lookback, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def aroon(self, high=None, low=None, length=None, scalar=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = aroon(high=high, low=low, length=length, scalar=scalar, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def chop(self, high=None, low=None, close=None, length=None, atr_length=None, scalar=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(close, 'high')
|
|
low = self._get_column(close, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = chop(high=high, low=low, close=close, length=length, atr_length=atr_length, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def cksp(self, high=None, low=None, close=None, p=None, x=None, q=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = cksp(high=high, low=low, close=close, p=p, x=x, q=q, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def decreasing(self, close=None, length=None, asint=True, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = decreasing(close=close, length=length, asint=asint, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def dpo(self, close=None, length=None, centered=True, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = dpo(close=close, length=length, centered=centered, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def increasing(self, close=None, length=None, asint=True, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = increasing(close=close, length=length, asint=asint, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def linear_decay(self, close=None, length=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = linear_decay(close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
# @finalize
|
|
def long_run(self, fast=None, slow=None, length=None, offset=None, **kwargs):
|
|
if fast is None and slow is None: return self._df
|
|
else:
|
|
fast = self._get_column(fast, f"{fast}")
|
|
slow = self._get_column(slow, f"{slow}")
|
|
|
|
result = long_run(fast=fast, slow=slow, length=length, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def psar(self, high=None, low=None, close=None, af=None, max_af=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
if close is not None:
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = psar(high=high, low=low, close=close, af=af, max_af=max_af, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def qstick(self, open_=None, close=None, length=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = qstick(open_=open_, close=close, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
# @finalize
|
|
def short_run(self, fast=None, slow=None, length=None, offset=None, **kwargs):
|
|
if fast is None and slow is None: return self._df
|
|
else:
|
|
fast = self._get_column(fast, f"{fast}")
|
|
slow = self._get_column(slow, f"{slow}")
|
|
|
|
result = short_run(fast=fast, slow=slow, length=length, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def supertrend(self, high=None, low=None, close=None, period=None, multiplier=None, mamode=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = supertrend(high=high, low=low, close=close, period=period, multiplier=multiplier, mamode=mamode, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def vortex(self, high=None, low=None, close=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = vortex(high=high, low=low, close=close, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
|
|
|
|
# Utility Indicators
|
|
def above(self, a=None, b=None, asint=True, offset=None, **kwargs):
|
|
if a is None and b is None: return self._df
|
|
else:
|
|
a = self._get_column(a, f"{a}")
|
|
b = self._get_column(b, f"{b}")
|
|
result = above(series_a=a, series_b=b, asint=asint, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
def above_value(self, a=None, value=None, asint=True, offset=None, **kwargs):
|
|
if a is None and value is None: return self._df
|
|
else:
|
|
a = self._get_column(a, f"{a}")
|
|
result = above_value(series_a=a, value=value, asint=asint, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
def below(self, a=None, b=None, asint=True, offset=None, **kwargs):
|
|
if a is None and b is None: return self._df
|
|
else:
|
|
a = self._get_column(a, f"{a}")
|
|
b = self._get_column(b, f"{b}")
|
|
result = below(series_a=a, series_b=b, asint=asint, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
def below_value(self, a=None, value=None, asint=True, offset=None, **kwargs):
|
|
if a is None and value is None: return self._df
|
|
else:
|
|
a = self._get_column(a, f"{a}")
|
|
result = below_value(series_a=a, value=value, asint=asint, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
def cross(self, a=None, b=None, above=True, asint=True, offset=None, **kwargs):
|
|
if a is None and b is None: return self._df
|
|
else:
|
|
a = self._get_column(a, f"{a}")
|
|
b = self._get_column(b, f"{b}")
|
|
result = cross(series_a=a, series_b=b, above=above, asint=asint, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
def cross_value(self, a=None, value=None, above=True, asint=True, offset=None, **kwargs):
|
|
if a is None and value is None: return self._df
|
|
else:
|
|
a = self._get_column(a, f"{a}")
|
|
result = cross_value(series_a=a, value=value, above=above, asint=asint, offset=offset, **kwargs)
|
|
self._add_prefix_suffix(result, **kwargs)
|
|
self._append(result, **kwargs)
|
|
return result
|
|
|
|
|
|
# Volatility Indicators
|
|
@finalize
|
|
def aberration(self, high=None, low=None, close=None, length=None, atr_length=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = aberration(high=high, low=low, close=close, length=length, atr_length=atr_length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def accbands(self, high=None, low=None, close=None, length=None, c=None, mamode=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = accbands(high=high, low=low, close=close, length=length, c=c, mamode=mamode, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def atr(self, high=None, low=None, close=None, length=None, mamode=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = atr(high=high, low=low, close=close, length=length, mamode=mamode, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def bbands(self, close=None, length=None, stdev=None, mamode=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = bbands(close=close, length=length, stdev=stdev, mamode=mamode, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def donchian(self, high=None, low=None, lower_length=None, upper_length=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = donchian(high=high, low=low, lower_length=lower_length, upper_length=upper_length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def kc(self, high=None, low=None, close=None, length=None, scalar=None, mamode=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = kc(high=high, low=low, close=close, length=length, scalar=scalar, mamode=mamode, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def massi(self, high=None, low=None, fast=None, slow=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = massi(high=high, low=low, fast=fast, slow=slow, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def natr(self, high=None, low=None, close=None, length=None, mamode=None, scalar=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = natr(high=high, low=low, close=close, length=length, mamode=mamode, scalar=scalar, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pdist(self, open_=None, high=None, low=None, close=None, drift=None, offset=None, **kwargs):
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = pdist(open_=open_, high=high, low=low, close=close, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def rvi(self, close=None, high=None, low=None, length=None, scalar=None, refined=None, thirds=None, mamode=None, drift=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
|
|
result = rvi(high=high, low=low, close=close, length=length, scalar=scalar, refined=refined, thirds=thirds, mamode=mamode, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def true_range(self, high=None, low=None, close=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = true_range(high=high, low=low, close=close, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def ui(self, close=None, length=None, scalar=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
|
|
result = ui(close=close, length=length, scalar=scalar, offset=offset, **kwargs)
|
|
return result
|
|
|
|
|
|
# Volume Indicators
|
|
@finalize
|
|
def ad(self, high=None, low=None, close=None, volume=None, open_=None, signed=True, offset=None, **kwargs):
|
|
if open_ is not None:
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = ad(high=high, low=low, close=close, volume=volume, open_=open_, signed=signed, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def adosc(self, high=None, low=None, close=None, volume=None, open_=None, fast=None, slow=None, signed=True, offset=None, **kwargs):
|
|
if open_ is not None:
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = adosc(high=high, low=low, close=close, volume=volume, open_=open_, fast=fast, slow=slow, signed=signed, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def aobv(self, close=None, volume=None, fast=None, slow=None, mamode=None, max_lookback=None, min_lookback=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = aobv(close=close, volume=volume, fast=fast, slow=slow, mamode=mamode, max_lookback=max_lookback, min_lookback=min_lookback, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def cmf(self, high=None, low=None, close=None, volume=None, open_=None, length=None, offset=None, **kwargs):
|
|
if open_ is not None:
|
|
open_ = self._get_column(open_, 'open')
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = cmf(high=high, low=low, close=close, volume=volume, open_=open_, length=length, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def efi(self, close=None, volume=None, length=None, mamode=None, offset=None, drift=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = efi(close=close, volume=volume, length=length, offset=offset, mamode=mamode, drift=drift, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def eom(self, high=None, low=None, close=None, volume=None, length=None, divisor=None, offset=None, drift=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = eom(high=high, low=low, close=close, volume=volume, length=length, divisor=divisor, offset=offset, drift=drift, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def mfi(self, high=None, low=None, close=None, volume=None, length=None, drift=None, offset=None, **kwargs):
|
|
high = self._get_column(high, 'high')
|
|
low = self._get_column(low, 'low')
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = mfi(high=high, low=low, close=close, volume=volume, length=length, drift=drift, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def nvi(self, close=None, volume=None, length=None, initial=None, signed=True, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = nvi(close=close, volume=volume, length=length, initial=initial, signed=signed, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def obv(self, close=None, volume=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = obv(close=close, volume=volume, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pvi(self, close=None, volume=None, length=None, initial=None, signed=True, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = pvi(close=close, volume=volume, length=length, initial=initial, signed=signed, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pvol(self, close=None, volume=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = pvol(close=close, volume=volume, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def pvt(self, close=None, volume=None, offset=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = pvt(close=close, volume=volume, offset=offset, **kwargs)
|
|
return result
|
|
|
|
@finalize
|
|
def vp(self, close=None, volume=None, width=None, percent=None, **kwargs):
|
|
close = self._get_column(close, 'close')
|
|
volume = self._get_column(volume, 'volume')
|
|
|
|
result = vp(close=close, volume=volume, width=width, percent=percent, **kwargs)
|
|
return result |