Skip to content

Error when creating new indicator #524

Open

Description

@hhashim1

I am creating a new indicator and have copied parts from BBANDS. I am getting an error on one of the variables and I cannot seem to figure out why I am getting this error. Can you @mrjbq7 or @trufanov-nok can either of you help plz?

tempBuffer2 is the one that is causing the issue.

I am trying to have an equivalent of the following line of code:

def rawRelVol = (volume - Average(volume, length)) / StDev(volume, length);

Here is my code:


   /* Insert TA function code here. */
    ENUM_DECLARATION(RetCode) retCode;
    double periodTotal, tempReal;
    int i, outIdx, trailingIdx, lookbackTotal;
    ARRAY_REF(tempBuffer1);
    ARRAY_REF(tempBuffer2);
    //double rawRelVol;

    /* Calculate moving average. */
    retCode = FUNCTION_CALL(SMA)(startIdx, endIdx, inVolume,
        optInTimePeriod, outBegIdx, outNBElement, tempBuffer1);

    if ((retCode != ENUM_VALUE(RetCode, TA_SUCCESS, Success)) || ((int)VALUE_HANDLE_DEREF(outNBElement) == 0))
    {
        VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
        return retCode;
    }


    /* Calculate the Standard Deviation */
    retCode = FUNCTION_CALL(STDDEV)((int)VALUE_HANDLE_DEREF(outBegIdx), endIdx, inVolume,
        optInTimePeriod, 1.0,
        outBegIdx, outNBElement, tempBuffer2);

    if (retCode != ENUM_VALUE(RetCode, TA_SUCCESS, Success))
    {
        VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
        return retCode;
    }

    tempReal = (inVolume - tempBuffer1);
    tempReal = tempReal / tempBuffer2;

Here is the screenshot:
image

