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 @@
+