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

Examples of Candlestick Pattern Recognition #74

Open
greencoder opened this issue Jan 21, 2015 · 34 comments
Open

Examples of Candlestick Pattern Recognition #74

greencoder opened this issue Jan 21, 2015 · 34 comments

Comments

@greencoder
Copy link

Do you know of any examples of using this library to do Candlestick Pattern Recognition? I'm struggling a bit trying to get started - I've got plenty of OHLCV data but I'm not sure how to use it here.

I'd be happy to help contribute working examples to this project's wiki if someone could help me get going.

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jan 21, 2015

There are quite a number of candlestick pattern recognition methods available, you can see a list here:

>>> import talib
>>> talib.get_function_groups()['Pattern Recognition']

Each one has some documentation available on how to call it, for example:

In [2]: ?talib.CDLTRISTAR
Type:        builtin_function_or_method
String form: <built-in function CDLTRISTAR>
Docstring:
CDLTRISTAR(open, high, low, close)

Tristar Pattern (Pattern Recognition)

Inputs:
    prices: ['open', 'high', 'low', 'close']
Outputs:
    integer (values are -100, 0 or 100)

I have not used these that much, but zero typically represents no-pattern, and positive and negative values represent that the pattern is observed at that point in the data.

It would be great to make a few test cases or examples showing a particular pattern and have it be detected by calling the relevant talib function!

@greencoder
Copy link
Author

Thanks @mrjbq7 for your help with this. Through a bit of fumbling with this example, I was able to figure out it's expecting a numpy ndarray, though I'm not familiar with numpy and obviously have a lot to learn.

This is a good example of how the actual usage eludes the beginner and where examples would help a lot.

The candlestick pattern recognition functions seem to take the same inputs, so if I can figure it out for this one, I should be apple to apply it to all.

import talib
import numpy 

sample_data = [
  ['Mon', 20, 28, 38, 45],
  ['Tue', 31, 38, 39, 50],
  ['Wed', 50, 55, 56, 62],
  ['Thu', 77, 70, 71, 60],
  ['Fri', 68, 66, 22, 15],
 ]

 # Not sure how to turn my sample data into a ndarray
 my_ndarray = numpy.ndarray(?)

 talib.CDLTRISTAR(my_ndarray)

I realize this is a question better suited for Stack Overflow, and I'll bring further questions there. If anyone can help me construct the numpy.ndarray for this trivial little example, perhaps it will help someone in the future.

I'll be happy to create further examples for the wiki if I can figure this out!

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jan 22, 2015

Ahh, I see your issue has to do with how to deal with the open, high, low, close values.

So, numpy.ndarray works a bit like a list, except it's usually typed values (meaning a list of 64-bit floats, or 32-bit integers, etc.). You can either do:

  1. Format the data initially the way talib expects:
import talib
import numpy

dates = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
open = [20, 31, 50, 77, 68]
high = [28, 38, 55, 70, 66]
low = [38, 39, 56, 71, 22]
close = [45, 50, 62, 60, 15]

# either start with numpy.ndarray, or convert to it like this
# (making sure to specify the ``dtype`` (or "data type") is
# 64-bit floating point which is what ``talib`` expects):
open = numpy.array(open, dtype=float)
high = numpy.array(high, dtype=float)
low = numpy.array(low, dtype=float)
close = numpy.array(close, dtype=float)

talib.CDLTRISTAR(open, high, low, close)
  1. Take your data like it is (as rows of observations), which is often how data comes back from CSV files or from Yahoo! Finance, etc. and convert to columns of data.
import talib
import numpy

sample_data = [
  ['Mon', 20, 28, 38, 45],
  ['Tue', 31, 38, 39, 50],
  ['Wed', 50, 55, 56, 62],
  ['Thu', 77, 70, 71, 60],
  ['Fri', 68, 66, 22, 15],
 ]

# convert data to columns
sample_data = numpy.column_stack(sample_data)

# extract the columns we need, making sure to make them 64-bit floats
open = sample_data[1].astype(float)
high = sample_data[2].astype(float)
low = sample_data[3].astype(float)
close = sample_data[4].astype(float)

talib.CDLTRISTAR(open, high, low, close)
  1. Other methods could include using pandas which has nice support for working with data.
import talib
import numpy
import pandas

