19 using System.Threading.Tasks;
21 using System.Collections.Generic;
51 private static readonly
object _lock =
new();
53 private readonly
Symbol _symbol;
70 if (dueTime > TimeSpan.FromMinutes(10))
73 return dueTime - TimeSpan.FromMinutes(10);
119 return optionSymbol.
Value switch
134 private static void StartExpirationTask(TimeSpan cacheRefreshPeriod)
141 _cacheClearTask = Task.Delay(cacheRefreshPeriod).ContinueWith(_ => StartExpirationTask(cacheRefreshPeriod));
154 return GetDividendYieldImpl(date,
null);
165 if (priceData.
Symbol != _symbol)
167 throw new ArgumentException($
"Trying to get {priceData.Symbol} dividend yield using the {_symbol} dividend yield provider.");
182 return GetDividendYieldImpl(date, securityPrice);
193 private decimal GetDividendYieldImpl(DateTime date, decimal? securityPrice)
195 List<BaseData> symbolCorporateEvents;
205 if (symbolCorporateEvents ==
null)
211 var mostRecentCorporateEventIndex = symbolCorporateEvents.FindLastIndex(x => x.EndTime <= date.Date);
212 if (mostRecentCorporateEventIndex == -1)
218 var mostRecentCorporateEvent = symbolCorporateEvents[mostRecentCorporateEventIndex];
219 var mostRecentDividend = mostRecentCorporateEvent as
Dividend;
220 if (mostRecentDividend ==
null)
222 for (var i = mostRecentCorporateEventIndex - 1; i >= 0; i--)
224 if (symbolCorporateEvents[i] is
Dividend dividend)
226 mostRecentDividend = dividend;
233 if (mostRecentDividend ==
null)
238 securityPrice ??= mostRecentDividend.ReferencePrice;
239 if (securityPrice == 0)
241 throw new ArgumentException(
"Security price cannot be zero.");
248 var trailingYearStartDate = mostRecentDividend.EndTime.AddDays(-350);
250 var yearlyDividend = 0m;
251 var currentSplitFactor = 1m;
252 for (var i = mostRecentCorporateEventIndex; i >= 0; i--)
254 var corporateEvent = symbolCorporateEvents[i];
255 if (corporateEvent.EndTime < trailingYearStartDate)
260 if (corporateEvent is
Dividend dividend)
262 yearlyDividend += dividend.Distribution * currentSplitFactor;
267 currentSplitFactor *= ((
Split)corporateEvent).SplitFactor;
271 return yearlyDividend / securityPrice.Value;
281 var corporateFactors = factorFileProvider
284 .Where(corporateFactor => corporateFactor !=
null);
286 var symbolCorporateEvents = FromCorporateFactorRows(corporateFactors, symbol).ToList();
287 if (symbolCorporateEvents.Count == 0)
292 return symbolCorporateEvents;
298 private IEnumerable<BaseData> FromCorporateFactorRows(IEnumerable<CorporateFactorRow> corporateFactors,
Symbol symbol)
300 var dividends =
new List<Dividend>();
303 var rows = corporateFactors.OrderBy(corporateFactor => corporateFactor.Date).ToArray();
304 for (var i = 0; i < rows.Length - 1; i++)
307 var nextRow = rows[i + 1];
308 if (row.PriceFactor != nextRow.PriceFactor)
310 yield
return row.GetDividend(nextRow, symbol, _exchangeHours, decimalPlaces: 3);
314 yield
return row.GetSplit(nextRow, symbol, _exchangeHours);