Skip to content

Commit

Permalink
ENH: Analytical BS European binary formulas (#437) (#553)
Browse files Browse the repository at this point in the history
  • Loading branch information
simaki authored Mar 23, 2022
1 parent c91f7ed commit 9a5c376
Showing 1 changed file with 46 additions and 26 deletions.
72 changes: 46 additions & 26 deletions pfhedge/nn/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,21 @@ def bilerp(
return torch.lerp(lerp1, lerp2, weight2)


def _bs_theta_gamma_relation(gamma: Tensor, spot: Tensor, volatility: Tensor) -> Tensor:
# theta = (1/2) * vola^2 * spot^2 * gamma
# by Black-Scholes formula
return gamma * volatility.square() * spot.square() / 2


def _bs_vega_gamma_relation(
gamma: Tensor, spot: Tensor, time_to_maturity: Tensor, volatility: Tensor
) -> Tensor:
# vega = vola * spot^2 * time * gamma
# in Black-Scholes model
# See Chapter 5 Appendix A, Bergomi "Stochastic volatility modeling"
return gamma * volatility * spot.square() * time_to_maturity


def bs_european_price(
log_moneyness: Tensor,
time_to_maturity: Tensor,
Expand Down Expand Up @@ -849,14 +864,13 @@ def bs_european_binary_gamma(
See :func:`pfhedge.nn.BSEuropeanBinaryOption.gamma` for details.
"""
# TODO(simaki): Directly compute gamma.
return autogreek.gamma_from_delta(
bs_european_binary_delta,
log_moneyness=log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
s, t, v = broadcast_all(log_moneyness, time_to_maturity, volatility)
spot = s.exp() * strike

d2_tensor = d2(s, t, v)
w = volatility * time_to_maturity.square()

return -npdf(d2_tensor).div(w * spot.square()) * (1 + d2_tensor.div(w))


def bs_european_binary_vega(
Expand All @@ -869,14 +883,16 @@ def bs_european_binary_vega(
See :func:`pfhedge.nn.BSEuropeanBinaryOption.vega` for details.
"""
# TODO(simaki): Directly compute gamma.
return autogreek.vega(
bs_european_binary_price,
gamma = bs_european_binary_gamma(
log_moneyness=log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
spot = log_moneyness.exp() * strike
return _bs_vega_gamma_relation(
gamma, spot=spot, time_to_maturity=time_to_maturity, volatility=volatility
)


def bs_european_binary_theta(
Expand All @@ -889,14 +905,14 @@ def bs_european_binary_theta(
See :func:`pfhedge.nn.BSEuropeanBinaryOption.theta` for details.
"""
# TODO(simaki): Directly compute theta.
return autogreek.theta(
bs_european_binary_price,
gamma = bs_european_binary_gamma(
log_moneyness=log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
spot = log_moneyness.exp() * strike
return _bs_theta_gamma_relation(gamma, spot=spot, volatility=volatility)


def bs_american_binary_price(
Expand Down Expand Up @@ -975,15 +991,17 @@ def bs_american_binary_vega(
See :func:`pfhedge.nn.BSAmericanBinaryOption.vega` for details.
"""
# TODO(simaki): Compute analytically
return autogreek.vega(
bs_american_binary_price,
gamma = bs_american_binary_gamma(
log_moneyness=log_moneyness,
max_log_moneyness=max_log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
spot = log_moneyness.exp() * strike
return _bs_vega_gamma_relation(
gamma, spot=spot, time_to_maturity=time_to_maturity, volatility=volatility
)


def bs_american_binary_theta(
Expand All @@ -997,15 +1015,15 @@ def bs_american_binary_theta(
See :func:`pfhedge.nn.BSAmericanBinaryOption.theta` for details.
"""
# TODO(simaki): Compute analytically
return autogreek.theta(
bs_american_binary_price,
gamma = bs_american_binary_gamma(
log_moneyness=log_moneyness,
max_log_moneyness=max_log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
spot = log_moneyness.exp() * strike
return _bs_theta_gamma_relation(gamma, spot=spot, volatility=volatility)


def bs_lookback_price(
Expand Down Expand Up @@ -1100,15 +1118,17 @@ def bs_lookback_vega(
See :func:`pfhedge.nn.BSLookbackOption.vega` for details.
"""
# TODO(simaki): Calculate analytically
return autogreek.vega(
bs_lookback_price,
gamma = bs_lookback_gamma(
log_moneyness=log_moneyness,
max_log_moneyness=max_log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
spot = log_moneyness.exp() * strike
return _bs_vega_gamma_relation(
gamma, spot=spot, time_to_maturity=time_to_maturity, volatility=volatility
)


def bs_lookback_theta(
Expand All @@ -1122,15 +1142,15 @@ def bs_lookback_theta(
See :func:`pfhedge.nn.BSLookbackOption.theta` for details.
"""
# TODO(simaki): Calculate analytically
return autogreek.theta(
bs_lookback_price,
gamma = bs_lookback_gamma(
log_moneyness=log_moneyness,
max_log_moneyness=max_log_moneyness,
time_to_maturity=time_to_maturity,
volatility=volatility,
strike=strike,
)
spot = log_moneyness.exp() * strike
return _bs_theta_gamma_relation(gamma, spot=spot, volatility=volatility)


def box_muller(
Expand Down

0 comments on commit 9a5c376

Please sign in to comment.