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

When can I access ChartPanel?

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

    When can I access ChartPanel?

    I'm writing a small demo program to help me explore when various data items are available. Any attempt to access ChartPanel gets the following error message, regardless of State (I have tried access during Historical, Transition, and Realtime):

    Indicator 'Vsa_Demo_GetInformation': Error on calling 'OnStateChange' method: The calling thread cannot access this object because a different thread owns it.​
    All I am doing is trying to print ChartPanel.Name, just to establish that I can access it. Is there something I need to be careful of?

    #2
    Update: further testing shows ChartPanel is:
    • null in State=Configure
    • available in State=Dataloaded
    • thread problem from Historical onward
    I guess I have answered my own question: if you want to access it, do so in Dataloaded.

    Am I correct that Dataloaded is the only state where you can access it, or am I missing something?

    Comment


      #3
      Hello ETFVoyageur,

      Thanks for your post.

      The error "The calling thread cannot access this object because a different thread owns it" occurs when attempting to access a UI element from a thread that did not create it.

      In WPF, UI elements can only be accessed by the thread that created them.

      To resolve this, you can use a Dispatcher in the script.

      For example:

      if (ChartControl != null)
      {
      ChartControl.Dispatcher.InvokeAsync(() =>
      {
      // Your code here.
      });
      }


      See this help guide page for more information about Multi-Threading Consideration for NinjaScript: https://ninjatrader.com/support/help...-threading.htm

      See this help guide page for more information about ChartPanel: https://ninjatrader.com/support/help...chartpanel.htm
      Brandon H.NinjaTrader Customer Service

      Comment


        #4
        The error "The calling thread cannot access this object because a different thread owns it" occurs when attempting to access a UI element from a thread that did not create it.
        I don't understand that ... note that it is a system object and, as my follow-up post said, I was able to access it in State=DataLoaded. My inability to access was from Historical onward. The facts that I could access it in DataLoaded and that it is a normal system object make me question whether ownership is the issue. What changed after my successful access in DataLoaded? Aren't indicators supposed to access it from Historical onward?

        Comment


          #5
          Hello ETFVoyageur,

          Thanks for your notes.

          When State.Historical processes that would now be on the market data processing thread with OnBarUpdate().

          If you need the name when the script starts you should call the code in OnStateChange() when the State == State.DataLoaded.

          For any other location, you would need to use a Dispatcher, such as ChartControl.Dispatcher, to prevent the error message from occurring which would get the name after the code which follows the Dispatcher at a later time.

          if (ChartControl != null)
          {
          ChartControl.Dispatcher.InvokeAsync(new Action(() =>
          {
          //Place your code here
          }));
          }


          See this help guide page for more information about Multi-Threading Consideration for NinjaScript: https://ninjatrader.com/support/help...-threading.htm
          Brandon H.NinjaTrader Customer Service

          Comment


            #6
            Thanks, Brandon. Is there a limitation on what the code I pass could be? The following code did not get a thread violation,but it also did not print anything. (Note: it was ChartPanel with the thread violation.

            Code:
            if(ChartPanel != null) {
                 ChartPanel.Dispatcher.InvokeAsync(() => { DoPrint($"{ID}ChartPanel={ChartPanel}"); });
            }
            ​
            Last edited by ETFVoyageur; 05-20-2024, 04:20 PM.

            Comment


              #7
              Hello ETFVoyageur,

              Can you provide more details on what you are trying to accomplish with the ChartPanel object? The ChartPanel.Name is not documented so I am unsure if that would print anything. In the latest post you are printing a variable named ID and the ChartPanel object its self, that may not print anything if ChartPanel does not have a defined result for its ToString() method.



              The code you posted otherwise works to dispatch the code inside the dispatcher to the chart panel.
              JesseNinjaTrader Customer Service

              Comment


                #8
                Hello ETFVoyageur,

                The ChartPanel is available in State.DataLoaded, State.Historical, and State.Realtime from OnStateChange() and after as this is when the script is running, and only if the ChartControl is not null (such as on the Strategies tab of the Control Center, Strategy Analyzer, or MarketAnalyzer).

                Use Print() to print to the NinjaTrader output window from an indicator.


                Try printing to check if the ChartPanel is null.
                if (ChartPanel == null)
                Print("Chart panel is null");

                A ChartControl.Dispatcher.InvokeAsync() is necessary as the UI runs on a different thread than the NinjaScript thread.

                Ownership would not be an issue.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Jesse,

                  Accomplish -- just a demo indicator for myself to explore what is available when.

                  Information -- the exact same DoPrint() statement worked fine in State=Dataloaded. It printed:
                  Code:
                  (#4) Vsa_Demo_GetInformation:DataLoaded           ChartPanel=Panel: Index=0 #[B=1;I=5;S=0;D=0] min=401.861843636365 max=539.027429090889
                  (​
                  Lambda -- to avoid extraneous confusion I changed the line as follows and still got nothing printed:
                  Code:
                  ChartPanel.Dispatcher.InvokeAsync(() => { Print ("Got here"); });
                  ​
                  Chelsea,
                  The ChartPanel is available in State.DataLoaded, State.Historical, and State.Realtime from OnStateChange()
                  This is from State=Historical.

                  and only if the ChartControl is not null (such as on the Strategies tab of the Control Center, Strategy Analyzer, or MarketAnalyzer).
                  This is an indicator on a chart. Although not shown in the code I showed you, I did check for ChartControl being non-null. The code I did show you also checks for ChartPanel being non-null, and there is no problem calling its Dispatcher (other than the lambda not printing).

                  Use Print() to print to the NinjaTrader output window from an indicator.
                  I did. DoPrint() just checks a bool to see whether printing is enabled and then calls Print()

                  Try printing to check if the ChartPanel is null.
                  if (ChartPanel == null)
                  Print("Chart panel is null");​
                  I just added that and it is not null -- no surprise since it was not null in earlier states.

                  A ChartControl.Dispatcher.InvokeAsync() is necessary as the UI runs on a different thread than the NinjaScript thread.
                  I tried the print statement without the thread protection and got a thread violation. Jesse, earlier in this thread, was not surprised and suggested using the Dispatcher. I am just trying to understand why a simple Print statement does not work that way. ("{ Print ("Got here"); });")

                  Comment


                    #10
                    Hello ETFVoyageur,

                    Where are you executing that code from?

                    I tried that code in State.Historical and see a Print, is it possible something is happening wrong in your custom DoPrint method?

                    Code:
                    else if (State == State.Historical)
                    {
                        if(ChartPanel != null) {
                          ChartPanel.Dispatcher.InvokeAsync(() => { Print("Here"); });
                       }
                    }​
                    It is still not clear what your end goal is here for using ChartPanel, what are you trying to do with the ChartPanel? You may not need a dispatcher and may just need to approach the problem in a different way.

                    The dispatcher is only needed if you are trying to access the ChartPanel from a different thread from which it resides, generally ChartPanel is not used at all from OnBarUpdate or OnStateChange but is referenced in OnRender for rendering purposes which does not require dispatching. For example the sample named " Using a static SharpDX Brush to render a rectangle on the chart panel"

                    https://ninjatrader.com/support/help...8/onrender.htm
                    JesseNinjaTrader Customer Service

                    Comment


                      #11
                      is it possible something is happening wrong in your custom DoPrint method?
                      The update I supplied, and is in the code sample you quote, uses just Print() precisely to avoid that concern. That still does not print.

                      It is still not clear what your end goal is here for using ChartPanel
                      My only goal is to explore what is available and when. If the answer is that accessing ChartPanel from Historical is not an approved usage, then fine. That would not cause me any problem; I just want to know.

                      I'm still curious why Print("Here") does not print, but that is nothing critical for me ... mainly curious because I am not used to async dispatch and its lambdas. An educational matter for me, not a business problem.
                      Last edited by ETFVoyageur; 05-21-2024, 01:14 PM.

                      Comment


                        #12
                        Hello ETFVoyageur,

                        I've tested the code Jesse has suggested and the print is appearing in the output window.

                        Below is a link to a video.


                        Attached is the test script.
                        ChartPanelDispatcherPrintTest_NT8.zip

                        Without modifying the test script, open the NinjaScript Output Window, then add the indicator to a chart.

                        Is the behavior different than what is shown in the video?
                        Chelsea B.NinjaTrader Customer Service

                        Comment


                          #13
                          Chelsea,

                          Thanks for all of your effort. I appreciate what you do.
                          • I watched the video and it does demonstrate the code working as it should.
                          • I imported your zip file, loaded it onto my chart, and that also works as it should.
                          • I cut-and-pasted your async line into my indicator, as you can see in the code below.
                          • You can also see that my own code line is exactly the same as yours, other than slightly different text.
                          Code:
                          else if (State == State.Historical)
                          {​
                          DoPrint($"{ID}ChartPanel is no longer directly available (thread violation) -- using async access");
                          ​if (ChartPanel != null) {
                               //ChartPanel.Dispatcher.InvokeAsync(() => { DoPrint($"{ID}ChartPanel={ChartPanel}"); });
                               Print($"{ID}Just before doing the dispatch");
                               ChartPanel.Dispatcher.InvokeAsync(() => { Print ("Got here"); });
                               ChartPanel.Dispatcher.InvokeAsync(() => { Print("Here"); });
                          }
                          else
                          {
                                DoPrint($"{ID}ChartPanel is null");
                          }
                          DoPrint($"{ID}Instrument={Instrument}");
                          ...
                          }
                          ​
                          The problem is that when I run it, I get the following.
                          Code:
                          (#4) Vsa_Demo_GetInformation:Historical           ChartPanel is no longer directly available (thread violation) -- using async access
                          (#4) Vsa_Demo_GetInformation:Historical           Just before doing the dispatch
                          (#4) Vsa_Demo_GetInformation:Historical           Instrument=SPY Default
                          ​
                          As you can see, the code got to the async statements, but I got no print from them.

                          If you have any suggestions, I'd like to hear them. Other than that, it looks like my problem and not yours. You have shown that the construct works. Now I need to figure out why not when put into my indicator. Any ideas?
                          Last edited by ETFVoyageur; 05-21-2024, 02:35 PM.

                          Comment


                            #14
                            Hello ETFVoyageur,

                            Is an issue with your custom method?

                            Try calling Print();
                            Chelsea B.NinjaTrader Customer Service

                            Comment


                              #15
                              Yes, I am using lots of Print() statements. As the output above shows, I print just before and after the async calls, but the async does not print. Since we know that the async code is correct (it works in your examples) my more complicated example must somehow be interfering.

                              I'll chase that down, but first I'm going to use SharpDX to address the fill issue we talked about in another thread.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by sofortune, Today, 02:31 AM
                              0 responses
                              7 views
                              0 likes
                              Last Post sofortune  
                              Started by sofortune, Today, 01:55 AM
                              1 response
                              5 views
                              0 likes
                              Last Post sofortune  
                              Started by cls71, Today, 01:37 AM
                              0 responses
                              8 views
                              0 likes
                              Last Post cls71
                              by cls71
                               
                              Started by WHICKED, 06-27-2023, 12:07 PM
                              63 responses
                              764 views
                              1 like
                              Last Post Leeroy_Jenkins  
                              Started by rtwave, Today, 12:10 AM
                              0 responses
                              6 views
                              0 likes
                              Last Post rtwave
                              by rtwave
                               
                              Working...
                              X