Пример #1
0
        /// <summary>
        /// Creates a new factor file with the specified data applied.
        /// Only <see cref="Dividend"/> and <see cref="Split"/> data types
        /// will be used.
        /// </summary>
        /// <param name="data">The data to apply</param>
        /// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
        /// <returns>A new factor file that incorporates the specified dividend</returns>
        public CorporateFactorProvider Apply(List <BaseData> data, SecurityExchangeHours exchangeHours)
        {
            if (data.Count == 0)
            {
                return(this);
            }

            var factorFileRows = new List <CorporateFactorRow>();
            var firstEntry     = SortedFactorFileData.First().Value.First();
            var lastEntry      = SortedFactorFileData.Last().Value.First();

            factorFileRows.Add(lastEntry);

            var splitsAndDividends = GetSplitsAndDividends(data[0].Symbol, exchangeHours);

            var combinedData = splitsAndDividends.Concat(data)
                               .DistinctBy(e => $"{e.GetType().Name}{e.Time.ToStringInvariant(DateFormat.EightCharacter)}")
                               .OrderByDescending(d => d.Time.Date);

            foreach (var datum in combinedData)
            {
                CorporateFactorRow nextEntry = null;
                var split    = datum as Split;
                var dividend = datum as Dividend;
                if (dividend != null)
                {
                    nextEntry = lastEntry.Apply(dividend, exchangeHours);
                    lastEntry = nextEntry;
                }
                else if (split != null)
                {
                    nextEntry = lastEntry.Apply(split, exchangeHours);
                    lastEntry = nextEntry;
                }

                if (nextEntry != null)
                {
                    // overwrite the latest entry -- this handles splits/dividends on the same date
                    if (nextEntry.Date == factorFileRows.Last().Date)
                    {
                        factorFileRows[factorFileRows.Count - 1] = nextEntry;
                    }
                    else
                    {
                        factorFileRows.Add(nextEntry);
                    }
                }
            }

            var firstFactorFileRow = new CorporateFactorRow(firstEntry.Date, factorFileRows.Last().PriceFactor, factorFileRows.Last().SplitFactor, firstEntry.ReferencePrice == 0 ? 0 : firstEntry.ReferencePrice);
            var existing           = factorFileRows.FindIndex(row => row.Date == firstFactorFileRow.Date);

            if (existing == -1)
            {
                // only add it if not present
                factorFileRows.Add(firstFactorFileRow);
            }

            return(new CorporateFactorProvider(Permtick, factorFileRows, FactorFileMinimumDate));
        }
Пример #2
0
        /// <summary>
        /// Gets all of the splits and dividends represented by this factor file
        /// </summary>
        /// <param name="symbol">The symbol to ues for the dividend and split objects</param>
        /// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
        /// <returns>All splits and diviends represented by this factor file in chronological order</returns>
        public List <BaseData> GetSplitsAndDividends(Symbol symbol, SecurityExchangeHours exchangeHours)
        {
            var dividendsAndSplits = new List <BaseData>();

            if (SortedFactorFileData.Count == 0)
            {
                Log.Trace($"{symbol} has no factors!");
                return(dividendsAndSplits);
            }

            var futureFactorFileRow = SortedFactorFileData.Last().Value;

            for (var i = SortedFactorFileData.Count - 2; i >= 0; i--)
            {
                var row      = SortedFactorFileData.Values[i];
                var dividend = row.GetDividend(futureFactorFileRow, symbol, exchangeHours);
                if (dividend.Distribution != 0m)
                {
                    dividendsAndSplits.Add(dividend);
                }

                var split = row.GetSplit(futureFactorFileRow, symbol, exchangeHours);
                if (split.SplitFactor != 1m)
                {
                    dividendsAndSplits.Add(split);
                }

                futureFactorFileRow = row;
            }

            return(dividendsAndSplits.OrderBy(d => d.Time.Date).ToList());
        }
Пример #3
0
        /// <summary>
        /// Writes this factor file data to an enumerable of csv lines
        /// </summary>
        /// <returns>An enumerable of lines representing this factor file</returns>
        public IEnumerable <string> ToCsvLines()
        {
            if (FactorFileMinimumDate != null)
            {
                var min = SortedFactorFileData.First().Value;
                yield return($"{FactorFileMinimumDate:yyyyMMdd},{min.PriceFactor},{min.SplitFactor}");
            }

            foreach (var kvp in SortedFactorFileData)
            {
                yield return($"{kvp.Key:yyyyMMdd},{kvp.Value.PriceFactor},{kvp.Value.SplitFactor}");
            }
        }
