Files
2026-07-13 13:02:50 +08:00

335 lines
14 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.IO;
using System.Text;
using NUnit.Framework;
using QuantConnect.Data;
using QuantConnect.Data.Market;
namespace QuantConnect.Tests.Common.Data.Market
{
[TestFixture]
public class QuoteBarTests
{
private QuoteBar _quoteBar;
[OneTimeSetUp]
public void Setup()
{
_quoteBar = new QuoteBar();
}
[Test]
public void DoesntGenerateCorruptedPricesIfBidOrAskAreMissing()
{
var bar = new QuoteBar();
bar.UpdateAsk(10, 15);
Assert.AreEqual(10, bar.Open);
Assert.AreEqual(10, bar.High);
Assert.AreEqual(10, bar.Low);
Assert.AreEqual(10, bar.Close);
bar = new QuoteBar();
bar.Ask = new Bar(11,11,11,11);
Assert.AreEqual(11, bar.Open);
Assert.AreEqual(11, bar.High);
Assert.AreEqual(11, bar.Low);
Assert.AreEqual(11, bar.Close);
}
[Test]
public void QuoteBarReader_CanParseMalformattedData_Successfully()
{
var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
// Neither a quote or a trade
var line = "14340000,1.10907,1.109075,1.108985,1.1090214400000,1.109005,1.109005,1.10884,1.10887";
var date = DateTime.MaxValue;
var isLiveMode = false;
var quoteBar = new QuoteBar();
var parsedQuoteBar = (QuoteBar)quoteBar.Reader(config, line, date, isLiveMode);
Assert.AreEqual(parsedQuoteBar.Symbol, Symbols.SPY);
Assert.AreEqual(parsedQuoteBar.Ask.Open, 0);
Assert.AreEqual(parsedQuoteBar.Ask.High, 0);
Assert.AreEqual(parsedQuoteBar.Ask.Low, 0);
Assert.AreEqual(parsedQuoteBar.Ask.Close, 0);
Assert.AreEqual(parsedQuoteBar.Bid.Open, 0);
Assert.AreEqual(parsedQuoteBar.Bid.High, 0);
Assert.AreEqual(parsedQuoteBar.Bid.Low, 0);
Assert.AreEqual(parsedQuoteBar.Bid.Close, 0);
}
[Test]
public void QuoteBarReader_CanParseQuoteBar_Successfully()
{
var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
// Neither a quote or a trade
var line = "14340000,11090,11090,11089,11090,100,11090,11088,11088,11090,10000";
var date = DateTime.MaxValue;
var isLiveMode = false;
var quoteBar = new QuoteBar();
var parsedQuoteBar = (QuoteBar)quoteBar.Reader(config, line, date, isLiveMode);
Assert.AreEqual(parsedQuoteBar.Symbol, Symbols.SPY);
Assert.AreEqual(parsedQuoteBar.Bid.Open, 1.1090);
Assert.AreEqual(parsedQuoteBar.Bid.High, 1.1090);
Assert.AreEqual(parsedQuoteBar.Bid.Low, 1.1089);
Assert.AreEqual(parsedQuoteBar.Bid.Close, 1.1090);
Assert.AreEqual(parsedQuoteBar.Ask.Open, 1.10900);
Assert.AreEqual(parsedQuoteBar.Ask.High, 1.1088);
Assert.AreEqual(parsedQuoteBar.Ask.Low, 1.1088);
Assert.AreEqual(parsedQuoteBar.Ask.Close, 1.1090);
}
[Test]
public void QuoteBar_CanParseEquity_Successfully()
{
var config = new SubscriptionDataConfig(typeof(QuoteBar), Symbols.SPY, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
var line = "14340000,10000,20000,30000,40000,0,50000,60000,70000,80000,1";
var quoteBar = _quoteBar.ParseEquity(config, line, DateTime.MinValue);
Assert.AreEqual(quoteBar.Bid.Open, 1m);
Assert.AreEqual(quoteBar.Bid.High, 2m);
Assert.AreEqual(quoteBar.Bid.Low, 3m);
Assert.AreEqual(quoteBar.Bid.Close, 4m);
Assert.AreEqual(quoteBar.LastBidSize, 0m);
Assert.AreEqual(quoteBar.Ask.Open, 5m);
Assert.AreEqual(quoteBar.Ask.High, 6m);
Assert.AreEqual(quoteBar.Ask.Low, 7m);
Assert.AreEqual(quoteBar.Ask.Close, 8m);
Assert.AreEqual(quoteBar.LastAskSize, 1m);
}
[Test]
public void QuoteBar_CanParseForex_Successfully()
{
var config = new SubscriptionDataConfig(typeof(QuoteBar), Symbols.EURUSD, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
var line = "14340000,1,2,3,4,0,5,6,7,8,1";
var quoteBar = _quoteBar.ParseForex(config, line, DateTime.MinValue);
Assert.AreEqual(quoteBar.Bid.Open, 1m);
Assert.AreEqual(quoteBar.Bid.High, 2m);
Assert.AreEqual(quoteBar.Bid.Low, 3m);
Assert.AreEqual(quoteBar.Bid.Close, 4m);
Assert.AreEqual(quoteBar.LastBidSize, 0m);
Assert.AreEqual(quoteBar.Ask.Open, 5m);
Assert.AreEqual(quoteBar.Ask.High, 6m);
Assert.AreEqual(quoteBar.Ask.Low, 7m);
Assert.AreEqual(quoteBar.Ask.Close, 8m);
Assert.AreEqual(quoteBar.LastAskSize, 1m);
}
[Test]
public void QuoteBar_CanParseCfd_Successfully()
{
var config = new SubscriptionDataConfig(typeof(QuoteBar), Symbols.DE10YBEUR, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
var line = "14340000,1,2,3,4,0,5,6,7,8,1";
var quoteBar = _quoteBar.ParseCfd(config, line, DateTime.MinValue);
Assert.AreEqual(quoteBar.Bid.Open, 1m);
Assert.AreEqual(quoteBar.Bid.High, 2m);
Assert.AreEqual(quoteBar.Bid.Low, 3m);
Assert.AreEqual(quoteBar.Bid.Close, 4m);
Assert.AreEqual(quoteBar.LastBidSize, 0m);
Assert.AreEqual(quoteBar.Ask.Open, 5m);
Assert.AreEqual(quoteBar.Ask.High, 6m);
Assert.AreEqual(quoteBar.Ask.Low, 7m);
Assert.AreEqual(quoteBar.Ask.Close, 8m);
Assert.AreEqual(quoteBar.LastAskSize, 1m);
}
[Test]
public void QuoteBar_CanParseOption_Successfully()
{
var config = new SubscriptionDataConfig(typeof(QuoteBar), Symbols.SPY_C_192_Feb19_2016, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
var line = "14340000,10000,20000,30000,40000,0,50000,60000,70000,80000,1";
var quoteBar = _quoteBar.ParseOption(config, line, DateTime.MinValue);
Assert.AreEqual(quoteBar.Bid.Open, 1m);
Assert.AreEqual(quoteBar.Bid.High, 2m);
Assert.AreEqual(quoteBar.Bid.Low, 3m);
Assert.AreEqual(quoteBar.Bid.Close, 4m);
Assert.AreEqual(quoteBar.LastBidSize, 0m);
Assert.AreEqual(quoteBar.Ask.Open, 5m);
Assert.AreEqual(quoteBar.Ask.High, 6m);
Assert.AreEqual(quoteBar.Ask.Low, 7m);
Assert.AreEqual(quoteBar.Ask.Close, 8m);
Assert.AreEqual(quoteBar.LastAskSize, 1m);
}
[Test]
public void QuoteBar_CanParseFuture_Successfully()
{
var config = new SubscriptionDataConfig(typeof(QuoteBar), Symbols.Fut_SPY_Feb19_2016, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
var line = "14340000,1,2,3,4,0,5,6,7,8,1";
var quoteBar = _quoteBar.ParseFuture(config, line, DateTime.MinValue);
Assert.AreEqual(quoteBar.Bid.Open, 1m);
Assert.AreEqual(quoteBar.Bid.High, 2m);
Assert.AreEqual(quoteBar.Bid.Low, 3m);
Assert.AreEqual(quoteBar.Bid.Close, 4m);
Assert.AreEqual(quoteBar.LastBidSize, 0m);
Assert.AreEqual(quoteBar.Ask.Open, 5m);
Assert.AreEqual(quoteBar.Ask.High, 6m);
Assert.AreEqual(quoteBar.Ask.Low, 7m);
Assert.AreEqual(quoteBar.Ask.Close, 8m);
Assert.AreEqual(quoteBar.LastAskSize, 1m);
}
[Test]
public void QuoteBarParseScalesOptionsWithEquityUnderlying()
{
var factory = new QuoteBar();
var underlying = Symbol.Create("SPY", SecurityType.Equity, QuantConnect.Market.USA);
var optionSymbol = Symbol.CreateOption(
underlying,
QuantConnect.Market.CME,
OptionStyle.American,
OptionRight.Put,
4200m,
SecurityIdentifier.DefaultDate);
var config = new SubscriptionDataConfig(
typeof(QuoteBar),
optionSymbol,
Resolution.Minute,
TimeZones.Chicago,
TimeZones.Chicago,
true,
false,
false,
false,
TickType.Quote,
true,
DataNormalizationMode.Raw);
var quoteLine = "40560000,10000,15000,10000,15000,90,10000,15000,10000,15000,100";
using var stream = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(quoteLine)));
var quoteBarFromLine = (QuoteBar)factory.Reader(config, quoteLine, new DateTime(2020, 9, 22), false);
var quoteBarFromStream = (QuoteBar)factory.Reader(config, stream, new DateTime(2020, 9, 22), false);
Assert.AreEqual(new DateTime(2020, 9, 22, 11, 17, 0), quoteBarFromLine.EndTime);
Assert.AreEqual(optionSymbol, quoteBarFromLine.Symbol);
Assert.AreEqual(1m, quoteBarFromLine.Bid.Open);
Assert.AreEqual(1.5m, quoteBarFromLine.Bid.High);
Assert.AreEqual(1m, quoteBarFromLine.Bid.Low);
Assert.AreEqual(1.5m, quoteBarFromLine.Bid.Close);
Assert.AreEqual(90m, quoteBarFromLine.LastBidSize);
Assert.AreEqual(1m, quoteBarFromLine.Ask.Open);
Assert.AreEqual(1.5m, quoteBarFromLine.Ask.High);
Assert.AreEqual(1m, quoteBarFromLine.Ask.Low);
Assert.AreEqual(1.5m, quoteBarFromLine.Ask.Close);
Assert.AreEqual(100m, quoteBarFromLine.LastAskSize);
Assert.AreEqual(new DateTime(2020, 9, 22, 11, 17, 0), quoteBarFromStream.EndTime);
Assert.AreEqual(optionSymbol, quoteBarFromStream.Symbol);
Assert.AreEqual(1m, quoteBarFromStream.Bid.Open);
Assert.AreEqual(1.5m, quoteBarFromStream.Bid.High);
Assert.AreEqual(1m, quoteBarFromStream.Bid.Low);
Assert.AreEqual(1.5m, quoteBarFromStream.Bid.Close);
Assert.AreEqual(90m, quoteBarFromStream.LastBidSize);
Assert.AreEqual(1m, quoteBarFromStream.Ask.Open);
Assert.AreEqual(1.5m, quoteBarFromStream.Ask.High);
Assert.AreEqual(1m, quoteBarFromStream.Ask.Low);
Assert.AreEqual(1.5m, quoteBarFromStream.Ask.Close);
Assert.AreEqual(100m, quoteBarFromStream.LastAskSize);
}
[Test]
public void QuoteBarParseDoesNotScaleOptionsWithNonEquityUnderlying()
{
var factory = new QuoteBar();
var underlying = Symbol.CreateFuture("ES", QuantConnect.Market.CME, new DateTime(2021, 3, 19));
var optionSymbol = Symbol.CreateOption(
underlying,
QuantConnect.Market.CME,
OptionStyle.American,
OptionRight.Put,
4200m,
SecurityIdentifier.DefaultDate);
var config = new SubscriptionDataConfig(
typeof(QuoteBar),
optionSymbol,
Resolution.Minute,
TimeZones.Chicago,
TimeZones.Chicago,
true,
false,
false,
false,
TickType.Quote,
true,
DataNormalizationMode.Raw);
var quoteLine = "40560000,1.0,1.5,1.0,1.5,90.0,1.0,1.5,1.0,1.5,100.0";
using var stream = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(quoteLine)));
var unscaledQuoteBarFromLine = (QuoteBar)factory.Reader(config, quoteLine, new DateTime(2020, 9, 22), false);
var unscaledQuoteBarFromStream = (QuoteBar)factory.Reader(config, stream, new DateTime(2020, 9, 22), false);
Assert.AreEqual(new DateTime(2020, 9, 22, 11, 17, 0), unscaledQuoteBarFromLine.EndTime);
Assert.AreEqual(optionSymbol, unscaledQuoteBarFromLine.Symbol);
Assert.AreEqual(1m, unscaledQuoteBarFromLine.Bid.Open);
Assert.AreEqual(1.5m, unscaledQuoteBarFromLine.Bid.High);
Assert.AreEqual(1m, unscaledQuoteBarFromLine.Bid.Low);
Assert.AreEqual(1.5m, unscaledQuoteBarFromLine.Bid.Close);
Assert.AreEqual(90m, unscaledQuoteBarFromLine.LastBidSize);
Assert.AreEqual(1m, unscaledQuoteBarFromLine.Ask.Open);
Assert.AreEqual(1.5m, unscaledQuoteBarFromLine.Ask.High);
Assert.AreEqual(1m, unscaledQuoteBarFromLine.Ask.Low);
Assert.AreEqual(1.5m, unscaledQuoteBarFromLine.Ask.Close);
Assert.AreEqual(100m, unscaledQuoteBarFromLine.LastAskSize);
Assert.AreEqual(new DateTime(2020, 9, 22, 11, 17, 0), unscaledQuoteBarFromStream.EndTime);
Assert.AreEqual(optionSymbol, unscaledQuoteBarFromStream.Symbol);
Assert.AreEqual(1m, unscaledQuoteBarFromStream.Bid.Open);
Assert.AreEqual(1.5m, unscaledQuoteBarFromStream.Bid.High);
Assert.AreEqual(1m, unscaledQuoteBarFromStream.Bid.Low);
Assert.AreEqual(1.5m, unscaledQuoteBarFromStream.Bid.Close);
Assert.AreEqual(90m, unscaledQuoteBarFromStream.LastBidSize);
Assert.AreEqual(1m, unscaledQuoteBarFromStream.Ask.Open);
Assert.AreEqual(1.5m, unscaledQuoteBarFromStream.Ask.High);
Assert.AreEqual(1m, unscaledQuoteBarFromStream.Ask.Low);
Assert.AreEqual(1.5m, unscaledQuoteBarFromStream.Ask.Close);
Assert.AreEqual(100m, unscaledQuoteBarFromStream.LastAskSize);
}
}
}