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
26 changes: 13 additions & 13 deletions Intrinio.Realtime.Tests/BlackScholesGreekCalculatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void AccuracyTest_Call()
#endregion

#region Act
Greek greek = Intrinio.Realtime.Composite.BlackScholesGreekCalculator.Calculate(riskFreeInterestRate, dividendYield, equitiesTrade.Price, optionsQuote.Timestamp, (optionsQuote.AskPrice + optionsQuote.BidPrice) / 2, optionsQuote.IsPut(), optionsQuote.GetStrikePrice(), optionsQuote.GetExpirationDate());
Greek greek = Intrinio.Realtime.Composite.BlackScholesGreekCalculator.Calculate(riskFreeInterestRate, dividendYield, equitiesTrade.Price, optionsQuote.Timestamp, (optionsQuote.AskPrice + optionsQuote.BidPrice) / 2, 0.0D, 0.0D, optionsQuote.IsPut(), optionsQuote.GetStrikePrice(), optionsQuote.GetExpirationDate());
#endregion

#region Asserts
Expand All @@ -107,7 +107,7 @@ public void Calculate_InvalidMarketPrice_ReturnsFailure()
double q = 0.0;
double S = 100.0;

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, 0.0D, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsFalse(result.IsValid);
Assert.AreEqual(0.0, result.ImpliedVolatility);
Expand All @@ -125,7 +125,7 @@ public void Calculate_InvalidRiskFreeRate_ReturnsFailure()
double q = 0.0;
double S = 100.0;

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsFalse(result.IsValid);
Assert.AreEqual(0.0, result.ImpliedVolatility);
Expand All @@ -143,7 +143,7 @@ public void Calculate_InvalidUnderlyingPrice_ReturnsFailure()
double q = 0.0;
double S = 0.0;

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsFalse(result.IsValid);
Assert.AreEqual(0.0, result.ImpliedVolatility);
Expand All @@ -161,7 +161,7 @@ public void Calculate_ExpirationInPast_ReturnsFailure()
double q = 0.0;
double S = 100.0;

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsFalse(result.IsValid);
Assert.AreEqual(0.0, result.ImpliedVolatility);
Expand All @@ -179,7 +179,7 @@ public void Calculate_ExpirationNow_ReturnsFailure()
double q = 0.0;
double S = 100.0;

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsFalse(result.IsValid);
Assert.AreEqual(0.0, result.ImpliedVolatility);
Expand All @@ -197,7 +197,7 @@ public void Calculate_InvalidStrike_ReturnsFailure()
double q = 0.0;
double S = 100.0;

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsFalse(result.IsValid);
Assert.AreEqual(0.0, result.ImpliedVolatility);
Expand Down Expand Up @@ -225,7 +225,7 @@ public void Calculate_ATMCall_ReturnsCorrectGreeks()

Intrinio.Realtime.Options.Quote quote = CreateQuote(askPrice: marketPrice, bidPrice: marketPrice, unixTimestamp: 1755292170, expirationSecondsFromNow: tSeconds, strike: K, isPut: isPut);

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsTrue(result.IsValid);
Assert.AreEqual(expectedIV, result.ImpliedVolatility, Tolerance);
Expand Down Expand Up @@ -253,7 +253,7 @@ public void Calculate_ITMCall_ReturnsCorrectGreeks()

Intrinio.Realtime.Options.Quote quote = CreateQuote(askPrice: marketPrice, bidPrice: marketPrice, unixTimestamp: 1755292170, expirationSecondsFromNow: tSeconds, strike: K, isPut: isPut);

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsTrue(result.IsValid);
Assert.AreEqual(expectedIV, result.ImpliedVolatility, Tolerance);
Expand Down Expand Up @@ -281,7 +281,7 @@ public void Calculate_OTMPut_ReturnsCorrectGreeks()

Intrinio.Realtime.Options.Quote quote = CreateQuote(askPrice: marketPrice, bidPrice: marketPrice, unixTimestamp: 1755292170, expirationSecondsFromNow: tSeconds, strike: K, isPut: isPut);

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsTrue(result.IsValid);
Assert.AreEqual(expectedIV, result.ImpliedVolatility, Tolerance);
Expand Down Expand Up @@ -309,7 +309,7 @@ public void Calculate_DeepITMCallLowVol_ReturnsCorrectGreeks()

Intrinio.Realtime.Options.Quote quote = CreateQuote(askPrice: marketPrice, bidPrice: marketPrice, unixTimestamp: 1755292170, expirationSecondsFromNow: tSeconds, strike: K, isPut: isPut);

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsTrue(result.IsValid);
Assert.AreEqual(expectedIV, result.ImpliedVolatility, Tolerance * 750); // looser for low vol
Expand Down Expand Up @@ -337,7 +337,7 @@ public void Calculate_DeepOTMPutHighVol_ReturnsCorrectGreeks()

Intrinio.Realtime.Options.Quote quote = CreateQuote(askPrice: marketPrice, bidPrice: marketPrice, unixTimestamp: 1755292170, expirationSecondsFromNow: tSeconds, strike: K, isPut: isPut);

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, (quote.AskPrice + quote.BidPrice) / 2, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsTrue(result.IsValid);
Assert.AreEqual(expectedIV, result.ImpliedVolatility, Tolerance);
Expand Down Expand Up @@ -365,7 +365,7 @@ public void Calculate_VeryShortTimeATMCall_ReturnsCorrectGreeks()

Intrinio.Realtime.Options.Quote quote = CreateQuote(askPrice: marketPrice, bidPrice: marketPrice, unixTimestamp: 1755292170, expirationSecondsFromNow: tSeconds, strike: K, isPut: isPut);

Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, marketPrice, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());
Greek result = BlackScholesGreekCalculator.Calculate(r, q, S, quote.Timestamp, marketPrice, 0.0D, 0.0D, quote.IsPut(), quote.GetStrikePrice(), quote.GetExpirationDate());

Assert.IsTrue(result.IsValid);
Assert.AreEqual(expectedIV, result.ImpliedVolatility, Tolerance);
Expand Down
76 changes: 54 additions & 22 deletions Intrinio.Realtime/ClientStats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,74 @@ public class ClientStats
{
private readonly UInt64 _socketDataMessages;
private readonly UInt64 _socketTextMessages;
private readonly int _queueDepth;
private readonly UInt64 _queueDepth;
private readonly UInt64 _eventCount;
private readonly int _queueCapacity;
private readonly int _overflowQueueDepth;
private readonly int _overflowQueueCapacity;
private readonly int _droppedCount;
private readonly int _overflowCount;
private readonly UInt64 _queueCapacity;
private readonly UInt64 _overflowQueueDepth;
private readonly UInt64 _overflowQueueCapacity;
private readonly UInt64 _droppedCount;
private readonly UInt64 _overflowCount;
private readonly UInt64 _priorityQueueDepth;
private readonly UInt64 _priorityQueueCapacity;
private readonly UInt64 _priorityQueueDroppedCount;

public ClientStats(UInt64 socketDataMessages, UInt64 socketTextMessages, int queueDepth, UInt64 eventCount, int queueCapacity, int overflowQueueDepth, int overflowQueueCapacity, int droppedCount, int overflowCount)
public ClientStats(UInt64 socketDataMessages,
UInt64 socketTextMessages,
UInt64 queueDepth,
UInt64 eventCount,
UInt64 queueCapacity,
UInt64 overflowQueueDepth,
UInt64 overflowQueueCapacity,
UInt64 droppedCount,
UInt64 overflowCount,
UInt64 priorityQueueDepth,
UInt64 priorityQueueCapacity,
UInt64 priorityQueueDroppedCount)
{
_socketDataMessages = socketDataMessages;
_socketTextMessages = socketTextMessages;
_queueDepth = queueDepth;
_eventCount = eventCount;
_queueCapacity = queueCapacity;
_overflowQueueDepth = overflowQueueDepth;
_overflowQueueCapacity = overflowQueueCapacity;
_droppedCount = droppedCount;
_overflowCount = overflowCount;
_socketDataMessages = socketDataMessages;
_socketTextMessages = socketTextMessages;
_queueDepth = queueDepth;
_eventCount = eventCount;
_queueCapacity = queueCapacity;
_overflowQueueDepth = overflowQueueDepth;
_overflowQueueCapacity = overflowQueueCapacity;
_droppedCount = droppedCount;
_overflowCount = overflowCount;
_priorityQueueDepth = priorityQueueDepth;
_priorityQueueCapacity = priorityQueueCapacity;
_priorityQueueDroppedCount = priorityQueueDroppedCount;
}

public UInt64 SocketDataMessages { get { return _socketDataMessages; } }

public UInt64 SocketTextMessages { get { return _socketTextMessages; } }

public int QueueDepth { get { return _queueDepth; } }
public UInt64 QueueDepth { get { return _queueDepth; } }

public int QueueCapacity { get { return _queueCapacity; } }
public UInt64 QueueCapacity { get { return _queueCapacity; } }

public int OverflowQueueDepth { get { return _overflowQueueDepth; } }
public UInt64 OverflowQueueDepth { get { return _overflowQueueDepth; } }

public int OverflowQueueCapacity { get { return _overflowQueueCapacity; } }
public UInt64 OverflowQueueCapacity { get { return _overflowQueueCapacity; } }

public UInt64 EventCount { get { return _eventCount; } }

public int DroppedCount { get { return _droppedCount; } }
public UInt64 DroppedCount { get { return _droppedCount; } }

public int OverflowCount { get { return _overflowCount; } }
public UInt64 OverflowCount { get { return _overflowCount; } }

public UInt64 PriorityQueueDroppedCount
{
get { return _priorityQueueDroppedCount; }
}

public UInt64 PriorityQueueCapacity
{
get { return _priorityQueueCapacity; }
}

public UInt64 PriorityQueueDepth
{
get { return _priorityQueueDepth; }
}
}
14 changes: 9 additions & 5 deletions Intrinio.Realtime/Composite/BlackScholesGreekCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@ public static class BlackScholesGreekCalculator
private const double MAX_Z_SCORE = 8.0D;
private static readonly double root2Pi = Math.Sqrt(2.0D * Math.PI);

public static Greek Calculate(double riskFreeInterestRate, double dividendYield, double underlyingPrice, double latestEventUnixTimestamp, double marketPrice, bool isPut, double strike, DateTime expirationDate)
public static Greek Calculate(double riskFreeInterestRate, double dividendYield, double underlyingPrice, double latestEventUnixTimestamp, double marketPrice, double askPrice, double bidPrice, bool isPut, double strike, DateTime expirationDate)
{
if (marketPrice <= 0.0D || riskFreeInterestRate <= 0.0D || underlyingPrice <= 0.0D)
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);

double yearsToExpiration = GetYearsToExpiration(latestEventUnixTimestamp, expirationDate);

if (yearsToExpiration <= 0.0D || strike <= 0.0D)
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);

double impliedVolatility = CalcImpliedVolatility(isPut, underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice);
if (impliedVolatility == 0.0D)
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);


double askImpliedVolatility = (askPrice > 0.0D) ? CalcImpliedVolatility(isPut, underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, askPrice) : 0.0D;
double bidImpliedVolatility = (askPrice > 0.0D) ? CalcImpliedVolatility(isPut, underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, bidPrice) : 0.0D;

// Compute common values once for all Greeks to avoid redundant calcs
double sqrtT = Math.Sqrt(yearsToExpiration);
Expand All @@ -46,7 +50,7 @@ public static Greek Calculate(double riskFreeInterestRate, double dividendYield,
double term3 = dividendYield * underlyingPrice * expQt * (isPut ? (1.0D - nD1) : nD1);
double theta = isPut ? (-term1 + term2 - term3) / 365.25D : (-term1 - term2 + term3) / 365.25D;

return new Greek(impliedVolatility, delta, gamma, theta, vega, true);
return new Greek(impliedVolatility, delta, gamma, theta, vega, askImpliedVolatility, bidImpliedVolatility, true);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
10 changes: 8 additions & 2 deletions Intrinio.Realtime/Composite/Greek.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ public struct Greek
public readonly double Gamma;
public readonly double Theta;
public readonly double Vega;
public readonly bool IsValid;
public readonly double AskImpliedVolatility;
public readonly double BidImpliedVolatility;
public readonly bool IsValid;

public Greek(double impliedVolatility, double delta, double gamma, double theta, double vega, bool isValid)
public Greek(double impliedVolatility, double delta, double gamma, double theta, double vega, double askImpliedVolatility, double bidImpliedVolatility, bool isValid)
{
ImpliedVolatility = impliedVolatility;
Delta = delta;
Gamma = gamma;
Theta = theta;
Vega = vega;
AskImpliedVolatility = askImpliedVolatility;
BidImpliedVolatility = bidImpliedVolatility;
IsValid = isValid;
}

Expand All @@ -33,6 +37,8 @@ public bool Equals(Greek obj)
&& Gamma == obj.Gamma
&& Theta == obj.Theta
&& Vega == obj.Vega
&& AskImpliedVolatility == obj.AskImpliedVolatility
&& BidImpliedVolatility == obj.BidImpliedVolatility
&& IsValid == obj.IsValid;
}
};
4 changes: 4 additions & 0 deletions Intrinio.Realtime/Composite/GreekClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ private void BlackScholesCalc(IOptionsContractData optionsContractData, ISecurit
equitiesTrade.Value.Price,
optionsQuote.Value.Timestamp,
(optionsQuote.Value.AskPrice + optionsQuote.Value.BidPrice) / 2.0D,
optionsQuote.Value.AskPrice,
optionsQuote.Value.BidPrice,
optionsQuote.Value.IsPut(),
optionsQuote.Value.GetStrikePrice(),
optionsQuote.Value.GetExpirationDate());
Expand Down Expand Up @@ -483,6 +485,8 @@ private void BlackScholesCalcOptionsEdge(IOptionsContractData optionsContractDat
equitiesTrade.Value.Price,
optionsTrade.Value.Timestamp,
optionsTrade.Value.Price,
optionsTrade.Value.Price,
optionsTrade.Value.Price,
optionsTrade.Value.IsPut(),
optionsTrade.Value.GetStrikePrice(),
optionsTrade.Value.GetExpirationDate());
Expand Down
Loading