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

"Unhandled exception: Write lock may not be acquired with read lock held"

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

    "Unhandled exception: Write lock may not be acquired with read lock held"

    Hello,

    I'm getting the "Unhandled exception: Write lock may not be acquired with read lock held" and my chart freezes NT8.

    I asked ChatGPT about this and it suggests the following:

    If you are getting the error "Unhandled exception: Write lock may not be acquired with read lock held" in NinjaTrader 8 and you are not using ReadLock or WriteLock in your code, the issue may be caused by a race condition or another synchronization problem. To fix the error, you will need to identify the shared resource that is causing the problem and use a locking mechanism such as the lock statement to synchronize access to it.​
    It seems that the following code may contain the cause of the error, but I have no idea how to approach the issue.
    Code:
    else if (State == State.Configure)
    {
    
    Brush1 = new SolidColorBrush((Color)ColorConverter.ConvertFromS tring("#FF1B1B1B"));
    Brush1.Freeze();
    
    Brush2 = new SolidColorBrush((Color)ColorConverter.ConvertFromS tring("#FF403F45"));
    Brush2.Freeze();
    
    NoTradeBrush =new SolidColorBrush(Color.FromRgb(64,64,64));
    //NoTradeBrush =new SolidColorBrush(Color.FromRgb(74,75,79));
    NoTradeBrush.Freeze();
    
    ShortBrush = new SolidColorBrush(Color.FromRgb(82,0,0));
    ShortBrush.Freeze();
    
    //AddDataSeries("ES 12-22", Data.BarsPeriodType.Range, 4, Data.MarketDataType.Last);
    
    
    
    
    
    AddDataSeries("",Data.BarsPeriodType.Range, 4, Data.MarketDataType.Last);
    
    EMA1 = EMA(Close, EMAPeriod);
    EMA2 = EMASecondarySeries(Close,5,4);
    SMA1 = SMA(EMA1, SMAPeriod);
    
    emaRange = EMASecondarySeries(EMAPeriod,RangePeriod);
    smaRange = SMA(emaRange, SMAPeriod);
    
    myTrendLine = AuEMA(Close, PeriodVWMA);
    
    DynSR = DynamicSR(Close, PeriodoDynSR);
    mad = aslMADifference(EMAPeriod,SMAPeriod,SepCorta);
    kama = KAMA(BarsArray[1],Fast, KPeriod, Slow);
    
    
    sw = Swing(mad,3);
    mk1 = MomentumKamaRp(Fast,KPeriod,Slow,MomPeriod,mk1Cota );
    mkr4 = rpKamaRange2Series(Fast,KPeriod,Slow,MomPeriod,KRa ngePeriod, mkr4Cota);
    mer4 = MomentumSeries2(EMA2);
    chopbox = CongestionBoxSecondarySeries(BoxOpacity, BoxOpacity, BoxOpacity, RangePeriod,2);
    atrC = ATRCongestion( SWPeriod, MxMnPeriod, ATRLength, ATRMultiplier,ATRPrints);
    
    AddPlot(new Stroke() { Brush = Brushes.Transparent }, PlotStyle.Dot, "IntheboxPlot");
    AddPlot(new Stroke() { Brush = Brushes.Transparent }, PlotStyle.Dot, "CongestionPlot");
    
    }​
    Can you please suggest a solution?

    Thank you

    Bob

    #2
    Hi Bob, thanks for posting. You will need to reduce the script down in a trial and error approach until the cause of this race condition is found. Unfortunately, the support team will not be able to debug custom scripts. This is so we can help all requests in a timely manner. Once you find the exact line, please feel free to post it here if you do not know why its causing the threading issue. From what I can see all of your brushes are properly frozen, so you will need to reduce this script down to smaller amounts of code.
    Chris L.NinjaTrader Customer Service

    Comment


      #3
      Hi Chris, I'm lost with this issue.

      Again, I got this response from the AI chatGPT:

      It is possible that the error is caused by some other part of the code that is not shown here, or that it is caused by a third-party library or plugin being used. I recommend checking the rest of your codebase and any other external dependencies to see if they are using any shared resources and if they are properly protected with locks. Additionally, you can check any official documentation or forum regarding the use of this software for more information about threading in NinjaTrader 8.
      I have no idea what kind of statements generate "shared resources", therefore, I don't know what to look for, either by using "try-catch" or "prints".

      Thanks,

      Bob

      Comment


        #4
        Hello, thanks for the follow up. I don't think this chatGPT tool will be of any use for debugging. You need to reduce the script and use a trial-and-error approach to find the line of code that is causing the threading issue here. If you are going to initialize indicators using BarsArray and Close series, this should be done in the DataLoaded state. The deadlock issue must be related to the custom brushes or the way you are using these brushes, which is why it will be best to reduce the script and re-introduce the components one at a time.
        Chris L.NinjaTrader Customer Service

        Comment


          #5
          Hi Chris, thank you for your reply.

          I did have some indicators initialized in the Configure state. I passed that code to the DataLodaded state.

          With regards to the brushes, is it ok to have the following code? I use this same approach in other Strategies.
          Code:
          protected override void OnBarUpdate()
          {
          // ... here is some general code of the script
          
          // here I modify the background colors depending on the direction of the market
          // To avoid repeating the same code, I made a custom method to take care of the opacity of the colors
          if (Direction == -1 && paintDirectionalFilter)
          {
          
          BackBrush = SetOpacity( ShortBrush,OpacityBG );
          
          }
          else if ((Direction == 1 && paintDirectionalFilter))
          {
          
          BackBrush = SetOpacity( LongBrush,OpacityBG );
          ​}
          
          // more code...
          } end of OBU method
          
          // This is the method that handles opacity values
          public Brush SetOpacity(Brush inBackBrush, double inOpacity)
          {
          BackBrush = inBackBrush;
          Brush newBrush = BackBrush.Clone();
          newBrush.Opacity = inOpacity;
          newBrush.Freeze();
          return inBackBrush = newBrush;
          }
          ​

          Is there anything in this code that may cause the "Unhandled exception: Write lock may not be acquired with read lock held"?
          Bob
          Last edited by bobperez; 01-10-2023, 03:42 PM.

          Comment


            #6
            Hi, thanks for your reply. I really can not say from this snippet. As stated before, you will need to single out the code that is causing this to happen. Our documentation on working with custom brushes can be found here: https://ninjatrader.com/support/help...th_brushes.htm
            Chris L.NinjaTrader Customer Service

            Comment


              #7
              Hello,

              I am seeing you have the following line in post # .

              AddDataSeries("",Data.BarsPeriodType.Range, 4, Data.MarketDataType.Last);

              The instrument cannot be an empty string.

              Use null instead.

              From the help guide:
              "Tips:
              4. For the instrument name parameter null could be passed in, resulting in the primary data series instrument being used."
              Chelsea B.NinjaTrader Customer Service

              Comment


                #8
                Originally posted by bobperez View Post
                Hi Chris, I'm lost with this issue.

                Again, I got this response from the AI chatGPT:



                I have no idea what kind of statements generate "shared resources", therefore, I don't know what to look for, either by using "try-catch" or "prints".

                Thanks,

                Bob
                That's because ChatGPT has no idea what it is talking about and is just spouting gibberish.
                Bruce DeVault
                QuantKey Trading Vendor Services
                NinjaTrader Ecosystem Vendor - QuantKey

                Comment


                  #9
                  bobperez Regarding that snippet above, I don't like the look of that SetOpacity function - that seems like it is probably the problem. If what you are trying to do is have a color that's an input parameter, plus an opacity that is an input parameter, then in State.Configure or State.DataLoaded, you should create your new partially transparent brush ONE TIME there in OnStateChanged in the handler for that state and freeze it right then, and everywhere else in your code refer to that saved variable instance of the partially transparent brush. Don't do it in a setter, and don't do it a bunch of times. I know that might sound like voodoo, but if you do it the way I described you won't have to worry about all this and if you do it like I described you should be okay. If you want to "go crazy" and even make an array for every possible opacity you can do that and stick them all in an array in advance. But that's pretty wasteful of resources. Try to stick to a reasonable number of opacities.

                  A key problem you might not be realizing is you're doing that brush operation in OnBarUpdate, while the screen is being drawn in OnRender. Those run in different threads, AT THE SAME TIME. So, if you are changing the brushes around in OnBarUpdate, you're always flirting with doom. Make all the brushes you are going to ever need in OnStateChanged BEFORE OnBarUpdate ever starts running and BEFORE OnRender starts drawing the screen - then when OnRender refers to these brushes they're already frozen and they are not in the middle of being replaced or in some weird interim state such as they might be if OnRender runs while you're in the middle of updating them. I would recommend you also have a variable bool MyBrushesAreInitialized = false; and only set that to true after you've initialized them all in State.Configure or State.DataLoaded, and if you are doing any custom OnRender, at the top of that function add if (!MyBrushesAreInitialized) return; so you have no chance of working with partially initialized brushes. If you are not doing custom OnRender, just get all your brushes set up first in OnStateChanged and freeze them there. Don't change any brush instances in OnBarUpdate.

                  And don't listen to anything ChatGPT says about issues like this - it has no idea and just prints out things that sound good but lead you to waste tremendous amounts of time trying to figure out what's slightly wrong with what it said when the fact is what it said is completely ungrounded in reality. There's a reason we don't yet have ChatGPT flying commercial airliners or doing open heart surgery. A good number of such passengers and patients would be dead right away.

                  NinjaTrader_ChelseaB is absolutely correct that you shouldn't send "" for the symbol in AddDataSeries. You absolutely need to make that a null or you are asking for trouble.
                  Last edited by QuantKey_Bruce; 05-03-2023, 11:53 AM.
                  Bruce DeVault
                  QuantKey Trading Vendor Services
                  NinjaTrader Ecosystem Vendor - QuantKey

                  Comment


                    #10
                    Originally posted by QuantKey_Bruce View Post
                    bobperez Regarding that snippet above, I don't like the look of that SetOpacity function - that seems like it is probably the problem. If what you are trying to do is have a color that's an input parameter, plus an opacity that is an input parameter, then in State.Configure or State.DataLoaded, you should create your new partially transparent brush ONE TIME there in OnStateChanged in the handler for that state and freeze it right then, and everywhere else in your code refer to that saved variable instance of the partially transparent brush. Don't do it in a setter, and don't do it a bunch of times. I know that might sound like voodoo, but if you do it the way I described you won't have to worry about all this and if you do it like I described you should be okay. If you want to "go crazy" and even make an array for every possible opacity you can do that and stick them all in an array in advance. But that's pretty wasteful of resources. Try to stick to a reasonable number of opacities.

                    A key problem you might not be realizing is you're doing that brush operation in OnBarUpdate, while the screen is being drawn in OnRender. Those run in different threads, AT THE SAME TIME. So, if you are changing the brushes around in OnBarUpdate, you're always flirting with doom. Make all the brushes you are going to ever need in OnStateChanged BEFORE OnBarUpdate ever starts running and BEFORE OnRender starts drawing the screen - then when OnRender refers to these brushes they're already frozen and they are not in the middle of being replaced or in some weird interim state such as they might be if OnRender runs while you're in the middle of updating them. I would recommend you also have a variable bool MyBrushesAreInitialized = false; and only set that to true after you've initialized them all in State.Configure or State.DataLoaded, and if you are doing any custom OnRender, at the top of that function add if (!MyBrushesAreInitialized) return; so you have no chance of working with partially initialized brushes. If you are not doing custom OnRender, just get all your brushes set up first in OnStateChanged and freeze them there. Don't change any brush instances in OnBarUpdate.

                    And don't listen to anything ChatGPT says about issues like this - it has no idea and just prints out things that sound good but lead you to waste tremendous amounts of time trying to figure out what's slightly wrong with what it said when the fact is what it said is completely ungrounded in reality. There's a reason we don't yet have ChatGPT flying commercial airliners or doing open heart surgery. A good number of such passengers and patients would be dead right away.

                    NinjaTrader_ChelseaB is absolutely correct that you shouldn't send "" for the symbol in AddDataSeries. You absolutely need to make that a null or you are asking for trouble.
                    Hi Bruce, Thank you very much for taking the time for your clear explanation. I appreciate it.

                    Comment


                      #11
                      Originally posted by NinjaTrader_ChelseaB View Post
                      Hello,

                      I am seeing you have the following line in post # .

                      AddDataSeries("",Data.BarsPeriodType.Range, 4, Data.MarketDataType.Last);

                      The instrument cannot be an empty string.

                      Use null instead.

                      From the help guide:
                      "Tips:
                      4. For the instrument name parameter null could be passed in, resulting in the primary data series instrument being used."
                      https://ninjatrader.com/support/help...dataseries.htm
                      Hi Chelsea, Thank you. Have you been able to spot why the screen freezes so often when using the Unirenko bars you designed, especially when an order is placed? A strange behavior I've also noted is that after force closing Ninja and restarting again, the order that caused the screen to freeze is placed as soon as Ninja is restarted again.

                      Comment


                        #12
                        Hi, thanks for the followup. Have you been able to isolate the behavior to a single chart with only the Unirenko bars applied? Please also let us know if there is a consistent way that you can reproduce this on the latest version of NinjaTrader.

                        Kind regards,
                        -ChrisL​
                        Chris L.NinjaTrader Customer Service

                        Comment


                          #13
                          Originally posted by NinjaTrader_ChrisL View Post
                          Hi, thanks for the followup. Have you been able to isolate the behavior to a single chart with only the Unirenko bars applied? Please also let us know if there is a consistent way that you can reproduce this on the latest version of NinjaTrader.

                          Kind regards,
                          -ChrisL​
                          Hi Chris,

                          Today I downloaded the latest version of NinjaTrader and the issue persists. Perhaps I can send you by email a zipped file containing the strategy and the test workspace with just one chart on it.

                          Bob

                          Comment


                            #14
                            Hi Bob, Just to confirm, do you see the screen freeze when you only use UniRenko bars, or when you use your strategy on UniRenko bars? If you are asking about the strategy that causes the screen to freeze, please first take the proper steps in debugging, and reduce the script down until the line of code causing this is found.
                            Chris L.NinjaTrader Customer Service

                            Comment


                              #15
                              Originally posted by NinjaTrader_ChrisL View Post
                              Hi Bob, Just to confirm, do you see the screen freeze when you only use UniRenko bars, or when you use your strategy on UniRenko bars? If you are asking about the strategy that causes the screen to freeze, please first take the proper steps in debugging, and reduce the script down until the line of code causing this is found.
                              Hi Chris,

                              I stripped down the strategy script. I'm using the sampleATM script with long and short entries. The conditions that trigger entries are calculated in an indicator I developed. If I run the indicator alone on the Unirenko bars, it signals the entries on screen fine. If I call the indicator from the strategy, the screen freezes. May I send you by email the scrips for you to test at your end?


                              HTML Code:
                                          #region Short Setup
                                              shortEntryPrice = 0;
                                          if (Unirk.Sell[0] == 1 && ! enShort)
                                          {
                              
                                              shortEntryPrice = Unirk.sEntryPrice[0];
                                              enShort = true;
                                              barNumberOfOrder = CurrentBar;
                                          }                
                                          // end short setup            
                                          #endregion
                              
                              
                                          #region Entries
                                          // Entries.
                                          // **** YOU MUST HAVE AN ATM STRATEGY TEMPLATE NAMED 'AtmStrategyTemplate' CREATED IN NINJATRADER (SUPERDOM FOR EXAMPLE) FOR THIS TO WORK ****
                                          // Enter long if Close is greater than Open.
                                          if(enLong)
                                          {
                                              // If there is a short ATM Strategy running close it.
                                              if(shortAtmId.Length != 0 && isShortAtmStrategyCreated)
                                              {
                                                  AtmStrategyClose(shortAtmId);
                                                  isShortAtmStrategyCreated = false;
                                                  enShort = false;
                                              }
                                              // Ensure no other long ATM Strategy is running.
                                              if(longOrderId.Length == 0 && longAtmId.Length == 0 && !isLongAtmStrategyCreated)
                                              {
                                                  longOrderId = GetAtmStrategyUniqueId();
                                                  longAtmId = GetAtmStrategyUniqueId();
                                                  AtmStrategyCreate(OrderAction.Buy, OrderType.Market, 0, 0, TimeInForce.Day, longOrderId, "AtmStrategyTemplate", longAtmId, (atmCallbackErrorCode, atmCallBackId) => {
                                                      //check that the atm strategy create did not result in error, and that the requested atm strategy matches the id in callback
                                                      if (atmCallbackErrorCode == ErrorCode.NoError && atmCallBackId == longAtmId)
                                                          isLongAtmStrategyCreated = true;
                                                  });
                                              }
                                          }
                              
                                          // Enter short if Close is less than Open.
                                          if(enShort)
                                          {
                                          //    Print("Short condition at " + Time[0]);
                                              // If there is a long ATM Strategy running close it.
                                              if(longAtmId.Length != 0  && isLongAtmStrategyCreated)
                                              {
                                                  AtmStrategyClose(longAtmId);
                                                  isLongAtmStrategyCreated = false;
                                                  enLong = false;    
                              
                                              }
                                              // Ensure no other short ATM Strategy is running.
                                              if(shortOrderId.Length == 0 && shortAtmId.Length == 0  && !isShortAtmStrategyCreated)
                                              {
                                                  shortOrderId = GetAtmStrategyUniqueId();
                                                  shortAtmId = GetAtmStrategyUniqueId();
                                                  AtmStrategyCreate(OrderAction.Sell, OrderType.Market, 0,0, TimeInForce.Day, shortOrderId, "AtmStrategyTemplate", shortAtmId, (atmCallbackErrorCode, atmCallBackId) => {
                                                      //check that the atm strategy create did not result in error, and that the requested atm strategy matches the id in callback
                                                      if (atmCallbackErrorCode == ErrorCode.NoError && atmCallBackId == shortAtmId)
                                                          isShortAtmStrategyCreated = true;
                                                  });
                                              }
                                          }
                                          // End entries.
                                          #endregion
                              
                              ​
                              Bob
                              Last edited by bobperez; 05-05-2023, 08:58 AM.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by fx.practic, 10-15-2013, 12:53 AM
                              5 responses
                              5,404 views
                              0 likes
                              Last Post Bidder
                              by Bidder
                               
                              Started by Shai Samuel, 07-02-2022, 02:46 PM
                              4 responses
                              95 views
                              0 likes
                              Last Post Bidder
                              by Bidder
                               
                              Started by DJ888, Yesterday, 10:57 PM
                              0 responses
                              8 views
                              0 likes
                              Last Post DJ888
                              by DJ888
                               
                              Started by MacDad, 02-25-2024, 11:48 PM
                              7 responses
                              159 views
                              0 likes
                              Last Post loganjarosz123  
                              Started by Belfortbucks, Yesterday, 09:29 PM
                              0 responses
                              8 views
                              0 likes
                              Last Post Belfortbucks  
                              Working...
                              X