ta-lib-python icon indicating copy to clipboard operation
ta-lib-python copied to clipboard

bollinger bands are the same for upper, middle and lower

Open KiudLyrl opened this issue 8 years ago • 61 comments

Hi,

I tried to get the bollinger bands, my data are valid since the EMA and RSI are good :

	ta_lib_data = data_table.get_talib_compatible_structure()
	complete_ema20 = talib.abstract.EMA(ta_lib_data, timeperiod=20, price='average')
	complete_ema40 = talib.abstract.EMA(ta_lib_data, timeperiod=40, price='average')
	complete_rsi = talib.abstract.RSI(ta_lib_data, timeperiod=14)
	upperBB, middleBB, lowerBB = talib.BBANDS(ta_lib_data['close'], nbdevup=2, nbdevdn=2, timeperiod=5) #matype=talib.MA_Type.T3

However the upperBB == middleBB == lowerBB here, why is that? I also tried without nbdevup=2, nbdevdn=2.

Thanks.

KiudLyrl avatar Jul 02 '17 22:07 KiudLyrl

Without seeing your test case data, I'm not sure. You can look at the BBANDS source code which might help:

mrjbq7 avatar Jul 02 '17 23:07 mrjbq7

https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_func/ta_BBANDS.c

mrjbq7 avatar Jul 02 '17 23:07 mrjbq7

Here,

Json data + python script that load the json and then compute, ema, rsi and bollinger bands. upper == middle == lower, weird.

https://www.dropbox.com/s/mn70t24t9u3puct/forBB.json?dl=0 https://www.dropbox.com/s/lnkkbqvacw4yz8o/bollinger.py?dl=0

KiudLyrl avatar Jul 03 '17 19:07 KiudLyrl

I have the same issue. I'm dealing with small numbers < .0002 stored in a numpy array, float64. Working in Python 2.7. array([ 0.00018185, 0.00017552, 0.00017599, ..., 0.00017896, 0.00017378, 0.00017192])

mthatcherclark avatar Sep 07 '17 02:09 mthatcherclark

By total coincidence, I just ran into the same exact problem with something I was coding completely separately from talib. While I don't have the skills to code a solution for you, I believe the answer to fixing this bug may be in this thread...https://stackoverflow.com/questions/35906411/list-on-python-appending-always-the-same-value. In other words, it must be an issue with the memory address for each element in the bbands array.

mthatcherclark avatar Sep 08 '17 06:09 mthatcherclark

Hello, iv'e discovered this:

#arr = np.array([0.00282, 0.00242, 0.00202, 0.0028, 0.0019, 0.0021, 0.0030, 0.0040], dtype=float) #this works
#arr = np.array([0.00282011, 0.00242011, 0.00202011, 0.00282011, 0.00192011, 0.00212011, 0.00302011, 0.00402011], dtype=float) this works
arr = np.array([0.000282, 0.000242, 0.000202, 0.00028, 0.00019, 0.00021, 0.00030, 0.00040], dtype=float) #this doesnt. it returns the same numbers for all bands
upper, middle, lower = talib.BBANDS(arr, timeperiod=2, nbdevup=2, nbdevdn=2, matype=0)

So if it's more than three zeroes it doesn't work. Do anyone know what's up then? How do i fix this.

hippylover avatar Sep 11 '17 15:09 hippylover

Probably has something to do with float precision and representing small numbers. If you take your numbers and scale them up by 1000 then it works:

arr = np.array([0.282, 0.242, 0.202, 0.28, 0.19, 0.21, 0.30, 0.40], dtype=float)

mrjbq7 avatar Sep 11 '17 16:09 mrjbq7

I have to scale them up by 100 000 because some of the numbers are 0.00000001. Anyway, won't this mess up the bollinger calculation? (also am i doing this right, and isnt this a bug?)

My attempt:

closehack = np.array([])
for x in close:
	closehack = np.append(close, x * 100000)

upper, middle, lower = talib.BBANDS(closehack, timeperiod=2, nbdevup=2, nbdevdn=2, matype=0)

for x in upper:
	upperhack = np.append(upper, x / 100000)

plt.plot(upperhack)

But that doesn't give correct plot. Please help because i feel i am so close now.

hippylover avatar Sep 11 '17 17:09 hippylover

I'm not sure why you use append instead of just passing close * 100000 and then doing upper / 100000.

mrjbq7 avatar Sep 11 '17 17:09 mrjbq7

Also your code would have he upper array contain two sets of vaues since you don't initialize and "upperhack" the way you do with "closehack".

mrjbq7 avatar Sep 11 '17 17:09 mrjbq7

Yeah that's what i did(the close * 100000 thing) :D sorry, i was a bit tired but i was just about to post that that is what i ended up doing.

I am still wondering if i have to do this kind of acrobatics with other indicators too and if this is considered a bug and will be fixed.

hippylover avatar Sep 11 '17 17:09 hippylover

Ok. So doing the close * 100000 i now end up with numbers like 0.00045050653989108142578184912352412538893986493349 when i do close / 100000 again. Am i supposed to round this up or down or what should i do to get correct numbers?

hippylover avatar Sep 12 '17 18:09 hippylover

You might lose a small amount of precision but I wouldn't think it would be a huge deal. That number has a lot of "apparent" precision but not in actuality I would guess.

mrjbq7 avatar Sep 12 '17 18:09 mrjbq7

Ok. Do you know if this is a limitation of the underlaying ta-lib or is it an issue with the python interface?

hippylover avatar Sep 12 '17 21:09 hippylover

Same problem here, i didn't understand why my strategy doesn't work, after some log i saw values was same...

So i use this before

upperband, middleband, lowerband = ta.BBANDS(close*100000, timeperiod=20, nbdevup=2, nbdevdn=2,matype=0)

upVal =upperband[i]/100000

middleVal = middleband[i]/100000

lowVal =  lowerband[i]/100000

ordimans avatar Sep 18 '17 15:09 ordimans

What assets are you working with that have such low value prices? Are these altcoins? Although it should be doing work on double-precision floating point numbers, it might have some mathematical errors as you are discovering with very small numbers. I haven't spent much time looking at the underlying C code, but you could look it over if you want:

https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_func/ta_BBANDS.c

As far as I'm aware, this lightweight Python wrapper for that underlying TA-Lib C library should not be doing any kind of conversion, and should just be passing through the numpy array of floats into the TA_BBANDS function call.

mrjbq7 avatar Sep 18 '17 17:09 mrjbq7

There's no problem with the library or the wrapper.

from matplotlib.finance import candlestick2_ohlc
import matplotlib.pyplot as plt
import datetime as datetime
import numpy as np
import talib

