Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BS vol and greeks #13

Open
feribg opened this issue Nov 20, 2019 · 10 comments
Open

BS vol and greeks #13

feribg opened this issue Nov 20, 2019 · 10 comments
Assignees

Comments

@feribg
Copy link

feribg commented Nov 20, 2019

I was wondering if there's an example implementation of BS implied vol estimation for American options and greeks. This tends to be the more commonly needed example than pricing, since the immediate need is to generate vol surfaces or ivol and use in further modelling. Wondering if this is supported, I couldn't see any examples in the American pricing notebook. Thanks!

@cyrilchim
Copy link
Contributor

Hi Feras,
We do not have those at the moment. Please let me know if you would like to contribute any of the approximate formulas, I'd be happy to assist you.

@feribg
Copy link
Author

feribg commented Nov 26, 2019

I have some simple python implementation of FD, but im quite foreign to tensorflow and maybe the most I can contribute is the python code. It's relatively trivial though.

@feribg
Copy link
Author

feribg commented Feb 13, 2020

@cyrilchim I can see that there's an American BS sample now and some IV approximations root finders (brent etc). So the only question left now is whether the FD solver outputs autograd values for greeks?

@cyrilchim
Copy link
Contributor

Hi Feras,

Yes, you can now compute Greeks using tff.math.gradients for backward gradient and tff.math.fwd_gradient for forward gradients for both PDE and Monte Carlo. I will add these as examples to the notebooks.

@feribg
Copy link
Author

feribg commented Feb 24, 2020

Were you able to add those and an IV root finder example in the American notebook, very curious to give it a speed test against my custom implementation (xtensor) and QL.

@cyrilchim
Copy link
Contributor

cyrilchim commented Feb 25, 2020

Not yet. We have somebody working on approximate American option pricer under Black-Scholes which will allow you to have a good starting position to recover the implied vols. Below I'll give an example of the code that should work if you run it within the American Option pricing example. Please feel free to clean that up or please wait till we add this functionality:

# Generate volatilities, rates, strikes
number_of_options = 10
time_delta = 0.005
expiry = 1.0  
number_grid_points = 1024 
dtype = tf.float64 
# option_param is defined in the colab
volatility, risk_free_rate, strike = option_param(number_of_options, dtype)

# Volatilities  you wish to recover
volatility (you will get some other numbers)
# [0.34651953, 0.31974535, 0.3634092 , 0.30981284, 0.31603689,
#       0.3786868 , 0.30805471, 0.39807124, 0.39334036, 0.31450737

# Here volatility is the true volatility we want to recover. Let's compute corresponding prices for some spots:

# Build a graph to compute prices of the American Options. `american_option` is defined in the 
# colab
estimate, grid_locations = american_option(
    time_delta=time_delta,
    expiry=expiry,
    number_grid_points=number_grid_points,
    volatility=volatility,
    risk_free_rate=risk_free_rate,
    strike=strike,
    dtype=dtype)

# Let the spot be
grid_locations[512]
150.15162267839688

# Corresponding prices are
prices = estimate[:, 512]
prices
# [99.0667007 , 23.85166692, 32.73295086, 81.08032504, 82.55783883,
#     82.58633041, 70.2186232 , 55.50203021, 61.82433372, 73.96888073]

# Set up the objective function for the brent algorithm
@tf.function
def objective_fn(volatility):
  estimate, _ = american_option(
      time_delta=time_delta,
      expiry=expiry,
      number_grid_points=number_grid_points,
      volatility=volatility,
      risk_free_rate=risk_free_rate,
      strike=strike,
      dtype=dtype)
  # Return shape should be the same as the input: [10, 1]
  return tf.expand_dims(prices - estimate[:, 512], -1)

# Set up Brent root search
brent_search = tf.function(tff.math.root_search.brentq)
# We need to pass the search brackets
start_vols = 0.1 * np.ones_like(volatility)
res = brent_search(objective_fn, left_bracket=0.1 * start_vols, right_bracket=10*start_vols)
# Implie volatilities
implied_vols = res.estimated_root
# Pretty good recovery
tf.reduce_max(tf.abs(implied_vols - volatility))
<tf.Tensor: shape=(), dtype=float64, numpy=2.582107927473487e-08>

That is it. Please feel free to test it out and as I said before I am happy to help you adding this to the colab. As for timing, I got roughly 4.3 seconds with the above specifications on the Tesla T4 shared GPU (I just run it in the colab): 1024 grid points, 200 timesteps, 10 options

%%timeit -n 10
brent_search(objective_fn, left_bracket=0.1 * start_vols, right_bracket=10*start_vols)
10 loops, best of 3: 4.29 s per loop

Our code is designed for batching, so you might as well can try increasing the number of options and running in on the cloud with a better GPU. I tried increasing the number of options to 100 and the time was 4.81 seconds. Root search takes 10 iterations to converge. You can as well use European option implied vols as a starting point for the root search (tff.black_scholes.implied_vol).

Please let me know if you have any questions.

@feribg
Copy link
Author

feribg commented Feb 25, 2020

Thanks, I will try that and compare to QL as well as clean up and try to add to the colab. Do you have a running example of tff.math.fwd_gradient either in the notebook or somewhere in the tests, only saw a very contrived one in https://github.com/google/tf-quant-finance/blob/39a1c03cc9938c6e08fceb63e405eff0fda835be/tf_quant_finance/math/integration/integration_test.py

@cyrilchim
Copy link
Contributor

Thanks for the request! Could you maybe file a separate bug for the gradient demo? One of our collaborators has written a colab and will be pushing it shortly.

@feribg
Copy link
Author

feribg commented Mar 22, 2020

@cyrilchim I had a couple more questions around the solve_backwards method:

  1. How would you incorporate dividends in the example notebook, do you just change the coeff funcs?
  2. Seems like because of the cyclic reduction nature of the solver it does only give you the final solution rather than the solution at each timestep (ie full grid). Is that a limitation of the CUDA library, if we got each estimate (or at least T and T-1) we can get theta for free as well.
  3. Again since im not sure how does the CUDA library factor in the boundary conditions, do you think that pre calculating the boundary region in the American case would speed it up (seems to be the approach QuantLib takes before running a more traidtional BiCGSTAB solver (refhttps://demonstrations.wolfram.com/KimsMethodWithNonuniformTimeGridForPricingAmericanOptions/)
  4. The boundary method is called _apply_boundary_after_step yet the CR is a parallel thing, so how do you apply it after the step exactly, I'm trying to understand the flow.

@arthurpham
Copy link

Yes, you can now compute Greeks using tff.math.gradients for backward gradient and tff.math.fwd_gradient for forward gradients for both PDE and Monte Carlo. I will add these as examples to the notebooks.

@cyrilchim Do you have an example on how to compute the greeks with the PDE and the MC ? For example, delta, gamma, rho, theta, vega. I saw some pieces here and there, but it would be helpful to see them directly in the jupyter notebooks that showcase how to use the library. Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants