17 using System.Collections.Generic;
20 using System.Reflection;
21 using System.Runtime.InteropServices;
22 using System.Security.Policy;
36 [ClassInterface(ClassInterfaceType.AutoDual)]
37 public class Loader : MarshalByRefObject
40 private readonly
bool _debugging;
43 private readonly TimeSpan _loaderTimeLimit;
49 private readonly Func<List<string>,
string> _multipleTypeNameResolverFunction;
62 private static readonly Type AlgorithmInterfaceType = typeof (
IAlgorithm);
67 private const string AlgorithmBaseTypeFullName =
"QuantConnect.Algorithm.QCAlgorithm";
72 private const string FrameworkBaseTypeFullName =
"QuantConnect.Algorithm.Framework.QCAlgorithmFramework";
78 : this(false,
Language.
CSharp, TimeSpan.FromSeconds(10), names => names.SingleOrDefault())
98 public Loader(
bool debugging,
Language language, TimeSpan loaderTimeLimit, Func<List<string>,
string> multipleTypeNameResolverFunction,
WorkerThread workerThread =
null)
100 _debugging = debugging;
101 _language = language;
102 _workerThread = workerThread;
103 if (multipleTypeNameResolverFunction ==
null)
105 throw new ArgumentNullException(nameof(multipleTypeNameResolverFunction));
108 _loaderTimeLimit = loaderTimeLimit;
109 _multipleTypeNameResolverFunction = multipleTypeNameResolverFunction;
123 algorithmInstance =
null;
127 if (!File.Exists(assemblyPath))
135 TryCreatePythonAlgorithm(assemblyPath, out algorithmInstance, out errorMessage);
139 TryCreateILAlgorithm(assemblyPath, out algorithmInstance, out errorMessage);
144 return algorithmInstance !=
null;
154 private bool TryCreatePythonAlgorithm(
string assemblyPath, out
IAlgorithm algorithmInstance, out
string errorMessage)
156 algorithmInstance =
null;
157 errorMessage =
string.Empty;
160 if (!File.Exists(assemblyPath))
162 errorMessage = $
"Loader.TryCreatePythonAlgorithm(): Unable to find py file: {assemblyPath}";
166 var pythonFile =
new FileInfo(assemblyPath);
167 var moduleName = pythonFile.Name.Replace(
".pyc",
"").Replace(
".py",
"");
176 if (!_debugging &&
Config.
GetBool(
"mute-python-library-logging",
true))
182 import logging, os, sys
183 sys.stdout = open(os.devnull, 'w')
184 logging.captureWarnings(True)"
192 errorMessage = $
"Loader.TryCreatePythonAlgorithm(): Unable to import python module {assemblyPath}. {e.Message}";
207 private bool TryCreateILAlgorithm(
string assemblyPath, out
IAlgorithm algorithmInstance, out
string errorMessage)
210 algorithmInstance =
null;
214 byte[] debugInformationBytes =
null;
218 var directoryName =
new FileInfo(assemblyPath).DirectoryName;
219 if (directoryName !=
null && directoryName.TrimEnd(Path.DirectorySeparatorChar) != AppDomain.CurrentDomain.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar))
222 var mdbFilename = assemblyPath +
".mdb";
223 var pdbFilename = assemblyPath.Substring(0, assemblyPath.Length - 4) +
".pdb";
224 if (
File.Exists(pdbFilename))
226 debugInformationBytes =
File.ReadAllBytes(pdbFilename);
229 if (
File.Exists(mdbFilename))
231 debugInformationBytes =
File.ReadAllBytes(mdbFilename);
237 if (debugInformationBytes ==
null)
239 Log.
Trace(
"Loader.TryCreateILAlgorithm(): Loading only the algorithm assembly");
240 assembly = Assembly.LoadFrom(assemblyPath);
244 Log.
Trace(
"Loader.TryCreateILAlgorithm(): Loading debug information with algorithm");
245 var assemblyBytes =
File.ReadAllBytes(assemblyPath);
246 assembly = Assembly.Load(assemblyBytes, debugInformationBytes);
251 Log.
Debug(
"Loader.TryCreateILAlgorithm(): Assembly types: " +
string.Join(
",", types));
254 if (types.Count == 0)
256 errorMessage =
"Algorithm type was not found.";
257 Log.
Error(
"Loader.TryCreateILAlgorithm(): Types array empty, no algorithm type found.");
264 types[0] = _multipleTypeNameResolverFunction.Invoke(types);
266 if (
string.IsNullOrEmpty(types[0]))
268 errorMessage =
"Algorithm type name not found, or unable to resolve multiple algorithm types to a single type. Please verify algorithm type name matches the algorithm name in the configuration file and that there is one and only one class derived from QCAlgorithm.";
269 Log.
Error($
"Loader.TryCreateILAlgorithm(): {errorMessage}");
274 algorithmInstance = (
IAlgorithm)assembly.CreateInstance(types[0],
true);
276 if (algorithmInstance !=
null)
278 Log.
Trace(
"Loader.TryCreateILAlgorithm(): Loaded " + algorithmInstance.GetType().Name);
282 catch (ReflectionTypeLoadException err)
285 Log.
Error(
"Loader.TryCreateILAlgorithm(1): " + err.LoaderExceptions[0]);
286 if (err.InnerException !=
null) errorMessage = err.InnerException.Message;
288 catch (Exception err)
290 errorMessage =
"Algorithm type name not found, or unable to resolve multiple algorithm types to a single type. Please verify algorithm type name matches the algorithm name in the configuration file and that there is one and only one class derived from QCAlgorithm.";
291 Log.
Error($
"Loader.TryCreateILAlgorithm(): {errorMessage}\n{err.InnerException ?? err}");
305 var types =
new List<string>();
308 Type[] assemblyTypes;
311 assemblyTypes = assembly.GetTypes();
313 catch (ReflectionTypeLoadException e)
317 assemblyTypes = e.Types.Where(t => t !=
null).ToArray();
319 var countTypesNotLoaded = e.LoaderExceptions.Length;
320 Log.
Error($
"Loader.GetExtendedTypeNames(): Unable to load {countTypesNotLoaded} of the requested types, " +
321 "see below for more details on what causes an issue:");
323 foreach (Exception inner
in e.LoaderExceptions)
325 Log.
Error($
"Loader.GetExtendedTypeNames(): {inner.Message}");
329 if (assemblyTypes !=
null && assemblyTypes.Length > 0)
331 types = (from t in assemblyTypes
334 where AlgorithmInterfaceType.IsAssignableFrom(t)
335 where t.FullName != AlgorithmBaseTypeFullName
336 where t.FullName != FrameworkBaseTypeFullName
337 where t.GetConstructor(Type.EmptyTypes) !=
null
338 select t.FullName).ToList();
342 Log.
Error(
"API.GetExtendedTypeNames(): No types found in assembly.");
345 catch (Exception err)
364 var error =
string.Empty;
368 var complete = isolator.ExecuteWithTimeLimit(_loaderTimeLimit, () =>
371 }, ramLimit, sleepIntervalMillis:100, workerThread:_workerThread);
373 algorithmInstance = instance;
374 errorMessage = error;
379 errorMessage =
"Failed to create algorithm instance within 10 seconds. Try re-building algorithm. " + error;
382 return complete && success && algorithmInstance !=
null;
385 #pragma warning disable CS1574
391 #pragma warning restore CS1574