23 using System.Collections.Generic;
35 public partial class QCAlgorithm
37 private readonly Dictionary<IntPtr, PythonIndicator> _pythonIndicators =
new Dictionary<IntPtr, PythonIndicator>();
65 return AddData(type, ticker, resolution,
null,
false, 1m);
89 return AddData(type, underlying, resolution,
null,
false, 1m);
105 public Security AddData(PyObject type,
string ticker,
Resolution? resolution, DateTimeZone timeZone,
bool fillForward =
false, decimal leverage = 1.0m)
107 return AddData(type.CreateType(), ticker, resolution, timeZone, fillForward, leverage);
133 return AddData(type.CreateType(), underlying, resolution, timeZone, fillForward, leverage);
149 public Security AddData(Type dataType,
string ticker,
Resolution? resolution, DateTimeZone timeZone,
bool fillForward =
false, decimal leverage = 1.0m)
152 var baseInstance = dataType.GetBaseDataInstance();
153 if (!baseInstance.RequiresMapping())
158 return AddDataImpl(dataType, symbol, resolution, timeZone, fillForward, leverage);
164 throw new InvalidOperationException($
"The custom data type {dataType.Name} requires mapping, but the provided ticker is not in the cache. " +
165 $
"Please add this custom data type using a Symbol or perform this call after " +
166 $
"a Security has been added using AddEquity, AddForex, AddCfd, AddCrypto, AddFuture, AddOption or AddSecurity. " +
167 $
"An example use case can be found in CustomDataAddDataRegressionAlgorithm");
170 return AddData(dataType, underlying, resolution, timeZone, fillForward, leverage);
194 public Security AddData(Type dataType,
Symbol underlying,
Resolution? resolution =
null, DateTimeZone timeZone =
null,
bool fillForward =
false, decimal leverage = 1.0m)
197 return AddDataImpl(dataType, symbol, resolution, timeZone, fillForward, leverage);
217 var dataType = type.CreateType();
221 SetDatabaseEntries(key, properties, exchangeHours);
224 return AddData(dataType, ticker, resolution,
null, fillForward, leverage);
237 Func<OptionFilterUniverse, OptionFilterUniverse> optionFilterUniverse;
238 if (!optionFilter.TryConvertToDelegate(out optionFilterUniverse))
240 throw new ArgumentException(
"Option contract universe filter provided is not a function");
258 private Security AddDataImpl(Type dataType,
Symbol symbol,
Resolution? resolution, DateTimeZone timeZone,
bool fillForward, decimal leverage)
263 if (timeZone !=
null)
276 extendedMarketHours:
true);
279 return AddToUserDefinedUniverse(security,
new List<SubscriptionDataConfig> { config });
287 [DocumentationAttribute(Universes)]
290 Func<IEnumerable<Fundamental>,
object> fundamentalSelector;
293 if (pyObject.TryCreateType(out var type))
298 else if(pyObject.TryConvert(out universe))
302 else if (pyObject.TryConvert(out universe, allowPythonDerivative:
true))
306 else if (pyObject.TryConvertToDelegate(out fundamentalSelector))
314 throw new ArgumentException($
"QCAlgorithm.AddUniverse: {pyObject.Repr()} is not a valid argument.");
328 Func<IEnumerable<CoarseFundamental>,
object> coarseFunc;
329 Func<IEnumerable<FineFundamental>,
object> fineFunc;
341 if (pyfine.TryConvertToDelegate(out coarseFunc))
343 return AddUniverse(dateRule, coarseFunc.ConvertToUniverseSelectionSymbolDelegate());
346 catch (InvalidCastException)
351 if (pyObject.TryCreateType(out var type))
355 else if (pyObject.TryConvert(out
Universe universe) && pyfine.TryConvertToDelegate(out fineFunc))
357 return AddUniverse(universe, fineFunc.ConvertToUniverseSelectionSymbolDelegate());
359 else if (pyObject.TryConvertToDelegate(out coarseFunc) && pyfine.TryConvertToDelegate(out fineFunc))
361 return AddUniverse(coarseFunc.ConvertToUniverseSelectionSymbolDelegate(),
362 fineFunc.ConvertToUniverseSelectionSymbolDelegate());
368 throw new ArgumentException($
"QCAlgorithm.AddUniverse: {pyObject.Repr()} or {pyfine.Repr()} is not a valid argument.");
383 var selector = pySelector.ConvertToDelegate<Func<DateTime, object>>();
384 return AddUniverse(name, resolution, selector.ConvertToUniverseSelectionStringDelegate());
396 var selector = pySelector.ConvertToDelegate<Func<DateTime, object>>();
397 return AddUniverse(name, selector.ConvertToUniverseSelectionStringDelegate());
412 var selector = pySelector.ConvertToDelegate<Func<DateTime, object>>();
413 return AddUniverse(securityType, name, resolution, market, universeSettings, selector.ConvertToUniverseSelectionStringDelegate());
427 return AddUniverse(
T.CreateType(),
null, name,
null,
null,
null, selector);
442 return AddUniverse(
T.CreateType(),
null, name, resolution,
null,
null, selector);
458 return AddUniverse(
T.CreateType(),
null, name, resolution,
null, universeSettings, selector);
473 return AddUniverse(
T.CreateType(),
null, name,
null,
null, universeSettings, selector);
489 return AddUniverse(
T.CreateType(), securityType, name, resolution, market,
null, selector);
505 return AddUniverse(
T.CreateType(), securityType, name, resolution, market, universeSettings, selector);
521 if (market.IsNullOrEmpty())
526 Func<IEnumerable<BaseData>, IEnumerable<Symbol>> wrappedSelector =
null;
527 if (pySelector !=
null)
529 var selector = pySelector.ConvertToDelegate<Func<IEnumerable<IBaseData>,
object>>();
530 wrappedSelector = baseDatas =>
532 var result = selector(baseDatas);
537 return ((
object[])result).Select(x => x is
Symbol symbol ? symbol :
QuantConnect.
Symbol.
Create((
string)x, securityType.Value, market, baseDataType: dataType));
540 return AddUniverseSymbolSelector(dataType, name, resolution, market, universeSettings, wrappedSelector);
552 Func<OptionFilterUniverse, OptionFilterUniverse> convertedOptionChain;
555 if (universe.TryConvert(out universeToChain) && optionFilter.TryConvertToDelegate(out convertedOptionChain))
563 throw new ArgumentException($
"QCAlgorithm.AddChainedEquityOptionUniverseSelectionModel: {universe.Repr()} or {optionFilter.Repr()} is not a valid argument.");
612 if (pyObject.TryConvert(out dataConsolidator))
631 TimeSpan? timeSpan = pyObject.As<TimeSpan>();
632 if (timeSpan !=
default(TimeSpan))
640 throw new ArgumentException(
"Invalid third argument, should be either a valid consolidator or timedelta object. The following exception was thrown: ", e);
665 if (indicator.TryConvert(out indicatorDataPoint))
667 RegisterIndicator(symbol, indicatorDataPoint, consolidator, selector?.ConvertToDelegate<Func<IBaseData, decimal>>());
670 else if (indicator.TryConvert(out indicatorDataBar))
672 RegisterIndicator(symbol, indicatorDataBar, consolidator, selector?.ConvertToDelegate<Func<IBaseData, IBaseDataBar>>());
675 else if (indicator.TryConvert(out indicatorTradeBar))
677 RegisterIndicator(symbol, indicatorTradeBar, consolidator, selector?.ConvertToDelegate<Func<IBaseData, TradeBar>>());
681 RegisterIndicator(symbol, WrapPythonIndicator(indicator), consolidator, selector?.ConvertToDelegate<Func<IBaseData, IBaseData>>());
699 WarmUpIndicator(symbol, indicatorDataPoint, resolution, selector?.ConvertToDelegate<Func<IBaseData, decimal>>());
704 WarmUpIndicator(symbol, indicatorDataBar, resolution, selector?.ConvertToDelegate<Func<IBaseData, IBaseDataBar>>());
709 WarmUpIndicator(symbol, indicatorTradeBar, resolution, selector?.ConvertToDelegate<Func<IBaseData, TradeBar>>());
713 WarmUpIndicator(symbol, WrapPythonIndicator(indicator), resolution, selector?.ConvertToDelegate<Func<IBaseData, IBaseData>>());
723 public void Plot(
string series, PyObject pyObject)
729 Plot(series, indicator);
735 var value = (((dynamic)pyObject).Value as PyObject).GetAndDispose<decimal>();
740 var pythonType = pyObject.GetPythonType().Repr();
741 throw new ArgumentException($
"QCAlgorithm.Plot(): The last argument should be a QuantConnect Indicator object, {pythonType} was provided.");
759 Plot(chart,
new[] { first, second, third, fourth }.Where(x => x !=
null).ToArray());
774 Plot(chart,
new[] { first, second, third, fourth }.Where(x => x !=
null).ToArray());
789 Plot(chart,
new[] { first, second, third, fourth }.Where(x => x !=
null).ToArray());
797 public void PlotIndicator(
string chart, PyObject first, PyObject second =
null, PyObject third =
null, PyObject fourth =
null)
799 var array = GetIndicatorArray(first, second, third, fourth);
800 PlotIndicator(chart, array[0], array[1], array[2], array[3]);
808 public void PlotIndicator(
string chart,
bool waitForReady, PyObject first, PyObject second =
null, PyObject third =
null, PyObject fourth =
null)
810 var array = GetIndicatorArray(first, second, third, fourth);
811 PlotIndicator(chart, waitForReady, array[0], array[1], array[2], array[3]);
826 var resolution = GetSubscription(symbol).
Resolution;
848 return filteredIdentity;
864 var name = $
"{symbol}({fieldName ?? "close
"}_{resolution.ToStringInvariant(null)})";
869 return filteredIdentity;
887 public PyObject
History(PyObject tickers,
int periods,
Resolution? resolution =
null,
bool? fillForward =
null,
889 int? contractDepthOffset =
null)
891 if (tickers.TryConvert<
Universe>(out var universe))
893 resolution ??= universe.Configuration.Resolution;
894 var requests = CreateBarCountHistoryRequests(
new[] { universe.Symbol }, universe.DataType, periods, resolution, fillForward, extendedMarketHours,
895 dataMappingMode, dataNormalizationMode, contractDepthOffset);
899 if (tickers.TryCreateType(out var type))
901 var requests = CreateBarCountHistoryRequests(
Securities.
Keys, type, periods, resolution, fillForward, extendedMarketHours,
902 dataMappingMode, dataNormalizationMode, contractDepthOffset);
903 return GetDataFrame(
History(requests.Where(x => x !=
null)), type);
906 var symbols = tickers.ConvertToSymbolEnumerable();
907 return GetDataFrame(
History(symbols, periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode,
908 contractDepthOffset));
926 public PyObject
History(PyObject tickers, TimeSpan span,
Resolution? resolution =
null,
bool? fillForward =
null,
928 int? contractDepthOffset =
null)
930 return History(tickers,
Time - span,
Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset);
948 public PyObject
History(PyObject tickers, DateTime start, DateTime end,
Resolution? resolution =
null,
bool? fillForward =
null,
950 int? contractDepthOffset =
null)
952 if (tickers.TryConvert<
Universe>(out var universe))
954 resolution ??= universe.Configuration.Resolution;
955 var requests =
CreateDateRangeHistoryRequests(
new[] { universe.Symbol }, universe.DataType, start, end, resolution, fillForward, extendedMarketHours,
956 dataMappingMode, dataNormalizationMode, contractDepthOffset);
960 if (tickers.TryCreateType(out var type))
963 dataMappingMode, dataNormalizationMode, contractDepthOffset);
964 return GetDataFrame(
History(requests.Where(x => x !=
null)), type);
967 var symbols = tickers.ConvertToSymbolEnumerable();
968 return GetDataFrame(
History(symbols, start, end, resolution, fillForward, extendedMarketHours, dataMappingMode,
969 dataNormalizationMode, contractDepthOffset));
988 public PyObject
History(PyObject type, PyObject tickers, DateTime start, DateTime end,
Resolution? resolution =
null,
989 bool? fillForward =
null,
bool? extendedMarketHours =
null,
DataMappingMode? dataMappingMode =
null,
992 var symbols = tickers.ConvertToSymbolEnumerable();
993 var requestedType = type.CreateType();
995 dataMappingMode, dataNormalizationMode, contractDepthOffset);
996 return GetDataFrame(
History(requests.Where(x => x !=
null)), requestedType);
1016 public PyObject
History(PyObject type, PyObject tickers,
int periods,
Resolution? resolution =
null,
bool? fillForward =
null,
1018 int? contractDepthOffset =
null)
1020 var symbols = tickers.ConvertToSymbolEnumerable();
1021 var requestedType = type.CreateType();
1022 CheckPeriodBasedHistoryRequestResolution(symbols, resolution, requestedType);
1024 var requests = CreateBarCountHistoryRequests(symbols, requestedType, periods, resolution, fillForward, extendedMarketHours,
1025 dataMappingMode, dataNormalizationMode, contractDepthOffset);
1027 return GetDataFrame(
History(requests.Where(x => x !=
null)), requestedType);
1046 public PyObject
History(PyObject type, PyObject tickers, TimeSpan span,
Resolution? resolution =
null,
bool? fillForward =
null,
1048 int? contractDepthOffset =
null)
1050 return History(type, tickers,
Time - span,
Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode,
1051 contractDepthOffset);
1070 public PyObject
History(PyObject type,
Symbol symbol, DateTime start, DateTime end,
Resolution? resolution =
null,
bool? fillForward =
null,
1072 int? contractDepthOffset =
null)
1074 return History(type.CreateType(), symbol, start, end, resolution, fillForward, extendedMarketHours, dataMappingMode,
1075 dataNormalizationMode, contractDepthOffset);
1093 private PyObject
History(Type type,
Symbol symbol, DateTime start, DateTime end,
Resolution? resolution,
bool? fillForward,
1095 int? contractDepthOffset)
1098 extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset);
1099 if (requests.IsNullOrEmpty())
1101 throw new ArgumentException($
"No history data could be fetched. " +
1102 $
"This could be due to the specified security not being of the requested type. Symbol: {symbol} Requested Type: {type.Name}");
1105 return GetDataFrame(
History(requests), type);
1124 [DocumentationAttribute(HistoricalData)]
1127 int? contractDepthOffset =
null)
1129 var managedType = type.CreateType();
1130 resolution = GetResolution(symbol, resolution, managedType);
1131 CheckPeriodBasedHistoryRequestResolution(
new[] { symbol }, resolution, managedType);
1133 var marketHours = GetMarketHours(symbol, managedType);
1134 var start = _historyRequestFactory.
GetStartTimeAlgoTz(symbol, periods, resolution.
Value, marketHours.ExchangeHours,
1135 marketHours.DataTimeZone, extendedMarketHours);
1136 return History(managedType, symbol, start,
Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode,
1137 contractDepthOffset);
1158 int? contractDepthOffset =
null)
1160 return History(type, symbol,
Time - span,
Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode,
1161 contractDepthOffset);
1176 var pyBenchmark =
PythonUtil.ToFunc<DateTime, decimal>(benchmark);
1177 if (pyBenchmark !=
null)
1195 if (!model.TryConvert(out brokerageModel))
1241 if (securityInitializer1 !=
null)
1259 public string Download(
string address, PyObject headers) =>
Download(address, headers,
null,
null);
1272 public string Download(
string address, PyObject headers,
string userName,
string password)
1274 var dict =
new Dictionary<string, string>();
1276 if (headers !=
null)
1282 if (PyDict.IsDictType(headers))
1284 using var iterator = headers.GetIterator();
1285 foreach (PyObject pyKey
in iterator)
1287 var key = (string)pyKey.AsManagedObject(typeof(
string));
1288 var value = (string)headers.GetItem(pyKey).AsManagedObject(typeof(
string));
1289 dict.Add(key, value);
1294 throw new ArgumentException($
"QCAlgorithm.Fetch(): Invalid argument. {headers.Repr()} is not a dict");
1298 return Download(address, dict, userName, password);
1310 Debug(message.ToSafeString());
1322 Error(message.ToSafeString());
1332 public void Log(PyObject message)
1334 Log(message.ToSafeString());
1344 Quit(message.ToSafeString());
1357 return Consolidate(symbol, period.ToTimeSpan(),
null, handler);
1371 return Consolidate(symbol, period.ToTimeSpan(), tickType, handler);
1384 return Consolidate(symbol, period,
null, handler);
1399 var type = GetSubscription(symbol, tickType).
Type;
1403 return Consolidate(symbol, period, tickType, handler.ConvertToDelegate<Action<TradeBar>>());
1408 return Consolidate(symbol, period, tickType, handler.ConvertToDelegate<Action<QuoteBar>>());
1411 return Consolidate(symbol, period, tickType, handler.ConvertToDelegate<Action<BaseData>>());
1424 return Consolidate(symbol, calendar,
null, handler);
1435 return Schedule.TrainingNow(trainingCode);
1448 return Schedule.Training(dateRule, timeRule, trainingCode);
1463 var type = GetSubscription(symbol, tickType).
Type;
1467 return Consolidate(symbol, calendar, tickType, handler.ConvertToDelegate<Action<TradeBar>>());
1472 return Consolidate(symbol, calendar, tickType, handler.ConvertToDelegate<Action<QuoteBar>>());
1475 return Consolidate(symbol, calendar, tickType, handler.ConvertToDelegate<Action<BaseData>>());
1483 private Type GetIndicatorBaseType(Type type)
1485 if (type.BaseType == typeof(
object))
1489 return GetIndicatorBaseType(type.BaseType);
1496 private dynamic[] GetIndicatorArray(PyObject first, PyObject second =
null, PyObject third =
null, PyObject fourth =
null)
1500 var array =
new[] {first, second, third, fourth}
1504 if (x ==
null)
return null;
1507 return x.GetPythonType().TryConvert(out type)
1508 ? x.AsManagedObject(type)
1509 : WrapPythonIndicator(x);
1513 var types = array.Where(x => x !=
null).Select(x => GetIndicatorBaseType(x.GetType())).Distinct();
1515 if (types.Count() > 1)
1517 throw new Exception(
"QCAlgorithm.GetIndicatorArray(). All indicators must be of the same type: data point, bar or tradebar.");
1533 if (!_pythonIndicators.TryGetValue(pyObject.Handle, out pythonIndicator))
1535 pyObject.TryConvert(out pythonIndicator);
1538 if (pythonIndicator ==
null)
1544 _pythonIndicators.Add(pyObject.Handle, pythonIndicator);
1547 return pythonIndicator;
1550 protected PyObject GetDataFrame(IEnumerable<Slice> data, Type dataType =
null)
1553 return TryCleanupCollectionDataFrame(dataType, history);
1556 protected PyObject GetDataFrame<T>(IEnumerable<T> data)
1560 return TryCleanupCollectionDataFrame(typeof(
T), history);
1563 private IEnumerable<T> RemoveMemoizing<T>(IEnumerable<T> data)
1566 if (memoizingEnumerable !=
null)
1570 memoizingEnumerable.
Enabled =
false;
1575 private PyObject TryCleanupCollectionDataFrame(Type dataType, PyObject history)
1581 dynamic dynamic = history;
1586 using PyObject columns = dynamic.columns;
1587 if (columns.As<
string[]>().Contains(
"data"))
1589 history = dynamic[
"data"];
1593 dynamic.index = dynamic.index.droplevel(
"symbol");