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

OnRender Help

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

    OnRender Help

    Hello,
    The OnRender code below to draw a rectangle above every bar is compiling, but the drawing is not being rendered. Any ideas what is wrong with my code? Also, where would I place a condition such as "if (Close[0] > Open[1])".

    Thank you.
    Code:
    //Examples for this coding came from NT8 Manual Best Practices > Using DrawObjects vs custom graphics in OnRender(), and SampleCustomRender
    			// loop through all of the viewable range of the chart
    			for (int index = ChartBars.FromIndex; index <= ChartBars.ToIndex; index++)  
    			{				
    			
    				// gets the pixel coordinate of the bar index passed to the method - X axis
    				float xStart    = chartControl.GetXByBarIndex(ChartBars, index) ;
    			
    				// gets the pixel coordinate of the price value passed to the method - Y axis
    				float yStart = chartScale.GetYByValue(High.GetValueAt(index) + 2*TickSize);
    				
    				float width = (float) chartControl.BarWidth*4; 				
    
    			    
    				// construct the rectangleF struct to describe the position and size the drawing
    				SharpDX.RectangleF rect = new SharpDX.RectangleF(xStart, yStart, width, width);	
    				
    //				// define the brush used in the rectangle
    				SharpDX.Direct2D1.SolidColorBrush customDXBrush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.Blue); 
    				
    				SharpDX.Direct2D1.SolidColorBrush outlineBrush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.Black);	
    				
    						 						
    				// The RenderTarget consists of two commands related to Rectangles.
    				// The FillRectangle() method is used to "Paint" the area of a Rectangle
    				// execute the render target fill rectangle with desired values
    				RenderTarget.FillRectangle(rect, customDXBrush);
    				
    				// and DrawRectangle() is used to "Paint" the outline of a Rectangle
    				RenderTarget.DrawRectangle(rect, outlineBrush, 2); //Added WH 6/5/2017
    				
    				// always dispose of a brush when finished
    				customDXBrush.Dispose();
    				outlineBrush.Dispose();
    			
    			}

    #2
    On another matter, I have an indicator which has a secondary series plot that is 3x the size of the BarsPeriod.Value. To prevent me having to manually change the value each time I load a different size chart, I am trying to use: SecondaryDataSeriesValue = BarsPeriod.Value * 3; in the code.
    The NT8 manual says BarsPeriod "This property should NOT be accessed within the OnStateChange() method before the State has reached State.DataLoaded" Placing the code in the State.DataLoaded leads to 0 for the plot. If however I place the code in the State.SetDefaults section with a fixed value of say 150 first, then also use SecondaryDataSeriesValue = BarsPeriod.Value * 3; in the State.DataLoaded section, the plot sets to the 150 value, but the value in properties is 3x the BarsPeriod.Value. It's also the same if it is placed in the OnBarUpdate() method. Where do I need to place this code to get the values automatically for the secondary plot?

    Thank you.

    Edit:
    I have found that when the indicator is first installed it picks up the value from State.SetDefaults, then if I reload the indicators by pressing F5, it picks up the values from State.DataLoaded or OnBarUpdate and I get the correct plots. Is this the correct way of using the BarsPeriod code in this instance? Or do secondary plot values need to be hard coded?
    Last edited by GeorgeW; 05-07-2017, 01:21 PM.

    Comment


      #3
      Hello George,

      I've added the code you have posted to an indicator and tested and I am finding the rectangles are being rendered.

      Attached is a screenshot of the chart and the indicator I've tested.

      From the Help guide:
      "Arguments supplied to AddDataSeries() should be hardcoded and NOT dependent on run-time variables which cannot be reliably obtained during State.Configure (e.g., Instrument, Bars, or user input). Attempting to add a data series dynamically is NOT guaranteed and therefore should be avoided. Trying to load bars dynamically may result into an error similar to: Unable to load bars series. Your NinjaScript may be trying to use an additional data series dynamically in an unsupported manner."



      Basically, the primary bar series is not guaranteed to be ready in State.Configure when AddDataSeries() is called. This is especially problematic when optimizing.

      This means that referencing the primary series to dynamically add a secondary series is not supported to do and will not work in all situations.
      Attached Files
      Chelsea B.NinjaTrader Customer Service

      Comment


        #4
        Thanks Chelsea_B.
        I'll have to search my indicator to see why it is not working there. Could you tell be how to centralise the rectangle over the bars, and also, if I want to place a condition for the rectangle to be drawn over a bar, where would that be placed (there will be several different conditions for different coloured rectangles, so I need the most efficient placing so that code is not duplicated)?

        Is there a conflict in using Drawing Objects and custom graphics in Onrender() in the same code, as I am now wondering if that is why the rectangles do not render in my code?
        Last edited by GeorgeW; 05-08-2017, 02:00 AM.

        Comment


          #5
          Hello GeorgeW,

          Subtract the width of the bar from the x position of the rendered object.

          The code for converting the x and y coordinates from price and time can be in OnRender() (or in a method called from OnRender() as these values will need to be calculated each time the chart is scrolled or moved (or rendered).

          Any other code should not be in OnRender().

          There is not a conflict between calling Draw methods in OnBarUpdate and also rendering with OnRender(), however, you should call base.OnRender(chartControl, chartScale); to ensure any objects rendered by another script are still rendered.
          Chelsea B.NinjaTrader Customer Service

          Comment


            #6
            Hello Chelsea_B,

            I have made some adjustments to your sample indicator to centre the the rectangles and they plot, but wherever I try to place a condition to restrict the bars they plot over, they do not plot. I have tried various positions within the OnRender code. Any ideas?
            Code:
            protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
            		{
            			  
            			for (int index = ChartBars.FromIndex; index <= ChartBars.ToIndex; index++)
            			{
            				
            				// gets the pixel coordinate of the bar index passed to the method - X axis
            				float xStart = chartControl.GetXByBarIndex(ChartBars, index);
            
            				// gets the pixel coordinate of the price value passed to the method - Y axis
            				float yStart = chartScale.GetYByValue(High.GetValueAt(index) + 2 * TickSize);
            
            				float width = (float)chartControl.BarWidth * 2;
            
            				
            				// construct the rectangleF struct to describe the position and size the drawing
            				//In order to centrlise the rectangle over the bar, xStart-width/2
            				SharpDX.RectangleF rect = new SharpDX.RectangleF(xStart-width/2, yStart, width, width);
            
            				
            				// define the brush used in the rectangle
            				SharpDX.Direct2D1.SolidColorBrush customDXBrush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.Blue);
            
            				SharpDX.Direct2D1.SolidColorBrush outlineBrush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.Black);
            
            				if (Close[0] > Open[0])
            				{
            				// The RenderTarget consists of two commands related to Rectangles.
            				// The FillRectangle() method is used to "Paint" the area of a Rectangle
            				// execute the render target fill rectangle with desired values
            				RenderTarget.FillRectangle(rect, customDXBrush);
            
            				// and DrawRectangle() is used to "Paint" the outline of a Rectangle
            				RenderTarget.DrawRectangle(rect, outlineBrush, 1); //Added WH 6/5/2017
            				}
            
            				// always dispose of a brush when finished
            				customDXBrush.Dispose();
            				outlineBrush.Dispose(); 				
            
            			}
            			// Default plotting in base class. Should be left Uncommented if indicators holds at least one plot you want displayed
            			base.OnRender(chartControl, chartScale);
            		}

            Comment


              #7
              Originally posted by GeorgeW View Post
              wherever I try to place a condition to restrict the bars they plot over, they do not plot. I have tried various positions within the OnRender code. Any ideas?
              Code:
              if (Close[0] > Open[0])
              Within OnRender you need to use Bars.GetClose() and Bars.GetOpen()

              Comment


                #8
                Hello GeorgeW,

                The High and Close series as well as any other series requires synchronization with the bar series. This happens in any data driven method (OnBarUpdate, OnMarketData, OnMarketDepth) but does not occur in non-data driven methods (OnRender(), custom timers, OnStateChange()..).

                tradesmart is correct. Using Bars.GetClose() and other Bars.Get methods do trigger NinjaTrader to synchronize the series before returning a value.

                You can also call TriggerCustomEvent() to trigger the synchronization of the Close, Open, High, and custom Series objects at any time. However, this is very resource intensive and would cause high CPU if called from OnRender().



                That said, I failed to answer an earlier question of where code like these conditions should go. Any logic or calculations with the exception of calculating x and y coordinates should not be done in OnRender() if possible. This should be done in a data driven event if possible.

                OnRender() triggers a lot. Especially as there is movement. Having to do these calculations and synchronization drives up the CPU.
                But getting the x and y coordinates are still required to do in OnRender() as they are going to be constantly changing as there is movement.

                With conditions such as if (Close[0] > Open[0]) this really should go in OnBarUpdate() but would have to be written to a bool array or bool series as well. An array or list would not need synchronizing and would mean no complex math or synchronizing would be done in OnRender().

                And be sure to reuse any objects you can in OnRender() such as brushes. These code samples are meant to be specific, short, and self contained. So concepts such as reusing brushes for performance gains are not demonstrated.
                Last edited by NinjaTrader_ChelseaB; 05-09-2017, 07:49 AM.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Hello ChelseaB,

                  I can get your test indicator to work when I use if (Bars.GetClose(index)>Bars.GetOpen(index)) to restrict the bars over which the rectangles are rendered, but when I try to use a bool series to restrict them, I am still getting them over all bars. I have attached your test example with my adjustments. I would be grateful if you could point out where my bool series code is going wrong.

                  Thanks.
                  Attached Files

                  Comment


                    #10
                    Instead of
                    PHP Code:
                    if (closeGreaterThanOpen[0] == true
                    use
                    PHP Code:
                    if (closeGreaterThanOpen.GetValueAt(index) == true
                    http://ninjatrader.com/support/helpG...getvalueat.htm

                    Comment


                      #11
                      Hello,

                      Code:
                      if (closeGreaterThanOpen.GetValueAt(index) == true)
                      This code works fine in the simplified code and the rectangles do render to the chart. Thank you.

                      However, once I include a secondary data series, as is included in the more complex indicator I want to adjust, the rectangles disappear. I believe the issue may be related to the one identified in this thread: BarsInProgress always 1 in OnRender() after AddDataSeries() and this one: AddDataSeries and OnBarUpdate (the workaround mentioned in post #2 of this thread does not work for me). Has a fix been found for this issue yet?

                      I have attached a copy of RenderRectangleTest03 which includes the 2nd data series.
                      Attached Files

                      Comment


                        #12
                        Originally posted by GeorgeW View Post
                        once I include a secondary data series, as is included in the more complex indicator I want to adjust, the rectangles disappear.

                        Check BarsInProgress

                        Comment


                          #13
                          Thank you, tradeSmart. I forgot to include
                          Code:
                          if (BarsInProgress == 0)
                          in the RenderrectangleTest03 indicator. Although, funnily enough, when I started the test workspace this morning, the rectangles rendered to the chart without it. They also render when I include it. It was already included in my main indicator, but they do not render there. I'll have to strip it down or try to rebuild it to see what's causing that.

                          Comment


                            #14
                            Originally posted by NinjaTrader_ChelseaB View Post
                            Hello GeorgeW,

                            The High and Close series as well as any other series requires synchronization with the bar series. This happens in any data driven method (OnBarUpdate, OnMarketData, OnMarketDepth) but does not occur in non-data driven methods (OnRender(), custom timers, OnStateChange()..).

                            tradesmart is correct. Using Bars.GetClose() and other Bars.Get methods do trigger NinjaTrader to synchronize the series before returning a value.

                            You can also call TriggerCustomEvent() to trigger the synchronization of the Close, Open, High, and custom Series objects at any time. However, this is very resource intensive and would cause high CPU if called from OnRender().



                            That said, I failed to answer an earlier question of where code like these conditions should go. Any logic or calculations with the exception of calculating x and y coordinates should not be done in OnRender() if possible. This should be done in a data driven event if possible.

                            OnRender() triggers a lot. Especially as there is movement. Having to do these calculations and synchronization drives up the CPU.
                            But getting the x and y coordinates are still required to do in OnRender() as they are going to be constantly changing as there is movement.

                            With conditions such as if (Close[0] > Open[0]) this really should go in OnBarUpdate() but would have to be written to a bool array or bool series as well. An array or list would not need synchronizing and would mean no complex math or synchronizing would be done in OnRender().

                            And be sure to reuse any objects you can in OnRender() such as brushes. These code samples are meant to be specific, short, and self contained. So concepts such as reusing brushes for performance gains are not demonstrated.
                            http://ninjatrader.com/support/forum...249#post461249
                            Chelsea,

                            Although this is a very old thread, I shall appreciate it if I'm able to use this OnRender method to do the rendering on chart candle bar instead of rendering a rectangle shape. I will also want to have a gradient effects on the candle bars. Please, how do I achieve this with this sample code above (or any other methods).

                            Regards.

                            Omololu

                            Comment


                              #15
                              Hello omololu,

                              If you want to fully customize the bars you can create a BarsType to generate custom bars or a ChartStyle to render the bar data in a custom way. OnRender from an Indicator could be used to draw over the bars but they would still exist as they were built/rendered by the selected bars type and chart style. You could make the chart style use transparent colors for the bars and then use OnRender to draw what you like as well.


                              Please let me know if I may be of further assistance.
                              JesseNinjaTrader Customer Service

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by DJ888, 04-16-2024, 06:09 PM
                              6 responses
                              18 views
                              0 likes
                              Last Post DJ888
                              by DJ888
                               
                              Started by Jon17, Today, 04:33 PM
                              0 responses
                              1 view
                              0 likes
                              Last Post Jon17
                              by Jon17
                               
                              Started by Javierw.ok, Today, 04:12 PM
                              0 responses
                              6 views
                              0 likes
                              Last Post Javierw.ok  
                              Started by timmbbo, Today, 08:59 AM
                              2 responses
                              10 views
                              0 likes
                              Last Post bltdavid  
                              Started by alifarahani, Today, 09:40 AM
                              6 responses
                              41 views
                              0 likes
                              Last Post alifarahani  
                              Working...
                              X