From 5c3bd08a00fc6b51d2b65ca5ef4441ae152d30ad Mon Sep 17 00:00:00 2001 From: Kevin Johnson Date: Mon, 18 Jan 2021 11:34:06 -0800 Subject: [PATCH] ENH #190 mcgd indicator added --- README.md | 6 +++-- pandas_ta/__init__.py | 2 +- pandas_ta/core.py | 4 ++-- pandas_ta/overlap/__init__.py | 2 +- pandas_ta/overlap/{mcg.py => mcgd.py} | 29 ++++++++++++++----------- setup.py | 2 +- tests/test_ext_indicator_overlap_ext.py | 5 +++++ tests/test_indicator_overlap.py | 5 +++++ 8 files changed, 35 insertions(+), 20 deletions(-) rename pandas_ta/overlap/{mcg.py => mcgd.py} (69%) diff --git a/README.md b/README.md index 3adc0ed..9e7d5fe 100644 --- a/README.md +++ b/README.md @@ -471,7 +471,7 @@ print(bothhl2.name) # "pre_HL2_post" |:--------:| | ![Example MACD](/images/SPY_MACD.png) | -### **Overlap** (29) +### **Overlap** (30) * _Double Exponential Moving Average_: **dema** * _Exponential Moving Average_: **ema** @@ -485,6 +485,7 @@ print(bothhl2.name) # "pre_HL2_post" * Use: help(ta.ichimoku). Returns two DataFrames. * _Kaufman's Adaptive Moving Average_: **kama** * _Linear Regression_: **linreg** +* _McGinley Dynamic_: **mcgd** * _Midpoint_: **midpoint** * _Midprice_: **midprice** * _Open-High-Low-Close Average_: **ohlc4** @@ -656,8 +657,9 @@ result = ta.cagr(df.close) * _Drawdown_ (**drawdown**) shows the peak-to-trough decline during a specific period for an investment, trading account, or fund. See: ```help(ta.drawdown)``` * _Gann High-Low Activator_ (**hilo**) was created by Robert Krausz in a 1998. See: ```help(ta.hilo)``` +* _McGinley Dynamic_ (**mcgd**) is an overlap indicator developed by John R. McGinley, a Certified Market Technician. See: ```help(ta.mcgd)``` +* _Price Volume Rank_ (**pvr**) was created by Anthony J. Macek. See: ```help(ta.pvr)``` * _Quantitative Qualitative Estimation_ (**qqe**) is like SuperTrend for a Smoothed RSI. See: ```help(ta.qqe)``` -* _Price Volume Rank_ (**pvr**) was created by Anthony J. Macek and is described in his article in the June, 1994 issue of Technical Analysis of Stocks & Commodities Magazine. See: ```help(ta.pvr)``` * _Relative Strength Xtra_ (**rsx**) is based on the popular RSI indicator and inspired by the work Jurik Research. See: ```help(ta.rsx)``` * _Ehler's Super Smoother Filter_ (**ssf**). Ehler's solution to reduce lag and remove aliasing noise compared to other common moving average indicators. See: ```help(ta.ssf)``` diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py index 436fa05..bfb07df 100644 --- a/pandas_ta/__init__.py +++ b/pandas_ta/__init__.py @@ -50,7 +50,7 @@ Category = { # Overlap "overlap": [ "dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku", - "kama", "linreg", "mcg", "midpoint", "midprice", "ohlc4", "pwma", "rma", + "kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4", "pwma", "rma", "sinwma", "sma", "ssf", "supertrend", "swma", "t3", "tema", "trima", "vidya", "vwap", "vwma", "wcp", "wma", "zlma" ], diff --git a/pandas_ta/core.py b/pandas_ta/core.py index fa861f0..cc96e06 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -1021,9 +1021,9 @@ class AnalysisIndicators(BasePandasObject): result = linreg(close=close, length=length, offset=offset, adjust=adjust, **kwargs) return self._post_process(result, **kwargs) - def mcg(self, length=None, offset=None, **kwargs): + def mcgd(self, length=None, offset=None, **kwargs): close = self._get_column(kwargs.pop("close", "close")) - result = mcg(close=close, length=length, offset=offset, **kwargs) + result = mcgd(close=close, length=length, offset=offset, **kwargs) return self._post_process(result, **kwargs) def midpoint(self, length=None, offset=None, **kwargs): diff --git a/pandas_ta/overlap/__init__.py b/pandas_ta/overlap/__init__.py index 90f9476..71725ae 100644 --- a/pandas_ta/overlap/__init__.py +++ b/pandas_ta/overlap/__init__.py @@ -10,7 +10,7 @@ from .kama import kama from .ichimoku import ichimoku from .linreg import linreg from .ma import ma -from .mcg import mcg +from .mcgd import mcgd from .midpoint import midpoint from .midprice import midprice from .ohlc4 import ohlc4 diff --git a/pandas_ta/overlap/mcg.py b/pandas_ta/overlap/mcgd.py similarity index 69% rename from pandas_ta/overlap/mcg.py rename to pandas_ta/overlap/mcgd.py index dfaebbd..f353c8c 100644 --- a/pandas_ta/overlap/mcg.py +++ b/pandas_ta/overlap/mcgd.py @@ -2,12 +2,12 @@ from pandas_ta.utils import get_offset, verify_series -def mcg(close, length: int = 10, offset: int = 0, c: float = 1, **kwargs): +def mcgd(close, length=None, offset=None, c=None, **kwargs): """Indicator: McGinley Dynamic Indicator""" # Validate arguments close = verify_series(close) - length = int(length) if length > 0 else 10 - c = c if 1 >= c > 0 else 1 + length = int(length) if length and length > 0 else 10 + c = float(c) if c and 0 < c <= 1 else 1 offset = get_offset(offset) # Calculate Result @@ -32,19 +32,22 @@ def mcg(close, length: int = 10, offset: int = 0, c: float = 1, **kwargs): mcg_ds.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category - mcg_ds.name = f"McGinley_{length}" - mcg_ds.category = 'overlap' + mcg_ds.name = f"MCGD_{length}" + mcg_ds.category = "overlap" return mcg_ds -mcg.__doc__ = \ +mcgd.__doc__ = \ """McGinley Dynamic Indicator -The McGinley Dynamic looks like a moving average line, yet it is actually a smoothing mechanism -for prices that minimizes price separation, price whipsaws, and hugs prices much more closely. -Because of the calculation, the Dynamic Line speeds up in down markets as it follows prices -yet moves more slowly in up markets. +The McGinley Dynamic looks like a moving average line, yet it is actually a +smoothing mechanism for prices that minimizes price separation, price whipsaws, +and hugs prices much more closely. Because of the calculation, the Dynamic Line +speeds up in down markets as it follows prices yet moves more slowly in up +markets. The indicator was designed by John R. McGinley, a Certified Market +Technician and former editor of the Market Technicians Association's Journal +of Technical Analysis. Sources: https://www.investopedia.com/articles/forex/09/mcginley-dynamic-indicator.asp @@ -54,7 +57,7 @@ Calculation: length=10 offset=0 c=1 - + def mcg_(series): denom = (constant * length * (series.iloc[1] / series.iloc[0]) ** 4) series.iloc[1] = (series.iloc[0] + ((series.iloc[1] - series.iloc[0]) / denom)) @@ -64,8 +67,8 @@ Calculation: Args: close (pd.Series): Series of 'close's - length (int): Indicator's period. Default: 10 - offset (int): Number of periods to offset the result. Default: 0 + length (int): Indicator's period. Default: 10 + offset (int): Number of periods to offset the result. Default: 0 c (float): Multiplier for the denominator, sometimes set to 0.6. Default: 1 Kwargs: diff --git a/setup.py b/setup.py index f4869c9..40f41cc 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( "pandas_ta.volatility", "pandas_ta.volume" ], - version=".".join(("0", "2", "35b")), + version=".".join(("0", "2", "36b")), 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 2074862..0ce4167 100644 --- a/tests/test_ext_indicator_overlap_ext.py +++ b/tests/test_ext_indicator_overlap_ext.py @@ -68,6 +68,11 @@ class TestOverlapExtension(TestCase): self.assertIsInstance(self.data, DataFrame) self.assertEqual(self.data.columns[-1], "LR_14") + def test_mcgd_ext(self): + self.data.ta.mcgd(append=True) + self.assertIsInstance(self.data, DataFrame) + self.assertEqual(self.data.columns[-1], "MCGD_10") + def test_midpoint_ext(self): self.data.ta.midpoint(append=True) self.assertIsInstance(self.data, DataFrame) diff --git a/tests/test_indicator_overlap.py b/tests/test_indicator_overlap.py index f747d52..c9c1c9d 100644 --- a/tests/test_indicator_overlap.py +++ b/tests/test_indicator_overlap.py @@ -189,6 +189,11 @@ class TestOverlap(TestCase): self.assertIsInstance(result, Series) self.assertEqual(result.name, "FWMA_15") + def test_mcgd(self): + result = pandas_ta.mcgd(self.close) + self.assertIsInstance(result, Series) + self.assertEqual(result.name, "MCGD_10") + def test_midpoint(self): result = pandas_ta.midpoint(self.close) self.assertIsInstance(result, Series)