/// <summary>
        /// Calculates the price factor of a <see cref="Dividend"/>
        /// </summary>
        /// <param name="dividend">The next dividend</param>
        /// <param name="previousFactorFileRow">The previous <see cref="FactorFileRow"/> generated</param>
        /// <returns><see cref="FactorFileRow"/> that represents the dividend event</returns>
        private FactorFileRow CalculateNextDividendFactor(BaseData dividend, FactorFileRow previousFactorFileRow)
        {
            var eventDayData = GetDailyDataForDate(dividend.Time);

            // If you don't have the equity data nothing can be calculated
            if (eventDayData == null)
            {
                return(null);
            }

            TradeBar previousClosingPrice = FindPreviousTradableDayClosingPrice(eventDayData.Time);

            // adjust the dividend for both price and split factors (!)
            var priceFactor = previousFactorFileRow.PriceFactor - dividend.Value *
                              previousFactorFileRow.PriceFactor /
                              previousClosingPrice.Close /
                              previousFactorFileRow.SplitFactor;

            return(new FactorFileRow(
                       previousClosingPrice.Time,
                       priceFactor.RoundToSignificantDigits(7),
                       previousFactorFileRow.SplitFactor,
                       previousClosingPrice.Close
                       ));
        }
예제 #2
0
        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"
            };

            DateTime?factorFileMinimumDate;
            var      factorFile = FactorFileRow.Parse(lines, out factorFileMinimumDate).ToList();

            Assert.AreEqual(5, factorFile.Count);

            Assert.IsNotNull(factorFileMinimumDate);
            Assert.AreEqual(new DateTime(2013, 12, 04), factorFileMinimumDate.Value);
        }
예제 #3
0
        public void AppliesSplitWithPreviousTradingDateEqualToRowDate()
        {
            var row      = new FactorFileRow(new DateTime(2018, 08, 23), 1m, 2m, 123m);
            var dividend = new Split(Symbols.SPY, row.Date.AddDays(1), 123m, 2m, SplitType.SplitOccurred);
            var updated  = row.Apply(dividend, SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork));

            Assert.AreEqual("20180823,1,4,123", updated.ToCsv());
        }
예제 #4
0
        public void ToCsv()
        {
            var row      = new FactorFileRow(new DateTime(2000, 01, 01), 1m, 2m, 123m);
            var actual   = row.ToCsv("source");
            var expected = "20000101,1,2,123,source";

            Assert.AreEqual(expected, actual);
        }
