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