Skip to content

Commit 3160c00

Browse files
Full context and 1st class greeks (#79)
* updated greek client for new calc and first class greeks * more context on callbacks * update sample app * version bump
1 parent 706d4de commit 3160c00

14 files changed

+244
-57
lines changed

.DS_Store

0 Bytes
Binary file not shown.

Intrinio.Realtime/Composite/DataCache.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ internal class DataCache : IDataCache
1919
public OnSecuritySupplementalDatumUpdated? SecuritySupplementalDatumUpdatedCallback { get; set; }
2020
public OnOptionsContractSupplementalDatumUpdated? OptionsContractSupplementalDatumUpdatedCallback { get; set; }
2121

22+
public OnOptionsContractGreekDataUpdated? OptionsContractGreekDataUpdatedCallback { get; set; }
23+
2224
public OnEquitiesTradeUpdated? EquitiesTradeUpdatedCallback { get; set; }
2325
public OnEquitiesQuoteUpdated? EquitiesQuoteUpdatedCallback { get; set; }
2426
public OnEquitiesTradeCandleStickUpdated? EquitiesTradeCandleStickUpdatedCallback { get; set; }
@@ -115,10 +117,37 @@ public bool SetOptionSupplementalDatum(string tickerSymbol, string contract, str
115117
}
116118

117119
return false;
118-
119120
}
120121

121122
#endregion //Supplementary Data
123+
124+
#region Greeks
125+
126+
public Greek? GetOptionsContractGreekData(string tickerSymbol, string contract, string key)
127+
{
128+
return _securities.TryGetValue(tickerSymbol, out ISecurityData securityData)
129+
? securityData.GetOptionsContractGreekData(contract, key)
130+
: null;
131+
}
132+
133+
public bool SetOptionGreekData(string tickerSymbol, string contract, string key, Greek? data, GreekDataUpdate update)
134+
{
135+
if (!String.IsNullOrWhiteSpace(tickerSymbol))
136+
{
137+
ISecurityData securityData;
138+
139+
if (!_securities.TryGetValue(tickerSymbol, out securityData))
140+
{
141+
SecurityData newDatum = new SecurityData(tickerSymbol, null, null, null, null, null, null);
142+
securityData = _securities.AddOrUpdate(tickerSymbol, newDatum, (key, oldValue) => oldValue == null ? newDatum : oldValue);
143+
}
144+
return ((SecurityData)securityData).SetOptionsContractGreekData(contract, key, data, OptionsContractGreekDataUpdatedCallback, this, update);
145+
}
146+
147+
return false;
148+
}
149+
150+
#endregion //Greeks
122151

123152
#region Sub-caches
124153

Intrinio.Realtime/Composite/Delegates.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,28 @@ namespace Intrinio.Realtime.Composite;
33
public delegate void OnSupplementalDatumUpdated(string key, double? datum, IDataCache dataCache);
44
public delegate void OnSecuritySupplementalDatumUpdated(string key, double? datum, ISecurityData securityData, IDataCache dataCache);
55
public delegate void OnOptionsContractSupplementalDatumUpdated(string key, double? datum, IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache);
6+
public delegate void OnOptionsContractGreekDataUpdated(string key, Greek? datum, IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache);
67

7-
public delegate void OnEquitiesTradeUpdated(ISecurityData securityData, IDataCache dataCache);
8-
public delegate void OnEquitiesQuoteUpdated(ISecurityData SecurityData, IDataCache DataCache);
9-
public delegate void OnEquitiesTradeCandleStickUpdated(ISecurityData securityData, IDataCache dataCache);
10-
public delegate void OnEquitiesQuoteCandleStickUpdated(ISecurityData SecurityData, IDataCache DataCache);
8+
public delegate void OnEquitiesTradeUpdated(ISecurityData securityData, IDataCache dataCache, Equities.Trade? trade);
9+
public delegate void OnEquitiesQuoteUpdated(ISecurityData SecurityData, IDataCache DataCache, Equities.Quote? quote);
10+
public delegate void OnEquitiesTradeCandleStickUpdated(ISecurityData securityData, IDataCache dataCache, Equities.TradeCandleStick? tradeCandleStick);
11+
public delegate void OnEquitiesQuoteCandleStickUpdated(ISecurityData SecurityData, IDataCache DataCache, Equities.QuoteCandleStick? quoteCandleStick);
1112

