/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using NodaTime;
using QuantConnect.Benchmarks;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Notifications;
using QuantConnect.Orders;
using QuantConnect.Scheduling;
using QuantConnect.Securities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Python.Runtime;
using ImpromptuInterface;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
namespace QuantConnect.Python.Wrappers
{
///
/// Wrapper for an IAlgorithm instance created in Python.
/// All calls to python should be inside a "using (Py.GIL()) {/* Your code here */}" block.
///
public class AlgorithmPythonWrapper : IAlgorithm
{
private IAlgorithm _algorithm;
private IBenchmark _benchmark;
private IBrokerageModel _brokerageModel;
private IHistoryProvider _historyProvider;
private ITradeBuilder _tradeBuilder;
private dynamic _pyAlgorithm;
///
/// constructor.
/// Creates and wraps the algorithm written in python.
///
/// Python module with the algorithm written in Python
public AlgorithmPythonWrapper(PyObject module)
{
_algorithm = null;
try
{
using (Py.GIL())
{
if (!module.HasAttr("QCAlgorithm"))
{
return;
}
var baseClass = module.GetAttr("QCAlgorithm");
// Load module with util methods
var onPythonData = Py.Import("AlgorithmPythonUtil").GetAttr("OnPythonData");
var moduleName = module.Repr().Split('\'')[1];
foreach (var name in module.Dir())
{
var attr = module.GetAttr(name.ToString());
if (attr.IsSubclass(baseClass) && attr.Repr().Contains(moduleName))
{
attr.SetAttr("OnPythonData", onPythonData);
_pyAlgorithm = attr.Invoke();
_algorithm = Impromptu.ActLike(_pyAlgorithm);
return;
}
}
}
}
catch (Exception e)
{
Logging.Log.Error(e);
}
}
///
/// Wrapper for in Python
///
public string AlgorithmId
{
get
{
using (Py.GIL())
{
return _algorithm.AlgorithmId;
}
}
}
///
/// Wrapper for in Python
///
public IBenchmark Benchmark
{
get
{
using (Py.GIL())
{
if (_benchmark == null)
{
_benchmark = new BenchmarkPythonWrapper(_algorithm.Benchmark);
}
return _benchmark;
}
}
}
///
/// Wrapper for in Python
///
public IBrokerageMessageHandler BrokerageMessageHandler
{
get
{
using (Py.GIL())
{
return _algorithm.BrokerageMessageHandler;
}
}
set
{
SetBrokerageMessageHandler(value);
}
}
///
/// Wrapper for in Python
///
public IBrokerageModel BrokerageModel
{
get
{
using (Py.GIL())
{
if (_brokerageModel == null)
{
_brokerageModel = new BrokerageModelPythonWrapper(_algorithm.BrokerageModel);
}
return _brokerageModel;
}
}
}
///
/// Wrapper for in Python
///
public ConcurrentQueue DebugMessages
{
get
{
using (Py.GIL())
{
return _algorithm.DebugMessages;
}
}
}
///
/// Wrapper for in Python
///
public DateTime EndDate
{
get
{
using (Py.GIL())
{
return _algorithm.EndDate;
}
}
}
///
/// Wrapper for in Python
///
public ConcurrentQueue ErrorMessages
{
get
{
using (Py.GIL())
{
return _algorithm.ErrorMessages;
}
}
}
///
/// Wrapper for in Python
///
public IHistoryProvider HistoryProvider
{
get
{
using (Py.GIL())
{
if (_historyProvider == null)
{
_historyProvider = new HistoryProviderPythonWrapper(_algorithm.HistoryProvider);
}
return _historyProvider;
}
}
set
{
SetHistoryProvider(value);
}
}
///
/// Wrapper for in Python
///
public bool IsWarmingUp
{
get
{
using (Py.GIL())
{
return _algorithm.IsWarmingUp;
}
}
}
///
/// Wrapper for in Python
///
public bool LiveMode
{
get
{
using (Py.GIL())
{
return _algorithm.LiveMode;
}
}
}
///
/// Wrapper for in Python
///
public ConcurrentQueue LogMessages
{
get
{
using (Py.GIL())
{
return _algorithm.LogMessages;
}
}
}
///
/// Wrapper for in Python
///
public string Name
{
get
{
using (Py.GIL())
{
return _algorithm.Name;
}
}
}
///
/// Wrapper for in Python
///
public NotificationManager Notify
{
get
{
using (Py.GIL())
{
return _algorithm.Notify;
}
}
}
///
/// Wrapper for in Python
///
public SecurityPortfolioManager Portfolio
{
get
{
using (Py.GIL())
{
return _algorithm.Portfolio;
}
}
}
///
/// Wrapper for in Python
///
public Exception RunTimeError
{
get
{
using (Py.GIL())
{
return _algorithm.RunTimeError;
}
}
set
{
SetRunTimeError(value);
}
}
///
/// Wrapper for in Python
///
public Dictionary RuntimeStatistics
{
get
{
using (Py.GIL())
{
return _algorithm.RuntimeStatistics;
}
}
}
///
/// Wrapper for in Python
///
public ScheduleManager Schedule
{
get
{
using (Py.GIL())
{
return _algorithm.Schedule;
}
}
}
///
/// Wrapper for in Python
///
public SecurityManager Securities
{
get
{
using (Py.GIL())
{
return _algorithm.Securities;
}
}
}
///
/// Wrapper for in Python
///
public ISecurityInitializer SecurityInitializer
{
get
{
using (Py.GIL())
{
return _algorithm.SecurityInitializer;
}
}
}
///
/// Wrapper for in Python
///
public ITradeBuilder TradeBuilder
{
get
{
using (Py.GIL())
{
if (_tradeBuilder == null)
{
_tradeBuilder = new TradeBuilderPythonWrapper(_algorithm.TradeBuilder);
}
return _tradeBuilder;
}
}
}
///
/// Wrapper for in Python
///
public DateTime StartDate
{
get
{
using (Py.GIL())
{
return _algorithm.StartDate;
}
}
}
///
/// Wrapper for in Python
///
public AlgorithmStatus Status
{
get
{
using (Py.GIL())
{
return _algorithm.Status;
}
}
set
{
SetStatus(value);
}
}
///
/// Wrapper for in Python
///
///
public void SetStatus(AlgorithmStatus value)
{
using (Py.GIL())
{
_algorithm.SetStatus(value);
}
}
///
/// Wrapper for in Python
///
///
public void SetAvailableDataTypes(Dictionary> availableDataTypes)
{
using (Py.GIL())
{
_algorithm.SetAvailableDataTypes(availableDataTypes);
}
}
///
/// Wrapper for in Python
///
public SubscriptionManager SubscriptionManager
{
get
{
using (Py.GIL())
{
return _algorithm.SubscriptionManager;
}
}
}
///
/// Wrapper for in Python
///
public DateTime Time
{
get
{
using (Py.GIL())
{
return _algorithm.Time;
}
}
}
///
/// Wrapper for in Python
///
public DateTimeZone TimeZone
{
get
{
using (Py.GIL())
{
return _algorithm.TimeZone;
}
}
}
///
/// Wrapper for in Python
///
public SecurityTransactionManager Transactions
{
get
{
using (Py.GIL())
{
return _algorithm.Transactions;
}
}
}
///
/// Wrapper for in Python
///
public UniverseManager UniverseManager
{
get
{
using (Py.GIL())
{
return _algorithm.UniverseManager;
}
}
}
///
/// Wrapper for in Python
///
public UniverseSettings UniverseSettings
{
get
{
using (Py.GIL())
{
return _algorithm.UniverseSettings;
}
}
}
///
/// Wrapper for in Python
///
public DateTime UtcTime
{
get
{
using (Py.GIL())
{
return _algorithm.UtcTime;
}
}
}
///
/// Wrapper for in Python
///
///
///
///
///
///
///
///
///
public Security AddSecurity(SecurityType securityType, string symbol, Resolution resolution, string market, bool fillDataForward, decimal leverage, bool extendedMarketHours)
{
using (Py.GIL())
{
return _algorithm.AddSecurity(securityType, symbol, resolution, market, fillDataForward, leverage, extendedMarketHours);
}
}
///
/// Creates and adds a new single contract to the algorithm
///
/// The futures contract symbol
/// The of market data, Tick, Second, Minute, Hour, or Daily. Default is
/// If true, returns the last available data even if none in that timeslice. Default is true
/// The requested leverage for this equity. Default is set by
/// The new security
public Future AddFutureContract(Symbol symbol, Resolution resolution = Resolution.Minute, bool fillDataForward = true, decimal leverage = 0m)
{
using (Py.GIL())
{
return _algorithm.AddFutureContract(symbol, resolution, fillDataForward, leverage);
}
}
///
/// Creates and adds a new single contract to the algorithm
///
/// The option contract symbol
/// The of market data, Tick, Second, Minute, Hour, or Daily. Default is
/// If true, returns the last available data even if none in that timeslice. Default is true
/// The requested leverage for this equity. Default is set by
/// The new security
public Option AddOptionContract(Symbol symbol, Resolution resolution = Resolution.Minute, bool fillDataForward = true, decimal leverage = 0m)
{
using (Py.GIL())
{
return _algorithm.AddOptionContract(symbol, resolution, fillDataForward, leverage);
}
}
///
/// Wrapper for in Python
///
///
public void Debug(string message)
{
using (Py.GIL())
{
_algorithm.Debug(message);
}
}
///
/// Wrapper for in Python
///
///
public void Error(string message)
{
using (Py.GIL())
{
_algorithm.Error(message);
}
}
///
/// Wrapper for in Python
///
///
///
public List GetChartUpdates(bool clearChartData = false)
{
using (Py.GIL())
{
return _algorithm.GetChartUpdates(clearChartData);
}
}
///
/// Wrapper for in Python
///
///
public bool GetLocked()
{
using (Py.GIL())
{
return _algorithm.GetLocked();
}
}
///
/// Wrapper for in Python
///
///
///
public string GetParameter(string name)
{
using (Py.GIL())
{
return _algorithm.GetParameter(name);
}
}
///
/// Wrapper for in Python
///
///
public IEnumerable GetWarmupHistoryRequests()
{
using (Py.GIL())
{
return _algorithm.GetWarmupHistoryRequests().ToList();
}
}
///
/// Wrapper for in Python
///
public void Initialize()
{
using (Py.GIL())
{
_algorithm.Initialize();
}
}
///
/// Wrapper for in Python
///
///
///
///
public List Liquidate(Symbol symbolToLiquidate = null, string tag = "Liquidated")
{
using (Py.GIL())
{
return _algorithm.Liquidate(symbolToLiquidate, tag);
}
}
///
/// Wrapper for in Python
///
///
public void Log(string message)
{
using (Py.GIL())
{
_algorithm.Log(message);
}
}
///
/// Wrapper for in Python
///
public void OnBrokerageDisconnect()
{
using (Py.GIL())
{
_algorithm.OnBrokerageDisconnect();
}
}
///
/// Wrapper for in Python
///
///
public void OnBrokerageMessage(BrokerageMessageEvent messageEvent)
{
using (Py.GIL())
{
_algorithm.OnBrokerageMessage(messageEvent);
}
}
///
/// Wrapper for in Python
///
public void OnBrokerageReconnect()
{
using (Py.GIL())
{
_algorithm.OnBrokerageReconnect();
}
}
///
/// Wrapper for in Python
///
public void OnData(Slice slice)
{
using (Py.GIL())
{
if (_algorithm.SubscriptionManager.HasCustomData)
{
_pyAlgorithm.OnPythonData(slice);
}
else
{
_algorithm.OnData(slice);
}
}
}
///
/// Wrapper for in Python
///
public void OnEndOfAlgorithm()
{
using (Py.GIL())
{
_algorithm.OnEndOfAlgorithm();
}
}
///
/// Wrapper for in Python
///
public void OnEndOfDay()
{
using (Py.GIL())
{
_algorithm.OnEndOfDay();
}
}
///
/// Wrapper for in Python
///
///
public void OnEndOfDay(Symbol symbol)
{
using (Py.GIL())
{
_algorithm.OnEndOfDay(symbol);
}
}
///
/// Wrapper for in Python
///
///
public void OnMarginCall(List requests)
{
using (Py.GIL())
{
_algorithm.OnMarginCall(requests);
}
}
///
/// Wrapper for in Python
///
public void OnMarginCallWarning()
{
using (Py.GIL())
{
_algorithm.OnMarginCallWarning();
}
}
///
/// Wrapper for in Python
///
///
public void OnOrderEvent(OrderEvent newEvent)
{
using (Py.GIL())
{
_algorithm.OnOrderEvent(newEvent);
}
}
///
/// Wrapper for in Python
///
///
public void OnAssignmentOrderEvent(OrderEvent newEvent)
{
using (Py.GIL())
{
_algorithm.OnAssignmentOrderEvent(newEvent);
}
}
///
/// Wrapper for in Python
///
///
public void OnSecuritiesChanged(SecurityChanges changes)
{
using (Py.GIL())
{
_algorithm.OnSecuritiesChanged(changes);
}
}
///
/// Wrapper for in Python
///
public void PostInitialize()
{
using (Py.GIL())
{
_algorithm.PostInitialize();
}
}
///
/// Wrapper for in Python
///
///
///
public bool RemoveSecurity(Symbol symbol)
{
using (Py.GIL())
{
return _algorithm.RemoveSecurity(symbol);
}
}
///
/// Wrapper for in Python
///
///
public void SetAlgorithmId(string algorithmId)
{
using (Py.GIL())
{
_algorithm.SetAlgorithmId(algorithmId);
}
}
///
/// Wrapper for in Python
///
///
public void SetBrokerageMessageHandler(IBrokerageMessageHandler brokerageMessageHandler)
{
using (Py.GIL())
{
_algorithm.SetBrokerageMessageHandler(brokerageMessageHandler);
}
}
///
/// Wrapper for in Python
///
///
public void SetBrokerageModel(IBrokerageModel brokerageModel)
{
using (Py.GIL())
{
_algorithm.SetBrokerageModel(new BrokerageModelPythonWrapper(brokerageModel));
}
}
///
/// Wrapper for in Python
///
///
public void SetCash(decimal startingCash)
{
using (Py.GIL())
{
_algorithm.SetCash(startingCash);
}
}
///
/// Wrapper for in Python
///
///
///
///
public void SetCash(string symbol, decimal startingCash, decimal conversionRate)
{
using (Py.GIL())
{
_algorithm.SetCash(symbol, startingCash, conversionRate);
}
}
///
/// Wrapper for in Python
///
///
public void SetDateTime(DateTime time)
{
using (Py.GIL())
{
_algorithm.SetDateTime(time);
}
}
///
/// Wrapper for in Python
///
///
public void SetRunTimeError(Exception exception)
{
using (Py.GIL())
{
_algorithm.SetRunTimeError(exception);
}
}
///
/// Wrapper for in Python
///
public void SetFinishedWarmingUp()
{
using (Py.GIL())
{
_algorithm.SetFinishedWarmingUp();
}
}
///
/// Wrapper for in Python
///
///
public void SetHistoryProvider(IHistoryProvider historyProvider)
{
using (Py.GIL())
{
_algorithm.SetHistoryProvider(new HistoryProviderPythonWrapper(historyProvider));
}
}
///
/// Wrapper for in Python
///
///
public void SetLiveMode(bool live)
{
using (Py.GIL())
{
_algorithm.SetLiveMode(live);
}
}
///
/// Wrapper for in Python
///
public void SetLocked()
{
using (Py.GIL())
{
_algorithm.SetLocked();
}
}
///
/// Wrapper for in Python
///
///
public void SetMaximumOrders(int max)
{
using (Py.GIL())
{
_algorithm.SetMaximumOrders(max);
}
}
///
/// Wrapper for in Python
///
///
public void SetParameters(Dictionary parameters)
{
using (Py.GIL())
{
_algorithm.SetParameters(parameters);
}
}
}
}