public Dictionary <string, string> CalculateDivFreqAndDivMonths(string tickerSymbol, Data.PIMS3Context ctx) { StringBuilder oneYearDivPayMonths_1 = new StringBuilder(); string oneYearDivPayMonths_2 = string.Empty; int divFreqCounter = 0; string tempDate = ""; var profileDataAccessComponent = new ProfileDataProcessing(ctx); JArray orderedJsonTickerPriceData = profileDataAccessComponent.FetchDividendSpecsForTicker(tickerSymbol); if (orderedJsonTickerPriceData == null) { Log.Warning("ProfileProcessing.CalculateDivFreqAndDivMonths() - found unresolved ticker in Tiingo service, unable to update Profile price data for {0}: ", tickerSymbol); return(null); } List <int> divPayoutDays = new List <int>(); foreach (JObject objChild in orderedJsonTickerPriceData.Children <JObject>()) { // Loop will key in on "divCash" for gathering needed freq & month specs. foreach (var property in objChild.Properties()) { if (property.Name == "date") { tempDate = property.Value.ToString(); } if (property.Name == "divCash") { if (decimal.Parse(property.Value.ToString()) > 0) { divFreqCounter += 1; oneYearDivPayMonths_1.Append(ExtractMonthFromDivPayDate(tempDate)); divPayoutDays.Add(ExtractDivPayDay(tempDate)); oneYearDivPayMonths_1.Append(","); } } } } int medianDivPayoutDay = CommonSvc.CalculateMedianValue(divPayoutDays); if (oneYearDivPayMonths_1.Length == 0) { return(null); } // Strip trailing comma. oneYearDivPayMonths_2 = oneYearDivPayMonths_1.ToString().Substring(0, oneYearDivPayMonths_1.Length - 1); string[] oneYearDivPayMonths_3 = oneYearDivPayMonths_2.Split(','); Dictionary <string, string> finalProfileSpecs = new Dictionary <string, string>(); int monthsCount = oneYearDivPayMonths_3.Length; /* == finalProfileSpecs Keys legend: == * "DF"(dividend frequency) * "DM"(dividend months) * "DPD"(dividend payout day) */ if (monthsCount >= 3 && monthsCount <= 5) { // Due to possible inconsistent number of income receipts made within the last 12 month price history obtained // from our 3rd party service (Tiingo), we'll account for this by designating as (Q)uarterly dividend frequency. finalProfileSpecs.Add("DF", "Q"); finalProfileSpecs.Add("DM", oneYearDivPayMonths_2); } else if (monthsCount >= 5) { finalProfileSpecs.Add("DF", "M"); finalProfileSpecs.Add("DM", "-"); } else if (monthsCount == 2) { finalProfileSpecs.Add("DF", "S"); finalProfileSpecs.Add("DM", oneYearDivPayMonths_2); } else { finalProfileSpecs.Add("DF", "A"); finalProfileSpecs.Add("DM", oneYearDivPayMonths_2); } if (medianDivPayoutDay > 0) { finalProfileSpecs.Add("DPD", medianDivPayoutDay.ToString()); } return(finalProfileSpecs); }
public ProfileForUpdateVm Process12MosRevenueHistory(string investorId) { // Revenue processing in response to investor-initiated Profile updating. ProfileForUpdateVm vm = new ProfileForUpdateVm(); try { string exceptionTickers = string.Empty; IQueryable <string> currentPositions = _ctx.Position.Where(p => p.PositionAsset.InvestorId == investorId && p.Status == "A") .Select(p => p.PositionAsset.Profile.TickerSymbol) .Distinct() .AsQueryable(); IQueryable <PositionIncomeVm> joinedPositionIncome = _ctx.Position.Where(p => p.PositionAsset.InvestorId == investorId && p.Status == "A") .Join(_ctx.Income, p => p.PositionId, i => i.PositionId, (p, i) => new PositionIncomeVm { ProfileId = p.PositionAsset.Profile.ProfileId, PositionId = p.PositionId, TickerSymbol = p.PositionAsset.Profile.TickerSymbol, Account = p.AccountType.AccountTypeDesc, DateRecvd = i.DateRecvd, DividendYield = Convert.ToDecimal(p.PositionAsset.Profile.DividendYield), TickerDescription = p.PositionAsset.Profile.TickerDescription }) .OrderBy(results => results.TickerSymbol) .ThenBy(results => results.Account) .AsQueryable(); joinedPositionIncome.OrderBy(pi => pi.DateRecvd); // To be initialized return collection. List <Data.Entities.Profile> updateProfileModelList = new List <Data.Entities.Profile>(); foreach (string currentTicker in currentPositions) { // Do we have income data for this position that is greater than or equal to a least a year old, as is necessary // for accurate calculation of both 1) dividend distribution frequency, and 2) dividend payout months values. // Back-dated info is always from the 1st of the calculated year ago month. int olderThanOneYearRevenueCount = joinedPositionIncome .Where(pi => pi.TickerSymbol == currentTicker && pi.DateRecvd <= DateTime.Now.AddMonths(-12).AddDays(-DateTime.Now.Day)).Count(); if (olderThanOneYearRevenueCount > 0) { Data.Entities.Profile updateProfileModel = new Data.Entities.Profile { TickerSymbol = currentTicker }; IQueryable <PositionIncomeVm> withinLastYearData = joinedPositionIncome .Where(pi => pi.TickerSymbol == currentTicker && pi.DateRecvd >= DateTime.Now.AddMonths(-12).AddDays(-DateTime.Now.Day)) .AsQueryable(); // Investor may have same position in multiple accounts, e.g. IRA, Roth-IRA. int dupAcctCount = withinLastYearData.Select(pi => pi.Account).Distinct().Count(); if (dupAcctCount > 1) { IQueryable <PositionIncomeVm> withUniqueAcct = withinLastYearData .Where(pi => pi.Account == withinLastYearData.First().Account).OrderBy(pi => pi.TickerSymbol); updateProfileModel.DividendFreq = CalculateDividendFrequency(withUniqueAcct); updateProfileModel.DividendMonths = updateProfileModel.DividendFreq != "M" ? CalculateDividendMonths(withUniqueAcct) : "N/A"; updateProfileModel.DividendPayDay = CommonSvc.CalculateMedianValue(BuildDivDaysList((withUniqueAcct))); } else { updateProfileModel.DividendFreq = CalculateDividendFrequency(withinLastYearData); updateProfileModel.DividendMonths = updateProfileModel.DividendFreq != "M" ? CalculateDividendMonths(withinLastYearData) : "N/A"; updateProfileModel.DividendPayDay = CommonSvc.CalculateMedianValue(BuildDivDaysList((withinLastYearData))); } // Satisfy 'required' Profile attributes & ProfileId for updating. updateProfileModel.ProfileId = joinedPositionIncome.Where(d => d.TickerSymbol == currentTicker).First().ProfileId; updateProfileModel.DividendYield = joinedPositionIncome.Where(d => d.TickerSymbol == currentTicker).First().DividendYield; updateProfileModel.TickerDescription = joinedPositionIncome.Where(d => d.TickerSymbol == currentTicker).First().TickerDescription; updateProfileModel.LastUpdate = DateTime.Now; updateProfileModelList.Add(updateProfileModel); } else { exceptionTickers += currentTicker + ", "; } } if (exceptionTickers.Length > 0) { exceptionTickers.Trim(); exceptionTickers = exceptionTickers.Remove(exceptionTickers.LastIndexOf(','), 1); } vm.BatchProfilesList = updateProfileModelList; vm.ExceptionTickerSymbols = (exceptionTickers.Length > 0 ? exceptionTickers : ""); vm.UpdateHasErrors = false; } catch (Exception) { vm.UpdateHasErrors = true; } return(vm); }