12-
public delegate void OnOptionsTradeUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
13-
public delegate void OnOptionsQuoteUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
14-
public delegate void OnOptionsRefreshUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
15-
public delegate void OnOptionsUnusualActivityUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
16-
public delegate void OnOptionsTradeCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
17-
public delegate void OnOptionsQuoteCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData);
13+
public delegate void OnOptionsTradeUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Trade? trade);
14+
public delegate void OnOptionsQuoteUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Quote? quote);
15+
public delegate void OnOptionsRefreshUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Refresh? refresh);
16+
public delegate void OnOptionsUnusualActivityUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.UnusualActivity? unusualActivity);
17+
public delegate void OnOptionsTradeCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.TradeCandleStick? tradeCandleStick);
18+
public delegate void OnOptionsQuoteCandleStickUpdated(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.QuoteCandleStick? quoteCandleStick);
1819

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

25+
/// <summary>
26+
/// The function used to update the Greek value in the cache.
27+
/// </summary>
28+
public delegate Greek? GreekDataUpdate(string key, Greek? oldValue, Greek? newValue);
29+
2130
public delegate void CalculateNewGreek(IOptionsContractData optionsContractData, ISecurityData securityData, IDataCache dataCache);

Intrinio.Realtime/Composite/Greek.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
13
namespace Intrinio.Realtime.Composite;
24

3-
public ref struct Greek
5+
public struct Greek
46
{
57
public readonly double ImpliedVolatility;
68
public readonly double Delta;
@@ -18,4 +20,19 @@ public Greek(double impliedVolatility, double delta, double gamma, double theta,
1820
Vega = vega;
1921
IsValid = isValid;
2022
}
23+
24+
public override bool Equals([NotNullWhen(true)] object? obj)
25+
{
26+
return obj != null && obj is Greek ? Equals((Greek)obj) : false;
27+
}
28+
29+
public bool Equals(Greek obj)
30+
{
31+
return ImpliedVolatility == obj.ImpliedVolatility
32+
&& Delta == obj.Delta
33+
&& Gamma == obj.Gamma
34+
&& Theta == obj.Theta
35+
&& Vega == obj.Vega
36+
&& IsValid == obj.IsValid;
37+
}
2138
};

