7705895cc6
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* Portfolio state chart - Cleanup and renames - Add series.IndexName. Uodating unit tests - Add Chart.LegendDisabled. Adding new unit tests - Add ChartPoint.Tooltip. Updating unit tests - Minor compression tweak. Adding unit test - Add ChartJsonConverter. Adding unit tests * Minor chart serialization order tweak * Refactor portfolio state sampling and storing * Move PortfolioMargin into a lean side chart
3827 lines
198 KiB
C#
3827 lines
198 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 NodaTime;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Python.Runtime;
|
|
using NUnit.Framework;
|
|
using QuantConnect.Data;
|
|
using QuantConnect.Util;
|
|
using QuantConnect.Python;
|
|
using QuantConnect.Algorithm;
|
|
using QuantConnect.Securities;
|
|
using QuantConnect.Interfaces;
|
|
using QuantConnect.Data.Market;
|
|
using System.Collections.Generic;
|
|
using QuantConnect.Lean.Engine.DataFeeds;
|
|
using QuantConnect.Tests.Engine.DataFeeds;
|
|
using QuantConnect.Lean.Engine.HistoricalData;
|
|
using HistoryRequest = QuantConnect.Data.HistoryRequest;
|
|
using QuantConnect.Data.Fundamental;
|
|
using QuantConnect.Data.UniverseSelection;
|
|
using QuantConnect.Tests.Common.Data.Fundamental;
|
|
using QuantConnect.Data.Custom;
|
|
|
|
namespace QuantConnect.Tests.Algorithm
|
|
{
|
|
[TestFixture, Parallelizable(ParallelScope.Fixtures)]
|
|
public class AlgorithmHistoryTests
|
|
{
|
|
private QCAlgorithm _algorithm;
|
|
private TestHistoryProvider _testHistoryProvider;
|
|
private IDataProvider _dataProvider;
|
|
private IMapFileProvider _mapFileProvider;
|
|
private IDataCacheProvider _cacheProvider;
|
|
private IFactorFileProvider _factorFileProvider;
|
|
|
|
[SetUp]
|
|
public void Setup()
|
|
{
|
|
_algorithm = new QCAlgorithm();
|
|
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
|
|
_algorithm.HistoryProvider = _testHistoryProvider = new TestHistoryProvider();
|
|
}
|
|
|
|
[OneTimeSetUp]
|
|
public void OneTimeSetUp()
|
|
{
|
|
_dataProvider = TestGlobals.DataProvider;
|
|
_mapFileProvider = TestGlobals.MapFileProvider;
|
|
_factorFileProvider = TestGlobals.FactorFileProvider;
|
|
_cacheProvider = TestGlobals.DataCacheProvider;
|
|
FundamentalService.Initialize(_dataProvider, new NullFundamentalDataProvider(), false);
|
|
}
|
|
|
|
[TestCase(Language.Python)]
|
|
[TestCase(Language.CSharp)]
|
|
public void FundamentalHistory(Language language)
|
|
{
|
|
var start = new DateTime(2014, 04, 07);
|
|
_algorithm = GetAlgorithm(start);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var result = _algorithm.History<Fundamental>(new[] { Symbols.SPY }, 10).ToList();
|
|
|
|
Assert.AreEqual(10, result.Count);
|
|
Assert.IsTrue(result.All(fundamentals =>
|
|
{
|
|
Assert.AreEqual(1, fundamentals.Count);
|
|
Assert.IsTrue(fundamentals.Values.All(x => !x.FinancialStatements.CashFlowStatement.CashFlowFromContinuingFinancingActivities.HasValue));
|
|
return fundamentals.Values.All(x => double.IsNaN(x.FinancialStatements.CashFlowStatement.CashFlowFromContinuingFinancingActivities));
|
|
}));
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var getHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getHistory(algorithm, symbol):
|
|
return algorithm.History(Fundamental, symbol, 10)
|
|
").GetAttr("getHistory");
|
|
_algorithm.SetPandasConverter();
|
|
|
|
var result = getHistory.Invoke(_algorithm.ToPython(), Symbols.SPY.ToPython());
|
|
Assert.AreEqual(10, result.GetAttr("shape")[0].As<int>());
|
|
|
|
dynamic subDataFrame = result.GetAttr("loc")[Symbols.SPY.ID.ToString()];
|
|
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
var index = subDataFrame.index[i];
|
|
var series = subDataFrame.loc[index];
|
|
var cashFlow = (double)series.financialstatements.CashFlowStatement.CashFlowFromContinuingFinancingActivities.Value;
|
|
Assert.AreEqual(double.NaN, cashFlow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Resolution.Daily, Language.CSharp, 2)]
|
|
[TestCase(Resolution.Hour, Language.CSharp, 14)]
|
|
[TestCase(Resolution.Minute, Language.CSharp, 780)]
|
|
[TestCase(Resolution.Second, Language.CSharp, 45676)]
|
|
[TestCase(Resolution.Daily, Language.Python, 2)]
|
|
[TestCase(Resolution.Hour, Language.Python, 14)]
|
|
[TestCase(Resolution.Minute, Language.Python, 780)]
|
|
[TestCase(Resolution.Second, Language.Python, 45676)]
|
|
public void TickResolutionSubscriptionHistoryRequestOtherResolution(Resolution resolution, Language language, int expectedHistoryCount)
|
|
{
|
|
var start = new DateTime(2013, 10, 07);
|
|
_algorithm = GetAlgorithm(start.AddDays(2));
|
|
|
|
_algorithm.AddEquity(Symbols.SPY, Resolution.Tick);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// Trades and quotes
|
|
var result = _algorithm.History(new [] { Symbols.SPY }, start, _algorithm.Time, resolution).ToList();
|
|
|
|
Assert.AreEqual(expectedHistoryCount, result.Count);
|
|
Assert.IsTrue(result.All(slice =>
|
|
{
|
|
foreach (var bar in slice.Bars.Values)
|
|
{
|
|
return (bar.EndTime - bar.Time) == resolution.ToTimeSpan();
|
|
}
|
|
foreach (var bar in slice.QuoteBars.Values)
|
|
{
|
|
return (bar.EndTime - bar.Time) == resolution.ToTimeSpan();
|
|
}
|
|
|
|
return false;
|
|
}));
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var getHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getHistory(algorithm, symbol, start, resolution):
|
|
return algorithm.History(symbol, start, algorithm.Time, resolution).loc[symbol]
|
|
").GetAttr("getHistory");
|
|
|
|
_algorithm.SetPandasConverter();
|
|
|
|
var result = getHistory.Invoke(_algorithm.ToPython(), Symbols.SPY.ToPython(), start.ToPython(), resolution.ToPython());
|
|
Assert.AreEqual(expectedHistoryCount, result.GetAttr("shape")[0].As<int>());
|
|
|
|
var times = result.GetAttr("index").GetAttr("tolist").Invoke().As<List<DateTime>>();
|
|
|
|
var prevDateTime = times[0].Subtract(resolution.ToTimeSpan());
|
|
Assert.IsTrue(times.Any(time =>
|
|
{
|
|
var timeSpan = time - prevDateTime;
|
|
prevDateTime = time;
|
|
return timeSpan == resolution.ToTimeSpan();
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void TickResolutionHistoryRequest(Language language)
|
|
{
|
|
var start = new DateTime(2013, 10, 07);
|
|
_algorithm = GetAlgorithm(start.AddDays(1));
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var result = _algorithm.History(new [] { Symbols.SPY }, start.AddHours(9.8), start.AddHours(10), Resolution.Tick).ToList();
|
|
var result2 = _algorithm.History<Tick>(Symbols.SPY, start.AddHours(9.8), start.AddHours(10), Resolution.Tick).ToList();
|
|
|
|
Assert.IsNotEmpty(result);
|
|
Assert.IsNotEmpty(result2);
|
|
|
|
Assert.IsTrue(result2.Any(tick => tick.TickType == TickType.Trade));
|
|
Assert.IsTrue(result2.Any(tick => tick.TickType == TickType.Quote));
|
|
|
|
var resultTickCount = result.Sum(slice => slice.Ticks[Symbols.SPY].Count);
|
|
Assert.AreEqual(resultTickCount, result2.Count);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var pythonModule = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getTradesAndQuotesHistory(algorithm, symbol, start):
|
|
return algorithm.History([symbol], start + timedelta(hours=12), start + timedelta(hours=12.2), Resolution.Second).loc[symbol].to_dict()
|
|
|
|
def getTradesOnlyHistory(algorithm, symbol, start):
|
|
return algorithm.History(Tick, symbol, start + timedelta(hours=9.8), start + timedelta(hours=10), Resolution.Tick).loc[symbol].to_dict()
|
|
");
|
|
var getTradesAndQuotesHistory = pythonModule.GetAttr("getTradesAndQuotesHistory");
|
|
var getTradesOnlyHistory = pythonModule.GetAttr("getTradesOnlyHistory");
|
|
_algorithm.SetPandasConverter();
|
|
var pySymbol = Symbols.SPY.ToPython();
|
|
var pyAlgorithm = _algorithm.ToPython();
|
|
var pyStart = start.ToPython();
|
|
|
|
var result = getTradesAndQuotesHistory.Invoke(pyAlgorithm, pySymbol, pyStart).ConvertToDictionary<string, dynamic>();
|
|
var result2 = getTradesOnlyHistory.Invoke(pyAlgorithm, pySymbol, pyStart).ConvertToDictionary<string, dynamic>();
|
|
|
|
Assert.IsNotEmpty(result);
|
|
Assert.IsNotEmpty(result2);
|
|
|
|
CollectionAssert.AreNotEquivalent(result.Keys, result2.Keys);
|
|
CollectionAssert.IsNotSubsetOf(result2.Keys, result.Keys);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ImplicitTickResolutionHistoryRequestTradeBarApiThrowsException()
|
|
{
|
|
var spy = _algorithm.AddEquity("SPY", Resolution.Tick).Symbol;
|
|
Assert.Throws<InvalidOperationException>(() => _algorithm.History(spy, 1).ToList());
|
|
}
|
|
|
|
[Test]
|
|
public void ExplicitTickResolutionHistoryRequestTradeBarApiThrowsException()
|
|
{
|
|
var spy = _algorithm.AddEquity("SPY", Resolution.Tick).Symbol;
|
|
Assert.Throws<InvalidOperationException>(() => _algorithm.History(spy, 1, Resolution.Tick).ToList());
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void TickResolutionPeriodBasedHistoryRequestThrowsException(Language language)
|
|
{
|
|
var spy = _algorithm.AddEquity("SPY", Resolution.Tick).Symbol;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
Assert.Throws<InvalidOperationException>(() => _algorithm.History<Tick>(spy, 1).ToList());
|
|
Assert.Throws<InvalidOperationException>(() => _algorithm.History<Tick>(spy, 1, Resolution.Tick).ToList());
|
|
Assert.Throws<InvalidOperationException>(() => _algorithm.History<Tick>(new [] { spy }, 1).ToList());
|
|
Assert.Throws<InvalidOperationException>(() => _algorithm.History<Tick>(new [] { spy }, 1, Resolution.Tick).ToList());
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
|
|
foreach (var testCase in new[] { "return algorithm.History(Tick, symbol, 1)", "return algorithm.History(Tick, symbol, 1)",
|
|
"return algorithm.History(Tick, [ symbol ], 1)", "return algorithm.History(Tick, [ symbol ], 1, Resolution.Tick)" } )
|
|
{
|
|
dynamic getTickHistory = PyModule.FromString("testModule",
|
|
@"from AlgorithmImports import *
|
|
|
|
def getTickHistory(algorithm, symbol):
|
|
" + testCase).GetAttr("getTickHistory");
|
|
|
|
Assert.Throws<ClrBubbledException>(() => getTickHistory(_algorithm, spy));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TickResolutionHistoryRequestTradeBarApiThrowsException()
|
|
{
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => _algorithm.History(Symbols.SPY, 1, Resolution.Tick).ToList());
|
|
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => _algorithm.History(Symbols.SPY, TimeSpan.FromSeconds(2), Resolution.Tick).ToList());
|
|
|
|
Assert.Throws<InvalidOperationException>(
|
|
() => _algorithm.History(Symbols.SPY, DateTime.UtcNow.AddDays(-1), DateTime.UtcNow, Resolution.Tick).ToList());
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void GetsTickResolutionHistoricalDataWithoutATickSubscription(Language language)
|
|
{
|
|
var spy = _algorithm.AddEquity("SPY", Resolution.Daily).Symbol;
|
|
var ibm = _algorithm.AddEquity("IBM", Resolution.Daily).Symbol;
|
|
_algorithm.SetStartDate(2014, 6, 10);
|
|
var start = new DateTime(2013, 10, 7);
|
|
var end = new DateTime(2013, 10, 8);
|
|
_algorithm.SetStartDate(2013, 10, 8);
|
|
|
|
_testHistoryProvider.Slices = new[]
|
|
{
|
|
new Slice(start, new[] { new Tick(start, spy, 100, 100) { TickType = TickType.Trade } }, start),
|
|
new Slice(start, new[] { new Tick(start, ibm, 200, 200) { TickType = TickType.Trade } }, start),
|
|
new Slice(end, new[] { new Tick(end, spy, 110, 110) { TickType = TickType.Trade }, new Tick(end, ibm, 210, 210) { TickType = TickType.Trade } }, end)
|
|
}.ToList();
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var spyHistory = _algorithm.History<Tick>(spy, start, end, Resolution.Tick);
|
|
Assert.AreEqual(2, spyHistory.Count());
|
|
|
|
var ibmHistory = _algorithm.History<Tick>(ibm, start, end, Resolution.Tick);
|
|
Assert.AreEqual(2, ibmHistory.Count());
|
|
|
|
var allHistory = _algorithm.History<Tick>(new[] { spy, ibm }, start, end, Resolution.Tick);
|
|
Assert.AreEqual(3, allHistory.Count());
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var getTickHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getTickHistory(algorithm, symbol, start, end):
|
|
history = algorithm.History(Tick, symbol, start, end, Resolution.Tick)
|
|
history = history if isinstance(symbol, list) else history.loc[symbol]
|
|
|
|
return history.values.tolist()
|
|
|
|
").GetAttr("getTickHistory");
|
|
|
|
_algorithm.SetPandasConverter();
|
|
using var pyAlgorithm = _algorithm.ToPython();
|
|
using var pySpy = spy.ToPython();
|
|
using var pyIbm = ibm.ToPython();
|
|
using var pySymbols = new PyList(new [] { pySpy, pyIbm });
|
|
using var pyStart = start.ToPython();
|
|
using var pyEnd = end.ToPython();
|
|
|
|
var spyHistory = getTickHistory.Invoke(pyAlgorithm, pySpy, pyStart, pyEnd).As<List<dynamic>>();
|
|
Assert.AreEqual(2, spyHistory.Count);
|
|
|
|
var ibmHistory = getTickHistory.Invoke(pyAlgorithm, pyIbm, pyStart, pyEnd).As<List<dynamic>>();
|
|
Assert.AreEqual(2, ibmHistory.Count);
|
|
|
|
var allHistory = getTickHistory.Invoke(pyAlgorithm, pySymbols, pyStart, pyEnd).As<List<dynamic>>();
|
|
Assert.AreEqual(4, allHistory.Count);
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Resolution.Second, Language.CSharp)]
|
|
[TestCase(Resolution.Minute, Language.CSharp)]
|
|
[TestCase(Resolution.Hour, Language.CSharp)]
|
|
[TestCase(Resolution.Daily, Language.CSharp)]
|
|
[TestCase(Resolution.Second, Language.Python)]
|
|
[TestCase(Resolution.Minute, Language.Python)]
|
|
[TestCase(Resolution.Hour, Language.Python)]
|
|
[TestCase(Resolution.Daily, Language.Python)]
|
|
public void TimeSpanHistoryRequestIsCorrectlyBuilt(Resolution resolution, Language language)
|
|
{
|
|
_algorithm.SetStartDate(2013, 10, 07);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
_algorithm.History(Symbols.SPY, TimeSpan.FromSeconds(2), resolution);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
_algorithm.History(Symbols.SPY.ToPython(), TimeSpan.FromSeconds(2), resolution);
|
|
}
|
|
}
|
|
|
|
Resolution? fillForwardResolution = null;
|
|
if (resolution != Resolution.Tick)
|
|
{
|
|
fillForwardResolution = resolution;
|
|
}
|
|
|
|
var expectedCount = resolution == Resolution.Hour || resolution == Resolution.Daily ? 1 : 2;
|
|
Assert.AreEqual(expectedCount, _testHistoryProvider.HistryRequests.Count);
|
|
Assert.AreEqual(Symbols.SPY, _testHistoryProvider.HistryRequests.First().Symbol);
|
|
Assert.AreEqual(resolution, _testHistoryProvider.HistryRequests.First().Resolution);
|
|
Assert.IsFalse(_testHistoryProvider.HistryRequests.First().IncludeExtendedMarketHours);
|
|
Assert.IsFalse(_testHistoryProvider.HistryRequests.First().IsCustomData);
|
|
Assert.AreEqual(fillForwardResolution, _testHistoryProvider.HistryRequests.First().FillForwardResolution);
|
|
Assert.AreEqual(DataNormalizationMode.Adjusted, _testHistoryProvider.HistryRequests.First().DataNormalizationMode);
|
|
Assert.AreEqual(TickType.Trade, _testHistoryProvider.HistryRequests.First().TickType);
|
|
}
|
|
|
|
[TestCase(Resolution.Second, Language.CSharp)]
|
|
[TestCase(Resolution.Minute, Language.CSharp)]
|
|
[TestCase(Resolution.Hour, Language.CSharp)]
|
|
[TestCase(Resolution.Daily, Language.CSharp)]
|
|
[TestCase(Resolution.Second, Language.Python)]
|
|
[TestCase(Resolution.Minute, Language.Python)]
|
|
[TestCase(Resolution.Hour, Language.Python)]
|
|
[TestCase(Resolution.Daily, Language.Python)]
|
|
public void BarCountHistoryRequestIsCorrectlyBuilt(Resolution resolution, Language language)
|
|
{
|
|
_algorithm.SetStartDate(2013, 10, 07);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
_algorithm.History(Symbols.SPY, 10, resolution);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
_algorithm.History(Symbols.SPY.ToPython(), 10, resolution);
|
|
}
|
|
}
|
|
|
|
Resolution? fillForwardResolution = null;
|
|
if (resolution != Resolution.Tick)
|
|
{
|
|
fillForwardResolution = resolution;
|
|
}
|
|
|
|
var expectedCount = resolution == Resolution.Hour || resolution == Resolution.Daily ? 1 : 2;
|
|
Assert.AreEqual(expectedCount, _testHistoryProvider.HistryRequests.Count);
|
|
Assert.AreEqual(Symbols.SPY, _testHistoryProvider.HistryRequests.First().Symbol);
|
|
Assert.AreEqual(resolution, _testHistoryProvider.HistryRequests.First().Resolution);
|
|
Assert.IsFalse(_testHistoryProvider.HistryRequests.First().IncludeExtendedMarketHours);
|
|
Assert.IsFalse(_testHistoryProvider.HistryRequests.First().IsCustomData);
|
|
Assert.AreEqual(fillForwardResolution, _testHistoryProvider.HistryRequests.First().FillForwardResolution);
|
|
Assert.AreEqual(DataNormalizationMode.Adjusted, _testHistoryProvider.HistryRequests.First().DataNormalizationMode);
|
|
Assert.AreEqual(TickType.Trade, _testHistoryProvider.HistryRequests.First().TickType);
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void TickHistoryRequestIgnoresFillForward(Language language)
|
|
{
|
|
_algorithm.SetStartDate(2013, 10, 07);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
_algorithm.History(new [] {Symbols.SPY}, new DateTime(1,1,1,1,1,1), new DateTime(1, 1, 1, 1, 1, 2), Resolution.Tick,
|
|
fillForward: true);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] {Symbols.SPY.ToPython()});
|
|
_algorithm.History(symbols, new DateTime(1,1,1,1,1,1), new DateTime(1, 1, 1, 1, 1, 2),
|
|
Resolution.Tick, fillForward: true);
|
|
}
|
|
}
|
|
|
|
Assert.AreEqual(2, _testHistoryProvider.HistryRequests.Count);
|
|
Assert.AreEqual(Symbols.SPY, _testHistoryProvider.HistryRequests.First().Symbol);
|
|
Assert.AreEqual(Resolution.Tick, _testHistoryProvider.HistryRequests.First().Resolution);
|
|
Assert.IsFalse(_testHistoryProvider.HistryRequests.First().IncludeExtendedMarketHours);
|
|
Assert.IsFalse(_testHistoryProvider.HistryRequests.First().IsCustomData);
|
|
Assert.AreEqual(null, _testHistoryProvider.HistryRequests.First().FillForwardResolution);
|
|
Assert.AreEqual(DataNormalizationMode.Adjusted, _testHistoryProvider.HistryRequests.First().DataNormalizationMode);
|
|
Assert.AreEqual(TickType.Trade, _testHistoryProvider.HistryRequests.First().TickType);
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPriceOfIlliquidAsset_RealData()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2014, 6, 6, 11, 0, 0));
|
|
|
|
//20140606_twx_minute_quote_american_call_230000_20150117.csv
|
|
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015,1,17));
|
|
var option = algorithm.AddOptionContract(optionSymbol);
|
|
|
|
var lastKnownPrice = algorithm.GetLastKnownPrice(option);
|
|
Assert.IsNotNull(lastKnownPrice);
|
|
|
|
// Data gap of more than 15 minutes
|
|
Assert.Greater((algorithm.Time - lastKnownPrice.EndTime).TotalMinutes, 15);
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPriceOfIlliquidAsset_TestData()
|
|
{
|
|
// Set the start date on Tuesday
|
|
_algorithm.SetStartDate(2014, 6, 10);
|
|
|
|
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015, 1, 17));
|
|
var option = _algorithm.AddOptionContract(optionSymbol);
|
|
|
|
// The last known price is on Friday, so we missed data from Monday and no data during Weekend
|
|
var barTime = new DateTime(2014, 6, 6, 15, 0, 0, 0);
|
|
_testHistoryProvider.Slices = new[]
|
|
{
|
|
new Slice(barTime, new[] { new TradeBar(barTime, optionSymbol, 100, 100, 100, 100, 1) }, barTime)
|
|
}.ToList();
|
|
|
|
var lastKnownPrice = _algorithm.GetLastKnownPrice(option);
|
|
Assert.IsNotNull(lastKnownPrice);
|
|
Assert.AreEqual(barTime.AddMinutes(1), lastKnownPrice.EndTime);
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPricesEquity()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
|
|
var equity = algorithm.AddEquity("SPY");
|
|
|
|
var lastKnownPrices = algorithm.GetLastKnownPrices(equity.Symbol).ToList();
|
|
Assert.AreEqual(2, lastKnownPrices.Count);
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(TradeBar)));
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
|
|
}
|
|
|
|
[TestCase(Resolution.Daily)]
|
|
[TestCase(Resolution.Minute)]
|
|
[TestCase(Resolution.Hour)]
|
|
public void GetLastKnownPricesUsesCorrectResolution(Resolution resolution)
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
|
|
algorithm.SetSecurityInitializer(security =>
|
|
{
|
|
var lastKnownPrices = algorithm.GetLastKnownPrices(security).ToList();
|
|
var data = lastKnownPrices.Where(x => x.GetType() == typeof(TradeBar)).Single().ConvertInvariant<TradeBar>();
|
|
var expectedPeriod = new TimeSpan();
|
|
switch (resolution)
|
|
{
|
|
case Resolution.Daily:
|
|
expectedPeriod = TimeSpan.FromDays(1);
|
|
break;
|
|
case Resolution.Minute:
|
|
expectedPeriod = TimeSpan.FromMinutes(1);
|
|
break;
|
|
case Resolution.Hour:
|
|
expectedPeriod = TimeSpan.FromHours(1);
|
|
break;
|
|
}
|
|
|
|
Assert.AreEqual(expectedPeriod, data.Period);
|
|
});
|
|
|
|
algorithm.AddEquity("SPY", resolution);
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void GetLastKnownPricesCustomData(Language language)
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
|
|
Symbol symbol;
|
|
if (language == Language.CSharp)
|
|
{
|
|
symbol = algorithm.AddData<CustomData>("SPY").Symbol;
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
PythonInitializer.Initialize();
|
|
|
|
var customDataType = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
class Test(PythonData):
|
|
def GetSource(self, config, date, isLiveMode):
|
|
fileName = LeanData.GenerateZipFileName(Symbols.SPY, date, config.Resolution, config.TickType)
|
|
source = f'{Globals.DataFolder}equity/usa/minute/spy/{fileName}'
|
|
return SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv)
|
|
|
|
def Reader(self, config, line, date, isLiveMode):
|
|
|
|
data = line.split(',')
|
|
|
|
result = Test()
|
|
result.DataType = MarketDataType.Base
|
|
result.Symbol = config.Symbol
|
|
result.Time = date + timedelta(milliseconds=int(data[0]))
|
|
result.Value = 1
|
|
|
|
return result
|
|
").GetAttr("Test");
|
|
symbol = algorithm.AddData(customDataType, "SPY").Symbol;
|
|
}
|
|
}
|
|
|
|
var lastKnownPrices = algorithm.GetLastKnownPrices(symbol).ToList();
|
|
Assert.AreEqual(1, lastKnownPrices.Count);
|
|
if (language == Language.CSharp)
|
|
{
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(CustomData)));
|
|
}
|
|
else
|
|
{
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(PythonData)));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPriceEquity()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
|
|
var equity = algorithm.AddEquity("SPY");
|
|
|
|
var lastKnownPrice = algorithm.GetLastKnownPrice(equity);
|
|
Assert.AreEqual(typeof(TradeBar), lastKnownPrice.GetType());
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPriceOption()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2014, 06, 09));
|
|
|
|
var option = algorithm.AddOptionContract(Symbols.CreateOptionSymbol("AAPL", OptionRight.Call, 250m, new DateTime(2016, 01, 15)));
|
|
|
|
var lastKnownPrice = algorithm.GetLastKnownPrice(option);
|
|
Assert.AreEqual(typeof(QuoteBar), lastKnownPrice.GetType());
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPricesOption()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2014, 06, 09));
|
|
|
|
var option = algorithm.AddOptionContract(Symbols.CreateOptionSymbol("AAPL", OptionRight.Call, 250m, new DateTime(2016, 01, 15)));
|
|
|
|
var lastKnownPrices = algorithm.GetLastKnownPrices(option).ToList();;
|
|
Assert.AreEqual(2, lastKnownPrices.Count);
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(TradeBar)));
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPriceFuture()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
|
|
var future = algorithm.AddSecurity(Symbols.CreateFutureSymbol(Futures.Indices.SP500EMini, new DateTime(2013, 12, 20)));
|
|
|
|
var lastKnownPrice = algorithm.GetLastKnownPrice(future);
|
|
Assert.AreEqual(typeof(QuoteBar), lastKnownPrice.GetType());
|
|
}
|
|
|
|
[Test]
|
|
public void GetLastKnownPricesFuture()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
|
|
var future = algorithm.AddSecurity(Symbols.CreateFutureSymbol(Futures.Indices.SP500EMini, new DateTime(2013, 12, 20)));
|
|
|
|
var lastKnownPrices = algorithm.GetLastKnownPrices(future).ToList();
|
|
Assert.AreEqual(2, lastKnownPrices.Count);
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(TradeBar)));
|
|
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void TickResolutionOpenInterestHistoryRequestIsNotFilteredWhenRequestedExplicitly(Language language)
|
|
{
|
|
var start = new DateTime(2014, 6, 05);
|
|
var end = start.AddDays(10);
|
|
_algorithm = GetAlgorithm(start);
|
|
_algorithm.SetStartDate(start);
|
|
_algorithm.SetDateTime(end);
|
|
|
|
_algorithm.UniverseSettings.FillForward = false;
|
|
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 45, new DateTime(2015, 1, 17));
|
|
var historyResolution = Resolution.Minute;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var openInterests = _algorithm.History<OpenInterest>(optionSymbol, start, end, historyResolution).ToList();
|
|
|
|
Assert.AreEqual(2, openInterests.Count);
|
|
Assert.AreEqual(new DateTime(2014, 06, 05, 6, 31, 0), openInterests[0].Time);
|
|
Assert.AreEqual(optionSymbol, openInterests[0].Symbol);
|
|
Assert.AreEqual(new DateTime(2014, 06, 06, 6, 30, 0), openInterests[1].Time);
|
|
Assert.AreEqual(optionSymbol, openInterests[1].Symbol);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var getOpenInterestHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getOpenInterestHistory(algorithm, symbol, start, end, resolution):
|
|
return algorithm.History(OpenInterest, symbol, start, end, resolution).reset_index().to_dict()
|
|
").GetAttr("getOpenInterestHistory");
|
|
|
|
_algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] {optionSymbol.ToPython()});
|
|
var openInterestsDataFrameDict = getOpenInterestHistory
|
|
.Invoke(_algorithm.ToPython(), symbols, start.ToPython(), end.ToPython(),
|
|
historyResolution.ToPython())
|
|
.ConvertToDictionary<string, PyObject>();
|
|
|
|
Assert.That(openInterestsDataFrameDict, Does.ContainKey("openinterest"));
|
|
Assert.That(openInterestsDataFrameDict, Does.ContainKey("time"));
|
|
|
|
var openInterests = openInterestsDataFrameDict["openinterest"].ConvertToDictionary<int, decimal>();
|
|
var times = openInterestsDataFrameDict["time"].ConvertToDictionary<int, DateTime>();
|
|
|
|
Assert.That(openInterests, Has.Count.EqualTo(2));
|
|
Assert.That(times, Has.Count.EqualTo(2));
|
|
Assert.That(times[0], Is.EqualTo(new DateTime(2014, 06, 05, 6, 31, 0)));
|
|
Assert.That(times[1], Is.EqualTo(new DateTime(2014, 06, 06, 6, 30, 0)));
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void TickResolutionOpenInterestHistoryRequestIsFilteredByDefault_SingleSymbol(Language language)
|
|
{
|
|
var start = new DateTime(2014, 6, 05);
|
|
var end = start.AddDays(2);
|
|
var historyResolution = Resolution.Minute;
|
|
_algorithm = GetAlgorithm(start);
|
|
_algorithm.SetStartDate(start);
|
|
_algorithm.SetDateTime(end);
|
|
|
|
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015, 1, 17));
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var result = _algorithm.History(new[] { optionSymbol }, start, end, historyResolution, fillForward:false).ToList();
|
|
|
|
Assert.AreEqual(53, result.Count);
|
|
Assert.IsTrue(result.Any(slice => slice.ContainsKey(optionSymbol)));
|
|
|
|
var openInterests = result.Select(slice => slice.Get(typeof(OpenInterest)) as DataDictionary<OpenInterest>).Where(dataDictionary => dataDictionary.Count > 0).ToList();
|
|
|
|
Assert.AreEqual(0, openInterests.Count);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var getOpenInterestHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getOpenInterestHistory(algorithm, symbol, start, end, resolution):
|
|
return algorithm.History(symbol, start, end, resolution)
|
|
").GetAttr("getOpenInterestHistory");
|
|
|
|
_algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] {optionSymbol.ToPython()});
|
|
var openInterests = getOpenInterestHistory.Invoke(_algorithm.ToPython(), symbols, start.ToPython(), end.ToPython(),
|
|
historyResolution.ToPython());
|
|
Assert.AreEqual(780, openInterests.GetAttr("shape")[0].As<int>());
|
|
|
|
var dataFrameDict = openInterests.GetAttr("to_dict").Invoke().ConvertToDictionary<string, dynamic>();
|
|
Assert.That(dataFrameDict, Does.Not.ContainKey("openinterest"));
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void TickResolutionOpenInterestHistoryRequestIsFilteredByDefault_MultipleSymbols(Language language)
|
|
{
|
|
var start = new DateTime(2014, 6, 05);
|
|
var end = start.AddDays(2);
|
|
var historyResolution = Resolution.Minute;
|
|
_algorithm = GetAlgorithm(start.AddDays(1));
|
|
_algorithm.SetStartDate(start);
|
|
_algorithm.SetDateTime(start.AddDays(2));
|
|
|
|
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015, 1, 17));
|
|
var optionSymbol2 = Symbol.CreateOption("AAPL", Market.USA, OptionStyle.American, OptionRight.Call, 500, new DateTime(2015, 1, 17));
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var result = _algorithm.History(new[] { optionSymbol, optionSymbol2 }, start, end, historyResolution, fillForward: false).ToList();
|
|
|
|
Assert.AreEqual(415, result.Count);
|
|
Assert.IsTrue(result.Any(slice => slice.ContainsKey(optionSymbol)));
|
|
Assert.IsTrue(result.Any(slice => slice.ContainsKey(optionSymbol2)));
|
|
|
|
var openInterests = result.Select(slice => slice.Get(typeof(OpenInterest)) as DataDictionary<OpenInterest>).Where(dataDictionary => dataDictionary.Count > 0).ToList();
|
|
|
|
Assert.AreEqual(0, openInterests.Count);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var getOpenInterestHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getOpenInterestHistory(algorithm, symbol, start, end, resolution):
|
|
return algorithm.History(symbol, start, end, resolution)
|
|
").GetAttr("getOpenInterestHistory");
|
|
|
|
_algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] { optionSymbol.ToPython(), optionSymbol2.ToPython() });
|
|
var result = getOpenInterestHistory
|
|
.Invoke(_algorithm.ToPython(), symbols, start.ToPython(), end.ToPython(), historyResolution.ToPython());
|
|
Assert.AreEqual(1170, result.GetAttr("shape")[0].As<int>());
|
|
|
|
var dataFrameDict = result
|
|
.GetAttr("reset_index").Invoke()
|
|
.GetAttr("to_dict").Invoke()
|
|
.ConvertToDictionary<string, PyObject>();
|
|
var dataFrameSymbols = dataFrameDict["symbol"].ConvertToDictionary<int, string>().Values.ToHashSet();
|
|
CollectionAssert.AreEquivalent(dataFrameSymbols, new[] { optionSymbol.ID.ToString(), optionSymbol2.ID.ToString() });
|
|
|
|
Assert.That(dataFrameDict, Does.Not.ContainKey("openinterest"));
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void SubscriptionHistoryRequestWithDifferentDataMappingMode(Language language)
|
|
{
|
|
var dataMappingModes = GetAllDataMappingModes();
|
|
var historyStart = new DateTime(2013, 10, 6);
|
|
var historyEnd = new DateTime(2014, 1, 1);
|
|
var resolution = Resolution.Daily;
|
|
_algorithm = GetAlgorithm(historyEnd);
|
|
var symbol = _algorithm.AddFuture(Futures.Indices.SP500EMini, resolution, dataMappingMode: dataMappingModes.First(),
|
|
extendedMarketHours: true).Symbol;
|
|
var expectedHistoryCount = 74;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var historyResults = dataMappingModes
|
|
.Select(x => _algorithm.History(new [] { symbol }, historyStart, historyEnd, resolution, dataMappingMode: x).ToList())
|
|
.ToList();
|
|
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
|
|
// Check that all history results have a mapping date at some point in the history
|
|
HashSet<DateTime> mappingDates = new HashSet<DateTime>();
|
|
for (int i = 0; i < historyResults.Count; i++)
|
|
{
|
|
var underlying = historyResults[i].First().Bars.Keys.First().Underlying;
|
|
int mappingsCount = 0;
|
|
|
|
foreach (var slice in historyResults[i])
|
|
{
|
|
var dataUnderlying = slice.Bars.Keys.First().Underlying;
|
|
if (dataUnderlying != underlying)
|
|
{
|
|
underlying = dataUnderlying;
|
|
mappingsCount++;
|
|
mappingDates.Add(slice.Time.Date);
|
|
}
|
|
}
|
|
|
|
if (mappingsCount == 0)
|
|
{
|
|
throw new Exception($"History results for {dataMappingModes[i]} data mapping mode did not contain any mappings");
|
|
}
|
|
}
|
|
|
|
if (mappingDates.Count < dataMappingModes.Length)
|
|
{
|
|
throw new Exception("History results should have had different mapping dates for each data mapping mode");
|
|
}
|
|
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data mapping mode at each time");
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] { symbol.ToPython() });
|
|
var historyResults = dataMappingModes
|
|
.Select(x => _algorithm.History(symbols, historyStart, historyEnd, resolution, dataMappingMode: x))
|
|
.ToList();
|
|
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data mapping mode at each time");
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(DataNormalizationMode.BackwardsRatio, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.BackwardsPanamaCanal, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.ForwardPanamaCanal, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.BackwardsRatio, Language.Python)]
|
|
[TestCase(DataNormalizationMode.BackwardsPanamaCanal, Language.Python)]
|
|
[TestCase(DataNormalizationMode.ForwardPanamaCanal, Language.Python)]
|
|
|
|
public void HistoryThrowsForUnsupportedDataNormalizationMode_Equity(DataNormalizationMode dataNormalizationMode, Language language)
|
|
{
|
|
_algorithm = GetAlgorithmWithEquity(new DateTime(2014, 6, 6));
|
|
Assert.AreEqual(2, _algorithm.SubscriptionManager.Subscriptions.ToList().Count);
|
|
var equity = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
Assert.AreEqual(SecurityType.Equity, equity.SecurityType);
|
|
|
|
var start = _algorithm.Time.AddDays(-1);
|
|
var end = _algorithm.Time;
|
|
TestDelegate historyCall;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
_algorithm.History(new [] { equity.Symbol }, start, end, equity.Resolution,
|
|
dataNormalizationMode: dataNormalizationMode).ToList();
|
|
};
|
|
}
|
|
else
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
var symbols = new PyList(new [] { equity.Symbol.ToPython() });
|
|
_algorithm.History(symbols, start, end, equity.Resolution, dataNormalizationMode: dataNormalizationMode);
|
|
}
|
|
};
|
|
}
|
|
|
|
Assert.Throws<ArgumentOutOfRangeException>(historyCall);
|
|
}
|
|
|
|
[TestCase(DataNormalizationMode.Adjusted, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.SplitAdjusted, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.TotalReturn, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.Adjusted, Language.Python)]
|
|
[TestCase(DataNormalizationMode.SplitAdjusted, Language.Python)]
|
|
[TestCase(DataNormalizationMode.TotalReturn, Language.Python)]
|
|
public void HistoryThrowsForUnsupportedDataNormalizationMode_Future(DataNormalizationMode dataNormalizationMode, Language language)
|
|
{
|
|
_algorithm = GetAlgorithmWithFuture(new DateTime(2014, 1, 1));
|
|
Assert.IsNotEmpty(_algorithm.SubscriptionManager.Subscriptions);
|
|
var future = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
Assert.AreEqual(SecurityType.Future, future.SecurityType);
|
|
|
|
var start = _algorithm.StartDate;
|
|
var end = _algorithm.EndDate;
|
|
TestDelegate historyCall;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
_algorithm.History(new [] { future.Symbol }, start, end, future.Resolution,
|
|
dataNormalizationMode: dataNormalizationMode).ToList();
|
|
};
|
|
}
|
|
else
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
var symbols = new PyList(new [] { future.Symbol.ToPython() });
|
|
_algorithm.History(symbols, start, end, future.Resolution, dataNormalizationMode: dataNormalizationMode);
|
|
}
|
|
};
|
|
}
|
|
|
|
Assert.Throws<ArgumentOutOfRangeException>(historyCall);
|
|
}
|
|
|
|
[TestCase(DataNormalizationMode.Raw, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.Adjusted, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.SplitAdjusted, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.TotalReturn, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.Raw, Language.Python)]
|
|
[TestCase(DataNormalizationMode.Adjusted, Language.Python)]
|
|
[TestCase(DataNormalizationMode.SplitAdjusted, Language.Python)]
|
|
[TestCase(DataNormalizationMode.TotalReturn, Language.Python)]
|
|
public void HistoryDoesNotThrowForSupportedDataNormalizationMode_Equity(DataNormalizationMode dataNormalizationMode, Language language)
|
|
{
|
|
_algorithm = GetAlgorithmWithEquity(new DateTime(2014, 6, 6));
|
|
Assert.AreEqual(2, _algorithm.SubscriptionManager.Subscriptions.ToList().Count);
|
|
var equity = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
Assert.AreEqual(SecurityType.Equity, equity.SecurityType);
|
|
|
|
var start = _algorithm.Time.AddDays(-1);
|
|
var end = _algorithm.Time;
|
|
TestDelegate historyCall;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
_algorithm.History(new [] { equity.Symbol }, start, end, equity.Resolution,
|
|
dataNormalizationMode: dataNormalizationMode).ToList();
|
|
};
|
|
}
|
|
else
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
var symbols = new PyList(new [] { equity.Symbol.ToPython() });
|
|
_algorithm.History(symbols, start, end, equity.Resolution, dataNormalizationMode: dataNormalizationMode);
|
|
}
|
|
};
|
|
}
|
|
|
|
Assert.DoesNotThrow(historyCall);
|
|
}
|
|
|
|
[TestCase(DataNormalizationMode.Raw, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.BackwardsRatio, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.BackwardsPanamaCanal, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.ForwardPanamaCanal, Language.CSharp)]
|
|
[TestCase(DataNormalizationMode.Raw, Language.Python)]
|
|
[TestCase(DataNormalizationMode.BackwardsRatio, Language.Python)]
|
|
[TestCase(DataNormalizationMode.BackwardsPanamaCanal, Language.Python)]
|
|
[TestCase(DataNormalizationMode.ForwardPanamaCanal, Language.Python)]
|
|
public void HistoryDoesNotThrowForSupportedDataNormalizationMode_Future(DataNormalizationMode dataNormalizationMode, Language language)
|
|
{
|
|
_algorithm = GetAlgorithmWithFuture(new DateTime(2014, 1, 1));
|
|
Assert.IsNotEmpty(_algorithm.SubscriptionManager.Subscriptions);
|
|
var future = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
Assert.AreEqual(SecurityType.Future, future.SecurityType);
|
|
|
|
var start = _algorithm.StartDate;
|
|
var end = _algorithm.Time;
|
|
TestDelegate historyCall;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
_algorithm.History(new [] { future.Symbol }, start, end, future.Resolution,
|
|
dataNormalizationMode: dataNormalizationMode).ToList();
|
|
};
|
|
}
|
|
else
|
|
{
|
|
historyCall = () =>
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
var symbols = new PyList(new [] { future.Symbol.ToPython() });
|
|
_algorithm.History(symbols, start, end, future.Resolution, dataNormalizationMode: dataNormalizationMode);
|
|
}
|
|
};
|
|
}
|
|
|
|
Assert.DoesNotThrow(historyCall);
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void SubscriptionHistoryRequestWithDifferentDataNormalizationModes_Equity(Language language)
|
|
{
|
|
var dataNormalizationModes = new DataNormalizationMode[]{
|
|
DataNormalizationMode.Raw,
|
|
DataNormalizationMode.Adjusted,
|
|
DataNormalizationMode.SplitAdjusted
|
|
};
|
|
_algorithm = GetAlgorithmWithEquity(new DateTime(2014, 6, 6));
|
|
var equity = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
dynamic symbol = language == Language.CSharp ? equity.Symbol : equity.Symbol.ToPython();
|
|
CheckHistoryResultsForDataNormalizationModes(_algorithm, symbol, _algorithm.Time.AddDays(-1), _algorithm.Time, equity.Resolution,
|
|
dataNormalizationModes, expectedHistoryCount: 390);
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void SubscriptionHistoryRequestWithDifferentDataNormalizationModes_Future(Language language)
|
|
{
|
|
var dataNormalizationModes = new DataNormalizationMode[]{
|
|
DataNormalizationMode.Raw,
|
|
DataNormalizationMode.BackwardsRatio,
|
|
DataNormalizationMode.BackwardsPanamaCanal,
|
|
DataNormalizationMode.ForwardPanamaCanal
|
|
};
|
|
_algorithm = GetAlgorithmWithFuture(new DateTime(2014, 1, 1));
|
|
var future = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
dynamic symbol = language == Language.CSharp ? future.Symbol : future.Symbol.ToPython();
|
|
CheckHistoryResultsForDataNormalizationModes(_algorithm, symbol, new DateTime(2013, 10, 6), _algorithm.Time, future.Resolution,
|
|
dataNormalizationModes, expectedHistoryCount: 74);
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void SubscriptionHistoryRequestForContinuousContractsWithDifferentDepthOffsets(Language language)
|
|
{
|
|
var start = new DateTime(2013, 10, 6);
|
|
var end = new DateTime(2014, 1, 1);
|
|
_algorithm = GetAlgorithmWithFuture(end);
|
|
var future = _algorithm.SubscriptionManager.Subscriptions.First();
|
|
var expectedHistoryCount = 74;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
Func<int, List<Slice>> getHistoryForContractDepthOffset = (contractDepthOffset) =>
|
|
{
|
|
return _algorithm.History(new [] { future.Symbol }, start, end, future.Resolution, contractDepthOffset: contractDepthOffset).ToList();
|
|
};
|
|
|
|
var frontMonthHistory = getHistoryForContractDepthOffset(0);
|
|
var backMonthHistory1 = getHistoryForContractDepthOffset(1);
|
|
var backMonthHistory2 = getHistoryForContractDepthOffset(2);
|
|
|
|
Func<List<Slice>, HashSet<Symbol>> getHistoryUnderlyings = (history) =>
|
|
{
|
|
HashSet<Symbol> underlyings = new();
|
|
foreach (var slice in history)
|
|
{
|
|
var underlying = slice.Keys.Single().Underlying;
|
|
underlyings.Add(underlying);
|
|
}
|
|
|
|
Assert.GreaterOrEqual(underlyings.Count, 2, "History result did not contain any mappings");
|
|
|
|
return underlyings;
|
|
};
|
|
|
|
var frontMonthHistoryUnderlyings = getHistoryUnderlyings(frontMonthHistory);
|
|
var backMonthHistory1Underlyings = getHistoryUnderlyings(backMonthHistory1);
|
|
var backMonthHistory2Underlyings = getHistoryUnderlyings(backMonthHistory2);
|
|
|
|
Assert.AreNotEqual(frontMonthHistoryUnderlyings, backMonthHistory2Underlyings);
|
|
Assert.AreNotEqual(frontMonthHistoryUnderlyings, backMonthHistory2Underlyings);
|
|
Assert.AreNotEqual(backMonthHistory1Underlyings, backMonthHistory2Underlyings);
|
|
|
|
var historyResults = new List<List<Slice>>{ frontMonthHistory, backMonthHistory1, backMonthHistory2 };
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data mapping mode at each time");
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
_algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] { future.Symbol.ToPython() });
|
|
|
|
Func<int, PyObject> getHistoryForContractDepthOffset = (contractDepthOffset) =>
|
|
{
|
|
return _algorithm.History(symbols, start, end, future.Resolution, contractDepthOffset: contractDepthOffset);
|
|
};
|
|
|
|
var frontMonthHistory = getHistoryForContractDepthOffset(0);
|
|
var backMonthHistory1 = getHistoryForContractDepthOffset(1);
|
|
var backMonthHistory2 = getHistoryForContractDepthOffset(2);
|
|
|
|
Assert.Greater(frontMonthHistory.GetAttr("shape")[0].As<int>(), 0);
|
|
Assert.Greater(backMonthHistory1.GetAttr("shape")[0].As<int>(), 0);
|
|
Assert.Greater(backMonthHistory2.GetAttr("shape")[0].As<int>(), 0);
|
|
|
|
var historyResults = new List<PyObject>{ frontMonthHistory, backMonthHistory1, backMonthHistory2 };
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each contract depth offset at each time");
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void GetHistoryWithCustomDataType(Language language)
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
var start = algorithm.StartDate;
|
|
var end = algorithm.EndDate;
|
|
var span = end - start;
|
|
var periods = (int)span.TotalMinutes;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var symbol = algorithm.AddData<CustomData>("SPY").Symbol;
|
|
|
|
var historyResults = new[]
|
|
{
|
|
algorithm.History<CustomData>(symbol, start, end, Resolution.Minute),
|
|
algorithm.History<CustomData>(symbol, span, Resolution.Minute),
|
|
algorithm.History<CustomData>(symbol, periods, Resolution.Minute)
|
|
};
|
|
|
|
foreach (var history in historyResults)
|
|
{
|
|
AssertCustomDataTypeHistory(history.ToList());
|
|
}
|
|
|
|
var historyResults2 = new[]
|
|
{
|
|
algorithm.History<CustomData>(new[] { symbol }, start, end, Resolution.Minute),
|
|
algorithm.History<CustomData>(new[] { symbol }, span, Resolution.Minute),
|
|
algorithm.History<CustomData>(new[] { symbol }, periods, Resolution.Minute)
|
|
};
|
|
|
|
foreach (var history in historyResults2)
|
|
{
|
|
AssertCustomDataTypeHistory(history.ToList());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
PythonInitializer.Initialize();
|
|
|
|
var testModule = PyModule.FromString("testModule",
|
|
@"
|
|
from typing import Union
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
class TestCustomMarketData(PythonData):
|
|
def GetSource(self, config, date, isLiveMode):
|
|
fileName = LeanData.GenerateZipFileName(Symbols.SPY, date, config.Resolution, config.TickType)
|
|
source = f'{Globals.DataFolder}equity/usa/minute/spy/{fileName}'
|
|
return SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv)
|
|
|
|
def Reader(self, config, line, date, isLiveMode):
|
|
|
|
data = line.split(',')
|
|
|
|
result = TestCustomMarketData()
|
|
result.DataType = MarketDataType.Base
|
|
result.Symbol = config.Symbol
|
|
result.Time = date + timedelta(milliseconds=int(data[0]))
|
|
result.Value = 1
|
|
|
|
return result
|
|
|
|
def getDateRangeHistory(algorithm: QCAlgorithm, symbol: Union[Symbol, List[Symbol]], start: datetime, end: datetime):
|
|
return list(algorithm.History[TestCustomMarketData](symbol, start, end, Resolution.Minute))
|
|
|
|
def getTimeSpanHistory(algorithm: QCAlgorithm, symbol: Union[Symbol, List[Symbol]], span: Union[timedelta, int]):
|
|
return list(algorithm.History[TestCustomMarketData](symbol, span, Resolution.Minute))
|
|
");
|
|
var customDataType = testModule.GetAttr("TestCustomMarketData");
|
|
var symbol = algorithm.AddData(customDataType, "SPY").Symbol;
|
|
|
|
dynamic getDateRangeHistory = testModule.GetAttr("getDateRangeHistory");
|
|
dynamic getTimeSpanHistory = testModule.GetAttr("getTimeSpanHistory");
|
|
|
|
var historyResults = new[]
|
|
{
|
|
getDateRangeHistory(algorithm, symbol, start, end),
|
|
getTimeSpanHistory(algorithm, symbol, span),
|
|
getTimeSpanHistory(algorithm, symbol, periods)
|
|
};
|
|
|
|
foreach (var history in historyResults)
|
|
{
|
|
AssertCustomDataTypeHistory(history.As<List<PythonData>>());
|
|
}
|
|
|
|
var historyResults2 = new[]
|
|
{
|
|
getDateRangeHistory(algorithm, new[] { symbol }, start, end),
|
|
getTimeSpanHistory(algorithm, new[] { symbol }, span),
|
|
getTimeSpanHistory(algorithm, new[] { symbol }, periods)
|
|
};
|
|
|
|
foreach (var history in historyResults2)
|
|
{
|
|
AssertCustomDataTypeHistory(history.As<List<DataDictionary<PythonData>>>());
|
|
}
|
|
}
|
|
}
|
|
|
|
Assert.That(_testHistoryProvider.HistryRequests, Has.All.Property("IsCustomData").True);
|
|
}
|
|
|
|
[Test]
|
|
public void GetHistoryFromPythonWithCSharpCustomDataType()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
var start = algorithm.StartDate;
|
|
var end = algorithm.EndDate;
|
|
var span = end - start;
|
|
var periods = (int)span.TotalMinutes;
|
|
|
|
using (Py.GIL())
|
|
{
|
|
PythonInitializer.Initialize();
|
|
|
|
var testModule = PyModule.FromString("testModule",
|
|
@"
|
|
from typing import Union
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
from QuantConnect.Tests.Algorithm import AlgorithmHistoryTests
|
|
|
|
def getDateRangeHistory(algorithm: QCAlgorithm, symbol: Union[Symbol, List[Symbol]], start: datetime, end: datetime):
|
|
return list(algorithm.History[AlgorithmHistoryTests.CustomData](symbol, start, end, Resolution.Minute))
|
|
|
|
def getTimeSpanHistory(algorithm: QCAlgorithm, symbol: Union[Symbol, List[Symbol]], span: Union[timedelta, int]):
|
|
return list(algorithm.History[AlgorithmHistoryTests.CustomData](symbol, span, Resolution.Minute))
|
|
");
|
|
var symbol = algorithm.AddData<CustomData>("SPY").Symbol;
|
|
|
|
dynamic getDateRangeHistory = testModule.GetAttr("getDateRangeHistory");
|
|
dynamic getTimeSpanHistory = testModule.GetAttr("getTimeSpanHistory");
|
|
|
|
var historyResults = new[]
|
|
{
|
|
getDateRangeHistory(algorithm, symbol, start, end),
|
|
getTimeSpanHistory(algorithm, symbol, span),
|
|
getTimeSpanHistory(algorithm, symbol, periods)
|
|
};
|
|
|
|
foreach (var history in historyResults)
|
|
{
|
|
AssertCustomDataTypeHistory(history.As<List<CustomData>>());
|
|
}
|
|
|
|
var historyResults2 = new[]
|
|
{
|
|
getDateRangeHistory(algorithm, new[] { symbol }, start, end),
|
|
getTimeSpanHistory(algorithm, new[] { symbol }, span),
|
|
getTimeSpanHistory(algorithm, new[] { symbol }, periods)
|
|
};
|
|
|
|
foreach (var history in historyResults2)
|
|
{
|
|
AssertCustomDataTypeHistory(history.As<List<DataDictionary<CustomData>>>());
|
|
}
|
|
}
|
|
|
|
Assert.That(_testHistoryProvider.HistryRequests, Has.All.Property("IsCustomData").True);
|
|
}
|
|
|
|
[Test]
|
|
public void GetHistoryWithCustomDataAndNormalizationMode()
|
|
{
|
|
var dataNormalizationModes = new DataNormalizationMode[]{
|
|
DataNormalizationMode.Raw,
|
|
DataNormalizationMode.Adjusted,
|
|
DataNormalizationMode.SplitAdjusted
|
|
};
|
|
var start = new DateTime(2014, 6, 5);
|
|
var end = start.AddDays(1);
|
|
var algorithm = GetAlgorithm(end);
|
|
|
|
using (Py.GIL())
|
|
{
|
|
var getHistoryForDataNormalizationMode = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getHistoryForDataNormalizationMode(algorithm, symbol, start, end, resolution, dataNormalizationMode):
|
|
return algorithm.History(TradeBar, symbol, start, end, resolution, dataNormalizationMode=dataNormalizationMode)
|
|
").GetAttr("getHistoryForDataNormalizationMode");
|
|
|
|
algorithm.SetPandasConverter();
|
|
var symbol = algorithm.AddEquity("AAPL", Resolution.Minute).Symbol.ToPython();
|
|
var pyAlgorithm = algorithm.ToPython();
|
|
var pyStart = start.ToPython();
|
|
var pyEnd = end.ToPython();
|
|
var pyResolution = Resolution.Minute.ToPython();
|
|
var historyResults = dataNormalizationModes
|
|
.Select(dataNormalizationMode =>
|
|
getHistoryForDataNormalizationMode.Invoke(pyAlgorithm, symbol, pyStart, pyEnd, pyResolution, dataNormalizationMode.ToPython()))
|
|
.ToList();
|
|
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount: 390);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data normalization mode at each time");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GetHistoryWithCustomDataAndDataMappingMode()
|
|
{
|
|
var dataMappingModes = GetAllDataMappingModes();
|
|
var historyStart = new DateTime(2013, 10, 6);
|
|
var historyEnd = new DateTime(2014, 1, 1);
|
|
var resolution = Resolution.Daily;
|
|
var algorithm = GetAlgorithm(historyEnd);
|
|
var symbol = algorithm.AddFuture(Futures.Indices.SP500EMini, resolution, dataMappingMode: dataMappingModes.First(),
|
|
extendedMarketHours: true).Symbol;
|
|
|
|
using (Py.GIL())
|
|
{
|
|
var getHistoryForDataMappingMode = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getHistoryForDataMappingMode(algorithm, symbol, start, end, resolution, dataMappingMode):
|
|
return algorithm.History(TradeBar, symbol, start, end, resolution, dataMappingMode=dataMappingMode)
|
|
").GetAttr("getHistoryForDataMappingMode");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var symbols = symbol.ToPython();
|
|
var pyAlgorithm = algorithm.ToPython();
|
|
var pyStart = historyStart.ToPython();
|
|
var pyEnd = historyEnd.ToPython();
|
|
var pyResolution = resolution.ToPython();
|
|
var historyResults = dataMappingModes
|
|
.Select(dataMappingMode =>
|
|
getHistoryForDataMappingMode.Invoke(pyAlgorithm, symbols, pyStart, pyEnd, pyResolution, dataMappingMode.ToPython()))
|
|
.ToList();
|
|
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount: 74);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data mapping mode at each time");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GetHistoryWithCustomDataAndContractDepthOffset()
|
|
{
|
|
var start = new DateTime(2013, 10, 6);
|
|
var end = new DateTime(2014, 1, 1);
|
|
var algorithm = GetAlgorithmWithFuture(end);
|
|
var future = algorithm.SubscriptionManager.Subscriptions.First();
|
|
|
|
using (Py.GIL())
|
|
{
|
|
var getHistoryForContractDepthOffset = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getHistoryForContractDepthOffset(algorithm, symbol, start, end, resolution, contractDepthOffset):
|
|
return algorithm.History(QuoteBar, symbol, start, end, resolution, contractDepthOffset=contractDepthOffset)
|
|
").GetAttr("getHistoryForContractDepthOffset");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var symbols = new PyList(new [] { future.Symbol.ToPython() });
|
|
var pyAlgorithm = algorithm.ToPython();
|
|
var pyStart = start.ToPython();
|
|
var pyEnd = end.ToPython();
|
|
var pyResolution = future.Resolution.ToPython();
|
|
|
|
var frontMonthHistory = getHistoryForContractDepthOffset.Invoke(pyAlgorithm, symbols, pyStart, pyEnd, pyResolution, 0.ToPython());
|
|
var backMonthHistory1 = getHistoryForContractDepthOffset.Invoke(pyAlgorithm, symbols, pyStart, pyEnd, pyResolution, 1.ToPython());
|
|
var backMonthHistory2 = getHistoryForContractDepthOffset.Invoke(pyAlgorithm, symbols, pyStart, pyEnd, pyResolution, 2.ToPython());
|
|
|
|
Assert.Greater(frontMonthHistory.GetAttr("shape")[0].As<int>(), 0);
|
|
Assert.Greater(backMonthHistory1.GetAttr("shape")[0].As<int>(), 0);
|
|
Assert.Greater(backMonthHistory2.GetAttr("shape")[0].As<int>(), 0);
|
|
|
|
var historyResults = new List<PyObject>{ frontMonthHistory, backMonthHistory1, backMonthHistory2 };
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount: 74);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each contract depth offset at each time");
|
|
}
|
|
}
|
|
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void GetsHistoryWithGivenBarType(Language language)
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2014, 6, 6));
|
|
var ibmSymbol = Symbol.Create("IBM", SecurityType.Equity, Market.USA);
|
|
var twxSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 45, new DateTime(2015, 1, 17));
|
|
|
|
var ibmHistoryStart = new DateTime(2013, 10, 7);
|
|
var ibmHistoryEnd = new DateTime(2013, 10, 8);
|
|
var twxHistoryStart = new DateTime(2014, 6, 5);
|
|
var twxHistoryEnd = new DateTime(2014, 6, 6);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var tradeHistory = algorithm.History<TradeBar>(ibmSymbol, ibmHistoryStart, ibmHistoryEnd);
|
|
Assert.AreEqual(390, tradeHistory.Count());
|
|
|
|
var quoteHistory = algorithm.History<QuoteBar>(ibmSymbol, ibmHistoryStart, ibmHistoryEnd);
|
|
Assert.AreEqual(390, quoteHistory.Count());
|
|
|
|
var tickHistory = algorithm.History<Tick>(ibmSymbol, ibmHistoryStart, ibmHistoryEnd, Resolution.Tick);
|
|
Assert.AreEqual(132104, tickHistory.Count());
|
|
|
|
var openInterestHistory = algorithm.History<OpenInterest>(twxSymbol, twxHistoryStart, twxHistoryEnd);
|
|
Assert.AreEqual(1050, openInterestHistory.Count());
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getTradeBarHistory(algorithm, symbol, start, end):
|
|
return algorithm.History(TradeBar, symbol, start, end)
|
|
|
|
def getQuoteBarHistory(algorithm, symbol, start, end):
|
|
return algorithm.History(QuoteBar, symbol, start, end)
|
|
|
|
def getTickHistory(algorithm, symbol, start, end):
|
|
return algorithm.History(Tick, symbol, start, end, Resolution.Tick)
|
|
|
|
def getOpenInterestHistory(algorithm, symbol, start, end):
|
|
return algorithm.History(OpenInterest, symbol, start, end)
|
|
");
|
|
|
|
dynamic getTradeBarHistory = testModule.GetAttr("getTradeBarHistory");
|
|
dynamic getQuoteBarHistory = testModule.GetAttr("getQuoteBarHistory");
|
|
dynamic getTickHistory = testModule.GetAttr("getTickHistory");
|
|
dynamic getOpenInterestHistory = testModule.GetAttr("getOpenInterestHistory");
|
|
|
|
algorithm.SetPandasConverter();
|
|
|
|
dynamic tradeHistory = getTradeBarHistory(algorithm, ibmSymbol, ibmHistoryStart, ibmHistoryEnd);
|
|
Assert.AreEqual(390, tradeHistory.shape[0].As<int>());
|
|
|
|
dynamic quoteHistory = getQuoteBarHistory(algorithm, ibmSymbol, ibmHistoryStart, ibmHistoryEnd);
|
|
Assert.AreEqual(390, quoteHistory.shape[0].As<int>());
|
|
|
|
dynamic tickHistory = getTickHistory(algorithm, ibmSymbol, ibmHistoryStart, ibmHistoryEnd);
|
|
Assert.AreEqual(132104, tickHistory.shape[0].As<int>());
|
|
|
|
dynamic openInterestHistory = getOpenInterestHistory(algorithm, twxSymbol, twxHistoryStart, twxHistoryEnd);
|
|
Assert.AreEqual(1050, openInterestHistory.shape[0].As<int>());
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void HistoryCallsGetSameTickCount()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2014, 6, 6));
|
|
var ibmSymbol = Symbol.Create("IBM", SecurityType.Equity, Market.USA);
|
|
|
|
var start = new DateTime(2013, 10, 7);
|
|
var end = new DateTime(2013, 10, 8);
|
|
|
|
var history = algorithm.History(new [] { ibmSymbol }, start, end, Resolution.Tick);
|
|
var tickCountInSliceHistoryCall = history.Sum(x => x.Ticks[ibmSymbol].Count);
|
|
Assert.AreEqual(132104, tickCountInSliceHistoryCall);
|
|
|
|
var tickHistory = algorithm.History<Tick>(ibmSymbol, start, end, Resolution.Tick).ToList();
|
|
var tickCountInTickHistoryCall = tickHistory.Count;
|
|
Assert.AreEqual(tickCountInSliceHistoryCall, tickCountInTickHistoryCall);
|
|
}
|
|
|
|
[Test]
|
|
public void PricesAreProperlyAdjustedForScaledRawHistoryRequest()
|
|
{
|
|
var start = new DateTime(2000, 01, 01);
|
|
var end = new DateTime(2016, 01, 01);
|
|
var algorithm = GetAlgorithm(end.AddDays(1));
|
|
var aaplSymbol = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
|
|
|
|
var rawHistory = algorithm.History(new[] { aaplSymbol }, start, end, Resolution.Daily, dataNormalizationMode: DataNormalizationMode.Raw).ToList();
|
|
var scaledRawHistory = algorithm.History(new[] { aaplSymbol }, start, end, Resolution.Daily, dataNormalizationMode: DataNormalizationMode.ScaledRaw).ToList();
|
|
|
|
Assert.IsNotEmpty(rawHistory);
|
|
Assert.AreEqual(rawHistory.Count, scaledRawHistory.Count);
|
|
|
|
var factorFile = _factorFileProvider.Get(aaplSymbol);
|
|
var factorDates = new List<DateTime>();
|
|
var factors = new List<decimal>();
|
|
var prevFactor = 0m;
|
|
for (var date = start; date <= end; date = date.AddDays(1))
|
|
{
|
|
var factor = factorFile.GetPriceFactor(date, DataNormalizationMode.ScaledRaw);
|
|
if (factor != prevFactor)
|
|
{
|
|
factorDates.Add(date.AddDays(-1));
|
|
factors.Add(factor);
|
|
prevFactor = factor;
|
|
}
|
|
}
|
|
var lastFactorDate = factorDates[factorDates.Count - 1];
|
|
var lastFactor = factors[factors.Count - 1];
|
|
factorDates.RemoveAt(0);
|
|
var currentFactorIndex = 0;
|
|
|
|
for (var i = 0; i < rawHistory.Count; i++)
|
|
{
|
|
var rawBar = rawHistory[i].Bars[aaplSymbol];
|
|
var scaledRawBar = scaledRawHistory[i].Bars[aaplSymbol];
|
|
|
|
if (currentFactorIndex < factorDates.Count && rawBar.Time > factorDates[currentFactorIndex])
|
|
{
|
|
currentFactorIndex++;
|
|
}
|
|
|
|
if (rawBar.Time <= lastFactorDate)
|
|
{
|
|
Assert.AreNotEqual(rawBar.Price, scaledRawBar.Price,
|
|
$@"Raw price {rawBar.Price} should have been different than scaled raw price {scaledRawBar.Price} at {
|
|
rawBar.Time} (before and at the last factor date {lastFactorDate})");
|
|
}
|
|
else
|
|
{
|
|
// after the last split/dividend, the factor is 1 because prices are adjusted to the prices after the last factor
|
|
Assert.AreEqual(1m, factors[currentFactorIndex] / lastFactor);
|
|
Assert.AreEqual(rawBar.Price, scaledRawBar.Price,
|
|
$@"Raw price {rawBar.Price} should have been equal to the scaled raw price {scaledRawBar.Price} at {
|
|
rawBar.Time} (after the last factor date {lastFactorDate})");
|
|
}
|
|
|
|
var expectedScaledRawPrice = rawBar.Price * factors[currentFactorIndex] / lastFactor;
|
|
Assert.Less(Math.Abs(expectedScaledRawPrice - scaledRawBar.Price), 1e-25m, $"Date: {rawBar.Time}");
|
|
}
|
|
}
|
|
|
|
// C#
|
|
[TestCase(Language.CSharp, Resolution.Second, true, 46800, 46800, 46800)]
|
|
[TestCase(Language.CSharp, Resolution.Second, false, 46800, 22884, 16093)]
|
|
[TestCase(Language.CSharp, Resolution.Minute, true, 780, 780, 780)]
|
|
[TestCase(Language.CSharp, Resolution.Minute, false, 780, 390, 390)]
|
|
// Python
|
|
[TestCase(Language.Python, Resolution.Second, true, 46800, 46800, 46800)]
|
|
[TestCase(Language.Python, Resolution.Second, false, 46800, 22884, 16093)]
|
|
[TestCase(Language.Python, Resolution.Minute, true, 780, 780, 780)]
|
|
[TestCase(Language.Python, Resolution.Minute, false, 780, 390, 390)]
|
|
public void HistoryRequestWithFillForward(Language language, Resolution resolution, bool fillForward, int periods,
|
|
int expectedHistoryCount, int expectedTradeBarOnlyHistoryCount)
|
|
{
|
|
// Theres data only for 2013-10-07 to 2013-10-11 for SPY. Data should be fill forwarded till the 15th.
|
|
var start = new DateTime(2013, 10, 11);
|
|
var end = new DateTime(2013, 10, 15);
|
|
var timeSpan = end - start;
|
|
|
|
var algorithm = GetAlgorithm(end);
|
|
var symbol = algorithm.AddEquity("SPY").Symbol;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// No symbol, time span
|
|
var noSymbolTimeSpanHistory = algorithm.History(timeSpan, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(noSymbolTimeSpanHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// No symbol, periods
|
|
var noSymbolPeriodBasedHistory = algorithm.History(periods, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(noSymbolPeriodBasedHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// No symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Single symbol, time span
|
|
var singleSymbolTimeSpanHistory = algorithm.History(symbol, timeSpan, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(singleSymbolTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Single symbol, periods
|
|
var singleSymbolPeriodBasedHistory = algorithm.History(symbol, periods, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(singleSymbolPeriodBasedHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Single symbol, date range
|
|
var singleSymbolDateRangeHistory = algorithm.History(symbol, start, end,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(singleSymbolDateRangeHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Symbol array, time span
|
|
var symbolsTimeSpanHistory = algorithm.History(new[] { symbol }, timeSpan, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(symbolsTimeSpanHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Symbol array, periods
|
|
var symbolsPeriodBasedHistory = algorithm.History(new[] { symbol }, periods, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(symbolsPeriodBasedHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Symbol array, date range
|
|
var symbolsdateRangeHistory = algorithm.History(new[] { symbol }, start, end, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(symbolsdateRangeHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, no symbol, time span
|
|
var typedNoSymbolTimeSpanHistory = algorithm.History<TradeBar>(timeSpan, resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedNoSymbolTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, no symbol, periods
|
|
// TODO: to be implemented
|
|
|
|
// Generic, no symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Generic, single symbol, time span
|
|
var typedSingleSymbolTimeSpanHistory = algorithm.History<TradeBar>(symbol, timeSpan,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedSingleSymbolTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, single symbol, periods
|
|
var typedSingleSymbolPeriodBasedHistory = algorithm.History<TradeBar>(symbol, periods,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedSingleSymbolPeriodBasedHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, single symbol, date range
|
|
var typedSingleSymbolDateRangeHistory = algorithm.History<TradeBar>(symbol, start, end,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedSingleSymbolDateRangeHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, symbol array, time span
|
|
var typedSymbolsTimeSpanHistory = algorithm.History<TradeBar>(new[] { symbol }, timeSpan,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedSymbolsTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, symbol array, periods
|
|
var typedSymbolsPeriodBasedHistory = algorithm.History<TradeBar>(new[] { symbol }, periods,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedSymbolsPeriodBasedHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, symbol array, date range
|
|
var typedSymbolsDateRangeHistory = algorithm.History<TradeBar>(new[] { symbol }, start, end,
|
|
resolution, fillForward: fillForward).ToList();
|
|
AssertFillForwardHistoryResults(typedSymbolsDateRangeHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule", @"
|
|
from AlgorithmImports import *
|
|
|
|
tradeBar = TradeBar
|
|
");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var pySymbol = symbol.ToPython();
|
|
using var pySymbols = new PyList(new[] { pySymbol });
|
|
using var pyTradeBarType = testModule.GetAttr("tradeBar");
|
|
|
|
// Single symbol, time span
|
|
var singleSymbolTimeSpanHistory = algorithm.History(pySymbol, timeSpan, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(singleSymbolTimeSpanHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Single symbol, periods
|
|
var singleSymbolPeriodBasedHistory = algorithm.History(pySymbol, periods, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(singleSymbolPeriodBasedHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Single symbol, date range
|
|
var singleSymbolDateRangeHistory = algorithm.History(pySymbol, start, end, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(singleSymbolDateRangeHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Symbol array, time span
|
|
var symbolsTimeSpanHistory = algorithm.History(pySymbols, timeSpan, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(symbolsTimeSpanHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Symbol array, periods
|
|
var symbolsPeriodBasedHistory = algorithm.History(pySymbols, periods, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(symbolsPeriodBasedHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Symbol array, date range
|
|
var symbolsDateRangeHistory = algorithm.History(pySymbols, start, end, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(symbolsDateRangeHistory, expectedHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, single symbol, time span
|
|
var typedSingleSymbolTimeSpanHistory = algorithm.History(pyTradeBarType, pySymbol, timeSpan,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSingleSymbolTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolTimeSpanHistory = algorithm.History(pyTradeBarType, symbol, timeSpan, resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSingleSymbolTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, single symbol, periods
|
|
var typedSingleSymbolPeriodBasedHistory = algorithm.History(pyTradeBarType, pySymbol, periods,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSingleSymbolPeriodBasedHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolPeriodBasedHistory = algorithm.History(pyTradeBarType, symbol, periods,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSingleSymbolPeriodBasedHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, single symbol, date range
|
|
var typedSingleSymbolDateRangeHistory = algorithm.History(pyTradeBarType, pySymbol, start, end,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSingleSymbolDateRangeHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolDateRangeHistory = algorithm.History(pyTradeBarType, symbol, start, end,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSingleSymbolDateRangeHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, symbol array, time span
|
|
var typedSymbolsTimeSpanHistory = algorithm.History(pyTradeBarType, pySymbols, timeSpan,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSymbolsTimeSpanHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, symbol array, periods
|
|
var typedSymbolsPeriodBasedHistory = algorithm.History(pyTradeBarType, pySymbols, periods,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSymbolsPeriodBasedHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
|
|
// Generic, symbol array, date range
|
|
var typedSymbolsDateRangeHistory = algorithm.History(pyTradeBarType, pySymbols, start, end,
|
|
resolution, fillForward: fillForward);
|
|
AssertFillForwardHistoryResults(typedSymbolsDateRangeHistory, expectedTradeBarOnlyHistoryCount, resolution, fillForward);
|
|
}
|
|
}
|
|
}
|
|
|
|
// C#
|
|
[TestCase(Language.CSharp, Resolution.Minute, true, 960)]
|
|
[TestCase(Language.CSharp, Resolution.Minute, false, 390)]
|
|
[TestCase(Language.CSharp, Resolution.Second, true, 57600)]
|
|
[TestCase(Language.CSharp, Resolution.Second, false, 23400)]
|
|
// Python
|
|
[TestCase(Language.Python, Resolution.Minute, true, 960)]
|
|
[TestCase(Language.Python, Resolution.Minute, false, 390)]
|
|
[TestCase(Language.Python, Resolution.Second, true, 57600)]
|
|
[TestCase(Language.Python, Resolution.Second, false, 23400)]
|
|
public void HistoryRequestWithExtendedMarketHours(Language language, Resolution resolution, bool extendedMarket, int expectedHistoryCount)
|
|
{
|
|
var start = new DateTime(2013, 10, 07);
|
|
var end = new DateTime(2013, 10, 08);
|
|
var algorithm = GetAlgorithm(end);
|
|
var symbol = algorithm.AddEquity("SPY").Symbol;
|
|
|
|
var extendedMarketPeriods = expectedHistoryCount;
|
|
var timeSpan = end - start;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// No symbol, time span
|
|
var noSymbolTimeSpanHistory = algorithm.History(timeSpan, resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(noSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// No symbol, periods
|
|
var noSymbolPeriodBasedHistory = algorithm.History(extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(noSymbolPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
//// No symbol, date range
|
|
//// TODO: to be implemented
|
|
|
|
// Single symbol, time span
|
|
var singleSymbolTimeSpanHistory = algorithm.History(symbol, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(singleSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Single symbol, periods
|
|
var singleSymbolPeriodBasedHistory = algorithm.History(symbol, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(singleSymbolPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Single symbol, date range
|
|
var singleSymbolDateRangeHistory = algorithm.History(symbol, start, end,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(singleSymbolDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Symbol array, time span
|
|
var symbolsTimeSpanHistory = algorithm.History(new[] { symbol }, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(symbolsTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Symbol array, periods
|
|
var symbolsPeriodBasedHistory = algorithm.History(new[] { symbol }, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(symbolsPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Symbol array, date range
|
|
var symbolsdateRangeHistory = algorithm.History(new[] { symbol }, start, end,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(symbolsdateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, no symbol, time span
|
|
var typedNoSymbolTimeSpanHistory = algorithm.History<TradeBar>(timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedNoSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
//// Generic, no symbol, periods
|
|
//// TODO: to be implemented
|
|
|
|
//// Generic, no symbol, date range
|
|
//// TODO: to be implemented
|
|
|
|
// Generic, single symbol, time span
|
|
var typedSingleSymbolTimeSpanHistory = algorithm.History<TradeBar>(symbol, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, single symbol, periods
|
|
var typedSingleSymbolPeriodBasedHistory = algorithm.History<TradeBar>(symbol, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, single symbol, date range
|
|
var typedSingleSymbolDateRangeHistory = algorithm.History<TradeBar>(symbol, start, end,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, symbol array, time span
|
|
var typedSymbolsTimeSpanHistory = algorithm.History<TradeBar>(new[] { symbol }, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSymbolsTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, symbol array, periods
|
|
var typedSymbolsPeriodBasedHistory = algorithm.History<TradeBar>(new[] { symbol }, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSymbolsPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, symbol array, date range
|
|
var typedSymbolsDateRangeHistory = algorithm.History<TradeBar>(new[] { symbol }, start, end,
|
|
resolution, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSymbolsDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule", @"
|
|
from AlgorithmImports import *
|
|
tradeBar = TradeBar
|
|
");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var pySymbol = symbol.ToPython();
|
|
using var pySymbols = new PyList(new[] { pySymbol });
|
|
using var pyTradeBarType = testModule.GetAttr("tradeBar");
|
|
|
|
// Single symbol, time span
|
|
var singleSymbolTimeSpanHistory = algorithm.History(pySymbol, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(singleSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Single symbol, periods
|
|
var singleSymbolPeriodBasedHistory = algorithm.History(pySymbol, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(singleSymbolPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Single symbol, date range
|
|
var singleSymbolDateRangeHistory = algorithm.History(pySymbol, start, end,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(singleSymbolDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Symbol array, time span
|
|
var symbolsTimeSpanHistory = algorithm.History(pySymbols, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(symbolsTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Symbol array, periods
|
|
var symbolsPeriodBasedHistory = algorithm.History(pySymbols, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(symbolsPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Symbol array, date range
|
|
var symbolsDateRangeHistory = algorithm.History(pySymbols, start, end,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(symbolsDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, single symbol, time span
|
|
var typedSingleSymbolTimeSpanHistory = algorithm.History(pyTradeBarType, pySymbol, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolTimeSpanHistory = algorithm.History(pyTradeBarType, symbol, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, single symbol, periods
|
|
var typedSingleSymbolPeriodBasedHistory = algorithm.History(pyTradeBarType, pySymbol,
|
|
extendedMarketPeriods, resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolPeriodBasedHistory = algorithm.History(pyTradeBarType, symbol,
|
|
extendedMarketPeriods, resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, single symbol, date range
|
|
var typedSingleSymbolDateRangeHistory = algorithm.History(pyTradeBarType, pySymbol, start, end,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolDateRangeHistory = algorithm.History(pyTradeBarType, symbol, start, end,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, symbol array, time span
|
|
var typedSymbolsTimeSpanHistory = algorithm.History(pyTradeBarType, pySymbols, timeSpan,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSymbolsTimeSpanHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, symbol array, periods
|
|
var typedSymbolsPeriodBasedHistory = algorithm.History(pyTradeBarType, pySymbols, extendedMarketPeriods,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSymbolsPeriodBasedHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
|
|
// Generic, symbol array, date range
|
|
var typedSymbolsDateRangeHistory = algorithm.History(pyTradeBarType, pySymbols, start, end,
|
|
resolution, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSymbolsDateRangeHistory, expectedHistoryCount, extendedMarket, resolution, symbol);
|
|
}
|
|
}
|
|
}
|
|
|
|
// C#
|
|
[TestCase(Language.CSharp, true, 326645, 69480)] // 326645, 69480
|
|
[TestCase(Language.CSharp, false, 288008, 60486)] // 288008, 60486
|
|
// Python
|
|
[TestCase(Language.Python, true, 326645)] //, 420604
|
|
[TestCase(Language.Python, false, 288008)] //, 288008
|
|
public void HistoryRequestWithExtendedMarketHoursTickResolution(
|
|
Language language,
|
|
bool extendedMarket,
|
|
int historyExpectedCount,
|
|
// History<T> methods that take multiple symbols still have a bug for Tick type,
|
|
// where slice.Get() returns only the last tick for each symbol, so the expected count is different
|
|
int cSharpTypedMultiSymbolHistoryExpectedCount = 0)
|
|
{
|
|
var start = new DateTime(2013, 10, 07, 15, 30, 0);
|
|
var end = start.AddHours(1);
|
|
var algorithm = GetAlgorithm(end);
|
|
var symbol = algorithm.AddEquity("SPY").Symbol;
|
|
|
|
var timeSpan = end - start;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// No symbol, time span
|
|
var noSymbolTimeSpanHistory = algorithm.History(timeSpan, Resolution.Tick, extendedMarketHours: extendedMarket)
|
|
.SelectMany(x => x.Ticks[symbol]).ToList();
|
|
AssertExtendedMarketHistoryResults(noSymbolTimeSpanHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// No symbol, periods
|
|
// Not available for tick resolution
|
|
|
|
//// No symbol, date range
|
|
//// TODO: to be implemented
|
|
|
|
// Single symbol, time span
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Single symbol, periods
|
|
// Not available for tick resolution
|
|
|
|
// Single symbol, date range
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Symbol array, time span
|
|
var symbolsTimeSpanHistory = algorithm.History(new[] { symbol }, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).SelectMany(x => x.Ticks[symbol]).ToList();
|
|
AssertExtendedMarketHistoryResults(symbolsTimeSpanHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Symbol array, periods
|
|
// Not available for tick resolution
|
|
|
|
//// Symbol array, date range
|
|
var symbolsdateRangeHistory = algorithm.History(new[] { symbol }, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).SelectMany(x => x.Ticks[symbol]).ToList();
|
|
AssertExtendedMarketHistoryResults(symbolsdateRangeHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Generic, no symbol, time span
|
|
var typedNoSymbolTimeSpanHistory = algorithm.History<Tick>(timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedNoSymbolTimeSpanHistory, cSharpTypedMultiSymbolHistoryExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
//// Generic, no symbol, periods
|
|
//// TODO: to be implemented
|
|
|
|
//// Generic, no symbol, date range
|
|
//// TODO: to be implemented
|
|
|
|
//// Generic, single symbol, time span
|
|
var typedSingleSymbolTimeSpanHistory = algorithm.History<Tick>(symbol, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolTimeSpanHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Generic, single symbol, periods
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
//// Generic, single symbol, date range
|
|
var typedSingleSymbolDateRangeHistory = algorithm.History<Tick>(symbol, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolDateRangeHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Generic, symbol array, time span
|
|
var typedSymbolsTimeSpanHistory = algorithm.History<Tick>(new[] { symbol }, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSymbolsTimeSpanHistory, cSharpTypedMultiSymbolHistoryExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
// Generic, symbol array, periods
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Generic, symbol array, date range
|
|
var typedSymbolsDateRangeHistory = algorithm.History<Tick>(new[] { symbol }, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket).ToList();
|
|
AssertExtendedMarketHistoryResults(typedSymbolsDateRangeHistory, cSharpTypedMultiSymbolHistoryExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule", @"
|
|
from AlgorithmImports import *
|
|
tick = Tick
|
|
");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var pySymbol = symbol.ToPython();
|
|
using var pySymbols = new PyList(new[] { pySymbol });
|
|
using var pyTickType = testModule.GetAttr("tick");
|
|
|
|
// Single symbol, time span
|
|
var singleSymbolTimeSpanHistory = algorithm.History(pySymbol, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(singleSymbolTimeSpanHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Single symbol, periods
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Single symbol, date range
|
|
var singleSymbolDateRangeHistory = algorithm.History(pySymbol, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(singleSymbolDateRangeHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Symbol array, time span
|
|
var symbolsTimeSpanHistory = algorithm.History(pySymbols, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(symbolsTimeSpanHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Symbol array, periods
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Symbol array, date range
|
|
var symbolsDateRangeHistory = algorithm.History(pySymbols, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(symbolsDateRangeHistory, historyExpectedCount, extendedMarket, Resolution.Tick, symbol);
|
|
|
|
// Generic, single symbol, time span
|
|
var typedSingleSymbolTimeSpanHistory = algorithm.History(pyTickType, pySymbol, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolTimeSpanHistory, historyExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolTimeSpanHistory = algorithm.History(pyTickType, symbol, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolTimeSpanHistory, historyExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
// Generic, single symbol, periods
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Generic, single symbol, date range
|
|
var typedSingleSymbolDateRangeHistory = algorithm.History(pyTickType, pySymbol, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolDateRangeHistory, historyExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
typedSingleSymbolDateRangeHistory = algorithm.History(pyTickType, symbol, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSingleSymbolDateRangeHistory, historyExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
// Generic, symbol array, time span
|
|
var typedSymbolsTimeSpanHistory = algorithm.History(pyTickType, pySymbols, timeSpan,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSymbolsTimeSpanHistory, historyExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
|
|
// Generic, symbol array, periods
|
|
// Not available for tick resolution (TradeBar API)
|
|
|
|
// Generic, symbol array, date range
|
|
var typedSymbolsDateRangeHistory = algorithm.History(pyTickType, pySymbols, start, end,
|
|
Resolution.Tick, extendedMarketHours: extendedMarket);
|
|
AssertExtendedMarketHistoryResults(typedSymbolsDateRangeHistory, historyExpectedCount, extendedMarket,
|
|
Resolution.Tick, symbol);
|
|
}
|
|
}
|
|
}
|
|
|
|
// C#
|
|
[TestCase(Language.CSharp, Resolution.Daily, 61)]
|
|
[TestCase(Language.CSharp, Resolution.Hour, 477)]
|
|
[TestCase(Language.CSharp, Resolution.Minute, 26670)]
|
|
// Python
|
|
[TestCase(Language.Python, Resolution.Daily, 61)]
|
|
[TestCase(Language.Python, Resolution.Hour, 477)]
|
|
[TestCase(Language.Python, Resolution.Minute, 26670)]
|
|
public void HistoryRequestWithDataMappingMode(Language language, Resolution resolution, int expectedHistoryCount)
|
|
{
|
|
var start = new DateTime(2013, 10, 6);
|
|
var end = new DateTime(2014, 1, 1);
|
|
var algorithm = GetAlgorithm(end);
|
|
var symbol = algorithm.AddFuture(Futures.Indices.SP500EMini, resolution, fillForward: true).Symbol;
|
|
|
|
var dataMappingModes = GetAllDataMappingModes();
|
|
var timeSpan = end - start;
|
|
var periods = expectedHistoryCount;
|
|
|
|
var expectedMappingDates = new List<DateTime>
|
|
{
|
|
// DataMappingMode.LastTradingDay (0)
|
|
new DateTime(2013, 12, 20),
|
|
// DataMappingMode.FirstDayMonth (1)
|
|
new DateTime(2013, 12, 02),
|
|
// DataMappingMode.OpenInterest (2)
|
|
new DateTime(2013, 12, 18),
|
|
// DataMappingMode.OpenInterestAnnual (3)
|
|
new DateTime(2013, 11, 18),
|
|
};
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// No symbol, time span
|
|
var historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(timeSpan, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// No symbol, periods
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(periods, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// No symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Single symbols, time span
|
|
var tradeBarHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(symbol, timeSpan, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Single symbols, periods
|
|
tradeBarHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(symbol, periods, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Single symbols, date range
|
|
tradeBarHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(symbol, start, end, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Symbol array, time span
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(new[] { symbol }, timeSpan, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount, resolution, expectedMappingDates);
|
|
|
|
// Symbol array, periods
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(new[] { symbol }, periods, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount, resolution, expectedMappingDates);
|
|
|
|
// Symbol array, date range
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(new[] { symbol }, start, end, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount, resolution, expectedMappingDates);
|
|
|
|
// Generic, no symbol, time span
|
|
var typedHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History<TradeBar>(timeSpan, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Generic, no symbol, periods
|
|
// TODO: to be implemented
|
|
|
|
// Generic, no symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Generic, single symbol, time span
|
|
tradeBarHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History<TradeBar>(symbol, timeSpan, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Generic, single symbol, periods
|
|
tradeBarHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History<TradeBar>(symbol, periods, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Generic, single symbol, date range
|
|
tradeBarHistoryResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History<TradeBar>(symbol, start, end, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Generic, symbol array, time span
|
|
typedHistoryResults = dataMappingModes
|
|
.Select(mappingMode =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, timeSpan, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Generic, symbol array, periods
|
|
typedHistoryResults = dataMappingModes
|
|
.Select(mappingMode =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, periods, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
|
|
// Generic, symbol array, date range
|
|
typedHistoryResults = dataMappingModes
|
|
.Select(mappingMode =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, start, end, resolution, dataMappingMode: mappingMode).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution,
|
|
expectedMappingDates);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule", @"
|
|
from AlgorithmImports import *
|
|
tradeBar = TradeBar
|
|
");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var pySymbol = symbol.ToPython();
|
|
using var pySymbols = new PyList(new[] { pySymbol });
|
|
using var pyTradeBar = testModule.GetAttr("tradeBar");
|
|
|
|
// Single symbols, time span
|
|
var historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pySymbol, timeSpan, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Single symbols, periods
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pySymbol, periods, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Single symbols, date range
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pySymbol, start, end, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, time span
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pySymbols, timeSpan, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, periods
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pySymbols, periods, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, date range
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pySymbols, start, end, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, time span
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, pySymbol, timeSpan, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, symbol, timeSpan, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, periods
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, pySymbol, periods, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, symbol, periods, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, date range
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, pySymbol, start, end, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar,symbol, start, end, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, time span
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, pySymbols, timeSpan, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, periods
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, pySymbols, periods, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, date range
|
|
historyResults = dataMappingModes
|
|
.Select(mappingMode => algorithm.History(pyTradeBar, pySymbols, start, end, resolution, dataMappingMode: mappingMode))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, symbol, expectedHistoryCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCaseSource(nameof(GetHistoryWithDataNormalizationModeTestCases))]
|
|
public void HistoryRequestWithDataNormalizationMode(Language language, Symbol symbol, Resolution resolution,
|
|
DateTime start, DateTime end, int expectedHistoryCount)
|
|
{
|
|
var algorithm = GetAlgorithm(end);
|
|
algorithm.AddSecurity(symbol, fillForward: true);
|
|
|
|
var dataNormalizationModes = symbol.SecurityType == SecurityType.Equity
|
|
? new[]
|
|
{
|
|
DataNormalizationMode.Raw,
|
|
DataNormalizationMode.Adjusted,
|
|
DataNormalizationMode.SplitAdjusted
|
|
}
|
|
: new[]
|
|
{
|
|
DataNormalizationMode.Raw,
|
|
DataNormalizationMode.BackwardsRatio,
|
|
DataNormalizationMode.BackwardsPanamaCanal,
|
|
DataNormalizationMode.ForwardPanamaCanal
|
|
};
|
|
var timeSpan = end - start;
|
|
// Request periods is used to get the start and end dates only, the actual number of periods is expectedHistoryCount
|
|
var periods = expectedHistoryCount;
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// No symbol, time span
|
|
var historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(timeSpan, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// No symbol, periods
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(periods, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// No symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Single symbols, time span
|
|
var tradeBarHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(symbol, timeSpan, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Single symbols, periods
|
|
tradeBarHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(symbol, periods, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Single symbols, date range
|
|
tradeBarHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(symbol, start, end, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Symbol array, time span
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(new[] { symbol }, timeSpan, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Symbol array, periods
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(new[] { symbol }, periods, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Symbol array, date range
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(new[] { symbol }, start, end, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, no symbol, time span
|
|
var typedHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History<TradeBar>(timeSpan, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, no symbol, periods
|
|
// TODO: to be implemented
|
|
|
|
// Generic, no symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Generic, single symbol, time span
|
|
tradeBarHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History<TradeBar>(symbol, timeSpan, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, single symbol, periods
|
|
tradeBarHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History<TradeBar>(symbol, periods, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, single symbol, date range
|
|
tradeBarHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History<TradeBar>(symbol, start, end, resolution,
|
|
dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, symbol array, time span
|
|
typedHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, timeSpan, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, symbol array, periods
|
|
typedHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, periods, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, symbol array, date range
|
|
typedHistoryResults = dataNormalizationModes
|
|
.Select(normalizationMode =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, start, end, resolution, dataNormalizationMode: normalizationMode).ToList())
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule", @"
|
|
from AlgorithmImports import *
|
|
tradeBar = TradeBar
|
|
");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var pySymbol = symbol.ToPython();
|
|
using var pySymbols = new PyList(new[] { pySymbol });
|
|
using var pyTradeBar = testModule.GetAttr("tradeBar");
|
|
|
|
// Single symbols, time span
|
|
var historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pySymbol, timeSpan, resolution, dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Single symbols, periods
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pySymbol, periods, resolution, dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Single symbols, date range
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pySymbol, start, end, resolution, dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, time span
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pySymbols, timeSpan, resolution, dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, periods
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pySymbols, periods, resolution, dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, date range
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pySymbols, start, end, resolution, dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, time span
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, pySymbol, timeSpan, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, symbol, timeSpan, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, periods
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, pySymbol, periods, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, symbol, periods, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, date range
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, pySymbol, start, end, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, symbol, start, end, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, time span
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, pySymbols, timeSpan, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, periods
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, pySymbols, periods, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, date range
|
|
historyResults = dataNormalizationModes
|
|
.Select(normalizationMode => algorithm.History(pyTradeBar, pySymbols, start, end, resolution,
|
|
dataNormalizationMode: normalizationMode))
|
|
.ToList();
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults, symbol, expectedHistoryCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
// C#
|
|
[TestCase(Language.CSharp, Resolution.Daily, 61)]
|
|
[TestCase(Language.CSharp, Resolution.Hour, 477)]
|
|
[TestCase(Language.CSharp, Resolution.Minute, 26670)]
|
|
// Python
|
|
[TestCase(Language.Python, Resolution.Daily, 61)]
|
|
[TestCase(Language.Python, Resolution.Hour, 477)]
|
|
[TestCase(Language.Python, Resolution.Minute, 26670)]
|
|
public void HistoryRequestWithContracDepthOffsets(Language language, Resolution resolution, int expectedHistoryCount)
|
|
{
|
|
var start = new DateTime(2013, 10, 07);
|
|
var end = new DateTime(2014, 1, 1);
|
|
var algorithm = GetAlgorithm(end);
|
|
var symbol = algorithm.AddFuture(Futures.Indices.SP500EMini, fillForward: true).Symbol;
|
|
|
|
var timeSpan = end - start;
|
|
// We are lacking minute data for the contract used for offset=2 on the request start date computed minute when using periods,
|
|
// So we use a slightly larger number of periods to compensate for that.
|
|
var periods = resolution != Resolution.Minute ? expectedHistoryCount : (int)(expectedHistoryCount * 1.001);
|
|
var offsets = new[] { 0, 1, 2 };
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
// No symbol, time span
|
|
var historyResults = offsets
|
|
.Select(offset => algorithm.History(timeSpan, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// No symbol, periods
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(periods, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// No symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Single symbols, time span
|
|
var tradeBarHistoryResults = offsets
|
|
.Select(offset => algorithm.History(symbol, timeSpan, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Single symbols, periods
|
|
tradeBarHistoryResults = offsets
|
|
.Select(offset => algorithm.History(symbol, periods, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Single symbols, date range
|
|
tradeBarHistoryResults = offsets
|
|
.Select(offset => algorithm.History(symbol, start, end, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Symbol array, time span
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(new[] { symbol }, timeSpan, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Symbol array, periods
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(new[] { symbol }, periods, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Symbol array, date range
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(new[] { symbol }, start, end, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, no symbol, time span
|
|
var typedHistoryResults = offsets
|
|
.Select(offset => algorithm.History<TradeBar>(timeSpan, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, no symbol, periods
|
|
// TODO: to be implemented
|
|
|
|
// Generic, no symbol, date range
|
|
// TODO: to be implemented
|
|
|
|
// Generic, single symbol, time span
|
|
tradeBarHistoryResults = offsets
|
|
.Select(offset => algorithm.History<TradeBar>(symbol, timeSpan, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, single symbol, periods
|
|
tradeBarHistoryResults = offsets
|
|
.Select(offset => algorithm.History<TradeBar>(symbol, periods, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, single symbol, date range
|
|
tradeBarHistoryResults = offsets
|
|
.Select(offset => algorithm.History<TradeBar>(symbol, start, end, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(tradeBarHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, symbol array, time span
|
|
typedHistoryResults = offsets
|
|
.Select(offset =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, timeSpan, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, symbol array, periods
|
|
typedHistoryResults = offsets
|
|
.Select(offset =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, periods, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
|
|
// Generic, symbol array, date range
|
|
typedHistoryResults = offsets
|
|
.Select(offset =>
|
|
algorithm.History<TradeBar>(new[] { symbol }, start, end, resolution, contractDepthOffset: offset).ToList())
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(typedHistoryResults, symbol, expectedHistoryCount, resolution);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
var testModule = PyModule.FromString("testModule", @"
|
|
from AlgorithmImports import *
|
|
tradeBar = TradeBar
|
|
");
|
|
|
|
algorithm.SetPandasConverter();
|
|
using var pySymbol = symbol.ToPython();
|
|
using var pySymbols = new PyList(new[] { pySymbol });
|
|
using var pyTradeBar = testModule.GetAttr("tradeBar");
|
|
|
|
// Single symbols, time span
|
|
var historyResults = offsets
|
|
.Select(offset => algorithm.History(pySymbol, timeSpan, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Single symbols, periods
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pySymbol, periods, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Single symbols, date range
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pySymbol, start, end, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, time span
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pySymbols, timeSpan, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, periods
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pySymbols, periods, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Symbol array, date range
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pySymbols, start, end, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, time span
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, pySymbol, timeSpan, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, symbol, timeSpan, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, periods
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, pySymbol, periods, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, symbol, periods, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, single symbol, date range
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, pySymbol, start, end, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
// Same as previous but using a Symbol instead of pySymbol
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, symbol, start, end, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, time span
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, pySymbols, timeSpan, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, periods
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, pySymbols, periods, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
|
|
// Generic, symbol array, date range
|
|
historyResults = offsets
|
|
.Select(offset => algorithm.History(pyTradeBar, pySymbols, start, end, resolution, contractDepthOffset: offset))
|
|
.ToList();
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(historyResults, symbol, expectedHistoryCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
// USA Equity market hours: 4am-9:30am (pre-market), 9:30am-4pm (regular market), 4pm-8pm (post-market)
|
|
// 6.5h (regular market duration) (rounded to 7)
|
|
[TestCase(Resolution.Hour, false, false, 7)]
|
|
// Hour resolution doesn't have extended hours data
|
|
[TestCase(Resolution.Hour, false, true, 7)]
|
|
[TestCase(Resolution.Hour, true, false, 7)]
|
|
[TestCase(Resolution.Hour, true, true, 7)]
|
|
[TestCase(Resolution.Hour, false, null, 7)]
|
|
[TestCase(Resolution.Hour, true, null, 7)]
|
|
// 390 = 6.5h (regular market duration) * 60min/h = 390min (bars)
|
|
[TestCase(Resolution.Minute, false, false, 390)]
|
|
// 960 = [5.5h (pre-market duration) + 6.5h (regular market duration) + 4h (post-market duration)] * 60min/h = 16h * 60min/h = 960min (bars)
|
|
[TestCase(Resolution.Minute, false, true, 960)]
|
|
[TestCase(Resolution.Minute, true, false, 390)]
|
|
[TestCase(Resolution.Minute, true, true, 960)]
|
|
[TestCase(Resolution.Minute, false, null, 390)]
|
|
[TestCase(Resolution.Minute, true, null, 960)]
|
|
[TestCase(Resolution.Second, false, false, 390 * 60)]
|
|
[TestCase(Resolution.Second, false, true, 960 * 60)]
|
|
[TestCase(Resolution.Second, true, false, 390 * 60)]
|
|
[TestCase(Resolution.Second, true, true, 960 * 60)]
|
|
[TestCase(Resolution.Second, false, null, 390 * 60)]
|
|
[TestCase(Resolution.Second, true, null, 960 * 60)]
|
|
public void HistoryRequestFactoryGetsTheRightStartTimeForBarCount(Resolution resolution, bool assetWithExtendedMarket,
|
|
bool? requestWithExtendedMarket, int requestPeriods)
|
|
{
|
|
var start = new DateTime(2014, 06, 09);
|
|
var end = new DateTime(2014, 06, 10);
|
|
var algorithm = GetAlgorithm(end);
|
|
var aapl = algorithm.AddEquity("AAPL", extendedMarketHours: assetWithExtendedMarket);
|
|
var config = algorithm.SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(aapl.Symbol).First();
|
|
var exchangeHours = aapl.Exchange.Hours;
|
|
|
|
var historyRequestFactory = new HistoryRequestFactory(algorithm);
|
|
var extendedMarket = resolution != Resolution.Hour ? requestWithExtendedMarket ?? assetWithExtendedMarket : false;
|
|
var marketOpen = exchangeHours.GetNextMarketOpen(start, extendedMarketHours: extendedMarket);
|
|
if (resolution == Resolution.Hour)
|
|
{
|
|
// Adjust the expected start in case the regular hours segment is not an exact int number of hours
|
|
var marketClose = exchangeHours.GetNextMarketClose(marketOpen, extendedMarketHours: extendedMarket);
|
|
marketOpen += TimeSpan.FromHours((marketClose.TimeOfDay - marketOpen.TimeOfDay).TotalHours - requestPeriods);
|
|
}
|
|
|
|
var requestStart = historyRequestFactory.GetStartTimeAlgoTz(aapl.Symbol, requestPeriods, resolution, exchangeHours,
|
|
config.DataTimeZone, extendedMarketHours: requestWithExtendedMarket);
|
|
Assert.AreEqual(marketOpen, requestStart);
|
|
}
|
|
|
|
// This reproduces https://github.com/QuantConnect/Lean/issues/7504
|
|
[TestCase(Language.CSharp)]
|
|
[TestCase(Language.Python)]
|
|
public void DefaultAlwaysOpenMarketHoursForBaseSecurityType(Language language)
|
|
{
|
|
var start = new DateTime(2013, 10, 8);
|
|
var end = start.AddDays(1);
|
|
var algorithm = GetAlgorithm(end);
|
|
|
|
if (language == Language.CSharp)
|
|
{
|
|
var spy = algorithm.AddEquity("SPY").Symbol;
|
|
// We will try to fetch history without a subscription
|
|
var customSymbol = Symbol.CreateBase(typeof(CustomData), spy);
|
|
|
|
List<CustomData> history = null;
|
|
Assert.DoesNotThrow(() => history = algorithm.History<CustomData>(customSymbol, start, end, Resolution.Minute).ToList());
|
|
Console.WriteLine(history.Count);
|
|
Assert.IsNotEmpty(history);
|
|
}
|
|
else
|
|
{
|
|
using (Py.GIL())
|
|
{
|
|
dynamic getHistory = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
from QuantConnect.Tests import *
|
|
|
|
class TestPythonCustomData(PythonData):
|
|
def GetSource(self, config, date, isLiveMode):
|
|
fileName = LeanData.GenerateZipFileName(Symbols.SPY, date, config.Resolution, config.TickType)
|
|
source = f'{Globals.DataFolder}equity/usa/minute/spy/{fileName}'
|
|
return SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv)
|
|
|
|
def Reader(self, config, line, date, isLiveMode):
|
|
data = line.split(',')
|
|
|
|
result = TestPythonCustomData()
|
|
result.DataType = MarketDataType.Base
|
|
result.Symbol = config.Symbol
|
|
result.Time = date.date() + timedelta(milliseconds=int(data[0]))
|
|
result.Value = float(data[4])
|
|
result[""Open""] = float(data[1])
|
|
result[""High""] = float(data[2])
|
|
result[""Low""] = float(data[3])
|
|
result[""Close""] = float(data[4])
|
|
|
|
return result
|
|
|
|
def getHistory(algorithm, start, end):
|
|
spy = algorithm.AddEquity(""SPY"").Symbol
|
|
customSymbol = Symbol.CreateBase(TestPythonCustomData, spy, Market.USA)
|
|
|
|
return algorithm.History(TestPythonCustomData, customSymbol, start, end, Resolution.Minute)
|
|
").GetAttr("getHistory");
|
|
|
|
algorithm.SetPandasConverter();
|
|
|
|
dynamic history = null;
|
|
Assert.DoesNotThrow(() => history = getHistory(algorithm, start, end));
|
|
Assert.IsNotNull(history);
|
|
Assert.Greater(history.shape[0].As<int>(), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void PythonCustomDataThrowing()
|
|
{
|
|
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
|
algorithm.SetHistoryProvider(new ThrowingHistoryProvider());
|
|
|
|
using (Py.GIL())
|
|
{
|
|
PythonInitializer.Initialize();
|
|
algorithm.SetPandasConverter();
|
|
|
|
var testModule = PyModule.FromString("testModule",
|
|
@"
|
|
from AlgorithmImports import *
|
|
|
|
def getHistory(algorithm, symbol, period):
|
|
return algorithm.History(symbol, period, Resolution.Minute)
|
|
");
|
|
dynamic getDateRangeHistory = testModule.GetAttr("getHistory");
|
|
|
|
Assert.Throws<ClrBubbledException>(() => getDateRangeHistory(algorithm, Symbols.AAPL, 10));
|
|
}
|
|
}
|
|
|
|
private class ThrowingHistoryProvider : HistoryProviderBase
|
|
{
|
|
public override int DataPointCount => 0;
|
|
|
|
public override IEnumerable<Slice> GetHistory(IEnumerable<HistoryRequest> requests, DateTimeZone sliceTimeZone)
|
|
{
|
|
throw new Exception("Expected exception");
|
|
yield return null;
|
|
}
|
|
|
|
public override void Initialize(HistoryProviderInitializeParameters parameters)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static TestCaseData[] GetHistoryWithDataNormalizationModeTestCases()
|
|
{
|
|
var equityStart = new DateTime(2014, 06, 05); // There is an AAPL split on 2014/06/06
|
|
var futureStart = new DateTime(2013, 12, 18); // There is an ES contract mapping on 2013/12/19
|
|
|
|
return new[] { Language.CSharp, Language.Python }.SelectMany(language =>
|
|
{
|
|
return new[]
|
|
{
|
|
// Test cases for equity
|
|
new TestCaseData(language, Symbols.AAPL, Resolution.Daily, equityStart, equityStart.AddDays(100), 70),
|
|
new TestCaseData(language, Symbols.AAPL, Resolution.Hour, equityStart, equityStart.AddDays(20), 98),
|
|
new TestCaseData(language, Symbols.AAPL, Resolution.Minute, equityStart, equityStart.AddDays(1), 390),
|
|
|
|
// Test cases for futures
|
|
new TestCaseData(language, Symbols.ES_Future_Chain, Resolution.Daily, futureStart, futureStart.AddDays(100), 70),
|
|
new TestCaseData(language, Symbols.ES_Future_Chain, Resolution.Hour, futureStart, futureStart.AddDays(20), 93),
|
|
new TestCaseData(language, Symbols.ES_Future_Chain, Resolution.Minute, futureStart, futureStart.AddDays(2), 900),
|
|
};
|
|
}).ToArray();
|
|
}
|
|
|
|
private QCAlgorithm GetAlgorithm(DateTime dateTime)
|
|
{
|
|
var algorithm = new QCAlgorithm();
|
|
algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
|
|
algorithm.HistoryProvider = new SubscriptionDataReaderHistoryProvider();
|
|
algorithm.SetDateTime(dateTime.ConvertToUtc(algorithm.TimeZone));
|
|
|
|
algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
|
|
null,
|
|
null,
|
|
_dataProvider,
|
|
_cacheProvider,
|
|
_mapFileProvider,
|
|
_factorFileProvider,
|
|
null,
|
|
false,
|
|
new DataPermissionManager(),
|
|
algorithm.ObjectStore));
|
|
return algorithm;
|
|
}
|
|
|
|
private class TestHistoryProvider : HistoryProviderBase
|
|
{
|
|
public override int DataPointCount { get; }
|
|
public List<HistoryRequest> HistryRequests { get; } = new List<HistoryRequest>();
|
|
|
|
public List<Slice> Slices { get; set; } = new List<Slice>();
|
|
|
|
public override void Initialize(HistoryProviderInitializeParameters parameters)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override IEnumerable<Slice> GetHistory(IEnumerable<HistoryRequest> requests, DateTimeZone sliceTimeZone)
|
|
{
|
|
foreach (var request in requests)
|
|
{
|
|
HistryRequests.Add(request);
|
|
}
|
|
|
|
if (!requests.Any()) return Enumerable.Empty<Slice>().ToList();
|
|
|
|
var startTime = requests.Min(x => x.StartTimeUtc.ConvertFromUtc(x.DataTimeZone));
|
|
var endTime = requests.Max(x => x.EndTimeUtc.ConvertFromUtc(x.DataTimeZone));
|
|
|
|
return Slices.Where(x => x.Time >= startTime && x.Time <= endTime).ToList();
|
|
}
|
|
}
|
|
|
|
public class CustomData : TradeBar
|
|
{
|
|
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
|
{
|
|
var source = Path.Combine(Globals.DataFolder, "equity", "usa", config.Resolution.ToString().ToLower(),
|
|
Symbols.SPY.Value.ToLowerInvariant(), LeanData.GenerateZipFileName(Symbols.SPY, date, config.Resolution, config.TickType));
|
|
return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv);
|
|
}
|
|
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
|
{
|
|
var baseData = base.Reader(new SubscriptionDataConfig(config, symbol: Symbols.SPY), line, date, isLiveMode);
|
|
|
|
return new CustomData
|
|
{
|
|
DataType = MarketDataType.Base,
|
|
Symbol = config.Symbol,
|
|
Time = baseData.EndTime,
|
|
Value = baseData.Price
|
|
};
|
|
}
|
|
}
|
|
|
|
private QCAlgorithm GetAlgorithmWithEquity(DateTime dateTime)
|
|
{
|
|
var resolution = Resolution.Minute;
|
|
var algorithm = GetAlgorithm(dateTime);
|
|
algorithm.AddEquity("AAPL", resolution);
|
|
|
|
return algorithm;
|
|
}
|
|
|
|
private QCAlgorithm GetAlgorithmWithFuture(DateTime dateTime)
|
|
{
|
|
var resolution = Resolution.Daily;
|
|
var algorithm = GetAlgorithm(dateTime);
|
|
algorithm.AddFuture(Futures.Indices.SP500EMini, resolution, extendedMarketHours: true);
|
|
|
|
return algorithm;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to check that all history results have the same bar count
|
|
/// </summary>
|
|
private static void CheckThatHistoryResultsHaveEqualBarCount<T>(IEnumerable<IEnumerable<T>> historyResults, int expectedHistoryCount)
|
|
{
|
|
Assert.That(historyResults, Has.All.Not.Empty.And.All.Count.EqualTo(expectedHistoryCount),
|
|
$@"Expected all history results to have {expectedHistoryCount} slices, but counts where {
|
|
string.Join(", ", historyResults.Select(x => x.Count()))}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to check that all history data frame results have the same bar count
|
|
/// </summary>
|
|
private static void CheckThatHistoryResultsHaveEqualBarCount(List<PyObject> historyResults, int expectedHistoryCount)
|
|
{
|
|
Assert.Greater(expectedHistoryCount, 0);
|
|
var historyCounts = historyResults.Select(x => x.GetAttr("shape")[0].As<int>()).ToList();
|
|
Assert.IsTrue(historyCounts.All(count => count == expectedHistoryCount),
|
|
$"Expected all history results to have {expectedHistoryCount} slices/bars, but counts where {string.Join(", ", historyCounts)}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to check that, for each history result, prices at each time are different
|
|
/// </summary>
|
|
private static void CheckThatHistoryResultsHaveDifferentPrices(List<List<BaseData>> historyResults, string message)
|
|
{
|
|
for (int i = 0; i < historyResults[0].Count; i++)
|
|
{
|
|
var prices = historyResults.Select(hr => hr[i].Price).ToHashSet();
|
|
Assert.AreEqual(historyResults.Count, prices.Count, message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to check that, for each history result, prices at each time are different
|
|
/// </summary>
|
|
private static void CheckThatHistoryResultsHaveDifferentPrices(IEnumerable<IEnumerable<Slice>> historyResults, string message)
|
|
{
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults.Select(hr => hr.Select(x => x.Values.First()).ToList()).ToList(), message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to check that, for each history data frame result, prices at each time are different
|
|
/// </summary>
|
|
private static void CheckThatHistoryResultsHaveDifferentPrices(List<PyObject> historyResults, string message)
|
|
{
|
|
var closesPerResult = historyResults.Select(hr => hr["close"].GetAttr("values").GetAttr("tolist").Invoke().As<List<decimal>>()).ToList();
|
|
|
|
for (int i = 0; i < closesPerResult.First().Count; i++)
|
|
{
|
|
var closePrices = closesPerResult.Select(close => close[i]).ToHashSet();
|
|
Assert.AreEqual(historyResults.Count, closePrices.Count, message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to perform history checks on different data normalization modes
|
|
/// </summary>
|
|
private static void CheckHistoryResultsForDataNormalizationModes(QCAlgorithm algorithm, Symbol symbol, DateTime start,
|
|
DateTime end, Resolution resolution, DataNormalizationMode[] dataNormalizationModes, int expectedHistoryCount)
|
|
{
|
|
var historyResults = dataNormalizationModes
|
|
.Select(x => algorithm.History(new [] { symbol }, start, end, resolution, dataNormalizationMode: x).ToList())
|
|
.ToList();
|
|
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data normalization mode at each time");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to perform history checks on different data normalization modes
|
|
/// </summary>
|
|
private static void CheckHistoryResultsForDataNormalizationModes(QCAlgorithm algorithm, PyObject symbol, DateTime start,
|
|
DateTime end, Resolution resolution, DataNormalizationMode[] dataNormalizationModes, int expectedHistoryCount)
|
|
{
|
|
var historyResults = dataNormalizationModes
|
|
.Select(x => algorithm.History(symbol, start, end, resolution, dataNormalizationMode: x))
|
|
.ToList();
|
|
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data normalization mode at each time");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to assert that the right custom data history is fetched
|
|
/// </summary>
|
|
private static void AssertCustomDataTypeHistory<T>(List<T> history)
|
|
where T : IBaseData
|
|
{
|
|
Assert.AreEqual(1539, history.Count);
|
|
Assert.That(history, Has.All.Property("DataType").EqualTo(MarketDataType.Base));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper method to assert that the right custom data history is fetched
|
|
/// </summary>
|
|
private static void AssertCustomDataTypeHistory<T>(List<DataDictionary<T>> history)
|
|
where T : IBaseData
|
|
{
|
|
Assert.AreEqual(1539, history.Count);
|
|
Assert.That(history.Select(x => x.Single().Value), Has.All.Property("DataType").EqualTo(MarketDataType.Base));
|
|
}
|
|
|
|
private static DataMappingMode[] GetAllDataMappingModes()
|
|
{
|
|
return (DataMappingMode[])Enum.GetValues(typeof(DataMappingMode));
|
|
}
|
|
|
|
private static DataNormalizationMode[] GetAllDataNormalizationModes()
|
|
{
|
|
return (DataNormalizationMode[])Enum.GetValues(typeof(DataNormalizationMode));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts history result has the expected count
|
|
/// </summary>
|
|
private static void AssertHistoryResultCount<T>(List<T> history, int expectedCount)
|
|
{
|
|
Assert.IsNotEmpty(history);
|
|
Assert.AreEqual(expectedCount, history.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with fillForward set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/> for Python cases.
|
|
/// </summary>
|
|
private static void AssertHistoryResultCount(PyObject history, int expectedCount)
|
|
{
|
|
var historyCount = history.GetAttr("shape")[0].As<int>();
|
|
Assert.Greater(historyCount, 0);
|
|
Assert.AreEqual(expectedCount, historyCount);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that data from a history request has the expected resolution
|
|
/// </summary>
|
|
private static void AssertHistoryResultResolution(IEnumerable<BaseData> history, Resolution resolution)
|
|
{
|
|
var expectedTimeSpan = resolution.ToTimeSpan();
|
|
Assert.IsTrue(history.All(data => data.EndTime - data.Time == expectedTimeSpan));
|
|
}
|
|
|
|
private static List<PyObject> GetHistoryDataFrameIndex(PyObject history)
|
|
{
|
|
return history
|
|
.GetAttr("index")
|
|
.GetAttr("to_flat_index").Invoke()
|
|
.GetAttr("tolist").Invoke()
|
|
.As<List<PyObject>>();
|
|
}
|
|
|
|
private static List<Symbol> GetSymbolsFromHistoryDataFrameIndex(List<PyObject> index)
|
|
{
|
|
dynamic builtins = Py.Import("builtins");
|
|
return index.Select(x => x[builtins.len(x) > 2 ? 1 : 0].As<Symbol>()).ToList();
|
|
}
|
|
|
|
private static List<DateTime> GetTimesFromHistoryDataFrameIndex(List<PyObject> index)
|
|
{
|
|
dynamic builtins = Py.Import("builtins");
|
|
return index.Select(x => x[builtins.len(x) > 2 ? 2 : 1].As<DateTime>()).ToList();
|
|
}
|
|
|
|
#region Fill-forwarded history assertions
|
|
|
|
/// <summary>
|
|
/// Asserts that fill forwarded history results has data for every period in the requested time span
|
|
/// </summary>
|
|
private static void AssertFillForwardedHistoryTimes(Symbol symbol, List<DateTime> times, TimeSpan period)
|
|
{
|
|
var hours = MarketHoursDatabase.FromDataFolder().GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType).ExchangeHours;
|
|
|
|
// We are assuming one regular segment per day for the test security
|
|
var periodMultiplier = 0;
|
|
var baseSegmentTimeIndex = 0;
|
|
for (var i = 0; i < times.Count; i++)
|
|
{
|
|
var currentTime = times[i];
|
|
if (i > 0 && currentTime.DayOfWeek != times[i - 1].DayOfWeek)
|
|
{
|
|
baseSegmentTimeIndex = i;
|
|
periodMultiplier = 0;
|
|
}
|
|
|
|
var expectedCurrentTime = times[baseSegmentTimeIndex] + periodMultiplier++ * period;
|
|
Assert.AreEqual(expectedCurrentTime, currentTime);
|
|
Assert.IsTrue(
|
|
// subtract `period` since the times list has the EndTime
|
|
hours.IsOpen(currentTime - period, extendedMarketHours: false),
|
|
$"Current time {currentTime} is not open");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history data, when called with fillForward set to true, has a period that is equal to the resolution used.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/>.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryData(List<TradeBar> history, Resolution resolution, bool fillForward)
|
|
{
|
|
var expectedPeriod = resolution.ToTimeSpan();
|
|
Assert.IsTrue(history.All(bar => bar.Period == expectedPeriod));
|
|
|
|
if (fillForward)
|
|
{
|
|
var symbol = history.First().Symbol;
|
|
var times = history.Select(bar => bar.EndTime).ToList();
|
|
AssertFillForwardedHistoryTimes(symbol, times, expectedPeriod);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history data, when called with fillForward set to true, has a period that is equal to the resolution used.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/>.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryData(List<Slice> history, Resolution resolution, bool fillForward)
|
|
{
|
|
AssertFillForwardHistoryData(
|
|
history.Select(slice => slice.Bars.Values.SingleOrDefault((TradeBar)null)).Where(bar => bar != null).ToList(),
|
|
resolution,
|
|
fillForward);
|
|
}
|
|
|
|
///// <summary>
|
|
/// Asserts that history data, when called with fillForward set to true, has a period that is equal to the resolution used.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/>.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryData(List<DataDictionary<TradeBar>> history, Resolution resolution, bool fillForward)
|
|
{
|
|
AssertFillForwardHistoryData(
|
|
history.Select(x => x.Values.SingleOrDefault((TradeBar)null)).Where(bar => bar != null).ToList(),
|
|
resolution,
|
|
fillForward);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with fillForward set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/>.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryResults(List<TradeBar> history, int expectedCount, Resolution resolution, bool fillForward)
|
|
{
|
|
AssertHistoryResultCount(history, expectedCount);
|
|
AssertFillForwardHistoryData(history, resolution, fillForward);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with fillForward set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/>.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryResults(List<Slice> history, int expectedCount, Resolution resolution, bool fillForward)
|
|
{
|
|
AssertHistoryResultCount(history, expectedCount);
|
|
AssertFillForwardHistoryData(history, resolution, fillForward);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with fillForward set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/>.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryResults(List<DataDictionary<TradeBar>> history, int expectedCount,
|
|
Resolution resolution, bool fillForward)
|
|
{
|
|
AssertHistoryResultCount(history, expectedCount);
|
|
AssertFillForwardHistoryData(history, resolution, fillForward);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with fillForward set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithFillForward"/> for Python cases.
|
|
/// </summary>
|
|
private static void AssertFillForwardHistoryResults(PyObject history, int expectedCount, Resolution resolution, bool fillForward)
|
|
{
|
|
AssertHistoryResultCount(history, expectedCount);
|
|
|
|
if (fillForward)
|
|
{
|
|
var index = GetHistoryDataFrameIndex(history);
|
|
var symbols = GetSymbolsFromHistoryDataFrameIndex(index);
|
|
var times = GetTimesFromHistoryDataFrameIndex(index);
|
|
AssertFillForwardedHistoryTimes(symbols[0], times, resolution.ToTimeSpan());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region History with extended market assertions
|
|
|
|
/// <summary>
|
|
/// Asserts that history with/without extended market results has data for regular hour segments and extended market segments, respectively.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryTimes(Symbol symbol, List<DateTime> times, bool extendedMarket)
|
|
{
|
|
var hours = MarketHoursDatabase.FromDataFolder().GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType).ExchangeHours;
|
|
|
|
var getTimesCheck = (bool inExtendedHours) => (DateTime time) =>
|
|
{
|
|
var currentDayHours = hours.GetMarketHours(time);
|
|
var segments = currentDayHours.Segments
|
|
.Where(x => inExtendedHours
|
|
? x.State != MarketHoursState.Market
|
|
: x.State == MarketHoursState.Market);
|
|
return segments.Any(segment => time.TimeOfDay > segment.Start && time.TimeOfDay <= segment.End);
|
|
};
|
|
var timeIsInRegularHours = getTimesCheck(false);
|
|
var timeIsInExtendedHours = getTimesCheck(true);
|
|
|
|
if (!extendedMarket)
|
|
{
|
|
Assert.IsTrue(times.All(timeIsInRegularHours));
|
|
}
|
|
else
|
|
{
|
|
Assert.IsTrue(times.Any(timeIsInRegularHours));
|
|
Assert.IsTrue(times.Any(timeIsInExtendedHours));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history with/without extended market results has data for regular hour segments and extended market segments, respectively.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResultsData(List<BaseData> history, bool extendedMarket, Resolution resolution,
|
|
Symbol expectedSymbol)
|
|
{
|
|
Assert.IsTrue(history.All(data => data.Symbol == expectedSymbol));
|
|
var times = history.Select(bar => bar.EndTime).ToList();
|
|
AssertExtendedMarketHistoryTimes(expectedSymbol, times, extendedMarket);
|
|
AssertHistoryResultResolution(history, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history with/without extended market results has data for regular hour segments and extended market segments, respectively.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResultsData(List<Slice> history, bool extendedMarket, Resolution resolution,
|
|
Symbol expectedSymbol)
|
|
{
|
|
var data = history.Select(slice => slice.Bars.Values.Cast<BaseData>().Concat(slice.QuoteBars.Values.Cast<BaseData>())).SelectMany(x => x);
|
|
Assert.IsTrue(data.All(x => x.Symbol == expectedSymbol));
|
|
|
|
var times = data.Select(x => x.EndTime).ToList();
|
|
AssertExtendedMarketHistoryTimes(expectedSymbol, times, extendedMarket);
|
|
AssertHistoryResultResolution(data, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with extendedMarket set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithExtendedMarket"/>.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResults(List<TradeBar> history, int expectedHistoryCount, bool extendedMarket,
|
|
Resolution resolution, Symbol expectedSymbol)
|
|
{
|
|
AssertHistoryResultCount(history, expectedHistoryCount);
|
|
AssertExtendedMarketHistoryResultsData(history.Cast<BaseData>().ToList(), extendedMarket, resolution, expectedSymbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with extendedMarket set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithExtendedMarket"/>.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResults(List<Slice> history, int expectedHistoryCount, bool extendedMarket,
|
|
Resolution resolution, Symbol expectedSymbol)
|
|
{
|
|
AssertHistoryResultCount(history, expectedHistoryCount);
|
|
AssertExtendedMarketHistoryResultsData(history, extendedMarket, resolution, expectedSymbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with extendedMarket set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithExtendedMarket"/>.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResults(List<DataDictionary<TradeBar>> history, int expectedHistoryCount, bool extendedMarket,
|
|
Resolution resolution, Symbol expectedSymbol)
|
|
{
|
|
AssertHistoryResultCount(history, expectedHistoryCount);
|
|
AssertExtendedMarketHistoryResultsData(history.Select(dict => dict.Values.First()).Cast<BaseData>().ToList(), extendedMarket, resolution,
|
|
expectedSymbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with extendedMarket set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithExtendedMarket"/>.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResults(List<Tick> history, int expectedHistoryCount, bool extendedMarket,
|
|
Resolution resolution, Symbol expectedSymbol)
|
|
{
|
|
AssertHistoryResultCount(history, expectedHistoryCount);
|
|
AssertExtendedMarketHistoryResultsData(history.Cast<BaseData>().ToList(), extendedMarket, resolution, expectedSymbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with extendedMarket set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithExtendedMarket"/>.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResults(List<DataDictionary<Tick>> history, int expectedHistoryCount, bool extendedMarket,
|
|
Resolution resolution, Symbol expectedSymbol)
|
|
{
|
|
AssertExtendedMarketHistoryResults(history.SelectMany(dict => dict.Values).ToList(), expectedHistoryCount, extendedMarket, resolution,
|
|
expectedSymbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history result has more data when called with extendedMarket set to true.
|
|
/// Used in the test <see cref="HistoryRequestWithExtendedMarket"/> for Python cases.
|
|
/// </summary>
|
|
private static void AssertExtendedMarketHistoryResults(PyObject history, int expectedHistoryCount, bool extendedMarket,
|
|
Resolution resolution, Symbol expectedSymbol)
|
|
{
|
|
AssertHistoryResultCount(history, expectedHistoryCount);
|
|
|
|
var index = GetHistoryDataFrameIndex(history);
|
|
var symbols = GetSymbolsFromHistoryDataFrameIndex(index);
|
|
Assert.IsTrue(symbols.All(x => x == expectedSymbol));
|
|
var times = GetTimesFromHistoryDataFrameIndex(index);
|
|
AssertExtendedMarketHistoryTimes(expectedSymbol, times, extendedMarket);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region History with different data mapping modes assertions
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data mapping mode, each has its expected mapping date, that is,
|
|
/// the date when underlying symbol change due to contract expiration.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentMappingModesResults(List<List<TradeBar>> historyResults, Symbol expectedSymbol,
|
|
int expectedHistoryCount, Resolution resolution, List<DateTime> expectedMappingDates)
|
|
{
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
|
|
// Check that all history results have a mapping date at some point in the history
|
|
for (var i = 0; i < historyResults.Count; i++)
|
|
{
|
|
var history = historyResults[i];
|
|
var prevUnderlying = history[0].Symbol.Underlying;
|
|
var mappingDates = new List<DateTime>();
|
|
|
|
foreach (var bar in history)
|
|
{
|
|
Assert.AreEqual(expectedSymbol, bar.Symbol, $"All bars symbol must have been {expectedSymbol} but found {bar.Symbol}");
|
|
|
|
var currentUnderlying = bar.Symbol.Underlying;
|
|
if (currentUnderlying != prevUnderlying)
|
|
{
|
|
mappingDates.Add(bar.EndTime.Date);
|
|
prevUnderlying = currentUnderlying;
|
|
}
|
|
}
|
|
|
|
Assert.AreEqual(1, mappingDates.Count, "We are expecting only one mapping for this case.");
|
|
var expectedMappingDate = expectedMappingDates[i];
|
|
Assert.AreEqual(expectedMappingDate, mappingDates[0],
|
|
$"Mapping date {mappingDates[0]} for {i}th history result is not the expected one {expectedMappingDate}.");
|
|
|
|
AssertHistoryResultResolution(history, resolution);
|
|
}
|
|
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults.Select(history => history.Cast<BaseData>().ToList()).ToList(),
|
|
"History results prices should have been different for each data mapping mode at each time");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data mapping mode, each has its expected mapping date.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentMappingModesResults(List<List<Slice>> historyResults, Symbol expectedSymbol,
|
|
int expectedHistoryCount, Resolution resolution, List<DateTime> expectedMappingDates)
|
|
{
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults.Select(x => x.Select(y => y.Bars.Values.First()).ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution, expectedMappingDates);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data mapping mode, each has its expected mapping date.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentMappingModesResults(List<List<DataDictionary<TradeBar>>> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount, Resolution resolution, List<DateTime> expectedMappingDates)
|
|
{
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults.Select(x => x.Select(y => y[expectedSymbol]).ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution, expectedMappingDates);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of Python history results, one for a different data mapping mode,
|
|
/// the result counts are the same and contain different prices.
|
|
/// In the data frames we don't have access to the actual mapping dates, so we cannot do the same checks we do for C# in
|
|
/// <see cref="AssertFuturesHistoryWithDifferentMappingModesResults(List{List{TradeBar}}, Symbol, int, Resolution, List{DateTime})"/>.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentMappingModesResults(List<PyObject> historyResults, Symbol expectedSymbol,
|
|
int expectedHistoryCount)
|
|
{
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults,
|
|
"History results prices should have been different for each data mapping mode at each time");
|
|
|
|
foreach (var history in historyResults)
|
|
{
|
|
var index = GetHistoryDataFrameIndex(history);
|
|
var symbols = GetSymbolsFromHistoryDataFrameIndex(index);
|
|
Assert.IsTrue(symbols.All(x => x == expectedSymbol));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region History with different data normalization modes assertions
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data normalization mode, prices are different for each time.
|
|
/// </summary>
|
|
private static void AssertHistoryWithDifferentNormalizationModesResults(List<List<TradeBar>> historyResults, Symbol expectedSymbol,
|
|
int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults.Select(history => history.Cast<BaseData>().ToList()).ToList(),
|
|
"History results prices should have been different for each data normalization mode at each time");
|
|
|
|
// Assert resolution and symbol
|
|
foreach (var history in historyResults)
|
|
{
|
|
AssertHistoryResultResolution(history, resolution);
|
|
foreach (var bar in history)
|
|
{
|
|
Assert.AreEqual(expectedSymbol, bar.Symbol, $"All bars symbol must have been {expectedSymbol} but found {bar.Symbol}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data normalization mode, prices are different for each time.
|
|
/// </summary>
|
|
private static void AssertHistoryWithDifferentNormalizationModesResults(List<List<Slice>> historyResults, Symbol expectedSymbol,
|
|
int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults.Select(x => x.Select(y => y.Bars.Values.First()).ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data normalization mode, prices are different for each time.
|
|
/// </summary>
|
|
private static void AssertHistoryWithDifferentNormalizationModesResults(List<List<DataDictionary<TradeBar>>> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
AssertHistoryWithDifferentNormalizationModesResults(historyResults.Select(x => x.Select(y => y[expectedSymbol]).ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that for a list of history results, one for a different data normalization mode, prices are different for each time.
|
|
/// </summary>
|
|
private static void AssertHistoryWithDifferentNormalizationModesResults(List<PyObject> historyResults, Symbol expectedSymbol,
|
|
int expectedHistoryCount)
|
|
{
|
|
// These are the same checks done for mapping modes, even regardless of the security type
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, expectedSymbol, expectedHistoryCount);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region History with different contract depth offsets assertions
|
|
|
|
/// <summary>
|
|
/// Asserts that history request with different contract depth offsets results have the expected mapped symbol depending on the offset used.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(List<List<BaseData>> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
CheckThatHistoryResultsHaveEqualBarCount(historyResults, expectedHistoryCount);
|
|
|
|
var futureChainProvider = new BacktestingFutureChainProvider(TestGlobals.DataCacheProvider);
|
|
var firstDateTime = historyResults[0][0].EndTime;
|
|
var futureChain = futureChainProvider.GetFutureContractList(expectedSymbol, firstDateTime).ToList();
|
|
|
|
// Check that the first mapped contract corresponds to the one in the future chain depending on the depth offset used,
|
|
// where historyResults[i] is the history result for contract depth offset = i
|
|
for (var i = 0; i < historyResults.Count; i++)
|
|
{
|
|
var history = historyResults[i];
|
|
var firstMappedContractSymbol = history[0].Symbol.Underlying;
|
|
|
|
Assert.AreEqual(futureChain[i], firstMappedContractSymbol,
|
|
$@"History[{i}]: Expected the first mapped contract to be the one on index {i} ({futureChain[i]
|
|
}) in the chain for date {firstDateTime}.");
|
|
|
|
// Finally, assert the resolution and symbol
|
|
AssertHistoryResultResolution(history, resolution);
|
|
Assert.IsTrue(history.All(x => x.Symbol == expectedSymbol));
|
|
}
|
|
|
|
CheckThatHistoryResultsHaveDifferentPrices(historyResults.Select(history => history.Cast<BaseData>().ToList()).ToList(),
|
|
"History results prices should have been different for each available offset at each time");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history request with different contract depth offsets results have the expected mapped symbol depending on the offset used.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(List<List<TradeBar>> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(
|
|
historyResults.Select(history => history.Cast<BaseData>().ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history request with different contract depth offsets results have the expected mapped symbol depending on the offset used.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(List<List<Slice>> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(
|
|
historyResults.Select(x => x.Select(y => (BaseData)y.Bars.Values.FirstOrDefault() ?? y.QuoteBars.Values.First()).ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history request with different contract depth offsets results have the expected mapped symbol depending on the offset used.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(List<List<DataDictionary<TradeBar>>> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount, Resolution resolution)
|
|
{
|
|
AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(
|
|
historyResults.Select(x => x.Select(y => y[expectedSymbol]).ToList()).ToList(),
|
|
expectedSymbol, expectedHistoryCount, resolution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asserts that history request with different contract depth offsets results have the expected mapped symbol depending on the offset used.
|
|
/// In the data frames we don't have access to the underylings, so we cannot do the same checks we do for C# in
|
|
/// <see cref="AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(List{List{BaseData}}, Symbol, int, Resolution)"/>.
|
|
/// </summary>
|
|
private static void AssertFuturesHistoryWithDifferentContractDepthOffsetsResults(List<PyObject> historyResults,
|
|
Symbol expectedSymbol, int expectedHistoryCount)
|
|
{
|
|
// These are the same checks done for mapping modes
|
|
AssertFuturesHistoryWithDifferentMappingModesResults(historyResults, expectedSymbol, expectedHistoryCount);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|