Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
31 changes: 30 additions & 1 deletion Intrinio.Realtime/Composite/DataCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ internal class DataCache : IDataCache
public OnSecuritySupplementalDatumUpdated? SecuritySupplementalDatumUpdatedCallback { get; set; }
public OnOptionsContractSupplementalDatumUpdated? OptionsContractSupplementalDatumUpdatedCallback { get; set; }

public OnOptionsContractGreekDataUpdated? OptionsContractGreekDataUpdatedCallback { get; set; }

public OnEquitiesTradeUpdated? EquitiesTradeUpdatedCallback { get; set; }
public OnEquitiesQuoteUpdated? EquitiesQuoteUpdatedCallback { get; set; }
public OnEquitiesTradeCandleStickUpdated? EquitiesTradeCandleStickUpdatedCallback { get; set; }
Expand Down Expand Up @@ -115,10 +117,37 @@ public bool SetOptionSupplementalDatum(string tickerSymbol, string contract, str
}

return false;

}

#endregion //Supplementary Data

#region Greeks

public Greek? GetOptionsContractGreekData(string tickerSymbol, string contract, string key)
{
return _securities.TryGetValue(tickerSymbol, out ISecurityData securityData)
? securityData.GetOptionsContractGreekData(contract, key)
: null;
}

public bool SetOptionGreekData(string tickerSymbol, string contract, string key, Greek? data, GreekDataUpdate update)
{
if (!String.IsNullOrWhiteSpace(tickerSymbol))
{
ISecurityData securityData;

if (!_securities.TryGetValue(tickerSymbol, out securityData))
{
SecurityData newDatum = new SecurityData(tickerSymbol, null, null, null, null, null, null);
securityData = _securities.AddOrUpdate(tickerSymbol, newDatum, (key, oldValue) => oldValue == null ? newDatum : oldValue);
}
return ((SecurityData)securityData).SetOptionsContractGreekData(contract, key, data, OptionsContractGreekDataUpdatedCallback, this, update);
}

return false;
}

#endregion //Greeks

#region Sub-caches

Expand Down
29 changes: 19 additions & 10 deletions Intrinio.Realtime/Composite/Delegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,28 @@ namespace Intrinio.Realtime.Composite;
public delegate void OnSupplementalDatumUpdated(string key, double? datum, IDataCache dataCache);
public delegate void OnSecuritySupplementalDatumUpdated(string key, double? datum, ISecurityData securityData, IDataCache dataCache);
public delegate void OnOptionsContractSupplementalDatumUpdated(string key, double? datum, IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache);
public delegate void OnOptionsContractGreekDataUpdated(string key, Greek? datum, IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache);

public delegate void OnEquitiesTradeUpdated(ISecurityData securityData, IDataCache dataCache);
public delegate void OnEquitiesQuoteUpdated(ISecurityData SecurityData, IDataCache DataCache);
public delegate void OnEquitiesTradeCandleStickUpdated(ISecurityData securityData, IDataCache dataCache);
public delegate void OnEquitiesQuoteCandleStickUpdated(ISecurityData SecurityData, IDataCache DataCache);
public delegate void OnEquitiesTradeUpdated(ISecurityData securityData, IDataCache dataCache, Equities.Trade? trade);
public delegate void OnEquitiesQuoteUpdated(ISecurityData SecurityData, IDataCache DataCache, Equities.Quote? quote);
public delegate void OnEquitiesTradeCandleStickUpdated(ISecurityData securityData, IDataCache dataCache, Equities.TradeCandleStick? tradeCandleStick);
public delegate void OnEquitiesQuoteCandleStickUpdated(ISecurityData SecurityData, IDataCache DataCache, Equities.QuoteCandleStick? quoteCandleStick);