Intrinio.Realtime/Composite/GreekClient.cs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,12 @@ public class GreekClient : Intrinio.Realtime.Equities.ISocketPlugIn, Intrinio.Re
1717
{
1818
#region Data Members
1919
private readonly IDataCache _cache;
20-
public const string BlackScholesImpliedVolatilityKeyName = "IntrinioBlackScholesImpliedVolatility";
21-
public const string BlackScholesDeltaKeyName = "IntrinioBlackScholesDelta";
22-
public const string BlackScholesGammaKeyName = "IntrinioBlackScholesGamma";
23-
public const string BlackScholesThetaKeyName = "IntrinioBlackScholesTheta";
24-
public const string BlackScholesVegaKeyName = "IntrinioBlackScholesVega";
2520
public const string DividendYieldKeyName = "DividendYield";
2621
public const string RiskFreeInterestRateKeyName = "RiskFreeInterestRate";
2722
public const string BlackScholesKeyName = "IntrinioBlackScholes";
2823
private readonly ConcurrentDictionary<string, CalculateNewGreek> _calcLookup;
29-
private readonly SupplementalDatumUpdate _updateFunc = (string key, double? oldValue, double? newValue) => { return newValue; };
24+
private readonly GreekDataUpdate _updateFunc = (string key, Greek? oldValue, Greek? newValue) => { return newValue; };
25+
private readonly SupplementalDatumUpdate _updateFuncNumber = (string key, double? oldValue, double? newValue) => { return newValue; };
3026
private Timer? _dividendFetchTimer;
3127
private Timer? _riskFreeInterestRateFetchTimer;
3228
private readonly Intrinio.SDK.Client.ApiClient _apiClient;
@@ -50,9 +46,9 @@ public int ApiCallSpacerMilliseconds
5046
private bool _dividendYieldWorking = false;
5147
private readonly bool _selfCache;
5248

53-
public OnOptionsContractSupplementalDatumUpdated? OnGreekValueUpdated
49+
public OnOptionsContractGreekDataUpdated? OnGreekValueUpdated
5450
{
55-
set { _cache.OptionsContractSupplementalDatumUpdatedCallback += value; }
51+
set { _cache.OptionsContractGreekDataUpdatedCallback += value; }
5652
}
5753
#endregion //Data Members
5854

@@ -65,7 +61,7 @@ public OnOptionsContractSupplementalDatumUpdated? OnGreekValueUpdated
6561
/// <param name="onGreekValueUpdated"></param>
6662
/// <param name="apiKey"></param>
6763
/// <param name="cache"></param>
68-
public GreekClient(GreekUpdateFrequency greekUpdateFrequency, OnOptionsContractSupplementalDatumUpdated onGreekValueUpdated, string apiKey, IDataCache? cache = null)
64+
public GreekClient(GreekUpdateFrequency greekUpdateFrequency, OnOptionsContractGreekDataUpdated onGreekValueUpdated, string apiKey, IDataCache? cache = null)
6965
{
7066
_apiCallSpacerMilliseconds = 1100;
7167
_dividendYieldUpdatePeriodHours = 4;
@@ -279,7 +275,7 @@ private void FetchInitialCompanyDividends(int daysAgo)
279275
{
280276
if (!String.IsNullOrWhiteSpace(companyDailyMetric.Company.Ticker) && companyDailyMetric.DividendYield.HasValue)
281277
{
282-
_cache.SetSecuritySupplementalDatum(companyDailyMetric.Company.Ticker, DividendYieldKeyName, Convert.ToDouble(companyDailyMetric.DividendYield ?? 0m), _updateFunc);
278+
_cache.SetSecuritySupplementalDatum(companyDailyMetric.Company.Ticker, DividendYieldKeyName, Convert.ToDouble(companyDailyMetric.DividendYield ?? 0m), _updateFuncNumber);
283279
_seenTickers[String.Intern(companyDailyMetric.Company.Ticker)] = DateTime.UtcNow;
284280
}
285281
}
@@ -305,13 +301,13 @@ private void RefreshDividendYield(string ticker)
305301
string securityId = _securityApi.GetSecurityByIdAsync($"{ticker}:US").Result.Id;
306302
Thread.Sleep(_apiCallSpacerMilliseconds); //don't try to get rate limited.
307303
decimal? result = _securityApi.GetSecurityDataPointNumberAsync(securityId, dividendYieldTag).Result;
308-
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, Convert.ToDouble(result ?? 0m), _updateFunc);
304+
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, Convert.ToDouble(result ?? 0m), _updateFuncNumber);
309305
_seenTickers[ticker] = DateTime.UtcNow;
310306
Thread.Sleep(_apiCallSpacerMilliseconds); //don't try to get rate limited.
311307
}
312308
catch (Exception e)
313309
{
314-
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, 0.0D, _updateFunc);
310+
_cache.SetSecuritySupplementalDatum(ticker, DividendYieldKeyName, 0.0D, _updateFuncNumber);
315311
_seenTickers[ticker] = DateTime.UtcNow;
316312
Thread.Sleep(_apiCallSpacerMilliseconds); //don't try to get rate limited.
317313
}
@@ -358,7 +354,7 @@ private void FetchRiskFreeInterestRate(object? _)
358354
Decimal? results = _indexApi.GetEconomicIndexDataPointNumber("$DTB3", "level");
359355
if (results.HasValue)
360356
{
361-
_cache.SetSupplementaryDatum(RiskFreeInterestRateKeyName, Convert.ToDouble(results.Value) / 100.0D, _updateFunc);
357+
_cache.SetSupplementaryDatum(RiskFreeInterestRateKeyName, Convert.ToDouble(results.Value) / 100.0D, _updateFuncNumber);
362358
success = true;
363359
}
364360

@@ -395,13 +391,35 @@ public void UpdateGreeks(ISecurityData securityData, IDataCache dataCache)
395391
foreach (KeyValuePair<string,IOptionsContractData> keyValuePair in securityData.AllOptionsContractData)
396392
UpdateGreeks(keyValuePair.Value, dataCache, securityData);
397393
}
394+
395+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
396+
public void UpdateGreeks(ISecurityData securityData, IDataCache dataCache, Equities.Trade? trade)
397+
{
398+
UpdateGreeks(securityData, dataCache);
399+
}
400+
401+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
402+
public void UpdateGreeks(ISecurityData securityData, IDataCache dataCache, Equities.Quote? quote)
403+
{
404+
UpdateGreeks(securityData, dataCache);
405+
}
398406

399407
[MethodImpl(MethodImplOptions.AggressiveInlining)]
400408
private void UpdateGreeks(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData)
401409
{
402410
foreach (CalculateNewGreek calculateNewGreek in _calcLookup.Values)
403411
calculateNewGreek(optionsContractData, securityData, dataCache);
404-
}
412+
}
413+
414+
private void UpdateGreeks(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Trade? trade)
415+
{
416+
UpdateGreeks(optionsContractData, dataCache, securityData);
417+
}
418+
419+
private void UpdateGreeks(IOptionsContractData optionsContractData, IDataCache dataCache, ISecurityData securityData, Options.Quote? quote)
420+
{
421+
UpdateGreeks(optionsContractData, dataCache, securityData);
422+
}
405423

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

