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

Avoid secondary data series in OnRender

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

    Avoid secondary data series in OnRender

    Hi,

    I'm working on an indicator that plots a vertical line across all panels given a user input time. I also need a secondary data series (1-Minute) to play a sound once at this time.

    * Without the secondary data series, the indicator renders correctly, but the sound alert well not play at the correct time.
    * With the secondary data series, the indicator renders incorrectly, but the sound alert plays at the correct time.

    It's a catch 22.

    Question: Is there any way within OnRender to distinguish one data series from another?

    When I use ChartBars.FromIndex / ChartBars.ToIndex for the for loop, I'm seeing both primary and secondary data series coming through based on the print statement placed inside the loop. I'm thinking that if there's a way to tell what data series is coming through, I can work around this issue.

    Any help or tips are very much appreciate.

    Thanks,
    gbrad

    #2
    Hello gbrad,

    Thank you for your reply.

    Can you provide a code snippet of what you're doing in OnRender? That would be helpful to determine what's occurring.

    Thanks in advance; I look forward to assisting you further.
    Kate W.NinjaTrader Customer Service

    Comment


      #3
      Hi Kate,

      See snippet below:

      protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
      {
      if (Bars == null || ChartControl == null || Bars.Instrument == null || !IsVisible || !Bars.BarsType.IsIntraday) return;

      int cbti = ChartBars.ToIndex;
      int cbfi = ChartBars.FromIndex;

      try
      {
      if (EnableAlert1)
      {
      SharpDX.Direct2D1.Brush dxBrush = C1.ToDxBrush(RenderTarget);
      NinjaTrader.Gui.Stroke MyStroke = new Stroke(C1, LineStyle1, Width1);

      string LableStr = UseTimeLabel1 ? LabelTime1 : Label1;
      SharpDX.DirectWrite.TextLayout textLayout;
      SharpDX.DirectWrite.TextFormat chartTextFormat = new SharpDX.DirectWrite.TextFormat(Core.Globals.Direct WriteFactory, "Arial",
      SharpDX.DirectWrite.FontWeight.Bold, SharpDX.DirectWrite.FontStyle.Normal, FontSize);
      SharpDX.DirectWrite.TextFormat textFormat = new SharpDX.DirectWrite.TextFormat(Core.Globals.Direct WriteFactory,
      chartTextFormat.FontFamilyName, chartTextFormat.FontWeight, chartTextFormat.FontStyle, FontSize);
      textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.Direct WriteFactory, LableStr, textFormat, 1000, textFormat.FontSize);
      SharpDX.Direct2D1.Brush textBrushDx = C1.ToDxBrush(RenderTarget);
      SharpDX.Vector2 startPointTxt = new SharpDX.Vector2();
      SharpDX.Vector2 endPointTxt = new SharpDX.Vector2();

      for (int idx = cbfi; idx <= cbti; idx++)
      {
      DateTime time0 = Time.GetValueAt(idx);
      DateTime time1 = Time.GetValueAt(idx-1);
      int xCoordinate = chartControl.GetXByTime(time0);

      if (time0 >= AlertTime1 && ((time1.TimeOfDay < Time1.TimeOfDay && time0.Date.Equals(time1.Date)) || time1.Date == time0.Date.AddDays(-1)))
      {
      RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive;
      ChartPanel panel = chartControl.ChartPanels[chartScale.PanelIndex];
      Vector pixelAdjustVec;
      Point startPoint = new Point(xCoordinate, 0);
      double strokePixAdj;

      strokePixAdj = ((double)(MyStroke.Width % 2)).ApproxCompare(0) == 0 ? 0.5d : 0d;
      pixelAdjustVec = new Vector(strokePixAdj, strokePixAdj);

      if (!IsInHitTest)
      {
      RenderTarget.PopAxisAlignedClip();
      RenderTarget.PushAxisAlignedClip(new SharpDX.RectangleF((float)0f, (float)0f, (float)startPoint.X, (float)chartControl.ActualHeight - (float)chartControl.AxisXHeight), RenderTarget.AntialiasMode);

      Point startAdj = (new Point(startPoint.X, 0)) + pixelAdjustVec;
      Point endAdj = (new Point(startPoint.X, chartControl.ActualHeight - chartControl.AxisXHeight)) + pixelAdjustVec;
      RenderTarget.DrawLine(startAdj.ToVector2(), endAdj.ToVector2(), dxBrush, MyStroke.Width*2, MyStroke.StrokeStyle);
      RenderTarget.PopAxisAlignedClip();
      RenderTarget.PushAxisAlignedClip(new SharpDX.RectangleF((float)ChartPanel.X, (float)ChartPanel.Y, (float)ChartPanel.W, (float)ChartPanel.H), RenderTarget.AntialiasMode);
      }
      else
      {
      Point startAdj = (new Point(startPoint.X, 0)) + pixelAdjustVec;
      Point endAdj = (new Point(startPoint.X, chartControl.ActualHeight - chartControl.AxisXHeight)) + pixelAdjustVec;
      RenderTarget.DrawLine(startAdj.ToVector2(), endAdj.ToVector2(), dxBrush, MyStroke.Width, MyStroke.StrokeStyle);
      }

      startPointTxt.X = (float)xCoordinate+10;
      startPointTxt.Y = (float)30;
      endPointTxt.X = startPointTxt.X;
      endPointTxt.Y = startPointTxt.Y;
      RenderTarget.DrawTextLayout(startPointTxt, textLayout, textBrushDx);
      }
      }

      dxBrush.Dispose();
      textLayout.Dispose();
      chartTextFormat.Dispose();
      textFormat.Dispose();
      textBrushDx.Dispose();
      }
      }
      catch {}
      }

      Comment


        #4
        Kate,
        I'm reposting this with less code. I removed code that doesn't really apply to the issue at hand...

        protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
        {
        if (Bars == null || ChartControl == null || Bars.Instrument == null || !IsVisible || !Bars.BarsType.IsIntraday || CurrentBar < 2) return;

        int cbti = ChartBars.ToIndex;
        int cbfi = ChartBars.FromIndex;

        try
        {
        if (EnableAlert1)
        {
        SharpDX.Direct2D1.Brush dxBrush = C1.ToDxBrush(RenderTarget);
        NinjaTrader.Gui.Stroke MyStroke = new Stroke(C1, LineStyle1, Width1);

        for (int idx = cbfi; idx <= cbti; idx++)
        {
        DateTime time0 = Time.GetValueAt(idx);
        DateTime time1 = Time.GetValueAt(idx-1);
        int xCoordinate = chartControl.GetXByTime(time0);

        if (time0 >= AlertTime1 && ((time1.TimeOfDay < Time1.TimeOfDay && time0.Date.Equals(time1.Date)) || time1.Date == time0.Date.AddDays(-1)))
        {
        RenderTarget.AntialiasMode = SharpDX.Direct2D1.AntialiasMode.PerPrimitive;
        ChartPanel panel = chartControl.ChartPanels[chartScale.PanelIndex];
        Vector pixelAdjustVec;
        Point startPoint = new Point(xCoordinate, 0);
        double strokePixAdj;

        strokePixAdj = ((double)(MyStroke.Width % 2)).ApproxCompare(0) == 0 ? 0.5d : 0d;
        pixelAdjustVec = new Vector(strokePixAdj, strokePixAdj);

        if (!IsInHitTest)
        {
        RenderTarget.PopAxisAlignedClip();
        RenderTarget.PushAxisAlignedClip(new SharpDX.RectangleF((float)0f, (float)0f, (float)startPoint.X, (float)chartControl.ActualHeight - (float)chartControl.AxisXHeight), RenderTarget.AntialiasMode);
        Point startAdj = (new Point(startPoint.X, 0)) + pixelAdjustVec;
        Point endAdj = (new Point(startPoint.X, chartControl.ActualHeight - chartControl.AxisXHeight)) + pixelAdjustVec;
        RenderTarget.DrawLine(startAdj.ToVector2(), endAdj.ToVector2(), dxBrush, MyStroke.Width*2, MyStroke.StrokeStyle);
        RenderTarget.PopAxisAlignedClip();
        RenderTarget.PushAxisAlignedClip(new SharpDX.RectangleF((float)ChartPanel.X, (float)ChartPanel.Y, (float)ChartPanel.W, (float)ChartPanel.H), RenderTarget.AntialiasMode);
        }
        else
        {
        Point startAdj = (new Point(startPoint.X, 0)) + pixelAdjustVec;
        Point endAdj = (new Point(startPoint.X, chartControl.ActualHeight - chartControl.AxisXHeight)) + pixelAdjustVec;
        RenderTarget.DrawLine(startAdj.ToVector2(), endAdj.ToVector2(), dxBrush, MyStroke.Width, MyStroke.StrokeStyle);
        }

        }
        }

        xBrush.Dispose();
        }
        }
        catch {}
        }

        Comment


          #5
          Hello gbrad,

          Thank you for your reply.

          Generally, for NinjaScript Properties such as the CurrentBar, BarsInProgress or other inherited properties you would need to store these as variables and access the Variable instead of the property directly. This is due to how the platform handles the event driven methods versus the other methods in the platform like OnRender.

          You could do something as simple as the following:

          Code:
          private int CurrentBIP = -1;
          
          protected override void OnBarUpdate()
          {
          CurrentBIP = BarsInProgress;
          
          }
          
          protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
          {
          if(CurrentBIP == 0)
          {
          
          } else if (CurrentBIP == 1)
          {
          
          }
          }
          You can see the included SampleCustomRender or Pivots indicators for more examples of OnRender usage - the Pivots indicator uses an added data series.


          I look forward to being of further assistance.
          Kate W.NinjaTrader Customer Service

          Comment


            #6
            Hi Kate,

            CurrentBIP didn't work out. I really had high hopes on this BarsInProgress idea. Nice thinking though.

            Let me ask you...is there a way to get the CurrentBar number within OnRender?

            This would be sort of like Time.GetValueAt(idx) but for CurrentBar.

            If there is such a thing, I could write a quick program that may lead to illustrating this issue and may also be a better point to troubleshoot from.

            The secondary series is always 1-minute bars that do not appear on the chart. I'm only using them to sound an alert at the right time. I'm a little puzzled why I would see these bars in OnRender since they don't appear on the chart and also there is this statement right at the beginning of OnRender that has !IsVisible:

            if (Bars == null || ChartControl == null || Bars.Instrument == null || !IsVisible || !Bars.BarsType.IsIntraday || CurrentBar < 2) return;

            Note, the way I know that both data series are flowing through OnRender is from the timestamps on the bars I'm printing within the OnRender for loop.

            Thanks for your help.

            gbrad


            Comment


              #7
              Hello gbrad,

              Thank you for your reply.

              The OnRender() method frequently runs once the State has reached State.Realtime in response to market data updates or a user interacting with the chart (e.g., clicking, resizing, rescaling, etc.). It's not based on whether or not OnBarUpdate is currently processing a specific series. It's entirely possible that when OnRender is running based on a change in the primary series that if you tried to access the CurrentBar from there that it could refer to either data series.

              For this reason, if you need to refer to a specific CurrentBar index, you would need to do pretty much the same thing as with BarsInProgress - save the CurrentBar to a variable and then refer to that on the next pass through OnRender.

              Providing a reduced example that reproduces what you're seeing would be helpful in narrowing down what exactly the issue is that you're seeing may be stemming from. I'd be happy to look over a reduced example.

              Please let us know if we may be of further assistance to you.
              Kate W.NinjaTrader Customer Service

              Comment


                #8
                Hi Kate,

                I found a case where someone was having the same issue:


                The issue really seems to be when adding a secondary data series. When that's done, it breaks OnRender.
                When I put Print("OnRender() BarsInProgress: " + BarsInProgress); in OnRender, I only see 1 in the output, indicating the secondary data series.

                I've prepared two indicator files (make sure you're using an intraday chart, 5-min will be fine):
                gbTimeAlerts1DS - this one only contains a single data series. When you put it on an intraday chart you'll see the lines that are drawn at the input times.
                gbTimeAlerts2DS - this one has a secondary data series (1-minute) which is used to sound alerts at the correct time. When this is included, it breaks OnRender (the lines do not appear).

                Note, the OnRender section in both scripts are identical. The only real difference is the secondary data series and related code within OnBarUpdate.

                The goal is to get the lines to render while also having the necessary secondary data series to play the alerts at the correct time.

                I would be very grateful if you could provide any guidance on how I can achieve this goal.

                Please let me know if you need anything else.

                Many Thanks,
                gbrad
                Attached Files

                Comment


                  #9
                  Hello gbrad,

                  Thank you for your reply.

                  I'm seeing the two indicators plot identically in my testing; please see the below screenshots. Have you removed and readded the indicator to your chart after compiling? That would be necessary to fully pick up changes within OnStateChange.

                  Thanks in advance; I look forward to assisting you further.
                  Attached Files
                  Kate W.NinjaTrader Customer Service

                  Comment


                    #10
                    Hi Kate,

                    Yes, I remove and add it back every time. I never refresh. At this point I've done that over a hundred times.

                    I'm really puzzled now that you got it and I didn't. Is there some sort of global setting that would cause this.

                    Also, the lines are suppose to extend the full screen (all panels) and I see that the lines are not doing that in your screen shots. It doesn't appear that you have another panel, but it should extend the full length (see my screen shot).

                    Thanks,
                    gbrad
                    Attached Files

                    Comment


                      #11
                      Hello gbrad,

                      Thank you for your reply.

                      In further analyzing this, I note you're just referrring to Bars in OnRender:

                      DateTime time0 = Bars.GetTime(idx);

                      Try this instead so you're specifically referring to the primary bars series:

                      DateTime time0 = BarsArray[0].GetTime(idx);

                      That appears to work for me on my end. Try replacing your references to Bars with BarsArray[0].

                      Thanks in advance; I look forward to assisting you further.
                      Kate W.NinjaTrader Customer Service

                      Comment


                        #12
                        Hi Kate,

                        Yeah, I tried that one also a while back. I've used these three so far:

                        BarsArray[0].GetTime(idx);
                        Time.GetValueAt(idx);
                        Bars.GetTime(idx);

                        Don't worry about it for now...I'll do some rethinking/experimenting over the weekend. Hopefully, I'll have a break through.

                        Go enjoy you Easter weekend.

                        Happy Easter
                        ​​​​​​​gbrad

                        Comment


                          #13
                          gbrad, if I understand your intent, you want one DataSeries and a sound played at a specific time? If so, why not use a timer for the sound. That way, you do not need an additional DataSeries with all the associated overhead. If that's not what you are trying to achieve, could you provide a simple statement of the outcome you want (not how you might achieve it).

                          Thanks.
                          Multi-Dimensional Managed Trading
                          jeronymite
                          NinjaTrader Ecosystem Vendor - Mizpah Software

                          Comment


                            #14
                            Hi jeronymite,

                            I've actually solved the issue over the weekend and it's working fine now. When you say timer, what do you mean exactly? I'm always interested in alternative methods.

                            Thanks,
                            gbrad

                            Comment


                              #15
                              The .NET Timer Class: https://docs.microsoft.com/en-us/dot...r?view=net-5.0 You can read all about it and see if it meets any need you have.

                              Thanks.
                              Multi-Dimensional Managed Trading
                              jeronymite
                              NinjaTrader Ecosystem Vendor - Mizpah Software

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by slightly, Today, 12:49 AM
                              0 responses
                              2 views
                              0 likes
                              Last Post slightly  
                              Started by sdauteuil, 09-23-2021, 10:16 AM
                              4 responses
                              1,208 views
                              0 likes
                              Last Post jacobpescaia44  
                              Started by agclub, 04-21-2024, 08:57 PM
                              5 responses
                              34 views
                              0 likes
                              Last Post agclub
                              by agclub
                               
                              Started by ESHunter, Yesterday, 08:06 PM
                              2 responses
                              18 views
                              0 likes
                              Last Post ESHunter  
                              Started by ETFVoyageur, 05-07-2024, 07:05 PM
                              19 responses
                              150 views
                              0 likes
                              Last Post ETFVoyageur  
                              Working...
                              X