|
From: Philippe H. <pha...@ma...> - 2024-07-16 22:25:58
|
So to answer Peter's suggestion below: "Maybe we should add a PriceCalibrationHelper that inherits from CalibrationHelper and a HestonPriceCalibrationHelper from PriceCalibrationHelper. Both of them operate directly in premium space rather than vol space." There might be an easier approach all in python. What I found is that the python helper has an impliedVolatility() method, which expects a premium as an input. So I could do a two step process whereby I fbuild a first-stage helper with an "external" BS implied vol, and then I fine-tune the value by calling the impliedVolatility() method of the helper, passing the correct market option price. This way, the vola I pass are by definition guaranteed to have the helper reprice the market. However... I do not know "officially" whether the helper created a Call or a Put. I could guess and it's not super hard, but it clearly would be much easier if such attribute was obtainable. So is there a way to know the option type of a given such helper from python? Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ On Jul 16, 2024, at 6:02 PM, Philippe Hatstadt <pha...@ma...> wrote: Please disregard. dummy error: T_minus_t = nd/365 instead of T_minus_t = nd/252 Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ On Jul 16, 2024, at 10:10 AM, Philippe Hatstadt <pha...@ma...> wrote: Here is a piece of portable code that attempts to compare the price of a call and a put using Black-Scholes-Merton versus the value that the HestonHelper uses to calibrate itself, using helper.marketValue() for such purpose. Please note that I didn't bother running the calibration, because I don't agree with what the helper believes the market price that it should calibrate to actually is, which needs to be sorted out first. This is the output, which demonstrates that the helper marketValue() methods doesn't return either the market call or put price, as proxied by the bsm valuation. spot strike expiration fwd vol helper_mv bsm_call bsm_put 5600 5400 January 18th, 2025 5600.0 0.15 193.522986 348.832747 148.832747 5600 5500 January 18th, 2025 5600.0 0.15 237.701503 290.942419 190.942419 5600 5600 January 18th, 2025 5600.0 0.15 287.487574 239.748097 239.748097 5600 5700 January 18th, 2025 5600.0 0.15 242.786146 195.164877 295.164877 5600 5800 January 18th, 2025 5600.0 0.15 203.403335 156.934525 356.934525 import QuantLib as ql from math import pow, sqrt import pandas as pd import numpy as np from scipy import stats def gbsm(s, k, r, b, sigma, t, call_put): d1 = (np.log(s / k) + t * (b + sigma ** 2 / 2)) / (sigma * np.sqrt(t)) d2 = d1 - sigma * np.sqrt(t) if call_put == 'C': return s * np.exp((b-r) * t) * stats.norm.cdf(d1) - k * np.exp(-r * t) * stats.norm.cdf(d2) elif call_put == 'P': return k * np.exp(-r * t) * stats.norm.cdf(-d2) - s * np.exp((b-r) * t) * stats.norm.cdf(-d1) day_count = ql.Actual365Fixed() calendar = ql.UnitedStates(ql.UnitedStates.NYSE) calculation_date = ql.Date(15, 7, 2024) ql.Settings.instance().evaluationDate = calculation_date spot = 5600 rf_rate = 0.0 div_yield = 0.0 yield_ts = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, rf_rate, day_count)) dividend_ts = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, div_yield, day_count)) expiration_date = ql.Date(18, 1, 2025) vol = .15 nd = expiration_date - calculation_date p = ql.Period(nd, ql.Days) df = pd.DataFrame(columns=['spot', 'strike', 'expiration', 'fwd', 'vol', 'helper_mv', 'bsm_call', 'bsm_put']) for i, strike in enumerate([5400, 5500, 5600, 5700, 5800]): helper = ql.HestonModelHelper(p, calendar, spot, strike, ql.QuoteHandle(ql.SimpleQuote(vol)),yield_ts, dividend_ts) # compute risk-neutral fwd value b = rf_rate - div_yield fwd = spot * np.exp(b * t) # compute bsm value T_minus_t = nd/365 bsm_call = gbsm(spot,strike,rf_rate, b, vol, T_minus_t,"C") bsm_put = gbsm(spot,strike,rf_rate, b, vol, T_minus_t,"P") df.loc[i] = { 'spot': spot, 'strike':strike, 'expiration':str(expiration_date), 'fwd':fwd, 'vol':vol, 'helper_mv':helper.marketValue(), 'bsm_call':bsm_call, 'bsm_put': bsm_put } display(df) Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ On Jul 15, 2024, at 9:08 PM, philippe hatstadt via QuantLib-users <qua...@li...> wrote: By the way how do you handle hard to borrow stock? Is put versus call nor using the same (secured) funding curve or does put call parity no longer hold? Regards Philippe Hatstadt +1-203-252-0408 On Jul 15, 2024, at 7:47 PM, James Mac Hale <jam...@qu...> wrote: ORE has a class for stripping a forward curve given put and call option prices here https://github.com/OpenSourceRisk/Engine/blob/master/QuantExt/qle/termstructures/equityforwardcurvestripper.hpp That's half the battle. It works well for OPRA SPX data but you need to remove some maturities with only a handful of strikes. On Mon, Jul 15, 2024, 10:19 PM philippe hatstadt via QuantLib-users < qua...@li... > wrote: That would be nice. I just built a prototype that uses SPX option quotes, and attempts to derive RidkNeutralForward/Strike for each option, carefully eliminating all calls where such ratio is >= 1 and puts where it is <1. I then compute a BS implied volatility for each option and use such data to build a helpers list, from which I calibrate Heston parameters via ql.LevenbergMarquart. If I then compute the calibration errors, what I observe is that for each helper, the value helper.marketValue() is nowhere near the market values I had used to compute the BS implied volatilities. Such respective values differ by anywhere from 15% to 65% relative option premium. I suppose I need to post some code if I want someone to help? But curious of the steps I took are ok? Regards Philippe Hatstadt +1-203-252-0408 > On Jul 15, 2024, at 2:35 PM, Peter Caspers < pca...@gm... > wrote: > > Maybe we should add a PriceCalibrationHelper that inherits from > CalibrationHelper and a HestonPriceCalibrationHelper from > PriceCalibrationHelper. Both of them operate directly in premium space > rather than vol space. > >> On Fri, 12 Jul 2024 at 22:15, Philippe Hatstadt < pha...@ma... > wrote: >> >> So if what I have are option quotes, I need to: >> 1. compute the risk-neutral forward for each expiry, replicating exactly what the Heston engine does? is there a way to do that using the engine? If not, what's the best way? >> 2. Use a BSM model, again making sure that it computes the same exact risk-neutral forward, compute the BSM implied volatility, correctly using either a call or a put depending on OTM forward. >> 3. Pass the vols and strikes to the HestonHelpers? >> >> For #1 and #2, I assume that passing the same exact dividend and risk-free rate handles to the respective BSM and Heston engines would guarantee matching risk-neutral forwards, but is there another approach altogether given than what I have are call and put prices? >> >> Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ >> >> On Jul 12, 2024, at 4:06 PM, Peter Caspers < pca...@gm... > wrote: >> >> >> forward I believe >> >> >> ------- Weitergeleitete Nachricht ------ >> Von: philippe hatstadt < pha...@ma... > >> Datum: Fr. 12. Juli 2024 um 20:37 >> Betreff: Re: [Quantlib-users] Heston Calibration >> An: Peter Caspers < pca...@gm... > >> Cc: < qua...@li... > >> >> >> Out of the money spot or forward? >> Regards >> >> Philippe Hatstadt >> +1-203-252-0408 >> >> >>>> On Jul 12, 2024, at 2:10 PM, Peter Caspers < pca...@gm... > wrote: >>> >>> Yes. It will always build the option type which is out-of-the-money. >>> Best, Peter >>> >>>> On Fri, 12 Jul 2024 at 18:30, Philippe Hatstadt via QuantLib-users >>>> < qua...@li... > wrote: >>>> >>>> Does the ql.HestonModelHelper only expects a BSM implied volatility as an input? I am asking because there doesn't seem to be any parameter for option type (call or put)? >>>> >>>> Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ >>>> >>>> >>>> _______________________________________________ >>>> QuantLib-users mailing list >>>> Qua...@li... >>>> https://lists.sourceforge.net/lists/listinfo/quantlib-users >> >> _______________________________________________ QuantLib-users mailing list Qua...@li... https://lists.sourceforge.net/lists/listinfo/quantlib-users Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline <untitled attachment> |