TA-Lib / ta-lib-python

Python wrapper for TA-Lib (http://ta-lib.org/).
http://ta-lib.github.io/ta-lib-python
Other
9.49k stars 1.74k forks source link

Different values (TradingView/Binance, ta-lib) #469

Closed tratteo closed 2 years ago

tratteo commented 2 years ago

I am getting substantially different values from ta-lib with respect to both Binance and Trading view. All three indicators: STOCH, RSI, MACD return different values. Sometimes the difference is negligible, other times it goes as high as 10 points for the stochastic. What is causing this? Code for reference

import websocket, json, pprint, talib, numpy
import config
from binance.client import Client
from binance.enums import *
import time

SOCKET = "wss://stream.binance.com:9443/ws/ethusdt@kline_1m"
RSI_PERIOD = 14
TRADE_SYMBOL = 'ETHUSDT'
TRADE_QUANTITY = 0.005

macds = []
closes = []
highs = []
lows = []

is_long = False
client = Client(config.API_KEY, config.API_SECRET)
current_timestamp = round(time.time() * 1000)
print(current_timestamp)
val = current_timestamp - (200 * 60000)
hist = client.get_historical_klines(TRADE_SYMBOL, '1m', val, None, 200, HistoricalKlinesType.SPOT)

for a in hist:
    closes.append(float(a[4]))
    highs.append(float(a[2]))
    lows.append(float(a[3]))

def on_open(ws):
    print('opened connection')

def on_close(ws):
    print('closed connection')

def on_message_event(ws, message):
    json_message = json.loads(message)
    # pprint.pprint(json_message)
    candle = json_message['k']

    is_candle_closed = candle['x']
    close = candle['c']
    if is_candle_closed:
        print("candle closed at {}".format(candle))
        closes.append(float(close))
        highs.append(float(candle['h']))
        lows.append(float(candle['l']))
        np_closes = numpy.array(closes)
        macd, signal, hist = talib.MACD(np_closes)
        rsi = talib.RSI(np_closes, RSI_PERIOD)
        stoch_k, stoch_d = talib.STOCH(numpy.array(highs), numpy.array(lows), np_closes, fastk_period=14,
                                       slowk_period=1,
                                       slowd_period=3, slowk_matype=0, slowd_matype=0)
        print("Stochastic: [k, d] > [" + str(stoch_k[-1]) + ", " + str(stoch_d[-1]) + "]")
        print("RSI: " + str(rsi[-1]))
        print("MACD: [macd, sig] > [" + str(macd[-1]) + ", " + str(signal[-1]) + "]")

        # print("checking")
        # can = can_long(rsi, [macd, signal], [stoch_k, stoch_d])
        # if can:
        #     print("Long entered")

ws = websocket.WebSocketApp(SOCKET, on_open=on_open, on_close=on_close, on_message=on_message_event)
ws.run_forever()
trufanov-nok commented 2 years ago

Imho, These are moving averages and they having "a memory". Their values today depends on what happened yesterday and so on. If you start one such moving average calculation since beginning of the year, and another (same function) will be calculated since the beginning of the month - you'll get the different results for today, depending on the size of moving window and how important is the past (weights of smoothing). Thus your function values will be different in a short term, but must converge in a long term. The question is: when TradingView/Binance have started their MACD etc. calculation? Start from the same point of historical data and then compare the results to minimize the influence of the memory. Or wait long enough to let your function results converge to their functions results.

mrjbq7 commented 2 years ago

That’s typically the reason, another one might be use of different moving average types. TA-Lib supports 7 or 8 and many functions take that as a parameter.

On Oct 9, 2021, at 9:11 AM, Alexander Trufanov @.***> wrote:

 Imho, These are moving averages and they having "a memory". Their values today depends on what happened yesterday and so on. If you start one such moving average calculation since beginning of the year, and another (same function) will be calculated since the beginning of the month - you'll get the different results for today, depending on the size of moving window and how important is the past (weights of smoothing). Thus your function values will be different in a short term, but must converge in a long term. The question is: when TradingView/Binance have started their MACD etc. calculation? Start from the same point of historical data and then compare the results to minimize the influence of the memory. Or wait long enough to let your function results converge to their functions results.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android.

tratteo commented 2 years ago

Thanks for the replies. It probably is simple a lack in my knowledge, however, if i set a certain period P for a certain indicator on Binance/TradingView, in a selected time frame, doesn't it mean that the indicator is calculated on that time frame using the last P candles? So if i set the same period P for the indicator and i calculate it over the same time frame in ta-lib, shouldn't they necessarily be the same? Where does the "memory" come from if i am using the period P and the indicator is calculated only by using the last P candles?

trufanov-nok commented 2 years ago

Where does the "memory" come from

"memory" appears if your indicator uses it's own previous value for calculation. Like EMA:

EMA_Today=(Value_Today∗(Smoothing1+Days))+EMA_Yesterday∗(1−(Smoothing1+Days))

There is a good article that compares EMA and SMA (which is just a moving average like you would expect): https://www.investopedia.com/terms/e/ema.asp

And the MACD is "The MACD is calculated by subtracting the 26-period exponential moving average (EMA) from the 12-period EMA. (https://www.investopedia.com/terms/m/macd.asp)

The RSI formula can be found here: https://www.investopedia.com/terms/r/rsi.asp I guess memory come from "previous average gain" in RSI_step_two description.

And it seems STOCH is the one here who has no memory effect: https://www.investopedia.com/terms/s/stochasticoscillator.asp So you may doublecheck the STOCH

tratteo commented 2 years ago

Got it, however the stoch is the one that ouputs the most different values

trufanov-nok commented 2 years ago

I am getting substantially different values from ta-lib with respect to both Binance and Trading view.

Are you sure they are displaying STOCH and not STOCHRSI? I couldn't find STOCH on Binance. TA-Lib has STOCHRSI indicator too. Perhaps you should use it instead of STOCH.

mrjbq7 commented 2 years ago

I think it uses a moving average of period P with longer history in the calculation.

On Oct 10, 2021, at 4:16 AM, Matteo Beltrame @.***> wrote:

 Thanks for the replies. It probably is simple a lack in my knowledge, however, if i set a certain period P for a certain indicator on Binance/TradingView, in a selected time frame, doesn't it mean that the indicator is calculated on that time frame using the last P candles? So if i set the same period P for the indicator and i calculate it over the same time frame in ta-lib, shouldn't they necessarily be the same? Where does the "memory" come from if i am using the period P and the indicator is calculated only by using the last P candles?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android.

tratteo commented 2 years ago

I am getting substantially different values from ta-lib with respect to both Binance and Trading view.

Are you sure they are displaying STOCH and not STOCHRSI? I couldn't find STOCH on Binance. TA-Lib has STOCHRSI indicator too. Perhaps you should use it instead of STOCH.

Well yes both on Binance and Trading view there are both the stochastic and the stochastic RSI, they have different values and ta-lib too has STOCH and STOCHRSI

trufanov-nok commented 2 years ago

I've registered on Binance, opened any graphic, selected settings of currently displayed indicator and able to see only:

MA EMA WMA BOLL VWAP AVL TRIX SAR 
Sub (1/5)
VOL MACD RSI KDJ OBV CCI StochRSI WR DMI MTM EMV

And no STOCH...

tratteo commented 2 years ago

The chart must be in Trading View mode, on the top right corner of the chart

trufanov-nok commented 2 years ago

The chart must be in Trading View mode, on the top right corner of the chart

Got it! So there is only one technical indicator to compare after all - the one that is built in by TradingView and shown by Binance. I'm comparing the 1m graphical data from https://www.binance.com/en/futures/ETHUSDT And the data I'm getting with the code:

import json
import numpy
import talib
import websocket

# *******PARAMETERS
# Name of Socket for BTC in USDT 1min Candle
SOCKET = "wss://stream.binance.com:9443/ws/ethusdt@kline_1m"
# Arrays
closes = []
highs = []
lows = []

def on_open_ws(ws):
    print('opened connection')

def on_close_ws(ws):
    print('closed connection')

def on_message_ws(ws, message):
    json_message = json.loads(message)
    # pprint.pprint(json_message)
    candle = json_message['k']

    is_candle_closed = candle['x']
    close = candle['c']
    if is_candle_closed:
        print("candle closed at {}".format(candle))
        closes.append(float(close))
        highs.append(float(candle['h']))
        lows.append(float(candle['l']))
        np_closes = numpy.array(closes)
        stoch_k, stoch_d = talib.STOCH(numpy.array(highs), numpy.array(lows), np_closes, fastk_period=14,
                                       slowk_period=1,
                                       slowd_period=3, slowk_matype=0, slowd_matype=0)
        print("Stochastic: [k, d] > [" + str(stoch_k[-1]) + ", " + str(stoch_d[-1]) + "]")

ws = websocket.WebSocketApp(SOCKET, on_open=on_open_ws, on_close=on_close_ws, on_message=on_message_ws)
ws.run_forever()

I'm observing STOCH mismatch, but I've also noticed that candle data mismatches too. Like I see 'c': '3606.60000000' for a latest candle while 3604.90 is on the trading view... Am I missing something? Could you reproduce that?

tratteo commented 2 years ago

You are checking the Binance futures while the code is running on Spot. Compare the code with the chart at: ETHUSDT. With this comparison i am getting a maximum error between the code and the chart of 0.2, in the closing price. I think that is neglegible. At this point having a maximum error of 0.2 (on multiple candles), why indicators are so different? (STOCH go as high as 10 points error, that is 10% error). And not only the STOCH, also the RSI and MACD.

trufanov-nok commented 2 years ago

If you wait 40 min and compare STOCH again, wouldn't it be pretty same? It looks like mine is converged to the one on graphic. If it is so, I could dig into the code to try to explain this behavior.

tratteo commented 2 years ago

I also noticed that it tends to converge to the right values. However, i am asking myself why is that? I still don't understand as the indicators just depends on N previous candles, with N the max of the periods. How come that the values are so different? The only thing that comes to mind is that Binance indeed does some weird smoothing under the hood.

trufanov-nok commented 2 years ago

Binance indeed does some weird smoothing under the hood.

I doubt so )

