Merge pull request #53 from twopirllc/master

Master -> Development
This commit is contained in:
Kevin Johnson
2020-05-26 12:11:45 -07:00
committed by GitHub
5 changed files with 124 additions and 7 deletions
+2 -2
View File
@@ -6,7 +6,7 @@
# Technical Analysis Library in Python 3.7
![Example Chart](/images/TA_Chart.png)
Technical Analysis (TA) is an easy to use library that is built upon Python's Pandas library with more than 85 Indicators. These indicators are comminly used for financial time series datasets with columns or labels similar to: datetime, open, high, low, close, volume, et al. Many commonly used indicators are included, such as: _Moving Average Convergence Divergence_ (*MACD*), _Hull Exponential Moving Average_ (*HMA*), _Bollinger Bands_ (*BBANDS*), _On-Balance Volume_ (*OBV*), _Aroon Oscillator_ (*AROON*) and more.
Technical Analysis (TA) is an easy to use library that is built upon Python's Pandas library with more than 100 Indicators. These indicators are comminly used for financial time series datasets with columns or labels similar to: datetime, open, high, low, close, volume, et al. Many commonly used indicators are included, such as: _Moving Average Convergence Divergence_ (*MACD*), _Hull Exponential Moving Average_ (*HMA*), _Bollinger Bands_ (*BBANDS*), _On-Balance Volume_ (*OBV*), _Aroon & Aroon Oscillator_ (*AROON*) and more.
This version contains both the orignal code branch as well as a newly refactored branch with the option to use [Pandas DataFrame Extension](https://pandas.pydata.org/pandas-docs/stable/extending.html) mode.
All the indicators return a named Series or a DataFrame in uppercase underscore parameter format. For example, MACD(fast=12, slow=26, signal=9) will return a DataFrame with columns: ['MACD_12_26_9', 'MACDH_12_26_9', 'MACDS_12_26_9'].
@@ -119,7 +119,7 @@ print(prehl2.columns) # "pre_HL2"
endhl2 = df.ta.hl2(suffix="end")
print(endhl2.columns) # "HL2_end"
bothhl2 = df.ta.hl2(suffix="end")
bothhl2 = df.ta.hl2(prefix="pre", suffix="end")
print(bothhl2.columns) # "pre_HL2_end"
```
+9
View File
@@ -951,6 +951,15 @@ class AnalysisIndicators(BasePandasObject):
result = cross(series_a=a, series_b=b, above=above, asint=asint, offset=offset, **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
+36 -3
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from pandas import DataFrame, concat
from ..overlap.ema import ema
from ..utils import get_offset, verify_series
from ..utils import get_offset, verify_series, generate_signal_indicators
def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
"""Indicator: Moving Average, Convergence/Divergence (MACD)"""
@@ -51,7 +51,40 @@ def macd(close, fast=None, slow=None, signal=None, offset=None, **kwargs):
macddf.name = f"MACD_{fast}_{slow}_{signal}"
macddf.category = 'momentum'
return macddf
signal_indicators = kwargs.pop('signal_indicators', False)
if signal_indicators:
signalsdf = concat(
[
macddf,
generate_signal_indicators(
indicator=histogram,
xa=kwargs.pop('xa', 0),
xb=kwargs.pop('xb', None),
xserie=kwargs.pop('xserie', None),
xserie_a=kwargs.pop('xserie_a', None),
xserie_b=kwargs.pop('xserie_b', None),
cross_values=kwargs.pop('cross_values', True),
cross_series=kwargs.pop('cross_series', True),
offset=offset,
),
generate_signal_indicators(
indicator=macd,
xa=kwargs.pop('xa', 0),
xb=kwargs.pop('xb', None),
xserie=kwargs.pop('xserie', None),
xserie_a=kwargs.pop('xserie_a', None),
xserie_b=kwargs.pop('xserie_b', None),
cross_values=kwargs.pop('cross_values', False),
cross_series=kwargs.pop('cross_series', True),
offset=offset,
),
],
axis=1
)
return signalsdf
else:
return macddf
+27 -2
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from ..utils import get_drift, get_offset, verify_series
from pandas import DataFrame, concat
from ..utils import get_drift, get_offset, verify_series, generate_signal_indicators
def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: Relative Strength Index (RSI)"""
@@ -36,7 +37,31 @@ def rsi(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
rsi.name = f"RSI_{length}"
rsi.category = 'momentum'
return rsi
signal_indicators = kwargs.pop('signal_indicators', False)
if signal_indicators:
signalsdf = concat(
[
DataFrame(
{rsi.name: rsi}
),
generate_signal_indicators(
indicator=rsi,
xa=kwargs.pop('xa', 80),
xb=kwargs.pop('xb', 20),
xserie=kwargs.pop('xserie', None),
xserie_a=kwargs.pop('xserie_a', None),
xserie_b=kwargs.pop('xserie_b', None),
cross_values=kwargs.pop('cross_values', False),
cross_series=kwargs.pop('cross_series', True),
offset=offset,
),
],
axis=1
)
return signalsdf
else:
return rsi
+50
View File
@@ -82,6 +82,10 @@ def combination(**kwargs):
return numerator // denominator
def cross_value(series_a:pd.Series, value:float, above:bool =True, asint:bool =True, offset:int =None, **kwargs):
series_b = pd.Series(value, index=series_a.index, name=f"{value}".replace('.','_'))
return cross(series_a, series_b, above, asint, offset, **kwargs)
def cross(series_a:pd.Series, series_b:pd.Series, above:bool =True, asint:bool =True, offset:int =None, **kwargs):
series_a = verify_series(series_a)
series_b = verify_series(series_b)
@@ -109,7 +113,53 @@ def cross(series_a:pd.Series, series_b:pd.Series, above:bool =True, asint:bool =
return cross
def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_series, offset):
signalsdf = pd.DataFrame()
if xa is not None and isinstance(xa, (int, float)):
if cross_values:
crossed_above_start = cross_value(indicator, xa, above=True, offset=offset)
crossed_above_end = cross_value(indicator, xa, above=False, offset=offset)
signalsdf[crossed_above_start.name] = crossed_above_start
signalsdf[crossed_above_end.name] = crossed_above_end
else:
crossed_above = above_value(indicator, xa, offset=offset)
signalsdf[crossed_above.name] = crossed_above
if xb is not None and isinstance(xb, (int, float)):
if cross_values:
crossed_below_start = cross_value(indicator, xb, above=True, offset=offset)
crossed_below_end = cross_value(indicator, xb, above=False, offset=offset)
signalsdf[crossed_below_start.name] = crossed_below_start
signalsdf[crossed_below_end.name] = crossed_below_end
else:
crossed_below = below_value(indicator, xb, offset=offset)
signalsdf[crossed_below.name] = crossed_below
# xseries is the default value for both xserie_a and xserie_b
if xserie_a is None:
xserie_a = xserie
if xserie_b is None:
xserie_b = xserie
if xserie_a is not None and verify_series(xserie_a):
if cross_series:
cross_serie_above = cross(indicator, xserie_a, above=True, offset=offset)
else:
cross_serie_above = above(indicator, xserie_a, offset=offset)
signalsdf[cross_serie_above.name] = cross_serie_above
if xserie_b is not None and verify_series(xserie_b):
if cross_series:
cross_serie_below = cross(indicator, xserie_b, above=False, offset=offset)
else:
cross_serie_below = below(indicator, xserie_b, offset=offset)
signalsdf[cross_serie_below.name] = cross_serie_below
return signalsdf
def df_error_analysis(dfA:pd.DataFrame, dfB:pd.DataFrame, **kwargs):
""" """
col = kwargs.pop('col', None)