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

Another mystery

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

    Another mystery

    I am enclosing a simple test case. The objective is to get a static function that can return the value of a moving average.

    It all works fine, except for the very last bar. The only thing I can think of is that "r" must not be getting CalculateOnBarClose set properly, in spite of the fact that it is set in its Initialize() method.

    The organization of the code is:
    • "aaaTest " is the indicator.

    • GetVal is a static function. That means it has no class object associated with it.

    • REF is a dummy class that exists only to give GetVal() access to functions like Print and EMA -- the are not static, and so need to be accessed through a class instance.

    • "r" is an instance of class REF -- GetVal() needs to make use of it.

    • I have configured CalculateOnBarClose false for aaaTest in the Indicators dialog

    I have included the last few lines of the printed output. You can see that everything is all peachy-keen up until that final bar. At that point:
    • Input[0] has a real value
    • EMA. called either of two ways in the indicator's OnBarUpdate() returns a good value
    • r.EMA, called from the static function returns 0. My best guess is that, in spite of its Initialize() method setting CalculateOnBarClose=false, r is behaving as if that were set true.

    So how do I make r.EMA return the last bar calculation properly? Do you see any possibility other than CalculateOnBarClose being set wrong? If that is the answer, then how do I get it set right?

    --EV

    Here is some output -- note that all is perfect up until the final bar:

    Code:
    GetVal:   EMA=600.787     Input series[0]=616.440
    EMA=600.787   EMA=600.787   GetVal=600.787   Input[0]=616.440   CurrentBar=1609
    
    GetVal:   EMA=602.008     Input series[0]=614.210
    EMA=602.008   EMA=602.008   GetVal=602.008   Input[0]=614.210   CurrentBar=1610
    
    GetVal:   EMA=603.281     Input series[0]=616.010
    EMA=603.281   EMA=603.281   GetVal=603.281   Input[0]=616.010   CurrentBar=1611
    
    GetVal:   EMA=604.516     Input series[0]=616.870
    EMA=604.516   EMA=604.516   GetVal=604.516   Input[0]=616.870   CurrentBar=1612
    
    GetVal:   EMA=605.623     Input series[0]=616.690
    EMA=605.623   EMA=605.623   GetVal=605.623   Input[0]=616.690   CurrentBar=1613
    
    GetVal:   EMA=0.000     Input series[0]=624.180
    EMA=607.310   EMA=607.310   GetVal=0.000   Input[0]=624.180   CurrentBar=1614
    Here is the test indicator that produced this output (Magic Code removed):

    Code:
    #region Using declarations
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Xml.Serialization;
    using NinjaTrader.Cbi;
    using NinjaTrader.Data;
    using NinjaTrader.Gui.Chart;
    #endregion
    
    // This namespace holds all indicators and is required. Do not change it.
    namespace NinjaTrader.Indicator
    {
        // Dummy class whose sole purpose is access to its base class' methods
        public class REF : Indicator {
            // Override abstract base members, even though we have nothing to do
            protected override void Initialize() { CalculateOnBarClose=false; return; }
            protected override void OnBarUpdate() { return; }
        }
    
        [Description("Test class")]
        public class aaaTest : Indicator
        {
            protected override void Initialize()  { CalculateOnBarClose=false; return; }
            protected override void OnBarUpdate()
            {
                if (CurrentBar < 21) return;
    
                Print(String.Format("EMA={0:F3}   EMA={1:F3}   GetVal={2:F3}   Input[0]={3:F3}   CurrentBar={4}",
                                EMA(21)[0], EMA(Input,21)[0], GetVal(Input), Input[0], CurrentBar));
                return;
            }
            
            // Gives static methods access to Indicator methods, such as moving averages
            static Indicator r = new REF();
            
            // Simple static class that just returns the current value of a moving average
            public static double GetVal(IDataSeries series)
            {
                double d = r.EMA(series, 21)[0];
                r.Print( String.Format("\r\nGetVal:   EMA={0:F3}     Input series[0]={1:F3}", d, series[0]) );
                return d;
            }
        }
    }

    #2
    FWIW: I did the obvious -- I solved the problem another way.

    Still, those who architect NT may want to consider that I could not construct a class that would honor CalculateOnBarClose or give me any way to turn it off that I know of.

    (If anyone does know how to modify that test code to report the last bar's moving average, I would like to hear the answer.)

    --EV

    Comment


      #3
      EV, thanks for your suggestions - unfortunately what you attempt to do is more general C# and outside of the scope we can support here.
      BertrandNinjaTrader Customer Service

      Comment


        #4
        It would appear that r.EMA()... is taking its CalculateOnBarClose value from EMA. May I ask if perchance you have already tested that hypothesis?

        Comment


          #5
          Originally posted by koganam View Post
          It would appear that r.EMA()... is taking its CalculateOnBarClose value from EMA. May I ask if perchance you have already tested that hypothesis?
          Inspired by your question, I took the time to do some further investigation, and the result is most interesting. I understand that NT thinks this is a C# question, but I think it is an NT question. The situation is:
          • In the Indicators dialog, I set the test indicator "Calculate on bar close" field to false
          • In the test indicator Initialize() I set it to false
          • In the helper class Initialize() I set it to false
          • I verified that the helper class Initialize() method did get called
          • I added Print() calls to verify CalculateOnBarClose -- it is always true

          It gets more interesting from here, and is instructive for those who think that the Help documentation is perfect and the Word of God. My first thought was that it is a read-only property, but the Help page does say that it can be set programmatically:

          This property should ONLY be set in an Initialize() method and be the last statement within that method.
          My first complaint about the Help page is the assertion that it must be the last statement in the Initialize() method. That makes no programming sense whatsoever to me. Unless someone can justify it with something better that "because I said so", it is wrong and should be fixed. Either explain what the real issue is or else remove that assertion.

          The more important point is that setting it in Initialize() does not even work, at least for this specific case. By the time I call EMA, it has been set to true, no matter how hard I tried to get it set false. I did, however, discover an alternative way to get it set that does work.

          I created a wrapper method, called DoEMA, so I could put some print statements in to verify that CalculateOnBarClose was in fact wrong (set to true). It was. So I tried setting it to false right there in the wrapper call -- SURPRISE -- that not only worked, but it was sticky. It remained set to false. And I got my last bar info just fine.

          So the Help documentation is flat-out wrong ("should ONLY be set in an Initialize() method"), at least for this specific case. If I set CalculateOnBarClose where they say to, it does not work. If I set it where they specifically say not to -- after Initialize() -- it works just fine. The property gets set, and it causes the proper action.

          Now I have a speculation as to what is going on, but I won't go into that here. After all, it is just my speculation, and as Dierk has already so clearly pointed out I do not know NT internals.

          Unless I am missing something, that seems to me to be an NT bug, not a C# question. Setting the property in their documented way fails to work, at least in this specific case. Setting it in the way they say not to works just fine.

          Granted I am creating the class in a way that is different than they had foreseen. Isn't unforeseen use the way a lot of bugs are discovered?

          --EV

          Comment


            #6
            Hello,

            The reason for this is there is possible issues with this in certain circumstances with hosted indicators that we have identified that it looks like you have found.

            This is why we never set CalculateOnBarClose manually in NS that we produce for this very reason if you check out our included in NinjaTrader indicators you should not see one what sets this manually in code. As it can end up giving you unexpected results when combined with a hosted indicator. In the case you may be running it hosted you would want to not set this and let the user set this property so it is the same for all.

            Let me know if I can be of further assistance.

            Comment


              #7
              EV,

              We are glad you are passionate about NinjaTrader. You will run into more situations using it where the documentation does not cover every possible scenario. We are happy to improve and clarify where appropriate. In this case, the documentation is accurate for usage of this property. It's to be set only once in Initialize() and not declared at all if you are calling the script from another indicator / strategy.

              It's great that you found other uses for it and we encourage you to get the most out of NinjaTrader, but because something "works" does not make it supported. We will not discuss every design detail to explain why you should do things the supported way.

              There will always be more you are capable of doing than is documented and supported. Please see the following thread if you are looking to explore undocumented aspects with other NinjaTrader community members:
              Ryan M.NinjaTrader Customer Service

              Comment


                #8
                Brett,

                I agree with not setting that property programmatically. I have noted that a number of the contributed indicators do set it and in fact I have had to remove that setting from some so that I could call them successfully from a custom indicator I was writing (RwbMA). I'll go make those fixes permanent one of these days.

                I also agree that the user who adds adds an indicator should have the last word, based on what he sets in the Indicators dialog. I would expect any setting in Initialize() to simply be setting the default, but I do not think that is the case.

                In any event, in the test case I started out not setting it programmatically at all. My issue is that when I do not set it, the helper class always has it set to true. Note that there is no user interaction with the helper class -- it is just a vehicle for being able to call functions like Print() and EMA() from a static method. The ultimate setting should be coming, somehow, from the indicator class that is added to the chart. After all, we agree that we should be honoring what the user configured.

                The only way I can see to make that work is to pass the value as an argument to the called static method, and have that pass it on to the helper class. Then the helper class can wrap any method that is needed, and explicitly set the user-originated value.

                I realize that this would be is a totally unsupported operation,and that it directly contradicts the Help page's very explicit direction, but it is the only way I can see that what we both agree is correct can work -- that what the user humanly set is honored.

                --EV

                PS: FWIW the code I am writing is taking a different path all together, and so does not run into this problem. I first started in this direction, but became convinced that it does not work. Now that I understand it better, I could make it work as described above, but that is unwieldy enough (mainly the having to wrap anything from the base class that cares about the property) that I am not going back to that route.

                Comment


                  #9
                  > In this case, the documentation is accurate for usage of this property. It's to be set only once in Initialize() and not declared at all if you are calling the script from another indicator / strategy.

                  1) What do you mean by "not declared at all if you are calling the script from another indicator "? I do not understand the term "declared" -- what is this declaration?

                  2) Note that Brett says to not set it at all, and my experience agrees with him. Why are you suggesting setting it at all? When is setting it a good idea? I have certainly run into cases (some of the contributed indicators) where it was being set and that caused problems.

                  3 The one time I can see setting it is to pass along what the user has configured (see the note I just posted responding to Brett). In that case, following the documentation flat-out does not work, as discussed in my previous post.

                  > It's great that you found other uses for it and we encourage you to get the most out of NinjaTrader, but because something "works" does not make it supported.

                  I understand that, and I also understand why that has to be so. No disagreement there. I do wish that all of your official indicators were coded entirely with supported code, though. If a capability is important enough that one of your official indicators needs it, then it would seem to be a good idea to have a supported way to do the job.

                  --EV

                  Comment


                    #10
                    Right - Don't write CalculateOnBarClose = true/false; for scripts that you plan to use in other indicators or strategies.
                    Ryan M.NinjaTrader Customer Service

                    Comment


                      #11
                      Originally posted by NinjaTrader_RyanM View Post
                      Right - Don't write CalculateOnBarClose = true/false; for scripts that you plan to use in other indicators or strategies.
                      Is there ever a good time to set it?

                      Aren't you basically closing off other scripts from using your indicator if you do? Shouldn't we want to avoid that?

                      --EV

                      Comment


                        #12
                        Yes, you can set it in code for convenience. I have an indicator I'd like to see a real time updated value each time I apply it to a chart. By setting it in code I don't have to change COBC = false through the gui each time I add this indicator.
                        Ryan M.NinjaTrader Customer Service

                        Comment


                          #13
                          Summary of the discussion:

                          • I was directly instantiating an instance of an Indicator subclass to use as a helper class so that static functions could access Indicator methods, such as Print() and moving averages.

                          • AFAIK that is an unsupported activity (please correct me if that is wrong)

                          • When you do that, there is a problem with setting CalculateOnBarClose
                            • When setting it works ( not in Initialize() )
                            • How you get CalculateOnBarClose set to the value the user has configured


                          • I have since looked into this further, and developed a well-commented demo indicator that illustrates just how to do this so that it does work.

                          • Since that is unsupported, I shall not post it here unless someone asks me to. If you want a copy, contact me and I'll be happy to supply you with the .cs file.

                          --EV
                          Last edited by ETFVoyageur; 01-21-2011, 09:34 AM.

                          Comment


                            #14
                            Sounds good and correct. Thanks EV.

                            Comment


                              #15
                              How about just posting it to the aptly named thread for undocumented/unsupported thingies?

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by Max238, Today, 01:28 AM
                              2 responses
                              26 views
                              0 likes
                              Last Post NinjaTrader_ChristopherJ  
                              Started by Shansen, 08-30-2019, 10:18 PM
                              25 responses
                              949 views
                              0 likes
                              Last Post NinjaTrader_BrandonH  
                              Started by JonesJoker, 04-22-2024, 12:23 PM
                              8 responses
                              41 views
                              0 likes
                              Last Post JonesJoker  
                              Started by timko, Today, 06:45 AM
                              0 responses
                              3 views
                              0 likes
                              Last Post timko
                              by timko
                               
                              Started by Waxavi, 04-19-2024, 02:10 AM
                              2 responses
                              39 views
                              0 likes
                              Last Post poeds
                              by poeds
                               
                              Working...
                              X