Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

OnRender Performance Questions

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

    OnRender Performance Questions

    Hello,

    I'm facing performance issues with my `OnRender` implementation in NinjaTrader, specifically when scrolling/zooming through the chart. The performance noticeably degrades, and I'm trying to understand the root cause.

    I've implemented a dictionary to map bar indexes to pattern IDs, which I then iterate through in `OnRender` to render pattern IDs relative to their candles. Here's a simplified version of my approach:

    Code:
    // Dictionary holding bar index and Pattern IDs
    private Dictionary<int, List<int>> erkannteMusterProIndex_Long = new Dictionary<int, List<int>>();
    
    // OnRender implementation
    protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
            {
              
                base.OnRender(chartControl, chartScale);
              
                int fromIndex = ChartBars.FromIndex;
                int toIndex = ChartBars.ToIndex;
                // Durchlaufe alle Einträge im Dictionary
                foreach (var entry in erkannteMusterProIndex_Long.Where(e => e.Key >= toIndex -25 && e.Key <= toIndex))
                {
                    int barIndex = entry.Key; // Der Index der Kerze
                    List<int> musterListe = entry.Value; // Die Liste der Muster für diese Kerze
                  
                    // Schriftart und Stil
                    SharpDX.DirectWrite.TextFormat textFormat = new SharpDX.DirectWrite.TextFormat(
                        NinjaTrader.Core.Globals.DirectWriteFactory,
                        "Arial",
                        SharpDX.DirectWrite.FontWeight.Bold, // Hier setzen wir den Text auf fett
                        SharpDX.DirectWrite.FontStyle.Normal,
                        14
                    );
                    SharpDX.Direct2D1.SolidColorBrush brush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget, SharpDX.Color.Green);
                  
                    float baseYPosition = 0; // Initialisieren der Basis-Y-Position; // Initialisieren der Basis-Y-Position
                    for (int i = 0; i < musterListe.Count; i++)
                    {
                        int musterNummer = musterListe[i];
                        string text = musterNummer.ToString();
                      
                        SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(NinjaTrader.Core.Globals.DirectWriteFactory, text, textFormat, 100, 100 );
                      
                        // Berechne die X-Position der aktuellen Bar im Chart
                        double barWidth = chartControl.BarWidth;
                        int  xPosition = chartControl.GetXByBarIndex(ChartBars, barIndex) ;
                      
                        // Berechne die Y-Position für das Zeichnen des Musters, basierend auf dem Low der Kerze plus einem Offset
                        // Die Verwendung von Low[barIndex] funktioniert in OnRender nicht direkt. Du musst den Wert umrechnen:
                        if ( i == 0 )
                        {
                            baseYPosition = chartScale.GetYByValue(Low.GetValueAt(barIndex)) + 5; // Offset nach unten für jedes Muster
                        }
                      
                        float yPosition = baseYPosition + (textLayout.Metrics.Height * i);
                      
                        // create a rectangle which will automatically resize to the width/height of the textLayout
    textLayout.Metrics.Height);
                      
                        // execute the render target draw rectangle with desired values
                                          
                        SharpDX.Vector2 startPoint = new SharpDX.Vector2(xPosition - 4, yPosition);
                        // Zeichne den Text bei den ersten sichtbaren Bar-Koordinaten als Beispiel      
                        RenderTarget.DrawTextLayout(startPoint, textLayout, brush);
                        textLayout.Dispose();
                      
                    }
                    // Aufräumen
                    textFormat.Dispose();
                    brush.Dispose();
                }
              
              
                      
            }​
    This implementation seems to cause performance issues, particularly during chart interactions like zooming and scrolling, even though `OnRender` is being called frequently (about 4 times per second).

    Is there a more performance-optimized way to manage and render these pattern IDs for visible bars only? How can I improve the efficiency of this rendering logic to mitigate the scrolling/zooming performance impact?

    Any insights or suggestions would be greatly appreciated!

    #2
    Hello lakman184,

    Some obvious reasons would be that you are using a linq expression to search the dictionary which will use resources for each loop iteration to find an element, if possible I would suggest not using a dictionary and instead use a Series or other type which natively supports indexing and then just use the bar index directly on the Series GetValueAt method.

    Another item is that you are creating a new brush and TextFormat for each iteration, those don't appear to change so those should be defined out of the loops or in OnRenderTargetChanged. https://ninjatrader.com/support/help...rTargetChanged

    You have an additional loops within your first loop which could cause extra usage, if possible I would suggest trying to simplify what you are doing to be index based instead of using loops.

    In most cases the suggested approach is to prepare all of your data in a Series<double> from OnBarUpdate, the result should be ready before using it in OnRender. If you do the processing at a less frequent interval from OnBarUpdate and then record the result in a Series<double> you can use GetValueAt on the series and just render the result for each bar. That would be similar to the sample in the following page which only gets a value for the currently visible bars from the series which you can then render. https://ninjatrader.com/support/help...ghtsub=toindex

    Comment


      #3
      Hi Jesse,

      Is there a way to change the amount of times OnRender is called per minute? Lets say I wanted to keep all of the drawing the same but only update the screen every 20 seconds. How would I accomplish this?

      Comment


        #4
        Hello morpheus0,

        There is no way to change when OnRender is called. That override is called any time a new render is required which can be for a wide variety of reasons. If you are still having performance problems you would be best off looking at the items I had noted. OnRender is intended to be used with pre calculated data meaning whatever you are trying to display should have already been processed in OnBarUpdate before being rendered. A simple way of looking at this would be your loop, in OnRender that loop could be executed thousands of times in a very short period so it will degrade performance, if that loops was instead in OnBarUpdate it will be called much less frequently which gains your performance back. The end result that needs rendered can be set to a Series<T> from OnBarUpdate so that your OnRender can access the values based on their indexes which removes linq expression slowness from your logic.

        Comment


          #5
          All of my data IS pre-calculated and not done during the onRender drawing phase - but there's got to be some way to prevent the amount of times it is being called. What if the script runs on bar close but you are using onRender just for minimizing the amount of drawing objects on screen.

          During high volatility Ive seen onrender called over 200 times in a minute and it did not update a single drawing object. Every drawing object stayed the same.

          Comment


            #6
            Hello morpheus0,

            You are using partially calculated data, you still have loops in OnRender meaning you still need to process that data before its rendered. Precalculated data is data that can be accessed from a series based on the bar index with no looping or other processing required.

            On Render is supposed to be called extremely frequently because that is how the chart is displayed, your logic in OnRender needs to be at its most simple form to avoid performance impacts.

            We do not suggest trying to use drawing objects from OnRender, they are also just outlets for rendering so calling them in OnRender can have major performance impacts. Drawing objects are intended to be used from OnBarUpdate where they are called infrequently. Using Onrender implies that you will do your own rendering and not use the platforms existing features like drawing objects or indicators, you are now in control of rendering with sharpdx instead of using the platforms existing tools.

            Comment


              #7
              Your own pivot indicator is drawing lines. Im not sure what you mean not to use drawing objects in onRender. Clearly lines and boxes are being drawn here in almost all examples.

              Ok so there is no way to reduce the frequency of drawing. Maybe this could be looked into -- Drawing updates should be possible. I want to maintain a consistent framerate - DirectX has provided options to keep a steady framerate etc. Mainly using drawing on predefined buffers.

              Comment


                #8
                Hello morpheus0,

                Yes the pivots calculates data in OnBarUpdate and stores it to a series, that is then custom rendered in OnRender. That is the efficiency process that your script also needs to follow. The pivots loops through the series that store the data (no calculation being done) and also loops over the visible bars which OnRender is displaying (no calculation being done). Then it displays the data.


                If what you are doing is causing a lag in the chart or delay that means you are not using OnRender correctly, you need to use OnRender for only displaying data and not doing any calculations or drawing tools. OnRender is intended to be called extremely quickly so whatever logic is in there needs to be able to execute extremely fast without delay.



                Comment

                Latest Posts

                Collapse

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