Lean  $LEAN_TAG$
AlgorithmPythonWrapper.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 using NodaTime;
17 using Python.Runtime;
22 using QuantConnect.Data;
27 using QuantConnect.Orders;
28 using QuantConnect.Python;
33 using System;
34 using System.Collections.Concurrent;
35 using System.Collections.Generic;
36 using QuantConnect.Storage;
40 
42 {
43  /// <summary>
44  /// Creates and wraps the algorithm written in python.
45  /// </summary>
47  {
48  private readonly PyObject _algorithm;
49  private readonly dynamic _onData;
50  private readonly dynamic _onMarginCall;
51  private readonly IAlgorithm _baseAlgorithm;
52 
53  // QCAlgorithm methods that might be implemented in the python algorithm:
54  // We keep them to avoid the BasePythonWrapper caching and eventual lookup overhead since these methods are called quite frequently
55  private dynamic _onBrokerageDisconnect;
56  private dynamic _onBrokerageMessage;
57  private dynamic _onBrokerageReconnect;
58  private dynamic _onSplits;
59  private dynamic _onDividends;
60  private dynamic _onDelistings;
61  private dynamic _onSymbolChangedEvents;
62  private dynamic _onEndOfDay;
63  private dynamic _onMarginCallWarning;
64  private dynamic _onOrderEvent;
65  private dynamic _onAssignmentOrderEvent;
66  private dynamic _onSecuritiesChanged;
67  private dynamic _onFrameworkSecuritiesChanged;
68 
69  /// <summary>
70  /// True if the underlying python algorithm implements "OnEndOfDay"
71  /// </summary>
72  public bool IsOnEndOfDayImplemented { get; }
73 
74  /// <summary>
75  /// True if the underlying python algorithm implements "OnEndOfDay(symbol)"
76  /// </summary>
77  public bool IsOnEndOfDaySymbolImplemented { get; }
78 
79  /// <summary>
80  /// <see cref = "AlgorithmPythonWrapper"/> constructor.
81  /// Creates and wraps the algorithm written in python.
82  /// </summary>
83  /// <param name="moduleName">Name of the module that can be found in the PYTHONPATH</param>
84  public AlgorithmPythonWrapper(string moduleName)
85  : base(false)
86  {
87  try
88  {
89  using (Py.GIL())
90  {
91  Logging.Log.Trace($"AlgorithmPythonWrapper(): Python version {PythonEngine.Version}: Importing python module {moduleName}");
92 
93  var module = Py.Import(moduleName);
94 
95  Logging.Log.Trace($"AlgorithmPythonWrapper(): {moduleName} successfully imported.");
96 
97  var pyList = module.Dir();
98  foreach (var name in pyList)
99  {
100  Type type;
101  var attr = module.GetAttr(name.ToString());
102  var repr = attr.Repr().GetStringBetweenChars('\'', '\'');
103 
104  if (repr.StartsWith(moduleName) && // Must be defined in the module
105  attr.TryConvert(out type, true) && // Must be a Type
106  typeof(QCAlgorithm).IsAssignableFrom(type)) // Must inherit from QCAlgorithm
107  {
108  Logging.Log.Trace("AlgorithmPythonWrapper(): Creating IAlgorithm instance.");
109 
110  _algorithm = attr.Invoke();
111  SetPythonInstance(_algorithm);
112  var dynAlgorithm = _algorithm as dynamic;
113 
114  // Set pandas
115  dynAlgorithm.SetPandasConverter();
116 
117  // IAlgorithm reference for LEAN internal C# calls (without going from C# to Python and back)
118  _baseAlgorithm = dynAlgorithm.AsManagedObject(type);
119 
120  // determines whether OnData method was defined or inherits from QCAlgorithm
121  // If it is not, OnData from the base class will not be called
122  _onData = _algorithm.GetPythonMethod("OnData");
123 
124  _onMarginCall = _algorithm.GetPythonMethod("OnMarginCall");
125 
126  PyObject endOfDayMethod = _algorithm.GetPythonMethod("OnEndOfDay");
127  if (endOfDayMethod != null)
128  {
129  // Since we have a EOD method implemented
130  // Determine which one it is by inspecting its arg count
131  var argCount = endOfDayMethod.GetPythonArgCount();
132  switch (argCount)
133  {
134  case 0: // EOD()
136  break;
137  case 1: // EOD(Symbol)
139  break;
140  }
141 
142  // Its important to note that even if both are implemented
143  // python will only use the last implemented, meaning only one will
144  // be used and seen.
145  }
146 
147  // Initialize the python methods
148  _onBrokerageDisconnect = _algorithm.GetMethod("OnBrokerageDisconnect");
149  _onBrokerageMessage = _algorithm.GetMethod("OnBrokerageMessage");
150  _onBrokerageReconnect = _algorithm.GetMethod("OnBrokerageReconnect");
151  _onSplits = _algorithm.GetMethod("OnSplits");
152  _onDividends = _algorithm.GetMethod("OnDividends");
153  _onDelistings = _algorithm.GetMethod("OnDelistings");
154  _onSymbolChangedEvents = _algorithm.GetMethod("OnSymbolChangedEvents");
155  _onEndOfDay = _algorithm.GetMethod("OnEndOfDay");
156  _onMarginCallWarning = _algorithm.GetMethod("OnMarginCallWarning");
157  _onOrderEvent = _algorithm.GetMethod("OnOrderEvent");
158  _onAssignmentOrderEvent = _algorithm.GetMethod("OnAssignmentOrderEvent");
159  _onSecuritiesChanged = _algorithm.GetMethod("OnSecuritiesChanged");
160  _onFrameworkSecuritiesChanged = _algorithm.GetMethod("OnFrameworkSecuritiesChanged");
161  }
162  attr.Dispose();
163  }
164  module.Dispose();
165  pyList.Dispose();
166  // If _algorithm could not be set, throw exception
167  if (_algorithm == null)
168  {
169  throw new Exception("Please ensure that one class inherits from QCAlgorithm.");
170  }
171  }
172  }
173  catch (Exception e)
174  {
175  // perform exception interpretation for error in module import
176  var interpreter = StackExceptionInterpreter.CreateFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
177  e = interpreter.Interpret(e, interpreter);
178 
179  throw new Exception($"AlgorithmPythonWrapper(): {interpreter.GetExceptionMessageHeader(e)}");
180  }
181  }
182 
183  /// <summary>
184  /// AlgorithmId for the backtest
185  /// </summary>
186  public string AlgorithmId => _baseAlgorithm.AlgorithmId;
187 
188  /// <summary>
189  /// Gets the function used to define the benchmark. This function will return
190  /// the value of the benchmark at a requested date/time
191  /// </summary>
192  public IBenchmark Benchmark => _baseAlgorithm.Benchmark;
193 
194  /// <summary>
195  /// Gets the brokerage message handler used to decide what to do
196  /// with each message sent from the brokerage
197  /// </summary>
199  {
200  get
201  {
202  return _baseAlgorithm.BrokerageMessageHandler;
203  }
204 
205  set
206  {
208  }
209  }
210 
211  /// <summary>
212  /// Gets the brokerage model used to emulate a real brokerage
213  /// </summary>
214  public IBrokerageModel BrokerageModel => _baseAlgorithm.BrokerageModel;
215 
216  /// <summary>
217  /// Gets the brokerage name.
218  /// </summary>
219  public BrokerageName BrokerageName => _baseAlgorithm.BrokerageName;
220 
221  /// <summary>
222  /// Gets the risk free interest rate model used to get the interest rates
223  /// </summary>
224  public IRiskFreeInterestRateModel RiskFreeInterestRateModel => _baseAlgorithm.RiskFreeInterestRateModel;
225 
226  /// <summary>
227  /// Debug messages from the strategy:
228  /// </summary>
229  public ConcurrentQueue<string> DebugMessages => _baseAlgorithm.DebugMessages;
230 
231  /// <summary>
232  /// Get Requested Backtest End Date
233  /// </summary>
234  public DateTime EndDate => _baseAlgorithm.EndDate;
235 
236  /// <summary>
237  /// Error messages from the strategy:
238  /// </summary>
239  public ConcurrentQueue<string> ErrorMessages => _baseAlgorithm.ErrorMessages;
240 
241  /// <summary>
242  /// Gets or sets the history provider for the algorithm
243  /// </summary>
245  {
246  get
247  {
248  return _baseAlgorithm.HistoryProvider;
249  }
250 
251  set
252  {
253  SetHistoryProvider(value);
254  }
255  }
256 
257  /// <summary>
258  /// Gets whether or not this algorithm is still warming up
259  /// </summary>
260  public bool IsWarmingUp => _baseAlgorithm.IsWarmingUp;
261 
262  /// <summary>
263  /// Algorithm is running on a live server.
264  /// </summary>
265  public bool LiveMode => _baseAlgorithm.LiveMode;
266 
267  /// <summary>
268  /// Algorithm running mode.
269  /// </summary>
270  public AlgorithmMode AlgorithmMode => _baseAlgorithm.AlgorithmMode;
271 
272  /// <summary>
273  /// Deployment target, either local or cloud.
274  /// </summary>
275  public DeploymentTarget DeploymentTarget => _baseAlgorithm.DeploymentTarget;
276 
277  /// <summary>
278  /// Log messages from the strategy:
279  /// </summary>
280  public ConcurrentQueue<string> LogMessages => _baseAlgorithm.LogMessages;
281 
282  /// <summary>
283  /// Public name for the algorithm.
284  /// </summary>
285  /// <remarks>Not currently used but preserved for API integrity</remarks>
286  public string Name
287  {
288  get
289  {
290  return _baseAlgorithm.Name;
291  }
292  set
293  {
294  _baseAlgorithm.Name = value;
295  }
296  }
297 
298  /// <summary>
299  /// A list of tags associated with the algorithm or the backtest, useful for categorization
300  /// </summary>
301  public HashSet<string> Tags
302  {
303  get
304  {
305  return _baseAlgorithm.Tags;
306  }
307  set
308  {
309  _baseAlgorithm.Tags = value;
310  }
311  }
312 
313  /// <summary>
314  /// Event fired algorithm's name is changed
315  /// </summary>
316  public event AlgorithmEvent<string> NameUpdated
317  {
318  add
319  {
320  _baseAlgorithm.NameUpdated += value;
321  }
322 
323  remove
324  {
325  _baseAlgorithm.NameUpdated -= value;
326  }
327  }
328 
329  /// <summary>
330  /// Event fired when the tag collection is updated
331  /// </summary>
332  public event AlgorithmEvent<HashSet<string>> TagsUpdated
333  {
334  add
335  {
336  _baseAlgorithm.TagsUpdated += value;
337  }
338 
339  remove
340  {
341  _baseAlgorithm.TagsUpdated -= value;
342  }
343  }
344 
345  /// <summary>
346  /// Notification manager for storing and processing live event messages
347  /// </summary>
348  public NotificationManager Notify => _baseAlgorithm.Notify;
349 
350  /// <summary>
351  /// Security portfolio management class provides wrapper and helper methods for the Security.Holdings class such as
352  /// IsLong, IsShort, TotalProfit
353  /// </summary>
354  /// <remarks>Portfolio is a wrapper and helper class encapsulating the Securities[].Holdings objects</remarks>
355  public SecurityPortfolioManager Portfolio => _baseAlgorithm.Portfolio;
356 
357  /// <summary>
358  /// Gets the run time error from the algorithm, or null if none was encountered.
359  /// </summary>
360  public Exception RunTimeError
361  {
362  get
363  {
364  return _baseAlgorithm.RunTimeError;
365  }
366 
367  set
368  {
369  SetRunTimeError(value);
370  }
371  }
372 
373  /// <summary>
374  /// Customizable dynamic statistics displayed during live trading:
375  /// </summary>
376  public ConcurrentDictionary<string, string> RuntimeStatistics => _baseAlgorithm.RuntimeStatistics;
377 
378  /// <summary>
379  /// Gets schedule manager for adding/removing scheduled events
380  /// </summary>
381  public ScheduleManager Schedule => _baseAlgorithm.Schedule;
382 
383  /// <summary>
384  /// Security object collection class stores an array of objects representing representing each security/asset
385  /// we have a subscription for.
386  /// </summary>
387  /// <remarks>It is an IDictionary implementation and can be indexed by symbol</remarks>
388  public SecurityManager Securities => _baseAlgorithm.Securities;
389 
390  /// <summary>
391  /// Gets an instance that is to be used to initialize newly created securities.
392  /// </summary>
393  public ISecurityInitializer SecurityInitializer => _baseAlgorithm.SecurityInitializer;
394 
395  /// <summary>
396  /// Gets the Trade Builder to generate trades from executions
397  /// </summary>
398  public ITradeBuilder TradeBuilder => _baseAlgorithm.TradeBuilder;
399 
400  /// <summary>
401  /// Gets the user settings for the algorithm
402  /// </summary>
403  public IAlgorithmSettings Settings => _baseAlgorithm.Settings;
404 
405  /// <summary>
406  /// Gets the option chain provider, used to get the list of option contracts for an underlying symbol
407  /// </summary>
408  public IOptionChainProvider OptionChainProvider => _baseAlgorithm.OptionChainProvider;
409 
410  /// <summary>
411  /// Gets the future chain provider, used to get the list of future contracts for an underlying symbol
412  /// </summary>
413  public IFutureChainProvider FutureChainProvider => _baseAlgorithm.FutureChainProvider;
414 
415  /// <summary>
416  /// Gets the object store, used for persistence
417  /// </summary>
418  public ObjectStore ObjectStore => _baseAlgorithm.ObjectStore;
419 
420  /// <summary>
421  /// Returns the current Slice object
422  /// </summary>
423  public Slice CurrentSlice => _baseAlgorithm.CurrentSlice;
424 
425  /// <summary>
426  /// Algorithm start date for backtesting, set by the SetStartDate methods.
427  /// </summary>
428  public DateTime StartDate => _baseAlgorithm.StartDate;
429 
430  /// <summary>
431  /// Gets or sets the current status of the algorithm
432  /// </summary>
433  public AlgorithmStatus Status
434  {
435  get
436  {
437  return _baseAlgorithm.Status;
438  }
439 
440  set
441  {
442  SetStatus(value);
443  }
444  }
445 
446  /// <summary>
447  /// Set the state of a live deployment
448  /// </summary>
449  /// <param name="status">Live deployment status</param>
450  public void SetStatus(AlgorithmStatus status) => _baseAlgorithm.SetStatus(status);
451 
452  /// <summary>
453  /// Set the available <see cref="TickType"/> supported by each <see cref="SecurityType"/> in <see cref="SecurityManager"/>
454  /// </summary>
455  /// <param name="availableDataTypes">>The different <see cref="TickType"/> each <see cref="Security"/> supports</param>
456  public void SetAvailableDataTypes(Dictionary<SecurityType, List<TickType>> availableDataTypes) => _baseAlgorithm.SetAvailableDataTypes(availableDataTypes);
457 
458  /// <summary>
459  /// Sets the option chain provider, used to get the list of option contracts for an underlying symbol
460  /// </summary>
461  /// <param name="optionChainProvider">The option chain provider</param>
462  public void SetOptionChainProvider(IOptionChainProvider optionChainProvider) => _baseAlgorithm.SetOptionChainProvider(optionChainProvider);
463 
464  /// <summary>
465  /// Sets the future chain provider, used to get the list of future contracts for an underlying symbol
466  /// </summary>
467  /// <param name="futureChainProvider">The future chain provider</param>
468  public void SetFutureChainProvider(IFutureChainProvider futureChainProvider) => _baseAlgorithm.SetFutureChainProvider(futureChainProvider);
469 
470  /// <summary>
471  /// Event fired when an algorithm generates a insight
472  /// </summary>
473  public event AlgorithmEvent<GeneratedInsightsCollection> InsightsGenerated
474  {
475  add
476  {
477  _baseAlgorithm.InsightsGenerated += value;
478  }
479 
480  remove
481  {
482  _baseAlgorithm.InsightsGenerated -= value;
483  }
484  }
485 
486  /// <summary>
487  /// Gets the time keeper instance
488  /// </summary>
489  public ITimeKeeper TimeKeeper => _baseAlgorithm.TimeKeeper;
490 
491  /// <summary>
492  /// Data subscription manager controls the information and subscriptions the algorithms recieves.
493  /// Subscription configurations can be added through the Subscription Manager.
494  /// </summary>
496 
497  /// <summary>
498  /// The project id associated with this algorithm if any
499  /// </summary>
500  public int ProjectId
501  {
502  set
503  {
504  _baseAlgorithm.ProjectId = value;
505  }
506  get
507  {
508  return _baseAlgorithm.ProjectId;
509  }
510  }
511 
512  /// <summary>
513  /// Current date/time in the algorithm's local time zone
514  /// </summary>
515  public DateTime Time => _baseAlgorithm.Time;
516 
517  /// <summary>
518  /// Gets the time zone of the algorithm
519  /// </summary>
520  public DateTimeZone TimeZone => _baseAlgorithm.TimeZone;
521 
522  /// <summary>
523  /// Security transaction manager class controls the store and processing of orders.
524  /// </summary>
525  /// <remarks>The orders and their associated events are accessible here. When a new OrderEvent is recieved the algorithm portfolio is updated.</remarks>
526  public SecurityTransactionManager Transactions => _baseAlgorithm.Transactions;
527 
528  /// <summary>
529  /// Gets the collection of universes for the algorithm
530  /// </summary>
532 
533  /// <summary>
534  /// Gets the subscription settings to be used when adding securities via universe selection
535  /// </summary>
537 
538  /// <summary>
539  /// Current date/time in UTC.
540  /// </summary>
541  public DateTime UtcTime => _baseAlgorithm.UtcTime;
542 
543  /// <summary>
544  /// Gets the account currency
545  /// </summary>
546  public string AccountCurrency => _baseAlgorithm.AccountCurrency;
547 
548  /// <summary>
549  /// Gets the insight manager
550  /// </summary>
551  public InsightManager Insights => _baseAlgorithm.Insights;
552 
553  /// <summary>
554  /// Sets the statistics service instance to be used by the algorithm
555  /// </summary>
556  /// <param name="statisticsService">The statistics service instance</param>
557  public void SetStatisticsService(IStatisticsService statisticsService) => _baseAlgorithm.SetStatisticsService(statisticsService);
558 
559  /// <summary>
560  /// The current statistics for the running algorithm.
561  /// </summary>
562  public StatisticsResults Statistics => _baseAlgorithm.Statistics;
563 
564  /// <summary>
565  /// Set a required SecurityType-symbol and resolution for algorithm
566  /// </summary>
567  /// <param name="securityType">SecurityType Enum: Equity, Commodity, FOREX or Future</param>
568  /// <param name="symbol">Symbol Representation of the MarketType, e.g. AAPL</param>
569  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily.</param>
570  /// <param name="market">The market the requested security belongs to, such as 'usa' or 'fxcm'</param>
571  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice.</param>
572  /// <param name="leverage">leverage for this security</param>
573  /// <param name="extendedMarketHours">Use extended market hours data</param>
574  /// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
575  /// <param name="dataNormalizationMode">The price scaling mode to use for the security</param>
576  public Security AddSecurity(SecurityType securityType, string symbol, Resolution? resolution, string market, bool fillForward, decimal leverage, bool extendedMarketHours,
577  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null)
578  => _baseAlgorithm.AddSecurity(securityType, symbol, resolution, market, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
579 
580 
581  /// <summary>
582  /// Set a required SecurityType-symbol and resolution for algorithm
583  /// </summary>
584  /// <param name="symbol">The security Symbol</param>
585  /// <param name="resolution">Resolution of the MarketType required: MarketData, Second or Minute</param>
586  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice.</param>
587  /// <param name="leverage">leverage for this security</param>
588  /// <param name="extendedMarketHours">Use extended market hours data</param>
589  /// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
590  /// <param name="dataNormalizationMode">The price scaling mode to use for the security</param>
591  /// <param name="contractDepthOffset">The continuous contract desired offset from the current front month.
592  /// For example, 0 (default) will use the front month, 1 will use the back month contract</param>
593  /// <returns>The new Security that was added to the algorithm</returns>
594  public Security AddSecurity(Symbol symbol, Resolution? resolution = null, bool fillForward = true, decimal leverage = Security.NullLeverage, bool extendedMarketHours = false,
595  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int contractDepthOffset = 0)
596  => _baseAlgorithm.AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset);
597 
598  /// <summary>
599  /// Creates and adds a new single <see cref="Future"/> contract to the algorithm
600  /// </summary>
601  /// <param name="symbol">The futures contract symbol</param>
602  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
603  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
604  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
605  /// <param name="extendedMarketHours">Use extended market hours data</param>
606  /// <returns>The new <see cref="Future"/> security</returns>
607  public Future AddFutureContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true, decimal leverage = 0m,
608  bool extendedMarketHours = false)
609  => _baseAlgorithm.AddFutureContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
610 
611  /// <summary>
612  /// Creates and adds a new single <see cref="Option"/> contract to the algorithm
613  /// </summary>
614  /// <param name="symbol">The option contract symbol</param>
615  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
616  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
617  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
618  /// <param name="extendedMarketHours">Use extended market hours data</param>
619  /// <returns>The new <see cref="Option"/> security</returns>
620  public Option AddOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true, decimal leverage = 0m, bool extendedMarketHours = false)
621  => _baseAlgorithm.AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
622 
623  /// <summary>
624  /// Invoked at the end of every time step. This allows the algorithm
625  /// to process events before advancing to the next time step.
626  /// </summary>
627  public void OnEndOfTimeStep()
628  {
629  _baseAlgorithm.OnEndOfTimeStep();
630  }
631 
632  /// <summary>
633  /// Send debug message
634  /// </summary>
635  /// <param name="message">String message</param>
636  public void Debug(string message) => _baseAlgorithm.Debug(message);
637 
638  /// <summary>
639  /// Send an error message for the algorithm
640  /// </summary>
641  /// <param name="message">String message</param>
642  public void Error(string message) => _baseAlgorithm.Error(message);
643 
644  /// <summary>
645  /// Add a Chart object to algorithm collection
646  /// </summary>
647  /// <param name="chart">Chart object to add to collection.</param>
648  public void AddChart(Chart chart) => _baseAlgorithm.AddChart(chart);
649 
650  /// <summary>
651  /// Get the chart updates since the last request:
652  /// </summary>
653  /// <param name="clearChartData"></param>
654  /// <returns>List of Chart Updates</returns>
655  public IEnumerable<Chart> GetChartUpdates(bool clearChartData = false) => _baseAlgorithm.GetChartUpdates(clearChartData);
656 
657  /// <summary>
658  /// Gets whether or not this algorithm has been locked and fully initialized
659  /// </summary>
660  public bool GetLocked() => _baseAlgorithm.GetLocked();
661 
662  /// <summary>
663  /// Gets a read-only dictionary with all current parameters
664  /// </summary>
665  public IReadOnlyDictionary<string, string> GetParameters() => _baseAlgorithm.GetParameters();
666 
667  /// <summary>
668  /// Gets the parameter with the specified name. If a parameter with the specified name does not exist,
669  /// the given default value is returned if any, else null
670  /// </summary>
671  /// <param name="name">The name of the parameter to get</param>
672  /// <param name="defaultValue">The default value to return</param>
673  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
674  public string GetParameter(string name, string defaultValue = null) => _baseAlgorithm.GetParameter(name, defaultValue);
675 
676  /// <summary>
677  /// Gets the parameter with the specified name parsed as an integer. If a parameter with the specified name does not exist,
678  /// or the conversion is not possible, the given default value is returned
679  /// </summary>
680  /// <param name="name">The name of the parameter to get</param>
681  /// <param name="defaultValue">The default value to return</param>
682  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
683  public int GetParameter(string name, int defaultValue) => _baseAlgorithm.GetParameter(name, defaultValue);
684 
685  /// <summary>
686  /// Gets the parameter with the specified name parsed as a double. If a parameter with the specified name does not exist,
687  /// or the conversion is not possible, the given default value is returned
688  /// </summary>
689  /// <param name="name">The name of the parameter to get</param>
690  /// <param name="defaultValue">The default value to return</param>
691  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
692  public double GetParameter(string name, double defaultValue) => _baseAlgorithm.GetParameter(name, defaultValue);
693 
694  /// <summary>
695  /// Gets the parameter with the specified name parsed as a decimal. If a parameter with the specified name does not exist,
696  /// or the conversion is not possible, the given default value is returned
697  /// </summary>
698  /// <param name="name">The name of the parameter to get</param>
699  /// <param name="defaultValue">The default value to return</param>
700  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
701  public decimal GetParameter(string name, decimal defaultValue) => _baseAlgorithm.GetParameter(name, defaultValue);
702 
703  /// <summary>
704  /// Initialise the Algorithm and Prepare Required Data:
705  /// </summary>
706  public void Initialize()
707  {
708  InvokeMethod(nameof(Initialize));
709  }
710 
711  /// <summary>
712  /// Liquidate your portfolio holdings:
713  /// </summary>
714  /// <param name="symbolToLiquidate">Specific asset to liquidate, defaults to all.</param>
715  /// <param name="tag">Custom tag to know who is calling this.</param>
716  /// <returns>list of order ids</returns>
717  public List<int> Liquidate(Symbol symbolToLiquidate = null, string tag = "Liquidated") => _baseAlgorithm.Liquidate(symbolToLiquidate, tag);
718 
719  /// <summary>
720  /// Save entry to the Log
721  /// </summary>
722  /// <param name="message">String message</param>
723  public void Log(string message) => _baseAlgorithm.Log(message);
724 
725  /// <summary>
726  /// Brokerage disconnected event handler. This method is called when the brokerage connection is lost.
727  /// </summary>
728  public void OnBrokerageDisconnect()
729  {
730  _onBrokerageDisconnect();
731  }
732 
733  /// <summary>
734  /// Brokerage message event handler. This method is called for all types of brokerage messages.
735  /// </summary>
736  public void OnBrokerageMessage(BrokerageMessageEvent messageEvent)
737  {
738  _onBrokerageMessage(messageEvent);
739  }
740 
741  /// <summary>
742  /// Brokerage reconnected event handler. This method is called when the brokerage connection is restored after a disconnection.
743  /// </summary>
744  public void OnBrokerageReconnect()
745  {
746  _onBrokerageReconnect();
747  }
748 
749  /// <summary>
750  /// v3.0 Handler for all data types
751  /// </summary>
752  /// <param name="slice">The current slice of data</param>
753  public void OnData(Slice slice)
754  {
755  if (_onData != null)
756  {
757  using (Py.GIL())
758  {
759  _onData(slice);
760  }
761  }
762  }
763 
764  /// <summary>
765  /// Used to send data updates to algorithm framework models
766  /// </summary>
767  /// <param name="slice">The current data slice</param>
768  public void OnFrameworkData(Slice slice)
769  {
770  _baseAlgorithm.OnFrameworkData(slice);
771  }
772 
773  /// <summary>
774  /// Event handler to be called when there's been a split event
775  /// </summary>
776  /// <param name="splits">The current time slice splits</param>
777  public void OnSplits(Splits splits)
778  {
779  _onSplits(splits);
780  }
781 
782  /// <summary>
783  /// Event handler to be called when there's been a dividend event
784  /// </summary>
785  /// <param name="dividends">The current time slice dividends</param>
786  public void OnDividends(Dividends dividends)
787  {
788  _onDividends(dividends);
789  }
790 
791  /// <summary>
792  /// Event handler to be called when there's been a delistings event
793  /// </summary>
794  /// <param name="delistings">The current time slice delistings</param>
795  public void OnDelistings(Delistings delistings)
796  {
797  _onDelistings(delistings);
798  }
799 
800  /// <summary>
801  /// Event handler to be called when there's been a symbol changed event
802  /// </summary>
803  /// <param name="symbolsChanged">The current time slice symbol changed events</param>
804  public void OnSymbolChangedEvents(SymbolChangedEvents symbolsChanged)
805  {
806  _onSymbolChangedEvents(symbolsChanged);
807  }
808 
809  /// <summary>
810  /// Call this event at the end of the algorithm running.
811  /// </summary>
812  public void OnEndOfAlgorithm()
813  {
815  }
816 
817  /// <summary>
818  /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
819  /// </summary>
820  /// <remarks>Method is called 10 minutes before closing to allow user to close out position.</remarks>
821  /// <remarks>Deprecated because different assets have different market close times,
822  /// and because Python does not support two methods with the same name</remarks>
823  [Obsolete("This method is deprecated. Please use this overload: OnEndOfDay(Symbol symbol)")]
824  public void OnEndOfDay()
825  {
826  try
827  {
828  _onEndOfDay();
829  }
830  // If OnEndOfDay is not defined in the script, but OnEndOfDay(Symbol) is, a python exception occurs
831  // Only throws if there is an error in its implementation body
832  catch (PythonException exception)
833  {
834  if (!exception.Message.Contains("OnEndOfDay() missing 1 required positional argument"))
835  {
836  _baseAlgorithm.SetRunTimeError(exception);
837  }
838  }
839  }
840 
841  /// <summary>
842  /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
843  /// </summary>
844  /// <remarks>
845  /// This method is left for backwards compatibility and is invoked via <see cref="OnEndOfDay(Symbol)"/>, if that method is
846  /// override then this method will not be called without a called to base.OnEndOfDay(string)
847  /// </remarks>
848  /// <param name="symbol">Asset symbol for this end of day event. Forex and equities have different closing hours.</param>
849  public void OnEndOfDay(Symbol symbol)
850  {
851  try
852  {
853  _onEndOfDay(symbol);
854  }
855  // If OnEndOfDay(Symbol) is not defined in the script, but OnEndOfDay is, a python exception occurs
856  // Only throws if there is an error in its implementation body
857  catch (PythonException exception)
858  {
859  if (!exception.Message.Contains("OnEndOfDay() takes 1 positional argument but 2 were given"))
860  {
861  _baseAlgorithm.SetRunTimeError(exception);
862  }
863  }
864  }
865 
866  /// <summary>
867  /// Margin call event handler. This method is called right before the margin call orders are placed in the market.
868  /// </summary>
869  /// <param name="requests">The orders to be executed to bring this algorithm within margin limits</param>
870  public void OnMarginCall(List<SubmitOrderRequest> requests)
871  {
872  using (Py.GIL())
873  {
874  var method = GetMethod(nameof(OnMarginCall));
875  var result = method.Invoke<PyObject>(requests);
876 
877  if (_onMarginCall != null)
878  {
879  // If the method does not return or returns a non-iterable PyObject, throw an exception
880  if (result == null || !result.IsIterable())
881  {
882  throw new Exception("OnMarginCall must return a non-empty list of SubmitOrderRequest");
883  }
884 
885  requests.Clear();
886 
887  using var iterator = result.GetIterator();
888  foreach (PyObject pyRequest in iterator)
889  {
890  SubmitOrderRequest request;
891  if (TryConvert(pyRequest, out request))
892  {
893  requests.Add(request);
894  }
895  }
896 
897  // If the PyObject is an empty list or its items are not SubmitOrderRequest objects, throw an exception
898  if (requests.Count == 0)
899  {
900  throw new Exception("OnMarginCall must return a non-empty list of SubmitOrderRequest");
901  }
902  }
903  }
904  }
905 
906  /// <summary>
907  /// Margin call warning event handler. This method is called when Portfolio.MarginRemaining is under 5% of your Portfolio.TotalPortfolioValue
908  /// </summary>
909  public void OnMarginCallWarning()
910  {
911  _onMarginCallWarning();
912  }
913 
914  /// <summary>
915  /// EXPERTS ONLY:: [-!-Async Code-!-]
916  /// New order event handler: on order status changes (filled, partially filled, cancelled etc).
917  /// </summary>
918  /// <param name="newEvent">Event information</param>
919  public void OnOrderEvent(OrderEvent newEvent)
920  {
921  _onOrderEvent(newEvent);
922  }
923 
924  /// <summary>
925  /// Will submit an order request to the algorithm
926  /// </summary>
927  /// <param name="request">The request to submit</param>
928  /// <remarks>Will run order prechecks, which include making sure the algorithm is not warming up, security is added and has data among others</remarks>
929  /// <returns>The order ticket</returns>
931  {
932  return _baseAlgorithm.SubmitOrderRequest(request);
933  }
934 
935  /// <summary>
936  /// Option assignment event handler. On an option assignment event for short legs the resulting information is passed to this method.
937  /// </summary>
938  /// <param name="assignmentEvent">Option exercise event details containing details of the assignment</param>
939  /// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks>
940  public void OnAssignmentOrderEvent(OrderEvent assignmentEvent)
941  {
942  _onAssignmentOrderEvent(assignmentEvent);
943  }
944 
945  /// <summary>
946  /// Event fired each time the we add/remove securities from the data feed
947  /// </summary>
948  /// <param name="changes">Security additions/removals for this time step</param>
950  {
951  _onSecuritiesChanged(changes);
952  }
953 
954  /// <summary>
955  /// Used to send security changes to algorithm framework models
956  /// </summary>
957  /// <param name="changes">Security additions/removals for this time step</param>
959  {
960  _onFrameworkSecuritiesChanged(changes);
961  }
962 
963  /// <summary>
964  /// Called by setup handlers after Initialize and allows the algorithm a chance to organize
965  /// the data gather in the Initialize method
966  /// </summary>
967  public void PostInitialize()
968  {
969  _baseAlgorithm.PostInitialize();
970  }
971 
972  /// <summary>
973  /// Called when the algorithm has completed initialization and warm up.
974  /// </summary>
975  public void OnWarmupFinished()
976  {
978  }
979 
980  /// <summary>
981  /// Removes the security with the specified symbol. This will cancel all
982  /// open orders and then liquidate any existing holdings
983  /// </summary>
984  /// <param name="symbol">The symbol of the security to be removed</param>
985  public bool RemoveSecurity(Symbol symbol) => _baseAlgorithm.RemoveSecurity(symbol);
986 
987  /// <summary>
988  /// Set the algorithm Id for this backtest or live run. This can be used to identify the order and equity records.
989  /// </summary>
990  /// <param name="algorithmId">unique 32 character identifier for backtest or live server</param>
991  public void SetAlgorithmId(string algorithmId) => _baseAlgorithm.SetAlgorithmId(algorithmId);
992 
993  /// <summary>
994  /// Sets the implementation used to handle messages from the brokerage.
995  /// The default implementation will forward messages to debug or error
996  /// and when a <see cref="BrokerageMessageType.Error"/> occurs, the algorithm
997  /// is stopped.
998  /// </summary>
999  /// <param name="handler">The message handler to use</param>
1000  public void SetBrokerageMessageHandler(IBrokerageMessageHandler handler) => _baseAlgorithm.SetBrokerageMessageHandler(handler);
1001 
1002  /// <summary>
1003  /// Sets the brokerage model used to resolve transaction models, settlement models,
1004  /// and brokerage specified ordering behaviors.
1005  /// </summary>
1006  /// <param name="brokerageModel">The brokerage model used to emulate the real
1007  /// brokerage</param>
1008  public void SetBrokerageModel(IBrokerageModel brokerageModel) => _baseAlgorithm.SetBrokerageModel(brokerageModel);
1009 
1010  /// <summary>
1011  /// Sets the account currency cash symbol this algorithm is to manage, as well
1012  /// as the starting cash in this currency if given
1013  /// </summary>
1014  /// <remarks>Has to be called during <see cref="Initialize"/> before
1015  /// calling <see cref="SetCash(decimal)"/> or adding any <see cref="Security"/></remarks>
1016  /// <param name="accountCurrency">The account currency cash symbol to set</param>
1017  /// <param name="startingCash">The account currency starting cash to set</param>
1018  public void SetAccountCurrency(string accountCurrency, decimal? startingCash = null) => _baseAlgorithm.SetAccountCurrency(accountCurrency, startingCash);
1019 
1020  /// <summary>
1021  /// Set the starting capital for the strategy
1022  /// </summary>
1023  /// <param name="startingCash">decimal starting capital, default $100,000</param>
1024  public void SetCash(decimal startingCash) => _baseAlgorithm.SetCash(startingCash);
1025 
1026  /// <summary>
1027  /// Set the cash for the specified symbol
1028  /// </summary>
1029  /// <param name="symbol">The cash symbol to set</param>
1030  /// <param name="startingCash">Decimal cash value of portfolio</param>
1031  /// <param name="conversionRate">The current conversion rate for the</param>
1032  public void SetCash(string symbol, decimal startingCash, decimal conversionRate = 0) => _baseAlgorithm.SetCash(symbol, startingCash, conversionRate);
1033 
1034  /// <summary>
1035  /// Set the DateTime Frontier: This is the master time and is
1036  /// </summary>
1037  /// <param name="time"></param>
1038  public void SetDateTime(DateTime time) => _baseAlgorithm.SetDateTime(time);
1039 
1040  /// <summary>
1041  /// Set the start date for the backtest
1042  /// </summary>
1043  /// <param name="start">Datetime Start date for backtest</param>
1044  /// <remarks>Must be less than end date and within data available</remarks>
1045  public void SetStartDate(DateTime start) => _baseAlgorithm.SetStartDate(start);
1046 
1047  /// <summary>
1048  /// Set the end date for a backtest.
1049  /// </summary>
1050  /// <param name="end">Datetime value for end date</param>
1051  /// <remarks>Must be greater than the start date</remarks>
1052  public void SetEndDate(DateTime end) => _baseAlgorithm.SetEndDate(end);
1053 
1054  /// <summary>
1055  /// Get the last known price using the history provider.
1056  /// Useful for seeding securities with the correct price
1057  /// </summary>
1058  /// <param name="security"><see cref="Security"/> object for which to retrieve historical data</param>
1059  /// <returns>A single <see cref="BaseData"/> object with the last known price</returns>
1060  public BaseData GetLastKnownPrice(Security security) => _baseAlgorithm.GetLastKnownPrice(security);
1061 
1062  /// <summary>
1063  /// Set the runtime error
1064  /// </summary>
1065  /// <param name="exception">Represents error that occur during execution</param>
1066  public void SetRunTimeError(Exception exception) => _baseAlgorithm.SetRunTimeError(exception);
1067 
1068  /// <summary>
1069  /// Sets <see cref="IsWarmingUp"/> to false to indicate this algorithm has finished its warm up
1070  /// </summary>
1071  public void SetFinishedWarmingUp()
1072  {
1073  _baseAlgorithm.SetFinishedWarmingUp();
1074 
1075  // notify the algorithm
1076  OnWarmupFinished();
1077  }
1078 
1079  /// <summary>
1080  /// Set the historical data provider
1081  /// </summary>
1082  /// <param name="historyProvider">Historical data provider</param>
1083  public void SetHistoryProvider(IHistoryProvider historyProvider) => _baseAlgorithm.SetHistoryProvider(historyProvider);
1084 
1085  /// <summary>
1086  /// Set live mode state of the algorithm run: Public setter for the algorithm property LiveMode.
1087  /// </summary>
1088  /// <param name="live">Bool live mode flag</param>
1089  public void SetLiveMode(bool live) => _baseAlgorithm.SetLiveMode(live);
1090 
1091  /// <summary>
1092  /// Sets the algorithm running mode
1093  /// </summary>
1094  /// <param name="algorithmMode">Algorithm mode</param>
1095  public void SetAlgorithmMode(AlgorithmMode algorithmMode) => _baseAlgorithm.SetAlgorithmMode(algorithmMode);
1096 
1097  /// <summary>
1098  /// Sets the algorithm deployment target
1099  /// </summary>
1100  /// <param name="deploymentTarget">Deployment target</param>
1101  public void SetDeploymentTarget(DeploymentTarget deploymentTarget) => _baseAlgorithm.SetDeploymentTarget(deploymentTarget);
1102 
1103  /// <summary>
1104  /// Set the algorithm as initialized and locked. No more cash or security changes.
1105  /// </summary>
1106  public void SetLocked() => _baseAlgorithm.SetLocked();
1107 
1108  /// <summary>
1109  /// Set the maximum number of orders the algorithm is allowed to process.
1110  /// </summary>
1111  /// <param name="max">Maximum order count int</param>
1112  public void SetMaximumOrders(int max) => _baseAlgorithm.SetMaximumOrders(max);
1113 
1114  /// <summary>
1115  /// Sets the parameters from the dictionary
1116  /// </summary>
1117  /// <param name="parameters">Dictionary containing the parameter names to values</param>
1118  public void SetParameters(Dictionary<string, string> parameters) => _baseAlgorithm.SetParameters(parameters);
1119 
1120  /// <summary>
1121  /// Tries to convert a PyObject into a C# object
1122  /// </summary>
1123  /// <typeparam name="T">Type of the C# object</typeparam>
1124  /// <param name="pyObject">PyObject to be converted</param>
1125  /// <param name="result">C# object that of type T</param>
1126  /// <returns>True if successful conversion</returns>
1127  private bool TryConvert<T>(PyObject pyObject, out T result)
1128  {
1129  result = default(T);
1130  var type = (Type)pyObject.GetPythonType().AsManagedObject(typeof(Type));
1131 
1132  if (type == typeof(T))
1133  {
1134  result = (T)pyObject.AsManagedObject(typeof(T));
1135  }
1136 
1137  return type == typeof(T);
1138  }
1139 
1140  /// <summary>
1141  /// Returns a <see cref = "string"/> that represents the current <see cref = "AlgorithmPythonWrapper"/> object.
1142  /// </summary>
1143  /// <returns></returns>
1144  public override string ToString()
1145  {
1146  if (_algorithm == null)
1147  {
1148  return base.ToString();
1149  }
1150  using (Py.GIL())
1151  {
1152  return _algorithm.Repr();
1153  }
1154  }
1155 
1156  /// <summary>
1157  /// Sets the current slice
1158  /// </summary>
1159  /// <param name="slice">The Slice object</param>
1160  public void SetCurrentSlice(Slice slice)
1161  {
1162  _baseAlgorithm.SetCurrentSlice(new PythonSlice(slice));
1163  }
1164 
1165  /// <summary>
1166  /// Provide the API for the algorithm.
1167  /// </summary>
1168  /// <param name="api">Initiated API</param>
1169  public void SetApi(IApi api) => _baseAlgorithm.SetApi(api);
1170 
1171  /// <summary>
1172  /// Sets the object store
1173  /// </summary>
1174  /// <param name="objectStore">The object store</param>
1175  public void SetObjectStore(IObjectStore objectStore) => _baseAlgorithm.SetObjectStore(objectStore);
1176 
1177  /// <summary>
1178  /// Determines if the Symbol is shortable at the brokerage
1179  /// </summary>
1180  /// <param name="symbol">Symbol to check if shortable</param>
1181  /// <param name="shortQuantity">Order's quantity to check if it is currently shortable, taking into account current holdings and open orders</param>
1182  /// <param name="updateOrderId">Optionally the id of the order being updated. When updating an order
1183  /// we want to ignore it's submitted short quantity and use the new provided quantity to determine if we
1184  /// can perform the update</param>
1185  /// <returns>True if the symbol can be shorted by the requested quantity</returns>
1186  public bool Shortable(Symbol symbol, decimal shortQuantity, int? updateOrderId = null)
1187  {
1188  return _baseAlgorithm.Shortable(symbol, shortQuantity, updateOrderId);
1189  }
1190 
1191  /// <summary>
1192  /// Gets the quantity shortable for the given asset
1193  /// </summary>
1194  /// <returns>
1195  /// Quantity shortable for the given asset. Zero if not
1196  /// shortable, or a number greater than zero if shortable.
1197  /// </returns>
1198  public long ShortableQuantity(Symbol symbol)
1199  {
1200  return _baseAlgorithm.ShortableQuantity(symbol);
1201  }
1202 
1203  /// <summary>
1204  /// Converts the string 'ticker' symbol into a full <see cref="Symbol"/> object
1205  /// This requires that the string 'ticker' has been added to the algorithm
1206  /// </summary>
1207  /// <param name="ticker">The ticker symbol. This should be the ticker symbol
1208  /// as it was added to the algorithm</param>
1209  /// <returns>The symbol object mapped to the specified ticker</returns>
1210  public Symbol Symbol(string ticker) => _baseAlgorithm.Symbol(ticker);
1211 
1212  /// <summary>
1213  /// For the given symbol will resolve the ticker it used at the current algorithm date
1214  /// </summary>
1215  /// <param name="symbol">The symbol to get the ticker for</param>
1216  /// <returns>The mapped ticker for a symbol</returns>
1217  public string Ticker(Symbol symbol) => _baseAlgorithm.Ticker(symbol);
1218 
1219  /// <summary>
1220  /// Sets name to the currently running backtest
1221  /// </summary>
1222  /// <param name="name">The name for the backtest</param>
1223  public void SetName(string name)
1224  {
1225  _baseAlgorithm.SetName(name);
1226  }
1227 
1228  /// <summary>
1229  /// Adds a tag to the algorithm
1230  /// </summary>
1231  /// <param name="tag">The tag to add</param>
1232  public void AddTag(string tag)
1233  {
1234  _baseAlgorithm.AddTag(tag);
1235  }
1236 
1237  /// <summary>
1238  /// Sets the tags for the algorithm
1239  /// </summary>
1240  /// <param name="tags">The tags</param>
1241  public void SetTags(HashSet<string> tags)
1242  {
1243  _baseAlgorithm.SetTags(tags);
1244  }
1245  }
1246 }