Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Cannot use enum properties from an indicator in my Strategy

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

    Cannot use enum properties from an indicator in my Strategy

    I have built a HTF Moving Average Indicator, where I can plot for a example a Daily EMA(200) on 5 minutes chart.


    ​When I now want to use the indicator in my Strategy, I can only specify two properties, "HigherTimeFrameBarPeriod" and "Period". I cannot specify the enum properties. Why?

    HTFMovingAverage()



    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;
    using NinjaTrader.NinjaScript.DrawingTools;
    #endregion
    
    //This namespace holds Indicators in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Indicators.Isak
    {
        public class HTFMovingAverage : Indicator
        {
            private CustomEnumNamespace.UniversalMovingAverage maType = CustomEnumNamespace
                .UniversalMovingAverage
                .SMA;
            private CustomEnumNamespace.BarsPeriodType bpType = CustomEnumNamespace
                .BarsPeriodType
                .Minute;
    
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Description                                    = @"Enter the description for your new custom Indicator here.";
                    Name                                        = "HTFMovingAverage";
                    Calculate                                    = Calculate.OnBarClose;
                    IsOverlay                                    = true;
                    BarsRequiredToPlot                            = 1;
                    IsAutoScale                                    = false;  
                    ScaleJustification                            = NinjaTrader.Gui.Chart.ScaleJustification.Right;
                    //Disable this property if your indicator requires custom values that cumulate with each new market data event.
                    //See Help Guide for additional information.
                    IsSuspendedWhileInactive                    = true;
                    HigherTimeFrameBarPeriod = 60;
                    Period = 20;
    
    
                    AddPlot(Brushes.Magenta, "HTF Plot");
                }
                else if (State == State.Configure)
                {
                    // We use a switch which allows NinjaTrader to only execute code pertaining to our case
                    switch (bpType)
                    {
                        // If the bpType is defined as Minute then...
                        case CustomEnumNamespace.BarsPeriodType.Minute:
                        {
                            // Sets the secondary data series bar period type to Minute
                              AddDataSeries(BarsPeriodType.Minute, HigherTimeFrameBarPeriod);
                            break;
                        }
    
                        // If the bpType is defined as Day then...
                        case CustomEnumNamespace.BarsPeriodType.Day:
                        {
                            // Sets the secondary data series bar period type to Minute
                            AddDataSeries(BarsPeriodType.Day, HigherTimeFrameBarPeriod);
                            break;
                        }
                    }
                }
            }
    
            protected override void OnBarUpdate()
            {
                if (BarsInProgress == 0 && CurrentBars[0] > 0)
                {
                    // extend the larger time frame for each primary bar so there are consecutive bars set so we can see it on the chart
                    if (!Values[0].IsValidDataPoint(0))
                        Values[0][0]    = Values[0][1];
                }
    
                if (BarsInProgress == 1 && CurrentBars[1] > 0)
                {
                    // We use a switch which allows NinjaTrader to only execute code pertaining to our case
                    switch (maType)
                    {
                        // If the maType is defined as an EMA then...
                        case CustomEnumNamespace.UniversalMovingAverage.EMA:
                        {
                            // Sets the plot to be equal to the EMA's plot
                            Values[0][0] = EMA(Closes[1], Period)[0];
                            break;
                        }
    
                        // If the maType is defined as a HMA then...
                        case CustomEnumNamespace.UniversalMovingAverage.HMA:
                        {
                            // Sets the plot to be equal to the HMA's plot
                            Values[0][0] = HMA(Closes[1], Period)[0];
                            break;
                        }
    
                        // If the maType is defined as a SMA then...
                        case CustomEnumNamespace.UniversalMovingAverage.SMA:
                        {
                            // Sets the plot to be equal to the SMA's plot
                            Values[0][0] = SMA(Closes[1], Period)[0];
                            break;
                        }
    
                        // If the maType is defined as a WMA then...
                        case CustomEnumNamespace.UniversalMovingAverage.WMA:
                        {
                            // Sets the plot to be equal to the WMA's plot
                            Values[0][0] = WMA(Closes[1], Period)[0];
                            break;
                        }
                        // If the maType is defined as a VMA then...
                        case CustomEnumNamespace.UniversalMovingAverage.VMA:
                        {
                            // Sets the plot to be equal to the WMA's plot
                            Values[0][0] = VMA(Closes[1], Period, Period)[0];
                            break;
                        }
                    }
                }
            }
            #region Properties
            [Display(GroupName = "Parameters", Description = "Choose a Moving Average Type.")]
            public CustomEnumNamespace.UniversalMovingAverage MAType
            {
                get { return maType; }
                set { maType = value; }
            }
            [Display(GroupName = "Parameters", Description = "Choose Bars Period Type")]
            public CustomEnumNamespace.BarsPeriodType BPType
            {
                get { return bpType; }
                set { bpType = value; }
            }
            [Range(1, int.MaxValue), NinjaScriptProperty]
            [Display(ResourceType = typeof(Custom.Resource), Name = "MA Period", GroupName = "NinjaScriptParameters", Order = 0)]
            public int Period
            { get; set; }
            [Range(1, int.MaxValue), NinjaScriptProperty]
            [Display(ResourceType = typeof(Custom.Resource), Name = "HTF Bar Period", GroupName = "NinjaScriptParameters", Order = 0)]
            public int HigherTimeFrameBarPeriod
            { get; set; }
            #endregion
        }
    }
    
    /* Creates an enum in a custom namespace that is assigned to UniversalMovingAverage.
    Basically it assigns a numerical value to each item in the list and the items can be referenced without the use
    of their numerical value.
    For more information on enums you can read up on it here: http://www.csharp-station.com/Tutorials/Lesson17.aspx */
    
    namespace CustomEnumNamespace
    {
        public enum UniversalMovingAverage
        {
            EMA,
            HMA,
            SMA,
            WMA,
            VMA
        }
        public enum BarsPeriodType
        {
            Minute,
            Day
        }
    }​

    #2
    Specify how?

    I don't see the NinjaScriptProperty attribute on your enum properties.

    I also don't see the auto generated code at the bottom of the
    indicator -- did you delete that?

    Comment


      #3
      Hello bltdavid
      Sorry I thought I did not need to show it here. Here is the indicator. It works perfectly on charts. I can switch between BarDatatype Minute and Day and I can set the HTF Time period for each bar, but in the strategy when I try to use the indicator I can only specify the proporties Period (of the HTF moving average) and HigherTimeFrameBarPeriod (the bar length in either a Day or Minute bar. I cannot specify the enum properties like "Day"/"Minute" or the moving averages I want to use in the strategy like "SMA"/"EMA", etc.
      Attached Files

      Comment


        #4
        Correct, you don't really need to show the auto generated code
        when you copy & paste into your posting.

        But it could have helped you solve this problem yourself.

        I'll make this a quick teaching moment and explain why.

        Look at your auto generated code, at the bottom. Note how
        code is generated for three different namespaces, take a deep
        look at the first one, the one for indicators.

        It shows this code,

        Code:
        public Isak.HTFMovingAverage HTFMovingAverage(int period, int higherTimeFrameBarPeriod)
        {
            return HTFMovingAverage(Input, period, higherTimeFrameBarPeriod);
        }
        This code is what allows you to call HTFMovingAverage(10, 20),
        the NT folks call this the auto-generated constructors, they're just
        methods w/the same name as your indicator class, which is allowed.

        The thing I want you to see is the two arguments -- the enum arguments
        are not included in the signature.

        The crux of your question is basically this:
        "I need to call this indicator from a strategy, but the 2 enum arguments
        are not made available in the method signature. How do I get NT to add
        the enums to the arguments for this indicator?"

        Simple.

        The answer to your problems is to add the NinjaScriptProperty on the
        two enum properties -- like I hinted in my first reply.

        That is, add [NinjaScriptProperty] to the tops of both enum properties,
        it is this decoration (called an attribute) that tells the NT compiler to include this
        property in the arguments when building the auto-generated constructor code.

        Make sense?

        -=o=-

        See attached, I've cleaned up the properties and recompiled so that the auto
        generated code was regenerated. [To regenerate, you may have to explicitly
        edit the indicator file in the NinjaScript editor, so it sees a change or two, only
        then does it regenerate when it recompiles. If you edit your indicator outside
        of the NT editor, like using Notepad or VS, you might have problems with the auto
        generated code not updating -- it seems to me, the NT compiler only regenerates
        the auto constructors when it sees edits made to the code in the NT editor.]

        Your eyeballs should look for [NinjaScriptProperty], that's the only editing
        I really did, the rest was just adding some blank lines to make it easier to read.

        Note how your original two properties have NinjaScriptProperty included
        at the end of their Range attribute, which is a bit sneaky but works fine.
        Attached Files

        Comment


          #5
          Your next question is, after adding [NinjaScriptProperty] to all the
          properties that must also be arguments in the auto-generated constructors,
          is going to be this:

          "Ok, so how do I call my indicator? I mean, what are the arguments, in which
          order, I gotta know the signature, which arguments come first, etc, it looks like
          code that used to call this indicator now no longer works."

          Yep, that's the whole point of my 'teaching moment' from above.

          To wit:
          The auto-generated code is your guide on how to call your indicator's
          constructor method
          , it shows you the arguments, the types, the method
          name, the new signature is right there for you to discover.

          When you add [NinjaScriptProperty], you are changing the signature
          of how you call your indicator, so you may have to update code elsewhere
          to use the new signature
          .

          That's why I say of the 3 namespaces generated, the first one is the only
          one you need to study, the other two are just a rehash of the first one.

          Make sense?

          Hang in there!

          Last edited by bltdavid; 09-24-2023, 10:58 AM.

          Comment


            #6
            Thank you bltdavid! I forgot to add the [NinjaScriptProperty] to those two properties!

            When I try to call this indicator I get this error, what I am doing wrong?
            Attached Files

            Comment


              #7
              Use the fully-qualified namespace for the enum name.

              You typed simply 'SMA', but that's not enough,

              Try using the full name,

              CustomEnumNamespace.UniversalMovingAverage.SMA

              Yikes, that's sure a lot of letters, don't type that.

              -=o=-

              There is a simpler, more convenient way.

              Try adding this line to your using declarations located at the
              top of your indicator [I usually make my personal custom
              namespace the last line of the using declarations],

              using CustomEnumNamespace​;

              By adding this using declaration, now you can type a lot
              less and just use,

              UniversalMovingAverage.SMA

              Pretty cool, huh?

              -=o=-

              But, let's extend the teaching moment out further.

              You've now learned an important lesson of coding:

              Using big long giant names can be a pain in the butt when
              it comes to programming. Sure, sometimes long names
              can be helpful, but they can also be quite the hindrance.

              When to use such long names?
              On things you will rarely type or see. Use long names for
              method names, esp methods that are not used that often.
              Devise a long name where the name itself documents the
              purpose of the method.

              When to use short names?
              On common things, esp things you might type or see a lot.

              Like you, I have a similar enum, but you know what I used
              for a type name? Ya wanna see something short and sweet?

              Here it is:
              In my personal code, my enum type name is very simple,

              MAType

              Which would you rather type?
              MAType.SMA or UniversalMovingAverage.SMA?

              -=o=-

              And that namespace ... Lord almighty, you could shorten
              that up a bit, too.

              Here's what I do:
              Pick a naming convention, use a 2, 3 or 4 letter prefix,
              such as your initials of your name or business. I have
              my personal custom namespace stored in a file called,

              BltCommon.cs

              and it declares a short and sweet namespace,

              namespace Blt.Common
              {
              }


              My point is:
              Wisely choose some shorter key names, because you may
              be typing them a lot. Find a good convention, and stick to it.

              Just my 2˘.

              Last edited by bltdavid; 09-24-2023, 02:08 PM.

              Comment


                #8
                bltdavid You are so kind! Thank you.

                I followed you tips to create a file (I called it IsakCommon.cs placed it in my folder under Indicators. I added the in last line of using declarations.

                Now I get this error.
                Attached Files

                Comment


                  #9
                  Hello prisonbreaker82,

                  Thanks for your notes.

                  bltdavid is correct in what they are saying. The NinjaScriptProperty attribute should be added to the NinjaScript properties. The NinjaScriptProperty attribute property determines if the property should be included in the NinjaScript object's constructor as a parameter. This is necessary if you plan on calling a NinjaScript object from another (e.g., calling a custom indicator from a strategy).

                  NinjaScriptAttribute: https://ninjatrader.com/support/help...yattribute.htm

                  You should make sure to use the fully qualified namespace for the enum as blddavid has noted in post # 7.

                  Here is a reference sample demonstrating creating a user-defined enum parameter: https://ninjatrader.com/support/help...ned_parame.htm
                  <span class="name">Brandon H.</span><span class="title">NinjaTrader Customer Service</span><iframe name="sig" id="sigFrame" src="/support/forum/core/clientscript/Signature/signature.php" frameborder="0" border="0" cellspacing="0" style="border-style: none;width: 100%; height: 120px;"></iframe>

                  Comment


                    #10
                    Trying to complie the code and it does not let me. I have add another .cs file under the Indicators/Isak folder where I have defned the CustomEnumNamespace

                    namespace CustomEnumNamespace
                    {
                    public enum MAType
                    {
                    EMA,
                    HMA,
                    SMA,
                    WMA,
                    VMA
                    }

                    public enum BPType
                    {
                    Minute,
                    Day
                    }
                    }​


                    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;
                    using NinjaTrader.NinjaScript.DrawingTools;
                    
                    using CustomEnumNamespace; // adding my custom namespace
                    
                    #endregion
                    
                    
                    //This namespace holds Indicators in this folder and is required. Do not change it.
                    namespace NinjaTrader.NinjaScript.Indicators.Isak
                    {
                        public class HTFMovingAverage : Indicator
                        {
                            private MAType maType = MAType.SMA;
                            private BPType bpType = BPType.Minute;
                    
                            protected override void OnStateChange()
                            {
                                if (State == State.SetDefaults)
                                {
                                    Description = @"Enter the description for your new custom Indicator here.";
                                    Name = "HTFMovingAverage";
                                    Calculate = Calculate.OnBarClose;
                                    IsOverlay = true;
                                    BarsRequiredToPlot = 1;
                                    IsAutoScale = false;
                                    ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right;
                                    //Disable this property if your indicator requires custom values that cumulate with each new market data event.
                                    //See Help Guide for additional information.
                                    IsSuspendedWhileInactive = true;
                                    HigherTimeFrameBarPeriod = 60;
                                    Period = 20;
                    
                                    AddPlot(Brushes.Magenta, "HTF Plot");
                                }
                                else if (State == State.Configure)
                                {
                                    // We use a switch which allows NinjaTrader to only execute code pertaining to our case
                                    switch (bpType)
                                    {
                                        // If the bpType is defined as Minute then...
                                        case BPType.Minute:
                                        {
                                            // Sets the secondary data series bar period type to Minute
                                            AddDataSeries(BarsPeriodType.Minute, HigherTimeFrameBarPeriod);
                                            break;
                                        }
                    
                                        // If the bpType is defined as Day then...
                                        case BPType.Day:
                                        {
                                            // Sets the secondary data series bar period type to Minute
                                            AddDataSeries(BarsPeriodType.Day, HigherTimeFrameBarPeriod);
                                            break;
                                        }
                                    }
                                }
                            }
                    
                            protected override void OnBarUpdate()
                            {
                                if (BarsInProgress == 0 && CurrentBars[0] > 0)
                                {
                                    // extend the larger time frame for each primary bar so there are consecutive bars set so we can see it on the chart
                                    if (!Values[0].IsValidDataPoint(0))
                                        Values[0][0] = Values[0][1];
                                }
                    
                                if (BarsInProgress == 1 && CurrentBars[1] > 0)
                                {
                                    // We use a switch which allows NinjaTrader to only execute code pertaining to our case
                                    switch (maType)
                                    {
                                        // If the maType is defined as an EMA then...
                                        case MAType.EMA:
                                        {
                                            // Sets the plot to be equal to the EMA's plot
                                            Values[0][0] = EMA(Closes[1], Period)[0];
                                            break;
                                        }
                    
                                        // If the maType is defined as a HMA then...
                                        case MAType.HMA:
                                        {
                                            // Sets the plot to be equal to the HMA's plot
                                            Values[0][0] = HMA(Closes[1], Period)[0];
                                            break;
                                        }
                    
                                        // If the maType is defined as a SMA then...
                                        case MAType.SMA:
                                        {
                                            // Sets the plot to be equal to the SMA's plot
                                            Values[0][0] = SMA(Closes[1], Period)[0];
                                            break;
                                        }
                    
                                        // If the maType is defined as a WMA then...
                                        case MAType.WMA:
                                        {
                                            // Sets the plot to be equal to the WMA's plot
                                            Values[0][0] = WMA(Closes[1], Period)[0];
                                            break;
                                        }
                                        // If the maType is defined as a VMA then...
                                        case MAType.VMA:
                                        {
                                            // Sets the plot to be equal to the WMA's plot
                                            Values[0][0] = VMA(Closes[1], Period, Period)[0];
                                            break;
                                        }
                                    }
                                }
                            }
                    
                            #region Properties
                    
                            [NinjaScriptProperty]
                            [Display(GroupName = "Parameters", Description = "Choose a Moving Average Type.")]
                            public MAType MAType
                            {
                                get { return maType; }
                                set { maType = value; }
                            }
                    
                            [NinjaScriptProperty]
                            [Display(GroupName = "Parameters", Description = "Choose Bars Period Type")]
                            public BarsPeriodType BPType
                            {
                                get { return bpType; }
                                set { bpType = value; }
                            }
                    
                            [Range(1, int.MaxValue), NinjaScriptProperty]
                            [Display(
                                ResourceType = typeof(Custom.Resource),
                                Name = "MA Period",
                                GroupName = "NinjaScriptParameters",
                                Order = 0
                            )]
                            public int Period { get; set; }
                    
                            [Range(1, int.MaxValue), NinjaScriptProperty]
                            [Display(
                                ResourceType = typeof(Custom.Resource),
                                Name = "HTF Bar Period",
                                GroupName = "NinjaScriptParameters",
                                Order = 0
                            )]
                            public int HigherTimeFrameBarPeriod { get; set; }
                    
                            #endregion
                        }
                    }
                    
                    #region NinjaScript generated code. Neither change nor remove.
                    
                    namespace NinjaTrader.NinjaScript.Indicators
                    {
                        public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
                        {
                            private Isak.HTFMovingAverage[] cacheHTFMovingAverage;
                            public Isak.HTFMovingAverage HTFMovingAverage(MAType mAType, BarsPeriodType bPType, int period, int higherTimeFrameBarPeriod)
                            {
                                return HTFMovingAverage(Input, mAType, bPType, period, higherTimeFrameBarPeriod);
                            }
                    
                            public Isak.HTFMovingAverage HTFMovingAverage(ISeries<double> input, MAType mAType, BarsPeriodType bPType, int period, int higherTimeFrameBarPeriod)
                            {
                                if (cacheHTFMovingAverage != null)
                                    for (int idx = 0; idx < cacheHTFMovingAverage.Length; idx++)
                                        if (cacheHTFMovingAverage[idx] != null && cacheHTFMovingAverage[idx].MAType == mAType && cacheHTFMovingAverage[idx].BPType == bPType && cacheHTFMovingAverage[idx].Period == period && cacheHTFMovingAverage[idx].HigherTimeFrameBarPeriod == higherTimeFrameBarPeriod && cacheHTFMovingAverage[idx].EqualsInput(input))
                                            return cacheHTFMovingAverage[idx];
                                return CacheIndicator<Isak.HTFMovingAverage>(new Isak.HTFMovingAverage(){ MAType = mAType, BPType = bPType, Period = period, HigherTimeFrameBarPeriod = higherTimeFrameBarPeriod }, input, ref cacheHTFMovingAverage);
                            }
                        }
                    }
                    
                    namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
                    {
                        public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
                        {
                            public Indicators.Isak.HTFMovingAverage HTFMovingAverage(MAType mAType, BarsPeriodType bPType, int period, int higherTimeFrameBarPeriod)
                            {
                                return indicator.HTFMovingAverage(Input, mAType, bPType, period, higherTimeFrameBarPeriod);
                            }
                    
                            public Indicators.Isak.HTFMovingAverage HTFMovingAverage(ISeries<double> input , MAType mAType, BarsPeriodType bPType, int period, int higherTimeFrameBarPeriod)
                            {
                                return indicator.HTFMovingAverage(input, mAType, bPType, period, higherTimeFrameBarPeriod);
                            }
                        }
                    }
                    
                    namespace NinjaTrader.NinjaScript.Strategies
                    {
                        public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
                        {
                            public Indicators.Isak.HTFMovingAverage HTFMovingAverage(MAType mAType, BarsPeriodType bPType, int period, int higherTimeFrameBarPeriod)
                            {
                                return indicator.HTFMovingAverage(Input, mAType, bPType, period, higherTimeFrameBarPeriod);
                            }
                    
                            public Indicators.Isak.HTFMovingAverage HTFMovingAverage(ISeries<double> input , MAType mAType, BarsPeriodType bPType, int period, int higherTimeFrameBarPeriod)
                            {
                                return indicator.HTFMovingAverage(input, mAType, bPType, period, higherTimeFrameBarPeriod);
                            }
                        }
                    }
                    
                    #endregion
                    ​
                    ​​

                    Comment


                      #11
                      Hello prisonbreaker82,

                      Use the fully qualified namespace, don't use ambiguous variable names.

                      private CustomEnumNamespace.MAType maType = MAType.SMA;
                      private CustomEnumNamespace.BPType bpType = BPType.Minute;

                      public CustomEnumNamespace.MAType MyMAType
                      { get; set; }​

                      public CustomEnumNamespace.MyBPType
                      { get; set; }​
                      Chelsea B.NinjaTrader Customer Service

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by LauraBauer1, Today, 09:41 AM
                      0 responses
                      6 views
                      0 likes
                      Last Post LauraBauer1  
                      Started by proptradingshop, Yesterday, 11:30 AM
                      9 responses
                      29 views
                      0 likes
                      Last Post NinjaTrader_ChelseaB  
                      Started by NRITV, Today, 09:05 AM
                      1 response
                      11 views
                      0 likes
                      Last Post NinjaTrader_Jesse  
                      Started by xiinteractive, Today, 08:29 AM
                      1 response
                      7 views
                      0 likes
                      Last Post NinjaTrader_Clayton  
                      Started by DT215, 08-08-2023, 11:03 AM
                      3 responses
                      445 views
                      0 likes
                      Last Post NinjaTrader_Clayton  
                      Working...
                      X