TA-Lib / ta-lib-python

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

Unable to work with timestamp input #669

Closed YadavGulshan closed 3 months ago

YadavGulshan commented 3 months ago

Hi!

I'm currently trying to add a VWAP indicator in my fork of ta-lib-python. I modified generate_func.py and generate_stream.py, to handle int input data. But I'm unable to generate _ta_lib.c through make cython. Can you guide where I am making mistakes?

_ta_lib.pxd

TA_RetCode TA_VWAP(int    startIdx,
                         int    endIdx,
                         const double  inHigh[],
                         const double  inLow[],
                         const double  inClose[],
                         const double  inVolume[],
                         const int    inTimestamp[],
                         int *outBegIdx,
                         int *outNBElement,
                         double        outReal[])

generated func

@wraparound(False)  # turn off relative indexing from end of lists
@boundscheck(False) # turn off bounds-checking for entire function
def VWAP( np.ndarray high not None , np.ndarray low not None , np.ndarray close not None , np.ndarray volume not None , np.ndarray timestamp not None ):
    """ VWAP(high, low, close, volume, timestamp)

    Volume Weighted Average Price (Volume Indicators)

    Inputs:
        prices: ['timeStamp']
    Outputs:
        real
    """
    cdef:
        np.npy_intp length
        int begidx, endidx, lookback
        TA_RetCode retCode
        int outbegidx
        int outnbelement
        np.ndarray outreal
    high = check_array(high)
    low = check_array(low)
    close = check_array(close)
    volume = check_array(volume)
    timestamp = check_array(timestamp)
    length = check_length5(high, low, close, volume, timestamp)
    begidx = check_begidx5(length, <double*>(high.data), <double*>(low.data), <double*>(close.data), <double*>(volume.data), <int*>(timestamp.data))
    endidx = <int>length - begidx - 1
    lookback = begidx + lib.TA_VWAP_Lookback( )
    outreal = make_double_array(length, lookback)
    retCode = lib.TA_VWAP( 0 , endidx , <double *>(high.data)+begidx , <double *>(low.data)+begidx , <double *>(close.data)+begidx , <double *>(volume.data)+begidx , <int *>(timestamp.data)+begidx , &outbegidx , &outnbelement , <double *>(outreal.data)+lookback )
    _ta_check_success("TA_VWAP", retCode)
    return outreal 

Error:

Error compiling Cython file:
    low = check_array(low)
    close = check_array(close)
    volume = check_array(volume)
    timestamp = check_array(timestamp)
    length = check_length5(high, low, close, volume, timestamp)
    begidx = check_begidx5(length, <double*>(high.data), <double*>(low.data), <double*>(close.data), <double*>(volume.data), <int*>(timestamp.data))
                                                                                                                             ^

I have correctly installed the latest update of my library, but, I'm still facing this issue.

Fork: https://github.com/YadavGulshan/ta-lib-python

mrjbq7 commented 3 months ago

Where do you define check_length5 and check_begidx5?

Are your timestamp actually <int*> timestamp.data in which case you should use check_begidx4 or if they are double, which is how you defined it by using timestamp = check_array(timestamp) then you should make new words instead of i guess just calling them and hoping they exist:

