You can subscribe to this list here.
| 2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
(60) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2001 |
Jan
(18) |
Feb
(4) |
Mar
(6) |
Apr
(2) |
May
|
Jun
(12) |
Jul
(48) |
Aug
(6) |
Sep
(3) |
Oct
(24) |
Nov
(15) |
Dec
(18) |
| 2002 |
Jan
(39) |
Feb
(12) |
Mar
(80) |
Apr
(72) |
May
(46) |
Jun
(27) |
Jul
(23) |
Aug
(34) |
Sep
(65) |
Oct
(71) |
Nov
(19) |
Dec
(14) |
| 2003 |
Jan
(44) |
Feb
(59) |
Mar
(18) |
Apr
(62) |
May
(54) |
Jun
(27) |
Jul
(46) |
Aug
(15) |
Sep
(44) |
Oct
(36) |
Nov
(19) |
Dec
(12) |
| 2004 |
Jan
(26) |
Feb
(33) |
Mar
(47) |
Apr
(63) |
May
(36) |
Jun
(65) |
Jul
(80) |
Aug
(163) |
Sep
(65) |
Oct
(39) |
Nov
(36) |
Dec
(39) |
| 2005 |
Jan
(97) |
Feb
(78) |
Mar
(64) |
Apr
(64) |
May
(48) |
Jun
(55) |
Jul
(89) |
Aug
(57) |
Sep
(51) |
Oct
(111) |
Nov
(86) |
Dec
(76) |
| 2006 |
Jan
(84) |
Feb
(103) |
Mar
(143) |
Apr
(92) |
May
(55) |
Jun
(58) |
Jul
(71) |
Aug
(57) |
Sep
(74) |
Oct
(59) |
Nov
(8) |
Dec
(32) |
| 2007 |
Jan
(60) |
Feb
(40) |
Mar
(50) |
Apr
(26) |
May
(61) |
Jun
(120) |
Jul
(119) |
Aug
(48) |
Sep
(121) |
Oct
(66) |
Nov
(103) |
Dec
(43) |
| 2008 |
Jan
(60) |
Feb
(109) |
Mar
(92) |
Apr
(106) |
May
(82) |
Jun
(59) |
Jul
(67) |
Aug
(118) |
Sep
(131) |
Oct
(56) |
Nov
(37) |
Dec
(69) |
| 2009 |
Jan
(75) |
Feb
(76) |
Mar
(103) |
Apr
(78) |
May
(61) |
Jun
(35) |
Jul
(66) |
Aug
(69) |
Sep
(166) |
Oct
(46) |
Nov
(72) |
Dec
(65) |
| 2010 |
Jan
(48) |
Feb
(57) |
Mar
(93) |
Apr
(85) |
May
(123) |
Jun
(82) |
Jul
(98) |
Aug
(121) |
Sep
(146) |
Oct
(86) |
Nov
(72) |
Dec
(34) |
| 2011 |
Jan
(96) |
Feb
(55) |
Mar
(73) |
Apr
(57) |
May
(33) |
Jun
(74) |
Jul
(89) |
Aug
(71) |
Sep
(103) |
Oct
(76) |
Nov
(52) |
Dec
(61) |
| 2012 |
Jan
(48) |
Feb
(54) |
Mar
(78) |
Apr
(60) |
May
(75) |
Jun
(59) |
Jul
(33) |
Aug
(66) |
Sep
(43) |
Oct
(46) |
Nov
(75) |
Dec
(51) |
| 2013 |
Jan
(112) |
Feb
(72) |
Mar
(49) |
Apr
(48) |
May
(42) |
Jun
(44) |
Jul
(80) |
Aug
(19) |
Sep
(33) |
Oct
(37) |
Nov
(38) |
Dec
(98) |
| 2014 |
Jan
(113) |
Feb
(93) |
Mar
(49) |
Apr
(106) |
May
(97) |
Jun
(155) |
Jul
(87) |
Aug
(127) |
Sep
(85) |
Oct
(48) |
Nov
(41) |
Dec
(37) |
| 2015 |
Jan
(34) |
Feb
(50) |
Mar
(104) |
Apr
(80) |
May
(82) |
Jun
(66) |
Jul
(41) |
Aug
(84) |
Sep
(37) |
Oct
(65) |
Nov
(83) |
Dec
(52) |
| 2016 |
Jan
(68) |
Feb
(35) |
Mar
(42) |
Apr
(35) |
May
(54) |
Jun
(75) |
Jul
(45) |
Aug
(52) |
Sep
(60) |
Oct
(52) |
Nov
(36) |
Dec
(64) |
| 2017 |
Jan
(92) |
Feb
(59) |
Mar
(35) |
Apr
(53) |
May
(83) |
Jun
(43) |
Jul
(65) |
Aug
(68) |
Sep
(46) |
Oct
(75) |
Nov
(40) |
Dec
(49) |
| 2018 |
Jan
(68) |
Feb
(54) |
Mar
(48) |
Apr
(58) |
May
(51) |
Jun
(44) |
Jul
(40) |
Aug
(68) |
Sep
(35) |
Oct
(15) |
Nov
(7) |
Dec
(37) |
| 2019 |
Jan
(43) |
Feb
(7) |
Mar
(22) |
Apr
(21) |
May
(31) |
Jun
(39) |
Jul
(73) |
Aug
(45) |
Sep
(47) |
Oct
(89) |
Nov
(19) |
Dec
(69) |
| 2020 |
Jan
(52) |
Feb
(63) |
Mar
(45) |
Apr
(59) |
May
(42) |
Jun
(57) |
Jul
(30) |
Aug
(29) |
Sep
(75) |
Oct
(64) |
Nov
(96) |
Dec
(22) |
| 2021 |
Jan
(14) |
Feb
(24) |
Mar
(35) |
Apr
(58) |
May
(36) |
Jun
(15) |
Jul
(18) |
Aug
(31) |
Sep
(30) |
Oct
(33) |
Nov
(27) |
Dec
(16) |
| 2022 |
Jan
(35) |
Feb
(22) |
Mar
(14) |
Apr
(20) |
May
(44) |
Jun
(53) |
Jul
(25) |
Aug
(56) |
Sep
(11) |
Oct
(47) |
Nov
(22) |
Dec
(36) |
| 2023 |
Jan
(30) |
Feb
(17) |
Mar
(31) |
Apr
(48) |
May
(31) |
Jun
(7) |
Jul
(25) |
Aug
(26) |
Sep
(61) |
Oct
(66) |
Nov
(19) |
Dec
(21) |
| 2024 |
Jan
(37) |
Feb
(29) |
Mar
(26) |
Apr
(26) |
May
(34) |
Jun
(9) |
Jul
(27) |
Aug
(13) |
Sep
(15) |
Oct
(25) |
Nov
(13) |
Dec
(8) |
| 2025 |
Jan
(13) |
Feb
(1) |
Mar
(16) |
Apr
(17) |
May
(8) |
Jun
(6) |
Jul
(9) |
Aug
|
Sep
(6) |
Oct
(15) |
Nov
(6) |
Dec
|
| 2026 |
Jan
(6) |
Feb
(4) |
Mar
(20) |
Apr
(21) |
May
(12) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: m s. <msc...@ho...> - 2026-05-25 23:41:23
|
Hello Chirag, I have created a fork and a merge request to Eric Ehlers code with my updates. Since the pull request is still pending, you can use the code directly from my fork. You can find it here: https://github.com/mscaturo/QuantLibAddin-Old It uses the 1.42.1 version of QuantLib, the 1_90_0 version of the Boost library, the 1.6.1 version of lib4cxx And is compiled using Visual Studio 2022. It compiles and creates the addin for me without errors. I've created a few spreadsheets and verified the results against Bloomberg. I'm happy to take a look if you find any errors with it. Regards, Mike ________________________________ From: Chirag Desai <chi...@ya...> Sent: Thursday, May 21, 2026 10:38 PM To: qua...@li... <qua...@li...>; m scaturo <msc...@ho...> Subject: Re: [Quantlib-users] QuantLibXL Addin Hi Miike Thank you for the below. Can I kindly ask if you can send me the Github repo of the below please ? I used the instructions below with VS 2022, Quantlib 1.22 with Boost 1.87 but there are far too many errors as most of the older Boost functions have been deprecated. QuantLibAddin: Build QuantLibXL From Source Code<https://www.quantlib.org/quantlibaddin/build_qlxl.html> QuantLibAddin: Build QuantLibXL From Source Code<https://www.quantlib.org/quantlibaddin/build_qlxl.html> in On Tuesday, May 5, 2026 at 09:15:28 AM GMT+8, m scaturo <msc...@ho...> wrote: Hello Everyone, I have built the QuantLibXL addin with version 1.42.1 of quantlib using Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 I have exposed the FXForward functions but I haven't fully tested them yet. If there's an interest, I'd be happy to contribute this code back to the project. Thanks, Mike _______________________________________________ QuantLib-users mailing list Qua...@li...<mailto:Qua...@li...> https://lists.sourceforge.net/lists/listinfo/quantlib-users |
|
From: Chirag D. <chi...@ya...> - 2026-05-22 02:38:21
|
Hi Miike
Thank you for the below. Can I kindly ask if you can send me the Github repo of the below please ?
I used the instructions below with VS 2022, Quantlib 1.22 with Boost 1.87 but there are far too many errors as most of the older Boost functions have been deprecated.
QuantLibAddin: Build QuantLibXL From Source Code
|
|
|
| | |
|
|
|
| |
QuantLibAddin: Build QuantLibXL From Source Code
|
|
|
in
On Tuesday, May 5, 2026 at 09:15:28 AM GMT+8, m scaturo <msc...@ho...> wrote:
Hello Everyone,
I have built the QuantLibXL addin with version 1.42.1 of quantlib usingMicrosoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1
I have exposed the FXForward functions but I haven't fully tested them yet.
If there's an interest, I'd be happy to contribute this code back to the project.
Thanks,Mike_______________________________________________
QuantLib-users mailing list
Qua...@li...
https://lists.sourceforge.net/lists/listinfo/quantlib-users
|
|
From: Mike K. <mik...@gm...> - 2026-05-10 21:53:46
|
Hi Eric, It’s much simpler than that. Here is an example of an option pricer in C++ with C like syntax that is not compiled against QuantLib directly, but instead uses the Python distribution of QuantLib. https://github.com/mkipnis/QuantLibAddin-Old/blob/pybind_experimental/QuantLibAddin/experimental/options.cpp Essentially, I am calling the QuantLib from C++ the same way I would from the Python interpreter. Notice that it uses a combination of QuantLib function calls and Python functions from the “/qlo/” directory. With this approach, ObjectHandler remains, GenSrc is updated to replace the current QLO calls with pybind calls like those in the sample code above, and QuantLibAddin/qlo goes away because its functionality is replaced by SWIG. This approach should preserve backward compatibility and simplify the build process, since there is no separate QLO compilation step that requires the QuantLib. It also avoids rebuilds for new QuantLib releases unless function signatures change, and it opens the door to the broader Python ecosystem. See the build instructions: https://github.com/mkipnis/QuantLibAddin-Old/blob/pybind_experimental/QuantLibAddin/experimental/README.md Once backward compatibility is addressed and Python can be called from the library, users can leverage JSON serialization of Python data structures. For example, a proxy pricer could take a curve as input, send it to a Python-based mid-curve pricer, and have the pricer return the results as JSON. The workflow is simple: the user creates a JSON request in VBA, sends it to Python through the add-in, receives JSON results back, and displays them in Excel. https://github.com/mkipnis/QuantLibAddin-Old/blob/pybind_experimental/QuantLibAddin/experimental/proxy_pricer.cpp https://github.com/mkipnis/QuantLibAddin-Old/tree/pybind_experimental/QuantLibAddin/experimental/pricers https://github.com/vba-tools/vba-json Since more development and analysis is happening in Python than in VBA, while Excel remains the shared interface, this capability can be useful and may attract attention. Beyond QuantLib integration, this approach could also be used to connect with other APIs for pulling market data, accessing databases, and integrating with LLM services. And as a bonus, I would add an Excel ribbon similar to the ones in Bloomberg or YieldBook. These are easy to implement and users generally like them. The ribbon could include sections such as Rates, Credit, Instruments, etc. For example, the user could click “Curve” under Rates, and the sheet would automatically create a curve with default settings for the selected index. Then, under Instruments, the user could select “OIS” to price a swap at par against that curve. This would remove much of the guesswork around which functions to call for curve bootstrapping and swap pricing. Although, this would probably be a separate project on its own. To conclude, I think this project can be revived, as long as it positions itself as a bridge between Excel and Python, with QuantLib as its centerpiece. Best Regards, Mike > On May 7, 2026, at 4:05 AM, Eric Ehlers <eri...@re...> wrote: > > Hi Mike, > > I took a closer look at pybind, I struggle to follow. > - The C++ code in qlo, you would replace that with python? > - Instead of autogenerating that code in C++, gensrc would autogenerate it in python? > > And you would leave the rest of the build - ObjectHandler, the bindings to the Excel C API, etc. - unchanged? So the motivation would be that coders extending QuantLibXL could look at python instead of C++? > > That seems like a lot of pain for not much gain. The fact that people who want to extend QuantLibXL need to know C++, this does not strike me as much of a barrier. And the task of adding new QuantLib functions to QuantLibXL is probably much easier now using agents. > > Regards, > Eric > > On 5/7/26 2:02 AM, Mike Kipnis wrote: >> Hi Eric, >> Yes — backward compatibility would be fully maintained. >> The idea is to keep the existing QuantLibXL interface unchanged and only replace the internals: replace QuantLib/C++ calls in QuantLibAddin/qlo with QuantLib/Python calls, and replace the C++ bindings in gensrc with pybind. >> From the Excel/user perspective nothing changes, so existing spreadsheets should continue to work as-is. >> I will put together some pybind/C++ examples over the weekend to show how this would work in practice. >> Regards, >> Mike >>> On May 6, 2026, at 5:05 AM, Eric Ehlers <eri...@re...> wrote: >>> >>> Hi Mike, >>> >>> Many thanks for your recommendations. There is no doubt that the design of QuantLibXL could be improved. One advantage of the existing design is that it uses the Excel C API, last time I checked, there was still no faster way to interface with Excel. Even if we were to stick with the Excel C API, there are probably better ways to go about it, and I also think that you could make a case for migrating to pybind. >>> >>> One goal that I have always had for QuantLibXL is to maintain backward compatibility. Your proposed approach, would it maintain the same interface? Otherwise I would consider it a new project, something that could live alongside the existing QuantLibXL. >>> >>> Regards, >>> Eric > |
|
From: Eric E. <eri...@re...> - 2026-05-07 08:05:40
|
Hi Mike, I took a closer look at pybind, I struggle to follow. - The C++ code in qlo, you would replace that with python? - Instead of autogenerating that code in C++, gensrc would autogenerate it in python? And you would leave the rest of the build - ObjectHandler, the bindings to the Excel C API, etc. - unchanged? So the motivation would be that coders extending QuantLibXL could look at python instead of C++? That seems like a lot of pain for not much gain. The fact that people who want to extend QuantLibXL need to know C++, this does not strike me as much of a barrier. And the task of adding new QuantLib functions to QuantLibXL is probably much easier now using agents. Regards, Eric On 5/7/26 2:02 AM, Mike Kipnis wrote: > Hi Eric, > > Yes — backward compatibility would be fully maintained. > > The idea is to keep the existing QuantLibXL interface unchanged and only > replace the internals: replace QuantLib/C++ calls in QuantLibAddin/qlo > with QuantLib/Python calls, and replace the C++ bindings in gensrc with > pybind. > > From the Excel/user perspective nothing changes, so existing > spreadsheets should continue to work as-is. > > I will put together some pybind/C++ examples over the weekend to show > how this would work in practice. > > Regards, > Mike > > >> On May 6, 2026, at 5:05 AM, Eric Ehlers <eri...@re...> wrote: >> >> Hi Mike, >> >> Many thanks for your recommendations. There is no doubt that the >> design of QuantLibXL could be improved. One advantage of the existing >> design is that it uses the Excel C API, last time I checked, there was >> still no faster way to interface with Excel. Even if we were to stick >> with the Excel C API, there are probably better ways to go about it, >> and I also think that you could make a case for migrating to pybind. >> >> One goal that I have always had for QuantLibXL is to maintain backward >> compatibility. Your proposed approach, would it maintain the same >> interface? Otherwise I would consider it a new project, something >> that could live alongside the existing QuantLibXL. >> >> Regards, >> Eric > |
|
From: Mike K. <mik...@gm...> - 2026-05-07 00:03:01
|
Hi Eric, Yes — backward compatibility would be fully maintained. The idea is to keep the existing QuantLibXL interface unchanged and only replace the internals: replace QuantLib/C++ calls in QuantLibAddin/qlo with QuantLib/Python calls, and replace the C++ bindings in gensrc with pybind. From the Excel/user perspective nothing changes, so existing spreadsheets should continue to work as-is. I will put together some pybind/C++ examples over the weekend to show how this would work in practice. Regards, Mike > On May 6, 2026, at 5:05 AM, Eric Ehlers <eri...@re...> wrote: > > Hi Mike, > > Many thanks for your recommendations. There is no doubt that the design of QuantLibXL could be improved. One advantage of the existing design is that it uses the Excel C API, last time I checked, there was still no faster way to interface with Excel. Even if we were to stick with the Excel C API, there are probably better ways to go about it, and I also think that you could make a case for migrating to pybind. > > One goal that I have always had for QuantLibXL is to maintain backward compatibility. Your proposed approach, would it maintain the same interface? Otherwise I would consider it a new project, something that could live alongside the existing QuantLibXL. > > Regards, > Eric |
|
From: m s. <msc...@ho...> - 2026-05-06 22:49:48
|
Hi Eric, I'll submit a merge request and if you think it's useful, let me know. Best, Mike |
|
From: Eric E. <eri...@re...> - 2026-05-06 09:05:18
|
Hi Mike, Many thanks for your recommendations. There is no doubt that the design of QuantLibXL could be improved. One advantage of the existing design is that it uses the Excel C API, last time I checked, there was still no faster way to interface with Excel. Even if we were to stick with the Excel C API, there are probably better ways to go about it, and I also think that you could make a case for migrating to pybind. One goal that I have always had for QuantLibXL is to maintain backward compatibility. Your proposed approach, would it maintain the same interface? Otherwise I would consider it a new project, something that could live alongside the existing QuantLibXL. Regards, Eric On 5/6/26 2:59 AM, Mike Kipnis wrote: > Hi Eric, > > > This used to be a very interesting project, but its technology stack is > now quite outdated. > > > Here’s, in my opinion, a practical approach that could help revive it: > > > * Update the avatar icon at https://github.com/eehlers <https:// > github.com/eehlers> > * Convert the C++ calls in https://github.com/eehlers/QuantLibAddin- > Old/tree/master/QuantLibAddin/qlo <https://github.com/eehlers/ > QuantLibAddin-Old/tree/master/QuantLibAddin/qlo> to Python using an > LLM, ideally in phases—from the most commonly used instruments to > the least > * Expose the resulting Python code back to C++ using pybind (https:// > pybind11.readthedocs.io/en/stable/advanced/pycpp/index.html > <https://pybind11.readthedocs.io/en/stable/advanced/pycpp/ > index.html>), making it accessible through the existing Excel and C+ > + frameworks in QuantLibAddin > > > Moving QuantLibAddin/qlo to Python has additional advantages. It would > make the library more accessible, as fewer developers are inclined to > work directly in C++ for pricing and risk. This could broaden adoption > and attract more contributors, allowing valuable ideas to be > reimplemented in QuantLib. It would also create a smoother bridge > between Python and Excel in general. > > > My two cents. > > > Best regards, > Mike > > >> On May 5, 2026, at 11:56 AM, Francois Botha <ig...@gm...> wrote: >> >> Eric, for what it's worth, my colleagues and I are still active users >> of the current released version. Would love to see the project revived >> on that long promised reposit refactoring. Thanks for what you've >> provided thus far. >> >> Francois Botha >> >> >> On Tue, 5 May 2026 at 17:29, Eric Ehlers <eri...@re... >> <mailto:eri...@re...>> wrote: >> >> Hi Mike, >> >> The project is kind of in limbo these days. If you would like, >> you are >> most welcome to raise a merge request, so that the change is >> available >> in case the project resumes. >> >> Regards, >> Eric >> >> On 5/5/26 3:11 AM, m scaturo wrote: >> > Hello Everyone, >> > >> > I have built the QuantLibXL addin with version 1.42.1 of >> quantlib using >> > Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 >> > >> > I have exposed the FXForward functions but I haven't fully >> tested them yet. >> > >> > If there's an interest, I'd be happy to contribute this code >> back to the >> > project. >> > >> > Thanks, >> > Mike >> > >> > >> > _______________________________________________ >> > QuantLib-users mailing list >> > Qua...@li... <mailto:QuantLib- >> us...@li...> >> > https://lists.sourceforge.net/lists/listinfo/quantlib-users >> <https://lists.sourceforge.net/lists/listinfo/quantlib-users> >> >> >> >> _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... <mailto:QuantLib- >> us...@li...> >> https://lists.sourceforge.net/lists/listinfo/quantlib-users >> <https://lists.sourceforge.net/lists/listinfo/quantlib-users> >> >> _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... >> https://lists.sourceforge.net/lists/listinfo/quantlib-users > |
|
From: Eric E. <eri...@re...> - 2026-05-06 08:58:37
|
Hi Francois, Thank you, that's very useful information. It's always hard to know how much interest there is in the project. We are talking now about the possibility of resurrecting QuantLibXL, maybe under the ORE umbrella. The simplest case would be to update QuantLibXL to the latest version of QuantLib. Beyond that we could look at extending QuantLibXL, maybe even to include ORE functions. The reposit build, I got it to the point of generating 80-90% of the functions in QuantLibXL. I was never too sure about that approach. Instead of using gensrc, and maintaining XML files, we would have to use a fork of SWIG, and maintain SWIG interface files. Regards, Eric On 5/5/26 5:56 PM, Francois Botha wrote: > Eric, for what it's worth, my colleagues and I are still active users of > the current released version. Would love to see the project revived on > that long promised reposit refactoring. Thanks for what you've provided > thus far. > > Francois Botha > > > On Tue, 5 May 2026 at 17:29, Eric Ehlers <eri...@re... > <mailto:eri...@re...>> wrote: > > Hi Mike, > > The project is kind of in limbo these days. If you would like, you are > most welcome to raise a merge request, so that the change is available > in case the project resumes. > > Regards, > Eric > > On 5/5/26 3:11 AM, m scaturo wrote: > > Hello Everyone, > > > > I have built the QuantLibXL addin with version 1.42.1 of quantlib > using > > Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 > > > > I have exposed the FXForward functions but I haven't fully tested > them yet. > > > > If there's an interest, I'd be happy to contribute this code back > to the > > project. > > > > Thanks, > > Mike > > > > > > _______________________________________________ > > QuantLib-users mailing list > > Qua...@li... <mailto:QuantLib- > us...@li...> > > https://lists.sourceforge.net/lists/listinfo/quantlib-users > <https://lists.sourceforge.net/lists/listinfo/quantlib-users> > > > > _______________________________________________ > QuantLib-users mailing list > Qua...@li... <mailto:QuantLib- > us...@li...> > https://lists.sourceforge.net/lists/listinfo/quantlib-users > <https://lists.sourceforge.net/lists/listinfo/quantlib-users> > |
|
From: Mike K. <mik...@gm...> - 2026-05-06 00:59:56
|
Hi Eric, This used to be a very interesting project, but its technology stack is now quite outdated. Here’s, in my opinion, a practical approach that could help revive it: Update the avatar icon at https://github.com/eehlers Convert the C++ calls in https://github.com/eehlers/QuantLibAddin-Old/tree/master/QuantLibAddin/qlo to Python using an LLM, ideally in phases—from the most commonly used instruments to the least Expose the resulting Python code back to C++ using pybind (https://pybind11.readthedocs.io/en/stable/advanced/pycpp/index.html), making it accessible through the existing Excel and C++ frameworks in QuantLibAddin Moving QuantLibAddin/qlo to Python has additional advantages. It would make the library more accessible, as fewer developers are inclined to work directly in C++ for pricing and risk. This could broaden adoption and attract more contributors, allowing valuable ideas to be reimplemented in QuantLib. It would also create a smoother bridge between Python and Excel in general. My two cents. Best regards, Mike > On May 5, 2026, at 11:56 AM, Francois Botha <ig...@gm...> wrote: > > Eric, for what it's worth, my colleagues and I are still active users of the current released version. Would love to see the project revived on that long promised reposit refactoring. Thanks for what you've provided thus far. > > Francois Botha > > > On Tue, 5 May 2026 at 17:29, Eric Ehlers <eri...@re... <mailto:eri...@re...>> wrote: >> Hi Mike, >> >> The project is kind of in limbo these days. If you would like, you are >> most welcome to raise a merge request, so that the change is available >> in case the project resumes. >> >> Regards, >> Eric >> >> On 5/5/26 3:11 AM, m scaturo wrote: >> > Hello Everyone, >> > >> > I have built the QuantLibXL addin with version 1.42.1 of quantlib using >> > Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 >> > >> > I have exposed the FXForward functions but I haven't fully tested them yet. >> > >> > If there's an interest, I'd be happy to contribute this code back to the >> > project. >> > >> > Thanks, >> > Mike >> > >> > >> > _______________________________________________ >> > QuantLib-users mailing list >> > Qua...@li... <mailto:Qua...@li...> >> > https://lists.sourceforge.net/lists/listinfo/quantlib-users >> >> >> >> _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... <mailto:Qua...@li...> >> https://lists.sourceforge.net/lists/listinfo/quantlib-users > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users |
|
From: Francois B. <ig...@gm...> - 2026-05-05 15:56:35
|
Eric, for what it's worth, my colleagues and I are still active users of the current released version. Would love to see the project revived on that long promised reposit refactoring. Thanks for what you've provided thus far. Francois Botha On Tue, 5 May 2026 at 17:29, Eric Ehlers <eri...@re...> wrote: > Hi Mike, > > The project is kind of in limbo these days. If you would like, you are > most welcome to raise a merge request, so that the change is available > in case the project resumes. > > Regards, > Eric > > On 5/5/26 3:11 AM, m scaturo wrote: > > Hello Everyone, > > > > I have built the QuantLibXL addin with version 1.42.1 of quantlib using > > Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 > > > > I have exposed the FXForward functions but I haven't fully tested them > yet. > > > > If there's an interest, I'd be happy to contribute this code back to the > > project. > > > > Thanks, > > Mike > > > > > > _______________________________________________ > > 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 > |
|
From: Eric E. <eri...@re...> - 2026-05-05 15:24:07
|
Hi Mike, The project is kind of in limbo these days. If you would like, you are most welcome to raise a merge request, so that the change is available in case the project resumes. Regards, Eric On 5/5/26 3:11 AM, m scaturo wrote: > Hello Everyone, > > I have built the QuantLibXL addin with version 1.42.1 of quantlib using > Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 > > I have exposed the FXForward functions but I haven't fully tested them yet. > > If there's an interest, I'd be happy to contribute this code back to the > project. > > Thanks, > Mike > > > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users |
|
From: m s. <msc...@ho...> - 2026-05-05 01:11:26
|
Hello Everyone, I have built the QuantLibXL addin with version 1.42.1 of quantlib using Microsoft visual studio 2022, boost 1_90_0, and lib4cxx 1.6.1 I have exposed the FXForward functions but I haven't fully tested them yet. If there's an interest, I'd be happy to contribute this code back to the project. Thanks, Mike |
|
From: Eric E. <eri...@re...> - 2026-04-30 08:50:41
|
Hi Chirag, QuantLibXL was last updated in 2021 for QuantLib version 1.22. Here is the relevant repo: https://github.com/eehlers/QuantLibAddin-Old Here is the documentation for exporting a QuantLib class to QuantLibXL: https://www.quantlib.org/quantlibaddin/tutorials.html Regards, Eric On 4/30/26 10:12 AM, Chirag Desai via QuantLib-users wrote: > Hi All > > I am trying to find out more on how to expose a new FX Forward class in > Quantlib I had written into Excel via the Quantlib XL addin. > > Luigi was kind to introduce the Github repo but I am lost on where to > start from. > > eehlers - Overview <https://github.com/eehlers/> > > Can anybody share some basic resources or specific areas I can look into > for me to learn from ? > > > Thank you very much > Chirag > > > > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users |
|
From: Chirag D. <chi...@ya...> - 2026-04-30 08:12:31
|
Hi All I am trying to find out more on how to expose a new FX Forward class in Quantlib I had written into Excel via the Quantlib XL addin. Luigi was kind to introduce the Github repo but I am lost on where to start from. eehlers - Overview Can anybody share some basic resources or specific areas I can look into for me to learn from ? Thank you very muchChirag |
|
From: Dmitri G. <dm...@ma...> - 2026-04-17 16:57:31
|
Hi Marco, Great to see ORE Studio — looks like a useful project. On the AAD side: we’ve had a working integration of AADC with ORE for several years now — transparent AAD valuation through the standard ORE workflow, including JIT compilation and replay for Monte Carlo paths. We have clients running this in production. Here’s a demo from 2022 <https://www.youtube.com/watch?v=1WN8gUF120M&utm_campaign=crm&utm_source=email&utm_medium=direct&tid=natwest-marco-craveiro-20260417-1> showing ORE+AADC in action. More details: live risk architecture <https://matlogica.com/technology/live-risk-architecture/?utm_campaign=crm&utm_source=email&utm_medium=direct&tid=natwest-marco-craveiro-20260417-2> and ORE LiveRisk <https://matlogica.com/technology/ore-liverisk/?utm_campaign=crm&utm_source=email&utm_medium=direct&tid=natwest-marco-craveiro-20260417-3> . Happy to show you a live demo or discuss how it might fit with ORE Studio. Kind regards, Dmitri Goloubentsev Head of Automatic Adjoint Differentiation, Matlogica LTD http://matlogica.com +447378414528 See my schedule and book <https://calendly.com/matlogica> a meeting with me On Thu, 16 Apr 2026 at 17:12, Marco Craveiro <mar...@gm...> wrote: > Hi QuantLib devs, > > A few months ago I started a new open source project called ORE Studio: > > - https://github.com/OreStudio/OreStudio > > This email is my first outreach attempt. ORE Studio's ultimate > objective will be to provide a CRUD and service layer for ORE [1]. > Note that the project is not directly affiliated with ORE, but it is > so named because it only targets ORE and no other risk engine. It may > be subject to change, If Roland or anyone from ORE has any qualms with > it. > > Releases are done when we accumulate enough commits; I am about to > release v0.0.16 over the next few days. I recommend always using main > and updating very frequently, as the code tends to move around a lot. > > I also feel compelled to provide some warnings and caveats: > > - Though I've been at it for over 6 months, it is *very* early days > for the project; many things don't work as expected, or don't work at > all. The code is stabilising somewhat but, in truth, *anything* may be > subject to change. For example, we just recently transitioned from a > monolith to a service-based architecture > - The documentation is not great, and it is certainly not up-to-date. > - ORE Studio is *100%* developed with AI - more specifically Claude > Code [2] - so the code is not exactly the absolute best. One of my > objectives with ORE Studio is to test the AI state of the art in anger > - the other being testing the suitability of ORE for Intraday Risk > management. If you do not like AI, I'm rather afraid ORE Studio won't > be to your liking. Contributions without AI are, of course, very > welcome. > > The main focus for the eventual v1.0.0 will be to get the end-to-end > workflow working correctly across the entire ORE instrument inventory > (as per ORE samples): > > - UI for entering trades (with instrument-specific handling), managing > curves, surfaces etc - effectively UIs covering all of ORE input data. > - reporting subsystem to create batches, send them for valuation; > - compute subsystem to value batches; > - UI to view report results. > > The skeleton for this structure is now in place, but has many (many) > limitations across the board. In fairness, I have somewhat rushed the > outreach; my objective was to get something basic finished by the ORE > user meet up but, given it is on the 11th of May, I ran out of time. I > wanted those interested to have time to have a play prior to the > event, and hopefully gather some feedback from the community at the > meetup, as to the usefulness of this project outside my use cases. > > Finally, I do not wish to abuse Luigi's patience and send too many > emails about ORE Studio on the QuantLib malinglist :-) so, if you want > to ask any questions or just have a chat, can I please ask you to pop > over to our discord: > > https://discord.gg/gcrYsjW3pd > > You can also contact me directly, either over email or Twitter. And, > as with any GitHub project, you can raise issues, discussions etc. > > I look forward to hearing from you. Many thanks for your time. > -- > Marco Craveiro, PhD > > about: https://mcraveiro.github.io/about.html > site: https://mcraveiro.github.io/ > twitter: https://twitter.com/MarcoCraveiro > > [1] https://github.com/OpenSourceRisk/Engine > [2] https://claude.com/product/claude-code > > > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users > |
|
From: Marco C. <mar...@gm...> - 2026-04-17 15:26:44
|
Hi Dmitri, > Great to see ORE Studio — looks like a useful project. Thanks for the kind words. Also, as requested by a few people, I created a quick video overview of the project; it gives a better idea of what we're aiming for (with apologies in advance for the sound quality): https://youtu.be/sgf7ybOpWxE > On the AAD side: we’ve had a working integration of AADC with ORE for several years now — transparent AAD valuation through the standard ORE workflow, including JIT compilation and replay for Monte Carlo paths. We have clients running this in production. > > Here’s a demo from 2022 showing ORE+AADC in action. > > More details: live risk architecture and ORE LiveRisk. Whilst I am very interested, I must confess I have not made much progress on the AAD front so far. I've had a brief conversation with Jorg regarding their QuantLibAAD approach [1]. It looked extremely interesting but required further work at my end to consume it. ORE Studio works best with something that "looks" like an ORE binary. On the other hand, from the links you provided [2, 3], ORE + AADC appears to integrate seamlessly with ORE Studio, requiring only config changes (the manifest of the compute package). > Happy to show you a live demo or discuss how it might fit with ORE Studio. I'll contact you directly - seems very promising and should be easy to test. Thanks very much for reaching out. Cheers -- Marco Craveiro, PhD about: https://mcraveiro.github.io/about.html site: https://mcraveiro.github.io/ twitter: https://twitter.com/MarcoCraveiro [1] https://sourceforge.net/p/quantlib/mailman/message/59293906/ [2] https://matlogica.com/technology/live-risk-architecture [3] https://matlogica.com/technology/ore-liverisk |
|
From: Luigi B. <lui...@gm...> - 2026-04-17 08:38:23
|
QuantLib 1.42.1 is now available for download at < https://www.quantlib.org/download.shtml>; precompiled binaries are also available from PyPI and NuGet for Python and C# respectively. This is a bug-fix release for the recently released QuantLib 1.42, removing a regression in the Gsr class possibly leading to an infinite notification loop. Thanks to Aleksis Ali Raza for the heads-up. If you have any problems with this release, please report them here on the QuantLib mailing list (<qua...@li...>) or open a GitHub issue at <https://github.com/lballabio/quantlib/issues>. |
|
From: Marco C. <mar...@gm...> - 2026-04-16 16:10:55
|
Hi QuantLib devs, A few months ago I started a new open source project called ORE Studio: - https://github.com/OreStudio/OreStudio This email is my first outreach attempt. ORE Studio's ultimate objective will be to provide a CRUD and service layer for ORE [1]. Note that the project is not directly affiliated with ORE, but it is so named because it only targets ORE and no other risk engine. It may be subject to change, If Roland or anyone from ORE has any qualms with it. Releases are done when we accumulate enough commits; I am about to release v0.0.16 over the next few days. I recommend always using main and updating very frequently, as the code tends to move around a lot. I also feel compelled to provide some warnings and caveats: - Though I've been at it for over 6 months, it is *very* early days for the project; many things don't work as expected, or don't work at all. The code is stabilising somewhat but, in truth, *anything* may be subject to change. For example, we just recently transitioned from a monolith to a service-based architecture - The documentation is not great, and it is certainly not up-to-date. - ORE Studio is *100%* developed with AI - more specifically Claude Code [2] - so the code is not exactly the absolute best. One of my objectives with ORE Studio is to test the AI state of the art in anger - the other being testing the suitability of ORE for Intraday Risk management. If you do not like AI, I'm rather afraid ORE Studio won't be to your liking. Contributions without AI are, of course, very welcome. The main focus for the eventual v1.0.0 will be to get the end-to-end workflow working correctly across the entire ORE instrument inventory (as per ORE samples): - UI for entering trades (with instrument-specific handling), managing curves, surfaces etc - effectively UIs covering all of ORE input data. - reporting subsystem to create batches, send them for valuation; - compute subsystem to value batches; - UI to view report results. The skeleton for this structure is now in place, but has many (many) limitations across the board. In fairness, I have somewhat rushed the outreach; my objective was to get something basic finished by the ORE user meet up but, given it is on the 11th of May, I ran out of time. I wanted those interested to have time to have a play prior to the event, and hopefully gather some feedback from the community at the meetup, as to the usefulness of this project outside my use cases. Finally, I do not wish to abuse Luigi's patience and send too many emails about ORE Studio on the QuantLib malinglist :-) so, if you want to ask any questions or just have a chat, can I please ask you to pop over to our discord: https://discord.gg/gcrYsjW3pd You can also contact me directly, either over email or Twitter. And, as with any GitHub project, you can raise issues, discussions etc. I look forward to hearing from you. Many thanks for your time. -- Marco Craveiro, PhD about: https://mcraveiro.github.io/about.html site: https://mcraveiro.github.io/ twitter: https://twitter.com/MarcoCraveiro [1] https://github.com/OpenSourceRisk/Engine [2] https://claude.com/product/claude-code |
|
From: Luigi B. <lui...@gm...> - 2026-04-16 09:46:25
|
Thanks!
On Thu, Apr 16, 2026 at 11:32 AM Aleksis Ali Raza <
ale...@go...> wrote:
> yes, the results tie with v1.40 after the code fix in 1.42.
>
> here's a comparison run for the test script i sent earlier.
>
> --- GSR live setValue bump test v1.42---
> base rate: 0.04875825
> base npv : 16.787915348295005
>
> setValue -> 0.04885825
> npv = 17.005154111913548
>
> setValue -> 0.04865825
> npv = 16.57057870270632
>
> setValue -> 0.04875825
> npv = 16.787915348295005
>
> starting stress loop...
> iter 000 rate=0.04885825 npv=17.005154111913548
> iter 020 rate=0.04885825 npv=17.005154111913548
> iter 040 rate=0.04885825 npv=17.005154111913548
> iter 060 rate=0.04885825 npv=17.005154111913548
> iter 080 rate=0.04885825 npv=17.005154111913548
> iter 100 rate=0.04885825 npv=17.005154111913548
> iter 120 rate=0.04885825 npv=17.005154111913548
> iter 140 rate=0.04885825 npv=17.005154111913548
> iter 160 rate=0.04885825 npv=17.005154111913548
> iter 180 rate=0.04885825 npv=17.005154111913548
>
> restored rate: 0.04875825
> restored npv : 16.787915348295005
>
>
> --- GSR live setValue bump test v1.40 ---
> base rate: 0.04875825
> base npv : 16.787915348295005
>
> setValue -> 0.04885825
> npv = 17.005154111913548
>
> setValue -> 0.04865825
> npv = 16.57057870270632
>
> setValue -> 0.04875825
> npv = 16.787915348295005
>
> starting stress loop...
> iter 000 rate=0.04885825 npv=17.005154111913548
> iter 020 rate=0.04885825 npv=17.005154111913548
> iter 040 rate=0.04885825 npv=17.005154111913548
> iter 060 rate=0.04885825 npv=17.005154111913548
> iter 080 rate=0.04885825 npv=17.005154111913548
> iter 100 rate=0.04885825 npv=17.005154111913548
> iter 120 rate=0.04885825 npv=17.005154111913548
> iter 140 rate=0.04885825 npv=17.005154111913548
> iter 160 rate=0.04885825 npv=17.005154111913548
> iter 180 rate=0.04885825 npv=17.005154111913548
>
> restored rate: 0.04875825
> restored npv : 16.787915348295005
>
>
> On Apr 16, 2026, at 12:38, Luigi Ballabio <lui...@gm...>
> wrote:
>
> May you check that it also reprices correctly after the bump? That is,
> that you get the same numerical results as 1.40?
>
> On Thu, Apr 16, 2026 at 9:04 AM Luigi Ballabio <lui...@gm...>
> wrote:
>
>> Thanks for the heads-up. Looks like I need to release a 1.42.1...
>>
>> Luigi
>>
>>
>> On Thu, Apr 16, 2026 at 8:57 AM Aleksis Ali Raza via QuantLib-users <
>> qua...@li...> wrote:
>>
>>> Yep, ditching registerWith(stateProcess_); works fine as well and is the
>>> cleaner fix.
>>>
>>> thanks.
>>>
>>> On Apr 16, 2026, at 11:34, Peter Caspers <pca...@gm...> wrote:
>>>
>>> Thanks. Since Gsr manages its stateProcess_, it does not need to and
>>> should not register with it as an Observer? I will take a closer look, but
>>> if you could test this change on your end, that would be valuable input.
>>> Best, Peter
>>>
>>>
>>> Aleksis Ali Raza via QuantLib-users <
>>> qua...@li...> schrieb am Do. 16. Apr. 2026 um
>>> 08:04:
>>>
>>>> Just to follow up on this, it's this line:
>>>>
>>>> void Gsr::update() {
>>>> if (stateProcess_ != nullptr) {
>>>>
>>>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
>>>>
>>>> *ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();*
>>>> }
>>>> LazyObject::update();
>>>> }
>>>>
>>>> in the gsr class that seems to be the cause. in my case, commenting out
>>>> that line out and rebuilding from source fixes the problem of my gsr-based
>>>> swaption risk runs.
>>>>
>>>> That line by itself looks pretty harmless but i think
>>>>
>>>> registerWith(stateProcess_);
>>>>
>>>> further down leads into some sort of feedback loop (setValue() →
>>>> notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() →
>>>> Gsr::update() → …) and ultimately a seg fault.
>>>>
>>>> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <
>>>> ale...@go...> wrote:
>>>>
>>>> Hi,
>>>>
>>>> I’m encountering what appears to be a regression or stability issue in
>>>> QuantLib 1.42 related to the GSR (Gaussian short rate) model and the
>>>> observer framework.
>>>>
>>>> Calling SimpleQuote.setValue() on a quote that is observed by a term
>>>> structure used in a Gsr model causes a segmentation fault.
>>>>
>>>> This occurs even in a minimal standalone script (no threading, no
>>>> external frameworks).
>>>>
>>>> Minimal reproduction
>>>>
>>>> The following sequence is sufficient:
>>>> 1. Create a SimpleQuote
>>>> 2. Build a FlatForward curve using that quote
>>>> 3. Construct a Gsr model from that term structure
>>>> 4. Attach a Gaussian1dSwaptionEngine
>>>> 5. Call setValue() on the original SimpleQuote
>>>>
>>>> This results in a segmentation fault.
>>>>
>>>> I have modified the Python/examples/bermudan_swaption.py file and
>>>> attached it below to illustrate (along with error log below it).
>>>>
>>>> Has something been changed in how one shud enquire / update quote
>>>> objects that I missed? I am coming from 1.40, where this was not an issue.
>>>> I am running python 3.14.4 on macOS 26.1.4 and using a source build of
>>>> Quantlib/SWIG.
>>>>
>>>> Thanks, Aleksis
>>>>
>>>> # ---
>>>> # jupyter:
>>>> # jupytext:
>>>> # formats: py:light
>>>> # text_representation:
>>>> # extension: .py
>>>> # format_name: light
>>>> # format_version: '1.5'
>>>> # jupytext_version: 1.4.2
>>>> # kernelspec:
>>>> # display_name: Python 3
>>>> # language: python
>>>> # name: python3
>>>> # ---
>>>>
>>>> # # Bermudan swaptions
>>>> #
>>>> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
>>>> #
>>>> # This file is part of QuantLib, a free-software/open-source library
>>>> # for financial quantitative analysts and developers - https://www.quantlib.org/
>>>> #
>>>> # QuantLib is free software: you can redistribute it and/or modify it under the
>>>> # terms of the QuantLib license. You should have received a copy of the
>>>> # license along with this program; if not, please email
>>>> # <qua...@li...>. The license is also available online at
>>>> # <https://www.quantlib.org/license.shtml>.
>>>> #
>>>> # This program is distributed in the hope that it will be useful, but WITHOUT
>>>> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
>>>> # FOR A PARTICULAR PURPOSE. See the license for more details.
>>>>
>>>> import QuantLib as ql
>>>> import pandas as pd
>>>>
>>>> # ### Setup
>>>>
>>>> todaysDate = ql.Date(15, ql.February, 2002)
>>>> ql.Settings.instance().evaluationDate = todaysDate
>>>> calendar = ql.TARGET()
>>>> settlementDate = ql.Date(19, ql.February, 2002)
>>>>
>>>>
>>>> def calibrate(model, helpers, l, name):
>>>> print("Model: %s" % name)
>>>>
>>>> method = ql.Simplex(l)
>>>> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>>>>
>>>> print("Parameters: %s" % model.params())
>>>>
>>>> totalError = 0.0
>>>> data = []
>>>> for swaption, helper in zip(swaptionVols, helpers):
>>>> maturity, length, vol = swaption
>>>> NPV = helper.modelValue()
>>>> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
>>>> error = implied - vol
>>>> totalError += abs(error)
>>>> data.append((maturity, length, vol, implied, error))
>>>> averageError = totalError / len(helpers)
>>>>
>>>> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>>>>
>>>> print("Average error: %.4f" % averageError)
>>>>
>>>>
>>>> # ### Market data
>>>>
>>>> swaptionVols = [
>>>> # maturity, length, volatility
>>>> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
>>>> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
>>>> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
>>>> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
>>>> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
>>>> ]
>>>>
>>>> # This is a flat yield term structure implying a 1x5 swap at 5%.
>>>>
>>>> rateQuote = ql.SimpleQuote(0.04875825)
>>>> rate = ql.QuoteHandle(rateQuote)
>>>> termStructure = ql.YieldTermStructureHandle(
>>>> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
>>>> )
>>>>
>>>> # Define the ATM/OTM/ITM swaps:
>>>>
>>>> swapEngine = ql.DiscountingSwapEngine(termStructure)
>>>>
>>>> fixedLegFrequency = ql.Annual
>>>> fixedLegTenor = ql.Period(1, ql.Years)
>>>> fixedLegConvention = ql.Unadjusted
>>>> floatingLegConvention = ql.ModifiedFollowing
>>>> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
>>>> floatingLegFrequency = ql.Semiannual
>>>> floatingLegTenor = ql.Period(6, ql.Months)
>>>>
>>>> payFixed = ql.Swap.Payer
>>>> fixingDays = 2
>>>> index = ql.Euribor6M(termStructure)
>>>> floatingLegDayCounter = index.dayCounter()
>>>>
>>>> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
>>>> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>>>>
>>>> fixedSchedule = ql.Schedule(
>>>> swapStart,
>>>> swapEnd,
>>>> fixedLegTenor,
>>>> calendar,
>>>> fixedLegConvention,
>>>> fixedLegConvention,
>>>> ql.DateGeneration.Forward,
>>>> False,
>>>> )
>>>> floatingSchedule = ql.Schedule(
>>>> swapStart,
>>>> swapEnd,
>>>> floatingLegTenor,
>>>> calendar,
>>>> floatingLegConvention,
>>>> floatingLegConvention,
>>>> ql.DateGeneration.Forward,
>>>> False,
>>>> )
>>>>
>>>> dummy = ql.VanillaSwap(
>>>> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
>>>> )
>>>> dummy.setPricingEngine(swapEngine)
>>>> atmRate = dummy.fairRate()
>>>>
>>>> atmSwap = ql.VanillaSwap(
>>>> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
>>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>>> )
>>>>
>>>> otmSwap = ql.VanillaSwap(
>>>> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
>>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>>> )
>>>>
>>>> itmSwap = ql.VanillaSwap(
>>>> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
>>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>>> )
>>>>
>>>> atmSwap.setPricingEngine(swapEngine)
>>>> otmSwap.setPricingEngine(swapEngine)
>>>> itmSwap.setPricingEngine(swapEngine)
>>>>
>>>> helpers = [
>>>> ql.SwaptionHelper(
>>>> maturity,
>>>> length,
>>>> ql.makeQuoteHandle(vol),
>>>> index,
>>>> index.tenor(),
>>>> index.dayCounter(),
>>>> index.dayCounter(),
>>>> termStructure,
>>>> )
>>>> for maturity, length, vol in swaptionVols
>>>> ]
>>>>
>>>> times = {}
>>>> for h in helpers:
>>>> for t in h.times():
>>>> times[t] = 1
>>>> times = sorted(times.keys())
>>>>
>>>> grid = ql.TimeGrid(times, 30)
>>>>
>>>> G2model = ql.G2(termStructure)
>>>> HWmodel = ql.HullWhite(termStructure)
>>>> HWmodel2 = ql.HullWhite(termStructure)
>>>> BKmodel = ql.BlackKarasinski(termStructure)
>>>>
>>>> # ### Calibrations
>>>>
>>>> for h in helpers:
>>>> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
>>>> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>>>>
>>>> for h in helpers:
>>>> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
>>>> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>>>>
>>>> for h in helpers:
>>>> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
>>>> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>>>>
>>>> for h in helpers:
>>>> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
>>>> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>>>>
>>>>
>>>> # ### Price Bermudan swaptions on defined swaps
>>>>
>>>> bermudanDates = [d for d in fixedSchedule][:-1]
>>>> exercise = ql.BermudanExercise(bermudanDates)
>>>>
>>>> atmSwaption = ql.Swaption(atmSwap, exercise)
>>>> otmSwaption = ql.Swaption(otmSwap, exercise)
>>>> itmSwaption = ql.Swaption(itmSwap, exercise)
>>>>
>>>> data = []
>>>>
>>>> # +
>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>>
>>>> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>
>>>> # +
>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>>
>>>> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>
>>>> # +
>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>>
>>>> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>
>>>> # +
>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>>
>>>> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>> # -
>>>>
>>>> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>>>>
>>>> # ### GSR live setValue bump test
>>>>
>>>> import faulthandler
>>>> faulthandler.enable(all_threads=True)
>>>>
>>>> print("\n--- GSR live setValue bump test ---")
>>>>
>>>> # Minimal European swaption test on the same underlying ATM swap
>>>> euroExercise = ql.EuropeanExercise(swapStart)
>>>> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>>>>
>>>> # For a European GSR setup: no step dates, one sigma, one reversion
>>>> stepDates = []
>>>> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>>> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>>>
>>>> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
>>>> gsrEngine = ql.Gaussian1dSwaptionEngine(
>>>> gsr,
>>>> 64, # integration points
>>>> 7.0, # std devs
>>>> True,
>>>> False,
>>>> termStructure
>>>> )
>>>> euroSwaption.setPricingEngine(gsrEngine)
>>>>
>>>> base_rate = 0.04875825
>>>>
>>>> print("base rate:", base_rate)
>>>> print("base npv :", euroSwaption.NPV())
>>>>
>>>> # Single bump up/down
>>>> for bump in [1e-4, -1e-4, 0.0]:
>>>> bumped = base_rate + bump
>>>> print(f"\nsetValue -> {bumped:.8f}")
>>>> rateQuote.setValue(bumped)
>>>> print("npv =", euroSwaption.NPV())
>>>>
>>>> # Stress loop: repeatedly bump the observed quote and reprice
>>>> print("\nstarting stress loop...")
>>>> for i in range(200):
>>>> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
>>>> rateQuote.setValue(bumped)
>>>> npv = euroSwaption.NPV()
>>>> if i % 20 == 0:
>>>> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>>>>
>>>> # Restore
>>>> rateQuote.setValue(base_rate)
>>>> print("\nrestored rate:", base_rate)
>>>> print("restored npv :", euroSwaption.NPV())
>>>>
>>>>
>>>> Log:
>>>>
>>>> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
>>>> Model: G2 (analytic formulae)
>>>> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
>>>> maturity length volatility implied error
>>>> 0 1Y 5Y 0.1148 0.101974 -0.012826
>>>> 1 2Y 4Y 0.1108 0.105611 -0.005189
>>>> 2 3Y 3Y 0.1070 0.106950 -0.000050
>>>> 3 4Y 2Y 0.1021 0.107873 0.005773
>>>> 4 5Y 1Y 0.1000 0.108556 0.008556
>>>> Average error: 0.0065
>>>> Model: Hull-White (analytic formulae)
>>>> Parameters: [ 0.046379; 0.00586848 ]
>>>> maturity length volatility implied error
>>>> 0 1Y 5Y 0.1148 0.106223 -0.008577
>>>> 1 2Y 4Y 0.1108 0.106292 -0.004508
>>>> 2 3Y 3Y 0.1070 0.106338 -0.000662
>>>> 3 4Y 2Y 0.1021 0.106439 0.004339
>>>> 4 5Y 1Y 0.1000 0.106609 0.006609
>>>> Average error: 0.0049
>>>> Model: Hull-White (numerical calibration)
>>>> Parameters: [ 0.0559314; 0.00609858 ]
>>>> maturity length volatility implied error
>>>> 0 1Y 5Y 0.1148 0.102941 -0.011859
>>>> 1 2Y 4Y 0.1108 0.105452 -0.005348
>>>> 2 3Y 3Y 0.1070 0.106560 -0.000440
>>>> 3 4Y 2Y 0.1021 0.107365 0.005265
>>>> 4 5Y 1Y 0.1000 0.108223 0.008223
>>>> Average error: 0.0062
>>>> Model: Black-Karasinski (numerical calibration)
>>>> Parameters: [ 0.0442393; 0.120656 ]
>>>> maturity length volatility implied error
>>>> 0 1Y 5Y 0.1148 0.103094 -0.011706
>>>> 1 2Y 4Y 0.1108 0.105637 -0.005163
>>>> 2 3Y 3Y 0.1070 0.106656 -0.000344
>>>> 3 4Y 2Y 0.1021 0.107333 0.005233
>>>> 4 5Y 1Y 0.1000 0.108028 0.008028
>>>> Average error: 0.0061
>>>> model in-the-money at-the-money out-of-the-money
>>>> 0 G2 analytic 42.919620 14.581452 3.443306
>>>> 1 HW analytic 42.245449 12.924016 2.512541
>>>> 2 HW numerical 42.340450 13.141040 2.614228
>>>> 3 BK numerical 41.805673 13.012682 3.271628
>>>>
>>>> --- GSR live setValue bump test ---
>>>> base rate: 0.04875825
>>>> base npv : 16.787915348295005
>>>>
>>>> setValue -> 0.04885825
>>>> Fatal Python error: Segmentation fault
>>>>
>>>> Current thread 0x00000001f0afd8c0 (most recent call first):
>>>> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
>>>> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>>>>
>>>> Current thread's C stack trace (most recent call first):
>>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
>>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
>>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
>>>> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>> <truncated rest of calls>
>>>>
>>>> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
>>>> Segmentation fault: 11
>>>>
>>>>
>>>> _______________________________________________
>>>> 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
>>>
>>
>
|
|
From: Aleksis A. R. <ale...@go...> - 2026-04-16 09:32:36
|
yes, the results tie with v1.40 after the code fix in 1.42.
here's a comparison run for the test script i sent earlier.
--- GSR live setValue bump test v1.42---
base rate: 0.04875825
base npv : 16.787915348295005
setValue -> 0.04885825
npv = 17.005154111913548
setValue -> 0.04865825
npv = 16.57057870270632
setValue -> 0.04875825
npv = 16.787915348295005
starting stress loop...
iter 000 rate=0.04885825 npv=17.005154111913548
iter 020 rate=0.04885825 npv=17.005154111913548
iter 040 rate=0.04885825 npv=17.005154111913548
iter 060 rate=0.04885825 npv=17.005154111913548
iter 080 rate=0.04885825 npv=17.005154111913548
iter 100 rate=0.04885825 npv=17.005154111913548
iter 120 rate=0.04885825 npv=17.005154111913548
iter 140 rate=0.04885825 npv=17.005154111913548
iter 160 rate=0.04885825 npv=17.005154111913548
iter 180 rate=0.04885825 npv=17.005154111913548
restored rate: 0.04875825
restored npv : 16.787915348295005
--- GSR live setValue bump test v1.40 ---
base rate: 0.04875825
base npv : 16.787915348295005
setValue -> 0.04885825
npv = 17.005154111913548
setValue -> 0.04865825
npv = 16.57057870270632
setValue -> 0.04875825
npv = 16.787915348295005
starting stress loop...
iter 000 rate=0.04885825 npv=17.005154111913548
iter 020 rate=0.04885825 npv=17.005154111913548
iter 040 rate=0.04885825 npv=17.005154111913548
iter 060 rate=0.04885825 npv=17.005154111913548
iter 080 rate=0.04885825 npv=17.005154111913548
iter 100 rate=0.04885825 npv=17.005154111913548
iter 120 rate=0.04885825 npv=17.005154111913548
iter 140 rate=0.04885825 npv=17.005154111913548
iter 160 rate=0.04885825 npv=17.005154111913548
iter 180 rate=0.04885825 npv=17.005154111913548
restored rate: 0.04875825
restored npv : 16.787915348295005
> On Apr 16, 2026, at 12:38, Luigi Ballabio <lui...@gm...> wrote:
>
> May you check that it also reprices correctly after the bump? That is, that you get the same numerical results as 1.40?
>
> On Thu, Apr 16, 2026 at 9:04 AM Luigi Ballabio <lui...@gm... <mailto:lui...@gm...>> wrote:
>> Thanks for the heads-up. Looks like I need to release a 1.42.1...
>>
>> Luigi
>>
>>
>> On Thu, Apr 16, 2026 at 8:57 AM Aleksis Ali Raza via QuantLib-users <qua...@li... <mailto:qua...@li...>> wrote:
>>> Yep, ditching registerWith(stateProcess_); works fine as well and is the cleaner fix.
>>>
>>> thanks.
>>>
>>>> On Apr 16, 2026, at 11:34, Peter Caspers <pca...@gm... <mailto:pca...@gm...>> wrote:
>>>>
>>>> Thanks. Since Gsr manages its stateProcess_, it does not need to and should not register with it as an Observer? I will take a closer look, but if you could test this change on your end, that would be valuable input.
>>>> Best, Peter
>>>>
>>>>
>>>> Aleksis Ali Raza via QuantLib-users <qua...@li... <mailto:qua...@li...>> schrieb am Do. 16. Apr. 2026 um 08:04:
>>>>> Just to follow up on this, it's this line:
>>>>>
>>>>> void Gsr::update() {
>>>>> if (stateProcess_ != nullptr) {
>>>>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
>>>>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();
>>>>> }
>>>>> LazyObject::update();
>>>>> }
>>>>>
>>>>> in the gsr class that seems to be the cause. in my case, commenting out that line out and rebuilding from source fixes the problem of my gsr-based swaption risk runs.
>>>>>
>>>>> That line by itself looks pretty harmless but i think
>>>>> registerWith(stateProcess_);
>>>>>
>>>>> further down leads into some sort of feedback loop (setValue() → notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() → Gsr::update() → …) and ultimately a seg fault.
>>>>>
>>>>>
>>>>>> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <ale...@go... <mailto:ale...@go...>> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I’m encountering what appears to be a regression or stability issue in QuantLib 1.42 related to the GSR (Gaussian short rate) model and the observer framework.
>>>>>>
>>>>>> Calling SimpleQuote.setValue() on a quote that is observed by a term structure used in a Gsr model causes a segmentation fault.
>>>>>>
>>>>>> This occurs even in a minimal standalone script (no threading, no external frameworks).
>>>>>>
>>>>>> Minimal reproduction
>>>>>>
>>>>>> The following sequence is sufficient:
>>>>>> 1. Create a SimpleQuote
>>>>>> 2. Build a FlatForward curve using that quote
>>>>>> 3. Construct a Gsr model from that term structure
>>>>>> 4. Attach a Gaussian1dSwaptionEngine
>>>>>> 5. Call setValue() on the original SimpleQuote
>>>>>>
>>>>>> This results in a segmentation fault.
>>>>>>
>>>>>> I have modified the Python/examples/bermudan_swaption.py file and attached it below to illustrate (along with error log below it).
>>>>>>
>>>>>> Has something been changed in how one shud enquire / update quote objects that I missed? I am coming from 1.40, where this was not an issue. I am running python 3.14.4 on macOS 26.1.4 and using a source build of Quantlib/SWIG.
>>>>>>
>>>>>> Thanks, Aleksis
>>>>>>
>>>>>> # ---
>>>>>> # jupyter:
>>>>>> # jupytext:
>>>>>> # formats: py:light
>>>>>> # text_representation:
>>>>>> # extension: .py
>>>>>> # format_name: light
>>>>>> # format_version: '1.5'
>>>>>> # jupytext_version: 1.4.2
>>>>>> # kernelspec:
>>>>>> # display_name: Python 3
>>>>>> # language: python
>>>>>> # name: python3
>>>>>> # ---
>>>>>>
>>>>>> # # Bermudan swaptions
>>>>>> #
>>>>>> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
>>>>>> #
>>>>>> # This file is part of QuantLib, a free-software/open-source library
>>>>>> # for financial quantitative analysts and developers - https://www.quantlib.org/
>>>>>> #
>>>>>> # QuantLib is free software: you can redistribute it and/or modify it under the
>>>>>> # terms of the QuantLib license. You should have received a copy of the
>>>>>> # license along with this program; if not, please email
>>>>>> # <qua...@li... <mailto:qua...@li...>>. The license is also available online at
>>>>>> # <https://www.quantlib.org/license.shtml>.
>>>>>> #
>>>>>> # This program is distributed in the hope that it will be useful, but WITHOUT
>>>>>> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
>>>>>> # FOR A PARTICULAR PURPOSE. See the license for more details.
>>>>>>
>>>>>> import QuantLib as ql
>>>>>> import pandas as pd
>>>>>>
>>>>>> # ### Setup
>>>>>>
>>>>>> todaysDate = ql.Date(15, ql.February, 2002)
>>>>>> ql.Settings.instance().evaluationDate = todaysDate
>>>>>> calendar = ql.TARGET()
>>>>>> settlementDate = ql.Date(19, ql.February, 2002)
>>>>>>
>>>>>>
>>>>>> def calibrate(model, helpers, l, name):
>>>>>> print("Model: %s" % name)
>>>>>>
>>>>>> method = ql.Simplex(l)
>>>>>> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>>>>>>
>>>>>> print("Parameters: %s" % model.params())
>>>>>>
>>>>>> totalError = 0.0
>>>>>> data = []
>>>>>> for swaption, helper in zip(swaptionVols, helpers):
>>>>>> maturity, length, vol = swaption
>>>>>> NPV = helper.modelValue()
>>>>>> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
>>>>>> error = implied - vol
>>>>>> totalError += abs(error)
>>>>>> data.append((maturity, length, vol, implied, error))
>>>>>> averageError = totalError / len(helpers)
>>>>>>
>>>>>> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>>>>>>
>>>>>> print("Average error: %.4f" % averageError)
>>>>>>
>>>>>>
>>>>>> # ### Market data
>>>>>>
>>>>>> swaptionVols = [
>>>>>> # maturity, length, volatility
>>>>>> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
>>>>>> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
>>>>>> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
>>>>>> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
>>>>>> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
>>>>>> ]
>>>>>>
>>>>>> # This is a flat yield term structure implying a 1x5 swap at 5%.
>>>>>>
>>>>>> rateQuote = ql.SimpleQuote(0.04875825)
>>>>>> rate = ql.QuoteHandle(rateQuote)
>>>>>> termStructure = ql.YieldTermStructureHandle(
>>>>>> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
>>>>>> )
>>>>>>
>>>>>> # Define the ATM/OTM/ITM swaps:
>>>>>>
>>>>>> swapEngine = ql.DiscountingSwapEngine(termStructure)
>>>>>>
>>>>>> fixedLegFrequency = ql.Annual
>>>>>> fixedLegTenor = ql.Period(1, ql.Years)
>>>>>> fixedLegConvention = ql.Unadjusted
>>>>>> floatingLegConvention = ql.ModifiedFollowing
>>>>>> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
>>>>>> floatingLegFrequency = ql.Semiannual
>>>>>> floatingLegTenor = ql.Period(6, ql.Months)
>>>>>>
>>>>>> payFixed = ql.Swap.Payer
>>>>>> fixingDays = 2
>>>>>> index = ql.Euribor6M(termStructure)
>>>>>> floatingLegDayCounter = index.dayCounter()
>>>>>>
>>>>>> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
>>>>>> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>>>>>>
>>>>>> fixedSchedule = ql.Schedule(
>>>>>> swapStart,
>>>>>> swapEnd,
>>>>>> fixedLegTenor,
>>>>>> calendar,
>>>>>> fixedLegConvention,
>>>>>> fixedLegConvention,
>>>>>> ql.DateGeneration.Forward,
>>>>>> False,
>>>>>> )
>>>>>> floatingSchedule = ql.Schedule(
>>>>>> swapStart,
>>>>>> swapEnd,
>>>>>> floatingLegTenor,
>>>>>> calendar,
>>>>>> floatingLegConvention,
>>>>>> floatingLegConvention,
>>>>>> ql.DateGeneration.Forward,
>>>>>> False,
>>>>>> )
>>>>>>
>>>>>> dummy = ql.VanillaSwap(
>>>>>> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
>>>>>> )
>>>>>> dummy.setPricingEngine(swapEngine)
>>>>>> atmRate = dummy.fairRate()
>>>>>>
>>>>>> atmSwap = ql.VanillaSwap(
>>>>>> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
>>>>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>>>>> )
>>>>>>
>>>>>> otmSwap = ql.VanillaSwap(
>>>>>> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
>>>>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>>>>> )
>>>>>>
>>>>>> itmSwap = ql.VanillaSwap(
>>>>>> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
>>>>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>>>>> )
>>>>>>
>>>>>> atmSwap.setPricingEngine(swapEngine)
>>>>>> otmSwap.setPricingEngine(swapEngine)
>>>>>> itmSwap.setPricingEngine(swapEngine)
>>>>>>
>>>>>> helpers = [
>>>>>> ql.SwaptionHelper(
>>>>>> maturity,
>>>>>> length,
>>>>>> ql.makeQuoteHandle(vol),
>>>>>> index,
>>>>>> index.tenor(),
>>>>>> index.dayCounter(),
>>>>>> index.dayCounter(),
>>>>>> termStructure,
>>>>>> )
>>>>>> for maturity, length, vol in swaptionVols
>>>>>> ]
>>>>>>
>>>>>> times = {}
>>>>>> for h in helpers:
>>>>>> for t in h.times():
>>>>>> times[t] = 1
>>>>>> times = sorted(times.keys())
>>>>>>
>>>>>> grid = ql.TimeGrid(times, 30)
>>>>>>
>>>>>> G2model = ql.G2(termStructure)
>>>>>> HWmodel = ql.HullWhite(termStructure)
>>>>>> HWmodel2 = ql.HullWhite(termStructure)
>>>>>> BKmodel = ql.BlackKarasinski(termStructure)
>>>>>>
>>>>>> # ### Calibrations
>>>>>>
>>>>>> for h in helpers:
>>>>>> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
>>>>>> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>>>>>>
>>>>>> for h in helpers:
>>>>>> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
>>>>>> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>>>>>>
>>>>>> for h in helpers:
>>>>>> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
>>>>>> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>>>>>>
>>>>>> for h in helpers:
>>>>>> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
>>>>>> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>>>>>>
>>>>>>
>>>>>> # ### Price Bermudan swaptions on defined swaps
>>>>>>
>>>>>> bermudanDates = [d for d in fixedSchedule][:-1]
>>>>>> exercise = ql.BermudanExercise(bermudanDates)
>>>>>>
>>>>>> atmSwaption = ql.Swaption(atmSwap, exercise)
>>>>>> otmSwaption = ql.Swaption(otmSwap, exercise)
>>>>>> itmSwaption = ql.Swaption(itmSwap, exercise)
>>>>>>
>>>>>> data = []
>>>>>>
>>>>>> # +
>>>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>>>>
>>>>>> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>>>
>>>>>> # +
>>>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>>>>
>>>>>> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>>>
>>>>>> # +
>>>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>>>>
>>>>>> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>>>
>>>>>> # +
>>>>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>>>>
>>>>>> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>>>> # -
>>>>>>
>>>>>> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>>>>>>
>>>>>> # ### GSR live setValue bump test
>>>>>>
>>>>>> import faulthandler
>>>>>> faulthandler.enable(all_threads=True)
>>>>>>
>>>>>> print("\n--- GSR live setValue bump test ---")
>>>>>>
>>>>>> # Minimal European swaption test on the same underlying ATM swap
>>>>>> euroExercise = ql.EuropeanExercise(swapStart)
>>>>>> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>>>>>>
>>>>>> # For a European GSR setup: no step dates, one sigma, one reversion
>>>>>> stepDates = []
>>>>>> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>>>>> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>>>>>
>>>>>> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
>>>>>> gsrEngine = ql.Gaussian1dSwaptionEngine(
>>>>>> gsr,
>>>>>> 64, # integration points
>>>>>> 7.0, # std devs
>>>>>> True,
>>>>>> False,
>>>>>> termStructure
>>>>>> )
>>>>>> euroSwaption.setPricingEngine(gsrEngine)
>>>>>>
>>>>>> base_rate = 0.04875825
>>>>>>
>>>>>> print("base rate:", base_rate)
>>>>>> print("base npv :", euroSwaption.NPV())
>>>>>>
>>>>>> # Single bump up/down
>>>>>> for bump in [1e-4, -1e-4, 0.0]:
>>>>>> bumped = base_rate + bump
>>>>>> print(f"\nsetValue -> {bumped:.8f}")
>>>>>> rateQuote.setValue(bumped)
>>>>>> print("npv =", euroSwaption.NPV())
>>>>>>
>>>>>> # Stress loop: repeatedly bump the observed quote and reprice
>>>>>> print("\nstarting stress loop...")
>>>>>> for i in range(200):
>>>>>> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
>>>>>> rateQuote.setValue(bumped)
>>>>>> npv = euroSwaption.NPV()
>>>>>> if i % 20 == 0:
>>>>>> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>>>>>>
>>>>>> # Restore
>>>>>> rateQuote.setValue(base_rate)
>>>>>> print("\nrestored rate:", base_rate)
>>>>>> print("restored npv :", euroSwaption.NPV())
>>>>>>
>>>>>> Log:
>>>>>> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
>>>>>> Model: G2 (analytic formulae)
>>>>>> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
>>>>>> maturity length volatility implied error
>>>>>> 0 1Y 5Y 0.1148 0.101974 -0.012826
>>>>>> 1 2Y 4Y 0.1108 0.105611 -0.005189
>>>>>> 2 3Y 3Y 0.1070 0.106950 -0.000050
>>>>>> 3 4Y 2Y 0.1021 0.107873 0.005773
>>>>>> 4 5Y 1Y 0.1000 0.108556 0.008556
>>>>>> Average error: 0.0065
>>>>>> Model: Hull-White (analytic formulae)
>>>>>> Parameters: [ 0.046379; 0.00586848 ]
>>>>>> maturity length volatility implied error
>>>>>> 0 1Y 5Y 0.1148 0.106223 -0.008577
>>>>>> 1 2Y 4Y 0.1108 0.106292 -0.004508
>>>>>> 2 3Y 3Y 0.1070 0.106338 -0.000662
>>>>>> 3 4Y 2Y 0.1021 0.106439 0.004339
>>>>>> 4 5Y 1Y 0.1000 0.106609 0.006609
>>>>>> Average error: 0.0049
>>>>>> Model: Hull-White (numerical calibration)
>>>>>> Parameters: [ 0.0559314; 0.00609858 ]
>>>>>> maturity length volatility implied error
>>>>>> 0 1Y 5Y 0.1148 0.102941 -0.011859
>>>>>> 1 2Y 4Y 0.1108 0.105452 -0.005348
>>>>>> 2 3Y 3Y 0.1070 0.106560 -0.000440
>>>>>> 3 4Y 2Y 0.1021 0.107365 0.005265
>>>>>> 4 5Y 1Y 0.1000 0.108223 0.008223
>>>>>> Average error: 0.0062
>>>>>> Model: Black-Karasinski (numerical calibration)
>>>>>> Parameters: [ 0.0442393; 0.120656 ]
>>>>>> maturity length volatility implied error
>>>>>> 0 1Y 5Y 0.1148 0.103094 -0.011706
>>>>>> 1 2Y 4Y 0.1108 0.105637 -0.005163
>>>>>> 2 3Y 3Y 0.1070 0.106656 -0.000344
>>>>>> 3 4Y 2Y 0.1021 0.107333 0.005233
>>>>>> 4 5Y 1Y 0.1000 0.108028 0.008028
>>>>>> Average error: 0.0061
>>>>>> model in-the-money at-the-money out-of-the-money
>>>>>> 0 G2 analytic 42.919620 14.581452 3.443306
>>>>>> 1 HW analytic 42.245449 12.924016 2.512541
>>>>>> 2 HW numerical 42.340450 13.141040 2.614228
>>>>>> 3 BK numerical 41.805673 13.012682 3.271628
>>>>>>
>>>>>> --- GSR live setValue bump test ---
>>>>>> base rate: 0.04875825
>>>>>> base npv : 16.787915348295005
>>>>>>
>>>>>> setValue -> 0.04885825
>>>>>> Fatal Python error: Segmentation fault
>>>>>>
>>>>>> Current thread 0x00000001f0afd8c0 (most recent call first):
>>>>>> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
>>>>>> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>>>>>>
>>>>>> Current thread's C stack trace (most recent call first):
>>>>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
>>>>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
>>>>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
>>>>>> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>>>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>>>>> <truncated rest of calls>
>>>>>>
>>>>>> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
>>>>>> Segmentation fault: 11
>>>>>
>>>>> _______________________________________________
>>>>> QuantLib-users mailing list
>>>>> Qua...@li... <mailto:Qua...@li...>
>>>>> https://lists.sourceforge.net/lists/listinfo/quantlib-users
>>>
>>> _______________________________________________
>>> QuantLib-users mailing list
>>> Qua...@li... <mailto:Qua...@li...>
>>> https://lists.sourceforge.net/lists/listinfo/quantlib-users
|
|
From: Luigi B. <lui...@gm...> - 2026-04-16 07:39:24
|
May you check that it also reprices correctly after the bump? That is, that
you get the same numerical results as 1.40?
On Thu, Apr 16, 2026 at 9:04 AM Luigi Ballabio <lui...@gm...>
wrote:
> Thanks for the heads-up. Looks like I need to release a 1.42.1...
>
> Luigi
>
>
> On Thu, Apr 16, 2026 at 8:57 AM Aleksis Ali Raza via QuantLib-users <
> qua...@li...> wrote:
>
>> Yep, ditching registerWith(stateProcess_); works fine as well and is the
>> cleaner fix.
>>
>> thanks.
>>
>> On Apr 16, 2026, at 11:34, Peter Caspers <pca...@gm...> wrote:
>>
>> Thanks. Since Gsr manages its stateProcess_, it does not need to and
>> should not register with it as an Observer? I will take a closer look, but
>> if you could test this change on your end, that would be valuable input.
>> Best, Peter
>>
>>
>> Aleksis Ali Raza via QuantLib-users <qua...@li...>
>> schrieb am Do. 16. Apr. 2026 um 08:04:
>>
>>> Just to follow up on this, it's this line:
>>>
>>> void Gsr::update() {
>>> if (stateProcess_ != nullptr) {
>>>
>>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
>>>
>>> *ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();*
>>> }
>>> LazyObject::update();
>>> }
>>>
>>> in the gsr class that seems to be the cause. in my case, commenting out
>>> that line out and rebuilding from source fixes the problem of my gsr-based
>>> swaption risk runs.
>>>
>>> That line by itself looks pretty harmless but i think
>>>
>>> registerWith(stateProcess_);
>>>
>>> further down leads into some sort of feedback loop (setValue() →
>>> notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() →
>>> Gsr::update() → …) and ultimately a seg fault.
>>>
>>> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <ale...@go...>
>>> wrote:
>>>
>>> Hi,
>>>
>>> I’m encountering what appears to be a regression or stability issue in
>>> QuantLib 1.42 related to the GSR (Gaussian short rate) model and the
>>> observer framework.
>>>
>>> Calling SimpleQuote.setValue() on a quote that is observed by a term
>>> structure used in a Gsr model causes a segmentation fault.
>>>
>>> This occurs even in a minimal standalone script (no threading, no
>>> external frameworks).
>>>
>>> Minimal reproduction
>>>
>>> The following sequence is sufficient:
>>> 1. Create a SimpleQuote
>>> 2. Build a FlatForward curve using that quote
>>> 3. Construct a Gsr model from that term structure
>>> 4. Attach a Gaussian1dSwaptionEngine
>>> 5. Call setValue() on the original SimpleQuote
>>>
>>> This results in a segmentation fault.
>>>
>>> I have modified the Python/examples/bermudan_swaption.py file and
>>> attached it below to illustrate (along with error log below it).
>>>
>>> Has something been changed in how one shud enquire / update quote
>>> objects that I missed? I am coming from 1.40, where this was not an issue.
>>> I am running python 3.14.4 on macOS 26.1.4 and using a source build of
>>> Quantlib/SWIG.
>>>
>>> Thanks, Aleksis
>>>
>>> # ---
>>> # jupyter:
>>> # jupytext:
>>> # formats: py:light
>>> # text_representation:
>>> # extension: .py
>>> # format_name: light
>>> # format_version: '1.5'
>>> # jupytext_version: 1.4.2
>>> # kernelspec:
>>> # display_name: Python 3
>>> # language: python
>>> # name: python3
>>> # ---
>>>
>>> # # Bermudan swaptions
>>> #
>>> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
>>> #
>>> # This file is part of QuantLib, a free-software/open-source library
>>> # for financial quantitative analysts and developers - https://www.quantlib.org/
>>> #
>>> # QuantLib is free software: you can redistribute it and/or modify it under the
>>> # terms of the QuantLib license. You should have received a copy of the
>>> # license along with this program; if not, please email
>>> # <qua...@li...>. The license is also available online at
>>> # <https://www.quantlib.org/license.shtml>.
>>> #
>>> # This program is distributed in the hope that it will be useful, but WITHOUT
>>> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
>>> # FOR A PARTICULAR PURPOSE. See the license for more details.
>>>
>>> import QuantLib as ql
>>> import pandas as pd
>>>
>>> # ### Setup
>>>
>>> todaysDate = ql.Date(15, ql.February, 2002)
>>> ql.Settings.instance().evaluationDate = todaysDate
>>> calendar = ql.TARGET()
>>> settlementDate = ql.Date(19, ql.February, 2002)
>>>
>>>
>>> def calibrate(model, helpers, l, name):
>>> print("Model: %s" % name)
>>>
>>> method = ql.Simplex(l)
>>> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>>>
>>> print("Parameters: %s" % model.params())
>>>
>>> totalError = 0.0
>>> data = []
>>> for swaption, helper in zip(swaptionVols, helpers):
>>> maturity, length, vol = swaption
>>> NPV = helper.modelValue()
>>> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
>>> error = implied - vol
>>> totalError += abs(error)
>>> data.append((maturity, length, vol, implied, error))
>>> averageError = totalError / len(helpers)
>>>
>>> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>>>
>>> print("Average error: %.4f" % averageError)
>>>
>>>
>>> # ### Market data
>>>
>>> swaptionVols = [
>>> # maturity, length, volatility
>>> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
>>> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
>>> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
>>> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
>>> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
>>> ]
>>>
>>> # This is a flat yield term structure implying a 1x5 swap at 5%.
>>>
>>> rateQuote = ql.SimpleQuote(0.04875825)
>>> rate = ql.QuoteHandle(rateQuote)
>>> termStructure = ql.YieldTermStructureHandle(
>>> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
>>> )
>>>
>>> # Define the ATM/OTM/ITM swaps:
>>>
>>> swapEngine = ql.DiscountingSwapEngine(termStructure)
>>>
>>> fixedLegFrequency = ql.Annual
>>> fixedLegTenor = ql.Period(1, ql.Years)
>>> fixedLegConvention = ql.Unadjusted
>>> floatingLegConvention = ql.ModifiedFollowing
>>> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
>>> floatingLegFrequency = ql.Semiannual
>>> floatingLegTenor = ql.Period(6, ql.Months)
>>>
>>> payFixed = ql.Swap.Payer
>>> fixingDays = 2
>>> index = ql.Euribor6M(termStructure)
>>> floatingLegDayCounter = index.dayCounter()
>>>
>>> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
>>> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>>>
>>> fixedSchedule = ql.Schedule(
>>> swapStart,
>>> swapEnd,
>>> fixedLegTenor,
>>> calendar,
>>> fixedLegConvention,
>>> fixedLegConvention,
>>> ql.DateGeneration.Forward,
>>> False,
>>> )
>>> floatingSchedule = ql.Schedule(
>>> swapStart,
>>> swapEnd,
>>> floatingLegTenor,
>>> calendar,
>>> floatingLegConvention,
>>> floatingLegConvention,
>>> ql.DateGeneration.Forward,
>>> False,
>>> )
>>>
>>> dummy = ql.VanillaSwap(
>>> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>> dummy.setPricingEngine(swapEngine)
>>> atmRate = dummy.fairRate()
>>>
>>> atmSwap = ql.VanillaSwap(
>>> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>>
>>> otmSwap = ql.VanillaSwap(
>>> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>>
>>> itmSwap = ql.VanillaSwap(
>>> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>>
>>> atmSwap.setPricingEngine(swapEngine)
>>> otmSwap.setPricingEngine(swapEngine)
>>> itmSwap.setPricingEngine(swapEngine)
>>>
>>> helpers = [
>>> ql.SwaptionHelper(
>>> maturity,
>>> length,
>>> ql.makeQuoteHandle(vol),
>>> index,
>>> index.tenor(),
>>> index.dayCounter(),
>>> index.dayCounter(),
>>> termStructure,
>>> )
>>> for maturity, length, vol in swaptionVols
>>> ]
>>>
>>> times = {}
>>> for h in helpers:
>>> for t in h.times():
>>> times[t] = 1
>>> times = sorted(times.keys())
>>>
>>> grid = ql.TimeGrid(times, 30)
>>>
>>> G2model = ql.G2(termStructure)
>>> HWmodel = ql.HullWhite(termStructure)
>>> HWmodel2 = ql.HullWhite(termStructure)
>>> BKmodel = ql.BlackKarasinski(termStructure)
>>>
>>> # ### Calibrations
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
>>> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
>>> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
>>> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
>>> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>>>
>>>
>>> # ### Price Bermudan swaptions on defined swaps
>>>
>>> bermudanDates = [d for d in fixedSchedule][:-1]
>>> exercise = ql.BermudanExercise(bermudanDates)
>>>
>>> atmSwaption = ql.Swaption(atmSwap, exercise)
>>> otmSwaption = ql.Swaption(otmSwap, exercise)
>>> itmSwaption = ql.Swaption(itmSwap, exercise)
>>>
>>> data = []
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>
>>> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>
>>> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>
>>> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>
>>> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>> # -
>>>
>>> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>>>
>>> # ### GSR live setValue bump test
>>>
>>> import faulthandler
>>> faulthandler.enable(all_threads=True)
>>>
>>> print("\n--- GSR live setValue bump test ---")
>>>
>>> # Minimal European swaption test on the same underlying ATM swap
>>> euroExercise = ql.EuropeanExercise(swapStart)
>>> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>>>
>>> # For a European GSR setup: no step dates, one sigma, one reversion
>>> stepDates = []
>>> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>>
>>> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
>>> gsrEngine = ql.Gaussian1dSwaptionEngine(
>>> gsr,
>>> 64, # integration points
>>> 7.0, # std devs
>>> True,
>>> False,
>>> termStructure
>>> )
>>> euroSwaption.setPricingEngine(gsrEngine)
>>>
>>> base_rate = 0.04875825
>>>
>>> print("base rate:", base_rate)
>>> print("base npv :", euroSwaption.NPV())
>>>
>>> # Single bump up/down
>>> for bump in [1e-4, -1e-4, 0.0]:
>>> bumped = base_rate + bump
>>> print(f"\nsetValue -> {bumped:.8f}")
>>> rateQuote.setValue(bumped)
>>> print("npv =", euroSwaption.NPV())
>>>
>>> # Stress loop: repeatedly bump the observed quote and reprice
>>> print("\nstarting stress loop...")
>>> for i in range(200):
>>> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
>>> rateQuote.setValue(bumped)
>>> npv = euroSwaption.NPV()
>>> if i % 20 == 0:
>>> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>>>
>>> # Restore
>>> rateQuote.setValue(base_rate)
>>> print("\nrestored rate:", base_rate)
>>> print("restored npv :", euroSwaption.NPV())
>>>
>>>
>>> Log:
>>>
>>> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
>>> Model: G2 (analytic formulae)
>>> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.101974 -0.012826
>>> 1 2Y 4Y 0.1108 0.105611 -0.005189
>>> 2 3Y 3Y 0.1070 0.106950 -0.000050
>>> 3 4Y 2Y 0.1021 0.107873 0.005773
>>> 4 5Y 1Y 0.1000 0.108556 0.008556
>>> Average error: 0.0065
>>> Model: Hull-White (analytic formulae)
>>> Parameters: [ 0.046379; 0.00586848 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.106223 -0.008577
>>> 1 2Y 4Y 0.1108 0.106292 -0.004508
>>> 2 3Y 3Y 0.1070 0.106338 -0.000662
>>> 3 4Y 2Y 0.1021 0.106439 0.004339
>>> 4 5Y 1Y 0.1000 0.106609 0.006609
>>> Average error: 0.0049
>>> Model: Hull-White (numerical calibration)
>>> Parameters: [ 0.0559314; 0.00609858 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.102941 -0.011859
>>> 1 2Y 4Y 0.1108 0.105452 -0.005348
>>> 2 3Y 3Y 0.1070 0.106560 -0.000440
>>> 3 4Y 2Y 0.1021 0.107365 0.005265
>>> 4 5Y 1Y 0.1000 0.108223 0.008223
>>> Average error: 0.0062
>>> Model: Black-Karasinski (numerical calibration)
>>> Parameters: [ 0.0442393; 0.120656 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.103094 -0.011706
>>> 1 2Y 4Y 0.1108 0.105637 -0.005163
>>> 2 3Y 3Y 0.1070 0.106656 -0.000344
>>> 3 4Y 2Y 0.1021 0.107333 0.005233
>>> 4 5Y 1Y 0.1000 0.108028 0.008028
>>> Average error: 0.0061
>>> model in-the-money at-the-money out-of-the-money
>>> 0 G2 analytic 42.919620 14.581452 3.443306
>>> 1 HW analytic 42.245449 12.924016 2.512541
>>> 2 HW numerical 42.340450 13.141040 2.614228
>>> 3 BK numerical 41.805673 13.012682 3.271628
>>>
>>> --- GSR live setValue bump test ---
>>> base rate: 0.04875825
>>> base npv : 16.787915348295005
>>>
>>> setValue -> 0.04885825
>>> Fatal Python error: Segmentation fault
>>>
>>> Current thread 0x00000001f0afd8c0 (most recent call first):
>>> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
>>> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>>>
>>> Current thread's C stack trace (most recent call first):
>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
>>> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> <truncated rest of calls>
>>>
>>> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
>>> Segmentation fault: 11
>>>
>>>
>>> _______________________________________________
>>> 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
>>
>
|
|
From: Luigi B. <lui...@gm...> - 2026-04-16 07:04:48
|
Thanks for the heads-up. Looks like I need to release a 1.42.1...
Luigi
On Thu, Apr 16, 2026 at 8:57 AM Aleksis Ali Raza via QuantLib-users <
qua...@li...> wrote:
> Yep, ditching registerWith(stateProcess_); works fine as well and is the
> cleaner fix.
>
> thanks.
>
> On Apr 16, 2026, at 11:34, Peter Caspers <pca...@gm...> wrote:
>
> Thanks. Since Gsr manages its stateProcess_, it does not need to and
> should not register with it as an Observer? I will take a closer look, but
> if you could test this change on your end, that would be valuable input.
> Best, Peter
>
>
> Aleksis Ali Raza via QuantLib-users <qua...@li...>
> schrieb am Do. 16. Apr. 2026 um 08:04:
>
>> Just to follow up on this, it's this line:
>>
>> void Gsr::update() {
>> if (stateProcess_ != nullptr) {
>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
>>
>> *ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();*
>> }
>> LazyObject::update();
>> }
>>
>> in the gsr class that seems to be the cause. in my case, commenting out
>> that line out and rebuilding from source fixes the problem of my gsr-based
>> swaption risk runs.
>>
>> That line by itself looks pretty harmless but i think
>>
>> registerWith(stateProcess_);
>>
>> further down leads into some sort of feedback loop (setValue() →
>> notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() →
>> Gsr::update() → …) and ultimately a seg fault.
>>
>> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <ale...@go...>
>> wrote:
>>
>> Hi,
>>
>> I’m encountering what appears to be a regression or stability issue in
>> QuantLib 1.42 related to the GSR (Gaussian short rate) model and the
>> observer framework.
>>
>> Calling SimpleQuote.setValue() on a quote that is observed by a term
>> structure used in a Gsr model causes a segmentation fault.
>>
>> This occurs even in a minimal standalone script (no threading, no
>> external frameworks).
>>
>> Minimal reproduction
>>
>> The following sequence is sufficient:
>> 1. Create a SimpleQuote
>> 2. Build a FlatForward curve using that quote
>> 3. Construct a Gsr model from that term structure
>> 4. Attach a Gaussian1dSwaptionEngine
>> 5. Call setValue() on the original SimpleQuote
>>
>> This results in a segmentation fault.
>>
>> I have modified the Python/examples/bermudan_swaption.py file and
>> attached it below to illustrate (along with error log below it).
>>
>> Has something been changed in how one shud enquire / update quote objects
>> that I missed? I am coming from 1.40, where this was not an issue. I am
>> running python 3.14.4 on macOS 26.1.4 and using a source build of
>> Quantlib/SWIG.
>>
>> Thanks, Aleksis
>>
>> # ---
>> # jupyter:
>> # jupytext:
>> # formats: py:light
>> # text_representation:
>> # extension: .py
>> # format_name: light
>> # format_version: '1.5'
>> # jupytext_version: 1.4.2
>> # kernelspec:
>> # display_name: Python 3
>> # language: python
>> # name: python3
>> # ---
>>
>> # # Bermudan swaptions
>> #
>> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
>> #
>> # This file is part of QuantLib, a free-software/open-source library
>> # for financial quantitative analysts and developers - https://www.quantlib.org/
>> #
>> # QuantLib is free software: you can redistribute it and/or modify it under the
>> # terms of the QuantLib license. You should have received a copy of the
>> # license along with this program; if not, please email
>> # <qua...@li...>. The license is also available online at
>> # <https://www.quantlib.org/license.shtml>.
>> #
>> # This program is distributed in the hope that it will be useful, but WITHOUT
>> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
>> # FOR A PARTICULAR PURPOSE. See the license for more details.
>>
>> import QuantLib as ql
>> import pandas as pd
>>
>> # ### Setup
>>
>> todaysDate = ql.Date(15, ql.February, 2002)
>> ql.Settings.instance().evaluationDate = todaysDate
>> calendar = ql.TARGET()
>> settlementDate = ql.Date(19, ql.February, 2002)
>>
>>
>> def calibrate(model, helpers, l, name):
>> print("Model: %s" % name)
>>
>> method = ql.Simplex(l)
>> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>>
>> print("Parameters: %s" % model.params())
>>
>> totalError = 0.0
>> data = []
>> for swaption, helper in zip(swaptionVols, helpers):
>> maturity, length, vol = swaption
>> NPV = helper.modelValue()
>> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
>> error = implied - vol
>> totalError += abs(error)
>> data.append((maturity, length, vol, implied, error))
>> averageError = totalError / len(helpers)
>>
>> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>>
>> print("Average error: %.4f" % averageError)
>>
>>
>> # ### Market data
>>
>> swaptionVols = [
>> # maturity, length, volatility
>> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
>> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
>> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
>> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
>> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
>> ]
>>
>> # This is a flat yield term structure implying a 1x5 swap at 5%.
>>
>> rateQuote = ql.SimpleQuote(0.04875825)
>> rate = ql.QuoteHandle(rateQuote)
>> termStructure = ql.YieldTermStructureHandle(
>> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
>> )
>>
>> # Define the ATM/OTM/ITM swaps:
>>
>> swapEngine = ql.DiscountingSwapEngine(termStructure)
>>
>> fixedLegFrequency = ql.Annual
>> fixedLegTenor = ql.Period(1, ql.Years)
>> fixedLegConvention = ql.Unadjusted
>> floatingLegConvention = ql.ModifiedFollowing
>> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
>> floatingLegFrequency = ql.Semiannual
>> floatingLegTenor = ql.Period(6, ql.Months)
>>
>> payFixed = ql.Swap.Payer
>> fixingDays = 2
>> index = ql.Euribor6M(termStructure)
>> floatingLegDayCounter = index.dayCounter()
>>
>> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
>> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>>
>> fixedSchedule = ql.Schedule(
>> swapStart,
>> swapEnd,
>> fixedLegTenor,
>> calendar,
>> fixedLegConvention,
>> fixedLegConvention,
>> ql.DateGeneration.Forward,
>> False,
>> )
>> floatingSchedule = ql.Schedule(
>> swapStart,
>> swapEnd,
>> floatingLegTenor,
>> calendar,
>> floatingLegConvention,
>> floatingLegConvention,
>> ql.DateGeneration.Forward,
>> False,
>> )
>>
>> dummy = ql.VanillaSwap(
>> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
>> )
>> dummy.setPricingEngine(swapEngine)
>> atmRate = dummy.fairRate()
>>
>> atmSwap = ql.VanillaSwap(
>> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
>> floatingSchedule, index, 0.0, floatingLegDayCounter
>> )
>>
>> otmSwap = ql.VanillaSwap(
>> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
>> floatingSchedule, index, 0.0, floatingLegDayCounter
>> )
>>
>> itmSwap = ql.VanillaSwap(
>> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
>> floatingSchedule, index, 0.0, floatingLegDayCounter
>> )
>>
>> atmSwap.setPricingEngine(swapEngine)
>> otmSwap.setPricingEngine(swapEngine)
>> itmSwap.setPricingEngine(swapEngine)
>>
>> helpers = [
>> ql.SwaptionHelper(
>> maturity,
>> length,
>> ql.makeQuoteHandle(vol),
>> index,
>> index.tenor(),
>> index.dayCounter(),
>> index.dayCounter(),
>> termStructure,
>> )
>> for maturity, length, vol in swaptionVols
>> ]
>>
>> times = {}
>> for h in helpers:
>> for t in h.times():
>> times[t] = 1
>> times = sorted(times.keys())
>>
>> grid = ql.TimeGrid(times, 30)
>>
>> G2model = ql.G2(termStructure)
>> HWmodel = ql.HullWhite(termStructure)
>> HWmodel2 = ql.HullWhite(termStructure)
>> BKmodel = ql.BlackKarasinski(termStructure)
>>
>> # ### Calibrations
>>
>> for h in helpers:
>> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
>> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>>
>> for h in helpers:
>> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
>> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>>
>> for h in helpers:
>> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
>> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>>
>> for h in helpers:
>> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
>> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>>
>>
>> # ### Price Bermudan swaptions on defined swaps
>>
>> bermudanDates = [d for d in fixedSchedule][:-1]
>> exercise = ql.BermudanExercise(bermudanDates)
>>
>> atmSwaption = ql.Swaption(atmSwap, exercise)
>> otmSwaption = ql.Swaption(otmSwap, exercise)
>> itmSwaption = ql.Swaption(itmSwap, exercise)
>>
>> data = []
>>
>> # +
>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>
>> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>
>> # +
>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>
>> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>
>> # +
>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>
>> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>
>> # +
>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>
>> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>> # -
>>
>> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>>
>> # ### GSR live setValue bump test
>>
>> import faulthandler
>> faulthandler.enable(all_threads=True)
>>
>> print("\n--- GSR live setValue bump test ---")
>>
>> # Minimal European swaption test on the same underlying ATM swap
>> euroExercise = ql.EuropeanExercise(swapStart)
>> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>>
>> # For a European GSR setup: no step dates, one sigma, one reversion
>> stepDates = []
>> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>
>> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
>> gsrEngine = ql.Gaussian1dSwaptionEngine(
>> gsr,
>> 64, # integration points
>> 7.0, # std devs
>> True,
>> False,
>> termStructure
>> )
>> euroSwaption.setPricingEngine(gsrEngine)
>>
>> base_rate = 0.04875825
>>
>> print("base rate:", base_rate)
>> print("base npv :", euroSwaption.NPV())
>>
>> # Single bump up/down
>> for bump in [1e-4, -1e-4, 0.0]:
>> bumped = base_rate + bump
>> print(f"\nsetValue -> {bumped:.8f}")
>> rateQuote.setValue(bumped)
>> print("npv =", euroSwaption.NPV())
>>
>> # Stress loop: repeatedly bump the observed quote and reprice
>> print("\nstarting stress loop...")
>> for i in range(200):
>> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
>> rateQuote.setValue(bumped)
>> npv = euroSwaption.NPV()
>> if i % 20 == 0:
>> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>>
>> # Restore
>> rateQuote.setValue(base_rate)
>> print("\nrestored rate:", base_rate)
>> print("restored npv :", euroSwaption.NPV())
>>
>>
>> Log:
>>
>> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
>> Model: G2 (analytic formulae)
>> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
>> maturity length volatility implied error
>> 0 1Y 5Y 0.1148 0.101974 -0.012826
>> 1 2Y 4Y 0.1108 0.105611 -0.005189
>> 2 3Y 3Y 0.1070 0.106950 -0.000050
>> 3 4Y 2Y 0.1021 0.107873 0.005773
>> 4 5Y 1Y 0.1000 0.108556 0.008556
>> Average error: 0.0065
>> Model: Hull-White (analytic formulae)
>> Parameters: [ 0.046379; 0.00586848 ]
>> maturity length volatility implied error
>> 0 1Y 5Y 0.1148 0.106223 -0.008577
>> 1 2Y 4Y 0.1108 0.106292 -0.004508
>> 2 3Y 3Y 0.1070 0.106338 -0.000662
>> 3 4Y 2Y 0.1021 0.106439 0.004339
>> 4 5Y 1Y 0.1000 0.106609 0.006609
>> Average error: 0.0049
>> Model: Hull-White (numerical calibration)
>> Parameters: [ 0.0559314; 0.00609858 ]
>> maturity length volatility implied error
>> 0 1Y 5Y 0.1148 0.102941 -0.011859
>> 1 2Y 4Y 0.1108 0.105452 -0.005348
>> 2 3Y 3Y 0.1070 0.106560 -0.000440
>> 3 4Y 2Y 0.1021 0.107365 0.005265
>> 4 5Y 1Y 0.1000 0.108223 0.008223
>> Average error: 0.0062
>> Model: Black-Karasinski (numerical calibration)
>> Parameters: [ 0.0442393; 0.120656 ]
>> maturity length volatility implied error
>> 0 1Y 5Y 0.1148 0.103094 -0.011706
>> 1 2Y 4Y 0.1108 0.105637 -0.005163
>> 2 3Y 3Y 0.1070 0.106656 -0.000344
>> 3 4Y 2Y 0.1021 0.107333 0.005233
>> 4 5Y 1Y 0.1000 0.108028 0.008028
>> Average error: 0.0061
>> model in-the-money at-the-money out-of-the-money
>> 0 G2 analytic 42.919620 14.581452 3.443306
>> 1 HW analytic 42.245449 12.924016 2.512541
>> 2 HW numerical 42.340450 13.141040 2.614228
>> 3 BK numerical 41.805673 13.012682 3.271628
>>
>> --- GSR live setValue bump test ---
>> base rate: 0.04875825
>> base npv : 16.787915348295005
>>
>> setValue -> 0.04885825
>> Fatal Python error: Segmentation fault
>>
>> Current thread 0x00000001f0afd8c0 (most recent call first):
>> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
>> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>>
>> Current thread's C stack trace (most recent call first):
>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
>> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>> <truncated rest of calls>
>>
>> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
>> Segmentation fault: 11
>>
>>
>> _______________________________________________
>> 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
>
|
|
From: Aleksis A. R. <ale...@go...> - 2026-04-16 06:57:17
|
Yep, ditching registerWith(stateProcess_); works fine as well and is the cleaner fix.
thanks.
> On Apr 16, 2026, at 11:34, Peter Caspers <pca...@gm...> wrote:
>
> Thanks. Since Gsr manages its stateProcess_, it does not need to and should not register with it as an Observer? I will take a closer look, but if you could test this change on your end, that would be valuable input.
> Best, Peter
>
>
> Aleksis Ali Raza via QuantLib-users <qua...@li... <mailto:qua...@li...>> schrieb am Do. 16. Apr. 2026 um 08:04:
>> Just to follow up on this, it's this line:
>>
>> void Gsr::update() {
>> if (stateProcess_ != nullptr) {
>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
>> ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();
>> }
>> LazyObject::update();
>> }
>>
>> in the gsr class that seems to be the cause. in my case, commenting out that line out and rebuilding from source fixes the problem of my gsr-based swaption risk runs.
>>
>> That line by itself looks pretty harmless but i think
>> registerWith(stateProcess_);
>>
>> further down leads into some sort of feedback loop (setValue() → notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() → Gsr::update() → …) and ultimately a seg fault.
>>
>>
>>> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <ale...@go... <mailto:ale...@go...>> wrote:
>>>
>>> Hi,
>>>
>>> I’m encountering what appears to be a regression or stability issue in QuantLib 1.42 related to the GSR (Gaussian short rate) model and the observer framework.
>>>
>>> Calling SimpleQuote.setValue() on a quote that is observed by a term structure used in a Gsr model causes a segmentation fault.
>>>
>>> This occurs even in a minimal standalone script (no threading, no external frameworks).
>>>
>>> Minimal reproduction
>>>
>>> The following sequence is sufficient:
>>> 1. Create a SimpleQuote
>>> 2. Build a FlatForward curve using that quote
>>> 3. Construct a Gsr model from that term structure
>>> 4. Attach a Gaussian1dSwaptionEngine
>>> 5. Call setValue() on the original SimpleQuote
>>>
>>> This results in a segmentation fault.
>>>
>>> I have modified the Python/examples/bermudan_swaption.py file and attached it below to illustrate (along with error log below it).
>>>
>>> Has something been changed in how one shud enquire / update quote objects that I missed? I am coming from 1.40, where this was not an issue. I am running python 3.14.4 on macOS 26.1.4 and using a source build of Quantlib/SWIG.
>>>
>>> Thanks, Aleksis
>>>
>>> # ---
>>> # jupyter:
>>> # jupytext:
>>> # formats: py:light
>>> # text_representation:
>>> # extension: .py
>>> # format_name: light
>>> # format_version: '1.5'
>>> # jupytext_version: 1.4.2
>>> # kernelspec:
>>> # display_name: Python 3
>>> # language: python
>>> # name: python3
>>> # ---
>>>
>>> # # Bermudan swaptions
>>> #
>>> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
>>> #
>>> # This file is part of QuantLib, a free-software/open-source library
>>> # for financial quantitative analysts and developers - https://www.quantlib.org/
>>> #
>>> # QuantLib is free software: you can redistribute it and/or modify it under the
>>> # terms of the QuantLib license. You should have received a copy of the
>>> # license along with this program; if not, please email
>>> # <qua...@li... <mailto:qua...@li...>>. The license is also available online at
>>> # <https://www.quantlib.org/license.shtml>.
>>> #
>>> # This program is distributed in the hope that it will be useful, but WITHOUT
>>> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
>>> # FOR A PARTICULAR PURPOSE. See the license for more details.
>>>
>>> import QuantLib as ql
>>> import pandas as pd
>>>
>>> # ### Setup
>>>
>>> todaysDate = ql.Date(15, ql.February, 2002)
>>> ql.Settings.instance().evaluationDate = todaysDate
>>> calendar = ql.TARGET()
>>> settlementDate = ql.Date(19, ql.February, 2002)
>>>
>>>
>>> def calibrate(model, helpers, l, name):
>>> print("Model: %s" % name)
>>>
>>> method = ql.Simplex(l)
>>> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>>>
>>> print("Parameters: %s" % model.params())
>>>
>>> totalError = 0.0
>>> data = []
>>> for swaption, helper in zip(swaptionVols, helpers):
>>> maturity, length, vol = swaption
>>> NPV = helper.modelValue()
>>> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
>>> error = implied - vol
>>> totalError += abs(error)
>>> data.append((maturity, length, vol, implied, error))
>>> averageError = totalError / len(helpers)
>>>
>>> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>>>
>>> print("Average error: %.4f" % averageError)
>>>
>>>
>>> # ### Market data
>>>
>>> swaptionVols = [
>>> # maturity, length, volatility
>>> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
>>> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
>>> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
>>> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
>>> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
>>> ]
>>>
>>> # This is a flat yield term structure implying a 1x5 swap at 5%.
>>>
>>> rateQuote = ql.SimpleQuote(0.04875825)
>>> rate = ql.QuoteHandle(rateQuote)
>>> termStructure = ql.YieldTermStructureHandle(
>>> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
>>> )
>>>
>>> # Define the ATM/OTM/ITM swaps:
>>>
>>> swapEngine = ql.DiscountingSwapEngine(termStructure)
>>>
>>> fixedLegFrequency = ql.Annual
>>> fixedLegTenor = ql.Period(1, ql.Years)
>>> fixedLegConvention = ql.Unadjusted
>>> floatingLegConvention = ql.ModifiedFollowing
>>> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
>>> floatingLegFrequency = ql.Semiannual
>>> floatingLegTenor = ql.Period(6, ql.Months)
>>>
>>> payFixed = ql.Swap.Payer
>>> fixingDays = 2
>>> index = ql.Euribor6M(termStructure)
>>> floatingLegDayCounter = index.dayCounter()
>>>
>>> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
>>> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>>>
>>> fixedSchedule = ql.Schedule(
>>> swapStart,
>>> swapEnd,
>>> fixedLegTenor,
>>> calendar,
>>> fixedLegConvention,
>>> fixedLegConvention,
>>> ql.DateGeneration.Forward,
>>> False,
>>> )
>>> floatingSchedule = ql.Schedule(
>>> swapStart,
>>> swapEnd,
>>> floatingLegTenor,
>>> calendar,
>>> floatingLegConvention,
>>> floatingLegConvention,
>>> ql.DateGeneration.Forward,
>>> False,
>>> )
>>>
>>> dummy = ql.VanillaSwap(
>>> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>> dummy.setPricingEngine(swapEngine)
>>> atmRate = dummy.fairRate()
>>>
>>> atmSwap = ql.VanillaSwap(
>>> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>>
>>> otmSwap = ql.VanillaSwap(
>>> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>>
>>> itmSwap = ql.VanillaSwap(
>>> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
>>> floatingSchedule, index, 0.0, floatingLegDayCounter
>>> )
>>>
>>> atmSwap.setPricingEngine(swapEngine)
>>> otmSwap.setPricingEngine(swapEngine)
>>> itmSwap.setPricingEngine(swapEngine)
>>>
>>> helpers = [
>>> ql.SwaptionHelper(
>>> maturity,
>>> length,
>>> ql.makeQuoteHandle(vol),
>>> index,
>>> index.tenor(),
>>> index.dayCounter(),
>>> index.dayCounter(),
>>> termStructure,
>>> )
>>> for maturity, length, vol in swaptionVols
>>> ]
>>>
>>> times = {}
>>> for h in helpers:
>>> for t in h.times():
>>> times[t] = 1
>>> times = sorted(times.keys())
>>>
>>> grid = ql.TimeGrid(times, 30)
>>>
>>> G2model = ql.G2(termStructure)
>>> HWmodel = ql.HullWhite(termStructure)
>>> HWmodel2 = ql.HullWhite(termStructure)
>>> BKmodel = ql.BlackKarasinski(termStructure)
>>>
>>> # ### Calibrations
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
>>> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
>>> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
>>> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>>>
>>> for h in helpers:
>>> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
>>> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>>>
>>>
>>> # ### Price Bermudan swaptions on defined swaps
>>>
>>> bermudanDates = [d for d in fixedSchedule][:-1]
>>> exercise = ql.BermudanExercise(bermudanDates)
>>>
>>> atmSwaption = ql.Swaption(atmSwap, exercise)
>>> otmSwaption = ql.Swaption(otmSwap, exercise)
>>> itmSwaption = ql.Swaption(itmSwap, exercise)
>>>
>>> data = []
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>>>
>>> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>>>
>>> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>>>
>>> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>>
>>> # +
>>> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>>>
>>> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>>> # -
>>>
>>> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>>>
>>> # ### GSR live setValue bump test
>>>
>>> import faulthandler
>>> faulthandler.enable(all_threads=True)
>>>
>>> print("\n--- GSR live setValue bump test ---")
>>>
>>> # Minimal European swaption test on the same underlying ATM swap
>>> euroExercise = ql.EuropeanExercise(swapStart)
>>> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>>>
>>> # For a European GSR setup: no step dates, one sigma, one reversion
>>> stepDates = []
>>> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>>>
>>> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
>>> gsrEngine = ql.Gaussian1dSwaptionEngine(
>>> gsr,
>>> 64, # integration points
>>> 7.0, # std devs
>>> True,
>>> False,
>>> termStructure
>>> )
>>> euroSwaption.setPricingEngine(gsrEngine)
>>>
>>> base_rate = 0.04875825
>>>
>>> print("base rate:", base_rate)
>>> print("base npv :", euroSwaption.NPV())
>>>
>>> # Single bump up/down
>>> for bump in [1e-4, -1e-4, 0.0]:
>>> bumped = base_rate + bump
>>> print(f"\nsetValue -> {bumped:.8f}")
>>> rateQuote.setValue(bumped)
>>> print("npv =", euroSwaption.NPV())
>>>
>>> # Stress loop: repeatedly bump the observed quote and reprice
>>> print("\nstarting stress loop...")
>>> for i in range(200):
>>> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
>>> rateQuote.setValue(bumped)
>>> npv = euroSwaption.NPV()
>>> if i % 20 == 0:
>>> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>>>
>>> # Restore
>>> rateQuote.setValue(base_rate)
>>> print("\nrestored rate:", base_rate)
>>> print("restored npv :", euroSwaption.NPV())
>>>
>>> Log:
>>> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
>>> Model: G2 (analytic formulae)
>>> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.101974 -0.012826
>>> 1 2Y 4Y 0.1108 0.105611 -0.005189
>>> 2 3Y 3Y 0.1070 0.106950 -0.000050
>>> 3 4Y 2Y 0.1021 0.107873 0.005773
>>> 4 5Y 1Y 0.1000 0.108556 0.008556
>>> Average error: 0.0065
>>> Model: Hull-White (analytic formulae)
>>> Parameters: [ 0.046379; 0.00586848 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.106223 -0.008577
>>> 1 2Y 4Y 0.1108 0.106292 -0.004508
>>> 2 3Y 3Y 0.1070 0.106338 -0.000662
>>> 3 4Y 2Y 0.1021 0.106439 0.004339
>>> 4 5Y 1Y 0.1000 0.106609 0.006609
>>> Average error: 0.0049
>>> Model: Hull-White (numerical calibration)
>>> Parameters: [ 0.0559314; 0.00609858 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.102941 -0.011859
>>> 1 2Y 4Y 0.1108 0.105452 -0.005348
>>> 2 3Y 3Y 0.1070 0.106560 -0.000440
>>> 3 4Y 2Y 0.1021 0.107365 0.005265
>>> 4 5Y 1Y 0.1000 0.108223 0.008223
>>> Average error: 0.0062
>>> Model: Black-Karasinski (numerical calibration)
>>> Parameters: [ 0.0442393; 0.120656 ]
>>> maturity length volatility implied error
>>> 0 1Y 5Y 0.1148 0.103094 -0.011706
>>> 1 2Y 4Y 0.1108 0.105637 -0.005163
>>> 2 3Y 3Y 0.1070 0.106656 -0.000344
>>> 3 4Y 2Y 0.1021 0.107333 0.005233
>>> 4 5Y 1Y 0.1000 0.108028 0.008028
>>> Average error: 0.0061
>>> model in-the-money at-the-money out-of-the-money
>>> 0 G2 analytic 42.919620 14.581452 3.443306
>>> 1 HW analytic 42.245449 12.924016 2.512541
>>> 2 HW numerical 42.340450 13.141040 2.614228
>>> 3 BK numerical 41.805673 13.012682 3.271628
>>>
>>> --- GSR live setValue bump test ---
>>> base rate: 0.04875825
>>> base npv : 16.787915348295005
>>>
>>> setValue -> 0.04885825
>>> Fatal Python error: Segmentation fault
>>>
>>> Current thread 0x00000001f0afd8c0 (most recent call first):
>>> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
>>> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>>>
>>> Current thread's C stack trace (most recent call first):
>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
>>> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
>>> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
>>> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
>>> <truncated rest of calls>
>>>
>>> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
>>> Segmentation fault: 11
>>
>> _______________________________________________
>> QuantLib-users mailing list
>> Qua...@li... <mailto:Qua...@li...>
>> https://lists.sourceforge.net/lists/listinfo/quantlib-users
|
|
From: Peter C. <pca...@gm...> - 2026-04-16 06:34:56
|
Thanks. Since Gsr manages its stateProcess_, it does not need to and should
not register with it as an Observer? I will take a closer look, but if you
could test this change on your end, that would be valuable input.
Best, Peter
Aleksis Ali Raza via QuantLib-users <qua...@li...>
schrieb am Do. 16. Apr. 2026 um 08:04:
> Just to follow up on this, it's this line:
>
> void Gsr::update() {
> if (stateProcess_ != nullptr) {
> ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
>
> *ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();*
> }
> LazyObject::update();
> }
>
> in the gsr class that seems to be the cause. in my case, commenting out
> that line out and rebuilding from source fixes the problem of my gsr-based
> swaption risk runs.
>
> That line by itself looks pretty harmless but i think
>
> registerWith(stateProcess_);
>
> further down leads into some sort of feedback loop (setValue() →
> notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() →
> Gsr::update() → …) and ultimately a seg fault.
>
> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <ale...@go...>
> wrote:
>
> Hi,
>
> I’m encountering what appears to be a regression or stability issue in
> QuantLib 1.42 related to the GSR (Gaussian short rate) model and the
> observer framework.
>
> Calling SimpleQuote.setValue() on a quote that is observed by a term
> structure used in a Gsr model causes a segmentation fault.
>
> This occurs even in a minimal standalone script (no threading, no external
> frameworks).
>
> Minimal reproduction
>
> The following sequence is sufficient:
> 1. Create a SimpleQuote
> 2. Build a FlatForward curve using that quote
> 3. Construct a Gsr model from that term structure
> 4. Attach a Gaussian1dSwaptionEngine
> 5. Call setValue() on the original SimpleQuote
>
> This results in a segmentation fault.
>
> I have modified the Python/examples/bermudan_swaption.py file and attached
> it below to illustrate (along with error log below it).
>
> Has something been changed in how one shud enquire / update quote objects
> that I missed? I am coming from 1.40, where this was not an issue. I am
> running python 3.14.4 on macOS 26.1.4 and using a source build of
> Quantlib/SWIG.
>
> Thanks, Aleksis
>
> # ---
> # jupyter:
> # jupytext:
> # formats: py:light
> # text_representation:
> # extension: .py
> # format_name: light
> # format_version: '1.5'
> # jupytext_version: 1.4.2
> # kernelspec:
> # display_name: Python 3
> # language: python
> # name: python3
> # ---
>
> # # Bermudan swaptions
> #
> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
> #
> # This file is part of QuantLib, a free-software/open-source library
> # for financial quantitative analysts and developers - https://www.quantlib.org/
> #
> # QuantLib is free software: you can redistribute it and/or modify it under the
> # terms of the QuantLib license. You should have received a copy of the
> # license along with this program; if not, please email
> # <qua...@li...>. The license is also available online at
> # <https://www.quantlib.org/license.shtml>.
> #
> # This program is distributed in the hope that it will be useful, but WITHOUT
> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
> # FOR A PARTICULAR PURPOSE. See the license for more details.
>
> import QuantLib as ql
> import pandas as pd
>
> # ### Setup
>
> todaysDate = ql.Date(15, ql.February, 2002)
> ql.Settings.instance().evaluationDate = todaysDate
> calendar = ql.TARGET()
> settlementDate = ql.Date(19, ql.February, 2002)
>
>
> def calibrate(model, helpers, l, name):
> print("Model: %s" % name)
>
> method = ql.Simplex(l)
> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>
> print("Parameters: %s" % model.params())
>
> totalError = 0.0
> data = []
> for swaption, helper in zip(swaptionVols, helpers):
> maturity, length, vol = swaption
> NPV = helper.modelValue()
> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
> error = implied - vol
> totalError += abs(error)
> data.append((maturity, length, vol, implied, error))
> averageError = totalError / len(helpers)
>
> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>
> print("Average error: %.4f" % averageError)
>
>
> # ### Market data
>
> swaptionVols = [
> # maturity, length, volatility
> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
> ]
>
> # This is a flat yield term structure implying a 1x5 swap at 5%.
>
> rateQuote = ql.SimpleQuote(0.04875825)
> rate = ql.QuoteHandle(rateQuote)
> termStructure = ql.YieldTermStructureHandle(
> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
> )
>
> # Define the ATM/OTM/ITM swaps:
>
> swapEngine = ql.DiscountingSwapEngine(termStructure)
>
> fixedLegFrequency = ql.Annual
> fixedLegTenor = ql.Period(1, ql.Years)
> fixedLegConvention = ql.Unadjusted
> floatingLegConvention = ql.ModifiedFollowing
> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
> floatingLegFrequency = ql.Semiannual
> floatingLegTenor = ql.Period(6, ql.Months)
>
> payFixed = ql.Swap.Payer
> fixingDays = 2
> index = ql.Euribor6M(termStructure)
> floatingLegDayCounter = index.dayCounter()
>
> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>
> fixedSchedule = ql.Schedule(
> swapStart,
> swapEnd,
> fixedLegTenor,
> calendar,
> fixedLegConvention,
> fixedLegConvention,
> ql.DateGeneration.Forward,
> False,
> )
> floatingSchedule = ql.Schedule(
> swapStart,
> swapEnd,
> floatingLegTenor,
> calendar,
> floatingLegConvention,
> floatingLegConvention,
> ql.DateGeneration.Forward,
> False,
> )
>
> dummy = ql.VanillaSwap(
> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
> )
> dummy.setPricingEngine(swapEngine)
> atmRate = dummy.fairRate()
>
> atmSwap = ql.VanillaSwap(
> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
> floatingSchedule, index, 0.0, floatingLegDayCounter
> )
>
> otmSwap = ql.VanillaSwap(
> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
> floatingSchedule, index, 0.0, floatingLegDayCounter
> )
>
> itmSwap = ql.VanillaSwap(
> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
> floatingSchedule, index, 0.0, floatingLegDayCounter
> )
>
> atmSwap.setPricingEngine(swapEngine)
> otmSwap.setPricingEngine(swapEngine)
> itmSwap.setPricingEngine(swapEngine)
>
> helpers = [
> ql.SwaptionHelper(
> maturity,
> length,
> ql.makeQuoteHandle(vol),
> index,
> index.tenor(),
> index.dayCounter(),
> index.dayCounter(),
> termStructure,
> )
> for maturity, length, vol in swaptionVols
> ]
>
> times = {}
> for h in helpers:
> for t in h.times():
> times[t] = 1
> times = sorted(times.keys())
>
> grid = ql.TimeGrid(times, 30)
>
> G2model = ql.G2(termStructure)
> HWmodel = ql.HullWhite(termStructure)
> HWmodel2 = ql.HullWhite(termStructure)
> BKmodel = ql.BlackKarasinski(termStructure)
>
> # ### Calibrations
>
> for h in helpers:
> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>
> for h in helpers:
> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>
> for h in helpers:
> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>
> for h in helpers:
> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>
>
> # ### Price Bermudan swaptions on defined swaps
>
> bermudanDates = [d for d in fixedSchedule][:-1]
> exercise = ql.BermudanExercise(bermudanDates)
>
> atmSwaption = ql.Swaption(atmSwap, exercise)
> otmSwaption = ql.Swaption(otmSwap, exercise)
> itmSwaption = ql.Swaption(itmSwap, exercise)
>
> data = []
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>
> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>
> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>
> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>
> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
> # -
>
> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>
> # ### GSR live setValue bump test
>
> import faulthandler
> faulthandler.enable(all_threads=True)
>
> print("\n--- GSR live setValue bump test ---")
>
> # Minimal European swaption test on the same underlying ATM swap
> euroExercise = ql.EuropeanExercise(swapStart)
> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>
> # For a European GSR setup: no step dates, one sigma, one reversion
> stepDates = []
> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>
> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
> gsrEngine = ql.Gaussian1dSwaptionEngine(
> gsr,
> 64, # integration points
> 7.0, # std devs
> True,
> False,
> termStructure
> )
> euroSwaption.setPricingEngine(gsrEngine)
>
> base_rate = 0.04875825
>
> print("base rate:", base_rate)
> print("base npv :", euroSwaption.NPV())
>
> # Single bump up/down
> for bump in [1e-4, -1e-4, 0.0]:
> bumped = base_rate + bump
> print(f"\nsetValue -> {bumped:.8f}")
> rateQuote.setValue(bumped)
> print("npv =", euroSwaption.NPV())
>
> # Stress loop: repeatedly bump the observed quote and reprice
> print("\nstarting stress loop...")
> for i in range(200):
> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
> rateQuote.setValue(bumped)
> npv = euroSwaption.NPV()
> if i % 20 == 0:
> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>
> # Restore
> rateQuote.setValue(base_rate)
> print("\nrestored rate:", base_rate)
> print("restored npv :", euroSwaption.NPV())
>
>
> Log:
>
> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
> Model: G2 (analytic formulae)
> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.101974 -0.012826
> 1 2Y 4Y 0.1108 0.105611 -0.005189
> 2 3Y 3Y 0.1070 0.106950 -0.000050
> 3 4Y 2Y 0.1021 0.107873 0.005773
> 4 5Y 1Y 0.1000 0.108556 0.008556
> Average error: 0.0065
> Model: Hull-White (analytic formulae)
> Parameters: [ 0.046379; 0.00586848 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.106223 -0.008577
> 1 2Y 4Y 0.1108 0.106292 -0.004508
> 2 3Y 3Y 0.1070 0.106338 -0.000662
> 3 4Y 2Y 0.1021 0.106439 0.004339
> 4 5Y 1Y 0.1000 0.106609 0.006609
> Average error: 0.0049
> Model: Hull-White (numerical calibration)
> Parameters: [ 0.0559314; 0.00609858 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.102941 -0.011859
> 1 2Y 4Y 0.1108 0.105452 -0.005348
> 2 3Y 3Y 0.1070 0.106560 -0.000440
> 3 4Y 2Y 0.1021 0.107365 0.005265
> 4 5Y 1Y 0.1000 0.108223 0.008223
> Average error: 0.0062
> Model: Black-Karasinski (numerical calibration)
> Parameters: [ 0.0442393; 0.120656 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.103094 -0.011706
> 1 2Y 4Y 0.1108 0.105637 -0.005163
> 2 3Y 3Y 0.1070 0.106656 -0.000344
> 3 4Y 2Y 0.1021 0.107333 0.005233
> 4 5Y 1Y 0.1000 0.108028 0.008028
> Average error: 0.0061
> model in-the-money at-the-money out-of-the-money
> 0 G2 analytic 42.919620 14.581452 3.443306
> 1 HW analytic 42.245449 12.924016 2.512541
> 2 HW numerical 42.340450 13.141040 2.614228
> 3 BK numerical 41.805673 13.012682 3.271628
>
> --- GSR live setValue bump test ---
> base rate: 0.04875825
> base npv : 16.787915348295005
>
> setValue -> 0.04885825
> Fatal Python error: Segmentation fault
>
> Current thread 0x00000001f0afd8c0 (most recent call first):
> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>
> Current thread's C stack trace (most recent call first):
> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> <truncated rest of calls>
>
> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
> Segmentation fault: 11
>
>
> _______________________________________________
> QuantLib-users mailing list
> Qua...@li...
> https://lists.sourceforge.net/lists/listinfo/quantlib-users
>
|
|
From: Aleksis A. R. <ale...@go...> - 2026-04-16 06:03:17
|
Just to follow up on this, it's this line:
void Gsr::update() {
if (stateProcess_ != nullptr) {
ext::static_pointer_cast<GsrProcess>(stateProcess_)->flushCache();
ext::static_pointer_cast<GsrProcess>(stateProcess_)->notifyObservers();
}
LazyObject::update();
}
in the gsr class that seems to be the cause. in my case, commenting out that line out and rebuilding from source fixes the problem of my gsr-based swaption risk runs.
That line by itself looks pretty harmless but i think
registerWith(stateProcess_);
further down leads into some sort of feedback loop (setValue() → notifyObservers() → Gsr::update() → stateProcess_->notifyObservers() → Gsr::update() → …) and ultimately a seg fault.
> On Apr 16, 2026, at 09:13, Aleksis Ali Raza <ale...@go...> wrote:
>
> Hi,
>
> I’m encountering what appears to be a regression or stability issue in QuantLib 1.42 related to the GSR (Gaussian short rate) model and the observer framework.
>
> Calling SimpleQuote.setValue() on a quote that is observed by a term structure used in a Gsr model causes a segmentation fault.
>
> This occurs even in a minimal standalone script (no threading, no external frameworks).
>
> Minimal reproduction
>
> The following sequence is sufficient:
> 1. Create a SimpleQuote
> 2. Build a FlatForward curve using that quote
> 3. Construct a Gsr model from that term structure
> 4. Attach a Gaussian1dSwaptionEngine
> 5. Call setValue() on the original SimpleQuote
>
> This results in a segmentation fault.
>
> I have modified the Python/examples/bermudan_swaption.py file and attached it below to illustrate (along with error log below it).
>
> Has something been changed in how one shud enquire / update quote objects that I missed? I am coming from 1.40, where this was not an issue. I am running python 3.14.4 on macOS 26.1.4 and using a source build of Quantlib/SWIG.
>
> Thanks, Aleksis
>
> # ---
> # jupyter:
> # jupytext:
> # formats: py:light
> # text_representation:
> # extension: .py
> # format_name: light
> # format_version: '1.5'
> # jupytext_version: 1.4.2
> # kernelspec:
> # display_name: Python 3
> # language: python
> # name: python3
> # ---
>
> # # Bermudan swaptions
> #
> # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl
> #
> # This file is part of QuantLib, a free-software/open-source library
> # for financial quantitative analysts and developers - https://www.quantlib.org/
> #
> # QuantLib is free software: you can redistribute it and/or modify it under the
> # terms of the QuantLib license. You should have received a copy of the
> # license along with this program; if not, please email
> # <qua...@li...>. The license is also available online at
> # <https://www.quantlib.org/license.shtml>.
> #
> # This program is distributed in the hope that it will be useful, but WITHOUT
> # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
> # FOR A PARTICULAR PURPOSE. See the license for more details.
>
> import QuantLib as ql
> import pandas as pd
>
> # ### Setup
>
> todaysDate = ql.Date(15, ql.February, 2002)
> ql.Settings.instance().evaluationDate = todaysDate
> calendar = ql.TARGET()
> settlementDate = ql.Date(19, ql.February, 2002)
>
>
> def calibrate(model, helpers, l, name):
> print("Model: %s" % name)
>
> method = ql.Simplex(l)
> model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7))
>
> print("Parameters: %s" % model.params())
>
> totalError = 0.0
> data = []
> for swaption, helper in zip(swaptionVols, helpers):
> maturity, length, vol = swaption
> NPV = helper.modelValue()
> implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50)
> error = implied - vol
> totalError += abs(error)
> data.append((maturity, length, vol, implied, error))
> averageError = totalError / len(helpers)
>
> print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"]))
>
> print("Average error: %.4f" % averageError)
>
>
> # ### Market data
>
> swaptionVols = [
> # maturity, length, volatility
> (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148),
> (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108),
> (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070),
> (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021),
> (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000),
> ]
>
> # This is a flat yield term structure implying a 1x5 swap at 5%.
>
> rateQuote = ql.SimpleQuote(0.04875825)
> rate = ql.QuoteHandle(rateQuote)
> termStructure = ql.YieldTermStructureHandle(
> ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())
> )
>
> # Define the ATM/OTM/ITM swaps:
>
> swapEngine = ql.DiscountingSwapEngine(termStructure)
>
> fixedLegFrequency = ql.Annual
> fixedLegTenor = ql.Period(1, ql.Years)
> fixedLegConvention = ql.Unadjusted
> floatingLegConvention = ql.ModifiedFollowing
> fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European)
> floatingLegFrequency = ql.Semiannual
> floatingLegTenor = ql.Period(6, ql.Months)
>
> payFixed = ql.Swap.Payer
> fixingDays = 2
> index = ql.Euribor6M(termStructure)
> floatingLegDayCounter = index.dayCounter()
>
> swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention)
> swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention)
>
> fixedSchedule = ql.Schedule(
> swapStart,
> swapEnd,
> fixedLegTenor,
> calendar,
> fixedLegConvention,
> fixedLegConvention,
> ql.DateGeneration.Forward,
> False,
> )
> floatingSchedule = ql.Schedule(
> swapStart,
> swapEnd,
> floatingLegTenor,
> calendar,
> floatingLegConvention,
> floatingLegConvention,
> ql.DateGeneration.Forward,
> False,
> )
>
> dummy = ql.VanillaSwap(
> payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter
> )
> dummy.setPricingEngine(swapEngine)
> atmRate = dummy.fairRate()
>
> atmSwap = ql.VanillaSwap(
> payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter,
> floatingSchedule, index, 0.0, floatingLegDayCounter
> )
>
> otmSwap = ql.VanillaSwap(
> payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter,
> floatingSchedule, index, 0.0, floatingLegDayCounter
> )
>
> itmSwap = ql.VanillaSwap(
> payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter,
> floatingSchedule, index, 0.0, floatingLegDayCounter
> )
>
> atmSwap.setPricingEngine(swapEngine)
> otmSwap.setPricingEngine(swapEngine)
> itmSwap.setPricingEngine(swapEngine)
>
> helpers = [
> ql.SwaptionHelper(
> maturity,
> length,
> ql.makeQuoteHandle(vol),
> index,
> index.tenor(),
> index.dayCounter(),
> index.dayCounter(),
> termStructure,
> )
> for maturity, length, vol in swaptionVols
> ]
>
> times = {}
> for h in helpers:
> for t in h.times():
> times[t] = 1
> times = sorted(times.keys())
>
> grid = ql.TimeGrid(times, 30)
>
> G2model = ql.G2(termStructure)
> HWmodel = ql.HullWhite(termStructure)
> HWmodel2 = ql.HullWhite(termStructure)
> BKmodel = ql.BlackKarasinski(termStructure)
>
> # ### Calibrations
>
> for h in helpers:
> h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16))
> calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)")
>
> for h in helpers:
> h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel))
> calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)")
>
> for h in helpers:
> h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid))
> calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)")
>
> for h in helpers:
> h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid))
> calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)")
>
>
> # ### Price Bermudan swaptions on defined swaps
>
> bermudanDates = [d for d in fixedSchedule][:-1]
> exercise = ql.BermudanExercise(bermudanDates)
>
> atmSwaption = ql.Swaption(atmSwap, exercise)
> otmSwaption = ql.Swaption(otmSwap, exercise)
> itmSwaption = ql.Swaption(itmSwap, exercise)
>
> data = []
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50))
>
> data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50))
>
> data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50))
>
> data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
>
> # +
> atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
> otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
> itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50))
>
> data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV()))
> # -
>
> print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"]))
>
> # ### GSR live setValue bump test
>
> import faulthandler
> faulthandler.enable(all_threads=True)
>
> print("\n--- GSR live setValue bump test ---")
>
> # Minimal European swaption test on the same underlying ATM swap
> euroExercise = ql.EuropeanExercise(swapStart)
> euroSwaption = ql.Swaption(atmSwap, euroExercise)
>
> # For a European GSR setup: no step dates, one sigma, one reversion
> stepDates = []
> sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
> reversions = [ql.QuoteHandle(ql.SimpleQuote(0.01))]
>
> gsr = ql.Gsr(termStructure, stepDates, sigmas, reversions)
> gsrEngine = ql.Gaussian1dSwaptionEngine(
> gsr,
> 64, # integration points
> 7.0, # std devs
> True,
> False,
> termStructure
> )
> euroSwaption.setPricingEngine(gsrEngine)
>
> base_rate = 0.04875825
>
> print("base rate:", base_rate)
> print("base npv :", euroSwaption.NPV())
>
> # Single bump up/down
> for bump in [1e-4, -1e-4, 0.0]:
> bumped = base_rate + bump
> print(f"\nsetValue -> {bumped:.8f}")
> rateQuote.setValue(bumped)
> print("npv =", euroSwaption.NPV())
>
> # Stress loop: repeatedly bump the observed quote and reprice
> print("\nstarting stress loop...")
> for i in range(200):
> bumped = base_rate + (1e-4 if i % 2 == 0 else -1e-4)
> rateQuote.setValue(bumped)
> npv = euroSwaption.NPV()
> if i % 20 == 0:
> print(f"iter {i:03d} rate={bumped:.8f} npv={npv}")
>
> # Restore
> rateQuote.setValue(base_rate)
> print("\nrestored rate:", base_rate)
> print("restored npv :", euroSwaption.NPV())
>
> Log:
> aleksisaliraza@Alis-MacBook-Pro:~/QuantLib-SWIG-1.42/Python/examples$ python3.14 bermudan-swaption.py
> Model: G2 (analytic formulae)
> Parameters: [ 0.0765369; 0.00279407; 0.0619638; 0.00954892; -1 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.101974 -0.012826
> 1 2Y 4Y 0.1108 0.105611 -0.005189
> 2 3Y 3Y 0.1070 0.106950 -0.000050
> 3 4Y 2Y 0.1021 0.107873 0.005773
> 4 5Y 1Y 0.1000 0.108556 0.008556
> Average error: 0.0065
> Model: Hull-White (analytic formulae)
> Parameters: [ 0.046379; 0.00586848 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.106223 -0.008577
> 1 2Y 4Y 0.1108 0.106292 -0.004508
> 2 3Y 3Y 0.1070 0.106338 -0.000662
> 3 4Y 2Y 0.1021 0.106439 0.004339
> 4 5Y 1Y 0.1000 0.106609 0.006609
> Average error: 0.0049
> Model: Hull-White (numerical calibration)
> Parameters: [ 0.0559314; 0.00609858 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.102941 -0.011859
> 1 2Y 4Y 0.1108 0.105452 -0.005348
> 2 3Y 3Y 0.1070 0.106560 -0.000440
> 3 4Y 2Y 0.1021 0.107365 0.005265
> 4 5Y 1Y 0.1000 0.108223 0.008223
> Average error: 0.0062
> Model: Black-Karasinski (numerical calibration)
> Parameters: [ 0.0442393; 0.120656 ]
> maturity length volatility implied error
> 0 1Y 5Y 0.1148 0.103094 -0.011706
> 1 2Y 4Y 0.1108 0.105637 -0.005163
> 2 3Y 3Y 0.1070 0.106656 -0.000344
> 3 4Y 2Y 0.1021 0.107333 0.005233
> 4 5Y 1Y 0.1000 0.108028 0.008028
> Average error: 0.0061
> model in-the-money at-the-money out-of-the-money
> 0 G2 analytic 42.919620 14.581452 3.443306
> 1 HW analytic 42.245449 12.924016 2.512541
> 2 HW numerical 42.340450 13.141040 2.614228
> 3 BK numerical 41.805673 13.012682 3.271628
>
> --- GSR live setValue bump test ---
> base rate: 0.04875825
> base npv : 16.787915348295005
>
> setValue -> 0.04885825
> Fatal Python error: Segmentation fault
>
> Current thread 0x00000001f0afd8c0 (most recent call first):
> File "/opt/homebrew/lib/python3.14/site-packages/QuantLib/QuantLib.py", line 6180 in setValue
> File "/Users/aleksisaliraza/QuantLib-SWIG-1.42/Python/examples/bermudan-swaption.py", line 277 in <module>
>
> Current thread's C stack trace (most recent call first):
> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1036d79d8]
> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1036e9f0c]
> Binary file "/opt/homebrew/Cellar/python@3.14/3.14.4/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x140 [0x1036e9dd0]
> Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x184cfd7a4]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib10Observable15notifyObserversEv+0x80 [0x10df9c4ec]
> Binary file "/usr/local/lib/libQuantLib.0.dylib", at _ZN8QuantLib3Gsr6updateEv+0xb4 [0x10df754d8]
> <truncated rest of calls>
>
> Extension modules: QuantLib._QuantLib, numpy._core._multiarray_umath, numpy.linalg._umath_linalg, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._pcg64, numpy.random._mt19937, numpy.random._generator, numpy.random._philox, numpy.random._sfc64, numpy.random.mtrand, pandas._libs.tslibs.ccalendar, pandas._libs.tslibs.np_datetime, pandas._libs.tslibs.dtypes, pandas._libs.tslibs.base, pandas._libs.tslibs.nattype, pandas._libs.tslibs.timezones, pandas._libs.tslibs.fields, pandas._libs.tslibs.timedeltas, pandas._libs.tslibs.tzconversion, pandas._libs.tslibs.timestamps, pandas._libs.properties, pandas._libs.tslibs.offsets, pandas._libs.tslibs.strptime, pandas._libs.tslibs.parsing, pandas._libs.tslibs.conversion, pandas._libs.tslibs.period, pandas._libs.tslibs.vectorized, pandas._libs.ops_dispatch, pandas._libs.missing, pandas._libs.hashtable, pandas._libs.algos, pandas._libs.interval, pandas._libs.lib, pandas._libs.ops, pandas._libs.hashing, pandas._libs.arrays, pandas._libs.tslib, pandas._libs.sparse, pandas._libs.internals, pandas._libs.indexing, pandas._libs.index, pandas._libs.writers, pandas._libs.join, pandas._libs.window.aggregations, pandas._libs.window.indexers, pandas._libs.reshape, pandas._libs.groupby, pandas._libs.json, pandas._libs.parsers, pandas._libs.testing (total: 52)
> Segmentation fault: 11
|