418436
if (result.IsValid)
419-
{
420-
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesImpliedVolatilityKeyName, result.ImpliedVolatility, _updateFunc);
421-
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesDeltaKeyName, result.Delta, _updateFunc);
422-
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesGammaKeyName, result.Gamma, _updateFunc);
423-
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesThetaKeyName, result.Theta, _updateFunc);
424-
dataCache.SetOptionSupplementalDatum(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesVegaKeyName, result.Vega, _updateFunc);
425-
}
437+
dataCache.SetOptionGreekData(securityData.TickerSymbol, optionsContractData.Contract, BlackScholesKeyName, result, _updateFunc);
426438
}
427439

428440
#endregion //Private Methods

Intrinio.Realtime/Composite/IDataCache.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,30 @@ public interface IDataCache : Intrinio.Realtime.Equities.ISocketPlugIn, Intrinio
7070

7171
#endregion //Supplementary Data
7272

73+
#region Greek Data
74+
75+
/// <summary>
76+
/// Get a supplemental data point stored in a specific option contract's cache.
77+
/// </summary>
78+
/// <param name="tickerSymbol"></param>
79+
/// <param name="contract"></param>
80+
/// <param name="key"></param>
81+
/// <returns></returns>
82+
Greek? GetOptionsContractGreekData(string tickerSymbol, string contract, string key);
83+
84+
/// <summary>
85+
/// Set a supplemental data point stored in a specific option contract's cache.
86+
/// </summary>
87+
/// <param name="tickerSymbol"></param>
88+
/// <param name="contract"></param>
89+
/// <param name="key"></param>
90+
/// <param name="data"></param>
91+
/// <param name="update">The function used to update the Greek value in the cache.</param>
92+
/// <returns></returns>
93+
bool SetOptionGreekData(string tickerSymbol, string contract, string key, Greek? data, GreekDataUpdate update);
94+
95+
#endregion //Supplementary Data
96+
7397
#region Sub-caches
7498
/// <summary>
7599
/// Get the cache for a specific security
@@ -342,5 +366,7 @@ public interface IDataCache : Intrinio.Realtime.Equities.ISocketPlugIn, Intrinio
342366
/// </summary>
343367
OnOptionsQuoteCandleStickUpdated? OptionsQuoteCandleStickUpdatedCallback { get; set; }
344368

369+
OnOptionsContractGreekDataUpdated? OptionsContractGreekDataUpdatedCallback { get; set; }
370+
345371
#endregion //Delegates
346372
}

Intrinio.Realtime/Composite/IOptionsContractData.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ public interface IOptionsContractData {
3636
internal bool SetSupplementaryDatum(string key, double? datum, SupplementalDatumUpdate update);
3737
internal bool SetSupplementaryDatum(string key, double? datum, OnOptionsContractSupplementalDatumUpdated? onOptionsContractSupplementalDatumUpdated, ISecurityData securityData, IDataCache dataCache, SupplementalDatumUpdate update);
3838
IReadOnlyDictionary<string, double?> AllSupplementaryData { get; }
39+
40+
Greek? GetGreekData(string key);
41+
internal bool SetGreekData(string key, Greek? datum, GreekDataUpdate update);
42+
internal bool SetGreekData(string key, Greek? datum, OnOptionsContractGreekDataUpdated? onOptionsContractGreekDataUpdated, ISecurityData securityData, IDataCache dataCache, GreekDataUpdate update);
43+
IReadOnlyDictionary<string, Greek?> AllGreekData { get; }
3944
}

Intrinio.Realtime/Composite/ISecurityData.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,9 @@ public interface ISecurityData {
8080

8181
internal bool SetOptionsContractSupplementalDatum(string contract, string key, double? datum, SupplementalDatumUpdate update);
8282
internal bool SetOptionsContractSupplementalDatum(string contract, string key, double? datum, OnOptionsContractSupplementalDatumUpdated? onOptionsContractSupplementalDatumUpdated, IDataCache dataCache, SupplementalDatumUpdate update);
83+
84+
Greek? GetOptionsContractGreekData(string contract, string key);
85+
86+
internal bool SetOptionsContractGreekData(string contract, string key, Greek? data, GreekDataUpdate update);
87+
internal bool SetOptionsContractGreekData(string contract, string key, Greek? data, OnOptionsContractGreekDataUpdated? onOptionsContractGreekDataUpdated, IDataCache dataCache, GreekDataUpdate update);
8388
}

0 commit comments

Comments
 (0)