예제 #5
0
        private static FactorFile GetFactorFile_LODE20191127()
        {
            const string factorFileContents = @"
19980102,1,5,8.5,qq
20171109,1,5,0.12,qq
20501231,1,1,0,qq
";
            DateTime?    factorFileMinimumDate;
            var          reader         = new StreamReader(factorFileContents.ToStream());
            var          enumerable     = new StreamReaderEnumerable(reader).Where(line => line.Length > 0);
            var          factorFileRows = FactorFileRow.Parse(enumerable, out factorFileMinimumDate);

            return(new FactorFile("lode", factorFileRows, factorFileMinimumDate));
        }
        public void FactorFiles_CanBeGenerated_Accurately()
        {
            // Arrange
            var yahooEvents = _yahooDataDownloader.DownloadSplitAndDividendData(_symbol, Parse.DateTime("01/01/1970"), DateTime.MaxValue);
            var filePath    = LeanData.GenerateRelativeFactorFilePath(_symbol);
            var tolerance   = 0.00001m;

            if (!File.Exists(filePath))
            {
                throw new ArgumentException("This test requires an already calculated factor file." +
                                            "Try using one of the pre-existing factor files ");
            }

            var originalFactorFileInstance = FactorFile.Read(PermTick, Market);

            // we limit events to the penultimate time in our factor file (last one is 2050)
            var lastValidRow = originalFactorFileInstance.SortedFactorFileData.Reverse().Skip(1).First();

            // Act
            var newFactorFileInstance = _factorFileGenerator.CreateFactorFile(yahooEvents.Where(data => data.Time.AddDays(-1) <= lastValidRow.Key).ToList());

            var earliestDate = originalFactorFileInstance.SortedFactorFileData.First().Key;
            var latestDate   = originalFactorFileInstance.SortedFactorFileData.Last().Key;

            // Assert
            Assert.AreEqual(originalFactorFileInstance.SortedFactorFileData.Count,
                            newFactorFileInstance.SortedFactorFileData.Count);

            for (var i = earliestDate; i < latestDate; i = i.AddDays(1))
            {
                FactorFileRow expected = null;
                FactorFileRow actual   = null;

                originalFactorFileInstance.SortedFactorFileData.TryGetValue(i, out expected);
                newFactorFileInstance.SortedFactorFileData.TryGetValue(i, out actual);

                if (expected == null || actual == null)
                {
                    Assert.IsTrue(actual == null);
                    Assert.IsTrue(expected == null);
                }
                else
                {
                    Assert.IsTrue(Math.Abs(expected.PriceFactor - actual.PriceFactor) < tolerance);
                    Assert.IsTrue(Math.Abs(expected.SplitFactor - actual.SplitFactor) < tolerance);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Calculates the split factor of a <see cref="Split"/>
        /// </summary>
        /// <param name="split">The next <see cref="Split"/></param>
        /// <param name="previousFactorFileRow">The previous <see cref="FactorFileRow"/> generated</param>
        /// <returns><see cref="FactorFileRow"/>  that represents the split event</returns>
        private FactorFileRow CalculateNextSplitFactor(BaseData split, FactorFileRow previousFactorFileRow)
        {
            var eventDayData = GetDailyDataForDate(split.Time);

            // If you don't have the equity data nothing can be done
            if (eventDayData == null)
            {
                return(null);
            }

            TradeBar previousClosingPrice = FindPreviousTradableDayClosingPrice(eventDayData.Time);

            return(new FactorFileRow(
                       previousClosingPrice.Time,
                       previousFactorFileRow.PriceFactor,
                       (previousFactorFileRow.SplitFactor * split.Value).RoundToSignificantDigits(6)
                       ));
        }
예제 #8
0
        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 = FactorFileRow.Parse(lines, out factorFileMinimumDate).ToList();

            Assert.AreEqual(3, factorFile.Count);

            Assert.IsNotNull(factorFileMinimumDate);
            Assert.AreEqual(new DateTime(2016, 3, 31), factorFileMinimumDate.Value);
        }
예제 #9
0
        private static FactorFile 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;
            var      reader         = new StreamReader(factorFileContents.ToStream());
            var      enumerable     = new StreamReaderEnumerable(reader).Where(line => line.Length > 0);
            var      factorFileRows = FactorFileRow.Parse(enumerable, out factorFileMinimumDate);

            return(new FactorFile("aapl", factorFileRows, factorFileMinimumDate));
        }
예제 #10
0
        // AAPL experiences a 0.73 dividend distribution on 2018.05.11
        private static FactorFile 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;
            var      reader         = new StreamReader(factorFileContents.ToStream());
            var      enumerable     = new StreamReaderEnumerable(reader).Where(line => line.Length > 0);
            var      factorFileRows = FactorFileRow.Parse(enumerable, out factorFileMinimumDate);

            return(new FactorFile("aapl", factorFileRows, factorFileMinimumDate));
        }
예제 #11
0
        /// <summary>
        /// Generates the <see cref="FactorFileRow"/> that represents a intraday dividend split.
        /// Applies the dividend first.
        /// </summary>
        /// <param name="intraDayDividendSplit"><see cref="IntraDayDividendSplit"/> instance that holds the intraday dividend and split information</param>
        /// <param name="last">The last <see cref="FactorFileRow"/> generated recursivly</param>
        /// <returns><see cref="FactorFileRow"/> that represents an intraday dividend and split</returns>
        private FactorFileRow CalculateIntradayDividendSplit(IntraDayDividendSplit intraDayDividendSplit, FactorFileRow last)
        {
            var row = CalculateNextDividendFactor(intraDayDividendSplit.Dividend, last);

            return(CalculateNextSplitFactor(intraDayDividendSplit.Split, row));
        }