Skip to content

Commit

Permalink
WIP on master (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssnyder-intrinio authored Dec 26, 2024
1 parent 6e54b57 commit a039767
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 48 deletions.
156 changes: 108 additions & 48 deletions Intrinio.Realtime/Composite/GreekClient.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Threading.Tasks;

namespace Intrinio.Realtime.Composite;

using Serilog;
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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<string,DateTime> 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)
Expand Down
1 change: 1 addition & 0 deletions SampleApp/GreekSampleApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit a039767

Please sign in to comment.