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

Export Works, But Import Fails When Indicator NinjaScriptProperty is a Custom Enum

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

    Export Works, But Import Fails When Indicator NinjaScriptProperty is a Custom Enum

    The Problem

    I have a very basic custom indicator that has no additional custom dependencies other than one custom enumeration:

    Code:
    public enum InstrumentInfoItem
    {
       DaysToNextRollover,
      InstrumentType,
      IsFuture,
      IsForex,
      IsIndex,
      IsStock,
      NextExpiryMonth,
      PointValue,
      TickSize,
      TickValue
    }
    This enumeration is used for the NinjaScriptProperty:

    Code:
    [NinjaScriptProperty]
    [Display(Name = "Info to Display", Description = "The type of information to display.", GroupName = "Parameters", Order = 0)]
    public InstrumentInfoItem InfoItem { get; set; }
    Because the enum is in the ninjascript property, it therefore appears in the method signatures of the autogenerated code that appears at the bottom of the indicator *.cs file.

    I've tried putting the enumeration a variety of places. My preference is to just put it in the indicator cs file in the same namespace as the indicator:

    Code:
    namespace NinjaTrader.NinjaScript.Indicators.NinjaMastery.Info
    {
        public enum InstrumentInfoItem
        {
            DaysToNextRollover,
            InstrumentType,
            IsFuture,
            IsForex,
            IsIndex,
            IsStock,
            NextExpiryMonth,
            PointValue,
            TickSize,
            TickValue
        }
    
        /// <summary>
        /// Bars since last entry
        /// Days since last entry
        /// IsFlat
        /// </summary>
        public class NinjaMastery_InstrumentInfo : Indicator
        {
             ....
    But no matter where I put it
    • AddOns folder
    • Indicator cs file but in NinjaTrader.NinjaScript.Indicators namespace
    • Separate DLL
    I can't successfully export (as assembly) and then import on another machine.

    The export completes successfully, but then when importing on the other machine I get the error that the enum cannot be found.

    This immediately looks like a missing using directive or something similar.

    What Appears to Be Causing the Problem

    The problem appears to be in the .cs file in the zip that is generated during the export which contains the autogenerated partial classes.

    The namespaces in this cs file are some default set of namespaces and do not reflect the namespaces in my indicator file.

    Code:
    #region Using declarations
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Xml.Serialization;
    using NinjaTrader.Cbi;
    using NinjaTrader.Gui;
    using NinjaTrader.Gui.Chart;
    using NinjaTrader.Gui.SuperDom;
    using NinjaTrader.Gui.Tools;
    using NinjaTrader.Data;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Core.FloatingPoint;
    #endregion
    As a result, the enum cannot be resolved because it's in the same namespaces as my indicator. If I take the enum out of any namespace, things work because everything that needs to resolve the enumeration is able to.

    The same problem occurs if I put the enum in the AddOns folder. Unless I were to put the enum in one of the above namespaces, it can't be resolved.

    I'm thinking the .cs file in the zip should actually include the namespace of the indicator class at a minimum. And if it were really smart it would also include the namespaces of any "AddOn" code included in the export to be sure that could be resolved.

    For example,

    Code:
    using NinjaTrader.NinjaScript.Indicators;
    or if the indicator is in a sub namespace it should include

    Code:
    using NinjaTrader.NinjaScript.Indicators.Folder1.Folder2;
    My Resolution

    When I manually modify the cs file in the zip to include the namespace of the enum then everything works fine.

    My Questions

    Am I missing something obvious? Is there another way to do this? Is it known that in a circumstance like this that you would just need to manually include the needed namespace?

    Seems to me that an excellent approach would be to have NT automatically insert the indicator namespace (and possibly the addon namespaces) in the cs file during export.

    I suppose it's possible that you intended to not support the use of enums as indicator NinjaScriptProperties, but they work great and I can't imagine a reason to disallow them.


    Thanks,
    Steve



    Last edited by BarzTrading; 02-03-2019, 10:17 PM.

    #2
    Hello BarzTrading,

    Are you able to export the SampleUniversalMovingAverage reference sample from the help guide and then import this into a new clean environment (or remove the original an import into the same environment) on your end?

    https://ninjatrader.com/support/help...ned_parame.htm
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Hi Chelsea,

      Yes, the Sample Universal Moving Average does work for me. Looks like there are a couple reasons why.

      1. The enum property does not have the [NinjaScriptProperty] attribute.

      This prevents it from appearing in the method signatures of the autogenerated code. Therefore, there's no problem with trying to resolve the enum type.

      2. The enum is defined outside of any namespace.

      So, when we add the NinjaScriptProperty attribute, then the enum type still resolves because C# always looks at objects without a namespace to resolve types regardless of the using directives.

      I didn't fully understand the NinjaScriptProperty attribute. I was thinking that it was needed in order for the property to appear in the UI where a user can set the value, but that's not the case. Only the Display attribute is needed for that.

      From the help, the NinjaScriptProperty attribute:

      Determines if the following declared property should be included in the NinjaScript object's constructor as a parameter.
      https://ninjatrader.com/support/help...scriptproperty
      This give us some flexibility. We can include it or not. I'd be curious what issues we'll run into if the property does not appear in the constructor.

      Right now, it looks to me like it's only a convenience. You can instantiate the constructor in one statement rather than two separate statements.

      For example, this

      Code:
      var ma = SampleUniversalMovingAverage(UniversalMovingAverage.EMA);
      instead of this

      Code:
      var ma = SampleUniversalMovingAverage();
      ma.MAType = UniversalMovingAverage.EMA;
      But does this have an impact elsewhere in the system? Are there places in the UI where the user might not be able to set the property value because it's not a part of the constructor?

      When I put the enum in its own namespace and also add the NinjaScriptProperty attribute to the MAType property of the indicator, then I see the problem I was running into.


      Here's my final summary of the problem:

      When a ninjascript has been exported to an assembly and you have an enum property on your ninjascript with the [NinjaScriptProperty] attribute and the enum is in a unique namespace, then import will not succeed because the enum type cannot be resolved in the autogenerated code found in the cs file in the zip archive.

      And the various resolutions:
      • Don't use the [NinjaScriptProperty] attribute
      • Define the enum outside of any namespace
      • Manually insert the enum namespace in the cs file of the exported zip archive.
      I tested all of these and they work fine.

      Is my understanding correct? Have I missed anything?

      Thanks,


      Comment


        #4
        Hello BarzTrading,

        Enums must be declared outside of the class of the script. Our examples use global enums outside of all namespaces, but you can also put the enums in a custom namespace. When declaring a property of that enum type be sure to use the fully qualified namespace.

        Using NinjaScriptProperty is fine.

        As an example, the DValueArea indicator for NinjaTrader 8 uses enums in a custom namespace and the properties using these enums have the NinjaScriptProperty applied.

        Try exporting this. And then model your code in a similar fashion.

        This is a conversion of the DValueArea. Please contact the original author for any questions or comments. Update Aug 10th, 2021: An improperly implemented timespan was causing xml errors in the Strategy Builder



        The NinjaTrader Ecosystem website is for educational and informational purposes only and should not be considered a solicitation to buy or sell a futures contract or make any other type of investment decision. The add-ons listed on this website are not to be considered a recommendation and it is the reader's responsibility to evaluate any product, service, or company. NinjaTrader Ecosystem LLC is not responsible for the accuracy or content of any product, service or company linked to on this website.
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          In theory, using the fully qualified namespace for the property type solves all the problems. This works so long as my namespaces resolve correctly.

          But suppose you have an indicator in this namespace:

          Code:
          NinjaTrader.NinjaScript.Indicators.NinjaMastery.Info
          And your enum is in this namespace:

          Code:
          NinjaMastery
          In the following code, the enum will not properly resolve because of the way .NET does it's namespace resolution.

          Code:
          namespace NinjaTrader.NinjaScript.Indicators.NinjaMastery.Info
          {
              public class NinjaMastery_InstrumentInfo : Indicator
              {
                  [NinjaScriptProperty]
                  [Display(Name = "Info to Display", Description = "The type of information to display.", GroupName = "Parameters", Order = 0)]
                  public NinjaMastery.InstrumentInfoItem InfoItem { get; set; }
          
                  ...
          .NET will assume the enum type namespace is:

          Code:
          NinjaTrader.NinjaScript.Indicators.NinjaMastery
          Any namespace that starts with NinjaMastery will not resolve correctly.

          The obvious resolution is to use global like this:

          Code:
          [NinjaScriptProperty]
          [Display(Name = "Info to Display", Description = "The type of information to display.", GroupName = "Parameters", Order = 0)]
          public global::NinjaMastery.InstrumentInfoItem InfoItem { get; set; }
          This compiles, but now NinjaTrader will ignore the property and it won't appear in the autogenerated code.

          So, I might request a feature enhancement, if possible, that the code generation would recognize and include the global:: specifier preceding the namespace.

          Obviously, I can work around this. Just something I ran into...

          Last edited by BarzTrading; 02-05-2019, 10:56 AM.

          Comment


            #6
            Hello BarzTrading,

            I would not recommend adding those enums to the NinjaTrader.NinjaScript.Indicators namespace or anywhere within it.

            Instead, put these in a custom namespace as demonstrated in the DValueArea indicator I have linked.
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Hi Chelsea,

              Yes. That's what my comment demonstrates. The enum is in the NinjaMastery namespace. The problem is that .NET doesn't know how to resolve the namespace correctly in the scenario I demonstrate. And when you use global:: to tell it how to resolve the namespace, it breaks the NinjaTrader autogenerated code.

              The only difference between what I did and the DValue example is:

              1. The indicator is in the NinjaTrader.NinjaScript.Indicators.NinjaMastery.In fonamespace rather than NinjaTrader.NinjaScript.Indicators.
              2. The enumeration is in the NinjaMastery namespace rather than _dValuesEnum namespace.

              I know this is a corner case. Obviously, I can do exactly as you suggest and that works and, in fact, I will end up doing something like that.

              It's just that the naming scheme I present makes a lot of sense and it would be nice to be able to use it. Not a requirement, just a nicety.

              And it might be a simple addition for NinjaTrader to handle the case where the fully qualified namespace included the leading "global::"



              Comment


                #8
                Hello BarzTrading,

                You are correct, the enums cannot be in the NinjaTrader namespace due to the NinjaTrader generated code and you must add these to a custom namespace.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Thanks, I appreciate the help.

                  Comment

                  Latest Posts

                  Collapse

                  Topics Statistics Last Post
                  Started by Waxavi, Today, 02:00 AM
                  0 responses
                  2 views
                  0 likes
                  Last Post Waxavi
                  by Waxavi
                   
                  Started by elirion, Today, 01:36 AM
                  0 responses
                  3 views
                  0 likes
                  Last Post elirion
                  by elirion
                   
                  Started by gentlebenthebear, Today, 01:30 AM
                  0 responses
                  4 views
                  0 likes
                  Last Post gentlebenthebear  
                  Started by samish18, Yesterday, 08:31 AM
                  2 responses
                  9 views
                  0 likes
                  Last Post elirion
                  by elirion
                   
                  Started by Mestor, 03-10-2023, 01:50 AM
                  16 responses
                  391 views
                  0 likes
                  Last Post z.franck  
                  Working...
                  X