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

Can I move NT8 AddOn code out to a DLL that uses C# versions > 5.0?

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

    Can I move NT8 AddOn code out to a DLL that uses C# versions > 5.0?

    Hey everyone. So I am interested in using newer C# features on my NT8 AddOn-based trading engine, but as as we know, NT8 is currently on .Net Framework 4.8, which means we are limited to C# 5.0.

    One way around this potentially would be to abstract the bulk of my trading engine out to a DLL that potentially runs against a newer version of .Net and then have my NT8 AddOn "shell" talk to it.

    My current assessment is that the best I could do would be to create an assembly against .Net Standard 2.0, since .Net Framework 4.8 can theoretically still talk to it. .Net Standard 2.0 gets me to C# 7.3.

    Questions:
    1. Do I have it right?
    2. Has anyone tried this and/or proved that it works?
    3. Are their hidden pitfalls or annoyances to watch out for?
    4. Does moving code out to a DLL meaningfully slow down the developer iteration cycle?

    I'm tempted to do an experiment to test this out, but I figured I'd get the downlow from people with experience, since it might save me from wasting time on dead ends.

    Cheers.

    #2
    Hello carnitron,

    Thank you for your note.

    This would be outside what we could support, however, I will leave this thread open in case any of our users would like to chime in with any experience they may have.

    Please let us know if we may be of further assistance to you.
    Kate W.NinjaTrader Customer Service

    Comment


      #3
      Just to be clear, do you mean:

      A. You wouldn't be able to support me with moving some of my code out into a DLL and whatever niggly details that requires.
      B. But you would still be able to support me on the code that remains running in the NT8 framework in C# 5 that talks to the C#7.3 DLL.

      Do I have it right?

      Comment


        #4
        Hello carnitron,

        We would be able to assist with any documented NinjaScript methods or properties in the help guide.

        We can provide an example of an addon window.



        However, we would not be able to assist with working with external dlls.

        Support for 3rd party assemblies is limited. Our team is able to assist with adding the dll and a reference to the dll, however we cannot assist with its use, or with any errors or unexpected behavior that may occur.

        With that said, we are happy to forward any insightful information we happen to be aware of.

        Below is a link to the help guide on referencing a 3rd party assembly dll.
        https://ninjatrader.com/support/help...indicators.htm

        Any referenced managed assembly will need to target .NET Framework 4.8 or lower. Other versions of .NET will not work, such as .NET Core or .NET 5.

        Alternatively, unmanaged assemblies can be P/Invoked.
        https://docs.microsoft.com/en-us/dot...nterop/pinvoke
        https://ninjatrader.com/support/foru...300#post777300
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Thanks for the info Chelsea. It's not an immediate priority for me, but I will investigate this when I get a chance, b/c newer versions of C# have some pretty useful features I'd like access to.

          The big question I need to validate is what happens if I build a project targeted at .Net Standard 2.1, whether that will work with NT8. The Microsoft doc implies that it is compatible with .Net Framework 4.8, but I'd like to prove that out cheaply before investing any real time there.

          Comment


            #6
            I spent some time exploring migrating the core of my trading engine out from the NinjaTrader.Custom project and into a .Net Standard 2.0-based DLL, so I can use a more modern version of C#.

            The results are basically positive. You can do it. You can run C# 7.3-based code from NT8 and debug right into the 2.0-based DLL straight from the NinjaTrader.Custom project, or by attaching the Visual Studio session for your DLL to NT8, like you would with the NinjaTrader.Custom one. It's not terribly complicated, and there is only one semi-serious drawback. Though it is probably not for everyone or every situation.


            Steps:

            1. Create a .Net Standard 2.0 based class library for the C# code you want to be running on C# 7.3. This cannot contain any NinjaTrader references, b/c it causes version conflicts. The NT8 code references .Net classes that are different between .Net Framework 4.8 and .Net Standard 2.0. This is probably a show-stopper for some people, but I am trying to keep my trading engine platform-neutral, so splitting it out this way is actually a good thing.

            2. Create a .Net Framework 4.8 based class library. This CAN have NinjaTrader references in it. I COULD put the bridge classes between the NT8 world and my abstracted trading engine world here. But I will probably just leave those in the core NinjaTrader.Custom project and keep this DLL super tiny and with one job: connecting the 4.8-based NT8 bridge classes to the 2.0-based trading engine classes.

            3. Add a reference to your .Net Standard 2.0-based class library into your .Net Framework 4.8-based class library.

            4. Copy the DLL for the 4.8-based class library into Documents\NinjaTrader 8\bin\Custom.

            5. Add a reference to the 4.8-based DLL to your NinjaTrader.Custom project, by right-clicking in the NT8 Editor window, selecting "References..." and choosing the .Net Framework 4.8-based DLL you copied into the Custom directory.

            6. Normally, you would need to copy the 2.0-based DLL to the Custom directory and add a reference to it as well. This does work. However, the following approach seems marginally better:

            Code:
            static Assembly CustomResolver(object sender, ResolveEventArgs args)
            {
                // Load your 2.0-based DLL via its path here.
                byte[] bytes = File.ReadAllBytes("C:\\Users\\carni\\source\\repos\\ClassLibraryTest\\ClassLibraryTest\\bin\\Debug\\ netstandard2.0\\ClassLibraryTest.dll");
                return Assembly.Load(bytes);
            }
            
            public void Engage()
            {
                AppDomain.CurrentDomain.AssemblyResolve += CustomResolver
            
                // In my test case, the FrameworkClassLibrayTest.Thing class below refers to a class in the 2.0-based ClassLibraryTest.
                // When we hit this line, the Assembly loading code triggers the CustomResolver above to load the DLL as a byte stream.
                FrameworkClassLibraryTest.Thing thing = new FrameworkClassLibraryTest.Thing();
                // ...
            The benefit of this approach is that I don't have to keep copying my 2.0-based DLL into the NT8 Custom directory, and NT8 never read locks the DLL, so I can build it as many times as I want while NT8 is running.


            Problems:

            1. It is not possible to just put a reference to 2.0-based DLL directly into the NinjaTrader.Custom project. If you do this, you get an error like:

            The type 'System.Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard Version=2.0.0.0 Culture=neutral PublicKeyToken=cc7b13ffcd2ddd51'.

            This might be an NT8 bug. I can create a 4.8-based console application in Visual Studio and have it refer to a 2.0-based DLL without issue. OTOH, adding the 2.0 netstandard.dll as a reference to the NinjaTrader.Custom project causes tons of errors like:

            The type 'System.DateTime' exists in both 'c:\Users\carni\.nuget\packages\netstandard.librar y\2.0.3\build\netstandard2.0\ref\netstandard.dll' and 'c:\Windows\Microsoft.NET\Framework64\v4.0.30319\m scorlib.dll'.

            So perhaps there is some structural issue I do not perceive.

            This forces me to create an extra "interdiction" class library that is 4.8-based that sits between the 4.8-based NinjaTrader.Custom project and my 2.0-based DLL. Not the end of the world, it's just random extra boilerplate complexity that would be nice to remove if there was a way.


            2. The far worse problem is that there is no way to unload a DLL from NT8 once it's loaded. Generally speaking, this is just how C# works. You can load assemblies into an AppDomain, but you cannot unload them. Unloading AppDomains is now obsolete as well. Custom AppDomains don't work here either.

            The reason this is an issue is that it hurts the iteration cycle. You have to restart NT8 every time you make and want to test a DLL code mod, b/c once the DLL is loaded, that version stays loaded, and subsequent changes to it will not get picked up until you restart NT8. The resolver code above doesn't even get called on subsequent runs in the same NT8 session.

            Fortunately, restarting NT8 takes seconds, so I am going to try this approach. I am used to large C++ projects that take 10+ minutes to compile, or even hours in some cases, lol.


            For NinjaTrader support:

            1. It would be great if the engineering team could see if there is a quick/easy way to support loading .Net Standard 2.0-based DLLs directly in the NinjaTrader.Custom project.

            2. It would be even greater if there was a way to flush and reload the NT8 AppDomain while NT8 is running. Like a "Restart C# environment" menu item or something.

            3. Best of all, of course, would be to bring NT8 forward onto more modern versions of .Net, but I'm sure you know that already.


            For everyone else:

            If people have comments, experience or advice that might solve or sidestep any of these issues, I'd love to hear them. I am not a C# expert, so I'm sure there are tips and techniques I'm missing. I'd love to do more with less if someone has a better solution along those lines.

            Cheers.
            Last edited by carnitron; 10-02-2022, 09:48 PM.

            Comment


              #7
              Hello carnitron,

              Thanks for your note.

              We are currently tracking interest in updating NinjaTrader to use the newer version of .NET and C# and I have added your vote.

              This request is being tracked under the number SFT-3124.

              As with all feature requests, interest is tracked before implementation is considered, so we cannot offer an ETA or promise of fulfillment. If implemented, it will be noted in the Release Notes page of the Help Guide.

              Release Notes — https://ninjatrader.com/support/help...ease_notes.htm

              That said this thread will be open for other community members to share their insights on the topic.

              Please let us know if we may be of further assistance to you.​
              Brandon H.NinjaTrader Customer Service

              Comment


                #8

                Thank you Brandon. I hope others adds their votes and we can move forward in version sooner rather than later, as there are many excellent quality of life features in future versions.

                FWIW, I now have my entire system migrated over to the dual-DLL solution I mentioned and it works without incident. So I am now making core engine changes in C#7.3!

                I have a goofy little PowerShell script for quickly cycling NT8, copying my DLLs and restarting it:


                Code:
                Write-Host "NinjaTrader DLL Cycler."
                
                $nid = (Get-Process -Name NinjaTrader).id
                
                if ($nid)
                {
                    Stop-Process -Id $nid
                
                    # Unfortunately, does not wait for dependent DLLs to unload.
                    # Wait-Process -Id $nid
                
                    Start-Sleep -Seconds 1
                
                    Write-Host "NinjaTrader shut down."
                }
                
                Copy-Item "E:\Documents\Dev\AlphaXNT8\bin\Debug\AlphaXNT8.dl l" -Destination "E:\Documents\NinjaTrader 8\bin\Custom"
                Copy-Item "E:\Documents\Dev\AlphaXEngine\bin\Debug\netstandard2.0\AlphaXEngine.dll" -Destination "E:\Documents\NinjaTrader 8\bin\Custom"
                
                Start-Process -FilePath "C:\Program Files (x86)\NinjaTrader 8\bin64\NinjaTrader.exe"

                Comment

                Latest Posts

                Collapse

                Topics Statistics Last Post
                Started by bortz, 11-06-2023, 08:04 AM
                47 responses
                1,602 views
                0 likes
                Last Post aligator  
                Started by jaybedreamin, Today, 05:56 PM
                0 responses
                8 views
                0 likes
                Last Post jaybedreamin  
                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
                4 views
                0 likes
                Last Post Jon17
                by Jon17
                 
                Started by Javierw.ok, Today, 04:12 PM
                0 responses
                12 views
                0 likes
                Last Post Javierw.ok  
                Working...
                X