All files / src/pricing-models BlackScholes.js

100% Statements 8/8
100% Branches 8/8
100% Functions 2/2
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42                5x   5x   5x   5x             7x                 7x       5x     2x        
import { standardNormalCdf } from "../utils/MathUtils.js";
 
/**
 * Vanilla European option.
 * The value of a European option and it's greeks can be calculated analytically using the Black-Scholes model (https://www.jstor.org/stable/1831029).
 * This model was extended by Merton (https://www.jstor.org/stable/3003143) to allow for the inclusion of a continuous dividend yield.
 */
function blackScholesMerton(type, S, K, t, vol, r, q) {
  const isCall = type === "call" ? 1 : -1;
  const d1 =
    (Math.log(S / K) + (r - q + vol ** 2 / 2) * t) / (vol * Math.sqrt(t));
  const d2 =
    (Math.log(S / K) + (r - q - vol ** 2 / 2) * t) / (vol * Math.sqrt(t));
 
  return (
    isCall * S * Math.exp(-q * t) * standardNormalCdf(isCall * d1) +
    -isCall * K * Math.exp(-r * t) * standardNormalCdf(isCall * d2)
  );
}
 
function price(option) {
  const [S, K, t, vol, r, q] = [
    option.initialSpotPrice,
    option.strikePrice,
    option.timeToMaturity,
    option.volatility,
    option.riskFreeRate,
    option.dividendYield,
  ];
 
  if (
    option.style === "european" ||
    (option.style === "american" && option.type === "call" && q === 0)
  ) {
    return blackScholesMerton(option.type, S, K, t, vol, r, q);
  }
 
  return undefined; // There is no known analytical solution
}
 
export { price };