Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Help Please - Not Everything Plots on Simple Indicator

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

    Help Please - Not Everything Plots on Simple Indicator

    I've written a simple practice indicator that plots colored UP/Down Volume Bars with an EMA of the Volume over layed on top of the bars. This is strictly a heuristic exercize so there is no urgency attached to my request

    The Up Down bars plot perfectly, but for some reason, the EMA AvgVol plot doesn't show. I cut and pasted code from VolumeUpDown and VOLMA to come up with the sutured indicator. If anyone can take a peek at the source and thell me what I'm doing wrong, it would be greatly appreciated. I'm a trader and not a programmer, though I probably know just enough to get into trouble as is the case here. I know that I can just put the two base indicators on a chart and drag and drop to get the same result, but like I said, this is a heuristic exercise.

    Thanks in advance for any pointers.

    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.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
    {
        /// <summary>
        /// This Indicator plots colored Up & Down Volume Bars and an Exponential Moving Average (EMA) of Volume.
        /// </summary>    
            public class LynxVolUpDownAvg : Indicator
        {
            private EMA AvgVol;
    
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Name                        = "LynxVolUpDownAvg";                
                    Description                    = @"LynxVolUpDownAvg Indicator plots colored Up & Down Volume Bars and an Exponential Moving Average (EMA) of Volume.";
                    Calculate                    = Calculate.OnBarClose;                
                    DrawOnPricePanel            = false;
                    IsOverlay                    = false;
                    IsSuspendedWhileInactive    = true;
                    Period                        = 13;                
    
                    AddPlot(new Stroke(Brushes.Lime, 5),    PlotStyle.Bar,    NinjaTrader.Custom.Resource.VolumeUp);
                    AddPlot(new Stroke(Brushes.Red, 5),        PlotStyle.Bar,    NinjaTrader.Custom.Resource.VolumeDown);
                    AddLine(Brushes.White, 0,                NinjaTrader.Custom.Resource.NinjaScriptIndicatorZeroLine);
                    AddPlot(Brushes.Cyan, "AvgVol");
    //                AddPlot(new Brushes.Cyan, 1, "ema");                
    
                }
                else if (State == State.DataLoaded)
                    AvgVol = EMA(Volume, Period);                    
                else if (State == State.Historical)
                {
                    if (Calculate == Calculate.OnPriceChange)
                    {
                        Draw.TextFixed(this, "NinjaScriptInfo", string.Format(NinjaTrader.Custom.Resource.NinjaScriptOnPriceChangeError, Name), TextPosition.BottomRight);
                        Log(string.Format(NinjaTrader.Custom.Resource.NinjaScriptOnPriceChangeError, Name), LogLevel.Error);
                    }
                }
            }
    
            protected override void OnBarUpdate()
            {
                //
                ///Add your custom indicator logic here.
                //
                    Value[0] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)AvgVol[0]) : AvgVol[0];
    
                if (Close[0] >= Open[0])
                {
                    UpVolume[0] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)Volume[0]) : Volume[0];
                    DownVolume.Reset();
                }
                else
                {
                    UpVolume.Reset();
                    DownVolume[0] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)Volume[0]) : Volume[0];
                }
            }
    
            #region Properties
            [Range(1, int.MaxValue), NinjaScriptProperty]
            [Display(ResourceType = typeof(Custom.Resource), Name = "Period", GroupName = "NinjaScriptParameters", Order = 0)]
            public int Period        
            { get; set; }        
    
            [Browsable(false)]
            [XmlIgnore]
            public Series<double> DownVolume
            {
                get { return Values[1]; }
            }
    
            [Browsable(false)]
            [XmlIgnore]
            public Series<double> UpVolume
            {
                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 LynxVolUpDownAvg[] cacheLynxVolUpDownAvg;
            public LynxVolUpDownAvg LynxVolUpDownAvg(int period)
            {
                return LynxVolUpDownAvg(Input, period);
            }
    
            public LynxVolUpDownAvg LynxVolUpDownAvg(ISeries<double> input, int period)
            {
                if (cacheLynxVolUpDownAvg != null)
                    for (int idx = 0; idx < cacheLynxVolUpDownAvg.Length; idx++)
                        if (cacheLynxVolUpDownAvg[idx] != null && cacheLynxVolUpDownAvg[idx].Period == period && cacheLynxVolUpDownAvg[idx].EqualsInput(input))
                            return cacheLynxVolUpDownAvg[idx];
                return CacheIndicator<LynxVolUpDownAvg>(new LynxVolUpDownAvg(){ Period = period }, input, ref cacheLynxVolUpDownAvg);
            }
        }
    }
    
    namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
    {
        public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
        {
            public Indicators.LynxVolUpDownAvg LynxVolUpDownAvg(int period)
            {
                return indicator.LynxVolUpDownAvg(Input, period);
            }
    
            public Indicators.LynxVolUpDownAvg LynxVolUpDownAvg(ISeries<double> input , int period)
            {
                return indicator.LynxVolUpDownAvg(input, period);
            }
        }
    }
    
    namespace NinjaTrader.NinjaScript.Strategies
    {
        public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
        {
            public Indicators.LynxVolUpDownAvg LynxVolUpDownAvg(int period)
            {
                return indicator.LynxVolUpDownAvg(Input, period);
            }
    
            public Indicators.LynxVolUpDownAvg LynxVolUpDownAvg(ISeries<double> input , int period)
            {
                return indicator.LynxVolUpDownAvg(input, period);
            }
        }
    }
    
    #endregion
    Attached Files

    #2
    Hello dmking,

    Thanks for your post.

    A good effort and a good project.

    When you use AddPlot() the sequence of the Addplot statements listed in the code creates Values[] array sequence number. The first addPlot is the UpVolume and it will be assigned to Values[0]. The second AddPlot is DownVolume and it is assigned to Values[1]. If you next look in the "region Properties", you can see how these are connected for example:

    [Browsable(false)]
    [XmlIgnore] public Series<double> DownVolume { get { return Values[1]; } } You would need to basically make a copy of that (except change the name from DownVolume to VolMA, change the Values to [2]) to do the same thing for the VolMA plot.. So in summary you only need 3 AddPlots and then in Region properties, you need to have the 3 assignments of the plots to the values[]

    In the OnBarUpdate() you are assigning the AvgVol to Values[0] which really would need to be Values[2].

    Comment


      #3
      GM Paul,

      Thanks for taking the time to respond. I'm 99% of the way there and understand your recommendations. A couple of questions:

      As the code stands now it compiles but nothing displays in the panel.

      The task is to display VolumeUp, VolumeDown and AvgVol together. I've implemented your recommendations as shown below.

      Does the order of the statements for the Values[] matter or do they have to follow the order of the AddPlot() statements in the main code, ie VolumeUpVolumeDown, AvgVol?

      Is line 70 what you are talking about
      Value[2] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)AvgVol[0]) : AvgVol[0];

      Line 70 specifies - Value[2] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)AvgVol[0]) : AvgVol[0];
      but line 94 is get { return Values[2]; }. It seems like they should both be Values[] which leads to an error if I change 70 to Values[2].


      Thanks in advance for your guidance.

      //
      //
      //
      #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
      {
      /// <summary>
      /// This Indicator plots colored Up & Down Volume Bars and an Exponential Moving Average (EMA) of Volume.
      /// </summary>
      public class LynxVolUpDownAvg : Indicator
      {
      private EMA AvgVol;

      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Name = "LynxVolUpDownAvg";
      Description = @"LynxVolUpDownAvg Indicator plots colored Up & Down Volume Bars and an Exponential Moving Average (EMA) of Volume.";
      Calculate = Calculate.OnBarClose;
      DrawOnPricePanel = false;
      IsOverlay = false;
      IsSuspendedWhileInactive = true;
      Period = 13;

      AddPlot(new Stroke(Brushes.Lime, 5), PlotStyle.Bar, NinjaTrader.Custom.Resource.VolumeUp);
      AddPlot(new Stroke(Brushes.Red, 5), PlotStyle.Bar, NinjaTrader.Custom.Resource.VolumeDown);
      AddPlot(Brushes.Cyan, "AvgVol");
      AddLine(Brushes.White, 0, NinjaTrader.Custom.Resource.NinjaScriptIndicatorZe roLine);
      }
      else if (State == State.DataLoaded)
      AvgVol = EMA(Volume, Period);
      else if (State == State.Historical)
      {
      if (Calculate == Calculate.OnPriceChange)
      {
      Draw.TextFixed(this, "NinjaScriptInfo", string.Format(NinjaTrader.Custom.Resource.NinjaScr iptOnPriceChangeError, Name), TextPosition.BottomRight);
      Log(string.Format(NinjaTrader.Custom.Resource.Ninj aScriptOnPriceChangeError, Name), LogLevel.Error);
      }
      }
      }

      protected override void OnBarUpdate()
      {
      //
      ///Add your custom indicator logic here.
      //
      Value[2] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)AvgVol[0]) : AvgVol[0];

      if (Close[0] >= Open[0])
      {
      UpVolume[0] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)Volume[0]) : Volume[0];
      DownVolume.Reset();
      }
      else
      {
      UpVolume.Reset();
      DownVolume[0] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)Volume[0]) : Volume[0];
      }
      }

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

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

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

      [Browsable(false)]
      [XmlIgnore]
      public Series<double> UpVolume
      {
      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 LynxVolUpDownAvg[] cacheLynxVolUpDownAvg;
      public LynxVolUpDownAvg LynxVolUpDownAvg(int period)
      {
      return LynxVolUpDownAvg(Input, period);
      }

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

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

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

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

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

      #endregion

      Comment


        #4
        Hello dmking,

        Thanks for your reply.

        When you have a script that compiles but when you apply it and it does not function as expected you can usually check the "log" tab of the control center for any "run time" errors of the script.

        The issue is related to the use of Value[2] in this line: Value[2] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)AvgVol[0]) : AvgVol[0];

        Please change to: Values[2][0] = Instrument.MasterInstrument.InstrumentType == InstrumentType.CryptoCurrency ? Core.Globals.ToCryptocurrencyVolume((long)AvgVol[0]) : AvgVol[0];

        Values[2] is the array, that relates to the plot and [0] would be the current bar of the array to put the value into.

        Comment


          #5
          Paul,

          You da MAN!!!!!!!!!!

          Great advice and guidance all through this... I need to find that log tab.

          Thanks loads everything works as expected and I learned a lot. Again. Thank You.

          D

          Comment

          Latest Posts

          Collapse

          Topics Statistics Last Post
          Started by Geovanny Suaza, 02-11-2026, 06:32 PM
          0 responses
          650 views
          0 likes
          Last Post Geovanny Suaza  
          Started by Geovanny Suaza, 02-11-2026, 05:51 PM
          0 responses
          370 views
          1 like
          Last Post Geovanny Suaza  
          Started by Mindset, 02-09-2026, 11:44 AM
          0 responses
          109 views
          0 likes
          Last Post Mindset
          by Mindset
           
          Started by Geovanny Suaza, 02-02-2026, 12:30 PM
          0 responses
          574 views
          1 like
          Last Post Geovanny Suaza  
          Started by RFrosty, 01-28-2026, 06:49 PM
          0 responses
          577 views
          1 like
          Last Post RFrosty
          by RFrosty
           
          Working...
          X