Пример #4
0
        /// <summary>
        /// Creates a new factor file with the specified data applied.
        /// Only <see cref="Dividend"/> and <see cref="Split"/> data types
        /// will be used.
        /// </summary>
        /// <param name="data">The data to apply</param>
        /// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
        /// <returns>A new factor file that incorporates the specified dividend</returns>
        public FactorFile Apply(List <BaseData> data, SecurityExchangeHours exchangeHours)
        {
            if (data.Count == 0)
            {
                return(this);
            }

            var factorFileRows = new List <FactorFileRow>();
            var lastEntry      = SortedFactorFileData.Last().Value;

            factorFileRows.Add(lastEntry);

            var combinedData = GetSplitsAndDividends(data[0].Symbol, exchangeHours).Concat(data)
                               .OrderByDescending(d => d.Time.Date);

            foreach (var datum in combinedData)
            {
                FactorFileRow nextEntry = null;
                var           split     = datum as Split;
                var           dividend  = datum as Dividend;
                if (dividend != null)
                {
                    nextEntry = lastEntry.Apply(dividend, exchangeHours);
                    lastEntry = nextEntry;
                }
                else if (split != null)
                {
                    nextEntry = lastEntry.Apply(split, exchangeHours);
                    lastEntry = nextEntry;
                }

                if (nextEntry != null)
                {
                    // overwrite the latest entry -- this handles splits/dividends on the same date
                    if (nextEntry.Date == factorFileRows.Last().Date)
                    {
                        factorFileRows[factorFileRows.Count - 1] = nextEntry;
                    }
                    else
                    {
                        factorFileRows.Add(nextEntry);
                    }
                }
            }

            return(new FactorFile(Permtick, factorFileRows, FactorFileMinimumDate));
        }
Пример #5
0
        /// <summary>
        /// Returns true if the specified date is the last trading day before a split event
        /// is to be fired
        /// </summary>
        /// <remarks>
        /// NOTE: The split event in the algorithm should be fired at the end or AFTER this
        /// date. This is the date in the file that a factor is applied, so for example MSFT
        /// has a split on 1999.03.29, but in the factor file the split factor is applied on
        /// 1999.03.26, which is the first trading day BEFORE the actual split date.
        /// </remarks>
        public bool HasSplitEventOnNextTradingDay(DateTime date, out decimal splitFactor)
        {
            splitFactor = 1;
            var index = SortedFactorFileData.IndexOfKey(date);

            if (index > -1 && index < SortedFactorFileData.Count - 1)
            {
                // grab the next key to ensure it's a split event
                var thisRow = SortedFactorFileData.Values[index];
                var nextRow = SortedFactorFileData.Values[index + 1];

                // if the split factors have changed then it's a split event
                if (thisRow.SplitFactor != nextRow.SplitFactor)
                {
                    splitFactor = thisRow.SplitFactor / nextRow.SplitFactor;
                    return(true);
                }
            }
            return(false);
        }
Пример #6
0
        /// <summary>
        /// Returns true if the specified date is the last trading day before a dividend event
        /// is to be fired
        /// </summary>
        /// <remarks>
        /// NOTE: The dividend event in the algorithm should be fired at the end or AFTER
        /// this date. This is the date in the file that a factor is applied, so for example,
        /// MSFT has a 31 cent dividend on 2015.02.17, but in the factor file the factor is applied
        /// to 2015.02.13, which is the first trading day BEFORE the actual effective date.
        /// </remarks>
        /// <param name="date">The date to check the factor file for a dividend event</param>
        /// <param name="priceFactorRatio">When this function returns true, this value will be populated
        /// with the price factor ratio required to scale the closing value (pf_i/pf_i+1)</param>
        public bool HasDividendEventOnNextTradingDay(DateTime date, out decimal priceFactorRatio)
        {
            priceFactorRatio = 0;
            var index = SortedFactorFileData.IndexOfKey(date);

            if (index > -1 && index < SortedFactorFileData.Count - 1)
            {
                // grab the next key to ensure it's a dividend event
                var thisRow = SortedFactorFileData.Values[index];
                var nextRow = SortedFactorFileData.Values[index + 1];

                // if the price factors have changed then it's a dividend event
                if (thisRow.PriceFactor != nextRow.PriceFactor)
                {
                    priceFactorRatio = thisRow.PriceFactor / nextRow.PriceFactor;
                    return(true);
                }
            }
            return(false);
        }
Пример #7
0
 /// <summary>
 /// Writes this factor file data to an enumerable of csv lines
 /// </summary>
 /// <returns>An enumerable of lines representing this factor file</returns>
 public IEnumerable <string> GetFileFormat()
 {
     return(SortedFactorFileData.SelectMany(kvp => kvp.Value.Select(row => row.GetFileFormat())));
 }