|
From: Wojciech S. <woj...@gm...> - 2022-11-17 09:46:28
|
Klaus,
I agree with Dan, it is very usefull, it deserves posting in
Python/examples directory.
Regards,
Wojtek
czw., 17 lis 2022, 02:29 użytkownik Dan VolPM <dan...@gm...> napisał:
> Thank you so much Klaus, this is extremely useful and thorough and
> definitely helps a ton !
>
> On Tue, Nov 15, 2022 at 5:32 PM Klaus Spanderen <kl...@sp...>
> wrote:
>
>> Hi Dan,
>>
>>
>>
>> please find below an example of a Andreasen-Huge local volatility
>> calibration, a Monte-Carlo pricing of one of the calibration options using
>> this local volatility surface and the comparison with the expected result.
>>
>>
>>
>> W.r.t. point 1, the GeneralizedBlackScholesProcess should be constructed
>> directly using the local volatility surface from the Andreasen-Huge
>> algorithm (see code below), not the implied volatility surface from the
>> Andreasen-Huge interpolation algorithm. In the latter case the process
>> would use Dupire's equation to get back the local volatility, which is
>> notourisly instable and might lead to arbitrage violations.
>>
>>
>>
>> I hope the example code below helps wr.t. 2 and 3.
>>
>>
>>
>> best regards
>>
>> Klaus
>>
>>
>>
>>
>>
>> import math
>>
>> import QuantLib as ql
>>
>>
>>
>> if __name__ == "__main__":
>>
>> today = ql.Date.todaysDate()
>>
>> ql.Settings.instance().evaluationDate = today
>>
>>
>>
>> spot = ql.QuoteHandle(ql.SimpleQuote(100))
>>
>>
>>
>> dc = ql.Actual365Fixed()
>>
>> qTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.025, dc))
>>
>> rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, dc))
>>
>>
>>
>> vol_data = [
>>
>> # maturity in days, strike, volatility
>>
>> (30, 75, 0.13),
>>
>> (30, 100, 0.26),
>>
>> (30, 125, 0.3),
>>
>> (180, 80, 0.4),
>>
>> (180, 150, 0.6),
>>
>> (365, 110, 0.5)]
>>
>>
>>
>> calibration_set = ql.CalibrationSet(
>>
>> [(
>>
>> ql.VanillaOption(
>>
>> ql.PlainVanillaPayoff(ql.Option.Call, strike),
>>
>> ql.EuropeanExercise(today + ql.Period(maturity_in_days, ql.Days))
>>
>> ),
>>
>> ql.SimpleQuote(volatility)
>>
>> ) for maturity_in_days, strike, volatility in vol_data]
>>
>> )
>>
>>
>>
>> local_vol = ql.LocalVolTermStructureHandle(
>>
>> ql.AndreasenHugeLocalVolAdapter(
>>
>> ql.AndreasenHugeVolatilityInterpl(calibration_set, spot, rTS, qTS)
>>
>> )
>>
>> )
>>
>>
>>
>> option = calibration_set[-2][0] # maturity in days: 180, strike: 150,
>> vol: 0.6
>>
>>
>>
>> dummy_vol = ql.BlackVolTermStructureHandle()
>>
>> local_vol_process = ql.GeneralizedBlackScholesProcess(spot, qTS, rTS,
>> dummy_vol, local_vol)
>>
>>
>>
>> option.setPricingEngine(ql.MCEuropeanEngine(
>>
>> local_vol_process, "lowdiscrepancy",
>>
>> timeSteps=100, brownianBridge=True, requiredSamples=32000, seed=42)
>>
>> )
>>
>>
>>
>> T = dc.yearFraction(today, option.exercise().lastDate())
>>
>> fwd = spot.value() * qTS.discount(T) / rTS.discount(T)
>>
>> vol = calibration_set[-2][1].value()
>>
>>
>>
>> expected = ql.BlackCalculator(
>>
>> ql.as_plain_vanilla_payoff(option.payoff()), fwd, vol * math.sqrt(T),
>> rTS.discount(T)).value()
>>
>>
>>
>> print("Expected : %.3f" % expected)
>>
>> print("Local Vol Monte-Carlo: %.3f" % option.NPV())
>>
>>
>>
>> time_steps = 100
>>
>> rsg = ql.GaussianRandomSequenceGenerator(
>>
>> ql.UniformRandomSequenceGenerator(time_steps,
>> ql.UniformRandomGenerator(42))
>>
>> )
>>
>> path_generator = ql.GaussianPathGenerator(local_vol_process, 1.0,
>> time_steps, rsg, False)
>>
>> next_path = path_generator.next().value()
>>
>>
>>
>> print("\nExample path: " + str({next_path.time(i): next_path.value(i) for
>> i in range(len(next_path))}))
>>
>>
>>
>>
>>
> _______________________________________________
> QuantLib-users mailing list
> Qua...@li...
> https://lists.sourceforge.net/lists/listinfo/quantlib-users
>
|