Activity

  1. mrjbq7 commented on Jun 24, 2022

    @mrjbq7
    Member

    Are you trying to divide a double by a double* ?

  2. hhashim1 commented on Jun 24, 2022

    @hhashim1
    Author

    What is a double*?

    This is what I am trying to do.
    rawRelVol = (volume - Average(volume, length)) / StDev(volume, length)

    tempBuffer2 is meant to be the StDev value that is returned.

    I have copied the Stdev code from BBANDS.

  3. trufanov-nok commented on Jun 24, 2022

    @trufanov-nok
    Contributor

    You need to learn how arrays in C are designed. double* is a pointer in memory to a first double element of an array. And you can't just divide array by array or make any other operations over arrays - it won't work, they are not objects. You need to iterate both arrays in a loop and devide each element. It's not a TA-Lib related issue. it's a C knowlage related issue. You may better to ask on stackoverflow or something.

  4. hhashim1 commented on Jun 24, 2022

    @hhashim1
    Author

    Ok, so I made some changes and added a loop to iterate however I have a different issue now. I don't know how else to initialize the variable.

    The error is Using uninitialized memory "tempBuffer1" and Using uninitialized memory "tempBuffer2"

    Here is the code:

    
       /* insert local variable here */
        ENUM_DECLARATION(RetCode) retCode;
        //double periodTotal;
        double tempReal, tempReal2;
        int i;// , outIdx, trailingIdx, lookbackTotal;
        ARRAY_REF(tempBuffer1);
        ARRAY_REF(tempBuffer2);
    
       /* Insert TA function code here. */
       #if defined(USE_SINGLE_PRECISION_INPUT) || defined( USE_SUBARRAY )
          tempBuffer1 = outRealMiddleBand;
          tempBuffer2 = outReal;
          /* Check that the caller is not doing tricky things. 
           * (like using the input buffer in two output!)
           */
          if( (tempBuffer1 == inVolume) || (tempBuffer2 == inVolume) )
             return ENUM_VALUE(RetCode,TA_BAD_PARAM,BadParam);
       #endif
    
        /* Calculate moving average. */
        retCode = FUNCTION_CALL(SMA)(startIdx, endIdx, inVolume,
            optInTimePeriod, outBegIdx, outNBElement, tempBuffer1);
    
        if ((retCode != ENUM_VALUE(RetCode, TA_SUCCESS, Success)) || ((int)VALUE_HANDLE_DEREF(outNBElement) == 0))
        {
            VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
            return retCode;
        }
    
    
        /* Calculate the Standard Deviation */
        retCode = FUNCTION_CALL(STDDEV)((int)VALUE_HANDLE_DEREF(outBegIdx), endIdx, inVolume,
            optInTimePeriod, 1.0,
            outBegIdx, outNBElement, tempBuffer2);
    
        if (retCode != ENUM_VALUE(RetCode, TA_SUCCESS, Success))
        {
            VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
            return retCode;
        }
    
    
    
        /* No standard deviation multiplier needed. */
        for (i = 0; i < (int)VALUE_HANDLE_DEREF(outNBElement); i++)
        {
            tempReal = (inVolume - tempBuffer1);
            tempReal2 = tempBuffer2[i];
            outReal[i] = tempReal / tempReal2;
        }
    
    
       return ENUM_VALUE(RetCode,TA_SUCCESS,Success);
    }
    

    Here is the screenshot:
    image

  5. trufanov-nok commented on Jun 24, 2022

    @trufanov-nok
    Contributor

    You are probably using ARRAY_REF. That's a template which is declared in ta_memory.h. And it's value is type *name. Which means ARRAY_REF(tempBuffer1); will be substituted by ARRAY_VTYPE_REF(double, name) and its turn by a double* tempBuffer1; during compilation by a C preprocessor. That only a pointer to a first element in array. Pointer to memory. But memory isn't allocated. So you need to use ARRAY_ALLOC(name,size) and ARRAY_FREE(name) templates instead to not only declare a pointer, but also allocate and deallocate a memory for an array at the end. name is tempBuffer1. The question is: what is the size? For ex., for tempBuffer1 I would try endIdx-startIdx-LOOKBACK_CALL(SMA)(optInTimePeriod);. Similar for a second buffer.

  6. hhashim1 commented on Jun 24, 2022

    @hhashim1
    Author

    For lookback, here is what I have.
    return LOOKBACK_CALL(SMA)(optInTimePeriod);

    Here are my inputs:

    /* Generated */ enum class Core::RetCode Core::RvStdev( int    startIdx,
    /* Generated */                                         int    endIdx,
    /* Generated */                                         SubArray<double>^ inVolume,
    /* Generated */                                         int           optInTimePeriod, /* From 2 to 100000 */
    /* Generated */                                         [Out]int%    outBegIdx,
    /* Generated */                                         [Out]int%    outNBElement,
    /* Generated */                                         SubArray<double>^  outReal )
    
  7. hhashim1 commented on Jun 24, 2022

    @hhashim1
    Author

    @trufanov-nok given the below psuedo code, how would you code it in talib?

    input length = 50;
    rawRelVol = (volume - Average(volume, length)) / StDev(volume, length);
    
  8. trufanov-nok commented on Jun 24, 2022

    @trufanov-nok
    Contributor

    I'll answer tomorrow.

  9. hhashim1 commented on Jun 24, 2022

    @hhashim1
    Author

    Thank you

  10. trufanov-nok commented on Jun 25, 2022

    @trufanov-nok
    Contributor

    @trufanov-nok given the below psuedo code, how would you code it in talib?

    input length = 50;
    rawRelVol = (volume - Average(volume, length)) / StDev(volume, length);
    

    I would start with something like that (didn't test it):

    /* insert local variable here */
    ENUM_DECLARATION(RetCode) retCode;
    int outBegIdx1, outBegIdx2;
    int currentIdx, currentIdx1, currentIdx2;
    ARRAY_ALLOC(tempBuffer1, 50);
    ARRAY_ALLOC(tempBuffer2, 50);
     
       
           /* Calculate moving average. */
        retCode = FUNCTION_CALL(SMA)(startIdx, endIdx, inVolume,
            optInTimePeriod, &outBegIdx1, outNBElement, tempBuffer1);
    
        if ((retCode != ENUM_VALUE(RetCode, TA_SUCCESS, Success)) || ((int)VALUE_HANDLE_DEREF(outNBElement) == 0))
        {
            ARRAY_FREE(tempBuffer1);
            ARRAY_FREE(tempBuffer2);
            VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
            return retCode;
        }
        
        /* Calculate the Standard Deviation */
        retCode = FUNCTION_CALL(STDDEV)(startIdx, endIdx, inVolume,
            optInTimePeriod, 1.0,
            &outBegIdx2, outNBElement, tempBuffer2);
            
        if ((retCode != ENUM_VALUE(RetCode, TA_SUCCESS, Success)) || ((int)VALUE_HANDLE_DEREF(outNBElement) == 0))
        {
            ARRAY_FREE(tempBuffer1);
            ARRAY_FREE(tempBuffer2);
            VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
            return retCode;
        }
        
            
        // startIdx is a MAX(startIdx, outBegIdx1, outBegIdx2)
        if (startIdx < outBegIdx1)
           startIdx = outBegIdx1;
        if (startIdx < outBegIdx2)
           startIdx = outBegIdx2;
           
        VALUE_HANDLE_DEREF(outBegIdx) = startIdx;
        
        if (startIdx > endIdx)
        {
            ARRAY_FREE(tempBuffer1);
            ARRAY_FREE(tempBuffer2);
            VALUE_HANDLE_DEREF_TO_ZERO(outNBElement);
            return retCode;
        }
    
    
        currentIdx = 0;
        currentIdx1 = startIdx - outBegIdx1;
        currentIdx2 = startIdx - outBegIdx2;
        
        for (i = startIdx; i < endIdx; i++)
        {
            outReal[currentIdx++] = (inVolume[i] - tempBuffer1[currentIdx1++]) / tempBuffer2[currentIdx2++];
        }
        
        
        ARRAY_FREE(tempBuffer1);
        ARRAY_FREE(tempBuffer2);
        (int)VALUE_HANDLE_DEREF(outNBElement) = currentIdx;
    
    return ENUM_VALUE(RetCode,TA_SUCCESS,Success);
    
  11. hhashim1 commented on Jun 27, 2022

    @hhashim1
    Author

    @trufanov-nok thank you. I was getting an error saying tempBuffer1 and 2 are uninitialized or something like that. I had to add the following code and it got rid of the error however I wanted to ask if this was the right thing to do or not.

        ARRAY_REF(tempBuffer1);
        ARRAY_REF(tempBuffer2);
    

    Here is my full variable declaration:

       /* insert local variable here */
        ENUM_DECLARATION(RetCode) retCode;
        int outBegIdx1, outBegIdx2;
        int currentIdx, currentIdx1, currentIdx2;
        int i;
        ARRAY_REF(tempBuffer1);
        ARRAY_REF(tempBuffer2);
        ARRAY_ALLOC(tempBuffer1, optInTimePeriod);
        ARRAY_ALLOC(tempBuffer2, optInTimePeriod);
    
  12. trufanov-nok commented on Jun 27, 2022

    @trufanov-nok
    Contributor

    You're rignt. ARRAY_REF is a type *name. The ARRAY_ALLOC is only a name = (type *)TA_Malloc( sizeof(type)*(size)). So both are required.

  13. hhashim1 commented on Jun 27, 2022

    @hhashim1
    Author

    Ok, thanks @trufanov-nok I do have another error that I dont know how to fix.

    image

    Also, while running make after running ./configure --prefix=/usr, I get the following error. I dont know if the two are related.

    image

    Thoughts?

  14. trufanov-nok commented on Jun 27, 2022

    @trufanov-nok
    Contributor

    could you upload a whole code at pastebin?

  15. hhashim1 commented on Jun 27, 2022

    @hhashim1
    Author
  16. 59 remaining items

  17. trufanov-nok commented on Jun 29, 2022

    @trufanov-nok
    Contributor

    I was able to build both and access to RVSTDEV from python, so the problem must be in environment.

    Screenshot_20220630_005836

  18. hhashim1 commented on Jun 29, 2022

    @hhashim1
    Author

    I was able to build both and access to RVSTDEV from python, so the problem must be in environment.

    Screenshot_20220630_005836

    The name of the function in your copy is different. Your screenshot says RCSTDEV. My function was called RVSTDEV. Do you have one with a similar name or did you change the name?

  19. trufanov-nok commented on Jun 29, 2022

    @trufanov-nok
    Contributor

    I just made a mistake when call it. Then I call it with a right name.

  20. hhashim1 commented on Jun 29, 2022

    @hhashim1
    Author

    Oh sorry...I didnt see that.

  21. hhashim1 commented on Jun 29, 2022

    @hhashim1
    Author

    What do you suggest for how to fix this?

  22. trufanov-nok commented on Jun 29, 2022

    @trufanov-nok
    Contributor

    find all libta_lib* files on your linux machine with sudo find / -iname "libta_lib*" and list the results

  23. hhashim1 commented on Jun 29, 2022

    @hhashim1
    Author

    image

    
    root@aa3bed537114:/# sudo find / -iname "libta_lib*"
    /usr/lib/libta_lib.a
    /usr/lib/libta_lib.so
    /usr/lib/libta_lib.so.0
    /usr/lib/libta_lib.so.0.0.0
    /usr/lib/libta_lib.la
    find: ‘/proc/21033/map_files’: Permission denied
    /ta-lib/src/.libs/libta_lib.a
    /ta-lib/src/.libs/libta_lib.la
    /ta-lib/src/.libs/libta_lib.lai
    /ta-lib/src/.libs/libta_lib.so
    /ta-lib/src/.libs/libta_lib.so.0
    /ta-lib/src/.libs/libta_lib.so.0.0.0
    /ta-lib/src/libta_lib.la
    
  24. trufanov-nok commented on Jun 29, 2022

    @trufanov-nok
    Contributor

    What says sudo find / -iname "_ta_lib.cpython*.so" ?

  25. hhashim1 commented on Jun 29, 2022

    @hhashim1
    Author

    image

  26. trufanov-nok commented on Jun 29, 2022

    @trufanov-nok
    Contributor

    you copied it wrong or something..

  27. hhashim1 commented on Jun 30, 2022

    @hhashim1
    Author

    Sorry I had a quote at the end. This list goes on though. Rest of the list is permission denied because its on the Windows drive.

    image

  28. hhashim1 commented on Jun 30, 2022

    @hhashim1
    Author

    @trufanov-nok I got it to work. I renamed my function and compiled it again and it seems to be working. I think it was just getting confused with STDDEV. I renamed my function to RVSTDDEV instead RVSTDEV

  29. hhashim1 commented on Aug 20, 2022

    @hhashim1
    Author

    @trufanov-nok I need to get a couple of indicators coded and its over my head. Are you able to help me get these indicators done in talib? I will pay you for it.

  30. hhashim1 commented on Aug 21, 2022

    @hhashim1
    Author

    @trufanov-nok thats great. Thank you. I will email you. You can delete your email address from the comment above now. I have copied it.

  31. trufanov-nok commented on Aug 25, 2022

    @trufanov-nok
    Contributor

    I've just passed the whole way from making a new indicator to adding it to the python's wrapper so I can write a little guide about that:

    1. Regarding addition of a new indicator to the TA-Lib library written in C language pls refer to this description: https://github.com/trufanov-nok/ta-lib-rt/wiki/Adding-new-TA-function
      and this thread. It's pretty relevant to original TA-Lib sourcecode.

    Just note that the archive of ta-lib sources which are automatically downloaded by the wrapper when it's installed via pip isn't suitable for a new indicator addition bcs of lacking some files. So you'll need a dump of a whole latest sourcecode trunk from sourceforge. This have some consequences which will be shown later.

    1. After successful creation of a new C indicator and compilation of a C library, one need to install it with make install or something like that. Read in console and remember there include/ta-lib/ta_func.h is stored.
    2. Doublecheck that your new indicator is declared in this ta_func.h header. If it's not - you did something wrong in the C code.
    3. Find any other ta_func.h files in default folders of your system and delete them, bcs TA-lib's wrapper will automatically search this header in your system using default paths. If it find an old one before reach up-to-date one - it won't get any info about your new indicator. The default folders are '/usr/include', '/usr/local/include', '/opt/include', '/opt/local/include', '/opt/homebrew/include', 'c:\ta-lib\c\include'.
    4. Get the latest sources of TA-Lib's wrapper for python from this github project. The package in system repositories won't work and you'll need exactly the latest sources as they contain some fixes.
    5. Uninstall all other python wrappers of TA-lib with pip uninstall ta-lib. Execute it a few times until it report that no any TA-Lib packages are installed.
    6. In python's wrapper folder edit files ./tools/generate_func.py and ./tools/generate_stream.py. In both comment out (with #) lines from talib import abstract then comment out:
        func_info = abstract.Function(shortname).info
        defaults, documentation = abstract._get_defaults_and_docs(func_info)
    

    then add after them:

        func_info = []
        defaults = []
        documentation = []
    

    This will disable usage of TA-Lib's python package in these scripts for generation of documentation for indicators. It won't work anyway as scripts will parse your new ta_func.h, and will try to get a documentation for a new indicator which is unknown yet for the wrapper installed in the system. And according to the 6 I advised to uninstall all wrappers anyway, so it won't work.

    1. Launch python3 tools/generate_func.py. This will print a lot of text (which is actually a new content of a _func.pxi) to the console. Check the last lines. If there are any errors - most probably you failed to perform step 7. If __TA_FUNCTION_NAMES__ is empty (__TA_FUNCTION_NAMES__ = []) - script can't find any ta_func.h file. If it contains a list of indicators names, but there is no your new one - then script catch ups some old ta_func.h and you failed step 4.
    2. If everything is okay, overwrite files talib/_func.pxi and talib/_stream.pxi with a new content generated by these scripts, with:
    python3 tools/generate_func.py > talib/_func.pxi
    python3 tools/generate_stream.py > talib/_stream.pxi
    
    1. Unfortunately there are few other files that need to be patched to add info about your new indicator. And there is no script to autopatch them. These are declarations in _ta_lib.pxd and (optionally) groups description in __init__.py.
      Also, TA-Lib's wrapper is designed to be used with an old version of TA-Lib 0.4.24, while sourceforge's trunk contain 0.4.25. It has 3 more indicators than previous one. Which means that along with your new indicator you'll need to add the info about these 3. Indicators are: ACCBANDS, AVGDEV, IMI. Scripts will grab their description from ta_func.h and update talib/_func.pxi and talib/_stream.pxi, but following is still need to be added into _ta_lib.pxd manually:
        TA_RetCode TA_ACCBANDS(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outRealUpperBand[], double outRealMiddleBand[], double outRealLowerBand[])
        int TA_ACCBANDS_Lookback(int optInTimePeriod)
        TA_RetCode TA_AVGDEV(int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[])
        int TA_AVGDEV_Lookback(int optInTimePeriod)
        TA_RetCode TA_IMI(int startIdx, int endIdx, const double inOpen[], const double inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[])
        int TA_IMI_Lookback(int optInTimePeriod)
    

    Do not forget to add definitions of the function for your new indicator there too.

    1. Perform python3 setup.py build. In case of any errors check the messages. If it's about your new indicator - the problem is on step 10.
    2. Perform sudo python3 setup.py install to install the wrapper binary. Launch python3 and execute import talib to check if everything is ok. DO NOT DO THIS FROM WRAPPERS SOURCECODE FOLDER - it won't work as python will try to load a local copy and fail. You may print a list of talib functions available from python side with talib.__TA_FUNCTION_NAMES__ and get its version with talib.__version__ to make sure wrapper loads the right wrapper and library.
    3. Revert the changes made at step 7 and repeat steps 9-12 again to generate .pxi files with additional documentation and correct default values. Note: step 12 is mandatory to be done before 13.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions