diff --git a/README.md b/README.md index 0ce142e..dbd0339 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ help(pd.DataFrame().ta.log_return) |:--------:| | ![Example MACD](/images/SPY_MACD.png) | -## _Overlap_ (23) +## _Overlap_ (24) * _Double Exponential Moving Average_: **dema** * _Exponential Moving Average_: **ema** @@ -128,6 +128,7 @@ help(pd.DataFrame().ta.log_return) * _Pascal's Weighted Moving Average_: **pwma** * _William's Moving Average_: **rma** * _Simple Moving Average_: **sma** +* _Sine Weighted Moving Average_: **sinwma** * _Symmetric Weighted Moving Average_: **swma** * _T3 Moving Average_: **t3** * _Triple Exponential Moving Average_: **tema** @@ -229,6 +230,7 @@ Use parameter: cumulative=**True** for cumulative results. # Inspiration +* TradingView: http://www.tradingview.com * Original TA-LIB: http://ta-lib.org/ * Bukosabino: https://github.com/bukosabino/ta diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py index 4f99926..7606998 100644 --- a/pandas_ta/__init__.py +++ b/pandas_ta/__init__.py @@ -56,6 +56,7 @@ from .overlap.midprice import midprice from .overlap.ohlc4 import ohlc4 from .overlap.pwma import pwma from .overlap.rma import rma +from .overlap.sinwma import sinwma from .overlap.sma import sma from .overlap.swma import swma from .overlap.t3 import t3 diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 01c9199..990d7ac 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -502,6 +502,13 @@ class AnalysisIndicators(BasePandasObject): self._append(result, **kwargs) return result + def sinwma(self, close=None, length=None, offset=None, **kwargs): + close = self._get_column(close, 'close') + from .overlap.sinwma import sinwma + result = sinwma(close=close, length=length, offset=offset, **kwargs) + self._append(result, **kwargs) + return result + def sma(self, close=None, length=None, offset=None, **kwargs): close = self._get_column(close, 'close') from .overlap.sma import sma diff --git a/pandas_ta/overlap/sinwma.py b/pandas_ta/overlap/sinwma.py new file mode 100644 index 0000000..b78aec0 --- /dev/null +++ b/pandas_ta/overlap/sinwma.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +from math import pi +from math import sin +from pandas import Series +from ..utils import get_offset, pascals_triangle, verify_series, weights + +def sinwma(close, length=None, asc=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 + min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length + offset = get_offset(offset) + + # Calculate Result + sines = Series([sin((i + 1) * pi / (length + 1)) for i in range(0, length)]) + w = sines / sines.sum() + + sinwma = close.rolling(length, min_periods=length).apply(weights(w), raw=True) + + # Offset + if offset != 0: + sinwma = sinwma.shift(offset) + + # Name & Category + sinwma.name = f"SINWMA_{length}" + sinwma.category = 'overlap' + + return sinwma + + + +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). + +Source: + https://www.tradingview.com/script/6MWFvnPO-Sine-Weighted-Moving-Average/ + Author: Everget (https://www.tradingview.com/u/everget/) + +Calculation: + Default Inputs: + length=10 + + def weights(w): + def _compute(x): + return np.dot(w * x) + return _compute + + sines = Series([sin((i + 1) * pi / (length + 1)) for i in range(0, length)]) + w = sines / sines.sum() + SINWMA = close.rolling(length, min_periods=length).apply(weights(w), raw=True) + +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 + +Kwargs: + fillna (value, optional): pd.DataFrame.fillna(value) + fill_method (value, optional): Type of fill method + +Returns: + pd.Series: New feature generated. +""" \ No newline at end of file diff --git a/setup.py b/setup.py index 0ecc321..c1d6790 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ long_description = "An easy to use Python 3 Pandas Extension with 80+ Technical setup( name ="pandas_ta", packages =['pandas_ta', 'pandas_ta.momentum', 'pandas_ta.overlap', 'pandas_ta.performance', 'pandas_ta.statistics', 'pandas_ta.trend', 'pandas_ta.volatility', 'pandas_ta.volume'], - version ="0.1.33b", + version ="0.1.34b", description =long_description, long_description =long_description, author ="Kevin Johnson", diff --git a/tests/test_indicator_overlap.py b/tests/test_indicator_overlap.py index f95c960..3656e4f 100644 --- a/tests/test_indicator_overlap.py +++ b/tests/test_indicator_overlap.py @@ -218,6 +218,11 @@ class TestOverlap(TestCase): self.assertIsInstance(result, Series) self.assertEqual(result.name, 'RMA_10') + def test_sinwma(self): + result = pandas_ta.sinwma(self.close) + self.assertIsInstance(result, Series) + self.assertEqual(result.name, 'SINWMA_14') + def test_sma(self): result = pandas_ta.sma(self.close) self.assertIsInstance(result, Series) diff --git a/tests/test_indicator_overlap_ext.py b/tests/test_indicator_overlap_ext.py index d88a42e..e4b12da 100644 --- a/tests/test_indicator_overlap_ext.py +++ b/tests/test_indicator_overlap_ext.py @@ -93,6 +93,11 @@ class TestOverlapExtension(TestCase): self.assertIsInstance(self.data, DataFrame) self.assertEqual(self.data.columns[-1], 'RMA_10') + def test_sinwma_ext(self): + self.data.ta.sinwma(append=True) + self.assertIsInstance(self.data, DataFrame) + self.assertEqual(self.data.columns[-1], 'SINWMA_14') + def test_sma_ext(self): self.data.ta.sma(append=True) self.assertIsInstance(self.data, DataFrame)