17 using System.Runtime.CompilerServices;
18 using MathNet.Numerics.Distributions;
36 public static double BlackTheoreticalPrice(
double volatility,
double spotPrice,
double strikePrice,
double timeToExpiration,
double riskFreeRate,
double dividendYield,
OptionRight optionType)
38 var d1 = CalculateD1(spotPrice, strikePrice, timeToExpiration, riskFreeRate, dividendYield, volatility);
39 var d2 = CalculateD2(d1, volatility, timeToExpiration);
40 var norm =
new Normal();
42 var optionPrice = 0.0;
45 optionPrice = spotPrice * Math.Exp(-dividendYield * timeToExpiration) * norm.CumulativeDistribution(d1)
46 - strikePrice * Math.Exp(-riskFreeRate * timeToExpiration) * norm.CumulativeDistribution(d2);
50 optionPrice = strikePrice * Math.Exp(-riskFreeRate * timeToExpiration) * norm.CumulativeDistribution(-d2)
51 - spotPrice * Math.Exp(-dividendYield * timeToExpiration) * norm.CumulativeDistribution(-d1);
55 throw new ArgumentException(
"Invalid option right.");
61 internal static double CalculateD1(
double spotPrice,
double strikePrice,
double timeToExpiration,
double riskFreeRate,
double dividendYield,
double volatility)
63 var numerator = Math.Log(spotPrice / strikePrice) + (riskFreeRate - dividendYield + 0.5 * volatility * volatility) * timeToExpiration;
64 var denominator = volatility * Math.Sqrt(Math.Max(0, timeToExpiration));
70 return numerator / denominator;
73 internal static double CalculateD2(
double d1,
double volatility,
double timeToExpiration)
75 return d1 - volatility * Math.Sqrt(Math.Max(0, timeToExpiration));
83 double timeToExpiration,
double riskFreeRate,
double dividendYield,
OptionRight optionType,
int steps =
Steps)
85 var deltaTime = timeToExpiration / steps;
86 var upFactor = Math.Exp(volatility * Math.Sqrt(deltaTime));
92 var downFactor = 1 / upFactor;
93 var probUp = (Math.Exp((riskFreeRate - dividendYield) * deltaTime) - downFactor) / (upFactor - downFactor);
95 return BinomialTheoreticalPrice(deltaTime, probUp, upFactor, riskFreeRate, spotPrice, strikePrice, optionType, steps);
102 double timeToExpiration,
double riskFreeRate,
double dividendYield,
OptionRight optionType,
int steps =
Steps)
104 var deltaTime = timeToExpiration / steps;
105 var discount = Math.Exp((riskFreeRate - dividendYield) * deltaTime);
106 var volatilityTimeSqrtDeltaTime = volatility * Math.Sqrt(deltaTime);
107 var upFactor = Math.Exp(volatilityTimeSqrtDeltaTime) * discount;
108 var downFactor = Math.Exp(-volatilityTimeSqrtDeltaTime) * discount;
109 if (upFactor - downFactor == 0)
116 var probUp = (discount - downFactor) / (upFactor - downFactor);
118 return BinomialTheoreticalPrice(deltaTime, probUp, upFactor, riskFreeRate, spotPrice, strikePrice, optionType, steps);
121 private static double BinomialTheoreticalPrice(
double deltaTime,
double probUp,
double upFactor,
double riskFreeRate,
122 double spotPrice,
double strikePrice,
OptionRight optionType,
int steps =
Steps)
124 var probDown = 1 - probUp;
125 var values =
new double[steps + 1];
127 var exerciseValues = optionType ==
OptionRight.Call ?
new double[2 * steps] :
null;
129 for (
int i = 0; i < (exerciseValues?.Length ?? values.Length); i++)
131 if (i < values.Length)
133 var nextPrice = spotPrice * Math.Pow(upFactor, 2 * i - steps);
139 var nextPrice = spotPrice * Math.Pow(upFactor, i - steps);
144 var factor = Math.Exp(-riskFreeRate * deltaTime);
145 var factorA = factor * probDown;
146 var factorB = factor * probUp;
148 for (var period = steps - 1; period >= 0; period--)
150 for (var i = 0; i <= period; i++)
152 var binomialValue = values[i] * factorA + values[i + 1] * factorB;
156 values[i] = binomialValue;
159 values[i] = Math.Max(binomialValue, exerciseValues[2 * i - period + steps]);
166 [MethodImpl(MethodImplOptions.AggressiveInlining)]
167 public static double TimeTillExpiry(DateTime expiry, DateTime referenceDate)
169 return (expiry - referenceDate).TotalDays / 365d;
172 [MethodImpl(MethodImplOptions.AggressiveInlining)]
173 internal static double Divide(
double numerator,
double denominator)
175 if (denominator != 0)
177 return numerator / denominator;