public delegate void OnOptionsTradeUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
public delegate void OnOptionsQuoteUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
public delegate void OnOptionsRefreshUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
public delegate void OnOptionsUnusualActivityUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
public delegate void OnOptionsTradeCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
public delegate void OnOptionsQuoteCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
public delegate void OnOptionsTradeUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Trade? trade);
public delegate void OnOptionsQuoteUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Quote? quote);
public delegate void OnOptionsRefreshUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Refresh? refresh);
public delegate void OnOptionsUnusualActivityUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.UnusualActivity? unusualActivity);
public delegate void OnOptionsTradeCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.TradeCandleStick? tradeCandleStick);
public delegate void OnOptionsQuoteCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.QuoteCandleStick? quoteCandleStick);

/// <summary>
/// The function used to update the Supplemental value in the cache.
/// </summary>
public delegate double? SupplementalDatumUpdate(string key, double? oldValue, double? newValue);

/// <summary>
/// The function used to update the Greek value in the cache.
/// </summary>
public delegate Greek? GreekDataUpdate(string key, Greek? oldValue, Greek? newValue);

public delegate void CalculateNewGreek(IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache);
19 changes: 18 additions & 1 deletion Intrinio.Realtime/Composite/Greek.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Diagnostics.CodeAnalysis;

namespace Intrinio.Realtime.Composite;

public ref struct Greek
public struct Greek
{
public readonly double ImpliedVolatility;
public readonly double Delta;
Expand All @@ -18,4 +20,19 @@ public Greek(double impliedVolatility, double delta, double gamma, double theta,
Vega = vega;
IsValid = isValid;
}

public override bool Equals([NotNullWhen(true)] object? obj)
{
return obj != null && obj is Greek ? Equals((Greek)obj) : false;
}

public bool Equals(Greek obj)
{
return ImpliedVolatility == obj.ImpliedVolatility
&& Delta == obj.Delta
&& Gamma == obj.Gamma
&& Theta == obj.Theta
&& Vega == obj.Vega
&& IsValid == obj.IsValid;
}
};
54 changes: 33 additions & 21 deletions Intrinio.Realtime/Composite/GreekClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,12 @@ public class GreekClient : Intrinio.Realtime.Equities.ISocketPlugIn, Intrinio.Re
{
#region Data Members
private readonly IDataCache _cache;
public const string BlackScholesImpliedVolatilityKeyName = "IntrinioBlackScholesImpliedVolatility";
public const string BlackScholesDeltaKeyName = "IntrinioBlackScholesDelta";
public const string BlackScholesGammaKeyName = "IntrinioBlackScholesGamma";
public const string BlackScholesThetaKeyName = "IntrinioBlackScholesTheta";
public const string BlackScholesVegaKeyName = "IntrinioBlackScholesVega";
public const string DividendYieldKeyName = "DividendYield";
public const string RiskFreeInterestRateKeyName = "RiskFreeInterestRate";
public const string BlackScholesKeyName = "IntrinioBlackScholes";
private readonly ConcurrentDictionary<string, CalculateNewGreek> _calcLookup;
private readonly SupplementalDatumUpdate _updateFunc = (string key, double? oldValue, double? newValue) => { return newValue; };
private readonly GreekDataUpdate _updateFunc = (string key, Greek? oldValue, Greek? newValue) => { return newValue; };
private readonly SupplementalDatumUpdate _updateFuncNumber = (string key, double? oldValue, double? newValue) => { return newValue; };
private Timer? _dividendFetchTimer;
private Timer? _riskFreeInterestRateFetchTimer;
private readonly Intrinio.SDK.Client.ApiClient _apiClient;
Expand All @@ -50,9 +46,9 @@ public int ApiCallSpacerMilliseconds
private bool _dividendYieldWorking = false;
private readonly bool _selfCache;

public OnOptionsContractSupplementalDatumUpdated? OnGreekValueUpdated
public OnOptionsContractGreekDataUpdated? OnGreekValueUpdated
{
set { _cache.OptionsContractSupplementalDatumUpdatedCallback += value; }
set { _cache.OptionsContractGreekDataUpdatedCallback += value; }
}
#endregion //Data Members

Expand All @@ -65,7 +61,7 @@ public OnOptionsContractSupplementalDatumUpdated? OnGreekValueUpdated
/// <param name="onGreekValueUpdated"></param>
/// <param name="apiKey"></param>
/// <param name="cache"></param>
public GreekClient(GreekUpdateFrequency greekUpdateFrequency, OnOptionsContractSupplementalDatumUpdated onGreekValueUpdated, string apiKey, IDataCache? cache = null)
public GreekClient(GreekUpdateFrequency greekUpdateFrequency, OnOptionsContractGreekDataUpdated onGreekValueUpdated, string apiKey, IDataCache? cache = null)
{
_apiCallSpacerMilliseconds = 1100;
_dividendYieldUpdatePeriodHours = 4;
Expand Down Expand Up @@ -279,7 +275,7 @@ private void FetchInitialCompanyDividends(int daysAgo)
{
if (!String.IsNullOrWhiteSpace(companyDailyMetric.Company.Ticker) && companyDailyMetric.DividendYield.HasValue)
{
_cache.SetSecuritySupplementalDatum(companyDailyMetric.Company.Ticker, DividendYieldKeyName, Convert.ToDouble(companyDailyMetric.DividendYield ?? 0m), _updateFunc);
_cache.SetSecuritySupplementalDatum(companyDailyMetric.Company.Ticker, DividendYieldKeyName, Convert.ToDouble(companyDailyMetric.DividendYield ?? 0m), _updateFuncNumber);
_seenTickers[String.Intern(companyDailyMetric.Company.Ticker)] = DateTime.UtcNow;
}
}
Expand All @@ -305,13 +301,13 @@ private void RefreshDividendYield(string ticker)
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);
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, Convert.ToDouble(result ?? 0m), _updateFuncNumber);
_seenTickers[ticker] = DateTime.UtcNow;
Thread.Sleep(_apiCallSpacerMilliseconds); //don't try to get rate limited.
}
catch (Exception e)
{
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, 0.0D, _updateFunc);
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, 0.0D, _updateFuncNumber);
_seenTickers[ticker] = DateTime.UtcNow;
Thread.Sleep(_apiCallSpacerMilliseconds); //don't try to get rate limited.
}
Expand Down Expand Up @@ -358,7 +354,7 @@ private void FetchRiskFreeInterestRate(object? _)
Decimal? results = _indexApi.GetEconomicIndexDataPointNumber("$DTB3", "level");
if (results.HasValue)
{
_cache.SetSupplementaryDatum(RiskFreeInterestRateKeyName, Convert.ToDouble(results.Value) / 100.0D, _updateFunc);
_cache.SetSupplementaryDatum(RiskFreeInterestRateKeyName, Convert.ToDouble(results.Value) / 100.0D, _updateFuncNumber);
success = true;
}

Expand Down Expand Up @@ -395,13 +391,35 @@ public void UpdateGreeks(ISecurityData securityData, IDataCache dataCache)
foreach (KeyValuePair<string,IOptionsContractData> keyValuePair in securityData.AllOptionsContractData)
UpdateGreeks(keyValuePair.Value, dataCache, securityData);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UpdateGreeks(ISecurityData securityData, IDataCache dataCache, Equities.Trade? trade)
{
UpdateGreeks(securityData, dataCache);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UpdateGreeks(ISecurityData securityData, IDataCache dataCache, Equities.Quote? quote)
{
UpdateGreeks(securityData, dataCache);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateGreeks(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData)
{
foreach (CalculateNewGreek calculateNewGreek in _calcLookup.Values)
calculateNewGreek(optionsContractData, securityData, dataCache);
}
}

private void UpdateGreeks(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Trade? trade)
{
UpdateGreeks(optionsContractData, dataCache, securityData);
}

private void UpdateGreeks(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Quote? quote)
{
UpdateGreeks(optionsContractData, dataCache, securityData);
}

private void BlackScholesCalc(IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache)
{
Expand All @@ -416,13 +434,7 @@ private void BlackScholesCalc(IOptionsContractData optionsContractData, ISecurit
Greek result = BlackScholesGreekCalculator.Calculate(riskFreeInterestRate.Value, dividendYield.Value, equitiesTrade.Value.Price, optionsQuote.Value);

if (result.IsValid)
{
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesImpliedVolatilityKeyName, result.ImpliedVolatility, _updateFunc);
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesDeltaKeyName, result.Delta, _updateFunc);
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesGammaKeyName, result.Gamma, _updateFunc);
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesThetaKeyName, result.Theta, _updateFunc);
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesVegaKeyName, result.Vega, _updateFunc);
}
dataCache.SetOptionGreekData(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesKeyName, result, _updateFunc);
}

#endregion //Private Methods
Expand Down
26 changes: 26 additions & 0 deletions Intrinio.Realtime/Composite/IDataCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ public interface IDataCache : Intrinio.Realtime.Equities.ISocketPlugIn, Intrinio

#endregion //Supplementary Data

#region Greek Data

/// <summary>
/// Get a supplemental data point stored in a specific option contract's cache.
/// </summary>
/// <param name="tickerSymbol"></param>
/// <param name="contract"></param>
/// <param name="key"></param>
/// <returns></returns>
Greek? GetOptionsContractGreekData(string tickerSymbol, string contract, string key);

/// <summary>
/// Set a supplemental data point stored in a specific option contract's cache.
/// </summary>
/// <param name="tickerSymbol"></param>
/// <param name="contract"></param>
/// <param name="key"></param>
/// <param name="data"></param>
/// <param name="update">The function used to update the Greek value in the cache.</param>
/// <returns></returns>
bool SetOptionGreekData(string tickerSymbol, string contract, string key, Greek? data, GreekDataUpdate update);

#endregion //Supplementary Data

#region Sub-caches
/// <summary>
/// Get the cache for a specific security
Expand Down Expand Up @@ -342,5 +366,7 @@ public interface IDataCache : Intrinio.Realtime.Equities.ISocketPlugIn, Intrinio
/// </summary>
OnOptionsQuoteCandleStickUpdated? OptionsQuoteCandleStickUpdatedCallback { get; set; }

OnOptionsContractGreekDataUpdated? OptionsContractGreekDataUpdatedCallback { get; set; }

#endregion //Delegates
}
5 changes: 5 additions & 0 deletions Intrinio.Realtime/Composite/IOptionsContractData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ public interface IOptionsContractData {
internal bool SetSupplementaryDatum(string key, double? datum, SupplementalDatumUpdate update);
internal bool SetSupplementaryDatum(string key, double? datum, OnOptionsContractSupplementalDatumUpdated? onOptionsContractSupplementalDatumUpdated, ISecurityData securityData, IDataCache dataCache, SupplementalDatumUpdate update);
IReadOnlyDictionary<string, double?> AllSupplementaryData { get; }

Greek? GetGreekData(string key);
internal bool SetGreekData(string key, Greek? datum, GreekDataUpdate update);
internal bool SetGreekData(string key, Greek? datum, OnOptionsContractGreekDataUpdated? onOptionsContractGreekDataUpdated, ISecurityData securityData, IDataCache dataCache, GreekDataUpdate update);
IReadOnlyDictionary<string, Greek?> AllGreekData { get; }
}
5 changes: 5 additions & 0 deletions Intrinio.Realtime/Composite/ISecurityData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,9 @@ public interface ISecurityData {

internal bool SetOptionsContractSupplementalDatum(string contract, string key, double? datum, SupplementalDatumUpdate update);
internal bool SetOptionsContractSupplementalDatum(string contract, string key, double? datum, OnOptionsContractSupplementalDatumUpdated? onOptionsContractSupplementalDatumUpdated, IDataCache dataCache, SupplementalDatumUpdate update);

Greek? GetOptionsContractGreekData(string contract, string key);

internal bool SetOptionsContractGreekData(string contract, string key, Greek? data, GreekDataUpdate update);
internal bool SetOptionsContractGreekData(string contract, string key, Greek? data, OnOptionsContractGreekDataUpdated? onOptionsContractGreekDataUpdated, IDataCache dataCache, GreekDataUpdate update);
}
Loading