Skip to content

Commit

Permalink
Merge pull request #92 from alembcke:expiration_fix
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 517952950
  • Loading branch information
tf-quant-finance-robot committed Mar 20, 2023
2 parents d5607b0 + d8c26a4 commit b9c8b8b
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 10 deletions.
29 changes: 20 additions & 9 deletions tf_quant_finance/black_scholes/approximations/american_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,13 @@ def _adesi_whaley(*, sigma, x, t, r, d, s, is_call_options, max_iterations,
# The divisive condition is different for put and call options
condition = tf.where(is_call_options, s < s_crit, s > s_crit)

american_prices = tf.where(condition, eu_prices + a2 * (s / s_crit)**q2,
(s - x) * sign)
# Distinguish the case of zero expiry.
american_prices = tf.where(
t > 0,
tf.where(condition, eu_prices + a2 * (s / s_crit)**q2, (s - x) * sign),
tf.where(is_call_options,
tf.math.maximum(s - x, 0),
tf.math.maximum(x - s, 0)))

return american_prices, converged, failed

Expand Down Expand Up @@ -513,13 +518,19 @@ def bjerksund_stensland(*,
is_call_options=is_call_options),
# For put options, adjust inputs according to call-put transformation
# function: P(S, X, T, r, b, sigma) = C(X, S, T, r - b, -b, sigma)
tf.where(is_call_options,
bjerksund_stensland_model(
spots, strikes, expiries, discount_rates,
cost_of_carries, volatilities),
bjerksund_stensland_model
(strikes, spots, expiries, discount_rates - cost_of_carries,
-cost_of_carries, volatilities)))
tf.where(
is_call_options,
tf.where(expiries > 0,
bjerksund_stensland_model(
spots, strikes, expiries, discount_rates,
cost_of_carries, volatilities),
tf.math.maximum(spots - strikes, 0)),
tf.where(expiries > 0,
bjerksund_stensland_model(
strikes, spots, expiries,
discount_rates - cost_of_carries,
-cost_of_carries, volatilities),
tf.math.maximum(strikes - spots, 0))))
return american_prices


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,26 @@ def test_option_prices_all_call_options(self):
with self.subTest(name='NonFailed'):
self.assertAllEqual(failed, tf.zeros_like(computed_prices))

def test_option_prices_expiration(self):
"""Tests Baron-Adesi Whaley prices at expiration."""
dtype = tf.float64
computed_prices, converged, failed = adesi_whaley(
volatilities=[0.2, 0.3, 0.4], strikes=[100],
expiries=[0.0], spots=[90, 100, 110],
tolerance=1e-08,
is_call_options=[True],
discount_rates=[0.0],
dtype=dtype)
# Computed using tff.black_scholes.option_price_binomial
expected_prices = [0.0, 0.0, 10.0]
with self.subTest(name='ExpectedPrices'):
self.assertAllClose(expected_prices, computed_prices,
rtol=1e-4, atol=5e-4)
with self.subTest(name='AllConverged'):
self.assertAllEqual(converged, tf.ones_like(computed_prices))
with self.subTest(name='NonFailed'):
self.assertAllEqual(failed, tf.zeros_like(computed_prices))

@parameterized.parameters(
(0.08, 0.12, 0.2, 0.25,
[0.03, 0.57, 3.49, 10.32, 20.0, 20.41, 11.25, 4.40, 1.12, 0.18]),
Expand Down Expand Up @@ -496,5 +516,30 @@ def test_bs2002_prices_types(self):
rtol=5e-3, atol=5e-3,
msg=msg)

def test_bs2002_prices_expiration(self):
"""Tests Bjerksund Stensland 2002 prices at expiration."""
discount_rates = tf.constant([0.10, 0.09, 0.08, 0.07, 0.06, 0.05])
dividend_rates = tf.constant([0.05, 0.06, 0.07, 0.08, 0.09, 0.10])
volatilities = tf.constant([0.10, 0.15, 0.20, 0.25, 0.30, 0.35])
expiries = tf.constant([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
spots = tf.constant([90.0, 100.0, 110.0, 90.0, 100.0, 110.0])
strikes = tf.constant([100.0] * 6)
is_call_options = tf.constant([True, True, True, False, False, False])
computed_prices = bjerksund_stensland(
volatilities=volatilities,
strikes=strikes,
expiries=expiries,
discount_rates=discount_rates,
dividend_rates=dividend_rates,
spots=spots,
is_call_options=is_call_options,
modified_boundary=True)
expected_prices = [0.0, 0.0, 10.0, 10.0, 0.0, 0.0]
with self.subTest(name='ExpectedPrices'):
msg = 'Failed: Bjerksund Stensland 2002 expiration tests.'
self.assertAllClose(expected_prices, computed_prices,
rtol=5e-3, atol=5e-3,
msg=msg)

if __name__ == '__main__':
tf.test.main()
7 changes: 6 additions & 1 deletion tf_quant_finance/black_scholes/crr_binomial_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,12 @@ def should_continue(current_values, current_log_spot_grid):
maximum_iterations=tf.cast(num_steps, dtype=tf.int32),
shape_invariants=(tf.TensorShape(batch_shape + [None]),
tf.TensorShape(batch_shape + [None])))
return tf.squeeze(pv, axis=-1)
return tf.where(
expiries > 0,
tf.squeeze(pv, axis=-1),
tf.where(is_call_options,
tf.math.maximum(spots - strikes, 0),
tf.math.maximum(strikes - spots, 0)))


def _get_payoff_fn(strikes, is_call_options):
Expand Down
21 changes: 21 additions & 0 deletions tf_quant_finance/black_scholes/crr_binomial_tree_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,27 @@ class BinomialModelPrice(parameterized.TestCase, tf.test.TestCase):
'expected': [[0.031603, 0.16827, 0.303679, 0.0, 1.110733],
[0.009376, 0.472969, 0.337524, 1.309396, 0.856245]],
'dtype': np.float32
}, {
'testcase_name': 'Expiration',
'spots': [[1.0, 2.0, 3.0, 4.0, 5.0],
[1.0, 2.0, 3.0, 4.0, 5.0]],
'strikes': [[3.0, 3.0, 3.0, 3.0, 3.0],
[3.0, 3.0, 3.0, 3.0, 3.0]],
'volatilities': [[0.1, 0.2, 0.3, 0.01, 0.4],
[0.15, 0.25, 0.35, 0.02, 0.35]],
'is_call_options': [[True, True, False, True, True],
[False, False, False, False, False]],
'is_american': [[False, True, True, False, True],
[True, True, False, False, True]],
'discount_rates': [[0.035, 0.01, 0.1, 0.01, 0.0],
[0.03, 0.02, 0.05, 0.02, 0.01]],
'dividend_rates': [[0.02, 0.0, 0.07, 0.01, 0.0],
[0.01, 0.01, 0.07, 0.01, 0.0]],
'expiries': [[0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0]],
'expected': [[0.0, 0.0, 0.0, 1.0, 2.0],
[2.0, 1.0, 0.0, 0.0, 0.0]],
'dtype': np.float32
})
def test_option_prices(self, spots, strikes, volatilities,
is_call_options, is_american, discount_rates,
Expand Down

0 comments on commit b9c8b8b

Please sign in to comment.