sample_data = [
  ['Mon', 20, 28, 38, 45],
  ['Tue', 31, 38, 39, 50],
  ['Wed', 50, 55, 56, 62],
  ['Thu', 77, 70, 71, 60],
  ['Fri', 68, 66, 22, 15],
 ]

sample_data = pandas.DataFrame(sample_data,
                               columns=["Day","Open","High","Low","Close"])

open = sample_data['Open']
high = sample_data['High']
low = sample_data['Low']
close = sample_data['Close']

talib.CDLTRISTAR(open, high, low, close)

As an aside, it is fairly common to see people abbreviate when working with numpy and pandas, for example:

import numpy as np
np.array([1,2,3,4])

import pandas as pd
pd.DataFrame([[1,2],[3,4]])

I've even see people do the same with import talib as ta. I think thats maybe a bit much, but it does tend to make the code more readable when you are calling a lot of numpy functions. I've also seen used shorthand o, h, l, c for the open, high, low, close variables. It's mostly an aesthetic thing and there is no universal right answer so play around and see what works for you.

@greencoder
Copy link
Author

@mrjbq7 First, thank you so much for taking the time to explain this so clearly. Your help is appreciated greatly.

I made a contrived example to test. I ran the number in Excel and produced a graph that looks like a Tristar pattern: http://cl.ly/image/3w1D0u1Y3O1O

Here's the code:

import talib
import numpy

sample_data = [
    ['1/22/14', 10, 18,  5, 20],
    ['1/23/14', 12, 21,  7, 22],
    ['1/24/14', 14, 24, 9 , 24],
    ['1/25/14', 16, 27, 11, 26],
    ['1/26/14', 18, 30, 13, 28],
    ['1/27/14', 20, 33, 15, 30],
    ['1/28/14', 22, 36, 17, 32],
    ['1/29/14', 24, 39, 19, 34],
    ['1/30/14', 26, 41, 21, 38],
    ['1/31/14', 30, 45, 25, 40],
    ['2/01/14', 43, 44, 42, 43],
    ['2/02/14', 46, 47, 45, 46],
    ['2/03/14', 44, 45, 43, 44],
    ['2/04/14', 40, 55, 35, 50],
]

# convert data to columns
sample_data = numpy.column_stack(sample_data)

# extract the columns we need, making sure to make them 64-bit floats
open = sample_data[1].astype(float)
high = sample_data[2].astype(float)
low = sample_data[3].astype(float)
close = sample_data[4].astype(float)

print talib.CDLTRISTAR(open, high, low, close)

The output is:

[   0    0    0    0    0    0    0    0    0    0    0    0 -100    0]

It looks like my sample data produced a result, though I'm not clear on what +100 vs -100 is?

@pcawthron
Copy link

@greencoder The -100 denotes a bearish Tristar pattern where the middle candle body is above the other two. Conversely +100 denotes a bullish Tristar pattern where the middle body is below the adjacent ones.

This is some TA-Lib source code from ta_CDLTRISTAR.c :

/* Proceed with the calculation for the requested range.
    * Must have:
    * - 3 consecutive doji days
    * - the second doji is a star
    * The meaning of "doji" is specified with TA_SetCandleSettings
    * outInteger is positive (1 to 100) when bullish or negative (-1 to -100) when bearish
    */
   i = startIdx;
   outIdx = 0;
   do
   {
        if( TA_REALBODY(i-2) <= TA_CANDLEAVERAGE( BodyDoji, BodyPeriodTotal, i-2 ) &&    // 1st: doji
            TA_REALBODY(i-1) <= TA_CANDLEAVERAGE( BodyDoji, BodyPeriodTotal, i-2 ) &&    // 2nd: doji
            TA_REALBODY(i) <= TA_CANDLEAVERAGE( BodyDoji, BodyPeriodTotal, i-2 ) ) {     // 3rd: doji
            outInteger[outIdx] = 0;
            if ( TA_REALBODYGAPUP(i-1,i-2)                                                  // 2nd gaps up
                 &&
                 max(inOpen[i],inClose[i]) < max(inOpen[i-1],inClose[i-1])                  // 3rd is not higher than 2nd
               )
                outInteger[outIdx] = -100;
            if ( TA_REALBODYGAPDOWN(i-1,i-2)                                                // 2nd gaps down
                 &&
                 min(inOpen[i],inClose[i]) > min(inOpen[i-1],inClose[i-1])                  // 3rd is not lower than 2nd
               )
                outInteger[outIdx] = +100;
            outIdx++;
        }
        else
            outInteger[outIdx++] = 0;
        /* add the current range and subtract the first range: this is done after the pattern recognition 
         * when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
         */
        BodyPeriodTotal += TA_CANDLERANGE( BodyDoji, i-2 ) - TA_CANDLERANGE( BodyDoji, BodyTrailingIdx );
        i++;
        BodyTrailingIdx++;
   } while( i <= endIdx );

