553 lines
26 KiB
C#
553 lines
26 KiB
C#
/*
|
|
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
|
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using NUnit.Framework;
|
|
using QuantConnect.Data;
|
|
using QuantConnect.Data.Auxiliary;
|
|
using QuantConnect.Data.Market;
|
|
using QuantConnect.Logging;
|
|
using QuantConnect.Securities;
|
|
using QuantConnect.Util;
|
|
|
|
namespace QuantConnect.Tests.Common.Data.Auxiliary
|
|
{
|
|
[TestFixture]
|
|
public class FactorFileTests
|
|
{
|
|
[Test]
|
|
public void ReadsFactorFileWithoutInfValues()
|
|
{
|
|
var PermTick = "AAPL";
|
|
var Market = "usa";
|
|
var _symbol = new Symbol(SecurityIdentifier.GenerateEquity(PermTick, Market), PermTick);
|
|
|
|
var factorFile = TestGlobals.FactorFileProvider.Get(_symbol) as CorporateFactorProvider;
|
|
|
|
Assert.AreEqual(41, factorFile.SortedFactorFileData.Count);
|
|
|
|
Assert.AreEqual(new DateTime(1998, 01, 01), factorFile.FactorFileMinimumDate.Value);
|
|
}
|
|
|
|
[Test]
|
|
public void ReadsFactorFileWithExponentialNotation()
|
|
{
|
|
// Source NEWL factor file at 2019-12-09
|
|
var lines = new[]
|
|
{
|
|
"19980102,0.8116779,1e+07",
|
|
"20051108,0.8116779,1e+07",
|
|
"20060217,0.8416761,1e+07",
|
|
"20060516,0.8644420,1e+07",
|
|
"20060814,0.8747766,1e+07",
|
|
"20061115,0.8901232,1e+07",
|
|
"20070314,0.9082148,1e+07",
|
|
"20070522,0.9166239,1e+07",
|
|
"20070814,0.9306799,1e+07",
|
|
"20071120,0.9534326,1e+07",
|
|
"20080520,0.9830510,1e+07",
|
|
"20100802,1.0000000,1e+07",
|
|
"20131016,1.0000000,1.11111e+06",
|
|
"20131205,1.0000000,75188",
|
|
"20140305,1.0000000,25000",
|
|
"20140514,1.0000000,2500",
|
|
"20140714,1.0000000,50",
|
|
"20501231,1.0000000,1"
|
|
};
|
|
|
|
var factorFile = PriceScalingExtensions.SafeRead("PermTick", lines, SecurityType.Equity);
|
|
|
|
Assert.AreEqual(5, factorFile.Count());
|
|
|
|
Assert.IsNotNull(factorFile.FactorFileMinimumDate);
|
|
Assert.AreEqual(new DateTime(2013, 12, 04), factorFile.FactorFileMinimumDate.Value);
|
|
}
|
|
|
|
[Test]
|
|
public void ReadsFactorFileWithInfValues()
|
|
{
|
|
var lines = new[]
|
|
{
|
|
"19980102,1.0000000,inf",
|
|
"20151211,1.0000000,inf",
|
|
"20160330,1.0000000,2500",
|
|
"20160915,1.0000000,80",
|
|
"20501231,1.0000000,1"
|
|
};
|
|
|
|
DateTime? factorFileMinimumDate;
|
|
var factorFile = PriceScalingExtensions.SafeRead("PermTick", lines, SecurityType.Equity);
|
|
|
|
Assert.AreEqual(3, factorFile.Count());
|
|
|
|
Assert.IsNotNull(factorFile.FactorFileMinimumDate);
|
|
Assert.AreEqual(new DateTime(2016, 3, 29), factorFile.FactorFileMinimumDate.Value);
|
|
}
|
|
|
|
[Test]
|
|
public void CorrectlyDeterminesTimePriceFactors()
|
|
{
|
|
var reference = DateTime.Today;
|
|
|
|
const string symbol = "n/a";
|
|
var file = GetTestFactorFile(symbol, reference);
|
|
// time price factors should be the price factor * split factor
|
|
|
|
Assert.AreEqual(1, file.GetPriceFactor(reference, DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(1, file.GetPriceFactor(reference.AddDays(-6), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.9, file.GetPriceFactor(reference.AddDays(-7), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.9, file.GetPriceFactor(reference.AddDays(-13), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.8, file.GetPriceFactor(reference.AddDays(-14), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.8, file.GetPriceFactor(reference.AddDays(-20), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.8m * .5m, file.GetPriceFactor(reference.AddDays(-21), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.8m * .5m, file.GetPriceFactor(reference.AddDays(-22), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.8m * .5m, file.GetPriceFactor(reference.AddDays(-89), DataNormalizationMode.Adjusted));
|
|
Assert.AreEqual(.8m * .25m, file.GetPriceFactor(reference.AddDays(-91), DataNormalizationMode.Adjusted));
|
|
}
|
|
|
|
[Test]
|
|
public void HasDividendEventOnNextTradingDay()
|
|
{
|
|
var reference = DateTime.Today;
|
|
|
|
const string symbol = "n/a";
|
|
decimal priceFactorRatio;
|
|
decimal referencePrice;
|
|
var file = GetTestFactorFile(symbol, reference);
|
|
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference, out priceFactorRatio, out referencePrice));
|
|
|
|
Assert.IsFalse(file.HasDividendEventOnNextTradingDay(reference.AddDays(-6), out priceFactorRatio, out referencePrice));
|
|
Assert.IsTrue(file.HasDividendEventOnNextTradingDay(reference.AddDays(-7), out priceFactorRatio, out referencePrice));
|
|
Assert.AreEqual(.9m/1m, priceFactorRatio);
|
|
Assert.IsFalse(file.HasDividendEventOnNextTradingDay(reference.AddDays(-8), out priceFactorRatio, out referencePrice));
|
|
|
|
Assert.IsFalse(file.HasDividendEventOnNextTradingDay(reference.AddDays(-13), out priceFactorRatio, out referencePrice));
|
|
Assert.IsTrue(file.HasDividendEventOnNextTradingDay(reference.AddDays(-14), out priceFactorRatio, out referencePrice));
|
|
Assert.AreEqual(.8m / .9m, priceFactorRatio);
|
|
Assert.IsFalse(file.HasDividendEventOnNextTradingDay(reference.AddDays(-15), out priceFactorRatio, out referencePrice));
|
|
|
|
Assert.IsFalse(file.HasDividendEventOnNextTradingDay(reference.AddDays(-364), out priceFactorRatio, out referencePrice));
|
|
Assert.IsTrue(file.HasDividendEventOnNextTradingDay(reference.AddDays(-365), out priceFactorRatio, out referencePrice));
|
|
Assert.AreEqual(.7m / .8m, priceFactorRatio);
|
|
Assert.IsFalse(file.HasDividendEventOnNextTradingDay(reference.AddDays(-366), out priceFactorRatio, out referencePrice));
|
|
|
|
Assert.IsNull(file.FactorFileMinimumDate);
|
|
}
|
|
|
|
[Test]
|
|
public void HasSplitEventOnNextTradingDay()
|
|
{
|
|
var reference = DateTime.Today;
|
|
|
|
const string symbol = "n/a";
|
|
decimal splitFactor;
|
|
decimal referencePrice;
|
|
var file = GetTestFactorFile(symbol, reference);
|
|
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference, out splitFactor, out referencePrice));
|
|
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference.AddDays(-20), out splitFactor, out referencePrice));
|
|
Assert.IsTrue(file.HasSplitEventOnNextTradingDay(reference.AddDays(-21), out splitFactor, out referencePrice));
|
|
Assert.AreEqual(.5, splitFactor);
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference.AddDays(-22), out splitFactor, out referencePrice));
|
|
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference.AddDays(-89), out splitFactor, out referencePrice));
|
|
Assert.IsTrue(file.HasSplitEventOnNextTradingDay(reference.AddDays(-90), out splitFactor, out referencePrice));
|
|
Assert.AreEqual(.5, splitFactor);
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference.AddDays(-91), out splitFactor, out referencePrice));
|
|
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference.AddDays(-364), out splitFactor, out referencePrice));
|
|
Assert.IsTrue(file.HasSplitEventOnNextTradingDay(reference.AddDays(-365), out splitFactor, out referencePrice));
|
|
Assert.AreEqual(.5, splitFactor);
|
|
Assert.IsFalse(file.HasSplitEventOnNextTradingDay(reference.AddDays(-366), out splitFactor, out referencePrice));
|
|
|
|
Assert.IsNull(file.FactorFileMinimumDate);
|
|
}
|
|
|
|
[Test]
|
|
public void GeneratesCorrectSplitsAndDividends()
|
|
{
|
|
var reference = new DateTime(2018, 01, 01);
|
|
var file = GetTestFactorFile("SPY", reference);
|
|
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(QuantConnect.Market.USA, Symbols.SPY, SecurityType.Equity);
|
|
var splitsAndDividends = file.GetSplitsAndDividends(Symbols.SPY, exchangeHours);
|
|
|
|
var dividend = (Dividend)splitsAndDividends.Single(d => d.Time == reference.AddDays(-6));
|
|
var distribution = Dividend.ComputeDistribution(100m, .9m / 1m, 2);
|
|
Assert.AreEqual(distribution, dividend.Distribution);
|
|
|
|
dividend = (Dividend) splitsAndDividends.Single(d => d.Time == reference.AddDays(-13));
|
|
distribution = Math.Round(Dividend.ComputeDistribution(100m, .8m / .9m, 2), 2);
|
|
Assert.AreEqual(distribution, dividend.Distribution);
|
|
|
|
var split = (Split) splitsAndDividends.Single(d => d.Time == reference.AddDays(-20));
|
|
var splitFactor = .5m;
|
|
Assert.AreEqual(splitFactor, split.SplitFactor);
|
|
|
|
split = (Split) splitsAndDividends.Single(d => d.Time == reference.AddDays(-89));
|
|
splitFactor = .5m;
|
|
Assert.AreEqual(splitFactor, split.SplitFactor);
|
|
|
|
dividend = splitsAndDividends.OfType<Dividend>().Single(d => d.Time == reference.AddDays(-363));
|
|
distribution = Dividend.ComputeDistribution(100m, .7m / .8m, 2);
|
|
Assert.AreEqual(distribution, dividend.Distribution);
|
|
|
|
split = splitsAndDividends.OfType<Split>().Single(d => d.Time == reference.AddDays(-363));
|
|
splitFactor = .5m;
|
|
Assert.AreEqual(splitFactor, split.SplitFactor);
|
|
}
|
|
|
|
[Test]
|
|
public void GetsSplitsAndDividends()
|
|
{
|
|
var factorFile = GetFactorFile_AAPL2018_05_11();
|
|
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(QuantConnect.Market.USA, Symbols.SPY, SecurityType.Equity);
|
|
var splitsAndDividends = factorFile.GetSplitsAndDividends(Symbols.AAPL, exchangeHours).ToList();
|
|
foreach (var sad in splitsAndDividends)
|
|
{
|
|
Log.Trace($"{sad.Time.Date:yyyy-MM-dd}: {sad}");
|
|
}
|
|
var splits = splitsAndDividends.OfType<Split>().ToList();
|
|
var dividends = splitsAndDividends.OfType<Dividend>().ToList();
|
|
|
|
var dividend = dividends.Single(d => d.Time == new DateTime(2018, 05, 11));
|
|
Assert.AreEqual(0.73m, dividend.Distribution.RoundToSignificantDigits(6));
|
|
|
|
var split = splits.Single(d => d.Time == new DateTime(2014, 06, 09));
|
|
Assert.AreEqual((1/7m).RoundToSignificantDigits(6), split.SplitFactor);
|
|
}
|
|
|
|
[Test]
|
|
public void AppliesDividend()
|
|
{
|
|
var factorFileBeforeDividend = GetFactorFile_AAPL2018_05_08();
|
|
var factorFileAfterDividend = GetFactorFile_AAPL2018_05_11();
|
|
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(QuantConnect.Market.USA, Symbols.SPY, SecurityType.Equity);
|
|
|
|
var dividend = new Dividend(Symbols.AAPL, new DateTime(2018, 05, 11), 0.73m, 190.03m);
|
|
var actual = factorFileBeforeDividend.Apply(new List<BaseData> {dividend}, exchangeHours);
|
|
|
|
Assert.AreEqual(factorFileAfterDividend.Count(), actual.Count());
|
|
Assert.True(actual.First().Date == new DateTime(1998, 01, 02),
|
|
$"Factor file first row changed from 1998-01-02 to {actual.First().Date:yyyy-MM-dd} after applying new event");
|
|
|
|
|
|
foreach (var item in factorFileAfterDividend.Reverse().Zip(actual.Reverse(), (a,e) => new{actual=a, expected=e}))
|
|
{
|
|
var expected = (CorporateFactorRow)item.expected;
|
|
var actualRow = (CorporateFactorRow)item.actual;
|
|
Log.Trace($"expected: {item.expected} actual: {item.actual} diff: {100* (1 - actualRow.PriceFactor/expected.PriceFactor):0.0000}%");
|
|
Assert.AreEqual(item.expected.Date, item.actual.Date);
|
|
Assert.AreEqual(expected.ReferencePrice, actualRow.ReferencePrice);
|
|
Assert.AreEqual(expected.SplitFactor, actualRow.SplitFactor);
|
|
|
|
var delta = (double)expected.PriceFactor * 1e-5;
|
|
Assert.AreEqual((double)expected.PriceFactor, (double)actualRow.PriceFactor, delta);
|
|
}
|
|
}
|
|
|
|
|
|
[Test]
|
|
public void AppliesSplit()
|
|
{
|
|
var factorFileBeforeSplit = GetFactorFile_LODE20191127();
|
|
var factorFileAfterSplit = GetFactorFile_LODE20191129();
|
|
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(QuantConnect.Market.USA, Symbols.SPY, SecurityType.Equity);
|
|
|
|
var eventTime = new DateTime(2019, 11, 29);
|
|
var split = new Split(Symbols.LODE, eventTime, 0.06m, 5, SplitType.SplitOccurred);
|
|
var actual = factorFileBeforeSplit.Apply(new List<BaseData> { split }, exchangeHours);
|
|
|
|
Assert.AreEqual(factorFileAfterSplit.Count(), actual.Count());
|
|
Assert.True(actual.First().Date == new DateTime(1998, 01, 02),
|
|
$"Factor file first row changed from 1998-01-02 to {actual.First().Date:yyyy-MM-dd} after applying new event");
|
|
Assert.True(((CorporateFactorRow)actual.First()).SplitFactor == 25m, "Factor File split factor is not computed correctly");
|
|
foreach (var item in actual.Reverse().Zip(factorFileAfterSplit.Reverse(), (a, e) => new { actual = a, expected = e }))
|
|
{
|
|
var expected = (CorporateFactorRow)item.expected;
|
|
var actualRow = (CorporateFactorRow)item.actual;
|
|
Log.Trace($"expected: {item.expected} actual: {item.actual} diff: {100 * (1 - actualRow.PriceFactor / expected.PriceFactor):0.0000}%");
|
|
Assert.AreEqual(item.expected.Date, item.actual.Date);
|
|
Assert.AreEqual(expected.ReferencePrice, actualRow.ReferencePrice);
|
|
Assert.AreEqual(expected.SplitFactor, actualRow.SplitFactor);
|
|
|
|
var delta = (double)expected.PriceFactor * 1e-5;
|
|
Assert.AreEqual((double)expected.PriceFactor, (double)actualRow.PriceFactor, delta);
|
|
}
|
|
}
|
|
|
|
|
|
[Test]
|
|
public void CanHandleRepeatedEventsCorrectly()
|
|
{
|
|
var factorFileBeforeSplit = GetFactorFile_LODE20191127();
|
|
var factorFileAfterSplit = GetFactorFile_LODE20191129();
|
|
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(QuantConnect.Market.USA, Symbols.SPY, SecurityType.Equity);
|
|
|
|
var eventTime = new DateTime(2019, 11, 29);
|
|
var split = new Split(Symbols.LODE, eventTime, 0.06m, 5, SplitType.SplitOccurred);
|
|
var events = new List<BaseData> { split, split, split };
|
|
var actual = factorFileBeforeSplit.Apply(events, exchangeHours);
|
|
|
|
Assert.AreEqual(factorFileAfterSplit.Count(), actual.Count());
|
|
Assert.True(actual.First().Date == new DateTime(1998, 01, 02),
|
|
$"Factor file first row changed from 1998-01-02 to {actual.First().Date:yyyy-MM-dd} after applying new event");
|
|
Assert.True(((CorporateFactorRow)actual.First()).SplitFactor == 25m, "Factor File split factor is not computed correctly");
|
|
foreach (var item in actual.Reverse().Zip(factorFileAfterSplit.Reverse(), (a, e) => new { actual = a, expected = e }))
|
|
{
|
|
var expectedRow = (CorporateFactorRow)item.expected;
|
|
var actualRow = (CorporateFactorRow)item.actual;
|
|
Log.Trace($"expected: {item.expected} actual: {item.actual} diff: {100 * (1 - actualRow.PriceFactor / expectedRow.PriceFactor):0.0000}%");
|
|
Assert.AreEqual(item.expected.Date, item.actual.Date);
|
|
Assert.AreEqual(expectedRow.ReferencePrice, actualRow.ReferencePrice);
|
|
Assert.AreEqual(expectedRow.SplitFactor, actualRow.SplitFactor);
|
|
|
|
var delta = (double)expectedRow.PriceFactor * 1e-5;
|
|
Assert.AreEqual((double)expectedRow.PriceFactor, (double)actualRow.PriceFactor, delta);
|
|
}
|
|
}
|
|
|
|
|
|
[Test]
|
|
public void AppliesSplitAndDividendAtSameTime()
|
|
{
|
|
var reference = new DateTime(2018, 08, 01);
|
|
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(QuantConnect.Market.USA, Symbols.SPY, SecurityType.Equity);
|
|
var expected = GetTestFactorFile("AAPL", reference);
|
|
|
|
// remove the last entry that contains a split and dividend at the same time
|
|
var factorFile = new CorporateFactorProvider("AAPL", expected.SortedFactorFileData.Where(kvp => kvp.Value.Single().PriceFactor >= .8m).Select(kvp => kvp.Value.Single()));
|
|
var actual = factorFile.Apply(new List<BaseData>
|
|
{
|
|
new Split(Symbols.AAPL, reference.AddDays(-364), 100m, 1 / 2m, SplitType.SplitOccurred),
|
|
new Dividend(Symbols.AAPL, reference.AddDays(-364), 12.5m, 100m)
|
|
}, exchangeHours);
|
|
|
|
foreach (var item in actual.Reverse().Zip(expected.Reverse(), (a, e) => new {actual = a, expected = e}))
|
|
{
|
|
var expectedRow = (CorporateFactorRow)item.expected;
|
|
var actualRow = (CorporateFactorRow)item.actual;
|
|
Log.Trace($"expected: {item.expected} actual: {item.actual} diff: {100 * (1 - actualRow.PriceFactor / expectedRow.PriceFactor):0.0000}%");
|
|
Assert.AreEqual(item.expected.Date, item.actual.Date);
|
|
Assert.AreEqual(expectedRow.ReferencePrice, actualRow.ReferencePrice);
|
|
Assert.AreEqual(expectedRow.SplitFactor, actualRow.SplitFactor);
|
|
|
|
Assert.AreEqual(expectedRow.PriceFactor.RoundToSignificantDigits(4), actualRow.PriceFactor.RoundToSignificantDigits(4));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void ReadsOldFactorFileFormat()
|
|
{
|
|
var lines = new[]
|
|
{
|
|
"19980102,1.0000000,0.5",
|
|
"20130828,1.0000000,0.5",
|
|
"20501231,1.0000000,1"
|
|
};
|
|
|
|
var factorFile = PriceScalingExtensions.SafeRead("bno", lines, SecurityType.Equity) as CorporateFactorProvider;
|
|
|
|
var firstRow = factorFile.SortedFactorFileData[new DateTime(1998, 01, 02)].Single();
|
|
Assert.AreEqual(1m, firstRow.PriceFactor);
|
|
Assert.AreEqual(0.5m, firstRow.SplitFactor);
|
|
Assert.AreEqual(0m, firstRow.ReferencePrice);
|
|
|
|
var secondRow = factorFile.SortedFactorFileData[new DateTime(2013, 08, 28)].Single();
|
|
Assert.AreEqual(1m, secondRow.PriceFactor);
|
|
Assert.AreEqual(0.5m, secondRow.SplitFactor);
|
|
Assert.AreEqual(0m, firstRow.ReferencePrice);
|
|
|
|
var thirdRow = factorFile.SortedFactorFileData[Time.EndOfTime].Single();
|
|
Assert.AreEqual(1m, thirdRow.PriceFactor);
|
|
Assert.AreEqual(1m, thirdRow.SplitFactor);
|
|
Assert.AreEqual(0m, firstRow.ReferencePrice);
|
|
}
|
|
|
|
[Test]
|
|
public void HandlesUnknownDataMappingModes()
|
|
{
|
|
var lines = new[]
|
|
{
|
|
"{\"Date\":\"2010-01-28T00:00:00\",\"BackwardsRatioScale\":[1.1575],\"BackwardsPanamaCanalScale\":[7.06],\"ForwardPanamaCanalScale\":[0.0],\"DataMappingMode\":1}",
|
|
"{\"Date\":\"2010-02-25T00:00:00\",\"BackwardsRatioScale\":[1.1575],\"BackwardsPanamaCanalScale\":[7.06],\"ForwardPanamaCanalScale\":[0.0],\"DataMappingMode\":788}"
|
|
};
|
|
|
|
var factorFile = PriceScalingExtensions.SafeRead("cl", lines, SecurityType.Future) as MappingContractFactorProvider;
|
|
Assert.AreEqual(1, factorFile.Count());
|
|
Assert.AreEqual(DataMappingMode.FirstDayMonth, (factorFile.First() as MappingContractFactorRow).DataMappingMode);
|
|
}
|
|
|
|
[Test]
|
|
public void ResolvesCorrectMostRecentFactorChangeDate()
|
|
{
|
|
var lines = new[]
|
|
{
|
|
"19980102,1.0000000,0.5",
|
|
"20130828,1.0000000,0.5",
|
|
"20501231,1.0000000,1"
|
|
};
|
|
|
|
var factorFile = PriceScalingExtensions.SafeRead("bno", lines, SecurityType.Equity) as CorporateFactorProvider;
|
|
Assert.AreEqual(new DateTime(2013, 08, 28), factorFile.MostRecentFactorChange);
|
|
}
|
|
|
|
[Test]
|
|
[TestCase("")]
|
|
[TestCase("20501231,1.0000000,1")]
|
|
public void EmptyFactorFileReturnsEmptyListForSplitsAndDividends(string contents)
|
|
{
|
|
var lines = contents.Split('\n').Where(l => !string.IsNullOrWhiteSpace(l));
|
|
|
|
var factorFile = PriceScalingExtensions.SafeRead("bno", lines, SecurityType.Equity) as CorporateFactorProvider;
|
|
Assert.IsEmpty(factorFile.GetSplitsAndDividends(Symbols.SPY, SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork)));
|
|
}
|
|
|
|
private static CorporateFactorProvider GetTestFactorFile(string symbol, DateTime reference)
|
|
{
|
|
var file = new CorporateFactorProvider(symbol, new List<CorporateFactorRow>
|
|
{
|
|
new CorporateFactorRow(reference, 1, 1),
|
|
new CorporateFactorRow(reference.AddDays(-7), .9m, 1, 100m), // dividend
|
|
new CorporateFactorRow(reference.AddDays(-14), .8m, 1, 100m), // dividend
|
|
new CorporateFactorRow(reference.AddDays(-21), .8m, .5m, 100m), // split
|
|
new CorporateFactorRow(reference.AddDays(-90), .8m, .25m, 100m), // split
|
|
new CorporateFactorRow(reference.AddDays(-365), .7m, .125m, 100m) // split+dividend
|
|
});
|
|
return file;
|
|
}
|
|
|
|
private static CorporateFactorProvider GetFactorFile_LODE20191127()
|
|
{
|
|
const string factorFileContents = @"
|
|
19980102,1,5,8.5,qq
|
|
20171109,1,5,0.12,qq
|
|
20501231,1,1,0,qq
|
|
";
|
|
DateTime? factorFileMinimumDate;
|
|
using var reader = new StreamReader(factorFileContents.ToStream());
|
|
using var streamReaderEnumerable = new StreamReaderEnumerable(reader);
|
|
var enumerable = streamReaderEnumerable.Where(line => line.Length > 0);
|
|
var factorFileRows = CorporateFactorRow.Parse(enumerable, out factorFileMinimumDate);
|
|
return new CorporateFactorProvider("lode", factorFileRows, factorFileMinimumDate);
|
|
}
|
|
|
|
private static CorporateFactorProvider GetFactorFile_LODE20191129()
|
|
{
|
|
const string factorFileContents = @"
|
|
19980102,1,25,8.5,qq
|
|
20171109,1,25,0.12,qq
|
|
20191127,1,5,0.06,qq
|
|
20501231,1,1,0,qq
|
|
";
|
|
DateTime? factorFileMinimumDate;
|
|
using var reader = new StreamReader(factorFileContents.ToStream());
|
|
using var streamReaderEnumerable = new StreamReaderEnumerable(reader);
|
|
var enumerable = streamReaderEnumerable.Where(line => line.Length > 0);
|
|
var factorFileRows = CorporateFactorRow.Parse(enumerable, out factorFileMinimumDate);
|
|
return new CorporateFactorProvider("lode", factorFileRows, factorFileMinimumDate);
|
|
}
|
|
|
|
private static CorporateFactorProvider GetFactorFile_AAPL2018_05_11()
|
|
{
|
|
const string factorFileContents = @"
|
|
19980102,0.8893653,0.0357143,16.25
|
|
20000620,0.8893653,0.0357143,101
|
|
20050225,0.8893653,0.0714286,88.97
|
|
20120808,0.8893653,0.142857,619.85
|
|
20121106,0.8931837,0.142857,582.85
|
|
20130206,0.8972636,0.142857,457.285
|
|
20130508,0.9024937,0.142857,463.71
|
|
20130807,0.908469,0.142857,464.94
|
|
20131105,0.9144679,0.142857,525.58
|
|
20140205,0.9198056,0.142857,512.59
|
|
20140507,0.9253111,0.142857,592.34
|
|
20140606,0.9304792,0.142857,645.57
|
|
20140806,0.9304792,1,94.96
|
|
20141105,0.9351075,1,108.86
|
|
20150204,0.9391624,1,119.55
|
|
20150506,0.9428692,1,125.085
|
|
20150805,0.9468052,1,115.4
|
|
20151104,0.9510909,1,122.01
|
|
20160203,0.9551617,1,96.34
|
|
20160504,0.9603451,1,94.19
|
|
20160803,0.9661922,1,105.8
|
|
20161102,0.9714257,1,111.6
|
|
20170208,0.9764128,1,132.04
|
|
20170510,0.9806461,1,153.26
|
|
20170809,0.9846939,1,161.1
|
|
20171109,0.9885598,1,175.87
|
|
20180208,0.9921138,1,155.16
|
|
20180510,0.9961585,1,190.03
|
|
20501231,1,1,0
|
|
";
|
|
|
|
DateTime? factorFileMinimumDate;
|
|
using var reader = new StreamReader(factorFileContents.ToStream());
|
|
using var streamReaderEnumerable = new StreamReaderEnumerable(reader);
|
|
var enumerable = streamReaderEnumerable.Where(line => line.Length > 0);
|
|
var factorFileRows = CorporateFactorRow.Parse(enumerable, out factorFileMinimumDate);
|
|
return new CorporateFactorProvider("aapl", factorFileRows, factorFileMinimumDate);
|
|
}
|
|
|
|
// AAPL experiences a 0.73 dividend distribution on 2018.05.11
|
|
private static CorporateFactorProvider GetFactorFile_AAPL2018_05_08()
|
|
{
|
|
const string factorFileContents = @"
|
|
19980102,0.8927948,0.0357143,16.25
|
|
20000620,0.8927948,0.0357143,101
|
|
20050225,0.8927948,0.0714286,88.97
|
|
20120808,0.8927948,0.142857,619.85
|
|
20121106,0.8966279,0.142857,582.85
|
|
20130206,0.9007235,0.142857,457.285
|
|
20130508,0.9059737,0.142857,463.71
|
|
20130807,0.9119721,0.142857,464.94
|
|
20131105,0.9179942,0.142857,525.58
|
|
20140205,0.9233525,0.142857,512.59
|
|
20140507,0.9288793,0.142857,592.34
|
|
20140606,0.9340673,0.142857,645.57
|
|
20140806,0.9340673,1,94.96
|
|
20141105,0.9387135,1,108.86
|
|
20150204,0.942784,1,119.55
|
|
20150506,0.9465051,1,125.085
|
|
20150805,0.9504563,1,115.4
|
|
20151104,0.9547586,1,122.01
|
|
20160203,0.9588451,1,96.34
|
|
20160504,0.9640485,1,94.19
|
|
20160803,0.9699181,1,105.8
|
|
20161102,0.9751718,1,111.6
|
|
20170208,0.9801781,1,132.04
|
|
20170510,0.9844278,1,153.26
|
|
20170809,0.9884911,1,161.1
|
|
20171109,0.992372,1,175.87
|
|
20180208,0.9959397,1,155.16
|
|
20501231,1,1,0
|
|
";
|
|
|
|
DateTime? factorFileMinimumDate;
|
|
using var reader = new StreamReader(factorFileContents.ToStream());
|
|
using var streamReaderEnumerable = new StreamReaderEnumerable(reader);
|
|
var enumerable = streamReaderEnumerable.Where(line => line.Length > 0);
|
|
var factorFileRows = CorporateFactorRow.Parse(enumerable, out factorFileMinimumDate);
|
|
return new CorporateFactorProvider("aapl", factorFileRows, factorFileMinimumDate);
|
|
}
|
|
}
|
|
}
|