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

Add indicator through Add-On

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

    #16
    Add strategy to chart, it can make AddChartIndicator (but during DataLoaded)
    Then make intercommunication with strategy and make chart F5

    Comment


      #17
      Add my vote too, please. Thanks
      sidlercom80
      NinjaTrader Ecosystem Vendor - Sidi Trading

      Comment


        #18
        +1

        Please add my vote.​

        Comment


          #19
          Thanks your votes have been added.

          For any future votes please note we may not continue to say that we added votes but we will count them internally for SFT-1445
          JesseNinjaTrader Customer Service

          Comment


            #20
            Hi everyone!

            Let me also add my vote for this feature. And I'd like to share my experience as I faced exactly the same problem - adding indicator to any open (or new) chart control via AddOn.

            I spent some time debugging the code and ended up with some understanding of the implemented workflows:

            1) ChartControl is created using a template containing some indicators
            2) ChartControl is created and indicator is added manually (via `Indicators` window)
            3) ChartControl instrument is changed

            Case 3 is the simplest one and is just for reference - everything is handled by NT, once you have an indicator added to any ChartControl instance, everything should work smooth and no extra handlers required. If you debug your code, you'll probably notice methods like
            Code:
            ApplyNinjaScripts()
            RefreshIndicators()
            in your call stack, Let's keep them in mind and go ahead.

            Cases 1 and 2 are more complicated.

            Case 1 workflow relies on some serialized XML data (I didn't look into it to be honest). But the main idea is that when an indicator is created there is no chart control and instrument, so this case workflow is: "Create Chart" -> "deserialize XML" -> "Create empty indicator by name" -> "Add indicator to ChartControl.Indicators list" -> "Select instrument" -> "Initialize indicator". Actually it's difficult to understand what happens during "Select instrument" stage as we cannot dive into protected code with debugger. But it seems that instrument is selected and data is fetched first, then indicator is initialized. Please pay your attention to the fact that indicator is already added to ChartControl.Indicators list before instrument is selected.

            Case 2 - when you open `Indicators` window all the indicators instances are created. `SetDefault` state is triggered by an indicator constructor. When you add any indicator to `Configured` list, it's cloned. When you press `Ok` - it's cloned again. But at that stage chart control and instrument (and other parameters) are available. So when an indicator is added to `Configured` list, it has references to instrument, bars etc. (and you may see it in the configuration window). When you press "Ok" button - the cloned version will have all the required parameters.

            Why do I explain two cases? Actually, Case 1 demonstrates that if you inject your custom indicator on window creation, it will work fine. Just a brief example (Add-On):

            Code:
            protected override void OnWindowCreated(Window window)
            {
                var chartWindow = window as Chart;
                if(chartWindow == null) return;
            
                var chartControl = chartWindow.ActiveChartControl;
                chartControl.Indicators.Add(new MyCustomIndicator());
            }
            If a new window is created - indicator is injected before other routines are triggered, so the added indicator will be initialized correctly. No need to invoke `SetState()` explicitly - `SetDefaults` state will be set on constructor invocation, other states ("Configure" -> "Data loaded" -> "Historical" -> "Transition" -> "Realtime") will be all changed during the initialization, no need to update them explicitly.

            The problem is with already created chart controls and indicators added via the Indicators window. Some magic is hidden somewhere in `OnIndicatorsHotKey` and related commands, when you click "OK" button - indicator is cloned and initialized. That means that the snippet above won't work for already opened windows (e.g. when Add-On is hot loaded/reloaded with some chart controls already initialized). In call stack you may notice that the indicator initialization magic is somewhere in:

            Code:
            OnIndicatorsHotKey()
            ApplyIndicatorChanges()
            After spending some time debugging the code it seems I found a workaround. The idea is to trigger chart initialization explicitly, so it will also initialize your added indicator. There is no public method in `ChartControl` class for that, but we may use reflection. What you should do is to trigger that initialization after your indicator is added to `ChartControl.Indicators` collection. The code may look like:

            Code:
            protected override void OnWindowCreated(Window window)
            {
                var chartWindow = window as Chart;
                if(chartWindow == null) return;
            
                var chartControl = chartWindow.ActiveChartControl;
                chartControl.Indicators.Add(new MyCustomIndicator());
            
                var refreshAllBarsMethod = chartControl.GetType().GetMethod("RefreshAllBars", BindingFlags.NonPublic | BindingFlags.Instance);
                refreshAllBarsMethod.Invoke(chartControl, new object[] { });
            }
            Don't ask me how I found that method ​ Debugging for the rescue.

            UPD: I tested the solution a bit more and found one more drawback: unfortunately, you cannot invoke "RefreshAllBars" every time "OnWindowCreated" is triggered as it may be triggered either by the corresponding event handler (when window is created indeed) or by some other routines when add-on is hot reloaded (in such case indicator would be duplicated). To overcome this problem, I'd recommend to check if ChartControl is fully initialized adding one more if-clause around method invocation:

            Code:
            if (chartControl.Instrument != null) // if instrument is not set - new chart control is created indeed, so no need to trigger "RefreshAllBars" method
            {
                var refreshAllBarsMethod = chartControl.GetType().GetMethod("RefreshAllBars", BindingFlags.NonPublic | BindingFlags.Instance);
                refreshAllBarsMethod.Invoke(chartControl, new object[] { });
            }
            ​
            If you want to remove indicator, you should explicitly change status first. One more example below:

            Code:
            var indicator = chartControl.Indicators.OfType<MyCustomIndicatorType>().FirstOrDefault();
            if (indicator != null)
            {
                // If indicator is added, change its status to Finalized (which will trigger Finalized -> Terminated transition under the hood)
                indicator.SetState(State.Finalized);
                chartControl.Indicators.Remove(indicator);
            }

            As mentioned in the snippet, you should set only "Finalized" status and "Terminated" status would be triggered under the hood.

            Unfortunately, all this things are not documented and found empirically, so be careful and use it at your own risk. I tested different scenarios, seems to work correctly. If you want to add Indicator not on window creation but e.g. on button click, the principle remains the same, you should add indicator to "ChartControl.Indicators" list and trigger "RefreshAllBars" method. Not the best solution as bars are reloaded, but still we are limited in documentation.

            Probably you should play around "ApplyNinjaScripts" and "RefreshIndicators" mentioned above. I tried to set all the parameters to a created indicator instance manually (e.g. "Instrument", "BarPeriod" etc.) with no any luck, the answer is probably somewhere in "OnIndicatorsHotKey" which handles indicator initialization when added via the Indicators window and related "ApplyIndicatorChanges" method. Both are not documented and protected so no way to debug it. Looking for a better solution
            Last edited by EvSpirit; 04-06-2023, 07:01 AM.

            Comment


              #21
              It seems a slightly better solution found. Instead of triggering "RefreshAllBars" we may use "RefreshIndicators" mentioned above. I tried one before, but it failed and I could not see the reason. Now I see what's missing - indicator "Input" parameter. Actually that's what happening in the IndicatorSelector window - when you add any indicator to "Configured" list, it's initialized with "Input series" parameter. When you click "OK" - indicator is cloned, but it already has input series defined. I also found out that one more parameter "ChartBars" is required before triggering "RefreshIndicators" method. So the updated code looks like:

              Code:
              protected override void OnWindowCreated(Window window)
              {
                  var chartWindow = window as Chart;
                  if(chartWindow == null) return;
              
                  var chartControl = chartWindow.ActiveChartControl;
                  var indicator = new MyCustomIndicator();
                  chartControl.Indicators.Add(indicator);
              
                  if (chartControl.Instrument != null) // if instrument is not set - new chart control is created indeed, so no need to trigger "RefreshAllBars" method
                  {
                      // before invoking "RefreshIndicators" required parameters must be set
                      indicator.ChartBars = chartControl.PrimaryBars;
                      indicator.SetInput(new PriceSeries(chartControl.PrimaryBars.Bars, PriceType.Close));​
              
                      var refreshIndicatorsMethod = chartControl.GetType().GetMethod("RefreshIndicators", BindingFlags.NonPublic | BindingFlags.Instance);
                      refreshIndicatorsMethod.Invoke(chartControl, new object[] { true, true });
                  }​
              }​

              When you invoke "RefreshIndicators" - it triggers all the indicator statuses updates under the hood, so still no need to explicitly update indicator status.

              This solution seems to be better as it does not reload bar history, so it's quite close to the initial NT implementation (when you add indicator via IndicatorSelector window). Going to use and test if for a while, let's see how it works

              Comment


                #22
                After testing the solution above I've noticed one more problem - drawing methods do not work properly. But if indicator is added manually via Indicators dialog - everything works fine. After comparing the states of indicators added using different approaches I noticed some more missing parameters. In case you need drawing support, you should also add "IsOwnedByChart" property. Some more properties are missing, they do not affect drawing support, however, I think it's better to keep them defined. So the patched code is:

                Code:
                protected override void OnWindowCreated(Window window)
                {
                    var chartWindow = window as Chart;
                    if(chartWindow == null) return;
                
                    var chartControl = chartWindow.ActiveChartControl;
                    var indicator = new MyCustomIndicator
                    {
                        IsOwnedByChart = true, // this one is required for drawing
                
                        // values below are not required for drawing, however they are defined when an indicator is added via Indicators dialog
                        Owner = chartWindow,
                        NumberOfPanels = 1,
                        Panel = -1
                    }
                
                    chartControl.Indicators.Add(indicator);
                
                    if (chartControl.Instrument != null) // if instrument is not set - new chart control is created indeed, so no need to trigger "RefreshAllBars" method
                    {
                        // before invoking "RefreshIndicators" required parameters must be set
                        indicator.ChartBars = chartControl.PrimaryBars;
                        indicator.SetInput(new PriceSeries(chartControl.PrimaryBars.Bars, PriceType.Close));​
                
                        var refreshIndicatorsMethod = chartControl.GetType().GetMethod("RefreshIndicators", BindingFlags.NonPublic | BindingFlags.Instance);
                        refreshIndicatorsMethod.Invoke(chartControl, new object[] { true, true });
                    }​
                }​​

                Comment


                  #23
                  Please add my vote too!

                  Comment


                    #24
                    Please add my vote!

                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by bortz, 11-06-2023, 08:04 AM
                    47 responses
                    1,607 views
                    0 likes
                    Last Post aligator  
                    Started by jaybedreamin, Today, 05:56 PM
                    0 responses
                    9 views
                    0 likes
                    Last Post jaybedreamin  
                    Started by DJ888, 04-16-2024, 06:09 PM
                    6 responses
                    19 views
                    0 likes
                    Last Post DJ888
                    by DJ888
                     
                    Started by Jon17, Today, 04:33 PM
                    0 responses
                    6 views
                    0 likes
                    Last Post Jon17
                    by Jon17
                     
                    Started by Javierw.ok, Today, 04:12 PM
                    0 responses
                    15 views
                    0 likes
                    Last Post Javierw.ok  
                    Working...
                    X