@greencoder
Copy link
Author

Thanks, @pcawthron! In general, are negative values bearish and positive values bullish for the candlestick recognition functions?

@pcawthron
Copy link

@greencoder As far as I know, yes, but it's best to check the source code. In my limited experience I've only ever seen -100, 0 and +100 so I'm not sure why the source talks of -1 to -100 and +1 to +100.

@greencoder
Copy link
Author

@mrjbq7 I'm trying to create a few samples we can use for showing people how to use the pattern recognition functions as you and @pcawthron taught me above.

Given this program:

import talib
import numpy

original_data = [
    ['1/22/14', 10, 18,  5, 20],
    ['1/23/14', 12, 21,  7, 22],
    ['1/24/14', 14, 24, 9 , 24],
    ['1/25/14', 16, 27, 11, 26],
    ['1/26/14', 18, 30, 13, 28],
    ['1/27/14', 20, 33, 15, 30],
    ['1/28/14', 22, 36, 17, 32],
    ['1/29/14', 24, 39, 19, 34],
    ['1/30/14', 26, 41, 21, 38],
    ['1/31/14', 30, 45, 25, 40],
    ['2/01/14', 43, 44, 42, 43],
    ['2/02/14', 46, 47, 45, 46],
    ['2/03/14', 44, 45, 43, 44],
    ['2/04/14', 40, 55, 35, 50],
]

# convert data to columns
columnar_data = numpy.column_stack(original_data)

# extract the columns we need, making sure to make them 64-bit floats
dates = columnar_data[0].astype(str)
open = columnar_data[1].astype(float)
high = columnar_data[2].astype(float)
low = columnar_data[3].astype(float)
close = columnar_data[4].astype(float)

result = talib.CDLTRISTAR(open, high, low, close)
print result

It produces this output:

[   0    0    0    0    0    0    0    0    0    0    0    0 -100    0]

This is the first time I've ever worked with Numpy and I'd like to make sure that how I'm using the result is correct and elegant.

To identify the day in the result, I'm doing this:

if -100 in values:
    result_index = values.tolist().index(-100)
    print "Identified bearish Tristar pattern at %s" % original_data[result_index][0]

This works, but I'm not sure if there is a more elegant way to do this. (there probably is)

Specifically:

  1. Is there a better way to find non-zero values in a numpy array than to convert it to a Python list?
  2. If so, perhaps I could correlate it to a value in the dates Numpy array I created?

Once I get this worked out, I'd like to put an example using Yahoo data in the project wiki.

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Mar 1, 2015

Regarding your question, non-zero values can be found several ways.

In [1]: import numpy as np

In [2]: a = np.array([0,0,100,-100,0,0])

In [3]: np.nonzero(a)
Out[3]: (array([2, 3]),)

In [4]: np.where(a != 0)
Out[4]: (array([2, 3]),)

@hasakura511
Copy link

mrjbq7,

thank you for the ta-lib contribution. For the CDLHIKKAKE function, I am getting some 200 & -200 output on my price series.

test = ta.CDLHIKKAKE(open,high,low,close)

for x in test.nonzero():
print test[x]

