Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supertrend indicator seems to incorrectly change orientation #125

Open
fniko opened this issue Nov 10, 2022 · 4 comments
Open

Supertrend indicator seems to incorrectly change orientation #125

fniko opened this issue Nov 10, 2022 · 4 comments

Comments

@fniko
Copy link
Contributor

fniko commented Nov 10, 2022

Hello,
I have switched my supertrend calculations from pandas_ta and I observe a inconsistency in supertrend values. The issue is (probably) caused by specific candle wicks.

I will continously work the description of this issue, since it's a bit difficult to be to debug or even describe.

Current behaviour

The issue occurs at 08:45 or 08:46. The extreme weird looking candles happens and the supertrend flips for a period of one candle.

  • Dataset: Binance OHCL BTCUSDT
  • Time range: from 2020-09-14 to 2020-09-15 (UTC)
  • ST Multiplier: 2
  • ST Window length: 25
  • Python 3.10
  • Stockstats 0.4.1

Note: I am using an web UI which is displaying only "active" supertrend. This is why is the other line missing from the chart. However I am going to provide charts with both lines, but it's a bit confusing a bit since it's not clear which one is "active".

Code snippet

import pandas as pd
import stockstats

filename = 'binance_btcusdt_ohcl_1m.parquet'
ohcl = pd.read_parquet(filename, engine="fastparquet")
st_a = stockstats.wrap(ohcl.copy())

st_a.SUPERTREND_MUL = 4
st_a.SUPERTREND_WINDOW = 25
st_a = st_a[['supertrend', 'supertrend_ub', 'supertrend_lb']]
# Here I merge the st_a with datetime column generated before the ST calculation
# st_a.insert(1, "datetime", date)
# And renaming columns in order to increase readability
# st_b.rename(columns={'supertrend_ub': 'st_upper', 'supertrend_lb': 'st_lower'}, inplace=True)

Supertrend values (raw)

id datetime st value st upper st lower
611587 2020-09-14 08:40:00  10447.284218  10447.284218  10388.507576
611588 2020-09-14 08:41:00  10447.284218  10447.284218  10388.507576
611589 2020-09-14 08:42:00  10447.284218  10447.284218  10388.507576
611590 2020-09-14 08:43:00  10447.025543  10447.025543  10388.507576
611591 2020-09-14 08:44:00  10447.025543  10447.025543  10388.507576
611592 2020-09-14 08:45:00  10388.507576  10393.494348  10388.507576
611593 2020-09-14 08:46:00  10399.716374  10399.716374  10388.507576
611594 2020-09-14 08:47:00  10399.716374  10399.716374  10293.768281
611595 2020-09-14 08:48:00  10399.716374  10399.716374  10293.768281
611596 2020-09-14 08:49:00  10399.716374  10399.716374  10293.768281
611597 2020-09-14 08:50:00  10399.716374  10399.716374  10293.768281

st_values_raw

OHCL with supertrend (stockstats)
st_stockstats

OHCL with supertrend (pandas_ta)
st_pandas

OHCL with supertrend and both [upper and lowes] values displayed (stockstats)
st_stockstats_both_st

Used data source - binance_btcusdt_ohcl_1m.parquet
I am using Pandas to work with data, loading parquet is very easy - guide - however in case of any issues, I can export data in different format (JSON etc.)
binance_btcusdt_ohcl_1m.parquet.zip

Expected behaviour

I do not think that the supertrend - trend should end (change). I think it should continue since the bull (positive/long) candle did not broke it.

@fniko
Copy link
Contributor Author

fniko commented Nov 11, 2022

I think, I was able to find a solution.

I have adjusted the trend switching logic to watch candle close and last supetrend (lower/upper) value, instead of current. See lines 587+

It's the same logic used in pandas-ta, lines 32+.

Original code

            if last_st == last_ub:
                if curr_close <= ub[i]:
                    st[i] = ub[i]
                else:
                    st[i] = lb[i]
            elif last_st == last_lb:
                if curr_close > lb[i]:
                    st[i] = lb[i]
                else:
                    st[i] = ub[i]

After my adjustment

            if last_st == last_ub:
                if curr_close <= last_ub:
                    st[i] = ub[i]
                else:
                    st[i] = lb[i]
            elif last_st == last_lb:
                if curr_close > last_lb:
                    st[i] = lb[i]
                else:
                    st[i] = ub[i]

@fniko
Copy link
Contributor Author

fniko commented Nov 11, 2022

Okay, I have opened a PR 126 which is implementing the suggested fix.

@fniko
Copy link
Contributor Author

fniko commented Nov 11, 2022

On the other hand, I am still unsure about this. The algorithm mentioned in comment inside the current codebase refers to current candle close, not previous.

# IF PREV.ST > PREV.CLOSE AND CUR.ST < CUR.CLOSE ==> BUY SIGNAL
# IF PREV.ST < PREV.CLOSE AND CUR.ST > CUR.CLOSE ==> SELL SIGNAL

for i in range(len(supertrend)):
        if close[i] > supertrend.iloc[i, 0]:
            upt.append(supertrend.iloc[i, 0])
            dt.append(np.nan)
        elif close[i] < supertrend.iloc[i, 0]:
            upt.append(np.nan)
            dt.append(supertrend.iloc[i, 0])
        else:
            upt.append(np.nan)
            dt.append(np.nan)

Also this code computes is in the similar way.

 #SUPERTREND = IF((Previous SUPERTREND = Previous FINAL UPPERBAND) and (Current Close <= Current FINAL UPPERBAND)) THEN...

# Line 175 -> df[ohlc[3]]
df[st].iat[i] = df['final_ub'].iat[i] if df[st].iat[i - 1] == df['final_ub'].iat[i - 1] and df[ohlc[3]].iat[

Also this strategy on Tradingview uses current price...
Note: Tradingview uses pinescript and when they refer to previous value, they do it like close[1] otherwise than in python close[-1]. So in the snippet below they use current close price and trend values.

# Line 20
trend := trend == -1 and close > dn1 ? 1 : trend == 1 and close < up1 ? -1 : trend

I think, I am missing something....

@jealous
Copy link
Owner

jealous commented Nov 16, 2022

Thanks for opening this issue.
I am not sure about this, either. Maybe both of them are correct. There are just 2 ways to calculate them. Please let me know if you have more clues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants