Skip to content

Commit

Permalink
Fix delta (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssnyder-intrinio authored Nov 22, 2024
1 parent 421ad43 commit c0e4e5c
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 87 deletions.
102 changes: 51 additions & 51 deletions Intrinio.Realtime/Composite/BlackScholesGreekCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,34 @@ public static Greek Calculate( double riskFreeInterestRate,
if (latestOptionQuote.AskPrice <= 0.0D || latestOptionQuote.BidPrice <= 0.0D || riskFreeInterestRate <= 0.0D || underlyingTrade.Price <= 0.0D)
return new Greek(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, false);

double daysToExpiration = GetDaysToExpiration(latestOptionTrade, latestOptionQuote);
double yearsToExpiration = GetYearsToExpiration(latestOptionTrade, latestOptionQuote);
double underlyingPrice = underlyingTrade.Price;
double strike = latestOptionTrade.GetStrikePrice();
bool isPut = latestOptionTrade.IsPut();
double marketPrice = (latestOptionQuote.AskPrice + latestOptionQuote.BidPrice) / 2.0D;

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

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

double delta = CalcDelta(isPut, underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double gamma = CalcGamma(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double theta = CalcTheta(isPut, underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double vega = CalcVega(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double delta = CalcDelta(isPut, underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double gamma = CalcGamma(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double theta = CalcTheta(isPut, underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);
double vega = CalcVega(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, impliedVolatility);

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

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcImpliedVolatilityCall(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice)
private static double CalcImpliedVolatilityCall(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice)
{
double low = LOW_VOL, high = HIGH_VOL;
while ((high - low) > VOL_TOLERANCE)
{
if (CalcPriceCall(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, (high + low) / 2.0D, dividendYield) > marketPrice)
if (CalcPriceCall(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, (high + low) / 2.0D, dividendYield) > marketPrice)
high = (high + low) / 2.0D;
else
low = (high + low) / 2.0D;
Expand All @@ -59,12 +59,12 @@ private static double CalcImpliedVolatilityCall(double underlyingPrice, double s
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcImpliedVolatilityPut(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice)
private static double CalcImpliedVolatilityPut(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice)
{
double low = LOW_VOL, high = HIGH_VOL;
while ((high - low) > VOL_TOLERANCE)
{
if (CalcPricePut(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, (high + low) / 2.0D, dividendYield) > marketPrice)
if (CalcPricePut(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, (high + low) / 2.0D, dividendYield) > marketPrice)
high = (high + low) / 2.0D;
else
low = (high + low) / 2.0D;
Expand All @@ -74,81 +74,81 @@ private static double CalcImpliedVolatilityPut(double underlyingPrice, double st
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcImpliedVolatility(bool isPut, double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice)
private static double CalcImpliedVolatility(bool isPut, double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice)
{
return isPut
? CalcImpliedVolatilityPut(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice)
: CalcImpliedVolatilityCall(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice);
? CalcImpliedVolatilityPut(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice)
: CalcImpliedVolatilityCall(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcDeltaCall(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcDeltaCall(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
return NormalSDist( D1( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) );
return NormalSDist( D1( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) );
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcDeltaPut(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcDeltaPut(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
return CalcDeltaCall( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma) - 1;
return CalcDeltaCall( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma) - 1D;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcDelta(bool isPut, double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcDelta(bool isPut, double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
return isPut
? CalcDeltaPut(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma)
: CalcDeltaCall(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma);
? CalcDeltaPut(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma)
: CalcDeltaCall(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcGamma(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcGamma(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
return Phi( D1( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) ) / ( underlyingPrice * sigma * System.Math.Sqrt(daysToExpiration) );
return Phi( D1( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) ) / ( underlyingPrice * sigma * System.Math.Sqrt(yearsToExpiration) );
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcThetaCall(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcThetaCall(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
double term1 = underlyingPrice * Phi( D1( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) ) * sigma / ( 2.0D * System.Math.Sqrt(daysToExpiration) );
double term2 = riskFreeInterestRate * strike * System.Math.Exp(-1.0D * riskFreeInterestRate * daysToExpiration) * NormalSDist( D2( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) );
double term1 = underlyingPrice * Phi( D1( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) ) * sigma / ( 2.0D * System.Math.Sqrt(yearsToExpiration) );
double term2 = riskFreeInterestRate * strike * System.Math.Exp(-1.0D * riskFreeInterestRate * yearsToExpiration) * NormalSDist( D2( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) );
return ( -term1 - term2 ) / 365.25D;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcThetaPut(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcThetaPut(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
double term1 = underlyingPrice * Phi( D1( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) ) * sigma / ( 2.0D * System.Math.Sqrt(daysToExpiration) );
double term2 = riskFreeInterestRate * strike * System.Math.Exp(-1.0D * riskFreeInterestRate * daysToExpiration) * NormalSDist( - D2( underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) );
double term1 = underlyingPrice * Phi( D1( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) ) * sigma / ( 2.0D * System.Math.Sqrt(yearsToExpiration) );
double term2 = riskFreeInterestRate * strike * System.Math.Exp(-1.0D * riskFreeInterestRate * yearsToExpiration) * NormalSDist( - D2( underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) );
return ( -term1 + term2 ) / 365.25D;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcTheta(bool isPut, double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcTheta(bool isPut, double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
return isPut
? CalcThetaPut(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma)
: CalcThetaCall(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma);
? CalcThetaPut(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma)
: CalcThetaCall(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, dividendYield, marketPrice, sigma);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcVega(double underlyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
private static double CalcVega(double underlyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double dividendYield, double marketPrice, double sigma)
{
return 0.01D * underlyingPrice * System.Math.Sqrt(daysToExpiration) * Phi(D1(underlyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield));
return 0.01D * underlyingPrice * System.Math.Sqrt(yearsToExpiration) * Phi(D1(underlyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double D1(double underylyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
private static double D1(double underylyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
{
double numerator = ( System.Math.Log(underylyingPrice / strike) + (riskFreeInterestRate - dividendYield + 0.5D * System.Math.Pow(sigma, 2.0D) ) * daysToExpiration);
double denominator = ( sigma * System.Math.Sqrt(daysToExpiration));
double numerator = ( System.Math.Log(underylyingPrice / strike) + (riskFreeInterestRate - dividendYield + 0.5D * System.Math.Pow(sigma, 2.0D) ) * yearsToExpiration);
double denominator = ( sigma * System.Math.Sqrt(yearsToExpiration));
return numerator / denominator;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double D2(double underylyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
private static double D2(double underylyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
{
return D1( underylyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield ) - ( sigma * System.Math.Sqrt(daysToExpiration) );
return D1( underylyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield ) - ( sigma * System.Math.Sqrt(yearsToExpiration) );
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down Expand Up @@ -176,38 +176,38 @@ private static double Phi(double x)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcPriceCall(double underylyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
private static double CalcPriceCall(double underylyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
{
double d1 = D1( underylyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield );
double discountedUnderlying = System.Math.Exp(-1.0D * dividendYield * daysToExpiration) * underylyingPrice;
double d1 = D1( underylyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield );
double discountedUnderlying = System.Math.Exp(-1.0D * dividendYield * yearsToExpiration) * underylyingPrice;
double probabilityWeightedValueOfBeingExercised = discountedUnderlying * NormalSDist( d1 );

double d2 = d1 - ( sigma * System.Math.Sqrt(daysToExpiration) );
double discountedStrike = System.Math.Exp(-1.0D * riskFreeInterestRate * daysToExpiration) * strike;
double d2 = d1 - ( sigma * System.Math.Sqrt(yearsToExpiration) );
double discountedStrike = System.Math.Exp(-1.0D * riskFreeInterestRate * yearsToExpiration) * strike;
double probabilityWeightedValueOfDiscountedStrike = discountedStrike * NormalSDist( d2 );

return probabilityWeightedValueOfBeingExercised - probabilityWeightedValueOfDiscountedStrike;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double CalcPricePut(double underylyingPrice, double strike, double daysToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
private static double CalcPricePut(double underylyingPrice, double strike, double yearsToExpiration, double riskFreeInterestRate, double sigma, double dividendYield)
{
double d2 = D2( underylyingPrice, strike, daysToExpiration, riskFreeInterestRate, sigma, dividendYield );
double discountedStrike = strike * System.Math.Exp(-1.0D * riskFreeInterestRate * daysToExpiration);
double d2 = D2( underylyingPrice, strike, yearsToExpiration, riskFreeInterestRate, sigma, dividendYield );
double discountedStrike = strike * System.Math.Exp(-1.0D * riskFreeInterestRate * yearsToExpiration);
double probabiltityWeightedValueOfDiscountedStrike = discountedStrike * NormalSDist( -1.0D * d2 );

double d1 = d2 + ( sigma * System.Math.Sqrt(daysToExpiration) );
double discountedUnderlying = underylyingPrice * System.Math.Exp(-1.0D * dividendYield * daysToExpiration);
double d1 = d2 + ( sigma * System.Math.Sqrt(yearsToExpiration) );
double discountedUnderlying = underylyingPrice * System.Math.Exp(-1.0D * dividendYield * yearsToExpiration);
double probabilityWeightedValueOfBeingExercised = discountedUnderlying * NormalSDist( -1.0D * d1 );

return probabiltityWeightedValueOfDiscountedStrike - probabilityWeightedValueOfBeingExercised;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double GetDaysToExpiration(Intrinio.Realtime.Options.Trade latestOptionTrade, Intrinio.Realtime.Options.Quote latestOptionQuote)
private static double GetYearsToExpiration(Intrinio.Realtime.Options.Trade latestOptionTrade, Intrinio.Realtime.Options.Quote latestOptionQuote)
{
double latestActivity = System.Math.Max(latestOptionTrade.Timestamp, latestOptionQuote.Timestamp);
double expiration = (latestOptionTrade.GetExpirationDate() - DateTime.UnixEpoch.ToUniversalTime()).TotalSeconds;
return (expiration - latestActivity) / 86400.0D; //86400 is seconds in a day
return (expiration - latestActivity) / 31557600.0D; //86400 is seconds in a day. Using 365.25 days in a year.
}
}
Loading

0 comments on commit c0e4e5c

Please sign in to comment.