Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

First Bar of Session issues using OnMarketData and OnRender

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

    First Bar of Session issues using OnMarketData and OnRender

    When using OnRender to draw values that are set by OnMarketData, I am not understanding how to deal with the first bar of the session. The example below sets a value of the mid price between the bid and the ask to be used in Tick Replay mode (calculated on each tick in Real time and Historical). See the question in the comments:

    Code:
            private Series<double> midSeries;
            private double tmpMid;
            private int activeBar = 0;
            private bool isFirstBarOfScript = true;
    
            protected override void OnBarUpdate()
            {
    
                if(CurrentBar < activeBar) return;
    
                //if this is the very first bar of the script, return so that OnMarketData can update a value into tmpMid, first
                if(isFirstBarOfScript)return;
    
                //if new bar
                if (CurrentBar > activeBar)
                {
                    //set tmpMid to it's last value known
                    tmpMid = midSeries[1];
    
                    //setting midSeries[0] = midSeries[1]; as shown below, creates inaccurate data on the first bar of the session
                    //This is especially evident when the market gaps.
                    //Since OnBarUpdate is called before OnMarketData, how can I get the mid point from OnMarketData
                    //If I just return from OnBarUpdate on the first tick of the day and wait for OnMarketData to be called,
                    //OnRender may try to get a value from midSeries[0] that is not there yet
                    //Since I am using the values of midSeries to draw from OnRender, and OnRender can be called
                    //at any time, this does not work.
                    //Is there a way to call OnMarketData from here? What is the normal approach to doing something like this?
                    midSeries[0] = midSeries[1];
    
    
                    activeBar = CurrentBar;
    
                }else{    
                    midSeries[0] = tmpMid;
                }
    
            }
    
            protected override void OnMarketData(MarketDataEventArgs e)
            {
                if (e.MarketDataType == MarketDataType.Last){
                    tmpMid = (e.Bid + e.Ask)/2;
    
                    //turn the first bar flag off
                    if(isFirstBarOfScript){                        
                        isFirstBarOfScript = false;
                    }
                }    
    
            }
    Last edited by swcooke; 03-10-2019, 02:02 PM.

    #2
    Hello swcooke,

    OnMarketData() will only trigger in real-time unless TickReplay is used. If TickReplay is used, OnMarketData() can trigger before the first bar updates OnBarUpdate if Calculate is OnBarClose.

    If Calculate is OnEachTick, OnMarketData() should always trigger after OnBarClose() in real-time or historical. In which case, Bars.IsFirstBarOfSession will be true because OnBarUpdate() triggered first.
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      I have Tick Replay enabled and I am set to Calculate.OnEachTick. I am aware of what you've explained but based on my example, the explanation does not solve anything. Am I missing a design pattern here? Should I be doing all of this in OnMarketData and leave OnBarUpdate empty? If you wanted to calculate the mid price between the bid and the ask in real time and historically using every update available, is this the approach you'd take? Keep in mind, this is just an example for support but eventually, I'd like to store the bid/ask updates to study them on each bar. I want to build an Indicator that measures certain things about the bid/ask updates.

      Comment


        #4
        Hello swcooke,

        To confirm, your question is:

        "Since OnBarUpdate is called before OnMarketData, how can I get the mid point from OnMarketData"

        Is this correct?

        What are you considering the mid point of OnMarketData?

        If you want to use a value from OnMarketData in OnBarUpdate() you can set this to a variable and then wait for the next tick. This would be the same in real-time as historical with TickReplay.

        The BuySellVolume indicator plots information from OnMarketData() and works with Tick Replay and is always 1 tick behind OnBarUpdate().
        https://ninjatrader.com/support/help...#BuySellVolume
        Last edited by NinjaTrader_ChelseaB; 03-11-2019, 07:45 AM.
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Can you take another look at my questions in the comments? The issue is that since OnBarUpdate is called first, how can I get the mid when it's the very first update of OnBarUpdate of a new session? If I use the tick before, I will be using the value from the last update of the previous session. Are you suggesting I return from OnBarUpdate if it's the first tick of the session? If so, is there a built in way to check if OnBarUpdate is being called for the very first update of the first bar of a new session?
          Last edited by swcooke; 03-11-2019, 09:45 AM.

          Comment


            #6
            Hello swcooke,

            When you mention:
            "Can you take another look at my questions in the comments?"

            Are you referring to the question:
            "Since OnBarUpdate is called before OnMarketData, how can I get the mid point from OnMarketData"

            I was not able to confirm, what are you considering the mid?

            Any script that is using OnMarketData will need to update 1 tick behind.

            You can print the time of each tick along with Bars.IsFirstBarOfSession to demonstrate that the first tick received after the open of a new session does trigger OnBarUpdate for that tick.
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              The code shows the tmpMid being set in the OnMarketData section as the mid point between the bid and the ask as follows:

              Code:
                       protected override void OnMarketData(MarketDataEventArgs e)
                      {
                           if (e.MarketDataType == MarketDataType.Last){
                              tmpMid = (e.Bid + e.Ask)/2;
              
                              //turn the first bar flag off
                              if(isFirstBarOfScript){  
                                  isFirstBarOfScript = false;
                              }  
                        }        
                   }

              Comment


                #8
                Hello swcooke,

                The tmpMid variable is set after a last event in OnMarketData. The set value can be used on the next update of OnBarUpdate().
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  I don't think you are understanding. I know I can do that. But when I do, and the market gaps, the first tick of a new session (which should be the mid point of the bid and the ask) is instead using the mid point of the bid and the ask from the tick prior (which was yesterdays closing value of the series) so any indicator that tries to use the value does not work. I believe all of this was conveyed in the code example in my first post.

                  Comment


                    #10
                    Hello swcooke,

                    OnMarketData() triggers after OnBarUpdate(). Just like with the BuySellVolume indicator, it updates one tick behind since it is relying on OnMarketData() to trigger before it can plot in OnBarUpdate.

                    You will need to wait until the second tick in OnBarUpdate when you have a value set from OnMarketData()
                    Chelsea B.NinjaTrader Customer Service

                    Comment


                      #11
                      Chelsea,

                      I try really hard to rebuild my examples so they only demonstrate the issue using as little code as possible. I believe the issue is demonstrated really well in my very first post which is what I strive for. Perhaps you and I are just not understanding each other as to what the issue is or even if there is one. Is it possible to ask Jim to take a look at my example? The questions are in the comments of the code sample and the issue is that the code example uses the previous days value on the opening bar of the following day. My other concern is that I shouldn't be using OnBarUpdate at all (or using it less). I was hoping for some suggestions, not just about the issue I presented, but also about whether this programming pattern is the way a more experienced NT programmer would do it (like yourselves). Thank you for your help.

                      Comment


                        #12
                        Hello swooke,

                        Plots should be set in OnBarUpdate since that is when we have clear context for bar slots associated with the primary data series. This would be a best practice for organization purposes. Your goal is to update the developing plot in OnMarketData instead of OnBarUpdate, so updating Buys[0] and Sells[0] at the end of the OnMarketData code in a Last event block.

                        You could do the following in an effort to have the plot update more visually correct, but the matter still remains: We are updating the plot after the OnBarUpdate for that tick, and we will always be 1 tick behind if we are referencing the indicator's developing plots Buys[0] and Sells[0] from other scripts.

                        Code:
                        protected override void OnMarketData(MarketDataEventArgs e)
                        {
                            if(e.MarketDataType == MarketDataType.Last)
                            {
                                if(e.Price >= e.Ask)
                                    buys += (Instrument.MasterInstrument.InstrumentType == Cbi.InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume(e.Volume) : e.Volume);
                                else if (e.Price <= e.Bid)
                                    sells += (Instrument.MasterInstrument.InstrumentType == Cbi.InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume(e.Volume) : e.Volume);
                        
                                Sells[0] = sells;
                                Buys[0] = buys + sells;
                            }
                        }
                        
                        protected override void OnBarUpdate()
                        {
                            if (CurrentBar < activeBar || CurrentBar <= BarsRequiredToPlot)
                                return;
                        
                            // New Bar has been formed
                            // - Assign last volume counted to the prior bar
                            // - Reset volume count for new bar
                            if (CurrentBar != activeBar)
                            {
                                Sells[1] = sells;
                                Buys[1] = buys + sells;
                                buys = 0;
                                sells = 0;
                                activeBar = CurrentBar;
                            }
                        
                        }
                        I have included a demonstration explaining further.

                        Demo - https://drive.google.com/file/d/1QMW...w?usp=drivesdk

                        Let us know if you have any additional questions.
                        JimNinjaTrader Customer Service

                        Comment

                        Latest Posts

                        Collapse

                        Topics Statistics Last Post
                        Started by GLFX005, Today, 03:23 AM
                        1 response
                        6 views
                        0 likes
                        Last Post NinjaTrader_Erick  
                        Started by nandhumca, Yesterday, 03:41 PM
                        1 response
                        12 views
                        0 likes
                        Last Post NinjaTrader_Gaby  
                        Started by The_Sec, Yesterday, 03:37 PM
                        1 response
                        11 views
                        0 likes
                        Last Post NinjaTrader_Gaby  
                        Started by vecnopus, Today, 06:15 AM
                        0 responses
                        1 view
                        0 likes
                        Last Post vecnopus  
                        Started by Aviram Y, Today, 05:29 AM
                        0 responses
                        5 views
                        0 likes
                        Last Post Aviram Y  
                        Working...
                        X