quotes = np.array([ (1459388100, 29.799999237060547, 29.799999237060547, 29.799999237060547, 29.799999237060547, 148929.0, 450030016.0),
   (1459388400, 29.799999237060547, 29.979999542236328, 29.709999084472656, 29.920000076293945, 10395.0, 31069984.0),
   (1459388700, 29.959999084472656, 30.18000030517578, 29.719999313354492, 30.149999618530273, 38522.0, 114999968.0),
   (1459389000, 30.170000076293945, 30.479999542236328, 30.0, 30.149999618530273, 29823.0, 90220032.0),
   (1459389300, 30.149999618530273, 30.75, 30.1299991607666, 30.549999237060547, 38903.0, 118620032.0),
   (1459389600, 30.59000015258789, 30.93000030517578, 30.559999465942383, 30.65999984741211, 42308.0, 130000000.0),
   (1459389900, 30.6200008392334, 30.690000534057617, 30.3799991607666, 30.3799991607666, 20209.0, 61689984.0),
   (1459390200, 30.3700008392334, 30.489999771118164, 30.18000030517578, 30.18000030517578, 18491.0, 56169984.0),
   (1459390500, 30.190000534057617, 30.329999923706055, 30.010000228881836, 30.010000228881836, 17641.0, 53200000.0),
   (1459390800, 30.030000686645508, 30.399999618530273, 30.030000686645508, 30.280000686645508, 9526.0, 28899968.0),
   (1459391100, 30.299999237060547, 30.31999969482422, 30.200000762939453, 30.209999084472656, 9282.0, 28100096.0),
   (1459391400, 30.190000534057617, 30.280000686645508, 30.049999237060547, 30.1200008392334, 8663.0, 26099968.0),
   (1459391700, 30.110000610351562, 30.110000610351562, 29.959999084472656, 30.100000381469727, 15677.0, 47099904.0),
   (1459392000, 30.1200008392334, 30.260000228881836, 30.0, 30.059999465942383, 5649.0, 17000064.0),
   (1459392300, 30.079999923706055, 30.299999237060547, 30.0, 30.280000686645508, 6057.0, 18199936.0),
   (1459392600, 30.290000915527344, 30.34000015258789, 30.1200008392334, 30.1200008392334, 7914.0, 24000000.0),
   (1459392900, 30.1299991607666, 30.15999984741211, 30.079999923706055, 30.139999389648438, 4521.0, 13600000.0),
   (1459393200, 30.139999389648438, 30.139999389648438, 29.829999923706055, 29.899999618530273, 16255.0, 48600064.0),
   (1459393500, 29.93000030517578, 30.1200008392334, 29.889999389648438, 30.1200008392334, 6877.0, 20600064.0),
   (1459393800, 30.1299991607666, 30.15999984741211, 29.979999542236328, 30.030000686645508, 3803.0, 11499904.0),
   (1459394100, 30.040000915527344, 30.1299991607666, 30.0, 30.030000686645508, 4421.0, 13300096.0),
   (1459394400, 29.989999771118164, 30.389999389648438, 29.989999771118164, 30.389999389648438, 7011.0, 21099904.0),
   (1459394700, 30.399999618530273, 30.450000762939453, 30.270000457763672, 30.299999237060547, 12095.0, 36800000.0),
   (1459395000, 30.34000015258789, 30.450000762939453, 30.280000686645508, 30.43000030517578, 9284.0, 28099968.0),
   (1459400700, 30.510000228881836, 30.729999542236328, 30.5, 30.600000381469727, 17139.0, 52500096.0),
   (1459401000, 30.600000381469727, 30.799999237060547, 30.530000686645508, 30.790000915527344, 11888.0, 36400000.0),
   (1459401300, 30.809999465942383, 31.100000381469727, 30.809999465942383, 31.049999237060547, 30692.0, 95099904.0),
   (1459401600, 31.06999969482422, 31.559999465942383, 30.93000030517578, 31.559999465942383, 24473.0, 76200064.0),
   (1459401900, 31.600000381469727, 31.860000610351562, 31.299999237060547, 31.450000762939453, 34497.0, 109200000.0),
   (1459402200, 31.43000030517578, 31.600000381469727, 31.18000030517578, 31.18000030517578, 18525.0, 58200064.0),
   (1459402500, 31.18000030517578, 31.350000381469727, 31.040000915527344, 31.18000030517578, 10153.0, 31599872.0),
   (1459402800, 31.200000762939453, 31.399999618530273, 31.010000228881836, 31.389999389648438, 9668.0, 30100096.0),
   (1459403100, 31.399999618530273, 31.399999618530273, 31.110000610351562, 31.360000610351562, 8445.0, 26499968.0),
   (1459403400, 31.360000610351562, 31.399999618530273, 31.040000915527344, 31.100000381469727, 9538.0, 29799936.0),
   (1459403700, 31.1200008392334, 31.399999618530273, 31.100000381469727, 31.270000457763672, 7996.0, 25000064.0),
   (1459404000, 31.270000457763672, 31.399999618530273, 31.15999984741211, 31.399999618530273, 6760.0, 21100032.0),
   (1459404300, 31.389999389648438, 32.400001525878906, 31.389999389648438, 32.189998626708984, 26108.0, 83700096.0),
   (1459404600, 32.209999084472656, 32.400001525878906, 31.860000610351562, 32.29999923706055, 15736.0, 50599936.0),
   (1459404900, 32.29999923706055, 32.310001373291016, 31.489999771118164, 31.489999771118164, 12945.0, 41399808.0),
   (1459405200, 31.5, 32.0, 31.40999984741211, 31.81999969482422, 11901.0, 37700096.0),
   (1459405500, 31.809999465942383, 31.940000534057617, 31.719999313354492, 31.770000457763672, 6503.0, 20700160.0),
   (1459405800, 31.760000228881836, 31.790000915527344, 31.399999618530273, 31.790000915527344, 10103.0, 31899904.0),
   (1459406100, 31.780000686645508, 32.029998779296875, 31.780000686645508, 31.850000381469727, 12033.0, 38500096.0),
   (1459406400, 31.809999465942383, 33.310001373291016, 31.809999465942383, 33.029998779296875, 58238.0, 192199936.0),
   (1459406700, 33.029998779296875, 33.310001373291016, 32.79999923706055, 32.79999923706055, 36689.0, 121900032.0),
   (1459407000, 32.79999923706055, 32.869998931884766, 32.61000061035156, 32.70000076293945, 15245.0, 49799936.0),
   (1459407300, 32.68000030517578, 32.689998626708984, 31.799999237060547, 32.0099983215332, 20507.0, 65999872.0),
   (1459407600, 32.02000045776367, 32.02000045776367, 31.760000228881836, 31.799999237060547, 29610.0, 94300160.0)],
   dtype=[('time', '<i4'), ('open', 'd'), ('high', 'd'), ('low', 'd'), ('close', 'd'), ('volume', 'd'), ('amount', 'd')])
   
