Announcement

Collapse
No announcement yet.

on demand efs recalculation

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • on demand efs recalculation

    Is there is a way to "manually" have an efs that is a "setComputeOnClose" to calculate even though the bar may not yet be complete?
    For example, I have an efs that is quite compute intensive. It only runs on the daily charts and as such the output isn't really valid until the day is over. So, I use the "setComputeOnClose". However, the output begins to become meaningful prior to the close, for example after lunch or the last couple hours. It would be nice to have a way to manually have the efs calculate a result from time to time even though the bar has not closed. So my specific questions:

    1. Is there a way to have the efs calculate as though the setComputeOnClose was not there on a manual intervention basis? Push a button or something?
    2. Is there a way to time schedule a one time recalc say at 1:00 pm, 2:00 pm, etc, again as though the setComputeOnClose was not there?

    Thanks

    bigtee

  • #2
    Hello bigtee,

    1. You can draw a button on the chart that will execute a function in your EFS when clicked. However, the updated information calculated by your formula won't be reflected on the chart until the close of the bar if you're using setComputeOnClose(). I suggest removing the setComputeOnClose() and control execution of your code manually. Then you can use the button to update the formulas output. The only catch is that the update on the chart may not be instantaneous after you click the button. The chart still needs to receive a tick to update the return values in the chart. On a fast market you wouldn't notice much delay. Take a look at the following code example.

    PHP Code:

    function preMain() {
        
    setStudyTitle("Manual Execute Button");
        
    setCursorLabelName("Cntr");
    }

    var 
    nCntr 0;
    var 
    bNewDay false;

    function 
    doMain() {
        
    main(1);
    }

    function 
    main(Manual) {
        if (
    getBarState() == BARSTATE_NEWBAR) {
            
    drawTextAbsolute(1020"Execute @URL=EFS:doMain"nullnull
                
    Text.BUTTON Text.CENTER Text.RELATIVETOLEFT Text.RELATIVETOBOTTOM
                
    null12"Btn1");
            if (
    getDay(0) != getDay(-1)) bNewDay true;
        }

        
        if (
    bNewDay == true || Manual == 1) {
            
    // Add your formula calcs here
            
    nCntr++;
            
    bNewDay false;
            if (
    Manual == 1debugPrintln("Manual Click " nCntr);
        }
        
        return 
    nCntr;

    This code is for use with a daily interval, but you can easily modify it for intra-day by just setting bNewDay to true on every instance of BARSTATE_NEWBAR. Try it out and let me know if you have any questions.

    2. This one isn't possible.
    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 Jason, I'll give it a try. Seems like some sort of overide to force calculation even though the bar has not closed would be a useful enhancement in the future. In the meantime, could you look at the below code. The problem seems to be that I am loading 27 bars of the high and low data and it apparently reloads every time a tick comes in. Perhaps I don't fully understand how to use the array functions.

      bigtee

      ----------

      var nFontAdj = 1.0; //adjust this as necessary so that text fits correctly
      var nLevels = 0; //text levels at this bar
      var grID = 0;
      var nFontSize = 12;
      var n2bardays = 20; // number days to look back for 2bar NR day
      var n3bardays = 25; // number days to look back for 3bar NR day

      function preMain() {
      setPriceStudy(true);
      setColorPriceBars(false);
      setStudyTitle("Crabel2");
      setShowCursorLabel(false);
      setComputeOnClose();
      grID = 0;
      }

      function main() {
      var vHigh = high();
      var vLow = low();
      var vPrevHigh = high(-1);
      var vPrevLow = low(-1);
      var vPrevHigh2 = high(-2);
      var vPrevLow2 = low(-2);

      nLevels = 0;

      if(vHigh == null || vLow == null || vPrevHigh == null || vPrevLow == null || vPrevHigh2 == null || vPrevLow2 == null) {
      return;
      }


      if (getInterval() == "D" || getInterval() == "W" || getInterval() == "M") {
      // check for NR7 or WR7 days.
      var vHigh = getValue("High", 0, -27); // must be two days longer than look back pd for nr 3 bar
      var vLow = getValue("Low", 0, -27);
      var i;

      NR7 = 0;
      NR4 = 0;
      NR2b = 0;
      NR3b = 0;


      //NR7 and NR4 days
      for(i = 0; i < 7; i++){
      if(i == 0)
      NR7 = vHigh[i] - vLow[i];
      else
      NR7 = Math.min(NR7, vHigh[i] - vLow[i]);
      }
      for(i = 0; i < 4; i++){
      if(i == 0)
      NR4 = vHigh[i] - vLow[i];
      else
      NR4 = Math.min(NR4, vHigh[i] - vLow[i]);
      }


      if(vHigh[0] - vLow[0] == NR7) {
      drawShapeAbsolute(getCurrentBarIndex(), high() + (NR4+nLevels*nFontAdj*NR4), Shape.DIAMOND, "", Color.red, Shape.TOP, getCurrentBarIndex());
      nLevels++;
      } else if(vHigh[0] - vLow[0] == NR4) {
      drawShapeAbsolute(getCurrentBarIndex(), high() + (NR4+nLevels*nFontAdj*NR4), Shape.DIAMOND, "", Color.blue, Shape.TOP, getCurrentBarIndex());
      nLevels++;
      }


      // Inside day symbol = I
      if ( high() < high(-1) && low() > low(-1) ) {

      drawTextRelative( 0, high() + (NR4+nLevels*nFontAdj*NR4), "I", Color.yellow, null, Text.ONTOP | Text.TOP | Text.CENTER | Text.BOLD, null,(nFontSize-2), gID() );
      nLevels++;
      }


      //2Bar NR day
      var v2brng = Math.max(vHigh[0],vHigh[1]) - Math.min(vLow[0],vLow[1]);

      for(i = 0; i < n2bardays; i++){
      if(i == 0)
      NR2b = Math.max(vHigh[i],vHigh[(i+1)]) - Math.min(vLow[i],vLow[(i+1)]);
      else
      NR2b = Math.min( NR2b, (Math.max(vHigh[i],vHigh[(i+1)]) - Math.min(vLow[i],vLow[(i+1)]) ) );
      }

      //3Bar NR day
      var v3brng = Math.max(vHigh[0],vHigh[1],vHigh[2]) - Math.min(vLow[0],vLow[1],vLow[2]);

      for(i = 0; i < n3bardays; i++){
      if(i == 0)
      NR3b = Math.max(vHigh[i],vHigh[(i+1)],vHigh[(i+2)]) - Math.min(vLow[i],vLow[(i+1)],vLow[(i+2)]);
      else
      NR3b = Math.min( NR3b, (Math.max(vHigh[i],vHigh[(i+1)],vHigh[(i+2)]) - Math.min(vLow[i],vLow[(i+1)],vLow[(i+2)]) ) );
      }


      if(v2brng == NR2b) {
      drawTextRelative( 0, high() + (NR4+nLevels*nFontAdj*NR4), "2", Color.yellow, null, Text.ONTOP | Text.TOP | Text.CENTER | Text.BOLD, null,(nFontSize-2), gID() );
      nLevels++;
      }

      if(v3brng == NR3b) {
      drawTextRelative( 0, high() + (NR4+nLevels*nFontAdj*NR4), "3", Color.yellow, null, Text.ONTOP | Text.TOP | Text.CENTER | Text.BOLD, null,(nFontSize-2), gID() );
      nLevels++;
      }


      }

      return;
      }

      // Support Functions

      //== gID function assigns unique identifier to graphic/text routines
      function gID() {
      grID ++;
      return( grID );
      }

      Comment


      • #4
        Hello bigtee,

        Just to clarify, your high and low arrays that get 27 bars of data are reinitialized every time the code is executed, but the formula itself does not reload every tick. Your formula should be fine the way it is especially if you incorporate the routine I previously described. Is there another specific problem you are trying to resolve?
        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
          So, do I understand correctly, that the high and low arrays get new data (reload themselves) every tick? When I first developed this I was only pulling 7 bars into the two arrays. When I went to 27 bars, it slowed down by factor of 4, which I guess it should, but now it is quite slow. That's why I asked the question, plus I want to understand

          Is there no way to avoid reloading the 26 previous bars every tick?

          I don't have any other problems, just trying to understand the use of arrays and efs better now that you have given me a routine to solve the speed problem.

          bigtee

          Comment


          • #6
            Hello bigtee,

            Your understanding of how your high a low arrays get established is correct. Here's another method you can use to avoid rebuilding the arrays on each tick.

            Make vHigh and vLow global variables by initializing them outside of main() with null values. Then add a nLength parameter to main, which we'll use to create the arrays with a specified size. You'll also need to change the names you are using to get the current high and low because we don't want to destroy the global arrays on each tick. We will still need to get the current high and low to update the [0] element of the global arrays.

            Next, add a check for BARSTATE_NEWBAR and apply a pop/unshift method to each array. The pop method removes the last element of the array and unshift inserts a new element to the front of the array. So, every time we process a new bar, we just insert the newest data to the [0] element and remove the oldest, which is no longer needed. During the interval, if you allow the code to execute that is, all we do is continue to update the [0] element of the array so it will contain the high and low values that are present at the close of the bar or interval. This routine allows us to maintain a fixed array size without reinitializing the entire array on each tick or execution of the formula.

            One last important thing to add is a null check on the last element of the arrays to make sure we have a completed array before we allow the rest of the formula to do its thing. What you do is check for null on the [nLength-1] element of the array, which is the last element. Arrays are always zero based. So if nLength is 27, the 27th element in the array would be vHigh[nLength-1] or vHigh[26].

            Take a look at the formula below and let me know if you have any questions.

            bigtee_Crabel2.efs
            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
              Jason,
              thanks for a very clear explanation of using arrays and the code. I put in your suggestions and they work. However it didn't speed up very much. Nonetheless the explanation is very much appreciated and helpful in understanding how arrays work.

              I have put the manual calc routine you supplied into use and the time used goes way down. However, I'm not 100% sure clicking the button causes a recalculation. I think the debugPrintln is supposed to print to the Formula Output window the number of times the calculation has occured, and the cursor is also supposed to show that, correct?

              Well, I get nothing in the Formula Output Window when I click the button. The Cursor label shows what is apparently the bar number on every bar except the current bar on which it shows <none>. Clicking the button does not change it.

              What am I missing? How can I be sure the manual button works when I click on it?

              Thanks,
              bigtee

              Comment


              • #8
                Hello bigtee,

                As I mentioned previously,

                The only catch is that the update on the chart may not be instantaneous after you click the button. The chart still needs to receive a tick to update the return values in the chart. On a fast market you wouldn't notice much delay.
                Is this the behavior you are seeing with your formula? You should see the result of a debugPrintln() statement instantaneously after a button click however. If you post your formula here, I'll take a look and see what the problem might be.
                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
                  Jason,
                  I get no output whatsoever for in the formula output window, even after several minutes. The Ave daily volume of this stock is 20M so there are plenty of ticks coming in.

                  The efs is below.

                  Also a question on your comment
                  The chart still needs to receive a tick to update the return values in the chart. On a fast market you wouldn't notice much delay.
                  This means at the end of the day, after the close and no more ticks are coming in, the efs will have to be manually updated, as it will not do it by itself until the next day, correct?

                  thanks
                  bigtee

                  /global variables
                  var nFontAdj = 1.0; //adjust this as necessary so that text fits correctly
                  var nLevels = 0; //text levels at this bar
                  var grID = 0;
                  var nFontSize = 12;
                  var n2bardays = 20; // number days to look back for 2bar NR day
                  var n3bardays = 25; // number days to look back for 3bar NR day

                  var vHigh = null; //initialize arrays outside of main with null values
                  var vLow = null;

                  function preMain() {
                  setPriceStudy(true);
                  setColorPriceBars(false);
                  setStudyTitle("Crabel 2 Man");
                  setCursorLabelName("Cntr");

                  //setShowCursorLabel(false);
                  //setComputeOnClose();
                  }

                  //added for manual recalc
                  var nCntr = 0;
                  var bNewDay = false;

                  function doMain() {
                  main(1);
                  }



                  function main(nLength,Manual) { //nLength must be 2 bars longer than n3bars.
                  // code for manual recalc
                  if (getBarState() == BARSTATE_NEWBAR) {
                  drawTextAbsolute(10, 20, "Execute @URL=EFS:doMain", null, null,
                  Text.BUTTON | Text.CENTER | Text.RELATIVETOLEFT | Text.RELATIVETOBOTTOM,
                  null, 12, "Btn1");
                  if (getDay(0) != getDay(-1)) bNewDay = true;
                  }


                  if (bNewDay == true || Manual == 1) {
                  // end code for manual recalc


                  if (nLength == null) nLength = 27;
                  if (vHigh == null) {
                  vHigh = new Array(nLength);
                  vLow = new Array(nLength);
                  }

                  if (getInterval() == "D" || getInterval() == "W" || getInterval() == "M") {
                  if (getBarState() == BARSTATE_NEWBAR) { // on each new bar shift the oldest out and newest in
                  vHigh.pop();
                  vHigh.unshift(0);
                  vLow.pop();
                  vLow.unshift(0);
                  }

                  var High = high(); // get current bar values to put in [0] array position as it is now empty
                  vHigh[0] = High;
                  var Low = low();
                  vLow[0] = Low;

                  nLevels = 0;

                  // If we don't have nLength days of data yet, return.
                  if (vHigh[nLength-1] == null && vLow[nLength-1] == null) return;

                  var i;
                  NR7 = 0;
                  NR4 = 0;
                  NR2b = 0;
                  NR3b = 0;

                  //check for NR7 and NR4 days
                  for(i = 0; i < 7; i++){
                  if(i == 0)
                  NR7 = vHigh[i] - vLow[i];
                  else
                  NR7 = Math.min(NR7, vHigh[i] - vLow[i]);
                  }
                  for(i = 0; i < 4; i++){
                  if(i == 0)
                  NR4 = vHigh[i] - vLow[i];
                  else
                  NR4 = Math.min(NR4, vHigh[i] - vLow[i]);
                  }

                  if(vHigh[0] - vLow[0] == NR7) {
                  drawShapeAbsolute(getCurrentBarIndex(), high() + (NR4+nLevels*nFontAdj*NR4), Shape.DIAMOND, "", Color.red, Shape.TOP, getCurrentBarIndex());
                  nLevels++;
                  } else if(vHigh[0] - vLow[0] == NR4) {
                  drawShapeAbsolute(getCurrentBarIndex(), high() + (NR4+nLevels*nFontAdj*NR4), Shape.DIAMOND, "", Color.blue, Shape.TOP, getCurrentBarIndex());
                  nLevels++;
                  }


                  // check for Inside day symbol = I
                  // if ( high() < high(-1) && low() > low(-1) ) {
                  if ( vHigh[0] < vHigh[1] && vLow[0] > vLow[1] ) {
                  drawTextRelative( 0, high() + (NR4+nLevels*nFontAdj*NR4), "I", Color.yellow, null, Text.ONTOP | Text.TOP | Text.CENTER | Text.BOLD, null,(nFontSize-2), gID() );
                  nLevels++;
                  }


                  //check for 2Bar NR day
                  var v2brng = Math.max(vHigh[0],vHigh[1]) - Math.min(vLow[0],vLow[1]);

                  for(i = 0; i < n2bardays; i++){
                  if(i == 0)
                  NR2b = Math.max(vHigh[i],vHigh[(i+1)]) - Math.min(vLow[i],vLow[(i+1)]);
                  else
                  NR2b = Math.min( NR2b, (Math.max(vHigh[i],vHigh[(i+1)]) - Math.min(vLow[i],vLow[(i+1)]) ) );
                  }

                  // check for 3Bar NR day
                  var v3brng = Math.max(vHigh[0],vHigh[1],vHigh[2]) - Math.min(vLow[0],vLow[1],vLow[2]);

                  for(i = 0; i < n3bardays; i++){
                  if(i == 0)
                  NR3b = Math.max(vHigh[i],vHigh[(i+1)],vHigh[(i+2)]) - Math.min(vLow[i],vLow[(i+1)],vLow[(i+2)]);
                  else
                  NR3b = Math.min( NR3b, (Math.max(vHigh[i],vHigh[(i+1)],vHigh[(i+2)]) - Math.min(vLow[i],vLow[(i+1)],vLow[(i+2)]) ) );
                  }


                  if(v2brng == NR2b) {
                  drawTextRelative( 0, high() + (NR4+nLevels*nFontAdj*NR4), "2", Color.yellow, null, Text.ONTOP | Text.TOP | Text.CENTER | Text.BOLD, null,(nFontSize-2), gID() );
                  nLevels++;
                  }

                  if(v3brng == NR3b) {
                  drawTextRelative( 0, high() + (NR4+nLevels*nFontAdj*NR4), "3", Color.yellow, null, Text.ONTOP | Text.TOP | Text.CENTER | Text.BOLD, null,(nFontSize-2), gID() );
                  nLevels++;
                  }
                  // more code for manual
                  nCntr++;
                  bNewDay = false;
                  if (Manual == 1) debugPrintln("Manual Click " + nCntr);
                  }

                  return nCntr;
                  }
                  /* }

                  return;*/
                  }

                  // Support Functions

                  //== gID function assigns unique identifier to graphic/text routines
                  function gID() {
                  grID ++;
                  return( grID );
                  }

                  Comment


                  • #10
                    Hello bigtee,

                    I have a fix for you, see attached. The reason you weren't seeing the formula update after the manual execute has to do with the parameters set up in function main. You have two parameters defined, main(nLength, Manual). Whenever you make a call to a function that is expecting parameters, you need to pass a value for each one in the order that they are defined in the function. In your doMain() function you were only passing one parameter, main(1). The main() function sees this as main(1, undefined). The 1 gets passed to the nLength parameter instead of Manual because it is the first value passed which corresponds to nLength. Since there is no value passed to main for Manual, the second parameter, main() assigns the undefined value to it. So Manual was never getting set to 1. The solution is to create global variables for any additional defined parameters in main so you can pass the current value for those along with the 1 for the Manual parameter. See lines 11 and 46. Your formula now has the global variable, nLengthGlobal, which will always be equal to the current value of nLength. In doMain, the call to main is now main(nLengthGlobal, 1). This retains the value for nLength and properly sets the value for Manual. Try it out and let me know if you have any questions.
                    Attached Files
                    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


                    • #11
                      Hi Jason,
                      Hope you had great time out of office.

                      I tried your solution and... well... I think it works but am not sure. The reason I'm not sure is that the efs is now a bigger resource hog than when we started. If you put it on a chart and let it run for a few minutes and then check the Performance Monitor you will get average time numbers like 26 or so. These are much larger than before we added the recalc button. I would expect that ave time would be low until you pushed the recalc button, then you would get a temp jump and then it would fall back. At the moment the idea of the recalc button would appear to be a bad one. Any ideas?

                      By the way, thanks again for your clear explanations. And as an aside, I took the concepts you supplied here earlier (not the recalc button part) and applied them to a bunch of my custom efs. I was able to cut the execution time on all but one down by a factor of 2-5 times. Thanks

                      bigtee

                      Comment


                      • #12
                        Hello bigtee,

                        If you're running the formula on a intraday interval and you don't have enough days of data loaded in your chart, you're probably getting stopped out by the conditional statement on line 69.

                        // If we don't have nLength days of data yet, return.
                        if (vHigh[nLength-1] == null && vLow[nLength-1] == null) return;

                        I was testing on a daily interval of INTC and it works fine. I also wasn't seeing the performance issue you described. I'm getting about .8 ms on average before and after clicking on the execute button. One thing that helps improve the efficiency is removing the debugPrintln statements. But they shouldn't be the culprit for 26+ ms average execution time. What symbol/interval/time template combo are you testing with?
                        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


                        • #13
                          Sorry about that last one. Finger problem.

                          I am running this on Daily chart only.
                          The Time period is Dynamic Daily. Symbol is SMH.
                          Actually I am using two instances of eSignal. Each instance has the SMH Daily chart. The two charts have different indicators.
                          I commented out the Printline stuff. It helped. When I put this efs on both of them, one of them now gives an average time of 16 and the other gives an average time of 50. Interestingly in both cases the Total Calles and Total Time time is virtually identical to the line for "System".

                          Ideas?

                          bigtee

                          Comment

                          Working...
                          X