Skip to content

parabolic_sar ¤

parabolic_sar ¤

parabolic_sar(
    dataframe: DataFrame,
    af0: float = 0.02,
    af: float = 0.02,
    max_af: float = 0.2,
    prefix: str = "psar_",
    inplace: bool = False,
    plot: bool | list[str] = False,
    plot_kwargs: dict | None = None,
) -> dict[str, Series] | DataFrame

Indicator: Parabolic Stop and Reverse (PSAR)

Source

https://github.com/twopirllc/pandas-ta/blob/main/pandas_ta/trend/psar.py

Parameters:

  • dataframe (DataFrame) –

    description

  • af0 (float, default: 0.02 ) –

    description. Defaults to 0.02.

  • af (float, default: 0.02 ) –

    description. Defaults to 0.02.

  • max_af (float, default: 0.2 ) –

    description. Defaults to 0.2.

  • prefix (str, default: 'psar_' ) –

    description. Defaults to "psar_".

  • inplace (bool, default: False ) –

    description. Defaults to False.

  • plot (bool | list, default: False ) –

    description. Defaults to False.

  • plot_kwargs (dict | None, default: None ) –

    description. Defaults to None.

Raises:

Returns:

  • dict[str, Series] | DataFrame

    dict[str, pd.Series] | pd.DataFrame: description

Source code in lettrade/indicator/trend/parabolic_sar.py
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def parabolic_sar(
    dataframe: pd.DataFrame,
    af0: float = 0.02,
    af: float = 0.02,
    max_af: float = 0.2,
    prefix: str = "psar_",
    inplace: bool = False,
    plot: bool | list[str] = False,
    plot_kwargs: dict | None = None,
) -> dict[str, pd.Series] | pd.DataFrame:
    """Indicator: Parabolic Stop and Reverse (PSAR)

    Source:
        https://github.com/twopirllc/pandas-ta/blob/main/pandas_ta/trend/psar.py

    Args:
        dataframe (pd.DataFrame): _description_
        af0 (float, optional): _description_. Defaults to 0.02.
        af (float, optional): _description_. Defaults to 0.02.
        max_af (float, optional): _description_. Defaults to 0.2.
        prefix (str, optional): _description_. Defaults to "psar_".
        inplace (bool, optional): _description_. Defaults to False.
        plot (bool | list, optional): _description_. Defaults to False.
        plot_kwargs (dict | None, optional): _description_. Defaults to None.

    Raises:
        RuntimeError: _description_

    Returns:
        dict[str, pd.Series] | pd.DataFrame: _description_
    """
    if __debug__:
        if not isinstance(dataframe, pd.DataFrame):
            raise RuntimeError(
                f"dataframe type '{type(dataframe)}' "
                "is not instance of pandas.DataFrame"
            )

    def _falling(high: pd.Series, low: pd.Series, drift: int = 1):
        """Returns the last -DM value"""
        # Not to be confused with ta.falling()
        up = high - high.shift(drift)
        dn = low.shift(drift) - low
        dmn = (((dn > up) & (dn > 0)) * dn).apply(zero).iloc[-1]
        return dmn > 0

    # Falling if the first NaN -DM is positive
    falling = _falling(dataframe.high.iloc[:2], dataframe.low.iloc[:2])
    if falling:
        sar = dataframe.high.iloc[0]
        ep = dataframe.low.iloc[0]
    else:
        sar = dataframe.low.iloc[0]
        ep = dataframe.high.iloc[0]

    sar = dataframe.close.iloc[0]

    i_long = pd.Series(np.nan, index=dataframe.high.index)
    i_short = i_long.copy()
    i_reversal = pd.Series(0, index=dataframe.high.index)
    i_af = i_long.copy()
    i_af.iloc[0:2] = af0

    # Calculate Result
    m = dataframe.high.shape[0]
    for row in range(1, m):
        high_ = dataframe.high.iloc[row]
        low_ = dataframe.low.iloc[row]

        if falling:
            _sar = sar + af * (ep - sar)
            reverse = high_ > _sar

            if low_ < ep:
                ep = low_
                af = min(af + af0, max_af)

            _sar = max(dataframe.high.iloc[row - 1], dataframe.high.iloc[row - 2], _sar)
        else:
            _sar = sar + af * (ep - sar)
            reverse = low_ < _sar

            if high_ > ep:
                ep = high_
                af = min(af + af0, max_af)

            _sar = min(dataframe.low.iloc[row - 1], dataframe.low.iloc[row - 2], _sar)

        if reverse:
            _sar = ep
            af = af0
            falling = not falling  # Must come before next line
            ep = low_ if falling else high_

        sar = _sar  # Update SAR

        # Seperate long/short sar based on falling
        if falling:
            i_short.iloc[row] = sar
        else:
            i_long.iloc[row] = sar

        i_af.iloc[row] = af
        i_reversal.iloc[row] = int(reverse)

    # Result is inplace or new dict
    result = dataframe if inplace else {}

    result[f"{prefix}long"] = i_long
    result[f"{prefix}short"] = i_short
    result[f"{prefix}af"] = i_af
    result[f"{prefix}reversal"] = i_reversal

    # Plot
    if plot:
        if plot_kwargs is None:
            plot_kwargs = dict()

        if isinstance(plot, list):
            if f"{prefix}long" in plot:
                plot_kwargs.update(long=f"{prefix}long")
            if f"{prefix}short" in plot:
                plot_kwargs.update(short=f"{prefix}short")
        else:
            plot_kwargs.update(
                long=f"{prefix}long",
                short=f"{prefix}short",
            )

        from lettrade.indicator.plot import IndicatorPlotter
        from lettrade.plot.plotly import plot_parabolic_sar

        IndicatorPlotter(
            dataframe=dataframe,
            plotter=plot_parabolic_sar,
            **plot_kwargs,
        )

    return result

zero ¤

zero(x: tuple[int, float]) -> tuple[int, float]

If the value is close to zero, then return zero. Otherwise return itself.

Source code in lettrade/indicator/trend/parabolic_sar.py
7
8
9
def zero(x: tuple[int, float]) -> tuple[int, float]:
    """If the value is close to zero, then return zero. Otherwise return itself."""
    return 0 if abs(x) < sflt.epsilon else x