diff --git a/Makefile b/Makefile index 149f014..659bbe4 100644 --- a/Makefile +++ b/Makefile @@ -28,5 +28,4 @@ test_ta: python -m unittest -v -f tests/test_indicator_*.py test_utils: - python -m unittest -v -f tests/test_utils.py - python -m unittest -v -f tests/test_utils_metrics.py \ No newline at end of file + python -m unittest -v -f tests/test_utils.py \ No newline at end of file diff --git a/README.md b/README.md index b197f4f..d621cb5 100644 --- a/README.md +++ b/README.md @@ -672,6 +672,7 @@ article in the June, 1994 issue of Technical Analysis of Stocks & Commodities Ma * _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. +* _Volume Weighted Average Price_ (**vwap**) Added a new parameter called ```anchor```. Default: "D" for "Daily". See [Timeseries Offset Aliases](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-offset-aliases) for additional options.
diff --git a/pandas_ta/core.py b/pandas_ta/core.py index cc96e06..ba34285 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -1104,7 +1104,7 @@ class AnalysisIndicators(BasePandasObject): result = vidya(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) - def vwap(self, offset=None, **kwargs): + def vwap(self, anchor=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")) @@ -1113,7 +1113,7 @@ class AnalysisIndicators(BasePandasObject): if not self.datetime_ordered: volume.index = self._df.index - result = vwap(high=high, low=low, close=close, volume=volume, offset=offset, **kwargs) + result = vwap(high=high, low=low, close=close, volume=volume, anchor=anchor, offset=offset, **kwargs) return self._post_process(result, **kwargs) def vwma(self, volume=None, length=None, offset=None, **kwargs): diff --git a/pandas_ta/overlap/vwap.py b/pandas_ta/overlap/vwap.py index b07eb8d..8ed1517 100644 --- a/pandas_ta/overlap/vwap.py +++ b/pandas_ta/overlap/vwap.py @@ -2,33 +2,33 @@ from .hlc3 import hlc3 from pandas_ta.utils import get_offset, is_datetime_ordered, verify_series -def vwap(high, low, close, volume, offset=None, **kwargs): +def vwap(high, low, close, volume, anchor=None, offset=None, **kwargs): """Indicator: Volume Weighted Average Price (VWAP)""" # Validate Arguments high = verify_series(high) low = verify_series(low) close = verify_series(close) volume = verify_series(volume) + anchor = anchor.upper() if anchor and isinstance(anchor, str) and len(anchor) >= 1 else "D" offset = get_offset(offset) typical_price = hlc3(high=high, low=low, close=close) - if not is_datetime_ordered(volume): print(f"[!] VWAP volume series is not datetime ordered. Results may not be as expected.") if not is_datetime_ordered(typical_price): print(f"[!] VWAP price series is not datetime ordered. Results may not be as expected.") # Calculate Result - weighted_price = typical_price * volume - vwap = weighted_price.groupby(weighted_price.index.to_period("d")).cumsum() - vwap /= volume.groupby(volume.index.to_period("d")).cumsum() + wp = typical_price * volume + vwap = wp.groupby(wp.index.to_period(anchor)).cumsum() + vwap /= volume.groupby(volume.index.to_period(anchor)).cumsum() # Offset if offset != 0: vwap = vwap.shift(offset) # Name & Category - vwap.name = "VWAP" + vwap.name = f"VWAP_{anchor}" vwap.category = "overlap" return vwap @@ -56,7 +56,11 @@ Args: low (pd.Series): Series of 'low's close (pd.Series): Series of 'close's volume (pd.Series): Series of 'volume's - offset (int): How many periods to offset the result. Default: 0 + anchor (str): How to anchor VWAP. Depending on the index values, it will + implement various Timeseries Offset Aliases as listed here: + https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-offset-aliases + Default: "D". + offset (int): How many periods to offset the result. Default: 0 Kwargs: fillna (value, optional): pd.DataFrame.fillna(value) diff --git a/setup.py b/setup.py index b9bfb4b..f20ee9a 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( "pandas_ta.volatility", "pandas_ta.volume" ], - version=".".join(("0", "2", "37b")), + version=".".join(("0", "2", "38b")), description=long_description, long_description=long_description, author="Kevin Johnson", diff --git a/tests/test_ext_indicator_overlap_ext.py b/tests/test_ext_indicator_overlap_ext.py index 0ce4167..9744621 100644 --- a/tests/test_ext_indicator_overlap_ext.py +++ b/tests/test_ext_indicator_overlap_ext.py @@ -150,7 +150,7 @@ class TestOverlapExtension(TestCase): def test_vwap_ext(self): self.data.ta.vwap(append=True) self.assertIsInstance(self.data, DataFrame) - self.assertEqual(self.data.columns[-1], "VWAP") + self.assertEqual(self.data.columns[-1], "VWAP_D") def test_vwma_ext(self): self.data.ta.vwma(append=True) diff --git a/tests/test_indicator_overlap.py b/tests/test_indicator_overlap.py index c9c1c9d..971aea6 100644 --- a/tests/test_indicator_overlap.py +++ b/tests/test_indicator_overlap.py @@ -331,7 +331,7 @@ class TestOverlap(TestCase): def test_vwap(self): result = pandas_ta.vwap(self.high, self.low, self.close, self.volume) self.assertIsInstance(result, Series) - self.assertEqual(result.name, "VWAP") + self.assertEqual(result.name, "VWAP_D") def test_vwma(self): result = pandas_ta.vwma(self.close, self.volume)