diff --git a/talib/_func.pxi b/talib/_func.pxi
index 9f73c39..c55e096 100644
--- a/talib/_func.pxi
+++ b/talib/_func.pxi
@@ -56,6 +56,20 @@ cdef np.npy_intp check_length4(np.ndarray a1, np.ndarray a2, np.ndarray a3, np.n
         raise Exception("input array lengths are different")
     return length

+cdef np.npy_intp check_length5(np.ndarray a1, np.ndarray a2, np.ndarray a3, np.ndarray a4, np.ndarray a5) except -1:
+    cdef:
+        np.npy_intp length
+    length = a1.shape[0]
+    if length != a2.shape[0]:
+        raise Exception("input array lengths are different")
+    if length != a3.shape[0]:
+        raise Exception("input array lengths are different")
+    if length != a4.shape[0]:
+        raise Exception("input array lengths are different")
+    if length != a5.shape[0]:
+        raise Exception("input array lengths are different")
+    return length
+
 cdef np.npy_int check_begidx1(np.npy_intp length, double* a1):
     cdef:
         double val
@@ -118,6 +132,29 @@ cdef np.npy_int check_begidx4(np.npy_intp length, double* a1, double* a2, double
     else:
         return length - 1

+cdef np.npy_int check_begidx5(np.npy_intp length, double* a1, double* a2, double* a3, double* a4, double* a5):
+    cdef:
+        double val
+    for i from 0 <= i < length:
+        val = a1[i]
+        if val != val:
+            continue
+        val = a2[i]
+        if val != val:
+            continue
+        val = a3[i]
+        if val != val:
+            continue
+        val = a4[i]
+        if val != val:
+            continue
+        val = a5[i]
+        if val != val:
+            continue
+        return i
+    else:
+        return length - 1
+
 cdef np.ndarray make_double_array(np.npy_intp length, int lookback):
     cdef:
         np.ndarray outreal
@@ -5525,11 +5562,11 @@ def VWAP( np.ndarray high not None , np.ndarray low not None , np.ndarray close
     volume = check_array(volume)
     timestamp = check_array(timestamp)
     length = check_length5(high, low, close, volume, timestamp)
-    begidx = check_begidx5(length, <double*>(high.data), <double*>(low.data), <double*>(close.data), <double*>(volume.data), <int*>(timestamp.data))
+    begidx = check_begidx5(length, <double*>(high.data), <double*>(low.data), <double*>(close.data), <double*>(volume.data), <double*>(timestamp.data))
     endidx = <int>length - begidx - 1
     lookback = begidx + lib.TA_VWAP_Lookback( )
     outreal = make_double_array(length, lookback)
-    retCode = lib.TA_VWAP( 0 , endidx , <double *>(high.data)+begidx , <double *>(low.data)+begidx , <double *>(close.data)+begidx , <double *>(volume.data)+begidx , <int *>(timestamp.data)+begidx , &outbegidx , &outnbelement , <double *>(outreal.data)+lookback )
+    retCode = lib.TA_VWAP( 0 , endidx , <double *>(high.data)+begidx , <double *>(low.data)+begidx , <double *>(close.data)+begidx , <double *>(volume.data)+begidx , <double *>(timestamp.data)+begidx , &outbegidx , &outnbelement , <double *>(outreal.data)+lookback )
     _ta_check_success("TA_VWAP", retCode)
     return outreal 

And now make cython works...

YadavGulshan commented 3 months ago

Thanks, next time I'll examine a little more before creating an issue. Cython was throwing an error related to types, so I was a little confused about what was wrong. Sorry for that, and also Thanks. I'll try to be a better dev.

mrjbq7 commented 3 months ago

No worries at all! Please keep pinging us if you run into more issues!

YadavGulshan commented 3 months ago
TA_INPUT_FLAGS = {
    1: 'open',
    2: 'high',
    4: 'low',
    8: 'close',
    16: 'volume',
    32: 'openInterest',
    64: 'timeStamp',
    128: 'UNKNOWN', # Adding this, so that when using timestamp input, it will be recognized as a valid input. Sum of all flags is 127
}

Do you think this is logically correct? Is there a better way of handling this?

I added this because I was unable to use the timestamp input.

__get_flags

    min_int = int(math.log(min(value_range), 2))
    max_int = int(math.log(max(value_range), 2))

    log('   min_int: %d' % min_int)
    log('   max_int: %d' % max_int)

    # if the flag we got is out-of-range, it just means no extra info provided
    log('2 ** max_int: %s' % (2 ** max_int))

    if flag < 1 or flag > 2 ** max_int:
        log('       flag is out-of-range')
        log('       flag: %d' % flag)
        log('END [__get_flags]')
        return None

The flag was not in range.