Announcement

Collapse
No announcement yet.

Help with ATR EFS Please

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help with ATR EFS Please

    I am trying to program an EFS that calculates the ATR of several symbols and am running into a problem.

    Whenever eSignal is FIRST started, and the symbols I'm interested in have NOT yet been charted, then a call to the atr() function for a particular symbol will return null the FIRST time it is called. When called the second and subsequent times (for that symbol), it works fine.

    Note that if a symbol has been charted before the formula is loaded, the ATR for that symbol is always calculated correctly for that symbol.

    Clearly I'm missing something in regards to how these series are initialized. The specific line of code exhibiting this behavior is:

    result = atr(50,sym(aSymbol+",D")).getValue(0);

    Please find a complete snippet of code that I created that exhibits the problem, together with the formula output.

    Thanks for your help.

    ----------------------------------

    var completed = false;

    function preMain() {

    setPriceStudy(false);
    setStudyTitle("Test");
    setCursorLabelName("vatr1", 0);
    setCursorLabelName("vatr2", 1);
    setCursorLabelName("vatr3", 2);
    setComputeOnClose();
    }
    function calcATR(aSymbol) {
    var result = 0;
    debugPrintln("Processing: " + aSymbol);
    result = atr(50,sym(aSymbol+",D")).getValue(0);
    if (result == null) {debugPrintln("ATR is null");}
    return result;
    }
    function main() {
    var vatr1;
    var vatr2;
    var vatr3;

    if ( (isDaily(getInterval()) == true) && (isLastBarOnChart() == true) && (!completed)) {
    debugPrintln();
    vatr1 = calcATR("MATK");
    if (vatr1 != null) vatr2 = calcATR("MOGN");
    if (vatr2 != null) vatr3 = calcATR("NVDA");
    completed = true;
    }
    return new Array (vatr1,vatr2,vatr3);
    }
    function postMain() {
    }

    Formula Output (from bottom up. Note would be nice to be able to reverse output to print top down!)
    Note selected chart symbols are not NVDA, MOGN or MATK. If these are charted prior to running the
    formula, then there is no problem.

    Processing: NVDA
    Processing: MOGN // ATR for all ok
    Processing: MATK // Selection of new chart symbol

    ATR is null
    Processing: NVDA
    Processing: MOGN // ATR for MATK & MOGN ok, but failed for NVDA
    Processing: MATK // Selection of new chart symbol

    ATR is null
    Processing: MOGN // ATR for MATK ok, but failed for MOGN
    Processing: MATK // Selection of new chart symbol

    ATR is null // ATR for MATK failed
    Processing: MATK // Upon initial load of formula

  • #2
    Hello ieng,

    The source of the problem is a timing issue created by your code logic. Because you wait until the chart has completely loaded before you make a request to the external symbols, the atr studies do not have enough time to initialize and return a valid number on the first execution. The instant that you make the call to the external symbol's atr study, that symbols data has to be loaded into the cache. The EFS will not wait for this action to complete in the background before continuing through the rest of the code. Therefore, when the getValue(0) method is executed the atr value has not been calculated yet and returns null. If you then manually reload the study once, you will see that you get to the second symbol before a null is returned. That is because the first external symbols' data got loaded after the first time the external atr call was made, which allows the atr study to return a valid calculation after the first reload. Reload a second time and you get to the third symbol before the null return for the same reason as the first symbol. Reload a third time and you will see that all 3 symbols now return valid atr values.

    I'm not sure why you want to wait until the last bar on the chart to retrieve the atr values, but the following code is the correct logic that will accomplish this for you. The key is to allow the atr studies (or series) to initialize during the initialization of the formula on the first execution of main(). Then make the request for the current atr values once you reach the last bar on the chart. Also, it's not neccessary to make the call to the calcATR() function. You can initialize the series directly in main(). If there is some reason why you want to have this done in the calcATR() function, please explain and we can explore other alternatives.

    PHP Code:
    var completed false;

    function 
    preMain() {

        
    setPriceStudy(false);
        
    setStudyTitle("Test");
        
    setCursorLabelName("vatr1"0);
        
    setCursorLabelName("vatr2"1);
        
    setCursorLabelName("vatr3"2);
        
    setComputeOnClose();
    }


    var 
    xatr1 null;
    var 
    xatr2 null;
    var 
    xatr3 null;

    function 
    main() {
        var 
    vatr1;
        var 
    vatr2;
        var 
    vatr3;
        
        if (!
    completed) {
            if (
    xatr1 == nullxatr1 atr(50sym("MATK,D"));
            if (
    xatr2 == nullxatr2 atr(50sym("MOGN,D")); 
            if (
    xatr3 == nullxatr3 atr(50sym("NVDA,D")); 
            
    completed true;
        }

        if ( 
    isDaily(getInterval()) == true && isLastBarOnChart() == true) {
            
    vatr1 xatr1.getValue(0);
            
    vatr2 xatr2.getValue(0); 
            
    vatr3 xatr3.getValue(0); 
        }

        return new Array (
    vatr1,vatr2,vatr3);

    Jason K.
    Project Manager
    eSignal - an Interactive Data company

    EFS KnowledgeBase
    JavaScript for EFS Video Series
    EFS Beginner Tutorial Series
    EFS Glossary
    Custom EFS Development Policy

    New User Orientation

    Comment


    • #3
      Thanks so much for the quick reply.

      If I understand correctly, the price history for an external symbol, upon which any derived series would be based, must first be loaded into cache before the series can be calculated. So the solution is to create the series on the first call to main(), which I understand to be the BARSTATE_ALLBARS state. If so, instead of the "completed" boolean we could just test for the BARSTATE_ALLBARS state. Alternatively, could I just create the series in preMain()?

      Another thought I have regarding the use of external symbols is to maybe initially use the sym(anExternalSymbol) function. Would this automatically initialize the external symbol for subsequent use in the script? The advantage here would be that I wouldn't have to pre-create a specific series.

      As an aside, I'm a bit surprised that the EFS engine operates in an asynchronous mode. If not specifically taken into account, wold this not lead to other anomolies? For example, does this mean that for the first bar calculated on a chart, any series based on an external symbol will not return a proper value? Won't this affect the calculations for subsequent bars that are based on running or cumulative calculations?

      The reason I waited for the last bar to calculate the ATR is that I am exporting these (among other series values) via DDE to Excel for further processing. As I only need the ATR value of the current Daily bar, I don't need to plot the values for the other bars, so I thought I would save processing time.

      Note that aside from the atr() function I have been having similar problems with the volume() function which seems to crash the script (i.e. immediately exit) the first time it is called for an external symbol. (Is there no way to trap these type of script failures and report the line number of the failure to the user?)

      Finally, the reason I use a calcATR() function is that I'm looping through an array of symbols to calculate their ATR's for export. Seems cleaner. You implied that your solution would not work if a calcATR function is used, but wouldn't this still be ok as long as the variables holding the atr series are within the scope of the calcATR function?

      Thanks for your help.

      P.S. Is there a way to reverse the direction of printing in the Formula Output window, so that it outputs from top to bottom?

      Comment


      • #4
        Hello ieng,

        Originally posted by ieng
        Thanks so much for the quick reply.

        If I understand correctly, the price history for an external symbol, upon which any derived series would be based, must first be loaded into cache before the series can be calculated. So the solution is to create the series on the first call to main(), which I understand to be the BARSTATE_ALLBARS state. If so, instead of the "completed" boolean we could just test for the BARSTATE_ALLBARS state. Alternatively, could I just create the series in preMain()?
        Yes, you could use the allbars state to preform this action as an alternative to the "completed" method. You should not include any of the formula logic inside preMain(). That function is for formula settings, parameters and formatting.

        Another thought I have regarding the use of external symbols is to maybe initially use the sym(anExternalSymbol) function. Would this automatically initialize the external symbol for subsequent use in the script? The advantage here would be that I wouldn't have to pre-create a specific series.
        I don't think so. The sym() function is not intended to be executed as a stand alone function. It's purpose is to be used as a parameter for the series functions. The code example I gave you would be the preferred method for initializing the external symbol series.

        As an aside, I'm a bit surprised that the EFS engine operates in an asynchronous mode. If not specifically taken into account, wold this not lead to other anomolies?
        Potentially. However, EFS2 has been in use for about a year now and I haven't run into any other situations where this causes a problem. As as you properly initialize your data series and perform null checks on the requested data before performing any calculations or testing for conditions based on that data you shouldn't have any problems.

        For example, does this mean that for the first bar calculated on a chart, any series based on an external symbol will not return a proper value? Won't this affect the calculations for subsequent bars that are based on running or cumulative calculations?
        Yes, that it true because many studies and processes will need to have a certain amount of bars processed before a valid value can be returned. Again, performing standard validation routines (i.e. null checks) prior to formula calculations will prevent these problems. This is standard programming practice.

        The reason I waited for the last bar to calculate the ATR is that I am exporting these (among other series values) via DDE to Excel for further processing. As I only need the ATR value of the current Daily bar, I don't need to plot the values for the other bars, so I thought I would save processing time.
        Yes, this would save some processing time. However, the only code that should be prevented from executing until the last bar on the chart in your case would be the code for the DDE links. The series that the dde links get their data from should be initialized as I've shown you or at the allbars state. Once the formula reaches the last bar you just need to retrieve the current value from the series with the .getValue(0) method.

        Note that aside from the atr() function I have been having similar problems with the volume() function which seems to crash the script (i.e. immediately exit) the first time it is called for an external symbol. (Is there no way to trap these type of script failures and report the line number of the failure to the user?)
        The EFS engine does report formula errors that source from invalid syntax. However, there are logic problems that can be created, such as endless loops, that cannot be trapped and reported by the engine. The answer lies within the specific code you are using. If you post some code that demonstrates the problem I'd be happy to take a look at it.

        Finally, the reason I use a calcATR() function is that I'm looping through an array of symbols to calculate their ATR's for export. Seems cleaner. You implied that your solution would not work if a calcATR function is used, but wouldn't this still be ok as long as the variables holding the atr series are within the scope of the calcATR function?
        There are many ways to arrive at this destination. It could be made to work in the calcATR function through the efsInternal() function. However, in your particular case the only difference between each series is the symbol. There's no real advantage of performing this routine in the calcATR() function. The easiest way to deal with this one would be to create an array of your symbols and put the loop inside the "completed" routine. Your series objects will also be stored in an array that has the same length as the symbols array. Give this a try and if you need help, post your code.

        Thanks for your help.

        P.S. Is there a way to reverse the direction of printing in the Formula Output window, so that it outputs from top to bottom?
        No, currently there is not. I don't think you would really want this as the newest information printed would be at the bottom of the file. Once the top lines of the output window have been filled up, you wouldn't see any of the new information unless you manually scrolled down to see it. It may be possible for development to add an option to view the output data in this fashion if they could also force the window to always scroll to the bottom. However, that may make it difficult for you to scroll up to see the historical prints. Anyway, feel free to submit a suggestion to development at [email protected].
        Jason K.
        Project Manager
        eSignal - an Interactive Data company

        EFS KnowledgeBase
        JavaScript for EFS Video Series
        EFS Beginner Tutorial Series
        EFS Glossary
        Custom EFS Development Policy

        New User Orientation

        Comment


        • #5
          I've implemented your suggestions and everything works fine. Thanks so much for the help.

          Re: the problem I experienced with volume(). The first thing I noticed is that although the documentation indicates that sym() should be used for an external symbol, the function seems to only accept a simple string.

          Secondly, if a null is passed instead of a valid symbol, the script crashes (immediately exits). See below for the test script that demonstrates this. You'll see that the 3rd debugPrintln never gets called.

          PHP Code:
          var completed false;

          function 
          preMain() {

              
          setPriceStudy(false);   
              
          setStudyTitle("Test2");
              
          setCursorLabelName("vvol"0);
              
          setComputeOnClose();
              
          }

          function 
          main() {
          var 
          vvol;
          var 
          aSymbol;

              if ( (
          isDaily(getInterval()) == true) && (isLastBarOnChart() == true) && (!completed)) {
                  
          debugPrintln();
                  
          aSymbol null//"MATK";
                  
          debugPrintln("Processing: " aSymbol);
                  
          vvol volume(0,1,aSymbol+",D");
                  
          debugPrintln("Processing Completed: " aSymbol);
                  
          completed true;
              }
              return 
          vvol;
          }

          function 
          postMain() {

          Comment


          • #6
            Hello ieng,

            The sym() function accepts a simple string, that is correct. The string can be just a symbol (i.e. "MATK" ) or a combination of symbol and interval (i.e. "MATK,D"). However, the symbol used needs to be a valid symbol. You cannot pass in null. I will make a request to development to trap an invalid symbol in this type of call to report a formula error rather than just a silent exit.

            The solution for your code example in the mean time is to change the volume() call to the following. Ensure that your aSymbol variable is not null prior to making the call. You also do not need to specify the number of bars of 1 in this case.

            PHP Code:
            if (aSymbol != null) {
                
            vvol volume(0sym(aSymbol+",D"));

            Also, if you are going to be sending the result out through DDE as you are with your ATR example, you may not want to use the "completed" flag here. During real time processing, your vvol variable will not update after subsequent trades or new bars occur if that flag is used. Just something you may want to consider.
            Jason K.
            Project Manager
            eSignal - an Interactive Data company

            EFS KnowledgeBase
            JavaScript for EFS Video Series
            EFS Beginner Tutorial Series
            EFS Glossary
            Custom EFS Development Policy

            New User Orientation

            Comment


            • #7
              Aside from the null symbol issue (thanks for flagging it to Development), I've discovered a problem with the use of sym().

              In my real script, I extract the last 10 values for volume() as:

              vvol = volume(0,-10,aSymbol+",D");

              The above works fine (with a valid symbol that is ), and returns the last 10 values.

              However when I used the sym function (per the doc spec) as in:

              vvol = volume(0,-10,sym(aSymbol+",D"));

              The value returned by the above is just a single data point, and NOT an array.

              Re: the completed' flag and DDE, as above in my real script I extract the last N values and discard the latest one, average them, and then export the avg. vol via DDE so I believe that just doing it once should be ok.

              Thanks again.

              Comment


              • #8
                Hello ieng,

                For future reference, the invalid symbol validation issue has been submitted as EDL# 22050.

                The numBars parameter of the volume() call is part of the EFS1 syntax. It does not exist in the EFS2 syntax. It is still part of the EFS language for backward compatibility reasons. With EFS2 syntax, you need to loop through a volume Series Object and retrieve the 10 values with the .getValue(-nIndex) method. You can populate an array with this routine or use the values directly depending on how you've written your formula.

                The call below in EFS1 logic, which will work on the current bar.

                vvol = volume(0,-10,aSymbol+",D");

                Once you add the sym() function to the parameters, you are operating in the EFS2 realm, which does not accept the numBars parameter. You can do something similar to the following.

                PHP Code:
                var xVol null;

                function 
                main() {
                    if (
                xVol == nullxVol volume(sym(aSymbol+",D"));
                    
                    if (
                isLastBarOnChart() == false) return;

                    var 
                aVol = new Array(10);
                    for (var 
                010i++ ) {
                        
                aVol[i] = xVol.getValue(-i);
                    }
                    
                    
                // calcs and dde code here

                    
                return;

                Jason K.
                Project Manager
                eSignal - an Interactive Data company

                EFS KnowledgeBase
                JavaScript for EFS Video Series
                EFS Beginner Tutorial Series
                EFS Glossary
                Custom EFS Development Policy

                New User Orientation

                Comment


                • #9
                  Thanks for clearing up the last of my issues.

                  I would note though that the EFS2 documentation for volume() should be updated, as it shows the numBars parm (together with examples) which as you indicate is no longer accepted when the sym() parm is used.

                  volume( barIndex [,numBars] [, sym()] [, inv()] )

                  Comment

                  Working...
                  X