From a0397677e56ebc22e2206460bf56ea1267642e10 Mon Sep 17 00:00:00 2001 From: ssnyder-intrinio <87659980+ssnyder-intrinio@users.noreply.github.com> Date: Thu, 26 Dec 2024 10:44:53 -0600 Subject: [PATCH] WIP on master (#54) --- Intrinio.Realtime/Composite/GreekClient.cs | 156 ++++++++++++++------- SampleApp/GreekSampleApp.cs | 1 + 2 files changed, 109 insertions(+), 48 deletions(-) diff --git a/Intrinio.Realtime/Composite/GreekClient.cs b/Intrinio.Realtime/Composite/GreekClient.cs index a70e5b6..4be25ec 100644 --- a/Intrinio.Realtime/Composite/GreekClient.cs +++ b/Intrinio.Realtime/Composite/GreekClient.cs @@ -1,3 +1,5 @@ +using System.Threading.Tasks; + namespace Intrinio.Realtime.Composite; using Serilog; @@ -96,10 +98,25 @@ public GreekClient(GreekUpdateFrequency greekUpdateFrequency, OnOptionsContractS public void Start() { - FetchInitialCompanyDividends(); + Task.Run(() => + { + Log.Information("Fetching company daily metrics in bulk"); + for(int i = 365; i >= 0; i--) + FetchInitialCompanyDividends(i); + }); + Task.Run(() => + { + Log.Information("Fetching list of tickers with options associated"); + CacheListOfOptionableTickers(); + }); + Task.Run(() => + { + Log.Information("Fetching list of all securities."); + CacheAllSecurities(); + }); Log.Information("Fetching risk free interest rate and periodically additional new dividend yields"); _riskFreeInterestRateFetchTimer = new Timer(FetchRiskFreeInterestRate, null, 0, 11*60*60*1000); - _dividendFetchTimer = new Timer(FetchDividendYields, null, 60*1000, 30*1000); + _dividendFetchTimer = new Timer(RefreshDividendYields, null, 60*1000, 30*1000); } public void Stop() @@ -185,82 +202,125 @@ public void AddBlackScholes() #region Private Methods - private void FetchInitialCompanyDividends() + private void CacheListOfOptionableTickers() { - Log.Information("Fetching company daily metrics in bulk"); - //Fetch daily metrics in bulk + //Fetch known options tickers try { - string? nextPage = null; - TimeSpan subtract; - switch (DateTime.UtcNow.DayOfWeek) - { - case DayOfWeek.Sunday: - subtract = TimeSpan.FromDays(2); - break; - case DayOfWeek.Monday: - subtract = TimeSpan.FromDays(3); - break; - default: - subtract = TimeSpan.FromDays(1); - break; - } - DateTime date = DateTime.Today - subtract; //Assume we're starting morning-ish, so today's values aren't available + ApiResponseOptionsTickers result = _optionsApi.GetAllOptionsTickers(); + foreach (string ticker in result.Tickers) + _seenTickers.TryAdd(String.Intern(ticker), DateTime.MinValue); + Log.Information($"Found {result.Tickers.Count} optionable tickers."); + } + catch (Exception e) + { + Log.Warning(e, e.Message); + } + } + + private void CacheAllSecurities() + { + //Fetch known options tickers + try + { + string nextPage = null; do { - ApiResponseCompanyDailyMetrics result = _companyApi.GetAllCompaniesDailyMetrics(date, 1000, nextPage, null); - foreach (CompanyDailyMetric companyDailyMetric in result.DailyMetrics) + try { - if (!String.IsNullOrWhiteSpace(companyDailyMetric.Company.Ticker) && companyDailyMetric.DividendYield.HasValue) + ApiResponseSecurities response = _securityApi.GetAllSecurities(active: true, delisted: false, primaryListing: true, compositeMic: "USCOMP", pageSize: 9999, nextPage: nextPage); + nextPage = response.NextPage; + foreach (SecuritySummary securitySummary in response.Securities) { - _cache.SetSecuritySupplementalDatum(companyDailyMetric.Company.Ticker, DividendYieldKeyName, Convert.ToDouble(companyDailyMetric.DividendYield ?? 0m), _updateFunc); - _seenTickers[String.Intern(companyDailyMetric.Company.Ticker)] = DateTime.UtcNow; + _seenTickers.TryAdd(String.Intern(securitySummary.Ticker), DateTime.MinValue); } + Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. + } + catch (Exception e) + { + Log.Warning(e, e.Message); + Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. } - Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. - } while (!String.IsNullOrWhiteSpace(nextPage)); + }while (!String.IsNullOrWhiteSpace(nextPage)); } catch (Exception e) { Log.Warning(e, e.Message); } + } - Log.Information("Fetching list of tickers with options assiciated"); - //Fetch known options tickers + private void FetchInitialCompanyDividends(int daysAgo) + { + if (!_dividendYieldWorking) + { + _dividendYieldWorking = true; + try + { + string? nextPage = null; + TimeSpan subtract = TimeSpan.FromDays(daysAgo); + DateTime date = DateTime.Today - subtract; //Assume we're starting morning-ish, so today's values aren't available + do + { + ApiResponseCompanyDailyMetrics result = _companyApi.GetAllCompaniesDailyMetrics(date, 1000, nextPage, null); + nextPage = result.NextPage; + foreach (CompanyDailyMetric companyDailyMetric in result.DailyMetrics) + { + if (!String.IsNullOrWhiteSpace(companyDailyMetric.Company.Ticker) && companyDailyMetric.DividendYield.HasValue) + { + _cache.SetSecuritySupplementalDatum(companyDailyMetric.Company.Ticker, DividendYieldKeyName, Convert.ToDouble(companyDailyMetric.DividendYield ?? 0m), _updateFunc); + _seenTickers[String.Intern(companyDailyMetric.Company.Ticker)] = DateTime.UtcNow; + } + } + Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. + } while (!String.IsNullOrWhiteSpace(nextPage)); + } + catch (Exception e) + { + Log.Warning(e, e.Message); + } + finally + { + _dividendYieldWorking = false; + } + } + } + + private void RefreshDividendYield(string ticker) + { + const string dividendYieldTag = "trailing_dividend_yield"; try { - foreach (string ticker in (_optionsApi.GetAllOptionsTickers()).Tickers) - _seenTickers.TryAdd(String.Intern(ticker), DateTime.MinValue); + string securityId = _securityApi.GetSecurityByIdAsync($"{ticker}:US").Result.Id; + Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. + decimal? result = _securityApi.GetSecurityDataPointNumberAsync(securityId, dividendYieldTag).Result; + _cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, Convert.ToDouble(result ?? 0m), _updateFunc); + _seenTickers[ticker] = DateTime.UtcNow; + Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. } catch (Exception e) { - Log.Warning(e, e.Message); + _cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, 0.0D, _updateFunc); + _seenTickers[ticker] = DateTime.UtcNow; + Thread.Sleep(ApiCallSpacerMilliseconds); //don't try to get rate limited. } - } + } - private void FetchDividendYields(object? _) + private void RefreshDividendYields(object? _) { - const string dividendYieldTag = "trailing_dividend_yield"; if (!_dividendYieldWorking) { _dividendYieldWorking = true; try { + RefreshDividendYield("SPY"); + RefreshDividendYield("SPX"); + RefreshDividendYield("SPXW"); + RefreshDividendYield("RUT"); + RefreshDividendYield("VIX"); + Log.Information($"Refreshing dividend yields for {_seenTickers.Count} tickers..."); foreach (KeyValuePair seenTicker in _seenTickers.Where(t => t.Value < (DateTime.UtcNow - TimeSpan.FromHours(DividendYieldUpdatePeriodHours)))) { - try - { - decimal? result = _securityApi.GetSecurityDataPointNumberAsync(_securityApi.GetSecurityByIdAsync($"{seenTicker.Key}:US").Result.Id, dividendYieldTag).Result; - _cache.SetSecuritySupplementalDatum(seenTicker.Key, DividendYieldKeyName, Convert.ToDouble(result ?? 0m), _updateFunc); - _seenTickers[seenTicker.Key] = DateTime.UtcNow; - Thread.Sleep(2 * ApiCallSpacerMilliseconds); //don't try to get rate limited. - } - catch (Exception e) - { - _cache.SetSecuritySupplementalDatum(seenTicker.Key, DividendYieldKeyName, 0.0D, _updateFunc); - _seenTickers[seenTicker.Key] = DateTime.UtcNow; - Thread.Sleep(2 * ApiCallSpacerMilliseconds); //don't try to get rate limited. - } + RefreshDividendYield(seenTicker.Key); } } catch (Exception e) diff --git a/SampleApp/GreekSampleApp.cs b/SampleApp/GreekSampleApp.cs index ff9b4b1..423c883 100644 --- a/SampleApp/GreekSampleApp.cs +++ b/SampleApp/GreekSampleApp.cs @@ -82,6 +82,7 @@ static void TimerCallback(object obj) Log("Greek updates: {0}", _greekUpdatedEventCount); Log("Data Cache Security Count: {0}", _dataCache.AllSecurityData.Count); + Log("Dividend Yield Count: {0}", _dataCache.AllSecurityData.Where(kvp => kvp.Value.GetSupplementaryDatum("DividendYield").HasValue).Count()); Log("Unique Securities with Greeks Count: {0}", _seenGreekTickers.Count); }