fig, ax = plt.subplots()
candlestick2_ohlc(ax,quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

xdate = [datetime.datetime.fromtimestamp(i) for i in quotes['time']]

def mydate(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

fig.autofmt_xdate()
fig.tight_layout()

plt.show()

o, h, l, c = quotes['open'], quotes['high'], quotes['low'], quotes['close']

upper, middle, lower = talib.BBANDS(c)

upper[47], middle[47],lower[47]
IN[284}:  upper[47], middle[47],lower[47]
Out[284]: (33.421259371477881, 32.467999267578122, 31.51473916367836)

pcawthron avatar Sep 18 '17 17:09 pcawthron

pcawthron: try that with numbers like 0.0002.

It might have something to do with this in the original lib: USE_SINGLE_PRECISION_INPUT but i don't speak c so that's just a guess.

hippylover avatar Sep 18 '17 18:09 hippylover

@mrjbq7 : It's Altcoin yes. I use numpy : close = np.append(close,r['C'])

with this for example

C | 0.00020201

I must change the precision of array ?

On MACD function, no problem.

ordimans avatar Sep 18 '17 18:09 ordimans

Are you using 64-bit? I think the dtype of your array is probably float which should be double precision on 64-bit.

mrjbq7 avatar Sep 18 '17 19:09 mrjbq7

Just to add, I am having this issue while looping through regular forex values. I loop through the close price on a number of markets (for example EUR-USD, EUR-GBP, GBP-HKD etc etc) calculating the bollinger values. It seems completely random as to when I get the same numbers for upper, middle and lower but what seems certain is that the longer my program is running, the more likely I am to get this error.

I have tried to clear out/delete the dictionary I am holding the values in on each loop - no guarantee of success. I have also tried multiplying/dividing the values as suggested above but again, no luck.

JTInfinite avatar Oct 26 '17 14:10 JTInfinite

Same last value for upper, middle, and lower? Or same all values?

mrjbq7 avatar Oct 26 '17 16:10 mrjbq7

Yeah same value for upper middle and lower. I have since noticed the granularity of the candle information I was requesting was defaulting to 5 seconds (rather than say 30 minutes or 5 minutes). That might have been having an impact but I would expect even on 5 seconds, the upper, middle and lower are different.

With the correct granularity, I am currently getting the correct values.

JTInfinite avatar Oct 26 '17 17:10 JTInfinite

Same problem here. Multiplying the input values 'fixes' the issue... Also ran into the same thing with the RSI indicator. When values are too low (0.00000140-ish), RSi spits out a 0.0

boochos avatar Nov 02 '17 01:11 boochos

@mrjbq7 : Yes i am in 64 Bits. sorry for late answer

ordimans avatar Jan 19 '18 17:01 ordimans

Small values are a result of this feature in the underlying TA-Lib C library:

https://github.com/mrjbq7/ta-lib/issues/157#issuecomment-338589408

mrjbq7 avatar Jan 19 '18 19:01 mrjbq7

Facing the same issue. The following produces three identical arrays for upper, middle and lower on 64 bit Python 2.7.14:

import numpy from talib import func

data = numpy.arange(0.08, 0.081, 0.00001, dtype=float)

bbands = func.BBANDS(data, timeperiod=10, nbdevup=2, nbdevdn=2, matype=0)

cbdite avatar Mar 05 '18 15:03 cbdite

I appreciate the report, but its not an issue I am able to workaround easily in this python wrapper. The underlying C library has a feature around "almost zero" values.

https://github.com/mrjbq7/ta-lib/issues/157#issuecomment-338589408

mrjbq7 avatar Mar 05 '18 16:03 mrjbq7

@mrjbq7 Appreciate your efforts and that your hands are tied in this regard. Without having looked into the underlying C library, it seems strange that it would fail for "almost zero" values of this order of magnitude. I would expect that data sets several orders of magnitude smaller are a common occurrence in the context of bbands.

cbdite avatar Mar 06 '18 09:03 cbdite

Well, the code is the best place to look, which is not exactly easy to read, but...

https://github.com/stoni/ta-lib/blob/master/src/ta_func/ta_BBANDS.c

BBANDS uses STDDEV, which you can see is zero for some "weird" reason:

>>> talib.STDDEV(data)
array([nan, nan, nan, nan,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

And if you look at the code for STDDEV:

https://github.com/stoni/ta-lib/blob/master/src/ta_func/ta_STDDEV.c

You can see that it calls to VAR, which are really small numbers:

>>> talib.VAR(data)
array([           nan,            nan,            nan,            nan,
       2.00000002e-10, 2.00000004e-10, 2.00000003e-10, 2.00000004e-10,
       2.00000003e-10, 2.00000004e-10, 2.00000003e-10, 2.00000003e-10,
       2.00000002e-10, 2.00000002e-10, 2.00000001e-10, 2.00000003e-10,
       2.00000002e-10, 2.00000005e-10, 2.00000002e-10, 2.00000002e-10,
       2.00000003e-10, 2.00000004e-10, 2.00000004e-10, 2.00000003e-10,
       2.00000003e-10, 2.00000005e-10, 2.00000004e-10, 2.00000003e-10,
       2.00000004e-10, 2.00000003e-10, 2.00000003e-10, 2.00000001e-10,
       2.00000002e-10, 2.00000004e-10, 2.00000003e-10, 2.00000003e-10,
       2.00000003e-10, 2.00000003e-10, 2.00000003e-10, 2.00000003e-10,
       2.00000002e-10, 2.00000004e-10, 2.00000001e-10, 2.00000001e-10,
       2.00000000e-10, 2.00000001e-10, 2.00000000e-10, 2.00000001e-10,
       2.00000001e-10, 2.00000004e-10, 2.00000002e-10, 2.00000001e-10,
       2.00000001e-10, 2.00000000e-10, 2.00000001e-10, 2.00000000e-10,
       1.99999999e-10, 2.00000001e-10, 1.99999997e-10, 1.99999997e-10,
       1.99999998e-10, 1.99999998e-10, 1.99999998e-10, 1.99999998e-10,
       1.99999998e-10, 2.00000001e-10, 1.99999998e-10, 1.99999999e-10,
       1.99999998e-10, 1.99999998e-10, 1.99999997e-10, 1.99999997e-10,
       1.99999997e-10, 1.99999999e-10, 1.99999998e-10, 1.99999998e-10,
       1.99999998e-10, 1.99999998e-10, 1.99999997e-10, 1.99999997e-10,
       1.99999997e-10, 1.99999999e-10, 1.99999997e-10, 1.99999997e-10,
       1.99999996e-10, 1.99999997e-10, 1.99999996e-10, 1.99999994e-10,
       1.99999994e-10, 1.99999997e-10, 1.99999995e-10, 1.99999994e-10,
       1.99999994e-10, 1.99999994e-10, 1.99999993e-10, 1.99999994e-10,
       1.99999995e-10, 1.99999997e-10, 1.99999995e-10, 1.99999995e-10,
       1.99999996e-10])

And if you look further at the code in ta_STDDEV.c, you can see this:

      for( i=0; i < (int)VALUE_HANDLE_DEREF(outNBElement); i++ )
      {
         tempReal = outReal[i];
         if( !TA_IS_ZERO_OR_NEG(tempReal) )
            outReal[i] = std_sqrt(tempReal);
         else
            outReal[i] = (double)0.0;
      }

So, if you look at the definition of TA_IS_ZERO_OR_NEG, you can see where the "small numbers" issue comes up:

ta_func/ta_utility.h
259:#define TA_IS_ZERO_OR_NEG(v) (v<0.00000001)

So, basically your numbers are all really close together in a way that the underlying C library thinks is too small precision (for some reason that I don't know since I've never talked to the author, maybe they had to work with small precision floats or something).

Your workaround is probably to either change TA_IS_ZERO_OR_NEG and recompile the underlying library, or fudge your data up and then down:

import numpy
import talib

data = numpy.arange(0.08, 0.081, 0.00001, dtype=float)

bbands = talib.BBANDS(data * 1000, timeperiod=10, nbdevup=2, nbdevdn=2, matype=0)
bbands = [b / 1000 for b in bbands]

I'm not sure if there's anything else I can or should be doing here... sorry!

mrjbq7 avatar Mar 06 '18 15:03 mrjbq7