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

Reading indicator from chart instance within strategy

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

    Reading indicator from chart instance within strategy

    I have strategy which reads value from indicators hosted on a chart.

    An indicator is declared at class level within the strategy for example: private GomiLadderIntegratedYMRealtime myTickReplayIndicatorYM = null;

    This variable is then set using the following code in the State == State.DataLoaded


    foreach (var x in ChartControl.Indicators)
    {

    if (x.Name == "GomiLadderIntegratedYMRealtime")
    {
    myTickReplayIndicatorYM = (GomiLadderIntegratedYMRealtime)x;
    myTickReplayIndicatorYM.IsSuspended = false;


    }

    }


    This then allows access to the properties of the indicator as the strategy is running in real time.

    This mechanism works however there is an intermittent error that occurs which seems to be fixed after refreshing the chart once or twice which indicates the compiler is having trouble matching the variable declared in the strategy to the object [indicator] of the same type :
    [B]YMInfinity3EngineRealtimeCalculateAzureMLNet2: State == State.DataLoaded [A]NinjaTrader.NinjaScript.Indicators.GomiLadderInteg ratedYMRealtime cannot be cast to
    NinjaTrader.NinjaScript.Indicators.GomiLadderInteg ratedYMRealtime. Type A originates from 'NinjaTrader.Custom, Version=8.0.24.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'C:\Users\DESKTOP-B322BQ3\Documents\NinjaTrader 8\bin\Custom\NinjaTrader.Custom.dll'. Type B originates from 'f48d05ceef0445478bdd9f83fcbed491, Version=8.0.24.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'C:\Users\DESKTOP-B322BQ3\Documents\NinjaTrader 8\tmp\f48d05ceef0445478bdd9f83fcbed491.dll'.
    Would it be preferable to instantiate the indicator at code level only rather than hosting on the chart to avoid this issue? This means however that any graphics generated by the child indicator will not be displayed on the chart directly but could be done via the strategy.

    #2
    Hello mballagan,

    Thank you for your post.

    Conflicts with separate DLLs would be something that could be addressed with dynamic type:



    If you're still having trouble, we would want to see a test script that uses a DLL built with a dummy indicator that reproduces this error that you could share the source code of.

    Thanks in advance; I look forward to assisting you further.
    Kate W.NinjaTrader Customer Service

    Comment


      #3
      Thanks for your reply. I tried the following code based on the sample:


      if (State == State.DataLoaded)
      {
      foreach (dynamic dt in ChartControl.Indicators)
      {

      if (dt.ToString() == "GomiLadderIntegratedYMRealtime")
      {

      myTickReplayIndicatorYM = (GomiLadderIntegratedYMRealtime)dt;
      myTickReplayIndicatorYM.IsSuspended = false;
      Log("dynamic all ok:" + dt.ToString(),LogLevel.Information);


      }

      }


      }

      However the variable myTickReplayIndicatorYM appears to have a null value when I try to access it in the OnBarUpdate() method. This also occurs without the explicit cast using myTickReplayIndicatorYM = dt in DataLoaded.




      protected override void OnBarUpdate()
      {

      if(State != State.Historical)
      {
      try
      {


      if(myTickReplayIndicatorYM != null)
      {
      Log("myTickReplayIndicatorYM != null",LogLevel.Information);

      }
      else
      {
      Log("myTickReplayIndicatorYM == null",LogLevel.Information);

      }



      }
      catch(Exception ex)
      {

      Log("myTickReplayIndicatorYM :" + ex.Message,LogLevel.Information);

      }


      }
      }


      Please advise thanks.

      Comment


        #4
        Hello mballagan,

        Thank you for your reply.

        You'd likely need to use a dispatcher since the ChartControl is likely on another thread:

        https://ninjatrader.com/support/help...-threading.htm

        Something that we noticed is that you're casting the dynamic type back to GomiLadderIntegratedYMRealtime when if you are using dynamic, you should just reference any properties as if the dynamic type was the type of your object.

        For example:

        Code:
        foreach (NinjaTrader.Gui.NinjaScript.IChartObject thisObject in myObjects.ToList())
        {
        Print(thisObject.ToString());
        if(thisObject.ToString().Equals("NinjaTrader.Ninja Script.DrawingTools.HorizontalLine"))
        {
        Print((thisObject as dynamic).StartAnchor.Price.ToString());
        }
        }
        I'd also suggest you stop using Log() for debugging and instead use Print(), and save the prints to a text file so we can see what's happening in that loop.

        To summarize:

        1. Use Dispatcher to access ChartControl if you are doing it from DataLoaded
        2. Use Prints to see what is null and to check the full namespace of your Gomi indicator
        3. Once you find the indicator in your loop, then cast to dynamic, and then reference property of that indicator as if it were not using dynamic

        Please let us know if we may be of further assistance to you.



        Last edited by NinjaTrader_Kate; 03-03-2021, 11:53 AM.
        Kate W.NinjaTrader Customer Service

        Comment


          #5
          Thanks for your reply. I have modified the code as follows in the dataloaded event:

          else if (State == State.DataLoaded)
          {

          if (ChartControl != null)
          {
          // add some text to the UserControlCollection through the ChartControls dispatcher
          ChartControl.Dispatcher.InvokeAsync(new Action(() => {


          foreach (dynamic dt in ChartControl.Indicators)
          {

          if (dt.GetType().ToString() == "NinjaTrader.NinjaScript.Indicators.GomiLadderInte gratedYMRealtime")
          {

          myTickReplayIndicatorYM = dt;
          myTickReplayIndicatorYM.IsSuspended = false;



          }

          }



          }));
          }




          }


          Then can access the variable in OnBarUpdate as follows: var signals = myTickReplayIndicatorYM.GomiSignals; This now works.

          Comment


            #6
            Originally posted by NinjaTrader_Kate View Post
            Hello mballagan,

            Thank you for your reply.

            You'd likely need to use a dispatcher since the ChartControl is likely on another thread:

            https://ninjatrader.com/support/help...-threading.htm

            Something that we noticed is that you're casting the dynamic type back to GomiLadderIntegratedYMRealtime when if you are using dynamic, you should just reference any properties as if the dynamic type was the type of your object.

            For example:

            Code:
            foreach (NinjaTrader.Gui.NinjaScript.IChartObject thisObject in myObjects.ToList())
            {
            Print(thisObject.ToString());
            if(thisObject.ToString().Equals("NinjaTrader.Ninja Script.DrawingTools.HorizontalLine"))
            {
            Print((thisObject as dynamic).StartAnchor.Price.ToString());
            }
            }
            I'd also suggest you stop using Log() for debugging and instead use Print(), and save the prints to a text file so we can see what's happening in that loop.

            To summarize:

            1. Use Dispatcher to access ChartControl if you are doing it from DataLoaded
            2. Use Prints to see what is null and to check the full namespace of your Gomi indicator
            3. Once you find the indicator in your loop, then cast to dynamic, and then reference property of that indicator as if it were not using dynamic

            Please let us know if we may be of further assistance to you.


            I have created a new strategy where an indicator is declared at class level:

            private MESSignalMTF9XZMERGETEST1XZR8SPM3StrategyRealtimeE ngine mestick;

            As previously I use a dynamic variable in the DataLoaded section to instantiate the variable:

            else if(State == State.DataLoaded)
            {
            if (ChartControl != null)
            {


            // add some text to the UserControlCollection through the ChartControls dispatcher
            ChartControl.Dispatcher.InvokeAsync(new Action(() =>
            {


            foreach (dynamic dt in ChartControl.Indicators)
            {
            try
            {


            if (dt.GetType().ToString() == "NinjaTrader.NinjaScript.Indicators.MESSignalM TF9X ZMERGETEST1XZR8SPM3StrategyRealtimeEngine")
            {
            mestick =dt;
            mestick.IsSuspended = false;

            Print("dynamic all ok:" + dt.ToString());





            }

            }
            catch(Exception ex)
            {
            Print("dynamic not all ok:" + ex.Message + " stacktrace: " +ex.StackTrace );

            }



            }





            }));
            }


            }

            This should work but the following exception occurs: Please advise thanks.

            dynamic not all ok:An unexpected exception occurred while binding a dynamic operation stacktrace: at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind( DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
            at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(D ynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
            at Microsoft.CSharp.RuntimeBinder.CSharpConvertBinder .FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
            at System.Dynamic.DynamicMetaObject.BindConvert(Conve rtBinder binder)
            at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
            at System.Runtime.CompilerServices.CallSiteBinder.Bin dCore[T](CallSite`1 site, Object[] args)
            at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
            at NinjaTrader.NinjaScript.Strategies.ESRenkoTickSign alStrategyRealtimeEngine.<OnStateChange>b__9()


            Comment


              #7
              Hello mballagan,

              Thank you for your reply.

              At runtime dynamic will try to guess what type to use. Since indicators can reside in multiple assemblies (especially ones that are base indicators), there is ambiguity and that is why it will fail.

              If you compile as an indicator as a DLL and try to access something from it when using dynamic type, there's a good chance you'll hit an error like this if the original is still on the system.

              In this case, you don't need a dispatcher because that code's not accessing a different thread. Try something like this:

              Code:
              else if(State == State.DataLoaded)
              {
                   if (ChartControl != null)
                   {
              
                       foreach (IndicatorBase dt in ChartControl.Indicators)
                       {
                            try
                            {
              
                                  if (dt.ToString() == "NinjaTrader.NinjaScript.Indicators.MESSignalMTF9X ZMERGETEST1XZR8SPM3StrategyRealtimeEngine")
                                  {
                                       dt.IsSuspended = false;
                                       Print(dt.IsSuspended);
                                       Print("dynamic all ok:" + dt.ToString());
              
                                   }
              
                             }
                            catch(Exception ex)
                            {
                                   Print("dynamic not all ok:" + ex.Message + " stacktrace: " + ex.StackTrace );
              
                            }
              
                       }
                   }
              
              }
              IndicatorBase is a common base class that is not mixed between different assemblies so you can use that to get standard indicator properties, where dynamic would fail.

              Please let us know if we may be of further assistance to you.
              Kate W.NinjaTrader Customer Service

              Comment


                #8
                Originally posted by NinjaTrader_Kate View Post
                Hello mballagan,

                Thank you for your reply.

                At runtime dynamic will try to guess what type to use. Since indicators can reside in multiple assemblies (especially ones that are base indicators), there is ambiguity and that is why it will fail.

                If you compile as an indicator as a DLL and try to access something from it when using dynamic type, there's a good chance you'll hit an error like this if the original is still on the system.

                In this case, you don't need a dispatcher because that code's not accessing a different thread. Try something like this:

                Code:
                else if(State == State.DataLoaded)
                {
                if (ChartControl != null)
                {
                
                foreach (IndicatorBase dt in ChartControl.Indicators)
                {
                try
                {
                
                if (dt.ToString() == "NinjaTrader.NinjaScript.Indicators.MESSignalMTF9X ZMERGETEST1XZR8SPM3StrategyRealtimeEngine")
                {
                dt.IsSuspended = false;
                Print(dt.IsSuspended);
                Print("dynamic all ok:" + dt.ToString());
                
                }
                
                }
                catch(Exception ex)
                {
                Print("dynamic not all ok:" + ex.Message + " stacktrace: " + ex.StackTrace );
                
                }
                
                }
                }
                
                }
                IndicatorBase is a common base class that is not mixed between different assemblies so you can use that to get standard indicator properties, where dynamic would fail.

                Please let us know if we may be of further assistance to you.

                Thanks for your reply.

                So if I declare a variable at class level such as:

                private MESSignalMTF9XZMERGETEST1XZR8SPM3StrategyRealtimeE ngine mestick;

                Using the block of code as you have specified how would the assignment be done?

                if (dt.ToString() == "NinjaTrader.NinjaScript.Indicators.MESSignalM TF9X ZMERGETEST1XZR8SPM3StrategyRealtimeEngine")
                {
                dt.IsSuspended = false;
                Print(dt.IsSuspended);
                Print("dynamic all ok:" + dt.ToString());

                mestick = dt; //this fails as dt is of type IndicatorBase and mestick is of type MESSignalMTF9XZMERGETEST1XZR8SPM3StrategyRealtimeE ngine

                mestick = (MESSignalMTF9XZMERGETEST1XZR8SPM3StrategyRealtime Engine)dt //this causes the original issue of 'indicator [A] not matching indicator [B]' assembly conflict

                //We can declare private IndicatorBase mestick but then how to access properties of the indicator from the strategy maybe use Values[] collection?

                }

                Comment


                  #9
                  Hello mballagan,

                  Thank you for your reply.

                  //We can declare private IndicatorBase mestick but then how to access properties of the indicator from the strategy maybe use Values[] collection?
                  We do not currently have anything to advise for accessing custom public properties of indicators that reside in a DLL, but using IndicatorBase would let you access plots I.E. Values, and that will work.

                  I'd take a look at this forum post my colleague created that shows accessing values when looping through the chart indicators:

                  Hi, Is it possible to acces and get the value of all Indicators, that are in a Chart? So, if I have an indicator, from which I don't know the code, can I get


                  Please let us know if we may be of further assistance to you.
                  Kate W.NinjaTrader Customer Service

                  Comment

                  Latest Posts

                  Collapse

                  Topics Statistics Last Post
                  Started by pechtri, 06-22-2023, 02:31 AM
                  10 responses
                  124 views
                  0 likes
                  Last Post Leeroy_Jenkins  
                  Started by judysamnt7, 03-13-2023, 09:11 AM
                  4 responses
                  59 views
                  0 likes
                  Last Post DynamicTest  
                  Started by ScottWalsh, Yesterday, 06:52 PM
                  4 responses
                  36 views
                  0 likes
                  Last Post ScottWalsh  
                  Started by olisav57, Yesterday, 07:39 PM
                  0 responses
                  7 views
                  0 likes
                  Last Post olisav57  
                  Started by trilliantrader, Yesterday, 03:01 PM
                  2 responses
                  22 views
                  0 likes
                  Last Post helpwanted  
                  Working...
                  X