Could you execute following?:

import talib
talib.__ta_version__

from talib import abstract
stoch =  abstract.Function('stoch')
stoch.set_parameters(fastk_period=14, slowk_period=1, slowd_period=3, slowk_matype=0, slowd_matype=0)
stoch.lookback

I wonder which talib sources is under the hood of your wrapper and what lookback value it return.

tratteo commented 2 years ago

Version: b'0.4.0 (Sep 29 2020 17:46:20) Stoch.lookback: 15

mrjbq7 commented 2 years ago

STOCH uses EMA which has a history, so of course it will converge over time, but be different if only considering "period" data points...

trufanov-nok commented 2 years ago

STOCH uses EMA which has a history, so of course it will converge over time, but be different if only considering "period" data points...

No, it's using lowk_matype=0, slowd_matype=0 which is SMA: https://sourceforge.net/p/ta-lib-git/code/ci/master/tree/ta-lib/c/include/ta_defs.h#l262. I've debugged the indicator step-by step on C side. I also run a few tests and now 100% sure STOCH with lowk_matype=0, slowd_matype=0 has no memory.

I finally found a setting that displays stoch arguments on binance graph - they are same: 14, 1, 3. Then I manually entered some data from the graph (13.10.2021 11:50 UTC - 12.05 UTC):

