chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,779 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NodaTime;
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Algorithm;
|
||||
using QuantConnect.Algorithm.Framework.Selection;
|
||||
using QuantConnect.Algorithm.Selection;
|
||||
using QuantConnect.AlgorithmFactory.Python.Wrappers;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Auxiliary;
|
||||
using QuantConnect.Data.Consolidators;
|
||||
using QuantConnect.Data.Custom.IconicTypes;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Tests.Engine.DataFeeds;
|
||||
using QuantConnect.Util;
|
||||
using Bitcoin = QuantConnect.Algorithm.CSharp.LiveTradingFeaturesAlgorithm.Bitcoin;
|
||||
using HistoryRequest = QuantConnect.Data.HistoryRequest;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm
|
||||
{
|
||||
[TestFixture]
|
||||
public class AlgorithmAddDataTests
|
||||
{
|
||||
[Test]
|
||||
public void DefaultDataFeeds_CanBeOverwritten_Successfully()
|
||||
{
|
||||
var algo = new QCAlgorithm();
|
||||
algo.SubscriptionManager.SetDataManager(new DataManagerStub(algo));
|
||||
|
||||
// forex defult - should be quotebar
|
||||
var forexTrade = algo.AddForex("EURUSD");
|
||||
Assert.IsTrue(forexTrade.Subscriptions.Count() == 1);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, forexTrade.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
// Change
|
||||
Config.Set("security-data-feeds", "{ Forex: [\"Trade\"] }");
|
||||
var dataFeedsConfigString = Config.Get("security-data-feeds");
|
||||
Dictionary<SecurityType, List<TickType>> dataFeeds = new Dictionary<SecurityType, List<TickType>>();
|
||||
if (!string.IsNullOrEmpty(dataFeedsConfigString))
|
||||
{
|
||||
dataFeeds = JsonConvert.DeserializeObject<Dictionary<SecurityType, List<TickType>>>(dataFeedsConfigString);
|
||||
}
|
||||
|
||||
algo.SetAvailableDataTypes(dataFeeds);
|
||||
|
||||
// new forex - should be tradebar
|
||||
var forexQuote = algo.AddForex("EURUSD");
|
||||
// The quote bar subscription is kept
|
||||
Assert.IsTrue(forexQuote.Subscriptions.Count() == 2);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, forexQuote.Symbol, typeof(TradeBar)) != null);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, forexQuote.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
// reset to empty string, affects other tests because config is static
|
||||
Config.Set("security-data-feeds", "");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultDataFeeds_AreAdded_Successfully()
|
||||
{
|
||||
var algo = new QCAlgorithm();
|
||||
algo.SubscriptionManager.SetDataManager(new DataManagerStub(algo));
|
||||
|
||||
// forex
|
||||
var forex = algo.AddSecurity(SecurityType.Forex, "eurusd");
|
||||
Assert.IsTrue(forex.Subscriptions.Count() == 1);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, forex.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
// equity high resolution
|
||||
var equityMinute = algo.AddSecurity(SecurityType.Equity, "goog");
|
||||
Assert.IsTrue(equityMinute.Subscriptions.Count() == 2);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, equityMinute.Symbol, typeof(TradeBar)) != null);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, equityMinute.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
// equity low resolution
|
||||
var equityDaily = algo.AddSecurity(SecurityType.Equity, "goog", Resolution.Daily);
|
||||
Assert.IsTrue(equityDaily.Subscriptions.Count() == 3);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, equityDaily.Symbol, typeof(TradeBar)) != null);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, equityMinute.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
Assert.IsTrue(ReferenceEquals(equityMinute, equityDaily));
|
||||
|
||||
var equitySubscriptions = algo.SubscriptionManager.SubscriptionDataConfigService
|
||||
.GetSubscriptionDataConfigs(equityMinute.Symbol);
|
||||
Assert.IsTrue(equitySubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Trade && s.Type == typeof(TradeBar) && s.Resolution == Resolution.Minute) != null);
|
||||
Assert.IsTrue(equitySubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Quote && s.Type == typeof(QuoteBar) && s.Resolution == Resolution.Minute) != null);
|
||||
Assert.IsTrue(equitySubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Trade && s.Type == typeof(TradeBar) && s.Resolution == Resolution.Daily) != null);
|
||||
|
||||
// option
|
||||
var option = algo.AddSecurity(SecurityType.Option, "goog");
|
||||
Assert.IsTrue(option.Subscriptions.Count() == 1);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, option.Symbol, typeof(OptionUniverse)) != null);
|
||||
|
||||
// index option
|
||||
var indexOption = algo.AddSecurity(SecurityType.IndexOption, "spx");
|
||||
Assert.IsTrue(indexOption.Subscriptions.Count() == 1);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, indexOption.Symbol, typeof(OptionUniverse)) != null);
|
||||
|
||||
// cfd
|
||||
var cfd = algo.AddSecurity(SecurityType.Cfd, "abc");
|
||||
Assert.IsTrue(cfd.Subscriptions.Count() == 1);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, cfd.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
// future
|
||||
var future = algo.AddSecurity(SecurityType.Future, "ES");
|
||||
Assert.IsTrue(future.Subscriptions.Count() == 1);
|
||||
Assert.IsTrue(future.Subscriptions.FirstOrDefault(x => typeof(FutureUniverse) == x.Type) != null);
|
||||
|
||||
// Crypto high resolution
|
||||
var cryptoMinute = algo.AddSecurity(SecurityType.Crypto, "btcusd");
|
||||
Assert.IsTrue(cryptoMinute.Subscriptions.Count() == 2);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, cryptoMinute.Symbol, typeof(TradeBar)) != null);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, cryptoMinute.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
// Crypto low resolution
|
||||
var cryptoHourly = algo.AddSecurity(SecurityType.Crypto, "btcusd", Resolution.Hour);
|
||||
Assert.IsTrue(cryptoHourly.Subscriptions.Count() == 4);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, cryptoHourly.Symbol, typeof(TradeBar)) != null);
|
||||
Assert.IsTrue(GetMatchingSubscription(algo, cryptoHourly.Symbol, typeof(QuoteBar)) != null);
|
||||
|
||||
Assert.IsTrue(ReferenceEquals(cryptoMinute, cryptoHourly));
|
||||
|
||||
var cryptoSubscriptions = algo.SubscriptionManager.SubscriptionDataConfigService
|
||||
.GetSubscriptionDataConfigs(cryptoMinute.Symbol);
|
||||
Assert.IsTrue(cryptoSubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Trade && s.Type == typeof(TradeBar) && s.Resolution == Resolution.Minute) != null);
|
||||
Assert.IsTrue(cryptoSubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Quote && s.Type == typeof(QuoteBar) && s.Resolution == Resolution.Minute) != null);
|
||||
Assert.IsTrue(cryptoSubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Trade && s.Type == typeof(TradeBar) && s.Resolution == Resolution.Hour) != null);
|
||||
Assert.IsTrue(cryptoSubscriptions.SingleOrDefault(
|
||||
s => s.TickType == TickType.Quote && s.Type == typeof(QuoteBar) && s.Resolution == Resolution.Hour) != null);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void CustomDataTypes_AreAddedToSubscriptions_Successfully()
|
||||
{
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
// Add a bitcoin subscription
|
||||
qcAlgorithm.AddData<Bitcoin>("BTC");
|
||||
var bitcoinSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.FirstOrDefault(x => x.Type == typeof(Bitcoin));
|
||||
Assert.AreEqual(bitcoinSubscription.Type, typeof(Bitcoin));
|
||||
|
||||
// Add a unlinkedData subscription
|
||||
qcAlgorithm.AddData<UnlinkedData>("EURCAD");
|
||||
var unlinkedDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.FirstOrDefault(x => x.Type == typeof(UnlinkedData));
|
||||
Assert.AreEqual(unlinkedDataSubscription.Type, typeof(UnlinkedData));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnEndOfTimeStepSeedsUnderlyingSecuritiesThatHaveNoData()
|
||||
{
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm, new MockDataFeed()));
|
||||
qcAlgorithm.SetLiveMode(true);
|
||||
qcAlgorithm.Settings.SeedInitialPrices = false;
|
||||
var testHistoryProvider = new TestHistoryProvider();
|
||||
qcAlgorithm.HistoryProvider = testHistoryProvider;
|
||||
|
||||
var option = qcAlgorithm.AddSecurity(SecurityType.Option, testHistoryProvider.underlyingSymbol);
|
||||
var option2 = qcAlgorithm.AddSecurity(SecurityType.Option, testHistoryProvider.underlyingSymbol2);
|
||||
Assert.IsFalse(qcAlgorithm.Securities.ContainsKey(option.Symbol.Underlying));
|
||||
Assert.IsFalse(qcAlgorithm.Securities.ContainsKey(option2.Symbol.Underlying));
|
||||
qcAlgorithm.OnEndOfTimeStep();
|
||||
var data = qcAlgorithm.Securities[testHistoryProvider.underlyingSymbol].GetLastData();
|
||||
var data2 = qcAlgorithm.Securities[testHistoryProvider.underlyingSymbol2].GetLastData();
|
||||
Assert.IsNotNull(data);
|
||||
Assert.IsNotNull(data2);
|
||||
Assert.AreEqual(data.Price, 2);
|
||||
Assert.AreEqual(data2.Price, 3);
|
||||
}
|
||||
|
||||
[Test, Parallelizable(ParallelScope.Self)]
|
||||
public void OnEndOfTimeStepDoesNotThrowWhenSeedsSameUnderlyingForTwoSecurities()
|
||||
{
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm, new MockDataFeed()));
|
||||
qcAlgorithm.SetLiveMode(true);
|
||||
qcAlgorithm.Settings.SeedInitialPrices = false;
|
||||
var testHistoryProvider = new TestHistoryProvider();
|
||||
qcAlgorithm.HistoryProvider = testHistoryProvider;
|
||||
var option = qcAlgorithm.AddOption(testHistoryProvider.underlyingSymbol);
|
||||
|
||||
var symbol = Symbol.CreateOption(testHistoryProvider.underlyingSymbol, Market.USA, OptionStyle.American,
|
||||
OptionRight.Call, 1, new DateTime(2015, 12, 24));
|
||||
var symbol2 = Symbol.CreateOption(testHistoryProvider.underlyingSymbol, Market.USA, OptionStyle.American,
|
||||
OptionRight.Put, 1, new DateTime(2015, 12, 24));
|
||||
|
||||
var optionContract = qcAlgorithm.AddOptionContract(symbol);
|
||||
var optionContract2 = qcAlgorithm.AddOptionContract(symbol2);
|
||||
|
||||
qcAlgorithm.OnEndOfTimeStep();
|
||||
var data = qcAlgorithm.Securities[testHistoryProvider.underlyingSymbol].GetLastData();
|
||||
Assert.IsNotNull(data);
|
||||
Assert.AreEqual(data.Price, 2);
|
||||
}
|
||||
|
||||
[TestCase("EURUSD", typeof(IndexedLinkedData), SecurityType.Cfd, false, true)]
|
||||
[TestCase("BTCUSD", typeof(IndexedLinkedData), SecurityType.Crypto, false, true)]
|
||||
[TestCase("CL", typeof(IndexedLinkedData), SecurityType.Future, true, true)]
|
||||
[TestCase("EURUSD", typeof(IndexedLinkedData), SecurityType.Forex, false, true)]
|
||||
[TestCase("AAPL", typeof(IndexedLinkedData), SecurityType.Equity, true, true)]
|
||||
[TestCase("EURUSD", typeof(UnlinkedData), SecurityType.Cfd, false, false)]
|
||||
[TestCase("BTCUSD", typeof(UnlinkedData), SecurityType.Crypto, false, false)]
|
||||
[TestCase("CL", typeof(UnlinkedData), SecurityType.Future, true, false)]
|
||||
[TestCase("AAPL", typeof(UnlinkedData), SecurityType.Equity, true, false)]
|
||||
[TestCase("EURUSD", typeof(UnlinkedData), SecurityType.Forex, false, false)]
|
||||
public void AddDataSecuritySymbolWithUnderlying(string ticker, Type customDataType, SecurityType securityType, bool securityShouldBeMapped, bool customDataShouldBeMapped)
|
||||
{
|
||||
SymbolCache.Clear();
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
Security asset;
|
||||
|
||||
switch (securityType)
|
||||
{
|
||||
case SecurityType.Cfd:
|
||||
asset = qcAlgorithm.AddCfd(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Crypto:
|
||||
asset = qcAlgorithm.AddCrypto(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Equity:
|
||||
asset = qcAlgorithm.AddEquity(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Forex:
|
||||
asset = qcAlgorithm.AddForex(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Future:
|
||||
asset = qcAlgorithm.AddFuture(ticker, Resolution.Minute);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"SecurityType {securityType} is not valid for this test");
|
||||
}
|
||||
|
||||
// Dummy here is meant to try to corrupt the SymbolCache. Ideally, SymbolCache should return non-custom data types with higher priority
|
||||
// in case we want to add two custom data types, but still have them associated with the equity from the cache if we're using it.
|
||||
// This covers the case where two idential data subscriptions are created.
|
||||
var dummy = qcAlgorithm.AddData(customDataType, asset.Symbol, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First().DataTimeZone);
|
||||
var customData = qcAlgorithm.AddData(customDataType, asset.Symbol, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First().DataTimeZone);
|
||||
|
||||
Assert.IsTrue(customData.Symbol.HasUnderlying, $"{customDataType.Name} added as {ticker} Symbol with SecurityType {securityType} does not have underlying");
|
||||
Assert.AreEqual(customData.Symbol.Underlying, asset.Symbol, $"Custom data underlying does not match {securityType} Symbol for {ticker}");
|
||||
|
||||
var assetSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First();
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Base).Single();
|
||||
|
||||
var assetShouldBeMapped = assetSubscription.TickerShouldBeMapped();
|
||||
var customShouldBeMapped = customDataSubscription.TickerShouldBeMapped();
|
||||
|
||||
Assert.AreEqual(securityShouldBeMapped, assetShouldBeMapped);
|
||||
Assert.AreEqual(customDataShouldBeMapped, customShouldBeMapped);
|
||||
|
||||
Assert.AreNotEqual(assetSubscription, customDataSubscription);
|
||||
|
||||
if (assetShouldBeMapped == customShouldBeMapped)
|
||||
{
|
||||
Assert.AreEqual(assetSubscription.MappedSymbol, customDataSubscription.MappedSymbol);
|
||||
Assert.AreEqual(asset.Symbol.Value, customData.Symbol.Value.Split('.').First());
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("EURUSD", typeof(IndexedLinkedData), SecurityType.Cfd, false, false)]
|
||||
[TestCase("BTCUSD", typeof(IndexedLinkedData), SecurityType.Crypto, false, false)]
|
||||
[TestCase("CL", typeof(IndexedLinkedData), SecurityType.Future, false, false)]
|
||||
[TestCase("EURUSD", typeof(IndexedLinkedData), SecurityType.Forex, false, false)]
|
||||
[TestCase("AAPL", typeof(IndexedLinkedData), SecurityType.Equity, true, true)]
|
||||
public void AddDataSecurityTickerWithUnderlying(string ticker, Type customDataType, SecurityType securityType, bool securityShouldBeMapped, bool customDataShouldBeMapped)
|
||||
{
|
||||
SymbolCache.Clear();
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
Security asset;
|
||||
|
||||
switch (securityType)
|
||||
{
|
||||
case SecurityType.Cfd:
|
||||
asset = qcAlgorithm.AddCfd(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Crypto:
|
||||
asset = qcAlgorithm.AddCrypto(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Equity:
|
||||
asset = qcAlgorithm.AddEquity(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Forex:
|
||||
asset = qcAlgorithm.AddForex(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Future:
|
||||
asset = qcAlgorithm.AddFuture(ticker, Resolution.Minute);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"SecurityType {securityType} is not valid for this test");
|
||||
}
|
||||
|
||||
// Aliased value for Futures contains a forward-slash, which causes the
|
||||
// lookup in the SymbolCache to fail
|
||||
if (securityType == SecurityType.Future)
|
||||
{
|
||||
ticker = asset.Symbol.Value;
|
||||
}
|
||||
|
||||
// Dummy here is meant to try to corrupt the SymbolCache. Ideally, SymbolCache should return non-custom data types with higher priority
|
||||
// in case we want to add two custom data types, but still have them associated with the equity from the cache if we're using it.
|
||||
// This covers the case where two idential data subscriptions are created.
|
||||
var dummy = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First().DataTimeZone);
|
||||
var customData = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First().DataTimeZone);
|
||||
|
||||
Assert.IsTrue(customData.Symbol.HasUnderlying, $"Custom data added as {ticker} Symbol with SecurityType {securityType} does not have underlying");
|
||||
Assert.AreEqual(customData.Symbol.Underlying, asset.Symbol, $"Custom data underlying does not match {securityType} Symbol for {ticker}");
|
||||
|
||||
var assetSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First();
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Base).Single();
|
||||
|
||||
var assetShouldBeMapped = assetSubscription.TickerShouldBeMapped();
|
||||
var customShouldBeMapped = customDataSubscription.TickerShouldBeMapped();
|
||||
|
||||
if (securityType == SecurityType.Equity)
|
||||
{
|
||||
Assert.AreEqual(securityShouldBeMapped, assetShouldBeMapped);
|
||||
Assert.AreEqual(customDataShouldBeMapped, customShouldBeMapped);
|
||||
|
||||
Assert.AreNotEqual(assetSubscription, customDataSubscription);
|
||||
|
||||
if (assetShouldBeMapped == customShouldBeMapped)
|
||||
{
|
||||
Assert.AreEqual(assetSubscription.MappedSymbol, customDataSubscription.MappedSymbol);
|
||||
Assert.AreEqual(asset.Symbol.Value, customData.Symbol.Value.Split('.').First());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("EURUSD", typeof(UnlinkedData), SecurityType.Cfd, false, false)]
|
||||
[TestCase("BTCUSD", typeof(UnlinkedData), SecurityType.Crypto, false, false)]
|
||||
[TestCase("CL", typeof(UnlinkedData), SecurityType.Future, true, false)]
|
||||
[TestCase("AAPL", typeof(UnlinkedData), SecurityType.Equity, true, false)]
|
||||
[TestCase("EURUSD", typeof(UnlinkedData), SecurityType.Forex, false, false)]
|
||||
public void AddDataSecurityTickerNoUnderlying(string ticker, Type customDataType, SecurityType securityType, bool securityShouldBeMapped, bool customDataShouldBeMapped)
|
||||
{
|
||||
SymbolCache.Clear();
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
Security asset;
|
||||
|
||||
switch (securityType)
|
||||
{
|
||||
case SecurityType.Cfd:
|
||||
asset = qcAlgorithm.AddCfd(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Crypto:
|
||||
asset = qcAlgorithm.AddCrypto(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Equity:
|
||||
asset = qcAlgorithm.AddEquity(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Forex:
|
||||
asset = qcAlgorithm.AddForex(ticker, Resolution.Daily);
|
||||
break;
|
||||
case SecurityType.Future:
|
||||
asset = qcAlgorithm.AddFuture(ticker, Resolution.Minute);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"SecurityType {securityType} is not valid for this test");
|
||||
}
|
||||
|
||||
// Dummy here is meant to try to corrupt the SymbolCache. Ideally, SymbolCache should return non-custom data types with higher priority
|
||||
// in case we want to add two custom data types, but still have them associated with the equity from the cache if we're using it.
|
||||
// This covers the case where two idential data subscriptions are created.
|
||||
var dummy = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First().DataTimeZone);
|
||||
var customData = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First().DataTimeZone);
|
||||
|
||||
// Check to see if we have an underlying symbol when we shouldn't
|
||||
Assert.IsFalse(customData.Symbol.HasUnderlying, $"{customDataType.Name} has underlying symbol for SecurityType {securityType} with ticker {ticker}");
|
||||
Assert.AreEqual(customData.Symbol.Underlying, null, $"{customDataType.Name} - Custom data underlying Symbol for SecurityType {securityType} is not null");
|
||||
|
||||
var assetSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == securityType).First();
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Base).Single();
|
||||
|
||||
var assetShouldBeMapped = assetSubscription.TickerShouldBeMapped();
|
||||
var customShouldBeMapped = customDataSubscription.TickerShouldBeMapped();
|
||||
|
||||
Assert.AreEqual(securityShouldBeMapped, assetShouldBeMapped);
|
||||
Assert.AreEqual(customDataShouldBeMapped, customShouldBeMapped);
|
||||
|
||||
Assert.AreNotEqual(assetSubscription, customDataSubscription);
|
||||
|
||||
if (assetShouldBeMapped == customShouldBeMapped)
|
||||
{
|
||||
// Would fail with CL future without this check because MappedSymbol returns "/CL" for the Future symbol
|
||||
if (assetSubscription.SecurityType == SecurityType.Future)
|
||||
{
|
||||
Assert.AreNotEqual(assetSubscription.MappedSymbol, customDataSubscription.MappedSymbol);
|
||||
Assert.AreNotEqual(asset.Symbol.Value, customData.Symbol.Value.Split('.').First());
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual(assetSubscription.MappedSymbol, customDataSubscription.MappedSymbol);
|
||||
Assert.AreEqual(asset.Symbol.Value, customData.Symbol.Value.Split('.').First());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddOptionWithUnderlyingFuture()
|
||||
{
|
||||
// Adds an option containing a Future as its underlying Symbol.
|
||||
// This is an essential step in enabling custom derivatives
|
||||
// based on any asset class provided to Option. This test
|
||||
// checks the ability to create Future Options.
|
||||
var algo = new QCAlgorithm();
|
||||
algo.SubscriptionManager.SetDataManager(new DataManagerStub(algo));
|
||||
|
||||
var underlying = algo.AddFuture("ES", Resolution.Minute, Market.CME);
|
||||
underlying.SetFilter(0, 365);
|
||||
|
||||
var futureOption = algo.AddOption(underlying.Symbol, Resolution.Minute);
|
||||
|
||||
Assert.IsTrue(futureOption.Symbol.HasUnderlying);
|
||||
Assert.AreEqual(underlying.Symbol, futureOption.Symbol.Underlying);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddFutureOptionContractNonEquityOption()
|
||||
{
|
||||
// Adds an option contract containing an underlying future contract.
|
||||
// We test to make sure that the security returned is a specific option
|
||||
// contract and with the future as the underlying.
|
||||
var algo = new QCAlgorithm();
|
||||
algo.SubscriptionManager.SetDataManager(new DataManagerStub(algo));
|
||||
|
||||
var underlying = algo.AddFutureContract(
|
||||
Symbol.CreateFuture("ES", Market.CME, new DateTime(2021, 3, 19)),
|
||||
Resolution.Minute);
|
||||
|
||||
var futureOptionContract = algo.AddFutureOptionContract(
|
||||
Symbol.CreateOption(underlying.Symbol, Market.CME, OptionStyle.American, OptionRight.Call, 2550m, new DateTime(2021, 3, 19)),
|
||||
Resolution.Minute);
|
||||
|
||||
Assert.AreEqual(underlying.Symbol, futureOptionContract.Symbol.Underlying);
|
||||
Assert.AreEqual(underlying, futureOptionContract.Underlying);
|
||||
Assert.IsFalse(underlying.Symbol.IsCanonical());
|
||||
Assert.IsFalse(futureOptionContract.Symbol.IsCanonical());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddFutureOptionAddsUniverseSelectionModel()
|
||||
{
|
||||
var algo = new QCAlgorithm();
|
||||
algo.SubscriptionManager.SetDataManager(new DataManagerStub(algo));
|
||||
|
||||
var underlying = algo.AddFuture("ES", Resolution.Minute, Market.CME);
|
||||
underlying.SetFilter(0, 365);
|
||||
|
||||
algo.AddFutureOption(underlying.Symbol, _ => _);
|
||||
Assert.IsTrue(algo.UniverseSelection is CompositeUniverseSelectionModel);
|
||||
}
|
||||
|
||||
[TestCase("AAPL", typeof(IndexedLinkedData), true)]
|
||||
[TestCase("TWX", typeof(IndexedLinkedData), true)]
|
||||
[TestCase("FB", typeof(IndexedLinkedData), true)]
|
||||
[TestCase("NFLX", typeof(IndexedLinkedData), true)]
|
||||
[TestCase("TWX", typeof(UnlinkedData), false)]
|
||||
[TestCase("AAPL", typeof(UnlinkedData), false)]
|
||||
public void AddDataOptionsSymbolHasChainedUnderlyingSymbols(string ticker, Type customDataType, bool customDataShouldBeMapped)
|
||||
{
|
||||
SymbolCache.Clear();
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
var asset = qcAlgorithm.AddOption(ticker);
|
||||
|
||||
// Dummy here is meant to try to corrupt the SymbolCache. Ideally, SymbolCache should return non-custom data types with higher priority
|
||||
// in case we want to add two custom data types, but still have them associated with the equity from the cache if we're using it.
|
||||
// This covers the case where two idential data subscriptions are created.
|
||||
var dummy = qcAlgorithm.AddData(customDataType, asset.Symbol, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single().DataTimeZone);
|
||||
var customData = qcAlgorithm.AddData(customDataType, asset.Symbol, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single().DataTimeZone);
|
||||
|
||||
// Check to see if we have an underlying symbol when we shouldn't
|
||||
Assert.IsTrue(customData.Symbol.HasUnderlying, $"{customDataType.Name} - {ticker} has no underlying Symbol");
|
||||
Assert.AreEqual(customData.Symbol.Underlying, asset.Symbol);
|
||||
Assert.AreEqual(customData.Symbol.Underlying.Underlying, asset.Symbol.Underlying);
|
||||
Assert.AreEqual(customData.Symbol.Underlying.Underlying.Underlying, null);
|
||||
|
||||
var assetSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single();
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Base).Single();
|
||||
|
||||
Assert.IsTrue(assetSubscription.TickerShouldBeMapped());
|
||||
Assert.AreEqual(customDataShouldBeMapped, customDataSubscription.TickerShouldBeMapped());
|
||||
|
||||
Assert.AreEqual($"?{assetSubscription.MappedSymbol}", customDataSubscription.MappedSymbol);
|
||||
}
|
||||
|
||||
[TestCase("AAPL", typeof(IndexedLinkedData))]
|
||||
[TestCase("TWX", typeof(IndexedLinkedData))]
|
||||
[TestCase("FB", typeof(IndexedLinkedData))]
|
||||
[TestCase("NFLX", typeof(IndexedLinkedData))]
|
||||
public void AddDataOptionsTickerHasChainedUnderlyingSymbol(string ticker, Type customDataType)
|
||||
{
|
||||
SymbolCache.Clear();
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
var asset = qcAlgorithm.AddOption(ticker);
|
||||
|
||||
// Dummy here is meant to try to corrupt the SymbolCache. Ideally, SymbolCache should return non-custom data types with higher priority
|
||||
// in case we want to add two custom data types, but still have them associated with the equity from the cache if we're using it.
|
||||
// This covers the case where two idential data subscriptions are created.
|
||||
var dummy = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single().DataTimeZone);
|
||||
var customData = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single().DataTimeZone);
|
||||
|
||||
// Check to see if we have an underlying symbol when we shouldn't
|
||||
Assert.IsTrue(customData.Symbol.HasUnderlying, $"{customDataType.Name} - {ticker} has no underlying Symbol");
|
||||
Assert.AreNotEqual(customData.Symbol.Underlying, asset.Symbol);
|
||||
Assert.IsFalse(customData.Symbol.Underlying.HasUnderlying);
|
||||
Assert.AreEqual(customData.Symbol.Underlying, asset.Symbol.Underlying);
|
||||
|
||||
var assetSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single();
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Base).Single();
|
||||
|
||||
Assert.IsTrue(assetSubscription.TickerShouldBeMapped());
|
||||
Assert.IsTrue(customDataSubscription.TickerShouldBeMapped());
|
||||
|
||||
Assert.AreEqual(assetSubscription.MappedSymbol, customDataSubscription.MappedSymbol);
|
||||
}
|
||||
|
||||
[TestCase("AAPL", typeof(UnlinkedData))]
|
||||
[TestCase("FDTR", typeof(UnlinkedData))]
|
||||
public void AddDataOptionsTickerHasNoChainedUnderlyingSymbols(string ticker, Type customDataType)
|
||||
{
|
||||
SymbolCache.Clear();
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
var asset = qcAlgorithm.AddOption(ticker);
|
||||
|
||||
// Dummy here is meant to try to corrupt the SymbolCache. Ideally, SymbolCache should return non-custom data types with higher priority
|
||||
// in case we want to add two custom data types, but still have them associated with the equity from the cache if we're using it.
|
||||
// This covers the case where two idential data subscriptions are created.
|
||||
var dummy = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single().DataTimeZone);
|
||||
var customData = qcAlgorithm.AddData(customDataType, ticker, Resolution.Daily, qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single().DataTimeZone);
|
||||
|
||||
// Check to see if we have an underlying symbol when we shouldn't
|
||||
Assert.IsFalse(customData.Symbol.HasUnderlying, $"{customDataType.Name} has an underlying Symbol");
|
||||
|
||||
var assetSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Option).Single();
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.Where(x => x.SecurityType == SecurityType.Base).Single();
|
||||
|
||||
Assert.IsTrue(assetSubscription.TickerShouldBeMapped());
|
||||
Assert.IsFalse(customDataSubscription.TickerShouldBeMapped());
|
||||
|
||||
//Assert.AreNotEqual(assetSubscription.MappedSymbol, customDataSubscription.MappedSymbol);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PythonCustomDataTypes_AreAddedToSubscriptions_Successfully()
|
||||
{
|
||||
var qcAlgorithm = new AlgorithmPythonWrapper("Test_CustomDataAlgorithm");
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
// Initialize contains the statements:
|
||||
// self.AddData(Nifty, "NIFTY")
|
||||
// self.AddData(CustomPythonData, "IBM", Resolution.Daily)
|
||||
qcAlgorithm.Initialize();
|
||||
|
||||
var niftySubscription = qcAlgorithm.SubscriptionManager.Subscriptions.FirstOrDefault(x => x.Symbol.Value == "NIFTY");
|
||||
Assert.IsNotNull(niftySubscription);
|
||||
|
||||
var niftyFactory = (BaseData)ObjectActivator.GetActivator(niftySubscription.Type).Invoke(new object[] { niftySubscription.Type });
|
||||
Assert.DoesNotThrow(() => niftyFactory.GetSource(niftySubscription, DateTime.UtcNow, false));
|
||||
|
||||
var customDataSubscription = qcAlgorithm.SubscriptionManager.Subscriptions.FirstOrDefault(x => x.Symbol.Value == "IBM");
|
||||
Assert.IsNotNull(customDataSubscription);
|
||||
Assert.IsTrue(customDataSubscription.IsCustomData);
|
||||
Assert.AreEqual("custom_data.CustomPythonData", customDataSubscription.Type.ToString());
|
||||
|
||||
var customDataFactory = (BaseData)ObjectActivator.GetActivator(customDataSubscription.Type).Invoke(new object[] { customDataSubscription.Type });
|
||||
Assert.DoesNotThrow(() => customDataFactory.GetSource(customDataSubscription, DateTime.UtcNow, false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PythonCustomDataTypes_AreAddedToConsolidator_Successfully()
|
||||
{
|
||||
var qcAlgorithm = new AlgorithmPythonWrapper("Test_CustomDataAlgorithm");
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
// Initialize contains the statements:
|
||||
// self.AddData(Nifty, "NIFTY")
|
||||
// self.AddData(CustomPythonData, "IBM", Resolution.Daily)
|
||||
qcAlgorithm.Initialize();
|
||||
|
||||
#pragma warning disable CS0618
|
||||
using var niftyConsolidator = new DynamicDataConsolidator(TimeSpan.FromDays(2));
|
||||
Assert.DoesNotThrow(() => qcAlgorithm.SubscriptionManager.AddConsolidator("NIFTY", niftyConsolidator));
|
||||
|
||||
using var customDataConsolidator = new DynamicDataConsolidator(TimeSpan.FromDays(2));
|
||||
Assert.DoesNotThrow(() => qcAlgorithm.SubscriptionManager.AddConsolidator("IBM", customDataConsolidator));
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingInvalidDataTypeThrows()
|
||||
{
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
Assert.Throws<ArgumentException>(() => qcAlgorithm.AddData(typeof(double),
|
||||
"double",
|
||||
Resolution.Daily,
|
||||
DateTimeZone.Utc));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddDataWithStringAsTypeArgumentThrowsClearError()
|
||||
{
|
||||
var qcAlgorithm = new QCAlgorithm();
|
||||
qcAlgorithm.SubscriptionManager.SetDataManager(new DataManagerStub(qcAlgorithm));
|
||||
|
||||
using var _ = Py.GIL();
|
||||
using var pyTicker = "VIX".ToPython();
|
||||
|
||||
// Passing a string instead of a custom data class as the first argument used to silently build a
|
||||
// dynamic assembly named after the string and later hang/fail downstream. It must now throw.
|
||||
var ex = Assert.Throws<ArgumentException>(() => qcAlgorithm.AddData(pyTicker, "VIX", Resolution.Daily));
|
||||
StringAssert.Contains("AddData", ex.Message);
|
||||
StringAssert.Contains("AddEquity", ex.Message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AppendsCustomDataTypeName_ToSecurityIdentifierSymbol()
|
||||
{
|
||||
const string ticker = "ticker";
|
||||
var algorithm = Algorithm();
|
||||
|
||||
var security = algorithm.AddData<UnlinkedData>(ticker);
|
||||
Assert.AreEqual(ticker.ToUpperInvariant(), security.Symbol.Value);
|
||||
Assert.AreEqual($"{ticker.ToUpperInvariant()}.{typeof(UnlinkedData).Name}", security.Symbol.ID.Symbol);
|
||||
Assert.AreEqual(SecurityIdentifier.GenerateBaseSymbol(typeof(UnlinkedData), ticker), security.Symbol.ID.Symbol);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RegistersSecurityIdentifierSymbol_AsTickerString_InSymbolCache()
|
||||
{
|
||||
var algorithm = Algorithm();
|
||||
|
||||
Symbol cachedSymbol;
|
||||
var security = algorithm.AddData<UnlinkedData>("ticker");
|
||||
var symbolCacheAlias = security.Symbol.ID.Symbol;
|
||||
|
||||
Assert.IsTrue(SymbolCache.TryGetSymbol(symbolCacheAlias, out cachedSymbol));
|
||||
Assert.AreSame(security.Symbol, cachedSymbol);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotCauseCollision_WhenRegisteringMultipleDifferentCustomDataTypes_WithSameTicker()
|
||||
{
|
||||
const string ticker = "ticker";
|
||||
var algorithm = Algorithm();
|
||||
|
||||
var security1 = algorithm.AddData<UnlinkedData>(ticker);
|
||||
var security2 = algorithm.AddData<Bitcoin>(ticker);
|
||||
|
||||
var unlinkedData = algorithm.Securities[security1.Symbol];
|
||||
Assert.AreSame(security1, unlinkedData);
|
||||
|
||||
var bitcoin = algorithm.Securities[security2.Symbol];
|
||||
Assert.AreSame(security2, bitcoin);
|
||||
|
||||
Assert.AreNotSame(unlinkedData, bitcoin);
|
||||
}
|
||||
|
||||
[TestCase(SecurityType.Equity)]
|
||||
[TestCase(SecurityType.Index)]
|
||||
[TestCase(SecurityType.Future)]
|
||||
public void AddOptionContractWithDelistedUnderlyingThrows(SecurityType underlyingSecurityType)
|
||||
{
|
||||
var algorithm = Algorithm();
|
||||
algorithm.SetStartDate(2007, 05, 25);
|
||||
|
||||
Security underlying = underlyingSecurityType switch
|
||||
{
|
||||
SecurityType.Equity => algorithm.AddEquity("SPY"),
|
||||
SecurityType.Index => algorithm.AddIndex("SPX"),
|
||||
SecurityType.Future => algorithm.AddFuture("ES"),
|
||||
_ => throw new ArgumentException($"Invalid test underlying security type {underlyingSecurityType}")
|
||||
};
|
||||
|
||||
underlying.IsDelisted = true;
|
||||
// let's remove the underlying since it's delisted
|
||||
algorithm.RemoveSecurity(underlying.Symbol);
|
||||
|
||||
var optionContractSymbol = Symbol.CreateOption(underlying.Symbol, Market.USA, OptionStyle.American, OptionRight.Call, 100,
|
||||
new DateTime(2007, 06, 15));
|
||||
|
||||
var exception = Assert.Throws<ArgumentException>(() => algorithm.AddOptionContract(optionContractSymbol));
|
||||
Assert.IsTrue(exception.Message.Contains("is delisted"), $"Unexpected exception message: {exception.Message}");
|
||||
}
|
||||
|
||||
private static SubscriptionDataConfig GetMatchingSubscription(QCAlgorithm algorithm, Symbol symbol, Type type)
|
||||
{
|
||||
// find a subscription matchin the requested type with a higher resolution than requested
|
||||
return algorithm.SubscriptionManager.SubscriptionDataConfigService
|
||||
.GetSubscriptionDataConfigs(symbol)
|
||||
.Where(config => type.IsAssignableFrom(config.Type))
|
||||
.OrderByDescending(s => s.Resolution)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private static QCAlgorithm Algorithm()
|
||||
{
|
||||
var algorithm = new QCAlgorithm();
|
||||
algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
private class TestHistoryProvider : HistoryProviderBase
|
||||
{
|
||||
public string underlyingSymbol = "GOOG";
|
||||
public string underlyingSymbol2 = "AAPL";
|
||||
public override int DataPointCount { get; }
|
||||
|
||||
public override void Initialize(HistoryProviderInitializeParameters parameters)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IEnumerable<Slice> GetHistory(IEnumerable<HistoryRequest> requests, DateTimeZone sliceTimeZone)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
#pragma warning disable CS0618
|
||||
var tradeBar1 = new TradeBar(now, underlyingSymbol, 1, 1, 1, 1, 1, TimeSpan.FromDays(1));
|
||||
var tradeBar2 = new TradeBar(now, underlyingSymbol2, 3, 3, 3, 3, 3, TimeSpan.FromDays(1));
|
||||
var slice1 = new Slice(now, new List<BaseData> { tradeBar1, tradeBar2 },
|
||||
new TradeBars(now) { tradeBar1, tradeBar2 }, new QuoteBars(),
|
||||
new Ticks(), new OptionChains(),
|
||||
new FuturesChains(), new Splits(),
|
||||
new Dividends(now), new Delistings(),
|
||||
new SymbolChangedEvents(), new MarginInterestRates(), now);
|
||||
var tradeBar1_2 = new TradeBar(now, underlyingSymbol, 2, 2, 2, 2, 2, TimeSpan.FromDays(1));
|
||||
#pragma warning restore CS0618
|
||||
var slice2 = new Slice(now, new List<BaseData> { tradeBar1_2 },
|
||||
new TradeBars(now) { tradeBar1_2 }, new QuoteBars(),
|
||||
new Ticks(), new OptionChains(),
|
||||
new FuturesChains(), new Splits(),
|
||||
new Dividends(now), new Delistings(),
|
||||
new SymbolChangedEvents(), new MarginInterestRates(), now);
|
||||
return new[] { slice1, slice2 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user