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

Chart rendering failed-same factory instance

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

    #16
    Originally posted by saltminer View Post
    Hi,
    I am needing some assistance with avoiding this OnRender exception. It is not occurring on my computer (frustratingly) but on customers' computers.

    Any help you've got would be appreciated.
    Cheers,
    saltminer
    Are you both using the same OS, same MS latest patches, same video drivers, 32 bit NT or 64 bit?

    So what's the difference, if any...between you and the customer?

    Comment


      #17
      Thank you for the updated sample. You are correct that this advice may contradict other advice given in the help guide. My goal in giving this advice was geared more toward isolating, reproducing, and repairing what is occurring in this particular case. If we know every SharpDX object is being set up and torn down inside a method, this will simplify the situation greatly. I would also like to agree with Sledge in that the more we know about the customer's systems, the better a position we will be in. I believe if it is possible to capture a workspace file from a customer's system which contains only built-in indicators and strategies, and NinjaScript source from this thread, this will be especially helpful.
      Last edited by NinjaTrader_JessicaP; 04-13-2017, 06:43 AM.
      Jessica P.NinjaTrader Customer Service

      Comment


        #18
        I reviewed our help guide, and our examples conform to my advice. Here is an example of a DX brush from the help guide that does not survive local scope.

        Code:
        [FONT=Courier New]protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
        {
          // get the starting and ending bars from what is rendered on the chart
          float startX = chartControl.GetXByBarIndex(ChartBars, ChartBars.FromIndex);
          float endX = chartControl.GetXByBarIndex(ChartBars, ChartBars.ToIndex);
         
          // Loop through each Plot Values on the chart
          for (int seriesCount = 0; seriesCount < Values.Length; seriesCount++)
          {
            // get the value at the last bar on the chart (if it has been set)
            if (Values[seriesCount].IsValidDataPointAt(ChartBars.ToIndex))
            {
                double plotValue = Values[seriesCount].GetValueAt(ChartBars.ToIndex);
         
                // convert the plot value to the charts "Y" axis point
                float chartScaleYValue = chartScale.GetYByValue(plotValue);
         
                // calculate the x and y values for the line to start and end
                SharpDX.Vector2 startPoint = new SharpDX.Vector2(startX, chartScaleYValue);
                SharpDX.Vector2 endPoint = new SharpDX.Vector2(endX, chartScaleYValue);
         
                // draw a line between the start and end point at each plot using the plots SharpDX Brush color and style
                RenderTarget.DrawLine(startPoint, endPoint, Plots[seriesCount].BrushDX,
                  Plots[seriesCount].Width, Plots[seriesCount].StrokeStyle);
         
                // use the chart control text form to draw plot values along the line
                SharpDX.DirectWrite.TextFormat textFormat = chartControl.Properties.LabelFont.ToDirectWriteTextFormat();
         
                // calculate the which will be rendered at each plot using it the plot name and its price
                string textToRender = Plots[seriesCount].Name + ": " + plotValue;
         
                // calculate the layout of the text to be drawn
                SharpDX.DirectWrite.TextLayout textLayout = new SharpDX.DirectWrite.TextLayout(Core.Globals.DirectWriteFactory,
                  textToRender, textFormat, 200, textFormat.FontSize);
         
                // draw a line at each plot using the plots SharpDX Brush color at the calculated start point
                RenderTarget.DrawTextLayout(startPoint, textLayout, Plots[seriesCount].BrushDX);
         
                // dipose of the unmanaged resources used
                textLayout.Dispose();
                textFormat.Dispose();
            }
          }
        }[/FONT]
        Jessica P.NinjaTrader Customer Service

        Comment


          #19
          Factory error continues

          Hi Jessica,
          changing the code as per your recent guidance - creating local instances of DX Brushes only within OnRender - has failed to make a difference. I modified all the indicators that use OnRender() in this suite of products - there are 5 that use OnRender(). I added a compiler variable
          #define LOCALRENDEROBJECTS
          I did this so I could easily swap back and forth between the version of the code that utilizes OnRenderTargetChanged() or to do the new version that instantiates every time within OnRender. Below is an example OnRender(), using two Brush objects and also a brush created on the fly from a Plot's Brush.

          Code:
          protected override void OnRender(Gui.Chart.ChartControl chartControl, Gui.Chart.ChartScale chartScale)
          		{
          			if (Bars == null || chartControl == null || chartScale == null)
          				return;			
          			if (CurrentBars[0] < 20)
          				return;
          			if (ChartPanel==null)
          				return;
          			if (!(State==State.Historical || State==State.Realtime))
          				return;
          			if (chartControl.Visibility != Visibility.Visible)
          				return;
          			
          			base.OnRender(chartControl,chartScale);
          #if LOCALRENDEROBJECTS	
          			upperBrush = upColor.ToDxBrush(RenderTarget);
          			upperBrush.Opacity = (float)(regionOpacity/10.0);
          			lowerBrush = downColor.ToDxBrush(RenderTarget);
          			lowerBrush.Opacity = (float)(regionOpacity/10.0);
          #endif
          			int y1 = chartScale.GetYByValue(SIXONE.GetValueAt(CurrentBars[0] - AZ));
          			int y2 = chartScale.GetYByValue(SIXSIX.GetValueAt(CurrentBars[0] - AZ));
          			int x1 = chartControl.GetXByBarIndex(ChartBars,CurrentBars[0]-(liveLatestBar?0:AZ));
          			int width = x1 - chartControl.GetXByBarIndex(ChartBars,CurrentBars[0]-1-(liveLatestBar?0:AZ));
          			int x2 = x1 + (int)Math.Max(30,width*(4+Calculate==Calculate.OnBarClose?1:0)+(liveLatestBar?0:1));
          			
          			if (SIXONE.IsValidDataPointAt(CurrentBars[0]-AZ) && SIXSIX.IsValidDataPointAt(CurrentBars[0]-AZ))
          				RenderTarget.FillRectangle(new SharpDX.RectangleF((float)x1,(float)y1,(float)(x2-x1+1),(float)(y2-y1)),upperBrush);
          			
          			y1 = chartScale.GetYByValue(FIVEONE.GetValueAt(CurrentBars[0] - AZ));
          			y2 = chartScale.GetYByValue(FIVESIX.GetValueAt(CurrentBars[0] - AZ));
          			
          			if (FIVEONE.IsValidDataPointAt(CurrentBars[0]-AZ) && FIVESIX.IsValidDataPointAt(CurrentBars[0]-AZ))
          				RenderTarget.FillRectangle(new SharpDX.RectangleF((float)x1,(float)y1,(float)(x2-x1+1),(float)(y2-y1)),lowerBrush);
          			
          			
          			// extend lines
          			x1 = chartControl.GetXByBarIndex(ChartBars,CurrentBars[0]-AZ)-0;
          			width = x1 - chartControl.GetXByBarIndex(ChartBars,CurrentBars[0]-1-AZ);
          			x2 = x1 + (int)Math.Max(30,width*(4+(Calculate==Calculate.OnBarClose?1:0)+(liveLatestBar?0:1)));
          			for (int line = 0; line<Plots.Length; line++)
          			{
          				if (!Values[line].IsValidDataPointAt(CurrentBars[0]-AZ) || Plots[line].Brush.ToString()==Brushes.Transparent.ToString())
          					continue;
          				y1 = chartScale.GetYByValue(Values[line].GetValueAt(CurrentBars[0]-AZ));
          				RenderTarget.DrawLine(new SharpDX.Vector2((float)x1,(float)y1),new SharpDX.Vector2((float)x2,(float)y1),Plots[line].Brush.ToDxBrush(RenderTarget),Plots[line].Width,Plots[line].StrokeStyle);
          				//Print("drew line "+x1+"/"+y1+" to "+x2+"/"+y1+", width is "+ChartPanel.W+" height is "+ChartPanel.H+" on line "+line+" from value "+Values[line].GetValueAt(CurrentBars[0]-AZ)+", CurrentBars[0]="+CurrentBars[0]+"/"+CurrentBars[0]);
          			}
          						
          #if LOCALRENDEROBJECTS
          				DisposeOfGraphicsResources();
          #endif
          		}
          Unfortunately this is STILL creating the following error:
          2017-04-18 14:49:55:515|3|4|A direct X error has occurred while rendering the chart: HRESULT: [0x88990012], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_WRONG_FACTORY/WrongFactory], Message: Objects used together must be created from the same factory instance.
          2017-04-18 14:49:55:515|3|16|Chart rendering failed. There is likely a problem with a chart object's OnRender method. D2D error = 'HRESULT: [0x88990012], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_WRONG_FACTORY/WrongFactory], Message: Objects used together must be created from the same factory instance. '


          What do you suggest as a way forward?

          Thanks,
          saltminer

          Comment


            #20
            It looks like we were able to rule out SharpDX brushes as the cause. I believe at this point we will need to focus on creating a reproducible scenario. I have been given code samples on my end via e-mail. I will be returning to this thread when I have a reliable way to see what the customer is seeing on my end in a controlled environment, with steps you will be able to use as well. It is my belief that when we have stack traces and the ability to make this happen with the debugger running it will become much easier to diagnose and fix this behavior.
            Jessica P.NinjaTrader Customer Service

            Comment


              #21
              In the meantime, to answer a previous question directly,

              I have a question about a TextLayout I am using to draw some text. It is generated on-the-fly in OnRender() and is based on a DirectWriteFactory in Ninja.Core.Globals. Can this factory instance change, and thus produce this "not the same factory instance" problem?
              This can be quickly tested with a singleton, e.g.

              Code:
              private static SharpDX.Direct2D1.Factory GetFactory()
              {
                  if (null == myFactory)
                  {
                      myFactory = NinjaTrader.Core.Globals.D2DFactory;
                  }
                  return myFactory;
              }
              private static SharpDX.Direct2D1.Factory myFactory;
              If using GetFactory() instead of NinjaTrader.Core.Globals.DirectWriteFactory does not resolve this customer's query, then we will be able to rule out this as a possible explanation as well.
              Last edited by NinjaTrader_JessicaP; 04-20-2017, 07:28 AM.
              Jessica P.NinjaTrader Customer Service

              Comment


                #22
                imalil and saltminer, I also want to mention that there was a new release of NinjaTrader. Please ensure that both you and any affected customers have upgraded to version 8.0.6.0 .
                Jessica P.NinjaTrader Customer Service

                Comment


                  #23
                  Another idea

                  Hi Jessica, thanks for the support on this.

                  I had another idea - there are some brushes being created to create a semi-transparent background on various alert events (infrequently).
                  Code in OnBarUpdate() looks like this:

                  Code:
                  				Brush bgBrush = pSellColor.Clone();
                  				bgBrush.Opacity = backGroundOpacity2/256.0;
                  				bgBrush.Freeze();
                  				BackBrushes[1] = bgBrush;
                  Could there be any issue with doing this, and having OnRender() code doing custom graphics? If the RenderTarget changed during the day, would old brushes on historical bars still painting background colors cause an error?

                  - -

                  By the way, the code example posted of a static instance of a Factory is a bit mixed up. There are two (at least) factories
                  * Core.Globals.DirectWriteFactory (used for TextLayout)
                  * Core.Globals.D2DFactory (used for PathGeometry)
                  The example confused the two.

                  Both factories are used in this suite of indicators. I have implemented your code suggestion, and we'll see if it makes a difference.

                  Thanks,
                  saltminer

                  Comment


                    #24
                    Thank you for looking over the code. This was a nice catch and I have corrected the code example I posted earlier.

                    With respect to freezing and cloning, from what I was able to find online in MSDN's publicly available documentation,

                    Learn how to use and create freezable objects in Windows Presentation Foundation (WPF) applications.


                    bgBrush is said to be a deep copy of pSellColor. While the implications with respect to brushes are not explicitly stated, if pSellColor retains memory of its factory, a scenario where this is causing this behavior is then possible.

                    To rule this out as a possibility I recommend memoizing brushes into a static class-level Dictionary "pallet" with ARGB values as keys and frozen brushes as values. This method (and your second set of eyes is appreciated as this is difficult to test) may help make it easy to retrieve frozen brushes by ARGB values.

                    Code:
                    [FONT=Courier New]
                    private static Dictionary<int, Brush> FrozenBrushes;
                    private static byte GetA(int ARGB)
                    {
                        return (byte) ((ARGB & 0xFF000000) >> 0x18);
                    }
                    private static byte GetR(int ARGB)
                    {
                        return (byte) ((ARGB & 0x00FF0000) >> 0x10);
                    }
                    private static byte GetG(int ARGB)
                    {
                        return (byte) ((ARGB & 0x0000FF00) >> 0x08);
                    }
                    private static byte GetB(int ARGB)
                    {
                        return (byte) ((ARGB & 0x000000FF) >> 0x00);
                    }
                    private static int GetARGB(byte A, byte R, byte G, byte B)
                    {
                        return (A << 0x18) + (R << 0x10) + (G << 0x08) + (B << 0x00) ;
                    }
                    private static Brush GetFrozenBrush(SolidColorBrush SourceBrush)
                    {
                        Brush output;
                        int argb = GetARGB(SourceBrush.Color.A, SourceBrush.Color.R, SourceBrush.Color.G, SourceBrush.Color.B);
                        if (null == FrozenBrushes)
                        {
                            FrozenBrushes = new Dictionary<int, Brush>();
                        }
                        if (FrozenBrushes.ContainsKey(argb))
                        {
                            return FrozenBrushes[argb];
                        }
                        output = SourceBrush.Clone();
                        output.Freeze();
                        return (FrozenBrushes[argb] = output);
                    }[/FONT][FONT=Courier New][FONT=Courier New]
                    private static Brush GetFrozenBrush(byte A, byte R, byte G, byte B)
                    {
                        if (null != FrozenBrushes && FrozenBrushes.ContainsKey(GetARGB(A, R, G, B)))
                        {
                            return FrozenBrushes[[/FONT][/FONT][FONT=Courier New][FONT=Courier New][FONT=Courier New][FONT=Courier New]GetARGB(A, R, G, B)[/FONT][/FONT]];
                        }
                        return GetFrozenBrush(new SolidColorBrush(Color.FromArgb(A, R, G, B)));
                    }[/FONT][FONT=Courier New]
                    [/FONT] private static Brush GetFrozenBrush(int ARGB)
                    {
                        return GetFrozenBrush(GetA(ARGB), GetR(ARGB), GetG(ARGB), GetB(ARGB));
                    }[/FONT][FONT=Courier New]
                    [/FONT]
                    Last edited by NinjaTrader_JessicaP; 04-20-2017, 08:23 AM.
                    Jessica P.NinjaTrader Customer Service

                    Comment


                      #25
                      Hi Jessica,
                      thanks for that. Maybe I"m missing the point of it, but isn't it still going to be using a frozen Clone that *might* retain its Factory?
                      Couldn't we just use any call of the OnRenderTargetChanged() method to reinstantiate this semi-transparent brush?

                      saltminer

                      Comment


                        #26
                        Draw. problems

                        Hi Jessica,
                        I'm getting some results back from the vendor. There appears to be some problems with Ninja's own Draw code. For example in this one, where Region crashes.

                        2017-04-20 13:54:07:405 ERROR: Failed to call OnRender() for chart object 'Region': 'The calling thread cannot access this object because a different thread owns it.'
                        2017-04-20 14:03:49:217 ERROR: A direct X error has occurred while rendering the chart: HRESULT: [0x88990012], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_WRONG_FACTORY/WrongFactory], Message: Objects used together must be created from the same factory instance.
                        2017-04-20 14:03:49:218 ERROR: Chart rendering failed. There is likely a problem with a chart object's OnRender method. D2D error = 'HRESULT: [0x88990012], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_WRONG_FACTORY/WrongFactory], Message: Objects used together must be created from the same factory instance. '

                        However, the "same factory instance" error can occur just by itself too - often straight after the trace files show Cbi.Instrument.RequestBars.

                        Cheers,
                        saltminer

                        Comment


                          #27
                          Thank you for your report saltminer. I will be investigating the Ninja platform itself to see if we can cause D2DERR_WRONG_FACTORY using only built-in NinjaScript and components. When I find more I will post here.
                          Jessica P.NinjaTrader Customer Service

                          Comment


                            #28
                            After an internal review I have replied directly via e-mail. I was able to determine that NinjaTrader only has one factory instance. Some of the information used to write tests and determine this can be found in the below publicly available links.



                            SharpDX GitHub Repository. Contribute to sharpdx/SharpDX development by creating an account on GitHub.

                            D2D1CreateFactory(D2D1_FACTORY_TYPE,REFIID,D2D1_FACTORY_OPTIONS*,void**) creates a factory object that can be used to create Direct2D resources.


                            The following files contain references to Core.Globals.D2DFactory . These have all been tested and guaranteed. We recommend users who come across D2DERR_WRONG_FACTORY copy and use code samples directly from these files to avoid this condition :

                            ChartStyles/@LineOnCloseStyle.cs
                            ChartStyles/@MountainStyle.cs
                            DrawingTools/@AndrewsPitchfork.cs
                            DrawingTools/@Arc.cs
                            DrawingTools/@ChartMarkers.cs
                            DrawingTools/@FibonacciTools.cs
                            DrawingTools/@GannFan.cs
                            DrawingTools/@Lines.cs
                            DrawingTools/@Region.cs
                            DrawingTools/@Shapes.cs
                            DrawingTools/@TrendChannel.cs
                            Indicators/@ZigZag.cs

                            Please let us know if there are any other ways we can help.
                            Jessica P.NinjaTrader Customer Service

                            Comment


                              #29
                              Hi, Jessica-

                              I installed 8061 yesterday. Today an hour before close I got the D2DERR_WRONG_FACTORY error, then it crashed.

                              I'm not as sophisticated as most on this forum. I see your instructions on how to fix, but I don't know how to implement. I have a few charts using lineonclose and I draw some lines.

                              Could you tell me how to use the .cs files you mention in my code? What part of the code do I copy and where exactly do I paste it?

                              Thank you.

                              Comment


                                #30
                                I will be happy to help imalil . Our first goal should be isolating which one of your tools is causing this. A great way to isolate things is to start with safe mode.

                                So we can further diagnose your system, please start NinjaTrader in Safe Mode.
                                Safe Mode will prevent NinjaTrader from:
                                • Loading workspaces.
                                • Connecting on start-up.
                                • Loading custom assemblies.
                                • Getting instrument updates from the server.

                                To enable safe mode, please use the following steps:
                                • Exit NinjaTrader.
                                • Hold the CONTROL key and double click the NinjaTrader icon.
                                • Keep the CONTROL key held down until you see the Control Center.
                                • You can verify you are in safe mode by going to Help -> About.


                                When you run in safe mode, you will likely notice that NinjaTrader runs smoothly. From there, I would like to advise you then create separate workspaces for each of your NinjaScript tools, such as your strategies and indicators.

                                I would then restart Ninja in normal mode and trade normally until an hour and a half before close. After, I would close all but one of your workspaces to test. If you trade normally and you receive a crash, make a note of what you were doing at the time, what tools were running, and what the market was like. It will help us help if you let us know this information here.


                                By duplicating the conditions leading to a crash, and isolating components in different workspaces, we will be able to determine which tool is causing your copy of Ninja to crash. Please let us know once you have determined this. If it turns out to be a tool you wrote, please e-mail a stripped-down copy of your source to platformsupport[at]ninjatrader[dot]com . By stripped down, I mean that only parts of the code related to drawing and rendering on a chart are left in; we are not interested in your trade logic, and you can leave this out. If it turns out to be a third party tool you purchased, please also e-mail this information to platformsupport[at]ninjatrader[dot]com .
                                Jessica P.NinjaTrader Customer Service

                                Comment

                                Latest Posts

                                Collapse

                                Topics Statistics Last Post
                                Started by kevinenergy, 02-17-2023, 12:42 PM
                                115 responses
                                2,699 views
                                1 like
                                Last Post kevinenergy  
                                Started by prdecast, Today, 06:07 AM
                                1 response
                                4 views
                                0 likes
                                Last Post NinjaTrader_LuisH  
                                Started by Christopher_R, Today, 12:29 AM
                                1 response
                                14 views
                                0 likes
                                Last Post NinjaTrader_LuisH  
                                Started by chartchart, 05-19-2021, 04:14 PM
                                3 responses
                                577 views
                                1 like
                                Last Post NinjaTrader_Gaby  
                                Started by bsbisme, Yesterday, 02:08 PM
                                1 response
                                15 views
                                0 likes
                                Last Post NinjaTrader_Gaby  
                                Working...
                                X