open  = [3459.47 , 3461.88 , 3459.25 , 3464.28 , 3466.38 , 3465.23 , 3466.79 , 3466.57 , 3467.91 , 3465.93 , 3468.67 , 3465.66 , 3469.43 , 3463.93 , 3469.36 , 3466.84]
high  = [3461.89 , 3462.03 , 3464.15 , 3467.94 , 3467.62 , 3466.80 , 3467.83 , 3468.48 , 3468.31 , 3469.04 , 3469.20 , 3472.76 , 3469.85 , 3469.67 , 3470.01 , 3470.00]
low   = [3458.76 , 3458.97 , 3457.69 , 3464.03 , 3464.55 , 3462.78 , 3466.11 , 3466.01 , 3465.55 , 3465.64 , 3464.32 , 3465.58 , 3462.65 , 3461.33 , 3466.82 , 3466.84]
close = [3461.89 , 3459.25 , 3463.76 , 3466.51 , 3465.32 , 3466.79 , 3466.57 , 3467.98 , 3465.83 , 3468.68 , 3465.65 , 3469.43 , 3463.93 , 3469.35 , 3466.82 , 3467.95]

stoch_k, stoch_d = talib.STOCH(numpy.array(high), numpy.array(low), numpy.array(close), fastk_period=14, slowk_period=1, slowd_period=3, slowk_matype=0, slowd_matype=0)

stoch_k is

array([        nan,         nan,         nan,         nan,         nan,
               nan,         nan,         nan,         nan,         nan,
               nan,         nan,         nan,         nan,         nan,
       68.08228268])

stoch_d is

array([        nan,         nan,         nan,         nan,         nan,
               nan,         nan,         nan,         nan,         nan,
               nan,         nan,         nan,         nan,         nan,
       68.67949569])

While the graph displays 68.0823 68.6795.

So the STOCH indicator is calculated correctly and it's exactly the same as Binance use. One may try himself with data after 12.05 UTC or another piece of data. Tips: write down only last 4 digits and add 3400 to them later. I also didn't notice that I don't need open prices from the beginning.

So, everything is fine with Binance and the indicator. The differences might be caused by incoming data fluctuations, or probably I don't see some problem in the python code (I'm not a python developer after all).

mrjbq7 commented 2 years ago

Thats a very good background and investigation, thank you @trufanov-nok

DILIPSKUMAR1410 commented 2 years ago

Any luck here ? Mine RSI value coming different from binance

import numpy import redis import tulipy as ti from talib import stream import time r = redis.StrictRedis( host='localhost', port=6379, connection_pool=None, db=0, decode_responses=True)

while True: candles = r.lrange("FETUSDT", -15, -1) y = [] for candle in candles: y.append(float(candle.split(',')[3]))

if len(y) > 0
    y = numpy.array(y)
    latest = stream.RSI(y)

    print("FETUSDT",latest)
time.sleep(2)
Screenshot 2021-11-13 at 11 07 13 PM Screenshot 2021-11-13 at 11 07 28 PM
DILIPSKUMAR1410 commented 2 years ago

Any luck here ? Mine RSI value coming different from binance

import numpy import redis import tulipy as ti from talib import stream import time r = redis.StrictRedis( host='localhost', port=6379, connection_pool=None, db=0, decode_responses=True)

while True: candles = r.lrange("FETUSDT", -15, -1) y = [] for candle in candles: y.append(float(candle.split(',')[3]))

if len(y) > 0
  y = numpy.array(y)
  latest = stream.RSI(y)

  print("FETUSDT",latest)
time.sleep(2)
Screenshot 2021-11-13 at 11 07 13 PM Screenshot 2021-11-13 at 11 07 28 PM

Any luck here?