[ 100 200 -100 -200 -100 -100 -200 -100 100 200 100 -100 100 -100 -200...

according to the help, it says 200/-200 is not an valid output.

Docstring:
CDLHIKKAKE(open, high, low, close)

Hikkake Pattern (Pattern Recognition)

Inputs:
prices: ['open', 'high', 'low', 'close']
Outputs:
integer (values are -100, 0 or 100)
Type: builtin_function_or_method

Should I assume that -200/200 to be 100's?

Thank you

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Nov 10, 2015

200/-200 is a little strange. I'd have to look at the underling libta_lib library code to see what it is doing...

@exquest
Copy link

exquest commented Apr 30, 2016

How do you access the documentation for each function?

@mrjbq7
Copy link
Collaborator

mrjbq7 commented May 1, 2016

What documentation are you looking for?

You can look at general documentation for various indicators: http://tadoc.org/.

You could also look at the underlying C source code of ta-lib: https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_func/

etc.

@exquest
Copy link

exquest commented May 1, 2016

I was looking for the python function documentation. I found it here:

https://mrjbq7.github.io/ta-lib/funcs.html

Thanks

@mrjbq7
Copy link
Collaborator

mrjbq7 commented May 1, 2016

You can also use help from the Python console to see what arguments a function takes and its default values.

@neerajgupta2407
Copy link

neerajgupta2407 commented Apr 9, 2017

@mrjbq7 HI, I want to validate the results.
Now for sampling, i am feeding the dummy data for MARUBOZU pattern which is very simple but still function is returning as 0. Please explain what i am missing??

Sample Data:
	# open, high, low, close
	[10,20,10,20]


import talib
import numpy

sample_data = [
	# open, high, low, close
	[10,20,10,20]
]
sample_data = numpy.column_stack(sample_data)
open = sample_data[0].astype(float)
high = sample_data[1].astype(float)
low = sample_data[2].astype(float)
close = sample_data[3].astype(float)

talib.CDLMARUBOZU(open, high, low, close)

It is returning array([0], dtype=int32), whereas data feeded is for pattern MARUBOZU.
How can i verify the results ??

@KabeerSinghBedi
Copy link

@mrjbq7 the issue with the talib-Pattern recognition is determining more than one candlestick type for a single type of ohlc value. Is their any way to solve this issue?? Can u please help
image

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jun 30, 2017

I don't understand the problem you are having @KabeerSinghBedi.

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jun 30, 2017

@neerajgupta2407 The pattern might not trigger because all the candle open=high=low=close and maybe it needs candle bodies or something to trigger. You can look at the code for the C library and see what logic it uses.

@KabeerSinghBedi
Copy link

@mrjbq7 as u can see in the image for a particular set of Ohlc it should determine it as single candle stick type but it is determining more than one type for in my case it's highwave and spinning top.
image

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jun 30, 2017

Why can't multiple candlestick patterns trigger on the same tick of the market?

@KabeerSinghBedi
Copy link

KabeerSinghBedi commented Jun 30, 2017 via email

@KabeerSinghBedi
Copy link

But in that case each candle stick has a different meaning so how can at a particular tick we can have different meanings.

@KabeerSinghBedi
Copy link

If i'm making changes in the ta_global.c file how to see that this changes are because if i'm changing the candle settings i'm not able to see the changes in pattern recognition method.

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jun 30, 2017

I don't see why more than one candlestick pattern might be recognized on the addition of a new candle. Are the two you observed inconsistent?

What changes are you making to ta_global.c? That's not something I can help you troubleshoot without access to what you are doing and not likely to have time to do so.

@MattinAhmed
Copy link

Hi..
Could someone please let me know about detecting candlestick patterns
To detect a candle-stick pattern in the stock data, do I need to have my data in my numpy array in ascending order with respect to dates(oldest to newest dates) or
the other way round.

for example
lets say my date is
sample_data = [
['2/5/2012', 20, 28, 38, 45],
['3/5/2012', 31, 38, 39, 50],
['4/5/2012', 50, 55, 56, 62],
['5/5/2012', 77, 70, 71, 60],
['6/5/2012', 68, 66, 22, 15],
]

convert data to columns

sample_data = numpy.column_stack(sample_data)

extract the columns we need, making sure to make them 64-bit floats

open = sample_data[1].astype(float)
high = sample_data[2].astype(float)
low = sample_data[3].astype(float)
close = sample_data[4].astype(float)

talib.CDLTRISTAR(open, high, low, close)

OR
Should i have my data in form of date from newest to oldest
like this
sample_data = [
['6/5/2012', 20, 28, 38, 45],
['5/5/2012', 31, 38, 39, 50],
['4/5/2012', 50, 55, 56, 62],
['3/5/2012', 77, 70, 71, 60],
['2/5/2012', 68, 66, 22, 15],
]

Please advice..
Thanks

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Aug 7, 2017

Typical time series arrays are oldest to newest.

@pcawthron
Copy link

pcawthron commented Aug 9, 2017

Here's an example that uses CDLHAMMER:

from matplotlib.finance import candlestick2_ohlc
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
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']]

ax.xaxis.set_major_locator(ticker.MaxNLocator(6))

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

ax.xaxis.set_major_formatter(ticker.FuncFormatter(mydate))

fig.autofmt_xdate()
fig.tight_layout()

plt.show()

o, h, l, c = np.double(quotes['open']), np.double(quotes['high']), np.double(quotes['low']), np.double(quotes['close'])
talib.CDLHAMMER(o,h,l,c)

CDHAMMER Demo

@metashock
Copy link

@mrjbq7 Any news about the 200/-200 issue? Following the documentation this should not happen. (including the inline documentation of the C code)

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jan 5, 2018

What is the issue?

And what documentation are you talking about?

This is in ta_CDLHIKKAKE.c:

https://svn.code.sf.net/p/ta-lib/code/trunk/ta-lib/c/src/ta_func/ta_CDLHIKKAKE.c

/* Generated */             if( i <= patternIdx+3 &&
/* Generated */                 ( ( patternResult > 0 && inClose[i] > inHigh[patternIdx-1] )    // close higher than the high of 2nd
/* Generated */                   ||
/* Generated */                   ( patternResult < 0 && inClose[i] < inLow[patternIdx-1] )     // close lower than the low of 2nd
/* Generated */                 )
/* Generated */             ) {
/* Generated */                 outInteger[outIdx++] = patternResult + 100 * ( patternResult > 0 ? 1 : -1 );
/* Generated */                 patternIdx = 0;
/* Generated */             } else
/* Generated */                 outInteger[outIdx++] = 0;

That implies that the patternResult is doubled if a confirmation candle is observed. So you can probably treat a 200 either a "100" or handle that case specially in your code.

I'm not sure there is anything to do here...

@metashock
Copy link

metashock commented Jan 5, 2018

Well, I'm not familiar with the talib C code so far and honestly, it is hard to read. But if you say so...

Btw, I'm referring to this piece of inline documentation:

   /* Proceed with the calculation for the requested range.
    * Must have:
    * - first and second candle: inside bar (2nd has lower high and higher low than 1st)
    * - third candle: lower high and lower low than 2nd (higher high and higher low than 2nd)
    * outInteger[hikkakebar] is positive (1 to 100) or negative (-1 to -100) meaning bullish or bearish hikkake
    * Confirmation could come in the next 3 days with:
    * - a day that closes higher than the high (lower than the low) of the 2nd candle
    * outInteger[confirmationbar] is equal to 100 + the bullish hikkake result or -100 - the bearish hikkake result
    * Note: if confirmation and a new hikkake come at the same bar, only the new hikkake is reported (the new hikkake
    * overwrites the confirmation of the old hikkake)
    */

But it looks like this applies only to the block below it. This 200 magic happens at the bottom, in an undocumented, generated block. Goodbye readability!


PS: I guess the key here is to do the math once manually to understand it. Then the C code becomes more readable. Anyhow, I was just playing around a bit.

Thanks for your help!

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jan 5, 2018

I think the 200 comes from this "confirmation" line in the documentation:

outInteger[confirmationbar] is equal to 100 + the bullish hikkake result

Assuming the bullish hikkake result is in the range [1,100] then that confirmation bar is in the range [101,200].

@mrjbq7
Copy link
Collaborator

mrjbq7 commented Jan 5, 2018

Also, I don't mind at all the questions. I learn something usually every time someone tries to figure out how the TA-Lib C library works!

@xiaxio
Copy link

xiaxio commented Jul 7, 2018

Thanks @pcawthron for your code. I always learn best with example code.
Of course thanks to @mrjbq7 for all your hard work on ta-lib.
If you are reading this and tried @pcawthron code, you will notice that matplotlib has deprecated the finance module since version 2.2. You will find the solution here:
https://stackoverflow.com/questions/42373104/since-matplotlib-finance-has-been-deprecated-how-can-i-use-the-new-mpl-finance
Best regards

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

10 participants