Lean  $LEAN_TAG$
Program.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15 */
16 
17 using System;
18 using System.Threading;
21 using QuantConnect.Logging;
22 using QuantConnect.Packets;
23 using QuantConnect.Python;
24 using QuantConnect.Util;
25 
27 {
28  public class Program
29  {
30  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.";
31  private static LeanEngineSystemHandlers leanEngineSystemHandlers;
32  private static LeanEngineAlgorithmHandlers leanEngineAlgorithmHandlers;
33  private static AlgorithmNodePacket job;
34  private static AlgorithmManager algorithmManager;
35 
36  static Program()
37  {
38  AppDomain.CurrentDomain.AssemblyLoad += (sender, e) =>
39  {
40  if (e.LoadedAssembly.FullName.ToLowerInvariant().Contains("python"))
41  {
42  Log.Trace($"Python for .NET Assembly: {e.LoadedAssembly.GetName()}");
43  }
44  };
45  }
46 
47  static void Main(string[] args)
48  {
49  if (OS.IsWindows)
50  {
51  Console.OutputEncoding = System.Text.Encoding.UTF8;
52  }
53 
54  // expect first argument to be config file name
55  if (args.Length > 0)
56  {
58  }
59 
60  //Name thread for the profiler:
61  Thread.CurrentThread.Name = "Algorithm Analysis Thread";
62 
64  leanEngineSystemHandlers = Initializer.GetSystemHandlers();
65 
66  //-> Pull job from QuantConnect job queue, or, pull local build:
67  job = leanEngineSystemHandlers.JobQueue.NextJob(out var assemblyPath);
68 
69  leanEngineAlgorithmHandlers = Initializer.GetAlgorithmHandlers();
70 
71  if (job == null)
72  {
73  const string jobNullMessage = "Engine.Main(): Sorry we could not process this algorithm request.";
74  Log.Error(jobNullMessage);
75  throw new ArgumentException(jobNullMessage);
76  }
77 
78  // Activate our PythonVirtualEnvironment
80 
81  // if the job version doesn't match this instance version then we can't process it
82  // we also don't want to reprocess redelivered jobs
83  if (job.Redelivered)
84  {
85  Log.Error("Engine.Run(): Job Version: " + job.Version + " Deployed Version: " + Globals.Version + " Redelivered: " + job.Redelivered);
86  //Tiny chance there was an uncontrolled collapse of a server, resulting in an old user task circulating.
87  //In this event kill the old algorithm and leave a message so the user can later review.
88  leanEngineSystemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, _collapseMessage);
89  leanEngineSystemHandlers.Notify.SetAuthentication(job);
90  leanEngineSystemHandlers.Notify.Send(new RuntimeErrorPacket(job.UserId, job.AlgorithmId, _collapseMessage));
91  leanEngineSystemHandlers.JobQueue.AcknowledgeJob(job);
92  Exit(1);
93  }
94 
95  try
96  {
97  // Set our exit handler for the algorithm
98  Console.CancelKeyPress += new ConsoleCancelEventHandler(ExitKeyPress);
99 
100  // Create the algorithm manager and start our engine
101  algorithmManager = new AlgorithmManager(Globals.LiveMode, job);
102 
103  leanEngineSystemHandlers.LeanManager.Initialize(leanEngineSystemHandlers, leanEngineAlgorithmHandlers, job, algorithmManager);
104 
105  OS.Initialize();
106 
107  var engine = new Engine.Engine(leanEngineSystemHandlers, leanEngineAlgorithmHandlers, Globals.LiveMode);
108  engine.Run(job, algorithmManager, assemblyPath, WorkerThread.Instance);
109  }
110  finally
111  {
112  var algorithmStatus = algorithmManager?.State ?? AlgorithmStatus.DeployError;
113 
114  Exit(algorithmStatus != AlgorithmStatus.Completed ? 1 : 0);
115  }
116  }
117 
118  public static void ExitKeyPress(object sender, ConsoleCancelEventArgs args)
119  {
120  // Allow our process to resume after this event
121  args.Cancel = true;
122 
123  // Stop the algorithm
124  algorithmManager.SetStatus(AlgorithmStatus.Stopped);
125  Log.Trace("Program.ExitKeyPress(): Lean instance has been cancelled, shutting down safely now");
126  }
127 
128  public static void Exit(int exitCode)
129  {
130  //Delete the message from the job queue:
131  leanEngineSystemHandlers.JobQueue.AcknowledgeJob(job);
132  Log.Trace("Engine.Main(): Packet removed from queue: " + job.AlgorithmId);
133 
134  // clean up resources
135  leanEngineSystemHandlers.DisposeSafely();
136  leanEngineAlgorithmHandlers.DisposeSafely();
137  Log.LogHandler.DisposeSafely();
138  OS.Dispose();
139 
141 
142  Log.Trace("Program.Main(): Exiting Lean...");
143  Environment.Exit(exitCode);
144  }
145  }
146 }