Calculate binance ATR in python with binance connector

143 views Asked by At

I'm using the binance connector API in python (https://binance-connector.readthedocs.io/en/latest/getting_started.html) and I want to build a function that computes the ATR of the previous candle (not the current one) based on a given length. I'm using the candlestick data format provided by the API: https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data. This is the code:

def tr(prices: list[list], length: int) -> list[float]:
    prices = prices[len(prices)-length-1:]
    tr_list: list[float] = []

    for i in range(1, len(prices)):
        high = float(prices[i][2])
        low = float(prices[i][3])
        close = float(prices[i-1][4])

        current_true_range = max(
            (high - low),
            abs(high - close),
            abs(low - close),
        )

        tr_list.append(current_true_range)

    return tr_list

def atr(prices: list[list], length: int) -> float:
    tr_values = tr(prices, length)
    return sum(tr_values) / len(tr_values)

this is how I get the klines:

self.binance_api_client.klines(symbol=self.trading_symbol, interval=self.klines_interval, limit=self.klines_limit_length)

I don't use the last kline because it's never complete yet, I only use the previous closed klines (that's why I use [:-1]):

atr = technical_indicators.atr(klines[:-1], 14)

However, I still don't get the right value and the error is significant, what am I doing wrong ? (self.klines_limit_length is, in this context, 200).

I've made sure that the interval is the same and I'm sure that I get the right data.


UPDATE:

When I call the supertrend function I always pass in the klines without the last candle (since it's not closed yet) so I don't have to think about not taking into consideration the values of the last candlestick when calculating the tr/atr. I now know that I am getting the right prices in the tr function, the problem that I have now is that, for some reason, the supertrend is still wrong.

This is all the code:

def tr(prices: list[list], length: int) -> list[float]:
    prices = prices[-length:]
    tr_list: list[float] = []

    for i in range(1, len(prices)):
        high = float(prices[i][2])
        low = float(prices[i][3])
        close = float(prices[i-1][4])

        current_true_range = max(
            (high - low),
            abs(high - close),
            abs(low - close),
        )

        tr_list.append(current_true_range)

    return tr_list

def atr(prices: list[list], length: int) -> float:
    tr_values = tr(prices, length)
    return sum(tr_values) / len(tr_values)


def supertrend(prices: list[list], length: int, multiplier: float) -> float:
    high = float(prices[-1][2])
    low = float(prices[-1][3])
    atr_value = atr(prices, length)

    supertrend = (low + high) / 2 + multiplier * atr_value
    return supertrend

I already exclude the last price when calling the supertrend:

supertrend = technical_indicators.supertrend(klines[:-1], 20, 2)

The klines have always at least 200 prices, so the length of 20 is not a problem.

1

There are 1 answers

4
anarchy On

I think you are slicing wrongly, I don't have access to the binance api but can you change this line.

prices[-length-1:-1] instead of prices[len(prices)-length-1:]

That way you will get the latest prices at the end of the array instead.

If this doesn't work you need to check if the bars that you are getting are correct. Maybe you could paste the result of the most recent bars you have and I can work on it from there.