Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Strong Event References & Zombie Instances

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

    Strong Event References & Zombie Instances

    I posted this last week about my setup/teardown problems and asking for advice. I've written a strategy which illustrates the problem. The first is a bug, and the second is a highly undesirable side-effect of how you're implementing event-handlers.

    1. Bug - Rendering ghosting

    Steps to reproduce:
    -- open a chart connected to a realtime feed
    - add strategy to chart
    - observe that metadata is printed on the chart - bid/ask datetime random guid etc
    - right click chart and choose "reload ninjascript"
    Expected behaviour
    - Chart should clear and reload afresh
    Actual behavior
    - The previous instance of the strategy is not cleared from the chart and we can see output from both.

    2. Strong event references

    This relates to the way I am utilising your API by instantiating my own classes and hooking into certain events in Ninjatrader - all in all my strategy has about 50 classes so far.

    The example strategy attached has two classes. An OrderManager and a BarsProxy - both hook into Ninjatrader events to do their work. Just start and stop the strategy a few times and you will see what the problem is...

    The order manager hooks into the Account.Execution_Update event - and is going to ensure my positions are covered by stops and targets; which will be reduced or increased according to fill amount, and also prevent overfills by identifying duplicate order submissions.

    The BarProxy is going to grab bars from another time series and sent them off to a processing pipeline - I've got Three pipelines for three timeframes - each with about 20 classes for parsing, scoring, aggregating and storing. I'm scanning for significant areas of price action in Forex which where subject to significant institutional-influence and determining the likelyhood that the institutional order was completely-filled. Because if not, then price is sure to turn there again when price action returns and the rest of their order is filled - its all working pretty great so far.

    Anyway... Reload the attached strategy a few times - or enable/disable. Look at the output window and you will see that the there are lots of BarsProxy instances and Order Manager instances still alive and processing.

    These instances survive beyond the lifetime of the Strategy because they are linking into Internal Ninjatrader events, by the += method. Objects are only garbage collected by the Common Language Runtime when nothing is referencing them - and although the original strategy instance that made the BarProxy and OrderManager is gone and has, itself, been garbage-collected the things it created are living on and still processing because the += method of binding to event handlers constitutes a strong incoming reference to my classes so they remain on the heap and continue to process events - using up memory and CPU cycles.

    This is not a bug - because events should be cleaned up and handlers unbound; but it is very highly undesirable. If an error/exception occurs and the call to unbind the handler via the -= method is never called then the instances will live on and keep processing. Or if a developer just forgets (as I did a couple of times).

    Its a really common problem and their are loads of solutions. But given the nature of Ninjatrader'appliation which is built for third parties to code against its pretty high risk exposing strong event references as you can see from the zombies that occur in the attached strategy - and microsoft has invested a lot of work in providing support in the .NET framework for this problem with the WeakEventManager



    This allows event handlers to be bound using WeakReferences - a weak reference is an one that does not protect the instance from the Garbage Collector. Meaning when my strategy instance is gone, and is no longer referencing the OrderManager and BarsProxy that it created, all strong-references to those objects are deemed to have gone and the ordermanager and barsproxy will be garbage collected from by the Runtime and stop using memory and processing cycles.

    I realise this is pretty advanced stuff but I think that it is an unacceptable risk for you to be allowing event binding by strong references in this way - given the nature of the Ninjatrader application and its third-party ecosystem, there is so much that can go wrong and cause a gradual degradation in performance. This has really tripped me up - I spent most of last week trying to track down an issues caused by an exception being thrown before an event was un-binded.

    I think one of the great strengths of Ninjatrader is that we are able to hook into these events. It enables me to write an enterprise-grade system of the back of Ninja and not just a single-file strategy. However I would suggest looking at the WeakEventManager to expose your underlying events to the third-party ecosystem in order to eliminate the risks exemplified in the attached strategy caused by strong event references.
    Attached Files

    #2
    Hello reach4thelasers,

    Thank you for your post.

    I will look into this on my end and follow up with you when I have information on your file.

    Comment


      #3
      I've been at this since 5am this morning trying to get WeakEventHandlers working but I can't seem to get a single OrderManager to live for the lifetime of the instance and then die, in fact I can't ever only get one OrderManager - it starts with two, and then adds one every time I run the strategy.

      I won't be happy until I get this working with weak references I'm not happy with the Risk of an unhandled exception and things living-on and continuing to execute in the background.

      Comment


        #4
        Hello reach4thelasers,

        I am able to reproduce the "rendering ghosting" that you have mentioned in your original post and have forwarded this to development.

        Thank you for your suggestions. I have forwarded your suggestions to development as well.
        Zachary G.NinjaTrader Customer Service

        Comment


          #5
          Thank you Zachary - another thing I would say about SetUp & TearDown - we are told to get things set up in the "Configure" state. Things seems a bit early though as it fires when you open the strategy window on a loaded, but disabled, strategy.

          There's an "Active" state in the State Enumeration but this never seems to get Fired.... It would be great if there was a state after configuration that got fired only when the strategy was activated. Ideally if this worked and got fired when the strategy was enabled then it would be a great State Event to get things set up.

          Comment


            #6
            Curious, is State.DataLoaded too late for what you're trying to do? Are you looking for a step between Configure and DataLoaded?
            MatthewNinjaTrader Product Management

            Comment


              #7
              I'm basically looking for a state that is fired when the strategy is switched on and starts running - whenever the "enabled" checkbox is first ticked I guess.

              I did notice the DataLoaded state but hadn't considered it. What does it represent? DataLoaded onto what, exactly? If its loaded onto the chart then its way too late, I need to have everything set up for Historical processing - unless it happens before that in which case it might work.

              Comment


                #8
                Wanted to post an update. Development suggests that you use an event handler and unsubscribe from the event handler in State.Terminated. This is they right approach to clean up the events on termination.

                You could also just use a regular delegate instead of an anon delegate to unsubscribe.
                Last edited by NinjaTrader_Brett; 10-16-2015, 09:33 AM.

                Comment


                  #9
                  Originally posted by reach4thelasers View Post
                  I'm basically looking for a state that is fired when the strategy is switched on and starts running - whenever the "enabled" checkbox is first ticked I guess.

                  I did notice the DataLoaded state but hadn't considered it. What does it represent? DataLoaded onto what, exactly? If its loaded onto the chart then its way too late, I need to have everything set up for Historical processing - unless it happens before that in which case it might work.
                  It is the next stage after a user enables a strategy. It indicates that all of the requested resources have been pooled and is the last chance to setup/declare any resources before OnBarUpdate() is ran historically.
                  MatthewNinjaTrader Product Management

                  Comment


                    #10
                    Matt/Brett sorry for the late response I've been real busy. Matt thats perfect for what I need and I have started using it.

                    Brett. I actually noticed that a couple of the provided samples for SuperDomColumns are using the WeakEventPattern I described. Namely @APQ.cs and @Volume.cs (search for WeakEventManager) - so might be worth talking to the guy who wrote them as I reckon its a better way.

                    Yes unbinding in the Terminated event is the preferred approach to strong event references, but using strong events is risky - if something goes wrong and the unbind request doesn't happen, or you just forget, then the handler will continue to process events forever causing a memory or performance leak - even after the strategy seems to be terminated it will still be alive and processing, Every time you start a new instance of the strategy it will add another handler to the event and that will live forever as well and keep processing.

                    So yeah, unbinding preferable.... but what I was saying was that an application like Ninjatrader with third party code running in individual threads - strong events is a potential risk that I personally wouldn't be happy with exposing to third parties.

                    Comment


                      #11
                      No problem, busy is a good problem to have

                      Thanks for the feedback!

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by f.saeidi, Today, 05:56 AM
                      1 response
                      3 views
                      0 likes
                      Last Post Jltarrau  
                      Started by Jltarrau, Today, 05:57 AM
                      0 responses
                      4 views
                      0 likes
                      Last Post Jltarrau  
                      Started by Stanfillirenfro, Yesterday, 09:19 AM
                      7 responses
                      51 views
                      0 likes
                      Last Post NinjaTrader_Gaby  
                      Started by TraderCro, 04-12-2024, 11:36 AM
                      4 responses
                      70 views
                      0 likes
                      Last Post Mindset
                      by Mindset
                       
                      Started by Mindset, Yesterday, 02:04 AM
                      1 response
                      15 views
                      0 likes
                      Last Post Mindset
                      by Mindset
                       
                      Working...
                      X