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

How To Get Indicator To Replot When Pressing A Button

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

    How To Get Indicator To Replot When Pressing A Button

    I'm creating an indicator where I can turn on/off the average and/or bands of Bollinger Bands.

    I've got two buttons on the toolbar to show/hide either one. However, I've not been able to get the indicator to redraw or erase the plots when the buttons are clicked. When I reload the script (e.g. F5) it works, but not automatically.

    I've tried Update() and ForceRefresh() and it won't work. I know part of the answer has to be resetting the number of bars that need to be updated in OnBarUpdate(). I know what I want is possible because I've seen other indicators replot based on a show/hide concept but cannot duplicate.

    What am I doing wrong or missing?

    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.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
    {
    public class BollingerPlus : Indicator
    {
    private SMA sma;
    private StdDev stdDev;
    private Chart chartWindow;
    private bool isToolBarButtonAdded;
    private System.Windows.Controls.Button averageButton;
    private System.Windows.Controls.Button bandsButton;

    protected override void OnStateChange()
    {
    if (State == State.SetDefaults)
    {
    Description = NinjaTrader.Custom.Resource.NinjaScriptIndicatorDe scriptionBollinger;
    Name = "Bollinger Plus";
    IsOverlay = true;
    IsSuspendedWhileInactive = true;
    NumStdDev = 2;
    Period = 20;
    averageClicked = false;
    bandsClicked = false;

    AddPlot(Brushes.Goldenrod, NinjaTrader.Custom.Resource.BollingerUpperBand);
    AddPlot(Brushes.Goldenrod, NinjaTrader.Custom.Resource.BollingerMiddleBand);
    AddPlot(Brushes.Goldenrod, NinjaTrader.Custom.Resource.BollingerLowerBand);
    }
    else if (State == State.Historical)
    {
    if ((ChartControl!=null) && (!isToolBarButtonAdded))
    {
    ChartControl.Dispatcher.InvokeAsync((Action)(() =>
    {
    AddButtonToToolbar();
    }));
    }
    }
    else if (State == State.Terminated)
    {
    if (chartWindow != null)
    {
    ChartControl.Dispatcher.InvokeAsync((Action)(() =>
    {
    DisposeToolBar();
    }));
    }
    }
    else if (State == State.DataLoaded)
    {
    sma = SMA(Period);
    stdDev = StdDev(Period);
    }
    }

    private void refreshChart()
    {
    try
    {
    ForceRefresh();
    //ReloadAllHistoricalData();
    }
    catch(Exception e)
    {
    Print(e.ToString());
    }
    }

    protected override void OnBarUpdate()
    {
    double sma0 = sma[0];
    double stdDev0 = stdDev[0];

    if(!bandsClicked) { Upper[0] = sma0 + NumStdDev * stdDev0; }
    if(!averageClicked) { Middle[0] = sma0; }
    if(!bandsClicked) { Lower[0] = sma0 - NumStdDev * stdDev0; }
    }

    private void OnButtonClick(object sender, RoutedEventArgs rea)
    {
    System.Windows.Controls.Button button = sender as System.Windows.Controls.Button;
    if ((button==averageButton) && (button.Name=="HideAverage") && (button.Foreground==Brushes.Black) && (button.Background==Brushes.PeachPuff))
    {
    button.Foreground = Brushes.White;
    button.Background = Brushes.DarkOrange;
    button.Name = "ShowAverage";
    averageClicked = true;
    refreshChart();
    return;
    }

    if ((button==averageButton) && (button.Name=="ShowAverage") && (button.Foreground==Brushes.White) && (button.Background==Brushes.DarkOrange))
    {
    button.Foreground = Brushes.Black;
    button.Background = Brushes.PeachPuff;
    button.Name = "HideAverage";
    averageClicked = false;
    refreshChart();
    return;
    }

    if ((button==bandsButton) && (button.Name=="HideBands") && (button.Foreground==Brushes.Black) && (button.Background==Brushes.Thistle))
    {
    button.Foreground = Brushes.White;
    button.Background = Brushes.Violet;
    button.Name = "ShowBands";
    bandsClicked = true;
    refreshChart();
    return;
    }

    if ((button==bandsButton) && (button.Name=="ShowBands") && (button.Foreground==Brushes.White) && (button.Background==Brushes.Violet))
    {
    button.Foreground = Brushes.Black;
    button.Background = Brushes.Thistle;
    button.Name = "HideBands";
    bandsClicked = false;
    refreshChart();
    return;
    }
    }

    private void AddButtonToToolbar()
    {
    string aName;
    string bName;
    Brush aFore;
    Brush bFore;
    Brush aBack;
    Brush bBack;

    if(averageClicked)
    {
    aName = "ShowAverage";
    aFore = Brushes.White;
    aBack = Brushes.DarkOrange;
    }
    else
    {
    aName = "HideAverage";
    aFore = Brushes.Black;
    aBack = Brushes.PeachPuff;
    }

    if(bandsClicked)
    {
    bName = "ShowBands";
    bFore = Brushes.White;
    bBack = Brushes.Violet;
    }
    else
    {
    bName = "HideBands";
    bFore = Brushes.Black;
    bBack = Brushes.Thistle;
    }

    chartWindow = Window.GetWindow(this.ChartControl.Parent) as Chart;

    if (chartWindow==null)
    {
    Print("chartWindow == null");
    return;
    }

    averageButton = new System.Windows.Controls.Button
    {
    Name = aName, Content = "AVG", Foreground = aFore, Background = aBack
    };
    averageButton.Click += OnButtonClick;
    chartWindow.MainMenu.Add(averageButton);

    bandsButton = new System.Windows.Controls.Button
    {
    Name = bName, Content = "BANDS", Foreground = bFore, Background = bBack
    };
    bandsButton.Click += OnButtonClick;
    chartWindow.MainMenu.Add(bandsButton);

    /*
    averageButton = new System.Windows.Controls.Button
    {
    if(averageClicked) { Name = "ShowAverage", Content = "AVG", Foreground = Brushes.White, Background = Brushes.DarkOrange }
    else { Name = "HideAverage", Content = "AVG", Foreground = Brushes.Black, Background = Brushes.PeachPuff }
    };
    averageButton.Click += OnButtonClick;
    chartWindow.MainMenu.Add(averageButton);

    bandsButton = new System.Windows.Controls.Button
    {
    if(bandsClicked) { Name = "ShowBands", Content = "BANDS", Foreground = Brushes.White, Background = Brushes.Violet }
    else { Name = "HideBands", Content = "BANDS", Foreground = Brushes.Black, Background = Brushes.Thistle }
    };
    bandsButton.Click += OnButtonClick;
    chartWindow.MainMenu.Add(bandsButton);
    */

    /*
    averageButton = new System.Windows.Controls.Button
    {
    Name = "HideAverage", Content = "AVG", Foreground = Brushes.Black, Background = Brushes.PeachPuff
    };
    averageButton.Click += OnButtonClick;
    chartWindow.MainMenu.Add(averageButton);

    bandsButton = new System.Windows.Controls.Button
    {
    Name = "HideBands", Content = "BANDS", Foreground = Brushes.Black, Background = Brushes.Thistle
    };
    bandsButton.Click += OnButtonClick;
    chartWindow.MainMenu.Add(bandsButton);
    */

    isToolBarButtonAdded = true;
    }

    private void DisposeToolBar()
    {
    if (averageButton!=null)
    {
    averageButton.Click -= OnButtonClick;
    chartWindow.MainMenu.Remove(averageButton);
    averageButton = null;
    }
    if (bandsButton!=null)
    {
    bandsButton.Click -= OnButtonClick;
    chartWindow.MainMenu.Remove(bandsButton);
    bandsButton = null;
    }
    }

    region Properties
    [Browsable(false)]
    [XmlIgnore()]
    public Series<double> Lower
    {
    get { return Values[2]; }
    }

    [Browsable(false)]
    [XmlIgnore()]
    public Series<double> Middle
    {
    get { return Values[1]; }
    }

    [Range(0, int.MaxValue), NinjaScriptProperty]
    [Display(ResourceType = typeof(Custom.Resource), Name = "NumStdDev", GroupName = "NinjaScriptParameters", Order = 0)]
    public double NumStdDev
    { get; set; }

    [Range(1, int.MaxValue), NinjaScriptProperty]
    [Display(ResourceType = typeof(Custom.Resource), Name = "Period", GroupName = "NinjaScriptParameters", Order = 1)]
    public int Period
    { get; set; }

    [Display(ResourceType = typeof(Custom.Resource), Name = "Hide Average", GroupName = "NinjaScriptParameters", Order = 2)]
    public bool averageClicked
    { get; set; }

    [Display(ResourceType = typeof(Custom.Resource), Name = "Hide Bands", GroupName = "NinjaScriptParameters", Order = 3)]
    public bool bandsClicked
    { get; set; }

    [Browsable(false)]
    [XmlIgnore()]
    public Series<double> Upper
    {
    get { return Values[0]; }
    }
    #endregion
    }
    }

    region NinjaScript generated code. Neither change nor remove.

    namespace NinjaTrader.NinjaScript.Indicators
    {
    public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
    {
    private BollingerPlus[] cacheBollingerPlus;
    public BollingerPlus BollingerPlus(double numStdDev, int period)
    {
    return BollingerPlus(Input, numStdDev, period);
    }

    public BollingerPlus BollingerPlus(ISeries<double> input, double numStdDev, int period)
    {
    if (cacheBollingerPlus != null)
    for (int idx = 0; idx < cacheBollingerPlus.Length; idx++)
    if (cacheBollingerPlus[idx] != null && cacheBollingerPlus[idx].NumStdDev == numStdDev && cacheBollingerPlus[idx].Period == period && cacheBollingerPlus[idx].EqualsInput(input))
    return cacheBollingerPlus[idx];
    return CacheIndicator<BollingerPlus>(new BollingerPlus(){ NumStdDev = numStdDev, Period = period }, input, ref cacheBollingerPlus);
    }
    }
    }

    namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
    {
    public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
    {
    public Indicators.BollingerPlus BollingerPlus(double numStdDev, int period)
    {
    return indicator.BollingerPlus(Input, numStdDev, period);
    }

    public Indicators.BollingerPlus BollingerPlus(ISeries<double> input , double numStdDev, int period)
    {
    return indicator.BollingerPlus(input, numStdDev, period);
    }
    }
    }

    namespace NinjaTrader.NinjaScript.Strategies
    {
    public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
    {
    public Indicators.BollingerPlus BollingerPlus(double numStdDev, int period)
    {
    return indicator.BollingerPlus(Input, numStdDev, period);
    }

    public Indicators.BollingerPlus BollingerPlus(ISeries<double> input , double numStdDev, int period)
    {
    return indicator.BollingerPlus(input, numStdDev, period);
    }
    }
    }

    #endregion

    #2
    Hello renner1984,

    You can set the plots brush to transparent to hide it and then set it back to a brush to show it however there is not a specific way to force the chart to re render. The rendering would happen based on the chart events like incoming data or mouse actions. A button click is not a NinjaScript event so that can happen out of sync with the other chart events leading to having to wait to see the result depending on the scripts settings.

    To set a plots color you can use

    Plots[0].Brush = Brushes.Transparent;
    JesseNinjaTrader Customer Service

    Comment


      #3
      What would I use to render the plot drawing as transparent? How can I force the plot to update its color on command (e.g. pressing a button or some other event without having to press "F5" or going through Indicators)? I know this is possible because I have indicators that do this where settings can be changed from a custom dropdown generated by those indicators.

      Comment


        #4
        Hello renner1984,

        The code that I had shown is how you would turn a plot to transparent, that sets the brush of the plot to transparent. You could do that as an action from the button or from OnBarUpdate based on a bool you toggle from the button. As mentioned updates cannot be forced, you can mark that a new render is needed by using ForceRefresh but that still requires something to cause a render like market data or a mouse event in the chart. If you have the source code for one of the custom items you mentioned you could look at how the script in question is making a change to see if it is doing something else.
        JesseNinjaTrader Customer Service

        Comment


          #5
          As per my code in the original post, I have this function

          private void refreshChart()
          {
          try
          {
          ForceRefresh();
          //ReloadAllHistoricalData();
          }
          catch(Exception e)
          {
          Print(e.ToString());
          }
          }​

          However, the plot does not disappear/reappear until I hit "F5" or "Reload NinjaScript". So, ForceRefresh() does not work on its own. So, what could I put in the code to force ForceRefresh() to execute and redraw a plot (whether it is Transparent or any other changes to the historical plot)?

          Comment


            #6
            Hello renner1984,

            From the help guide:

            Note: As the chart is optimized on a timer, calling ForceRefresh() will NOT immediately trigger a render event. Calling ForceRefesh() simply re-queues the render event to trigger during the next timed event. In other words, it may take up to 250ms for the render event to function.
            ​You still would need to wait for the render to happen after making a change that is rendered. ForceRefresh generally wouldn't be needed in this case because you are not using OnRender so a request to re render is not needed.What would be needed is something that causes the script to process which would be market data.

            I can see the plot change on my end if I toggle the brush of a plot using a button so something in your code may be incorrect if you are still having problems with the plot not changing colors. The answer is still the same on how to toggle the plot to be hidden, its brush can be set to transparent to hide it and it can be set to a color to show it. This is what I tried and see this working but I do need to be connected to live data so the chart is processing data so that update happens.

            Keep in mind that to hide a plot you would still need to continue plotting the data, your problem is likely that you are using conditions in OnBarUpdate which prevent saving values to the plots. You need to always plot the data and if you want to hide a plot set it to transparent.


            Code:
            bool isPlotOn;
            protected void OnMyButtonClick(object sender, RoutedEventArgs e)
            {
                if(isPlotOn)
               {
                     Plots[0].Brush = Brushes.Red;
               } else {
                     Plots[0].Brush = Brushes.Transparent;
               }
               isPlotOn = !isPlotOn;
            }
            
            protected override void OnBarUpdate()
            {
               Value[0] = Close[0];
            }
            Last edited by NinjaTrader_Jesse; 06-18-2024, 07:41 AM.
            JesseNinjaTrader Customer Service

            Comment


              #7
              That did work for me, so thank you!

              Unfortunately, this indicator is really just a "dummy" for another project... was hoping someone here could show me how I could get a plot to recalculate including historical bars (e.g. the equivalent of OnBarUpdate running from scratch, replotting the plot values with different values). Any insight on that? For example, a button is pressed and instead of the middle band being SMA it now plots as an EMA instead.

              Comment


                #8
                Hello renner1984,

                To have a script recalculate you would need to use F5, that is the only time it will re run the historical bars and states. You can reset plot values if you wanted to change them later but there is not a way to have the indicator physically recalculate unless you press F5 or re apply it.
                JesseNinjaTrader Customer Service

                Comment

                Latest Posts

                Collapse

                Topics Statistics Last Post
                Started by ngchun1, Today, 09:05 PM
                0 responses
                1 view
                0 likes
                Last Post ngchun1
                by ngchun1
                 
                Started by xfactscout, 07-22-2024, 09:01 PM
                1 response
                23 views
                0 likes
                Last Post xfactscout  
                Started by Chrisnasdaq, 08-26-2023, 08:37 PM
                4 responses
                1,405 views
                0 likes
                Last Post pierodicarlo  
                Started by GillRymhes, 06-23-2022, 09:16 AM
                13 responses
                746 views
                5 likes
                Last Post pierodicarlo  
                Started by aligator, 06-22-2022, 01:10 PM
                13 responses
                1,823 views
                0 likes
                Last Post pierodicarlo  
                Working...
                X