Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Index of Last Complete Bar

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

    Index of Last Complete Bar

    When building indicators, especially ones with high computations, its best if the indicator only calculates when its needed. The indicator may be designed with Calculate.OnBarClose in mind but when it is used by another indicator that is Calculate.OnEachTick, it will be updated as often as the parent indicator. This will result in a lot more calculations then may be desired.

    OnBarUpdate can have two execution behaviors.
    1. Calculate == Calculate.OnBarClose
      or
      Calculate == Calculate.OnEachTick && State == State.Historical && IsTickReplays[0] == null || IsTickReplays[0].Value == false

      Under these conditions, IsFirstTickOfBar == true for each execution, and the CurrentBar references the last complete bar. 0 bars ago also refers to the last complete bar.
    2. Calculate == Calculate.OnEachTick
      and
      State == State.Realtime || State == State.Historical && IsTickReplays[0].Value == true

      Under these conditions. IsFirstTickOfBar == true only when it’s the first tick of a bar. CurrentBar - 1 refers to the last complete bar. 1 bars ago also refers to the last complete bar.
    I created the following class that makes it easy to calculate.

    Code:
    class LastCompleteBarTracker
    {
        public LastCompleteBarTracker(Indicator indicator)
        {
            this.indicator = indicator;
    
            lastCompleteBar = Enumerable.Repeat(-1, indicator.BarsArray.Length).ToArray();
        }
    
        public int this[int index]
        {
            get { return lastCompleteBar[index]; }
        }
    
        public int BarsAgo(int barsInProgress)
        {
            return indicator.CurrentBar - lastCompleteBar[barsInProgress];
        }
    
        public int BarsAgo()
        {
            return BarsAgo(indicator.BarsInProgress);
        }
    
        public void OnBarUpdate()
        {
            if(indicator.IsFirstTickOfBar)
            {
                var barsInProgress = indicator.BarsInProgress;
    
                if(indicator.Calculate == Calculate.OnBarClose)
                {
                    lastCompleteBar[barsInProgress] = indicator.CurrentBars[barsInProgress];
                }
                else
                {
                    if(indicator.State == State.Realtime ||
                        indicator.IsTickReplays[barsInProgress].HasValue && indicator.IsTickReplays[barsInProgress].Value)
                    {
                        lastCompleteBar[barsInProgress] = indicator.CurrentBars[barsInProgress] - 1;
                    }
                    else
                    {
                        lastCompleteBar[barsInProgress] = indicator.CurrentBars[barsInProgress];
                    }
                }
            }
        }
    
        Indicator indicator;
    
        int[] lastCompleteBar;
    }

    To use it

    Code:
    public class MyIndicator: Indicator
    {
        protected override void OnStateChange()
        {
            switch(State)
            {
                case State.SetDefaults:
                    // Set your defaults:
                    break;
                case State.DataLoaded:
                    lastCompleteBar = new LastCompleteBarTracker(this);
                    break;
            }
        }
    
        protected override void OnBarUpdate()
        {
            lastCompleteBar.OnBarUpdate();
    
            var theLastCompleteBar = lastCompleteBar[BarsInProgress];
    
            var lastClose = Close[lastCompleteBar.BarsAgo()];
        }
    
        LastCompleteBarTracker lastCompleteBar;
    }
    For a 5 second chart of AAPL

    If Calculate == Calculate.OnEachTick and tick replay is off, this is how OnBarUpdate, executes

    Code:
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = 0, Close = 143.28 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 1, Close = 143.23 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 2, Time = 1/26/2021 15:59:25, LastCompleteBar = 2, Close = 143.23 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 3, Time = 1/26/2021 15:59:30, LastCompleteBar = 3, Close = 143.28 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 4, Time = 1/26/2021 15:59:35, LastCompleteBar = 4, Close = 143.28 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 5, Time = 1/26/2021 15:59:40, LastCompleteBar = 5, Close = 143.3 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 6, Time = 1/26/2021 15:59:45, LastCompleteBar = 6, Close = 143.31 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 7, Time = 1/26/2021 15:59:50, LastCompleteBar = 7, Close = 143.28 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 8, Time = 1/26/2021 15:59:55, LastCompleteBar = 8, Close = 143.26 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 9, Time = 1/26/2021 16:00:00, LastCompleteBar = 9, Close = 143.19 IsFirstTickOfBar
    If Calculate == Calculate.OnEachTick and tick replay is on

    Code:
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.2 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.21
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.21
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.21
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.21
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.21
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.22
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.22
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.22
    OnBarUpdate CurrentBar = 0, Time = 1/26/2021 15:59:15, LastCompleteBar = -1, Close = 143.22
    ...
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.28 IsFirstTickOfBar
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.27
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.27
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.28
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.28
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.26
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.26
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.26
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.26
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.26
    OnBarUpdate CurrentBar = 1, Time = 1/26/2021 15:59:20, LastCompleteBar = 0, Close = 143.26
    There was a lot more output for this mode so its been trimmed to show the beginnings of two bars.
    Last edited by ntbone; 02-06-2021, 03:56 PM.

    #2
    Hello ntbone,

    Thank you for sharing this solution!

    As a heads up, NinjaTrader does not directly support hosted scripts using a different Calculate setting than the host script, and may lead to unexpected behavior. Use as your own discretion.

    The official supported structure is for the Calculate setting to be inherited by the hosted script from the host, even if this results in higher resource use.
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      My understanding, and observation is that yes, hosted scripts use the parent scripts Calculate field. This is why I calculate the LastCompleteBar. It allows me to create an indicator that only ever offers and calculates on a complete bar, even in situations where it is hosted by a script with Calculate.OnEachTick.

      Comment

      Latest Posts

      Collapse

      Topics Statistics Last Post
      Started by Geovanny Suaza, 02-11-2026, 06:32 PM
      0 responses
      576 views
      0 likes
      Last Post Geovanny Suaza  
      Started by Geovanny Suaza, 02-11-2026, 05:51 PM
      0 responses
      334 views
      1 like
      Last Post Geovanny Suaza  
      Started by Mindset, 02-09-2026, 11:44 AM
      0 responses
      101 views
      0 likes
      Last Post Mindset
      by Mindset
       
      Started by Geovanny Suaza, 02-02-2026, 12:30 PM
      0 responses
      553 views
      1 like
      Last Post Geovanny Suaza  
      Started by RFrosty, 01-28-2026, 06:49 PM
      0 responses
      551 views
      1 like
      Last Post RFrosty
      by RFrosty
       
      Working...
      X