diff --git a/README.md b/README.md index 0a32abb..0c4dfc9 100644 --- a/README.md +++ b/README.md @@ -554,11 +554,82 @@ help(ta.yf)

# **Indicators** (_by Category_) -### **Candles** (3) +### **Candles** (63) -* _Doji_: **cdl_doji** -* _Inside Bar_: **cdl_inside** +* _Patterns_: cdl_pattern (Patterns that aren't bold, need TA-Lib to be installed: "```pip install TA-Lib```") + * 2crows + * 3blackcrows + * 3inside + * 3linestrike + * 3outside + * 3starsinsouth + * 3whitesoldiers + * abandonedbaby + * advanceblock + * belthold + * breakaway + * closingmarubozu + * concealbabyswall + * counterattack + * darkcloudcover + * **doji** + * dojistar + * dragonflydoji + * engulfing + * eveningdojistar + * eveningstar + * gapsidesidewhite + * gravestonedoji + * hammer + * hangingman + * harami + * haramicross + * highwave + * hikkake + * hikkakemod + * homingpigeon + * identical3crows + * inneck + * **inside** + * invertedhammer + * kicking + * kickingbylength + * ladderbottom + * longleggeddoji + * longline + * marubozu + * matchinglow + * mathold + * morningdojistar + * morningstar + * onneck + * piercing + * rickshawman + * risefall3methods + * separatinglines + * shootingstar + * shortline + * spinningtop + * stalledpattern + * sticksandwich + * takuri + * tasukigap + * thrusting + * tristar + * unique3river + * upsidegap2crows + * xsidegap3methods * _Heikin-Ashi_: **ha** +```python +# Get all candle patterns (This is the default behaviour) +df = df.ta.cdl_pattern(name="all") + +# Get only one pattern +df = df.ta.cdl_pattern(name="doji") + +# Get some patterns +df = df.ta.cdl_pattern(name=["doji", "inside"]) +```
diff --git a/pandas_ta/__init__.py b/pandas_ta/__init__.py index f816e4e..52cf265 100644 --- a/pandas_ta/__init__.py +++ b/pandas_ta/__init__.py @@ -40,7 +40,7 @@ Imports = { Category = { # Candles "candles": [ - "cdl_doji", "cdl_inside", "ha" + "cdl_pattern", "ha" ], # Cycles "cycles": ["ebsw"], diff --git a/pandas_ta/candles/__init__.py b/pandas_ta/candles/__init__.py index a94f3f7..b0444e2 100644 --- a/pandas_ta/candles/__init__.py +++ b/pandas_ta/candles/__init__.py @@ -2,3 +2,4 @@ from .ha import ha from .cdl_doji import cdl_doji from .cdl_inside import cdl_inside +from .cdl_pattern import cdl_pattern, ALL_PATTERNS as CDL_PATTERN_NAMES diff --git a/pandas_ta/candles/cdl_pattern.py b/pandas_ta/candles/cdl_pattern.py new file mode 100644 index 0000000..3a2cb0f --- /dev/null +++ b/pandas_ta/candles/cdl_pattern.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +from typing import Sequence, Union +from pandas import Series, DataFrame + +from . import cdl_doji, cdl_inside +from pandas_ta.utils import get_offset, verify_series +from pandas_ta import Imports +if Imports["talib"]: + import talib.abstract as tala + + +ALL_PATTERNS = [ + "2crows", "3blackcrows", "3inside", "3linestrike", "3outside", "3starsinsouth", + "3whitesoldiers", "abandonedbaby", "advanceblock", "belthold", "breakaway", + "closingmarubozu", "concealbabyswall", "counterattack", "darkcloudcover", "doji", + "dojistar", "dragonflydoji", "engulfing", "eveningdojistar", "eveningstar", + "gapsidesidewhite", "gravestonedoji", "hammer", "hangingman", "harami", + "haramicross", "highwave", "hikkake", "hikkakemod", "homingpigeon", + "identical3crows", "inneck", "inside", "invertedhammer", "kicking", "kickingbylength", + "ladderbottom", "longleggeddoji", "longline", "marubozu", "matchinglow", "mathold", + "morningdojistar", "morningstar", "onneck", "piercing", "rickshawman", + "risefall3methods", "separatinglines", "shootingstar", "shortline", "spinningtop", + "stalledpattern", "sticksandwich", "takuri", "tasukigap", "thrusting", "tristar", + "unique3river", "upsidegap2crows", "xsidegap3methods" +] + + +def cdl_pattern(open_, high, low, close, name: Union[str, Sequence[str]]="all", scalar=None, offset=None, **kwargs) -> DataFrame: + """Candle Pattern""" + # Validate Arguments + open_ = verify_series(open_) + high = verify_series(high) + low = verify_series(low) + close = verify_series(close) + offset = get_offset(offset) + scalar = float(scalar) if scalar else 100 + + # Patterns that implemented in pandas-ta + pta_patterns = { + "doji": cdl_doji, "inside": cdl_inside, + } + + if name == "all": + name = ALL_PATTERNS + if type(name) is str: + name = [name] + + result = {} + for n in name: + if n not in ALL_PATTERNS: + print(f"[X] There is no candle pattern named {n} available!") + continue + if n in pta_patterns: + pattern_result = pta_patterns[n](open_, high, low, close, offset=offset, scalar=scalar, **kwargs) + result[pattern_result.name] = pattern_result + else: + if not Imports["talib"]: + print(f"[X] Please install TA-Lib to use {n}. (pip install TA-Lib)") + continue + + pattern_func = tala.Function("CDL" + n.upper()) + pattern_result = Series(pattern_func(open_, high, low, close, **kwargs) / 100 * scalar) + pattern_result.index = close.index + + # Offset + if offset != 0: + pattern_result = pattern_result.shift(offset) + + # Handle fills + if "fillna" in kwargs: + pattern_result.fillna(kwargs["fillna"], inplace=True) + if "fill_method" in kwargs: + pattern_result.fillna(method=kwargs["fill_method"], inplace=True) + + result["CDL_" + n.upper()] = pattern_result + + if len(result) == 0: + return + + # Prepare DataFrame to return + df = DataFrame(result) + df.name = "CDL_PATTERN" + df.category = "candles" + return df + + +cdl_pattern.__doc__ = \ +"""Candle Pattern + +A wrapper around all candle patterns. + +Args: + open_ (pd.Series): Series of 'open's + high (pd.Series): Series of 'high's + low (pd.Series): Series of 'low's + close (pd.Series): Series of 'close's + name: (Union[str, Sequence[str]]): name of the patterns + scalar (float): How much to magnify. Default: 100 + 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.DataFrame: one column for each pattern. +""" diff --git a/pandas_ta/core.py b/pandas_ta/core.py index 3862b61..5f8696b 100644 --- a/pandas_ta/core.py +++ b/pandas_ta/core.py @@ -832,20 +832,12 @@ class AnalysisIndicators(BasePandasObject): # Public DataFrame Methods: Indicators and Utilities # Candles - def cdl_doji(self, offset=None, **kwargs): + def cdl_pattern(self, name="all", offset=None, **kwargs): open_ = self._get_column(kwargs.pop("open", "open")) high = self._get_column(kwargs.pop("high", "high")) low = self._get_column(kwargs.pop("low", "low")) close = self._get_column(kwargs.pop("close", "close")) - result = cdl_doji(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs) - return self._post_process(result, **kwargs) - - def cdl_inside(self, offset=None, **kwargs): - open_ = self._get_column(kwargs.pop("open", "open")) - high = self._get_column(kwargs.pop("high", "high")) - low = self._get_column(kwargs.pop("low", "low")) - close = self._get_column(kwargs.pop("close", "close")) - result = cdl_inside(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs) + result = cdl_pattern(open_=open_, high=high, low=low, close=close, name=name, offset=offset, **kwargs) return self._post_process(result, **kwargs) def ha(self, offset=None, **kwargs): diff --git a/tests/test_indicator_candle.py b/tests/test_indicator_candle.py index beba7f9..81a1345 100644 --- a/tests/test_indicator_candle.py +++ b/tests/test_indicator_candle.py @@ -39,6 +39,17 @@ class TestCandle(TestCase): self.assertIsInstance(result, DataFrame) self.assertEqual(result.name, "Heikin-Ashi") + def test_cdl_pattern(self): + result = pandas_ta.cdl_pattern(self.open, self.high, self.low, self.close, name="all") + self.assertIsInstance(result, DataFrame) + self.assertEqual(len(result.columns), len(pandas_ta.CDL_PATTERN_NAMES)) + + result = pandas_ta.cdl_pattern(self.open, self.high, self.low, self.close, name="doji") + self.assertIsInstance(result, DataFrame) + + result = pandas_ta.cdl_pattern(self.open, self.high, self.low, self.close, name=["doji", "inside"]) + self.assertIsInstance(result, DataFrame) + def test_cdl_doji(self): result = pandas_ta.cdl_doji(self.open, self.high, self.low, self.close) self.assertIsInstance(result, Series)