diff --git a/Optimizer.Launcher/ConsoleLeanOptimizer.cs b/Optimizer.Launcher/ConsoleLeanOptimizer.cs index 768fc1a7628f..a0c41ad1c26c 100644 --- a/Optimizer.Launcher/ConsoleLeanOptimizer.cs +++ b/Optimizer.Launcher/ConsoleLeanOptimizer.cs @@ -47,7 +47,7 @@ public ConsoleLeanOptimizer(OptimizationNodePacket nodePacket) : base(nodePacket Directory.CreateDirectory(_rootResultDirectory); _leanLocation = Configuration.Config.Get("lean-binaries-location", - Path.Combine(Directory.GetCurrentDirectory(), "../../../Launcher/bin/Debug/QuantConnect.Lean.Launcher")); + Path.Combine(Directory.GetCurrentDirectory(), "../../../Launcher/bin/Debug/QuantConnect.Lean.Launcher.dll")); var closeLeanAutomatically = Configuration.Config.GetBool("optimizer-close-automatically", true); _extraLeanArguments = $"--close-automatically {closeLeanAutomatically}"; @@ -85,18 +85,11 @@ protected override string RunLean(ParameterSet parameterSet, string backtestName var resultDirectory = Path.Combine(_rootResultDirectory, backtestId); Directory.CreateDirectory(resultDirectory); - // Use ProcessStartInfo class - var startInfo = new ProcessStartInfo - { - FileName = _leanLocation, - WorkingDirectory = Directory.GetParent(_leanLocation).FullName, - Arguments = $"--results-destination-folder \"{resultDirectory}\" --algorithm-id \"{backtestId}\" --optimization-id \"{optimizationId}\" --parameters {parameterSet} --backtest-name \"{backtestName}\" {_extraLeanArguments}", - WindowStyle = ProcessWindowStyle.Minimized - }; + var arguments = $"--results-destination-folder \"{resultDirectory}\" --algorithm-id \"{backtestId}\" --optimization-id \"{optimizationId}\" --parameters {parameterSet} --backtest-name \"{backtestName}\" {_extraLeanArguments}"; var process = new Process { - StartInfo = startInfo, + StartInfo = CreateLeanStartInfo(_leanLocation, arguments), EnableRaisingEvents = true }; _processByBacktestId[backtestId] = process; @@ -121,6 +114,32 @@ protected override string RunLean(ParameterSet parameterSet, string backtestName return backtestId; } + /// + /// Creates the start info to launch Lean from the given location + /// + /// The Lean launcher assembly (.dll) or executable to run + /// The Lean command line arguments + /// The start info for the Lean process + internal static ProcessStartInfo CreateLeanStartInfo(string leanLocation, string arguments) + { + var startInfo = new ProcessStartInfo + { + FileName = leanLocation, + WorkingDirectory = Directory.GetParent(leanLocation).FullName, + Arguments = arguments, + WindowStyle = ProcessWindowStyle.Minimized + }; + + // Run assemblies through the dotnet host: the native apphost only runs on the architecture it was built for + if (leanLocation.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + { + startInfo.FileName = "dotnet"; + startInfo.Arguments = $"\"{leanLocation}\" {arguments}"; + } + + return startInfo; + } + /// /// Stops lean process /// diff --git a/Optimizer.Launcher/Properties/AssemblyInfo.cs b/Optimizer.Launcher/Properties/AssemblyInfo.cs index e74da607af3e..316bdba0a908 100644 --- a/Optimizer.Launcher/Properties/AssemblyInfo.cs +++ b/Optimizer.Launcher/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -14,4 +15,5 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("d46d2a8d-340c-4b40-8ee6-6baa7b1198ab")] \ No newline at end of file +[assembly: Guid("d46d2a8d-340c-4b40-8ee6-6baa7b1198ab")] +[assembly: InternalsVisibleTo("QuantConnect.Tests")] \ No newline at end of file diff --git a/Tests/Optimizer/ConsoleLeanOptimizerTests.cs b/Tests/Optimizer/ConsoleLeanOptimizerTests.cs new file mode 100644 index 000000000000..5f87eb73f0a0 --- /dev/null +++ b/Tests/Optimizer/ConsoleLeanOptimizerTests.cs @@ -0,0 +1,62 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +using System.IO; +using NUnit.Framework; +using QuantConnect.Optimizer.Launcher; + +namespace QuantConnect.Tests.Optimizer +{ + [TestFixture] + public class ConsoleLeanOptimizerTests + { + [TestCase("QuantConnect.Lean.Launcher.dll")] + [TestCase("QuantConnect.Lean.Launcher.DLL")] + public void LaunchesAssemblyThroughTheDotnetHost(string fileName) + { + var leanLocation = Path.Combine("Lean", "Launcher", "bin", "Debug", fileName); + + var startInfo = ConsoleLeanOptimizer.CreateLeanStartInfo(leanLocation, "--algorithm-id \"backtest-id\""); + + Assert.AreEqual("dotnet", startInfo.FileName); + Assert.AreEqual($"\"{leanLocation}\" --algorithm-id \"backtest-id\"", startInfo.Arguments); + Assert.AreEqual(Path.GetFullPath(Path.Combine("Lean", "Launcher", "bin", "Debug")), startInfo.WorkingDirectory); + } + + [TestCase("QuantConnect.Lean.Launcher")] + [TestCase("QuantConnect.Lean.Launcher.exe")] + public void LaunchesExecutableDirectly(string fileName) + { + var directory = Directory.CreateTempSubdirectory().FullName; + try + { + // an explicitly configured executable is used as is, even with the assembly next to it + File.WriteAllText(Path.Combine(directory, "QuantConnect.Lean.Launcher.dll"), string.Empty); + var leanLocation = Path.Combine(directory, fileName); + + var startInfo = ConsoleLeanOptimizer.CreateLeanStartInfo(leanLocation, "--algorithm-id \"backtest-id\""); + + Assert.AreEqual(leanLocation, startInfo.FileName); + Assert.AreEqual("--algorithm-id \"backtest-id\"", startInfo.Arguments); + Assert.AreEqual(directory, startInfo.WorkingDirectory); + } + finally + { + Directory.Delete(directory, true); + } + } + } +} diff --git a/Tests/QuantConnect.Tests.csproj b/Tests/QuantConnect.Tests.csproj index 53842e014757..30dab6a1cacc 100644 --- a/Tests/QuantConnect.Tests.csproj +++ b/Tests/QuantConnect.Tests.csproj @@ -421,6 +421,7 @@ +