Files
quantconnect--lean/Launcher/Program.cs
2019-07-28 18:26:02 -07:00

170 lines
7.0 KiB
C#

/*
* 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;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using QuantConnect.Configuration;
using QuantConnect.Interfaces;
using QuantConnect.Lean.Engine;
using QuantConnect.Logging;
using QuantConnect.Packets;
using QuantConnect.Python;
using QuantConnect.Util;
namespace QuantConnect.Lean.Launcher
{
public class Program
{
private const string _collapseMessage = "Unhandled exception breaking past controls and causing collapse of algorithm node. This is likely a memory leak of an external dependency or the underlying OS terminating the LEAN engine.";
static Program()
{
AppDomain.CurrentDomain.AssemblyLoad += (sender, e) =>
{
if (e.LoadedAssembly.FullName.ToLower().Contains("python"))
{
Log.Trace($"Python for .NET Assembly: {e.LoadedAssembly.GetName()}");
}
};
}
static void Main(string[] args)
{
//Initialize:
var mode = "RELEASE";
#if DEBUG
mode = "DEBUG";
#endif
if (OS.IsWindows)
{
Console.OutputEncoding = System.Text.Encoding.Unicode;
}
// expect first argument to be config file name
if (args.Length > 0)
{
Config.MergeCommandLineArgumentsWithConfiguration(LeanArgumentParser.ParseArguments(args));
}
var environment = Config.Get("environment");
var liveMode = Config.GetBool("live-mode");
Log.DebuggingEnabled = Config.GetBool("debug-mode");
Log.LogHandler = Composer.Instance.GetExportedValueByTypeName<ILogHandler>(Config.Get("log-handler", "CompositeLogHandler"));
//Name thread for the profiler:
Thread.CurrentThread.Name = "Algorithm Analysis Thread";
Log.Trace("Engine.Main(): LEAN ALGORITHMIC TRADING ENGINE v" + Globals.Version + " Mode: " + mode + " (" + (Environment.Is64BitProcess ? "64" : "32") + "bit)");
Log.Trace("Engine.Main(): Started " + DateTime.Now.ToShortTimeString());
//Import external libraries specific to physical server location (cloud/local)
LeanEngineSystemHandlers leanEngineSystemHandlers;
try
{
leanEngineSystemHandlers = LeanEngineSystemHandlers.FromConfiguration(Composer.Instance);
}
catch (CompositionException compositionException)
{
Log.Error("Engine.Main(): Failed to load library: " + compositionException);
throw;
}
//Setup packeting, queue and controls system: These don't do much locally.
leanEngineSystemHandlers.Initialize();
LeanEngineAlgorithmHandlers leanEngineAlgorithmHandlers;
try
{
leanEngineAlgorithmHandlers = LeanEngineAlgorithmHandlers.FromConfiguration(Composer.Instance);
}
catch (CompositionException compositionException)
{
Log.Error("Engine.Main(): Failed to load library: " + compositionException);
throw;
}
//-> Pull job from QuantConnect job queue, or, pull local build:
string assemblyPath;
var job = leanEngineSystemHandlers.JobQueue.NextJob(out assemblyPath);
if (job == null)
{
throw new Exception("Engine.Main(): Job was null.");
}
if (environment.EndsWith("-desktop"))
{
if (!File.Exists(Config.Get("desktop-exe")))
{
var message = $"desktop-exe path ({Config.Get("desktop-exe")}) does not exist. You may need to update this path with the build configuration (currently ${mode})";
Log.Error(message);
throw new FileNotFoundException(message);
}
var info = new ProcessStartInfo
{
UseShellExecute = false,
FileName = Config.Get("desktop-exe"),
Arguments = Config.Get("desktop-http-port")
};
Process.Start(info);
}
// if the job version doesn't match this instance version then we can't process it
// we also don't want to reprocess redelivered jobs
if (VersionHelper.IsNotEqualVersion(job.Version) || job.Redelivered)
{
Log.Error("Engine.Run(): Job Version: " + job.Version + " Deployed Version: " + Globals.Version + " Redelivered: " + job.Redelivered);
//Tiny chance there was an uncontrolled collapse of a server, resulting in an old user task circulating.
//In this event kill the old algorithm and leave a message so the user can later review.
leanEngineSystemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, _collapseMessage);
leanEngineSystemHandlers.Notify.SetAuthentication(job);
leanEngineSystemHandlers.Notify.Send(new RuntimeErrorPacket(job.UserId, job.AlgorithmId, _collapseMessage));
leanEngineSystemHandlers.JobQueue.AcknowledgeJob(job);
return;
}
try
{
var algorithmManager = new AlgorithmManager(liveMode);
leanEngineSystemHandlers.LeanManager.Initialize(leanEngineSystemHandlers, leanEngineAlgorithmHandlers, job, algorithmManager);
var engine = new Engine.Engine(leanEngineSystemHandlers, leanEngineAlgorithmHandlers, liveMode);
engine.Run(job, algorithmManager, assemblyPath);
}
finally
{
//Delete the message from the job queue:
leanEngineSystemHandlers.JobQueue.AcknowledgeJob(job);
Log.Trace("Engine.Main(): Packet removed from queue: " + job.AlgorithmId);
// clean up resources
leanEngineSystemHandlers.Dispose();
leanEngineAlgorithmHandlers.Dispose();
Log.LogHandler.Dispose();
Log.Trace("Program.Main(): Exiting Lean...");
Environment.Exit(0);
}
}
}
}