1480 lines
59 KiB
C#
1480 lines
59 KiB
C#
/*
|
|
* 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 NodaTime;
|
|
using NUnit.Framework;
|
|
using Python.Runtime;
|
|
using QuantConnect.Data;
|
|
using QuantConnect.Data.Custom;
|
|
using QuantConnect.Data.Custom.IconicTypes;
|
|
using QuantConnect.Data.Market;
|
|
using QuantConnect.Indicators;
|
|
using QuantConnect.Python;
|
|
|
|
namespace QuantConnect.Tests.Common.Data
|
|
{
|
|
[TestFixture]
|
|
public class SliceTests
|
|
{
|
|
private readonly DateTime _dataTime = DateTime.UtcNow;
|
|
|
|
[Test]
|
|
public void AccessesByDataType()
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
var tradeBar = new TradeBar { Symbol = Symbols.SPY, Time = now };
|
|
var unlinkedData = new UnlinkedData { Symbol = Symbols.SPY, Time = now };
|
|
var quoteBar = new QuoteBar { Symbol = Symbols.SPY, Time = now };
|
|
var tick = new Tick(now, Symbols.SPY, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
var openInterest = new OpenInterest(now, Symbols.SPY, 1);
|
|
var split = new Split(Symbols.SPY, now, 1, 1, SplitType.SplitOccurred);
|
|
var delisting = new Delisting(Symbols.SPY, now, 1, DelistingType.Delisted);
|
|
var marginInterest = new MarginInterestRate { Symbol = Symbols.SPY, Time = now, InterestRate = 0.08m };
|
|
|
|
var slice = new Slice(now, new BaseData[] { quoteBar, tradeBar, unlinkedData, tick, split, delisting, openInterest, marginInterest }, now);
|
|
|
|
Assert.AreEqual(slice.Get(typeof(TradeBar))[Symbols.SPY], tradeBar);
|
|
Assert.AreEqual(slice.Get(typeof(UnlinkedData))[Symbols.SPY], unlinkedData);
|
|
Assert.AreEqual(slice.Get(typeof(QuoteBar))[Symbols.SPY], quoteBar);
|
|
Assert.AreEqual(slice.Get(typeof(Tick))[Symbols.SPY], tick);
|
|
Assert.AreEqual(slice.Get(typeof(Split))[Symbols.SPY], split);
|
|
Assert.AreEqual(slice.Get(typeof(Delisting))[Symbols.SPY], delisting);
|
|
Assert.AreEqual(slice.Get(typeof(OpenInterest))[Symbols.SPY], openInterest);
|
|
Assert.AreEqual(slice.Get(typeof(MarginInterestRate))[Symbols.SPY], marginInterest);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesByDataTypeAndSymbol()
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
var tradeBar = new TradeBar { Symbol = Symbols.SPY, Time = now };
|
|
var unlinkedData = new UnlinkedData { Symbol = Symbols.SPY, Time = now };
|
|
var quoteBar = new QuoteBar { Symbol = Symbols.SPY, Time = now };
|
|
var tick = new Tick(now, Symbols.SPY, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
var openInterest = new OpenInterest(now, Symbols.SPY, 1);
|
|
var split = new Split(Symbols.SPY, now, 1, 1, SplitType.SplitOccurred);
|
|
var delisting = new Delisting(Symbols.SPY, now, 1, DelistingType.Delisted);
|
|
var marginInterest = new MarginInterestRate { Symbol = Symbols.SPY, Time = now, InterestRate = 0.08m };
|
|
|
|
var slice = new Slice(now, new BaseData[] { quoteBar, tradeBar, unlinkedData, tick, split, delisting, openInterest, marginInterest }, now);
|
|
|
|
{
|
|
Assert.IsTrue(slice.TryGet<TradeBar>(Symbols.SPY, out var foundTradeBar));
|
|
Assert.AreEqual(foundTradeBar, tradeBar);
|
|
Assert.IsTrue(slice.TryGet<UnlinkedData>(Symbols.SPY, out var foundUnlinkedData));
|
|
Assert.AreEqual(foundUnlinkedData, unlinkedData);
|
|
Assert.IsTrue(slice.TryGet<QuoteBar>(Symbols.SPY, out var foundQuoteBar));
|
|
Assert.AreEqual(foundQuoteBar, quoteBar);
|
|
Assert.IsTrue(slice.TryGet<Tick>(Symbols.SPY, out var foundTick));
|
|
Assert.AreEqual(foundTick, tick);
|
|
Assert.IsTrue(slice.TryGet<Split>(Symbols.SPY, out var foundSplit));
|
|
Assert.AreEqual(foundSplit, split);
|
|
Assert.IsTrue(slice.TryGet<Delisting>(Symbols.SPY, out var foundDelisting));
|
|
Assert.AreEqual(foundDelisting, delisting);
|
|
Assert.IsTrue(slice.TryGet<OpenInterest>(Symbols.SPY, out var foundOpenInterest));
|
|
Assert.AreEqual(foundOpenInterest, openInterest);
|
|
Assert.IsTrue(slice.TryGet<MarginInterestRate>(Symbols.SPY, out var foundMarginInterest));
|
|
Assert.AreEqual(foundMarginInterest, marginInterest);
|
|
|
|
Assert.IsFalse(slice.TryGet<TradeBar>(Symbols.AAPL, out _));
|
|
}
|
|
|
|
{
|
|
Assert.IsTrue(slice.TryGet(typeof(TradeBar), Symbols.SPY, out var foundTradeBar));
|
|
Assert.AreEqual(foundTradeBar, tradeBar);
|
|
Assert.IsTrue(slice.TryGet(typeof(UnlinkedData), Symbols.SPY, out var foundUnlinkedData));
|
|
Assert.AreEqual(foundUnlinkedData, unlinkedData);
|
|
Assert.IsTrue(slice.TryGet(typeof(QuoteBar), Symbols.SPY, out var foundQuoteBar));
|
|
Assert.AreEqual(foundQuoteBar, quoteBar);
|
|
Assert.IsTrue(slice.TryGet(typeof(Tick), Symbols.SPY, out var foundTick));
|
|
Assert.AreEqual(foundTick, tick);
|
|
Assert.IsTrue(slice.TryGet(typeof(Split), Symbols.SPY, out var foundSplit));
|
|
Assert.AreEqual(foundSplit, split);
|
|
Assert.IsTrue(slice.TryGet(typeof(Delisting), Symbols.SPY, out var foundDelisting));
|
|
Assert.AreEqual(foundDelisting, delisting);
|
|
Assert.IsTrue(slice.TryGet(typeof(OpenInterest), Symbols.SPY, out var foundOpenInterest));
|
|
Assert.AreEqual(foundOpenInterest, openInterest);
|
|
Assert.IsTrue(slice.TryGet(typeof(MarginInterestRate), Symbols.SPY, out var foundMarginInterest));
|
|
Assert.AreEqual(foundMarginInterest, marginInterest);
|
|
|
|
Assert.IsFalse(slice.TryGet(typeof(TradeBar), Symbols.AAPL, out _));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesBaseBySymbol()
|
|
{
|
|
IndicatorDataPoint tick = new IndicatorDataPoint(Symbols.SPY, DateTime.Now, 1);
|
|
Slice slice = new Slice(DateTime.Now, new[] { tick }, DateTime.Now);
|
|
|
|
IndicatorDataPoint data = slice[tick.Symbol];
|
|
|
|
Assert.AreEqual(tick, data);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTradeBarBySymbol()
|
|
{
|
|
TradeBar tradeBar = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
Slice slice = new Slice(DateTime.Now, new[] { tradeBar }, DateTime.Now);
|
|
|
|
TradeBar data = slice[tradeBar.Symbol];
|
|
|
|
Assert.AreEqual(tradeBar, data);
|
|
}
|
|
|
|
[Test]
|
|
public void EquitiesIgnoreQuoteBars()
|
|
{
|
|
var quoteBar = new QuoteBar { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
var slice = new Slice(DateTime.Now, new[] { quoteBar }, DateTime.Now);
|
|
|
|
Assert.IsFalse(slice.HasData);
|
|
Assert.IsTrue(slice.ToList().Count == 0);
|
|
Assert.IsFalse(slice.ContainsKey(Symbols.SPY));
|
|
Assert.Throws<KeyNotFoundException>(() => { var data = slice[Symbols.SPY]; });
|
|
Assert.AreEqual(0, slice.Count);
|
|
|
|
var tickQuoteBar = new Tick { Symbol = Symbols.SPY, Time = DateTime.Now, TickType = TickType.Quote };
|
|
slice = new Slice(DateTime.Now, new[] { tickQuoteBar }, DateTime.Now);
|
|
|
|
Assert.IsFalse(slice.HasData);
|
|
Assert.IsTrue(slice.ToList().Count == 0);
|
|
Assert.IsFalse(slice.ContainsKey(Symbols.SPY));
|
|
Assert.Throws<KeyNotFoundException>(() => { var data = slice[Symbols.SPY]; });
|
|
Assert.AreEqual(0, slice.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTradeBarCollection()
|
|
{
|
|
TradeBar tradeBar1 = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
TradeBar tradeBar2 = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now };
|
|
Slice slice = new Slice(DateTime.Now, new[] { tradeBar1, tradeBar2 }, DateTime.Now);
|
|
|
|
TradeBars tradeBars = slice.Bars;
|
|
Assert.AreEqual(2, tradeBars.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTicksBySymbol()
|
|
{
|
|
Tick tick1 = new Tick { Time = DateTime.Now, Symbol = Symbols.SPY, Value = 1m, Quantity = 2m };
|
|
Tick tick2 = new Tick { Time = DateTime.Now, Symbol = Symbols.SPY, Value = 1.1m, Quantity = 2.1m };
|
|
Slice slice = new Slice(DateTime.Now, new[] { tick1, tick2 }, DateTime.Now);
|
|
|
|
List<Tick> data = slice[tick1.Symbol];
|
|
Assert.IsInstanceOf(typeof(List<Tick>), data);
|
|
Assert.AreEqual(2, data.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTicksCollection()
|
|
{
|
|
Tick tick1 = new Tick { Time = DateTime.Now, Symbol = Symbols.SPY, Value = 1, Quantity = 2 };
|
|
Tick tick2 = new Tick { Time = DateTime.Now, Symbol = Symbols.SPY, Value = 1.1m, Quantity = 2.1m };
|
|
Tick tick3 = new Tick { Time = DateTime.Now, Symbol = Symbols.AAPL, Value = 1, Quantity = 2 };
|
|
Tick tick4 = new Tick { Time = DateTime.Now, Symbol = Symbols.AAPL, Value = 1.1m, Quantity = 2.1m };
|
|
Slice slice = new Slice(DateTime.Now, new[] { tick1, tick2, tick3, tick4 }, DateTime.Now);
|
|
|
|
Ticks ticks = slice.Ticks;
|
|
Assert.AreEqual(2, ticks.Count);
|
|
Assert.AreEqual(2, ticks[Symbols.SPY].Count);
|
|
Assert.AreEqual(2, ticks[Symbols.AAPL].Count);
|
|
}
|
|
|
|
[Test]
|
|
public void DifferentCollectionsAreCorrectlyGeneratedSameSymbol()
|
|
{
|
|
var quoteBar = new QuoteBar(DateTime.Now, Symbols.SPY,
|
|
new Bar(3100, 3100, 3100, 3100), 0,
|
|
new Bar(3101, 3101, 3101, 3101), 0,
|
|
Time.OneMinute);
|
|
var tradeBar = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
var slice = new Slice(DateTime.Now, new BaseData[] { quoteBar, tradeBar }, DateTime.Now);
|
|
|
|
Assert.AreEqual(1, slice.QuoteBars.Count);
|
|
Assert.AreEqual(1, slice.Bars.Count);
|
|
|
|
Assert.AreEqual(1, slice.Get<QuoteBar>().Count);
|
|
Assert.AreEqual(1, slice.Get<TradeBar>().Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesCustomGenericallyByTypeOtherTypesPresent()
|
|
{
|
|
var tradeBar = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
var slice = new Slice(DateTime.Now, new BaseData[] { unlinkedDataSpy, tradeBar }, DateTime.Now);
|
|
|
|
var unlinkedData = slice.Get<UnlinkedData>();
|
|
Assert.AreEqual(1, unlinkedData.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesCustomGenericallyByType()
|
|
{
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataSpy, unlinkedDataAapl }, DateTime.Now);
|
|
|
|
var unlinkedData = slice.Get<UnlinkedData>();
|
|
Assert.AreEqual(2, unlinkedData.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTickGenericallyByType()
|
|
{
|
|
Tick TickSpy = new Tick { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
Tick TickAapl = new Tick { Symbol = Symbols.AAPL, Time = DateTime.Now };
|
|
Slice slice = new Slice(DateTime.Now, new[] { TickSpy, TickAapl }, DateTime.Now);
|
|
|
|
DataDictionary<Tick> TickData = slice.Get<Tick>();
|
|
Assert.AreEqual(2, TickData.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTradeBarGenericallyByType()
|
|
{
|
|
TradeBar TradeBarSpy = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
TradeBar TradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now };
|
|
Slice slice = new Slice(DateTime.Now, new[] { TradeBarSpy, TradeBarAapl }, DateTime.Now);
|
|
|
|
DataDictionary<TradeBar> TradeBarData = slice.Get<TradeBar>();
|
|
Assert.AreEqual(2, TradeBarData.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesGenericallyByTypeAndSymbol()
|
|
{
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataSpy, unlinkedDataAapl }, DateTime.Now);
|
|
|
|
var unlinkedData = slice.Get<UnlinkedData>(Symbols.SPY);
|
|
Assert.AreEqual(unlinkedDataSpy, unlinkedData);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeSlice()
|
|
{
|
|
var tradeBar1 = new TradeBar { Symbol = Symbols.SPY, Time = _dataTime };
|
|
var tradeBar2 = new TradeBar { Symbol = Symbols.AAPL, Time = _dataTime, Open = 23 };
|
|
var quoteBar1 = new QuoteBar { Symbol = Symbols.SPY, Time = _dataTime };
|
|
var tick1 = new Tick(_dataTime, Symbols.SPY, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
var split1 = new Split(Symbols.SPY, _dataTime, 1, 1, SplitType.SplitOccurred);
|
|
var dividend1 = new Dividend(Symbols.SPY, _dataTime, 1, 1);
|
|
var delisting1 = new Delisting(Symbols.SPY, _dataTime, 1, DelistingType.Delisted);
|
|
var symbolChangedEvent1 = new SymbolChangedEvent(Symbols.SPY, _dataTime, "SPY", "SP");
|
|
var marginInterestRate1 = new MarginInterestRate { Time = _dataTime, Symbol = Symbols.SPY, InterestRate = 8 };
|
|
var slice1 = new Slice(_dataTime, new BaseData[] { tradeBar1, tradeBar2,
|
|
quoteBar1, tick1, split1, dividend1, delisting1, symbolChangedEvent1, marginInterestRate1
|
|
}, _dataTime);
|
|
|
|
var tradeBar3 = new TradeBar { Symbol = Symbols.AAPL, Time = _dataTime, Open = 24 };
|
|
var tradeBar4 = new TradeBar { Symbol = Symbols.SBIN, Time = _dataTime };
|
|
var tradeBar3_4 = new TradeBar { Symbol = Symbols.BTCEUR, Time = _dataTime };
|
|
var quoteBar2 = new QuoteBar { Symbol = Symbols.SBIN, Time = _dataTime };
|
|
var tick2 = new Tick(_dataTime, Symbols.SBIN, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
var split2 = new Split(Symbols.SBIN, _dataTime, 1, 1, SplitType.SplitOccurred);
|
|
var dividend2 = new Dividend(Symbols.SBIN, _dataTime, 1, 1);
|
|
var delisting2 = new Delisting(Symbols.SBIN, _dataTime, 1, DelistingType.Delisted);
|
|
var symbolChangedEvent2 = new SymbolChangedEvent(Symbols.SBIN, _dataTime, "SBIN", "BIN");
|
|
var marginInterestRate2 = new MarginInterestRate { Time = _dataTime, Symbol = Symbols.SBIN, InterestRate = 18 };
|
|
var slice2 = new Slice(_dataTime, new BaseData[] { tradeBar3, tradeBar4, tradeBar3_4,
|
|
quoteBar2, tick2, split2, dividend2, delisting2, symbolChangedEvent2, marginInterestRate2
|
|
}, _dataTime);
|
|
|
|
slice1.MergeSlice(slice2);
|
|
Assert.AreEqual(4, slice1.Bars.Count);
|
|
Assert.AreEqual(2, slice1.QuoteBars.Count);
|
|
Assert.AreEqual(2, slice1.Ticks.Count);
|
|
Assert.AreEqual(2, slice1.Splits.Count);
|
|
Assert.AreEqual(2, slice1.Dividends.Count);
|
|
Assert.AreEqual(2, slice1.Delistings.Count);
|
|
Assert.AreEqual(2, slice1.SymbolChangedEvents.Count);
|
|
Assert.AreEqual(2, slice1.MarginInterestRates.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void CheckMergeUpdatePrivateAttributes()
|
|
{
|
|
var tradeBar0 = new TradeBar { Symbol = Symbols.BTCUSD, Time = _dataTime };
|
|
var slice1 = new Slice(_dataTime, new BaseData[] { tradeBar0 }, _dataTime);
|
|
var tradeBar1 = new TradeBar { Symbol = Symbols.SPY, Time = _dataTime };
|
|
var tradeBar2 = new TradeBar { Symbol = Symbols.AAPL, Time = _dataTime, Open = 23 };
|
|
var slice2 = new Slice(_dataTime, new BaseData[] { tradeBar1, tradeBar2 }, _dataTime);
|
|
|
|
slice1.MergeSlice(slice2);
|
|
// Check private _data is updated
|
|
Assert.AreEqual(3, slice1.Values.Count);
|
|
|
|
var tradeBar3 = new TradeBar { Symbol = Symbols.AAPL, Time = _dataTime, Open = 24 };
|
|
var tradeBar4 = new TradeBar { Symbol = Symbols.SBIN, Time = _dataTime };
|
|
var tradeBar3_4 = new TradeBar { Symbol = Symbols.BTCEUR, Time = _dataTime };
|
|
var slice3 = new Slice(_dataTime, new BaseData[] { tradeBar3, tradeBar4, tradeBar3_4 }, _dataTime);
|
|
|
|
slice1.MergeSlice(slice3);
|
|
|
|
// Should use first non Null value
|
|
var testTradeBar = (TradeBar)slice1.Values.Where(datum => datum.DataType == MarketDataType.TradeBar && datum.Symbol.Value == "AAPL").Single();
|
|
Assert.AreEqual(23, testTradeBar.Open);
|
|
|
|
// Check private _rawDataList is updated
|
|
Assert.AreEqual(5, slice1.Values.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeTicks()
|
|
{
|
|
var tradeBar1 = new TradeBar { Symbol = Symbols.SPY, Time = _dataTime };
|
|
var tick1 = new Tick(_dataTime, Symbols.SPY, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
var slice1 = new Slice(_dataTime, new BaseData[] { tradeBar1, tick1 }, _dataTime);
|
|
//var Use List<tick>
|
|
var ticks = new Ticks { { Symbols.MSFT, new List<Tick> { tick1 } } };
|
|
var slice2 = new Slice(_dataTime, new List<BaseData>(), null, null, ticks, null, null, null, null, null, null, null, _dataTime);
|
|
slice1.MergeSlice(slice2);
|
|
Assert.AreEqual(2, slice1.Ticks.Count);
|
|
|
|
// Should merge only when different
|
|
var tick2 = new Tick(_dataTime, Symbols.MSFT, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
var slice3 = new Slice(_dataTime, new BaseData[] { tradeBar1, tick2 }, _dataTime);
|
|
slice2.MergeSlice(slice3);
|
|
Assert.AreEqual(1, slice2.Ticks.Count);
|
|
}
|
|
|
|
[TestCase(null)]
|
|
[TestCase("")]
|
|
public void AccessingTicksParsedSaleConditinoDoesNotThrow(string saleCondition)
|
|
{
|
|
var tick1 = new Tick(_dataTime, Symbols.SPY, 1.1m, 2.1m) { TickType = TickType.Trade };
|
|
tick1.SaleCondition = saleCondition;
|
|
Assert.DoesNotThrow(() => tick1.ParsedSaleCondition.ToString());
|
|
}
|
|
|
|
[Test]
|
|
public void MergeOptionsAndFuturesChain()
|
|
{
|
|
// Merge optionChains and FutureChains
|
|
var optionChain1 = new OptionChains();
|
|
var optionChain2 = new OptionChains();
|
|
optionChain1.Add(Symbols.SPY, new OptionChain(Symbols.SPY, _dataTime));
|
|
optionChain2.Add(Symbols.AAPL, new OptionChain(Symbols.SPY, _dataTime));
|
|
var futuresChain1 = new FuturesChains();
|
|
var futuresChain2 = new FuturesChains();
|
|
futuresChain1.Add(Symbols.SPY, new FuturesChain(Symbols.SPY, _dataTime));
|
|
futuresChain2.Add(Symbols.AAPL, new FuturesChain(Symbols.SPY, _dataTime));
|
|
var slice4 = new Slice(_dataTime, new List<BaseData>(),
|
|
new TradeBars(_dataTime), new QuoteBars(),
|
|
new Ticks(), optionChain1,
|
|
futuresChain1, new Splits(),
|
|
new Dividends(_dataTime), new Delistings(),
|
|
new SymbolChangedEvents(), new MarginInterestRates(), _dataTime);
|
|
var slice5 = new Slice(_dataTime, new List<BaseData>(),
|
|
new TradeBars(_dataTime), new QuoteBars(),
|
|
new Ticks(), optionChain2,
|
|
futuresChain2, new Splits(),
|
|
new Dividends(_dataTime), new Delistings(),
|
|
new SymbolChangedEvents(), new MarginInterestRates(), _dataTime);
|
|
slice4.MergeSlice(slice5);
|
|
Assert.AreEqual(2, slice4.OptionChains.Count);
|
|
Assert.AreEqual(2, slice4.FutureChains.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void MergeCustomData()
|
|
{
|
|
var tradeBar1 = new TradeBar { Symbol = Symbols.SPY, Time = _dataTime };
|
|
var tradeBar2 = new TradeBar { Symbol = Symbols.AAPL, Time = _dataTime, Open = 23 };
|
|
var custom1 = new FxcmVolume { DataType = MarketDataType.Base, Symbol = Symbols.MSFT };
|
|
var custom2 = new FxcmVolume { DataType = MarketDataType.Base, Symbol = Symbols.SBIN };
|
|
var custom3 = new FxcmVolume { DataType = MarketDataType.Base, Symbol = Symbols.MSFT };
|
|
var custom4 = new FxcmVolume { DataType = MarketDataType.Base, Symbol = Symbols.SBIN };
|
|
var slice6 = new Slice(_dataTime, new BaseData[] { custom1, custom2, custom3, tradeBar2 }, _dataTime);
|
|
var slice5 = new Slice(_dataTime, new BaseData[] { tradeBar1, custom4 }, _dataTime);
|
|
slice5.MergeSlice(slice6);
|
|
Assert.AreEqual(4, slice5.Values.Count);
|
|
Assert.AreEqual(2, slice5.Values.Where(x => x.DataType == MarketDataType.Base).Count());
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetCustomData()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(UnlinkedData)
|
|
return data").GetAttr("Test");
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataSpy, unlinkedDataAapl }, DateTime.Now);
|
|
|
|
var data = test(slice);
|
|
Assert.AreEqual(2, (int)data.Count);
|
|
Assert.AreEqual(10, (int)data[Symbols.SPY].Value);
|
|
Assert.AreEqual(11, (int)data[Symbols.AAPL].Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonCustomDataPyObjectValue()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic testModule = PyModule.FromString("testModule",
|
|
@"
|
|
|
|
from AlgorithmImports import *
|
|
|
|
class CustomDataTest(PythonData):
|
|
def Reader(self, config, line, date, isLiveMode):
|
|
result = CustomDataTest()
|
|
result.Symbol = config.Symbol
|
|
result.Value = 10
|
|
result[""TimeTest""] = datetime.strptime(""2022-05-05"", ""%Y-%m-%d"")
|
|
return result
|
|
|
|
def Test(slice, symbol):
|
|
data = slice.Get(CustomDataTest)
|
|
return data[symbol][""TimeTest""]");
|
|
var test = testModule.GetAttr("Test");
|
|
|
|
var type = Extensions.CreateType(testModule.GetAttr("CustomDataTest"));
|
|
var customDataTest = new PythonData(testModule.GetAttr("CustomDataTest")());
|
|
var config = new SubscriptionDataConfig(type, Symbols.SPY, Resolution.Daily, DateTimeZone.Utc,
|
|
DateTimeZone.Utc, false, false, false, isCustom: true);
|
|
var data1 = customDataTest.Reader(config, "something", DateTime.UtcNow, false);
|
|
|
|
var slice = new Slice(DateTime.UtcNow, new[] { data1 }, DateTime.UtcNow);
|
|
|
|
Assert.AreEqual(new DateTime(2022, 05, 05), (DateTime)test(slice, Symbols.SPY));
|
|
}
|
|
}
|
|
|
|
[TestCase("reader", "get_source", "get")]
|
|
[TestCase("Reader", "GetSource", "get")]
|
|
[TestCase("reader", "get_source", "Get")]
|
|
[TestCase("Reader", "GetSource", "Get")]
|
|
public void PythonGetPythonCustomData(string reader, string getSource, string get)
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic testModule = PyModule.FromString("testModule",
|
|
$@"
|
|
|
|
from AlgorithmImports import *
|
|
|
|
class CustomDataTest(PythonData):
|
|
def {reader}(self, config, line, date, isLiveMode):
|
|
result = CustomDataTest()
|
|
result.Symbol = config.Symbol
|
|
result.Value = 10
|
|
return result
|
|
def {getSource}(config, date, isLiveMode):
|
|
return None
|
|
|
|
class CustomDataTest2(PythonData):
|
|
def {reader}(self, config, line, date, isLiveMode):
|
|
result = CustomDataTest2()
|
|
result.Symbol = config.Symbol
|
|
result.Value = 11
|
|
return result
|
|
def {getSource}(config, date, isLiveMode):
|
|
return None
|
|
|
|
def Test(slice):
|
|
data = slice.{get}(CustomDataTest)
|
|
return data");
|
|
var test = testModule.GetAttr("Test");
|
|
|
|
var type = Extensions.CreateType(testModule.GetAttr("CustomDataTest"));
|
|
var customDataTest = new PythonData(testModule.GetAttr("CustomDataTest")());
|
|
var config = new SubscriptionDataConfig(type, Symbols.SPY, Resolution.Daily, DateTimeZone.Utc,
|
|
DateTimeZone.Utc, false, false, false, isCustom: true);
|
|
var data1 = customDataTest.Reader(config, "something", DateTime.UtcNow, false);
|
|
|
|
var customDataTest2 = new PythonData(testModule.GetAttr("CustomDataTest2")());
|
|
var config2 = new SubscriptionDataConfig(config, Extensions.CreateType(testModule.GetAttr("CustomDataTest2")));
|
|
var data2 = customDataTest2.Reader(config2, "something2", DateTime.UtcNow, false);
|
|
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.UtcNow, Value = 10 };
|
|
var slice = new Slice(DateTime.UtcNow, new[] { unlinkedDataSpy, data2, data1 }, DateTime.UtcNow);
|
|
|
|
var data = test(slice);
|
|
Assert.AreEqual(1, (int)data.Count);
|
|
Assert.AreEqual(10, (int)data[Symbols.SPY].Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonEnumerationWorks()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
for dataPoint in slice:
|
|
return dataPoint").GetAttr("Test");
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataAapl }, DateTime.Now);
|
|
|
|
var data = test(slice) as PyObject;
|
|
var keyValuePair = data.As<KeyValuePair<Symbol, BaseData>>();
|
|
Assert.IsNotNull(keyValuePair);
|
|
Assert.AreEqual(11, keyValuePair.Value.Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetBySymbolCustomData()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(UnlinkedData)
|
|
value = data[Symbols.AAPL].Value
|
|
if value != 11:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataSpy, unlinkedDataAapl }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetAndSymbolCustomData()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(UnlinkedData, Symbols.AAPL)
|
|
value = data.Value
|
|
if value != 11:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataSpy, unlinkedDataAapl }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetTradeBar()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(TradeBar)
|
|
return data").GetAttr("Test");
|
|
var TradeBarSpy = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 8 };
|
|
var TradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 9 };
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new BaseData[] { unlinkedDataSpy, TradeBarAapl, unlinkedDataAapl, TradeBarSpy }, DateTime.Now);
|
|
|
|
var data = test(slice);
|
|
Assert.AreEqual(2, (int)data.Count);
|
|
Assert.AreEqual(8, (int)data[Symbols.SPY].Value);
|
|
Assert.AreEqual(9, (int)data[Symbols.AAPL].Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetBySymbolOpenInterest()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(OpenInterest)
|
|
value = data[Symbols.AAPL].Value
|
|
if value != 33:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var now = DateTime.UtcNow;
|
|
var TradeBarSpy = new TradeBar { Symbol = Symbols.SPY, Time = now, Value = 8 };
|
|
var TradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = now, Value = 9 };
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = now, Value = 11 };
|
|
var openInterest = new OpenInterest(now, Symbols.AAPL, 33);
|
|
var slice = new Slice(now, new BaseData[] { unlinkedDataSpy, TradeBarAapl, unlinkedDataAapl, TradeBarSpy, openInterest }, now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetBySymbolTradeBar()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(TradeBar)
|
|
value = data[Symbols.AAPL].Value
|
|
if value != 9:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var TradeBarSpy = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 8 };
|
|
var TradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 9 };
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new BaseData[] { unlinkedDataSpy, TradeBarAapl, unlinkedDataAapl, TradeBarSpy }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetAndSymbolTradeBar()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(TradeBar, Symbols.AAPL)
|
|
value = data.Value
|
|
if value != 9:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var TradeBarSpy = new TradeBar { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 8 };
|
|
var TradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 9 };
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new BaseData[] { unlinkedDataSpy, TradeBarAapl, unlinkedDataAapl, TradeBarSpy }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetCustomData_Iterate_IndexedLinkedData()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Data.Custom.IconicTypes import *
|
|
from QuantConnect.Logging import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(IndexedLinkedData)
|
|
count = 0
|
|
for singleData in data:
|
|
Log.Trace(str(singleData))
|
|
count += 1
|
|
if count != 2:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var indexedLinkedDataSpy = new IndexedLinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var tradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 9 };
|
|
var indexedLinkedDataAapl = new IndexedLinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new BaseData[] { indexedLinkedDataSpy, tradeBarAapl, indexedLinkedDataAapl }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetCustomData_Iterate_IndexedLinkedData_Empty()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Data.Custom.IconicTypes import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(IndexedLinkedData)
|
|
for singleData in data:
|
|
raise Exception('Unexpected iteration')
|
|
for singleData in data.Values:
|
|
raise Exception('Unexpected iteration')
|
|
data = slice.Get(IndexedLinkedData)
|
|
for singleData in data:
|
|
raise Exception('Unexpected iteration')
|
|
for singleData in data.Values:
|
|
raise Exception('Unexpected iteration')").GetAttr("Test");
|
|
var tradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 9 };
|
|
var slice = new Slice(DateTime.Now, new List<BaseData> { tradeBarAapl }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonGetCustomData_Iterate()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
data = slice.Get(UnlinkedData)
|
|
count = 0
|
|
for singleData in data:
|
|
count += 1
|
|
if count != 2:
|
|
raise Exception('Unexpected value')").GetAttr("Test");
|
|
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var unlinkedDataAapl = new UnlinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
var slice = new Slice(DateTime.Now, new[] { unlinkedDataSpy, unlinkedDataAapl }, DateTime.Now);
|
|
|
|
Assert.DoesNotThrow(() => test(slice));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void EnumeratorDoesNotThrowWithTicks()
|
|
{
|
|
var slice = new Slice(DateTime.Now, new[]
|
|
{
|
|
new Tick {Time = DateTime.Now, Symbol = Symbols.SPY, Value = 1, Quantity = 2},
|
|
new Tick{Time = DateTime.Now, Symbol = Symbols.SPY, Value = 1.1m, Quantity = 2.1m},
|
|
new Tick{Time = DateTime.Now, Symbol = Symbols.AAPL, Value = 1, Quantity = 2},
|
|
new Tick{Time = DateTime.Now, Symbol = Symbols.AAPL, Value = 1.1m, Quantity = 2.1m}
|
|
}, DateTime.Now);
|
|
|
|
#pragma warning disable CA1829
|
|
Assert.AreEqual(4, slice.Count());
|
|
#pragma warning restore CA1829
|
|
}
|
|
|
|
[Test]
|
|
public void AccessesTradeBarAndQuoteBarForSameSymbol()
|
|
{
|
|
var tradeBar = new TradeBar(DateTime.Now, Symbols.BTCUSD,
|
|
3000, 3000, 3000, 3000, 100, Time.OneMinute);
|
|
|
|
var quoteBar = new QuoteBar(DateTime.Now, Symbols.BTCUSD,
|
|
new Bar(3100, 3100, 3100, 3100), 0,
|
|
new Bar(3101, 3101, 3101, 3101), 0,
|
|
Time.OneMinute);
|
|
|
|
var tradeBars = new TradeBars { { Symbols.BTCUSD, tradeBar } };
|
|
var quoteBars = new QuoteBars { { Symbols.BTCUSD, quoteBar } };
|
|
|
|
var slice = new Slice(DateTime.Now, new List<BaseData>() { tradeBar, quoteBar }, tradeBars, quoteBars, null, null, null, null, null, null, null, null, DateTime.Now);
|
|
|
|
var tradeBarData = slice.Get<TradeBar>();
|
|
Assert.AreEqual(1, tradeBarData.Count);
|
|
Assert.AreEqual(3000, tradeBarData[Symbols.BTCUSD].Close);
|
|
|
|
var quoteBarData = slice.Get<QuoteBar>();
|
|
Assert.AreEqual(1, quoteBarData.Count);
|
|
Assert.AreEqual(3100, quoteBarData[Symbols.BTCUSD].Bid.Close);
|
|
Assert.AreEqual(3101, quoteBarData[Symbols.BTCUSD].Ask.Close);
|
|
|
|
slice = new Slice(DateTime.Now, new BaseData[] { tradeBar, quoteBar }, DateTime.Now);
|
|
|
|
tradeBarData = slice.Get<TradeBar>();
|
|
Assert.AreEqual(1, tradeBarData.Count);
|
|
Assert.AreEqual(3000, tradeBarData[Symbols.BTCUSD].Close);
|
|
|
|
quoteBarData = slice.Get<QuoteBar>();
|
|
Assert.AreEqual(1, quoteBarData.Count);
|
|
Assert.AreEqual(3100, quoteBarData[Symbols.BTCUSD].Bid.Close);
|
|
Assert.AreEqual(3101, quoteBarData[Symbols.BTCUSD].Ask.Close);
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_clear()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
slice.clear()").GetAttr("Test");
|
|
|
|
Assert.That(() => test(GetSlice()),
|
|
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<InvalidOperationException>(),
|
|
"Slice is read-only: cannot clear the collection");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_popitem()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
slice.popitem()").GetAttr("Test");
|
|
|
|
Assert.That(() => test(GetSlice()),
|
|
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<NotSupportedException>(),
|
|
$"Slice is read-only: cannot pop the value for {Symbols.SPY} from the collection");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_pop()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
slice.pop(symbol)").GetAttr("Test");
|
|
|
|
Assert.That(() => test(GetSlice(), Symbols.SPY),
|
|
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<InvalidOperationException>(),
|
|
$"Slice is read-only: cannot pop the value for {Symbols.SPY} from the collection");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_pop_default()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol, default_value):
|
|
slice.pop(symbol, default_value)").GetAttr("Test");
|
|
|
|
Assert.That(() => test(GetSlice(), Symbols.SPY, null),
|
|
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<InvalidOperationException>(),
|
|
$"Slice is read-only: cannot pop the value for {Symbols.SPY} from the collection");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_update_fails()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
item = { symbol: 1 }
|
|
slice.update(item)").GetAttr("Test");
|
|
|
|
Assert.That(() => test(GetSlice(), Symbols.SPY),
|
|
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<InvalidOperationException>(),
|
|
"Slice is read-only: cannot update the collection");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_update_success()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol, bar):
|
|
item = { symbol: bar }
|
|
slice.Bars.update(item)").GetAttr("Test");
|
|
|
|
var expected = new TradeBar();
|
|
var pythonSlice = GetSlice();
|
|
Assert.DoesNotThrow(() => test(pythonSlice, Symbols.SPY, expected));
|
|
Assert.AreEqual(expected, pythonSlice.Bars[Symbols.SPY]);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_contains()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
AddReference(""QuantConnect.Tests"")
|
|
from QuantConnect.Tests.Common.Data import *
|
|
|
|
def Test(slice, symbol):
|
|
return symbol in slice").GetAttr("Test");
|
|
|
|
bool result = false;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
Assert.IsTrue(result);
|
|
|
|
result = false;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
Assert.IsTrue(result);
|
|
}
|
|
}
|
|
|
|
[Test, Ignore("Performance test")]
|
|
public void PythonSlice_performance()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
AddReference(""QuantConnect.Tests"")
|
|
from QuantConnect.Tests.Common.Data import *
|
|
|
|
def Test(slice, symbol):
|
|
msg = '__contains__'
|
|
|
|
if 'SPY' in slice:
|
|
msg += ' Py'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = 'SPY' in slice
|
|
span1 = (datetime.now()-now).total_seconds()
|
|
|
|
if slice.ContainsKey('SPY'):
|
|
msg += ' C#\n'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.ContainsKey('SPY')
|
|
span2 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += f'Py: {span1}\nC#: {span2}\nRatio: {span1/span2}'
|
|
|
|
msg += '\n\n__len__'
|
|
|
|
if len(slice) > 0:
|
|
msg += ' Py'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = len(slice)
|
|
span1 = (datetime.now()-now).total_seconds()
|
|
|
|
if slice.Count > 0:
|
|
msg += ' C#\n'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.Count
|
|
span2 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += f'Py: {span1}\nC#: {span2}\nRatio: {span1/span2}'
|
|
|
|
msg += '\n\nkeys()'
|
|
|
|
if len(slice.keys()) > 0:
|
|
msg += ' Py'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.keys()
|
|
span1 = (datetime.now()-now).total_seconds()
|
|
|
|
if len(slice.Keys) > 0:
|
|
msg += ' C#\n'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.Keys
|
|
span2 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += f'Py: {span1}\nC#: {span2}\nRatio: {span1/span2}'
|
|
|
|
msg += '\n\nvalues()'
|
|
|
|
if len(slice.values()) > 0:
|
|
msg += ' Py'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.values()
|
|
span1 = (datetime.now()-now).total_seconds()
|
|
|
|
if len(slice.Values) > 0:
|
|
msg += ' C#\n'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.Values
|
|
span2 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += f'Py: {span1}\nC#: {span2}\nRatio: {span1/span2}'
|
|
|
|
msg += '\n\nget()'
|
|
|
|
if slice.get(symbol):
|
|
msg += ' Py'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.get(symbol)
|
|
span1 = (datetime.now()-now).total_seconds()
|
|
|
|
dummy = None
|
|
if slice.TryGetValue(symbol, dummy):
|
|
msg += ' C#\n'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = slice.TryGetValue(symbol, dummy)
|
|
span2 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += f'Py: {span1}\nC#: {span2}\nRatio: {span1/span2}'
|
|
|
|
msg += '\n\nitems()'
|
|
|
|
if slice.items():
|
|
msg += ' Py'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = list(slice.items())
|
|
span1 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += ' C#\n'
|
|
now = datetime.now()
|
|
for i in range(0,1000000):
|
|
result = [x for x in slice]
|
|
span2 = (datetime.now()-now).total_seconds()
|
|
|
|
msg += f'Py: {span1}\nC#: {span2}\nRatio: {span1/span2}'
|
|
|
|
return msg").GetAttr("Test");
|
|
|
|
var message = string.Empty;
|
|
Assert.DoesNotThrow(() => message = test(GetSlice(), Symbols.SPY));
|
|
|
|
Assert.Ignore(message);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_len()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
AddReference(""QuantConnect.Tests"")
|
|
from QuantConnect.Tests.Common.Data import *
|
|
|
|
def Test(slice, symbol):
|
|
return len(slice)").GetAttr("Test");
|
|
|
|
var result = -1;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
Assert.AreEqual(2, result);
|
|
|
|
result = -1;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
Assert.AreEqual(2, result);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_copy()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
copy = slice.copy()
|
|
return ', '.join([f'{k}: {v.Value}' for k,v in copy.items()])").GetAttr("Test");
|
|
|
|
var result = string.Empty;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
Assert.AreEqual("AAPL R735QTJ8XC9X: 11.0, SPY R735QTJ8XC9X: 10.0", result);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_items()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
return ', '.join([f'{k}: {v.Value}' for k,v in slice.items()])").GetAttr("Test");
|
|
|
|
var result = string.Empty;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice()));
|
|
Assert.AreEqual("AAPL R735QTJ8XC9X: 11.0, SPY R735QTJ8XC9X: 10.0", result);
|
|
}
|
|
}
|
|
|
|
|
|
[Test]
|
|
public void PythonSlice_keys()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
return slice.keys()").GetAttr("Test");
|
|
|
|
var slice = GetSlice();
|
|
var result = new List<Symbol>();
|
|
Assert.DoesNotThrow(() => result = test(slice));
|
|
foreach (var key in slice.Keys)
|
|
{
|
|
Assert.IsTrue(result.Contains(key));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_values()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice):
|
|
return slice.values()").GetAttr("Test");
|
|
|
|
var slice = GetSlice();
|
|
var result = new List<BaseData>();
|
|
Assert.DoesNotThrow(() => result = test(slice));
|
|
foreach (var value in slice.Values)
|
|
{
|
|
Assert.IsTrue(result.Contains(value));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_fromkeys()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, keys):
|
|
newDict = slice.fromkeys(keys)
|
|
return ', '.join([f'{k}: {v.Value}' for k,v in newDict.items()])").GetAttr("Test");
|
|
|
|
var result = string.Empty;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), new[] { Symbols.SPY }));
|
|
Assert.AreEqual("SPY R735QTJ8XC9X: 10.0", result);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_fromkeys_default()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, keys, default_value):
|
|
newDict = slice.fromkeys(keys, default_value)
|
|
return ', '.join([f'{k}: {v.Value}' for k,v in newDict.items()])").GetAttr("Test");
|
|
|
|
var result = string.Empty;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), new[] { Symbols.EURUSD }, new Tick()));
|
|
Assert.AreEqual("EURUSD 8G: 0.0", result);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_get_success()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
return slice.get(symbol)").GetAttr("Test");
|
|
|
|
var pythonSlice = GetSlice();
|
|
dynamic expected = pythonSlice[Symbols.SPY];
|
|
PyObject result = null;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
BaseData actual;
|
|
Assert.IsTrue(result.TryConvert(out actual));
|
|
Assert.AreEqual(expected.Symbol, actual.Symbol);
|
|
Assert.AreEqual(expected.Value, actual.Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_get_default()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol, default_value):
|
|
return slice.get(symbol, default_value)").GetAttr("Test");
|
|
|
|
var pythonSlice = GetSlice();
|
|
var expected = new QuoteBar { Symbol = Symbols.EURUSD, Time = DateTime.Now, Value = 9 };
|
|
PyObject result = null;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.EURUSD, expected));
|
|
BaseData actual;
|
|
Assert.IsTrue(result.TryConvert(out actual));
|
|
Assert.AreEqual(expected.Symbol, actual.Symbol);
|
|
Assert.AreEqual(expected.Value, actual.Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_get_NoneIfKeyNotFound()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
return slice.get(symbol)").GetAttr("Test");
|
|
|
|
Assert.IsNull(test(GetSlice(), Symbols.EURUSD));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_setdefault_success()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
return slice.setdefault(symbol)").GetAttr("Test");
|
|
|
|
var pythonSlice = GetSlice();
|
|
dynamic expected = pythonSlice[Symbols.SPY];
|
|
PyObject result = null;
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY));
|
|
BaseData actual;
|
|
Assert.IsTrue(result.TryConvert(out actual));
|
|
Assert.AreEqual(expected.Symbol, actual.Symbol);
|
|
Assert.AreEqual(expected.Value, actual.Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_setdefault_default_success()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol, default_value):
|
|
return slice.setdefault(symbol, default_value)").GetAttr("Test");
|
|
|
|
var value = new Tick();
|
|
var pythonSlice = GetSlice();
|
|
dynamic expected = pythonSlice[Symbols.SPY];
|
|
PyObject result = null;
|
|
|
|
// Since SPY is found, no need to set the default. Therefore it does not throw.
|
|
Assert.DoesNotThrow(() => result = test(GetSlice(), Symbols.SPY, value));
|
|
BaseData actual;
|
|
Assert.IsTrue(result.TryConvert(out actual));
|
|
Assert.AreEqual(expected.Symbol, actual.Symbol);
|
|
Assert.AreEqual(expected.Value, actual.Value);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonSlice_setdefault_keynotfound()
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic test = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def Test(slice, symbol):
|
|
return slice.setdefault(symbol)").GetAttr("Test");
|
|
|
|
var symbol = Symbols.EURUSD;
|
|
Assert.That(() => test(GetSlice(), symbol),
|
|
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<KeyNotFoundException>(),
|
|
$"Slice is read-only: cannot set default value to for {symbol}");
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(PushThroughWorksWithDifferentTypesTestCases))]
|
|
public void PushThroughWorksWithDifferentTypes(Slice slice, Type dataType, decimal expectedValue)
|
|
{
|
|
decimal valuePushed = default;
|
|
|
|
var action = new Action<IBaseData>(data => { valuePushed = data.Value; });
|
|
|
|
var slices = new List<Slice>(){ slice };
|
|
|
|
slices.PushThrough(action, dataType);
|
|
Assert.AreEqual(expectedValue, valuePushed);
|
|
}
|
|
|
|
private Slice GetSlice()
|
|
{
|
|
SymbolCache.Clear();
|
|
var indexedLinkedDataSpy = new IndexedLinkedData { Symbol = Symbols.SPY, Time = DateTime.Now, Value = 10 };
|
|
var tradeBarAapl = new TradeBar { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 9 };
|
|
var indexedLinkedDataAapl = new IndexedLinkedData { Symbol = Symbols.AAPL, Time = DateTime.Now, Value = 11 };
|
|
return new Slice(DateTime.Now, new BaseData[] { indexedLinkedDataSpy, tradeBarAapl, indexedLinkedDataAapl }, DateTime.Now);
|
|
}
|
|
|
|
public static object[] PushThroughWorksWithDifferentTypesTestCases =
|
|
{
|
|
new object[] {new Slice(
|
|
new DateTime(2013, 10, 3),
|
|
new List<BaseData>(),
|
|
new TradeBars(),
|
|
new QuoteBars() { new QuoteBar() { Symbol = Symbols.IBM, Value = 100m } },
|
|
new Ticks(),
|
|
new OptionChains(),
|
|
new FuturesChains(),
|
|
new Splits(),
|
|
new Dividends(),
|
|
new Delistings(),
|
|
new SymbolChangedEvents(),
|
|
new MarginInterestRates(),
|
|
DateTime.UtcNow), typeof(QuoteBar), 100m},
|
|
new object[] {new Slice(
|
|
new DateTime(2013, 10, 3),
|
|
new List<BaseData>(),
|
|
new TradeBars() { new TradeBar() { Symbol = Symbols.IBM, Value = 100m } },
|
|
new QuoteBars(),
|
|
new Ticks(),
|
|
new OptionChains(),
|
|
new FuturesChains(),
|
|
new Splits(),
|
|
new Dividends(),
|
|
new Delistings(),
|
|
new SymbolChangedEvents(),
|
|
new MarginInterestRates(),
|
|
DateTime.UtcNow), typeof(TradeBar), 100m},
|
|
new object[] {new Slice(
|
|
new DateTime(2013, 10, 3),
|
|
new List<BaseData>(),
|
|
new TradeBars(),
|
|
new QuoteBars(),
|
|
new Ticks() { { Symbols.IBM, new Tick() { Value = 100m } } },
|
|
new OptionChains(),
|
|
new FuturesChains(),
|
|
new Splits(),
|
|
new Dividends(),
|
|
new Delistings(),
|
|
new SymbolChangedEvents(),
|
|
new MarginInterestRates(),
|
|
DateTime.UtcNow), typeof(Tick), 100m},
|
|
new object[] {new Slice(
|
|
new DateTime(2013, 10, 3),
|
|
new List<BaseData>() { new TradeBar() { Symbol = Symbols.IBM, Value = 100m } },
|
|
new TradeBars(),
|
|
new QuoteBars(),
|
|
new Ticks(),
|
|
new OptionChains(),
|
|
new FuturesChains(),
|
|
new Splits(),
|
|
new Dividends(),
|
|
new Delistings(),
|
|
new SymbolChangedEvents(),
|
|
new MarginInterestRates(),
|
|
DateTime.UtcNow), null, 100m},
|
|
new object[] {new Slice(
|
|
new DateTime(2013, 10, 3),
|
|
new List<BaseData>() { new CustomData() { Symbol = Symbols.IBM, Value = 100m } },
|
|
new TradeBars(),
|
|
new QuoteBars(),
|
|
new Ticks(),
|
|
new OptionChains(),
|
|
new FuturesChains(),
|
|
new Splits(),
|
|
new Dividends(),
|
|
new Delistings(),
|
|
new SymbolChangedEvents(),
|
|
new MarginInterestRates(),
|
|
DateTime.UtcNow), typeof(CustomData), 100m}
|
|
};
|
|
}
|
|
|
|
public class PublicArrayTest
|
|
{
|
|
public int[] items { get; set; }
|
|
|
|
public PublicArrayTest()
|
|
{
|
|
items = new int[5] { 0, 1, 2, 3, 4 };
|
|
}
|
|
}
|
|
|
|
public class CustomData: BaseData
|
|
{
|
|
}
|
|
}
|