├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── quantlib-risks.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ChangeLog.txt ├── LICENSE.md ├── Python ├── CMakeLists.txt ├── QuantLib_Risks │ ├── CMakeLists.txt │ ├── __init__.py │ ├── converters.cpp │ └── converters.hpp ├── README.md ├── build_extensions.py.in ├── examples │ ├── README.md │ ├── american-option.py │ ├── basket-option.py │ ├── bermudan-swaption.py │ ├── bonds.py │ ├── callablebonds.py │ ├── capsfloors.py │ ├── cashflows.py │ ├── cds.py │ ├── european-option.py │ ├── gaussian1d-models.py │ ├── global-bootstrap.py │ ├── isda-engine.py │ ├── multicurve-bootstrapping.py │ ├── slv.py │ ├── swap-adjoint.py │ ├── swap.py │ └── swing.py ├── pyproject.toml.in ├── run_tests.bat ├── run_tests.sh └── test │ ├── QuantLibTestSuite.py │ ├── __init__.py │ ├── test_americanquantooption.py │ ├── test_assetswap.py │ ├── test_blackformula.py │ ├── test_bondfunctions.py │ ├── test_bonds.py │ ├── test_calendars.py │ ├── test_capfloor.py │ ├── test_cms.py │ ├── test_coupons.py │ ├── test_currencies.py │ ├── test_date.py │ ├── test_daycounters.py │ ├── test_equityindex.py │ ├── test_extrapolation.py │ ├── test_fdm.py │ ├── test_iborindex.py │ ├── test_inflation.py │ ├── test_instruments.py │ ├── test_integrals.py │ ├── test_marketelements.py │ ├── test_ode.py │ ├── test_options.py │ ├── test_ratehelpers.py │ ├── test_risks.py │ ├── test_sabr.py │ ├── test_slv.py │ ├── test_solvers1d.py │ ├── test_swap.py │ ├── test_swaption.py │ ├── test_termstructures.py │ └── test_volatilities.py ├── README.md ├── SWIG ├── asianoptions.i ├── barrieroptions.i ├── basketoptions.i ├── blackformula.i ├── bondfunctions.i ├── bonds.i ├── calendars.i ├── calibratedmodel.i ├── calibrationhelpers.i ├── capfloor.i ├── cashflows.i ├── cliquetoptions.i ├── common.i ├── convertiblebonds.i ├── credit.i ├── creditdefaultswap.i ├── currencies.i ├── date.i ├── date_extra.i ├── daycounters.i ├── defaultprobability.i ├── discountcurve.i ├── distributions.i ├── dividends.i ├── exchangerates.i ├── exercise.i ├── fdm.i ├── fdm_extra.i ├── fittedbondcurve.i ├── forward.i ├── forwardcurve.i ├── fra.i ├── functions.i ├── futures.i ├── gaussian1dmodel.i ├── grid.i ├── indexes.i ├── inflation.i ├── instruments.i ├── integrals.i ├── interestrate.i ├── interpolation.i ├── lazyobject.i ├── linearalgebra.i ├── lmm.i ├── localvolatilities.i ├── lookbackoptions.i ├── marketelements.i ├── money.i ├── montecarlo.i ├── null.i ├── observer.i ├── ode.i ├── old_volatility.i ├── operators.i ├── optimizers.i ├── options.i ├── parameter.i ├── payoffs.i ├── piecewiseyieldcurve.i ├── ql.i ├── quantlib.i ├── randomnumbers.i ├── ratehelpers.i ├── rounding.i ├── sampledcurve.i ├── scheduler.i ├── settings.i ├── shortratemodels.i ├── slv.i ├── spreadoption.i ├── statistics.i ├── stochasticprocess.i ├── swap.i ├── swaption.i ├── swingoption.i ├── tape.i ├── termstructures.i ├── timebasket.i ├── timeseries.i ├── tracing.i ├── tuple.i ├── types.i ├── vectors.i ├── vectors_extra.i ├── volatilities.i ├── volatilitymodels.i └── zerocurve.i ├── binder ├── labconfig │ └── default_setting_overrides.json ├── postBuild └── requirements.txt └── tools ├── prebuild_ql-risks.bat └── prebuild_ql-risks.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | *.i linguist-detectable=false -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | # Check for updates to GitHub Actions every weekday 8 | interval: "weekly" 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compilation artifacts 2 | Python/QuantLib/quantlib_wrap.cpp 3 | Python/.cache/ 4 | Python/QuantLib.egg-info 5 | Python/QuantLib_Python.egg-info 6 | Python/dist 7 | Python/examples/*.ipynb 8 | Python/examples/.ipynb_checkpoints 9 | 10 | # Build outputs 11 | **/x64/Debug 12 | **/x64/Release 13 | **/Debug 14 | **/Release 15 | **/bin/*.xml 16 | **/bin/*.manifest 17 | 18 | # CLion 19 | .idea 20 | cmake-build-debug 21 | 22 | # Artifacts created in multiple directories 23 | Makefile 24 | Makefile.in 25 | testCaseCollection.xml 26 | .deps 27 | .libs 28 | *.la 29 | *.lo 30 | *.o 31 | *.so 32 | *.dylib 33 | .build-stamp 34 | *.pyc 35 | *.exe 36 | *.dll 37 | *.exp 38 | *.lib 39 | *.pdb 40 | *.ilk 41 | *.class 42 | *~ 43 | *.ncb 44 | *.suo 45 | *.vcproj.*.user 46 | *.vcxproj.user 47 | *.VC.db 48 | *.VC.opendb 49 | *.log 50 | *.sdf 51 | *.opensdf 52 | *.pch 53 | *.idb 54 | *.ipch 55 | 56 | # Outputs 57 | Python/QuantLib_Risks/QuantLib_Risks.py 58 | Python/build 59 | 60 | .vscode 61 | **/venv 62 | /build 63 | **/.venv 64 | __pycache__ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/QuantLib"] 2 | path = lib/QuantLib 3 | url = https://github.com/lballabio/QuantLib.git 4 | [submodule "lib/xad"] 5 | path = lib/xad 6 | url = https://github.com/auto-differentiation/xad.git 7 | [submodule "lib/QuantLib-Risks-Cpp"] 8 | path = lib/QuantLib-Risks-Cpp 9 | url = https://github.com/auto-differentiation/QuantLib-Risks-Cpp.git 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog 2 | 3 | This log is to be read in conjunction with [ChangeLog.txt](./ChangeLog.txt). 4 | It lists the QuantLib-Risks specific changes on top of what is already listed in 5 | the underlying QuantLib-SWIG changelog. 6 | 7 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 8 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 9 | 10 | ## [1.33.3] - 2024-04-04 11 | 12 | - Builds against renamed xad-autodiff -> xad Python package 13 | - Cleanup of repository 14 | 15 | ## [1.33.2] - 2024-03-29 16 | 17 | - Renaming quantlib-risks -> QuantLib-Risks for consistency 18 | - Fixing markdown annotations in examples 19 | - otherwise technically identical 20 | 21 | ## [1.33] - 2024-03-25 22 | 23 | Initial release, matching QuantLib Python bindings version 1.33 24 | 25 | 26 | [1.33.3]: https://github.com/auto-differentiation/QuantLib-Risks-Py/compare/v1.33.2...v1.33.3 27 | 28 | [1.33.2]: https://github.com/auto-differentiation/QuantLib-Risks-Py/compare/v1.33...v1.33.2 29 | 30 | [1.33]: https://github.com/auto-differentiation/QuantLib-Risks-Py/releases/tag/v1.33 31 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # CMake file for QuantLib-Risks. The version set here is used for the Python 3 | # package. 4 | # 5 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | # for risk computation using automatic differentiation. It uses XAD, 7 | # a fast and comprehensive C++ library for automatic differentiation. 8 | # 9 | # Copyright (C) 2010-2024 Xcelerit Computing Ltd. 10 | # 11 | # This program is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU Affero General Public License as published 13 | # by the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU Affero General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU Affero General Public License 22 | # along with this program. If not, see . 23 | # 24 | ############################################################################## 25 | 26 | cmake_minimum_required(VERSION 3.15.0) 27 | project(QuantLib_Risks LANGUAGES CXX VERSION 1.33.3) 28 | 29 | # For MSVC RUNTIME LIBRARY, need CMP0091=NEW and cmake 3.15+ 30 | cmake_policy(SET CMP0091 NEW) 31 | set(PACKAGE_VERSION "${PROJECT_VERSION}") 32 | set(PACKAGE_VERSION_HEX "0x013303f0") 33 | set(QLR_VERSION ${PACKAGE_VERSION}) 34 | set(QLR_HEX_VERSION ${PACKAGE_VERSION_HEX}) 35 | 36 | 37 | find_package(QuantLib-Risks REQUIRED) 38 | find_package(SWIG REQUIRED) 39 | 40 | include(UseSWIG) 41 | 42 | enable_testing() 43 | 44 | 45 | add_subdirectory(Python) 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We love pull requests from everyone. By participating in this project, you agree to abide 4 | by our [code of conduct](CODE_OF_CONDUCT.md). 5 | 6 | Note that this fork is importing all changes from the QuantLib-SWIG repository on each 7 | release. Changes related to QuantLib's own Python bindings will be included in each new 8 | release. 9 | Contributions to this repository should only be made if they are related to building 10 | the Python bindings for QuantLib-Risks (enabled with XAD). 11 | 12 | 1. Fork, then clone the repository: 13 | 14 | ```bash 15 | git clone https://github.com/yourusername/QuantLib-Risks.git 16 | ``` 17 | 18 | 2. Follow the [Build Instructions](README.md) to setup the dependencies and 19 | build the software. Make sure all tests pass. 20 | 21 | 3. Create a feature branch, typically based on master, for your change 22 | 23 | ```bash 24 | git checkout -b feature/my-change main 25 | ``` 26 | 27 | 4. Make your changes, adding tests as you go, and commit. Again, make sure all 28 | tests pass. 29 | 30 | 5. Push your fork 31 | 32 | 6. [Submit a pull request][pr]. Not that you will have to sign the [Contributor License Agreement][cla] 33 | before the PR can be merged. 34 | 35 | At this point, you are depending on the core team to review your request. 36 | We may suggest changes, improvements, or alternatives. 37 | We strive to at least comment on a pull request within 3 business days. 38 | After feedback has been given, we expect a response within 2 weeks, 39 | after which we may close the pull request if it isn't showing activity. 40 | 41 | Some things that will highly increase the chance that your pull request gets 42 | accepted: 43 | 44 | - Discuss the change you wish to make via issue or email 45 | 46 | - Write good tests for all added features 47 | 48 | - Write good commit messages (short one-liner, followed by a blank line, 49 | followed by a more detailed explanation) 50 | 51 | 52 | [pr]: https://github.com/auto-differentiation/QuantLib-Risks/compare/ 53 | 54 | [cla]: https://gist.github.com/auto-differentiation-dev/5c6121c3f341e2de710fa034e9ff3263 55 | -------------------------------------------------------------------------------- /Python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Main CMake file for the Python extension. 3 | # 4 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 5 | # for risk computation using automatic differentiation. It uses XAD, 6 | # a fast and comprehensive C++ library for automatic differentiation. 7 | # 8 | # Copyright (C) 2010-2024 Xcelerit Computing Ltd. 9 | # 10 | # This program is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published 12 | # by the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with this program. If not, see . 22 | # 23 | ############################################################################## 24 | if(NOT "${QLR_PYTHON_VERSION}" STREQUAL "") 25 | find_package (Python3 ${QLR_PYTHON_VERSION} EXACT COMPONENTS Interpreter Development.Module REQUIRED) 26 | else() 27 | find_package (Python3 COMPONENTS Interpreter Development.Module REQUIRED) 28 | endif() 29 | 30 | # fetch pybind11 dependency on the fly 31 | include(FetchContent) 32 | 33 | FetchContent_Declare(pybind11 34 | GIT_REPOSITORY https://github.com/pybind/pybind11.git 35 | GIT_TAG v2.11.1) 36 | FetchContent_GetProperties(pybind11) 37 | if(NOT pybind11_POPULATED) 38 | FetchContent_Populate(pybind11) 39 | add_subdirectory(${pybind11_SOURCE_DIR} ${pybind11_BINARY_DIR}) 40 | endif() 41 | 42 | if(WIN32) 43 | set(QL_MODULE_SUFFIX ".${Python3_SOABI}.pyd") 44 | else() 45 | set(QL_MODULE_SUFFIX ".${Python3_SOABI}${CMAKE_SHARED_MODULE_SUFFIX}") 46 | endif() 47 | 48 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build_extensions.py.in 49 | ${CMAKE_CURRENT_BINARY_DIR}/build_extensions.py @ONLY) 50 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml.in 51 | ${CMAKE_CURRENT_BINARY_DIR}/pyproject.toml @ONLY) 52 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/README.md 53 | ${CMAKE_CURRENT_BINARY_DIR}/README.md COPYONLY) 54 | 55 | 56 | add_subdirectory(QuantLib_Risks) 57 | 58 | -------------------------------------------------------------------------------- /Python/QuantLib_Risks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Build SWIG binary module and optionally wheel package. 3 | # 4 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 5 | # for risk computation using automatic differentiation. It uses XAD, 6 | # a fast and comprehensive C++ library for automatic differentiation. 7 | # 8 | # Copyright (C) 2010-2024 Xcelerit Computing Ltd. 9 | # 10 | # This program is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published 12 | # by the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with this program. If not, see . 22 | # 23 | ############################################################################## 24 | 25 | set_property(SOURCE ${PROJECT_SOURCE_DIR}/SWIG/quantlib.i PROPERTY CPLUSPLUS ON) 26 | set_property(SOURCE ${PROJECT_SOURCE_DIR}/SWIG/quantlib.i PROPERTY USE_SWIG_DEPENDENCIES TRUE) 27 | set_property(SOURCE ${PROJECT_SOURCE_DIR}/SWIG/quantlib.i PROPERTY COMPILE_OPTIONS 28 | -DQL_XAD=1 29 | -DQLR_VERSION=\"${QLR_VERSION}\" 30 | -DQLR_HEX_VERSION=${QLR_HEX_VERSION}) 31 | swig_add_library(QuantLib_Risks 32 | LANGUAGE python 33 | OUTPUT_DIR . 34 | SOURCES ${PROJECT_SOURCE_DIR}/SWIG/quantlib.i converters.cpp 35 | ) 36 | target_link_libraries(QuantLib_Risks PRIVATE Python3::Module QuantLib::QuantLib pybind11::headers) 37 | target_compile_features(QuantLib_Risks PRIVATE cxx_std_17) 38 | target_compile_definitions(QuantLib_Risks PRIVATE QL_XAD=1 QLR_VERSION=\"${QLR_VERSION}\" QLR_HEX_VERSION=${QLR_HEX_VERSION}) 39 | target_include_directories(QuantLib_Risks PRIVATE .) 40 | set_property(TARGET QuantLib_Risks PROPERTY SUFFIX "${QL_MODULE_SUFFIX}") 41 | if(MSVC) 42 | # we build with the static runtime in Windows 43 | set_target_properties(QuantLib_Risks PROPERTIES 44 | MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 45 | endif() 46 | 47 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py 48 | ${CMAKE_CURRENT_BINARY_DIR}/__init__.py COPYONLY) 49 | 50 | if(WIN32) 51 | set(VENV_PYTHON ${CMAKE_CURRENT_BINARY_DIR}/../.venv/Scripts/python.exe) 52 | else() 53 | set(VENV_PYTHON ${CMAKE_CURRENT_BINARY_DIR}/../.venv/bin/python) 54 | endif() 55 | 56 | add_custom_command( 57 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../wheel.stamp 58 | DEPENDS QuantLib_Risks 59 | ${CMAKE_CURRENT_BINARY_DIR}/../pyproject.toml 60 | ${CMAKE_CURRENT_BINARY_DIR}/../build_extensions.py 61 | ${CMAKE_CURRENT_BINARY_DIR}/../README.md 62 | __init__.py 63 | # create environment 64 | COMMAND ${Python3_EXECUTABLE} -m venv .venv 65 | # install build dependencies 66 | COMMAND ${VENV_PYTHON} -m pip install -U pip setuptools wheel build 67 | # build the wheel 68 | COMMAND ${VENV_PYTHON} -m pip wheel . 69 | # install the wheel in the venv 70 | COMMAND ${VENV_PYTHON} -m pip install QuantLib_Risks*.whl --force-reinstall 71 | # install other dependencies for running the examples / tests 72 | COMMAND ${VENV_PYTHON} -m pip install -r ${PROJECT_SOURCE_DIR}/binder/requirements.txt 73 | # update the stamp file, to keep track of when we last build it 74 | COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/../wheel.stamp 75 | COMMENT "Building Python wheel..." 76 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.. 77 | ) 78 | 79 | # main target for building the python wheel - custom command above will be hooked to this target 80 | add_custom_target(python_wheel 81 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../wheel.stamp) 82 | 83 | -------------------------------------------------------------------------------- /Python/QuantLib_Risks/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: iso-8859-1 -*- 2 | """ 3 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 4 | Copyright (C) 2024 Xcelerit Computing Limited. 5 | 6 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 7 | for risk computation using automatic differentiation. It uses XAD, 8 | a fast and comprehensive C++ library for automatic differentiation. 9 | 10 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published 12 | by the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | QuantLib-Risks is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | QuantLib is free software: you can redistribute it and/or modify it 24 | under the terms of the QuantLib license. You should have received a 25 | copy of the license along with this program; if not, please email 26 | . The license is also available online at 27 | . 28 | 29 | This program is distributed in the hope that it will be useful, but WITHOUT 30 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 31 | FOR A PARTICULAR PURPOSE. See the license for more details. 32 | """ 33 | 34 | from .QuantLib_Risks import * 35 | 36 | if XAD_ENABLED: 37 | from xad.adj_1st import Real, Tape 38 | from typing import Union, Tuple, List 39 | 40 | # as part of the input at the top, we'll have _QuantLib_Risks in scope 41 | DoubleVector = _QuantLib_Risks.DoubleVector 42 | DoublePairVector = _QuantLib_Risks.DoublePairVector 43 | DoubleVectorVector = _QuantLib_Risks.DoubleVectorVector 44 | 45 | def Concentrating1dMesherPoint( 46 | x1: Union[Real, float, int], x2: Union[Real, float, int], v: bool 47 | ) -> Tuple[Real, Real, bool]: 48 | return (Real(x1), Real(x2), bool(v)) 49 | 50 | def PairDoubleVector( 51 | x1: List[Union[Real, float, int]] = [], x2: List[Union[Real, float, int]] = [] 52 | ) -> Tuple[List[Real], List[Real]]: 53 | return ([Real(x) for x in x1], [Real(x) for x in x2]) 54 | 55 | # monkey-patch the tape activation function to register this tape with QuantLib's internal 56 | # global tape pointer (we have 2 due to double static linking) 57 | def _wrap_tape_activation(): 58 | original_enter = Tape.__enter__ 59 | 60 | def _tape_enter(t: Tape): 61 | t = original_enter(t) 62 | _QuantLib_Risks._activate_tape(t) 63 | return t 64 | 65 | original_exit = Tape.__exit__ 66 | 67 | def _tape_exit(t: Tape, *args, **kwargs): 68 | original_exit(t, *args, **kwargs) 69 | _QuantLib_Risks._deactivate_tape() 70 | 71 | original_activate = Tape.activate 72 | 73 | def _tape_activate(t: Tape): 74 | original_activate(t) 75 | _QuantLib_Risks._activate_tape(t) 76 | 77 | original_deactivate = Tape.deactivate 78 | 79 | def _tape_deactivate(t: Tape): 80 | original_deactivate(t) 81 | _QuantLib_Risks._deactivate_tape() 82 | 83 | Tape.__enter__ = _tape_enter 84 | Tape.__exit__ = _tape_exit 85 | Tape.activate = _tape_activate 86 | Tape.deactivate = _tape_deactivate 87 | 88 | _wrap_tape_activation() 89 | 90 | if hasattr(_QuantLib_Risks, "__version__"): 91 | __version__ = _QuantLib_Risks.__version__ 92 | elif hasattr(_QuantLib_Risks.cvar, "__version__"): 93 | __version__ = _QuantLib_Risks.cvar.__version__ 94 | else: 95 | print("Could not find __version__ attribute") 96 | 97 | if hasattr(_QuantLib_Risks, "__hexversion__"): 98 | __hexversion__ = _QuantLib_Risks.__hexversion__ 99 | elif hasattr(_QuantLib_Risks.cvar, "__hexversion__"): 100 | __hexversion__ = _QuantLib_Risks.cvar.__hexversion__ 101 | else: 102 | print("Could not find __hexversion__ attribute") 103 | -------------------------------------------------------------------------------- /Python/README.md: -------------------------------------------------------------------------------- 1 | This package enables fast risks calculations on the QuantLib Python package. 2 | It provides the same interface as the [standard QuantLib package](https://pypi.org/project/QuantLib/), and in addition allows to calculate risks (sensitivities) using automatic differentiation via the [XAD automatic differentiation tool](https://auto-differentation.github.io). 3 | 4 | Useful links: 5 | 6 | - [QuantLib Documentation](https://www.quantlib.org) 7 | - [XAD Documentation, incl Python bindings and QuantLib integration](https://auto-differentiation.github.io/quantlib-risks/python/) 8 | 9 | ## Installation 10 | 11 | ``` 12 | pip install QuantLib-Risks 13 | ``` 14 | 15 | ## Usage Illustration 16 | 17 | ```python 18 | import QuantLib_Risks as ql 19 | from xad.adj_1st import Tape 20 | 21 | with Tape() as t: 22 | rate = ql.Real(0.2) 23 | tape.registerInput(rate) 24 | 25 | # quantlib pricing code 26 | ... 27 | npv = option.NPV() 28 | 29 | 30 | tape.registerOutput(npv) 31 | npv.derivative = 1.0 32 | tape.computeAdjoints() 33 | 34 | print(f"price = {npv}") 35 | print(f"delta = {rate.derivative}") 36 | ``` 37 | 38 | ## Related Projects 39 | 40 | - XAD Comprehensive automatic differentiation in [Python](https://github.com/auto-differentiation/xad-py) and [C++](https://github.com/auto-differentiation/xad) 41 | - QuantLib-Risks: Fast risk evaluations in [Python](https://github.com/auto-differentiation/QuantLib-Risks-Py) and [C++](https://github.com/auto-differentiation/QuantLib-Risks-Cpp) 42 | -------------------------------------------------------------------------------- /Python/build_extensions.py.in: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # Build file for extension module - using pre-built binary with SWIG/CMake. 4 | # 5 | # This was inspired by: 6 | # https://github.com/tim-mitchell/prebuilt_binaries/tree/main 7 | # 8 | # 9 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 10 | # for risk computation using automatic differentiation. It uses XAD, 11 | # a fast and comprehensive C++ library for automatic differentiation. 12 | # 13 | # Copyright (C) 2010-2024 Xcelerit Computing Ltd. 14 | # 15 | # This program is free software: you can redistribute it and/or modify 16 | # it under the terms of the GNU Affero General Public License as published 17 | # by the Free Software Foundation, either version 3 of the License, or 18 | # (at your option) any later version. 19 | # 20 | # This program is distributed in the hope that it will be useful, 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | # GNU Affero General Public License for more details. 24 | # 25 | # You should have received a copy of the GNU Affero General Public License 26 | # along with this program. If not, see . 27 | # 28 | ############################################################################## 29 | 30 | import os 31 | from pathlib import Path 32 | from distutils.file_util import copy_file 33 | try: 34 | from setuptools import Extension 35 | from setuptools.command.build_ext import build_ext 36 | except ImportError: 37 | from distutils.command.build_ext import build_ext 38 | from distutils.extension import Extension 39 | 40 | 41 | class QuantLibExtension(Extension): 42 | """Extension module for QuantLib, using the pre-built file from CMAKE instead of 43 | actually building it.""" 44 | 45 | def __init__(self, name: str, input_file: str): 46 | filepath = Path(input_file) 47 | if not filepath.exists(): 48 | raise ValueError(f"extension file {input_file} does not exist") 49 | self.input_file = input_file 50 | 51 | super().__init__(f"QuantLib_Risks.{name}", ["dont-need-this-source-file.c"]) 52 | 53 | class ql_build_ext(build_ext): 54 | """Overrides build_ext to simply copy the file built with CMake into the 55 | right location, rather than actually building it""" 56 | 57 | def run(self): 58 | for ext in self.extensions: 59 | if not isinstance(ext, QuantLibExtension): 60 | raise ValueError("Only pre-built extensions supported") 61 | 62 | fullname = self.get_ext_fullname(ext.name) 63 | filename = self.get_ext_filename(fullname) 64 | dest_path = Path(self.build_lib) / "QuantLib_Risks" 65 | dest_path.mkdir(parents=True, exist_ok=True) 66 | dest_filename = dest_path / os.path.basename(filename) 67 | 68 | copy_file( 69 | ext.input_file, 70 | dest_filename, 71 | verbose=self.verbose, 72 | dry_run=self.dry_run, 73 | ) 74 | 75 | if self.inplace: 76 | self.copy_extensions_to_source() 77 | 78 | def build(setup_kwargs: dict): 79 | """Main extension build file""" 80 | ext_modules = [QuantLibExtension("_QuantLib_Risks", 81 | 'QuantLib_Risks/_QuantLib_Risks@QL_MODULE_SUFFIX@')] 82 | setup_kwargs.update( 83 | { 84 | "ext_modules": ext_modules, 85 | "cmdclass": {"build_ext": ql_build_ext}, 86 | "zip_safe": False 87 | } 88 | ) 89 | -------------------------------------------------------------------------------- /Python/examples/README.md: -------------------------------------------------------------------------------- 1 | # QuantLib-Risks Python examples 2 | 3 | [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/auto-differentiation/QuantLib-Risks/main?labpath=Python%2Fexamples) 4 | 5 | This directory contains a number of examples of using risk-enabled QuantLib from 6 | Python. They can also run as Jupyter notebooks by means of 7 | [Jupytext](https://jupytext.readthedocs.io/). 8 | 9 | You can try them online thanks to [Binder](https://mybinder.org/). 10 | If you're seeing this file as a notebook, you're probably there already. 11 | If not, you can click the "Launch Binder" badge at the top of this file. 12 | 13 | If you want to run these examples locally, you'll need the modules listed in the 14 | `requirements.txt` file in the `binder` folder at the root of the [QuantLib-Risks 15 | repository](https://github.com/auto-differentiation/QuantLib-Risks); to install 16 | them, you can execute 17 | 18 | pip install -r requirements.txt 19 | 20 | from that directory. 21 | -------------------------------------------------------------------------------- /Python/examples/callablebonds.py: -------------------------------------------------------------------------------- 1 | # --- 2 | # jupyter: 3 | # jupytext: 4 | # formats: py:light 5 | # text_representation: 6 | # extension: .py 7 | # format_name: light 8 | # format_version: '1.5' 9 | # jupytext_version: 1.14.5 10 | # kernelspec: 11 | # display_name: Python 3 (ipykernel) 12 | # language: python 13 | # name: python3 14 | # --- 15 | 16 | # # Callable bonds 17 | # 18 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 19 | # for risk computation using automatic differentiation. It uses XAD, 20 | # a fast and comprehensive C++ library for automatic differentiation. 21 | # 22 | # QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 23 | # it under the terms of the GNU Affero General Public License as published 24 | # by the Free Software Foundation, either version 3 of the License, or 25 | # (at your option) any later version. 26 | # 27 | # QuantLib-Risks is distributed in the hope that it will be useful, 28 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | # GNU Affero General Public License for more details. 31 | # 32 | # You should have received a copy of the GNU Affero General Public License 33 | # along with this program. If not, see . 34 | # 35 | # QuantLib is free software: you can redistribute it and/or modify it under the 36 | # terms of the QuantLib license. You should have received a copy of the 37 | # license along with this program; if not, please email 38 | # . The license is also available online at 39 | # . 40 | # 41 | # This program is distributed in the hope that it will be useful, but WITHOUT 42 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 43 | # FOR A PARTICULAR PURPOSE. See the license for more details. 44 | 45 | import QuantLib_Risks as ql 46 | import numpy as np 47 | 48 | calcDate = ql.Date(16, 8, 2006) 49 | ql.Settings.instance().evaluationDate = calcDate 50 | 51 | dayCount = ql.ActualActual(ql.ActualActual.Bond) 52 | rate = 0.0465 53 | termStructure = ql.FlatForward(calcDate, rate, dayCount, ql.Compounded, ql.Semiannual) 54 | term_structure_handle = ql.RelinkableYieldTermStructureHandle(termStructure) 55 | 56 | callabilitySchedule = ql.CallabilitySchedule() 57 | callPrice = 100.0 58 | callDate = ql.Date(15, ql.September, 2006); 59 | nc = ql.NullCalendar() 60 | 61 | # Number of calldates is 24 62 | for i in range(0, 24): 63 | callabilityPrice = ql.BondPrice(callPrice, ql.BondPrice.Clean) 64 | callabilitySchedule.append(ql.Callability(callabilityPrice, ql.Callability.Call, callDate)) 65 | callDate = nc.advance(callDate, 3, ql.Months) 66 | 67 | issueDate = ql.Date(16, ql.September, 2004) 68 | maturityDate = ql.Date(15, ql.September, 2012) 69 | calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) 70 | tenor = ql.Period(ql.Quarterly) 71 | accrualConvention = ql.Unadjusted 72 | schedule = ql.Schedule(issueDate, maturityDate, tenor, calendar, 73 | accrualConvention, accrualConvention, ql.DateGeneration.Backward, False) 74 | 75 | settlement_days = 3 76 | faceAmount = 100 77 | accrual_daycount = ql.ActualActual(ql.ActualActual.Bond) 78 | coupon = 0.025 79 | bond = ql.CallableFixedRateBond(settlement_days, faceAmount, schedule, 80 | [coupon], accrual_daycount, ql.Following, 81 | faceAmount, issueDate, callabilitySchedule) 82 | 83 | def engine(a, s, grid_points): 84 | model = ql.HullWhite(term_structure_handle, a, s) 85 | return ql.TreeCallableFixedRateBondEngine(model, grid_points) 86 | 87 | # 6% mean reversion and 20% volatility 88 | bond.setPricingEngine(engine(0.06, 0.20, 40)) 89 | print("Bond price: ", bond.cleanPrice()) 90 | 91 | # 3% mean reversion and 15% volatility 92 | bond.setPricingEngine(engine(0.03, 0.15, 40)) 93 | print("Bond price: ", bond.cleanPrice()) 94 | -------------------------------------------------------------------------------- /Python/examples/capsfloors.py: -------------------------------------------------------------------------------- 1 | # --- 2 | # jupyter: 3 | # jupytext: 4 | # formats: py:light 5 | # text_representation: 6 | # extension: .py 7 | # format_name: light 8 | # format_version: '1.5' 9 | # jupytext_version: 1.14.5 10 | # kernelspec: 11 | # display_name: Python 3 (ipykernel) 12 | # language: python 13 | # name: python3 14 | # --- 15 | 16 | # # Caps and Floors 17 | # 18 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 19 | # for risk computation using automatic differentiation. It uses XAD, 20 | # a fast and comprehensive C++ library for automatic differentiation. 21 | # 22 | # QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 23 | # it under the terms of the GNU Affero General Public License as published 24 | # by the Free Software Foundation, either version 3 of the License, or 25 | # (at your option) any later version. 26 | # 27 | # QuantLib-Risks is distributed in the hope that it will be useful, 28 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | # GNU Affero General Public License for more details. 31 | # 32 | # You should have received a copy of the GNU Affero General Public License 33 | # along with this program. If not, see . 34 | # 35 | # QuantLib is free software: you can redistribute it and/or modify it under the 36 | # terms of the QuantLib license. You should have received a copy of the 37 | # license along with this program; if not, please email 38 | # . The license is also available online at 39 | # . 40 | # 41 | # This program is distributed in the hope that it will be useful, but WITHOUT 42 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 43 | # FOR A PARTICULAR PURPOSE. See the license for more details. 44 | 45 | import QuantLib_Risks as ql 46 | 47 | calcDate = ql.Date(14, 6, 2016) 48 | ql.Settings.instance().evaluationDate = calcDate 49 | 50 | dates = [ql.Date(14,6,2016), ql.Date(14,9,2016), 51 | ql.Date(14,12,2016), ql.Date(14,6,2017), 52 | ql.Date(14,6,2019), ql.Date(14,6,2021), 53 | ql.Date(15,6,2026), ql.Date(16,6,2031), 54 | ql.Date(16,6,2036), ql.Date(14,6,2046)] 55 | 56 | yields = [0.000000, 0.006616, 0.007049, 0.007795, 57 | 0.009599, 0.011203, 0.015068, 0.017583, 58 | 0.018998, 0.020080] 59 | 60 | dayCount = ql.ActualActual(ql.ActualActual.Bond) 61 | calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) 62 | interpolation = ql.Linear() 63 | compounding = ql.Compounded 64 | compoundingFrequency = ql.Annual 65 | term_structure = ql.ZeroCurve(dates, yields, dayCount, calendar, interpolation, compounding, compoundingFrequency) 66 | ts_handle = ql.YieldTermStructureHandle(term_structure) 67 | 68 | start_date = ql.Date(14, 6, 2016) 69 | end_date = ql.Date(14, 6 , 2026) 70 | period = ql.Period(3, ql.Months) 71 | buss_convention = ql.ModifiedFollowing 72 | rule = ql.DateGeneration.Forward 73 | end_of_month = False 74 | schedule = ql.Schedule(start_date, end_date, period, calendar, buss_convention, buss_convention, rule, end_of_month) 75 | 76 | iborIndex = ql.USDLibor(ql.Period(3, ql.Months), ts_handle) 77 | iborIndex.addFixing(ql.Date(10,6,2016), 0.0065560) 78 | ibor_leg = ql.IborLeg([1000000], schedule, iborIndex) 79 | 80 | strike = 0.02 81 | cap = ql.Cap(ibor_leg, [strike]) 82 | vols = ql.QuoteHandle(ql.SimpleQuote(0.547295)) 83 | engine = ql.BlackCapFloorEngine(ts_handle, vols) 84 | cap.setPricingEngine(engine) 85 | print("Value of Caps given constant volatility:", cap.NPV()) 86 | -------------------------------------------------------------------------------- /Python/examples/cds.py: -------------------------------------------------------------------------------- 1 | # --- 2 | # jupyter: 3 | # jupytext: 4 | # formats: py:light 5 | # text_representation: 6 | # extension: .py 7 | # format_name: light 8 | # format_version: '1.5' 9 | # jupytext_version: 1.4.2 10 | # kernelspec: 11 | # display_name: Python 3 12 | # language: python 13 | # name: python3 14 | # --- 15 | 16 | # # Credit default swaps 17 | # 18 | # Copyright (©) 2014 Thema Consulting SA 19 | # Copyright (©) 2024 Xcelerit Computing Limited. 20 | # 21 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 22 | # for risk computation using automatic differentiation. It uses XAD, 23 | # a fast and comprehensive C++ library for automatic differentiation. 24 | # 25 | # QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 26 | # it under the terms of the GNU Affero General Public License as published 27 | # by the Free Software Foundation, either version 3 of the License, or 28 | # (at your option) any later version. 29 | # 30 | # QuantLib-Risks is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU Affero General Public License for more details. 34 | # 35 | # You should have received a copy of the GNU Affero General Public License 36 | # along with this program. If not, see . 37 | # 38 | # QuantLib is free software: you can redistribute it and/or modify it under the 39 | # terms of the QuantLib license. You should have received a copy of the 40 | # license along with this program; if not, please email 41 | # . The license is also available online at 42 | # . 43 | # 44 | # This program is distributed in the hope that it will be useful, but WITHOUT 45 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 46 | # FOR A PARTICULAR PURPOSE. See the license for more details. 47 | 48 | # ### Setup 49 | 50 | import QuantLib_Risks as ql 51 | 52 | calendar = ql.TARGET() 53 | 54 | todaysDate = ql.Date(15, ql.May, 2007) 55 | ql.Settings.instance().evaluationDate = todaysDate 56 | 57 | risk_free_rate = ql.YieldTermStructureHandle(ql.FlatForward(todaysDate, 0.01, ql.Actual365Fixed())) 58 | 59 | # ### CDS parameters 60 | 61 | recovery_rate = 0.5 62 | quoted_spreads = [0.0150, 0.0150, 0.0150, 0.0150] 63 | tenors = [ql.Period(3, ql.Months), ql.Period(6, ql.Months), ql.Period(1, ql.Years), ql.Period(2, ql.Years)] 64 | maturities = [calendar.adjust(todaysDate + x, ql.Following) for x in tenors] 65 | 66 | instruments = [ 67 | ql.SpreadCdsHelper( 68 | ql.QuoteHandle(ql.SimpleQuote(s)), 69 | tenor, 70 | 0, 71 | calendar, 72 | ql.Quarterly, 73 | ql.Following, 74 | ql.DateGeneration.TwentiethIMM, 75 | ql.Actual365Fixed(), 76 | recovery_rate, 77 | risk_free_rate, 78 | ) 79 | for s, tenor in zip(quoted_spreads, tenors) 80 | ] 81 | 82 | hazard_curve = ql.PiecewiseFlatHazardRate(todaysDate, instruments, ql.Actual365Fixed()) 83 | print("Calibrated hazard rate values: ") 84 | for x in hazard_curve.nodes(): 85 | print("hazard rate on {} is {:.7f}".format(*x)) 86 | 87 | print("Some survival probability values: ") 88 | print( 89 | "1Y survival probability: {:.4g}, \n\t\texpected {:.4g}".format( 90 | hazard_curve.survivalProbability(todaysDate + ql.Period("1Y")), 0.9704) 91 | ) 92 | print( 93 | "2Y survival probability: {:.4g}, \n\t\texpected {:.4g}".format( 94 | hazard_curve.survivalProbability(todaysDate + ql.Period("2Y")), 0.9418) 95 | ) 96 | 97 | # ### Reprice instruments 98 | 99 | nominal = 1000000.0 100 | probability = ql.DefaultProbabilityTermStructureHandle(hazard_curve) 101 | 102 | # We'll create a cds for every maturity: 103 | 104 | all_cds = [] 105 | for maturity, s in zip(maturities, quoted_spreads): 106 | schedule = ql.Schedule( 107 | todaysDate, 108 | maturity, 109 | ql.Period(ql.Quarterly), 110 | calendar, 111 | ql.Following, 112 | ql.Unadjusted, 113 | ql.DateGeneration.TwentiethIMM, 114 | False, 115 | ) 116 | cds = ql.CreditDefaultSwap(ql.Protection.Seller, nominal, s, schedule, ql.Following, ql.Actual365Fixed()) 117 | engine = ql.MidPointCdsEngine(probability, recovery_rate, risk_free_rate) 118 | cds.setPricingEngine(engine) 119 | all_cds.append(cds) 120 | 121 | print("Repricing of quoted CDSs employed for calibration: ") 122 | for cds, tenor in zip(all_cds, tenors): 123 | print("{} fair spread: {:.7g}".format(tenor, cds.fairSpread())) 124 | print(" NPV: {:g}".format(cds.NPV())) 125 | print(" default leg: {:.7g}".format(cds.defaultLegNPV())) 126 | print(" coupon leg: {:.7g}".format(cds.couponLegNPV())) 127 | print("") 128 | -------------------------------------------------------------------------------- /Python/examples/swing.py: -------------------------------------------------------------------------------- 1 | # --- 2 | # jupyter: 3 | # jupytext: 4 | # formats: py:light 5 | # text_representation: 6 | # extension: .py 7 | # format_name: light 8 | # format_version: '1.5' 9 | # jupytext_version: 1.4.2 10 | # kernelspec: 11 | # display_name: Python 3 12 | # language: python 13 | # name: python3 14 | # --- 15 | 16 | # # Swing options 17 | # 18 | # Copyright (©) 2018 Klaus Spanderen 19 | # Copyright (©) 2024 Xcelerit Computing Limited. 20 | # 21 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 22 | # for risk computation using automatic differentiation. It uses XAD, 23 | # a fast and comprehensive C++ library for automatic differentiation. 24 | # 25 | # QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 26 | # it under the terms of the GNU Affero General Public License as published 27 | # by the Free Software Foundation, either version 3 of the License, or 28 | # (at your option) any later version. 29 | # 30 | # QuantLib-Risks is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU Affero General Public License for more details. 34 | # 35 | # You should have received a copy of the GNU Affero General Public License 36 | # along with this program. If not, see . 37 | # 38 | # QuantLib is free software: you can redistribute it and/or modify it under the 39 | # terms of the QuantLib license. You should have received a copy of the 40 | # license along with this program; if not, please email 41 | # . The license is also available online at 42 | # . 43 | # 44 | # This program is distributed in the hope that it will be useful, but WITHOUT 45 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 46 | # FOR A PARTICULAR PURPOSE. See the license for more details. 47 | 48 | import QuantLib_Risks as ql 49 | from xad import math 50 | 51 | todaysDate = ql.Date(30, ql.September, 2018) 52 | ql.Settings.instance().evaluationDate = todaysDate 53 | settlementDate = todaysDate 54 | riskFreeRate = ql.FlatForward(settlementDate, 0.0, ql.Actual365Fixed()) 55 | dividendYield = ql.FlatForward(settlementDate, 0.0, ql.Actual365Fixed()) 56 | underlying = ql.SimpleQuote(30.0) 57 | volatility = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.20, ql.Actual365Fixed()) 58 | 59 | 60 | exerciseDates = [ql.Date(1, ql.January, 2019) + i for i in range(31)] 61 | 62 | swingOption = ql.VanillaSwingOption( 63 | ql.VanillaForwardPayoff(ql.Option.Call, underlying.value()), ql.SwingExercise(exerciseDates), 0, len(exerciseDates) 64 | ) 65 | 66 | bsProcess = ql.BlackScholesMertonProcess( 67 | ql.QuoteHandle(underlying), 68 | ql.YieldTermStructureHandle(dividendYield), 69 | ql.YieldTermStructureHandle(riskFreeRate), 70 | ql.BlackVolTermStructureHandle(volatility), 71 | ) 72 | 73 | swingOption.setPricingEngine(ql.FdSimpleBSSwingEngine(bsProcess)) 74 | 75 | print("Black Scholes Price: {:f}".format(swingOption.NPV())) 76 | 77 | x0 = 0.0 78 | x1 = 0.0 79 | 80 | beta = 4.0 81 | eta = 4.0 82 | jumpIntensity = 1.0 83 | speed = 1.0 84 | volatility = 0.1 85 | 86 | curveShape = [] 87 | for d in exerciseDates: 88 | t = ql.Actual365Fixed().yearFraction(todaysDate, d) 89 | gs = ( 90 | math.log(underlying.value()) 91 | - volatility * volatility / (4 * speed) * (1 - math.exp(-2 * speed * t)) 92 | - jumpIntensity / beta * math.log((eta - math.exp(-beta * t)) / (eta - 1.0)) 93 | ) 94 | curveShape.append((t, gs)) 95 | 96 | ouProcess = ql.ExtendedOrnsteinUhlenbeckProcess(speed, volatility, x0, lambda x: x0) 97 | jProcess = ql.ExtOUWithJumpsProcess(ouProcess, x1, beta, jumpIntensity, eta) 98 | 99 | swingOption.setPricingEngine(ql.FdSimpleExtOUJumpSwingEngine(jProcess, riskFreeRate, 25, 25, 200, curveShape)) 100 | 101 | print("Kluge Model Price : {:f}".format(swingOption.NPV())) 102 | -------------------------------------------------------------------------------- /Python/pyproject.toml.in: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Pypproject main file for QuantLib-Risks 3 | # 4 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 5 | # for risk computation using automatic differentiation. It uses XAD, 6 | # a fast and comprehensive C++ library for automatic differentiation. 7 | # 8 | # Copyright (C) 2010-2024 Xcelerit Computing Ltd. 9 | # 10 | # This program is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published 12 | # by the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with this program. If not, see . 22 | # 23 | ############################################################################## 24 | 25 | [tool.poetry] 26 | name = "QuantLib-Risks" 27 | version = "@PACKAGE_VERSION@" 28 | description = "Fast risks calculations in QuantLib" 29 | authors = [ 30 | "Auto Differentiation Dev Team ", 31 | "QuantLib Team " 32 | ] 33 | readme = "README.md" 34 | homepage = "https://auto-differentiation.github.io" 35 | repository = "https://github.com/auto-differentiation/QuantLib-Risks-Py" 36 | documentation = "https://auto-differentiation.github.io/quantlib-risks" 37 | keywords = [ 38 | "automatic-differentiation", 39 | "derivatives", 40 | "risk-management", 41 | "quant-finance", 42 | "greeks", 43 | "risks" 44 | ] 45 | classifiers = [ 46 | "Development Status :: 5 - Production/Stable", 47 | "Intended Audience :: Developers", 48 | "Intended Audience :: Education", 49 | "Intended Audience :: Financial and Insurance Industry", 50 | "Intended Audience :: Science/Research", 51 | "Intended Audience :: End Users/Desktop", 52 | "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", 53 | "License :: Other/Proprietary License", 54 | "Operating System :: MacOS :: MacOS X", 55 | "Operating System :: Microsoft :: Windows", 56 | "Operating System :: POSIX :: Linux", 57 | "Natural Language :: English", 58 | "Programming Language :: Python :: 3.8", 59 | "Programming Language :: Python :: 3.9", 60 | "Programming Language :: Python :: 3.10", 61 | "Programming Language :: Python :: 3.11", 62 | "Programming Language :: Python :: 3.12", 63 | "Programming Language :: Python :: Implementation :: CPython", 64 | "Topic :: Scientific/Engineering", 65 | "Topic :: Software Development" 66 | ] 67 | license = "AGPL-3.0-or-later" 68 | packages = [ 69 | { include = "QuantLib_Risks" } 70 | ] 71 | exclude = [ 72 | "QuantLib_Risks/CMakeFiles", 73 | "QuantLib_Risks/*.cmake", 74 | "QuantLib_Risks/*.cxx", 75 | ] 76 | 77 | [tool.poetry.urls] 78 | download = "https://pypi.org/project/QuantLib-Risks/#files" 79 | tracker = "https://github.com/auto-differentiation/QuantLib-Risks-Py/issues" 80 | 81 | [tool.poetry.build] 82 | script = "build_extensions.py" 83 | generate-setup-file = false 84 | 85 | [tool.poetry.dependencies] 86 | python = ">=3.8.1,<4.0" 87 | xad = ">=1.5.2" 88 | 89 | 90 | [build-system] 91 | requires = [ 92 | "poetry-core>=1.0.0", 93 | "setuptools>=42" 94 | ] 95 | build-backend = "poetry.core.masonry.api" 96 | 97 | -------------------------------------------------------------------------------- /Python/run_tests.bat: -------------------------------------------------------------------------------- 1 | :: ############################################################################# 2 | :: 3 | :: 4 | :: This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 5 | :: for risk computation using automatic differentiation. It uses XAD, 6 | :: a fast and comprehensive C++ library for automatic differentiation. 7 | :: 8 | :: Copyright (C) 2010-2024 Xcelerit Computing Ltd. 9 | :: 10 | :: This program is free software: you can redistribute it and/or modify 11 | :: it under the terms of the GNU Affero General Public License as published 12 | :: by the Free Software Foundation, either version 3 of the License, or 13 | :: (at your option) any later version. 14 | :: 15 | :: This program is distributed in the hope that it will be useful, 16 | :: but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | :: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | :: GNU Affero General Public License for more details. 19 | :: 20 | :: You should have received a copy of the GNU Affero General Public License 21 | :: along with this program. If not, see . 22 | :: 23 | :: ############################################################################# 24 | 25 | @echo on 26 | 27 | 28 | "C:\Program Files\Git\bin\bash.exe" "%~dp0\run_tests.sh" || exit 1 -------------------------------------------------------------------------------- /Python/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ############################################################################## 4 | # 5 | # 6 | # This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 7 | # for risk computation using automatic differentiation. It uses XAD, 8 | # a fast and comprehensive C++ library for automatic differentiation. 9 | # 10 | # Copyright (C) 2010-2024 Xcelerit Computing Ltd. 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU Affero General Public License as published 14 | # by the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU Affero General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Affero General Public License 23 | # along with this program. If not, see . 24 | # 25 | ############################################################################## 26 | 27 | set -e 28 | 29 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 30 | 31 | python "${SCRIPT_DIR}/test/QuantLibTestSuite.py" 32 | 33 | cd "${SCRIPT_DIR}/examples" 34 | 35 | had_errors=0 36 | for f in "swap-adjoint.py" "swap.py" "multicurve-bootstrapping.py" ; do 37 | echo "" 38 | echo "----------- RUNNING $f ----------------" 39 | python "$f" || had_errors=1 40 | done 41 | 42 | if [ "$had_errors" == "1" ] ; then 43 | echo "there were errors" 44 | exit 1 45 | fi 46 | -------------------------------------------------------------------------------- /Python/test/QuantLibTestSuite.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2009 Joseph Malicki 4 | Copyright (C) 2024 Xcelerit Computing Limited. 5 | 6 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 7 | for risk computation using automatic differentiation. It uses XAD, 8 | a fast and comprehensive C++ library for automatic differentiation. 9 | 10 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published 12 | by the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | QuantLib-Risks is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | QuantLib is free software: you can redistribute it and/or modify it 24 | under the terms of the QuantLib license. You should have received a 25 | copy of the license along with this program; if not, please email 26 | . The license is also available online at 27 | . 28 | 29 | This program is distributed in the hope that it will be useful, but WITHOUT 30 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 31 | FOR A PARTICULAR PURPOSE. See the license for more details. 32 | """ 33 | 34 | import os 35 | import sys 36 | import unittest 37 | 38 | import QuantLib_Risks as ql 39 | 40 | 41 | def test(): 42 | print('testing QuantLib_Risks', ql.__version__) 43 | sys.argv[1:1] = ['discover', '-s', os.path.dirname(__file__)] 44 | unittest.main(module=None, verbosity=2) 45 | 46 | 47 | if __name__ == '__main__': 48 | test() 49 | -------------------------------------------------------------------------------- /Python/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auto-differentiation/QuantLib-Risks-Py/30235106779882720d2adf154f78e1f322922b1e/Python/test/__init__.py -------------------------------------------------------------------------------- /Python/test/test_americanquantooption.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Klaus Spanderen 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import unittest 34 | import QuantLib_Risks as ql 35 | 36 | class AmericanQuantoOptionTest(unittest.TestCase): 37 | def setUp(self): 38 | self.today = ql.Date(21, ql.April, 2019) 39 | self.dc = ql.Actual365Fixed() 40 | ql.Settings.instance().evaluationDate = self.today 41 | 42 | self.domesticTS = ql.FlatForward(self.today, 0.025, self.dc) 43 | self.foreignTS = ql.FlatForward(self.today, 0.075, self.dc) 44 | self.fxVolTS = ql.BlackConstantVol(self.today, ql.TARGET(), 0.15, self.dc) 45 | 46 | self.quantoHelper = ql.FdmQuantoHelper( 47 | self.domesticTS, self.foreignTS, self.fxVolTS, -0.75, 1.0) 48 | 49 | self.divYieldTS = ql.FlatForward(self.today, 0.03, self.dc) 50 | 51 | divDate = ql.DateVector() 52 | divDate.push_back(self.today + ql.Period(6, ql.Months)) 53 | 54 | divAmount = ql.DoubleVector() 55 | divAmount.push_back(8.0) 56 | 57 | maturityDate = self.today + ql.Period(9, ql.Months) 58 | 59 | self.option = ql.DividendVanillaOption( 60 | ql.PlainVanillaPayoff(ql.Option.Call, 105), 61 | ql.AmericanExercise(self.today, maturityDate), 62 | divDate, 63 | divAmount) 64 | 65 | 66 | def tearDown(self): 67 | ql.Settings.instance().evaluationDate = ql.Date() 68 | 69 | def testAmericanBSQuantoOption(self): 70 | """ Testing American Black-Scholes quanto option """ 71 | 72 | volTS = ql.BlackConstantVol(self.today, ql.TARGET(), 0.3, self.dc) 73 | 74 | bsmProcess = ql.BlackScholesMertonProcess( 75 | ql.QuoteHandle(ql.SimpleQuote(100)), 76 | ql.YieldTermStructureHandle(self.divYieldTS), 77 | ql.YieldTermStructureHandle(self.domesticTS), 78 | ql.BlackVolTermStructureHandle(volTS)) 79 | 80 | fdmBlackScholesEngine = ql.FdBlackScholesVanillaEngine( 81 | bsmProcess, self.quantoHelper, 100, 400, 1) 82 | 83 | self.option.setPricingEngine(fdmBlackScholesEngine) 84 | 85 | fdmPrice = self.option.NPV() 86 | expected = 8.90611734 87 | 88 | self.assertAlmostEqual(fdmPrice, expected, 3, 89 | msg="Unable to reproduce American BS quanto option price.") 90 | 91 | 92 | def testAmericanHestonQuantoOption(self): 93 | """ Testing American Heston quanto option """ 94 | 95 | hestonModel = ql.HestonModel( 96 | ql.HestonProcess( 97 | ql.YieldTermStructureHandle(self.domesticTS), 98 | ql.YieldTermStructureHandle(self.divYieldTS), 99 | ql.QuoteHandle(ql.SimpleQuote(100)), 100 | 0.09, 1.0, 0.09, 1e-4, 0.0)) 101 | 102 | fdmHestonVanillaEngine = ql.FdHestonVanillaEngine( 103 | hestonModel, self.quantoHelper, 100, 400, 3, 1) 104 | 105 | self.option.setPricingEngine(fdmHestonVanillaEngine) 106 | 107 | fdmPrice = self.option.NPV() 108 | expected = 8.90611734 109 | 110 | self.assertAlmostEqual(fdmPrice, expected, 3, 111 | msg="Unable to reproduce American Heston quanto option price.") 112 | 113 | 114 | if __name__ == '__main__': 115 | print("testing QuantLib", ql.__version__) 116 | unittest.main(verbosity=2) 117 | -------------------------------------------------------------------------------- /Python/test/test_calendars.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2023 Skandinaviska Enskilda Banken AB (publ) 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | import itertools 33 | import unittest 34 | 35 | import QuantLib_Risks as ql 36 | 37 | 38 | class JointCalendarTest(unittest.TestCase): 39 | 40 | def test_joint_calendar_holidays(self): 41 | base_calendars = [ql.Sweden(), ql.Denmark(), ql.Finland(), ql.Norway(), ql.Iceland()] 42 | joint_nordics = ql.JointCalendar(base_calendars) 43 | start_date = ql.Date(1, ql.January, 2023) 44 | end_date = ql.Date(31, ql.December, 2023) 45 | 46 | joint_holidays = set(joint_nordics.holidayList(start_date, end_date)) 47 | base_holidays = [calendar.holidayList(start_date, end_date) for calendar in base_calendars] 48 | base_holidays = set(itertools.chain.from_iterable(base_holidays)) 49 | for holiday in base_holidays: 50 | self.assertIn(holiday, joint_holidays) 51 | 52 | 53 | class ResetBespokeCalendarTest(unittest.TestCase): 54 | 55 | def test_reset_added_holidays(self): 56 | calendar = ql.BespokeCalendar("bespoke thing") 57 | 58 | test_date: ql.Date = ql.Date(1, ql.January, 2024) 59 | self.assertFalse(calendar.isHoliday(test_date)) 60 | calendar.addHoliday(test_date) 61 | self.assertTrue(calendar.isHoliday(test_date)) 62 | # TODO: Can extend test with this, if exposed: 63 | # self.assertEqual(len(calendar.addedHolidays()), 1) 64 | calendar.resetAddedAndRemovedHolidays() 65 | self.assertFalse(calendar.isHoliday(test_date)) 66 | 67 | 68 | if __name__ == "__main__": 69 | print("testing QuantLib", ql.__version__) 70 | unittest.main(verbosity=2) 71 | -------------------------------------------------------------------------------- /Python/test/test_currencies.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2021 Marcin Rybacki 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import unittest 34 | import QuantLib_Risks as ql 35 | 36 | 37 | class CurrencyTest(unittest.TestCase): 38 | 39 | def test_default_currency_constructor(self): 40 | """Testing default currency constructor""" 41 | fail_msg = "Failed to create default currency." 42 | default_ccy = ql.Currency() 43 | self.assertTrue(default_ccy.empty(), fail_msg) 44 | 45 | def test_eur_constructor(self): 46 | """Testing EUR constructor""" 47 | fail_msg = "Failed to create EUR currency." 48 | eur = ql.EURCurrency() 49 | self.assertFalse(eur.empty(), fail_msg) 50 | 51 | def test_bespoke_currency_constructor(self): 52 | """Testing bespoke currency constructor""" 53 | fail_msg = "Failed to create bespoke currency." 54 | custom_ccy = ql.Currency( 55 | "CCY", "CCY", 100, "#", "", 100, ql.Rounding(), "") 56 | self.assertFalse(custom_ccy.empty(), fail_msg) 57 | 58 | 59 | if __name__ == '__main__': 60 | print("testing QuantLib", ql.__version__) 61 | unittest.main(verbosity=2) 62 | -------------------------------------------------------------------------------- /Python/test/test_date.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import QuantLib_Risks as ql 34 | import unittest 35 | 36 | 37 | class DateTest(unittest.TestCase): 38 | def setUp(self): 39 | pass 40 | 41 | def testArithmetics(self): 42 | "Testing date arithmetics" 43 | today = ql.Date.todaysDate() 44 | date = today - ql.Period(30, ql.Years) 45 | end_date = today + ql.Period(30, ql.Years) 46 | 47 | dold = date.dayOfMonth() 48 | mold = date.month() 49 | yold = date.year() 50 | 51 | while date < end_date: 52 | date += 1 53 | 54 | d = date.dayOfMonth() 55 | m = date.month() 56 | y = date.year() 57 | 58 | # check if skipping any date 59 | if not ( 60 | (d == dold + 1 and m == mold and y == yold) 61 | or (d == 1 and m == mold + 1 and y == yold) 62 | or (d == 1 and m == 1 and y == yold + 1) 63 | ): 64 | self.fail( 65 | """ 66 | wrong day, month, year increment 67 | date: %(t)s 68 | day, month, year: %(d)d, %(m)d, %(y)d 69 | previous: %(dold)d, %(mold)d, %(yold)d 70 | """ 71 | % locals() 72 | ) 73 | dold = d 74 | mold = m 75 | yold = y 76 | 77 | def testHolidayList(self): 78 | """ Testing Calendar testHolidayList() method. """ 79 | holidayLstFunction = ql.Calendar.holidayList(ql.Poland(), ql.Date(31, 12, 2014), ql.Date(3, 4, 2015), False) 80 | holidayLstManual = (ql.Date(1, 1, 2015), ql.Date(6, 1, 2015)) 81 | # check if dates both from function and from manual imput are the same 82 | self.assertTrue(all([(a == b) for a, b in zip(holidayLstFunction, holidayLstManual)])) 83 | 84 | def tearDown(self): 85 | pass 86 | 87 | 88 | if __name__ == "__main__": 89 | print("testing QuantLib", ql.__version__) 90 | unittest.main(verbosity=2) 91 | -------------------------------------------------------------------------------- /Python/test/test_daycounters.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 3 | for risk computation using automatic differentiation. It uses XAD, 4 | a fast and comprehensive C++ library for automatic differentiation. 5 | 6 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Affero General Public License as published 8 | by the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | QuantLib-Risks is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Affero General Public License for more details. 15 | 16 | You should have received a copy of the GNU Affero General Public License 17 | along with this program. If not, see . 18 | 19 | QuantLib is free software: you can redistribute it and/or modify it 20 | under the terms of the QuantLib license. You should have received a 21 | copy of the license along with this program; if not, please email 22 | . The license is also available online at 23 | . 24 | 25 | This program is distributed in the hope that it will be useful, but WITHOUT 26 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 27 | FOR A PARTICULAR PURPOSE. See the license for more details. 28 | """ 29 | 30 | import QuantLib_Risks as ql 31 | import unittest 32 | 33 | 34 | class DayCountersTest(unittest.TestCase): 35 | def test_bus252(self): 36 | """Test Business252 daycounter""" 37 | 38 | calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) 39 | 40 | # 41 | # Check that SWIG signature for Business252 calendar allows to 42 | # pass custom calendar into the class constructor. Old 43 | # QuantLib-SWIG versions allow only to create Business252 44 | # calendar with default constructor parameter (Brazil 45 | # calendar), and generate an exception when trying to pass a 46 | # custom calendar as a parameter. So we just check here that 47 | # no exception occurs. 48 | # 49 | ql.Business252(calendar) 50 | 51 | 52 | if __name__ == "__main__": 53 | print("testing QuantLib", ql.__version__) 54 | unittest.main(verbosity=2) 55 | -------------------------------------------------------------------------------- /Python/test/test_equityindex.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2023 Marcin Rybacki 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import QuantLib_Risks as ql 34 | import unittest 35 | 36 | 37 | EPSILON = 1.e-2 38 | 39 | CAL = ql.TARGET() 40 | DCT = ql.Actual365Fixed() 41 | VALUATION_DATE = CAL.adjust(ql.Date(31, ql.January, 2023)) 42 | 43 | 44 | def flat_rate(rate): 45 | return ql.FlatForward( 46 | 2, CAL, ql.QuoteHandle(ql.SimpleQuote(rate)), DCT) 47 | 48 | 49 | class EquityIndexTest(unittest.TestCase): 50 | def setUp(self): 51 | ql.Settings.instance().evaluationDate = VALUATION_DATE 52 | 53 | self.interest_handle = ql.YieldTermStructureHandle(flat_rate(0.03)) 54 | self.dividend_handle = ql.YieldTermStructureHandle(flat_rate(0.01)) 55 | spot_handle = ql.QuoteHandle(ql.SimpleQuote(8690.0)) 56 | 57 | ql.IndexManager.instance().clearHistory("eq_idx") 58 | self.equity_idx = ql.EquityIndex( 59 | "eq_idx", CAL, self.interest_handle, self.dividend_handle, spot_handle) 60 | 61 | def test_equity_index_inspectors(self): 62 | """Testing equity index inspectors""" 63 | fail_msg = "Unable to replicate the properties of an equity index." 64 | 65 | self.assertEqual(self.equity_idx.name(), "eq_idx", msg=fail_msg) 66 | self.assertEqual(self.equity_idx.fixingCalendar(), CAL, msg=fail_msg) 67 | 68 | def test_equity_index_projections(self): 69 | """Testing equity index projections""" 70 | fail_msg = "Failed to calculate the expected index projection." 71 | 72 | self.assertAlmostEqual( 73 | self.equity_idx.fixing(VALUATION_DATE), 8690.0, delta=EPSILON, msg=fail_msg) 74 | 75 | future_dt = ql.Date(20, ql.May, 2030) 76 | self.assertAlmostEqual( 77 | self.equity_idx.fixing(future_dt), 10055.76, delta=EPSILON, msg=fail_msg) 78 | 79 | 80 | if __name__ == '__main__': 81 | print("testing QuantLib", ql.__version__) 82 | unittest.main(verbosity=2) 83 | -------------------------------------------------------------------------------- /Python/test/test_extrapolation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Klaus Spanderen 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import unittest 34 | 35 | import QuantLib_Risks as ql 36 | if ql.XAD_ENABLED: 37 | from xad import math 38 | else: 39 | import math 40 | 41 | 42 | class ExtrapolationTest(unittest.TestCase): 43 | def testKnownExpExtrapolation(self): 44 | """Testing Richardson extrapolation of e^x at x->1 with known order of convergence""" 45 | f = lambda x: math.exp(1+x) 46 | x = ql.RichardsonExtrapolation(f, 0.01, 1.0)(4.0) 47 | 48 | self.assertAlmostEqual(x, math.exp(1), 4, 49 | msg="Unable to extrapolate exp(x) at x->1") 50 | 51 | def testUnknownExpExtrapolation(self): 52 | """Testing Richardson extrapolation of e^x at x->1 with unknown order of convergence""" 53 | f = lambda x: math.exp(1+x) 54 | x = ql.RichardsonExtrapolation(f, 0.01)(4.0, 2.0) 55 | 56 | self.assertAlmostEqual(x, math.exp(1), 4, 57 | msg="Unable to extrapolate exp(x) at x->1") 58 | 59 | 60 | if __name__ == "__main__": 61 | print("testing QuantLib", ql.__version__) 62 | unittest.main(verbosity=2) 63 | -------------------------------------------------------------------------------- /Python/test/test_iborindex.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8-unix 2 | """ 3 | Copyright (C) 2018 Wojciech Ślusarski 4 | Copyright (C) 2024 Xcelerit Computing Limited. 5 | 6 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 7 | for risk computation using automatic differentiation. It uses XAD, 8 | a fast and comprehensive C++ library for automatic differentiation. 9 | 10 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published 12 | by the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | QuantLib-Risks is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | QuantLib is free software: you can redistribute it and/or modify it 24 | under the terms of the QuantLib license. You should have received a 25 | copy of the license along with this program; if not, please email 26 | . The license is also available online at 27 | . 28 | 29 | This program is distributed in the hope that it will be useful, but WITHOUT 30 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 31 | FOR A PARTICULAR PURPOSE. See the license for more details. 32 | """ 33 | 34 | import QuantLib_Risks as ql 35 | import unittest 36 | 37 | 38 | class IborIndexTest(unittest.TestCase): 39 | @classmethod 40 | def setUpClass(cls): 41 | cls.euribor3m = ql.Euribor3M() 42 | 43 | def setUp(self): 44 | self.euribor3m.clearFixings() 45 | # values are not real due to copyrights of the fixing 46 | self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.3) 47 | self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.3, -0.3]) 48 | 49 | def testAddFixingFail(self): 50 | """Testing for RuntimeError while trying to overwrite fixing value""" 51 | 52 | with self.assertRaises(RuntimeError): 53 | # attempt to overwrite value that is already set at different level 54 | self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.4) 55 | 56 | with self.assertRaises(RuntimeError): 57 | # attempt to overwrite value that is already set at different level 58 | self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.4, -0.4]) 59 | 60 | def testAddFixing(self): 61 | """Testing for overwriting fixing value""" 62 | 63 | force_overwrite = True 64 | try: 65 | # attempt to overwrite value that is already set at different level 66 | self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.4, force_overwrite) 67 | self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.4, -0.4], force_overwrite) 68 | # try clearFixings and repeat with original levels 69 | self.euribor3m.clearFixings() 70 | self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.3) 71 | self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.3, -0.3]) 72 | 73 | except RuntimeError as err: 74 | raise AssertionError("Failed to overwrite index fixixng " + "{}".format(err)) 75 | 76 | def testTimeSeries(self): 77 | """Testing for getting time series of the fixing""" 78 | 79 | dates = (ql.Date(12, 7, 2018), ql.Date(13, 7, 2018), ql.Date(17, 7, 2018)) 80 | values = (-0.3, -0.3, -0.3) 81 | for expected, actual in zip(dates, self.euribor3m.timeSeries().dates()): 82 | self.assertTrue(expected == actual) 83 | for expected, actual in zip(values, self.euribor3m.timeSeries().values()): 84 | self.assertTrue(expected == actual) 85 | 86 | 87 | if __name__ == "__main__": 88 | print("testing QuantLib", ql.__version__) 89 | unittest.main(verbosity=2) 90 | -------------------------------------------------------------------------------- /Python/test/test_instruments.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import QuantLib_Risks as ql 34 | import unittest 35 | 36 | flag = None 37 | 38 | 39 | def raiseFlag(): 40 | global flag 41 | flag = 1 42 | 43 | 44 | class InstrumentTest(unittest.TestCase): 45 | def testObservable(self): 46 | "Testing observability of stocks" 47 | global flag 48 | flag = None 49 | me1 = ql.SimpleQuote(0.0) 50 | h = ql.RelinkableQuoteHandle(me1) 51 | s = ql.Stock(h) 52 | s.NPV() 53 | 54 | obs = ql.Observer(raiseFlag) 55 | obs.registerWith(s) 56 | 57 | me1.setValue(3.14) 58 | if not flag: 59 | self.fail("Observer was not notified of instrument change") 60 | 61 | s.NPV() 62 | flag = None 63 | me2 = ql.SimpleQuote(0.0) 64 | h.linkTo(me2) 65 | if not flag: 66 | self.fail("Observer was not notified of instrument change") 67 | 68 | s.NPV() 69 | flag = None 70 | s.freeze() 71 | me2.setValue(2.71) 72 | if flag: 73 | self.fail("Observer was notified of frozen instrument change") 74 | s.unfreeze() 75 | if not flag: 76 | self.fail("Observer was not notified of instrument change") 77 | 78 | 79 | if __name__ == "__main__": 80 | print("testing QuantLib", ql.__version__) 81 | unittest.main(verbosity=2) 82 | -------------------------------------------------------------------------------- /Python/test/test_integrals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import QuantLib_Risks as ql 34 | import unittest 35 | if ql.XAD_ENABLED: 36 | from xad import math 37 | else: 38 | import math 39 | 40 | 41 | class IntegralTest(unittest.TestCase): 42 | def Gauss(self, x): 43 | return math.exp(-x * x / 2.0) / math.sqrt(2 * math.pi) 44 | 45 | def singleTest(self, I): 46 | tolerance = 1e-4 47 | cases = [ 48 | ["f(x) = 1", lambda x: 1, 0.0, 1.0, 1.0], 49 | ["f(x) = x", lambda x: x, 0.0, 1.0, 0.5], 50 | ["f(x) = x^2", lambda x: x * x, 0.0, 1.0, 1.0 / 3.0], 51 | ["f(x) = sin(x)", math.sin, 0.0, math.pi, 2.0], 52 | ["f(x) = cos(x)", math.cos, 0.0, math.pi, 0.0], 53 | ["f(x) = Gauss(x)", self.Gauss, -10.0, 10.0, 1.0], 54 | ] 55 | 56 | for tag, f, a, b, expected in cases: 57 | calculated = I(f, a, b) 58 | if not (abs(calculated - expected) <= tolerance): 59 | self.fail( 60 | """ 61 | integrating %(tag)s 62 | calculated: %(calculated)f 63 | expected : %(expected)f 64 | """ 65 | % locals() 66 | ) 67 | 68 | def testSegment(self): 69 | "Testing segment integration" 70 | self.singleTest(ql.SegmentIntegral(10000)) 71 | 72 | def testTrapezoid(self): 73 | "Testing trapezoid integration" 74 | self.singleTest(ql.TrapezoidIntegralDefault(1.0e-4, 1000)) 75 | 76 | def testSimpson(self): 77 | "Testing Simpson integration" 78 | self.singleTest(ql.SimpsonIntegral(1.0e-4, 1000)) 79 | 80 | def testKronrod(self): 81 | "Testing Gauss-Kronrod integration" 82 | self.singleTest(ql.GaussKronrodAdaptive(1.0e-4)) 83 | 84 | 85 | if __name__ == "__main__": 86 | print("testing QuantLib", ql.__version__) 87 | unittest.main(verbosity=2) 88 | -------------------------------------------------------------------------------- /Python/test/test_marketelements.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import QuantLib_Risks as ql 34 | import unittest 35 | 36 | flag = None 37 | 38 | 39 | def raiseFlag(): 40 | global flag 41 | flag = 1 42 | 43 | 44 | class MarketElementTest(unittest.TestCase): 45 | def testObservable(self): 46 | "Testing observability of market elements" 47 | global flag 48 | flag = None 49 | me = ql.SimpleQuote(0.0) 50 | obs = ql.Observer(raiseFlag) 51 | obs.registerWith(me) 52 | me.setValue(3.14) 53 | if not flag: 54 | self.fail("Observer was not notified of market element change") 55 | 56 | def testObservableHandle(self): 57 | "Testing observability of market element handles" 58 | global flag 59 | flag = None 60 | me1 = ql.SimpleQuote(0.0) 61 | h = ql.RelinkableQuoteHandle(me1) 62 | obs = ql.Observer(raiseFlag) 63 | obs.registerWith(h) 64 | me1.setValue(3.14) 65 | if not flag: 66 | self.fail("Observer was not notified of market element change") 67 | flag = None 68 | me2 = ql.SimpleQuote(0.0) 69 | h.linkTo(me2) 70 | if not flag: 71 | self.fail("Observer was not notified of market element change") 72 | 73 | 74 | if __name__ == "__main__": 75 | print("testing QuantLib", ql.__version__) 76 | unittest.main(verbosity=2) 77 | -------------------------------------------------------------------------------- /Python/test/test_ode.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Klaus Spanderen 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import unittest 34 | 35 | import QuantLib_Risks as ql 36 | if ql.XAD_ENABLED: 37 | from xad import math 38 | else: 39 | import math 40 | 41 | class OdeTest(unittest.TestCase): 42 | 43 | def test1dODE(self): 44 | """ Testing one dimesnional ODE """ 45 | 46 | yEnd = ql.RungeKutta(1e-8)(lambda x, y : y, 1, 0, 1) 47 | 48 | self.assertAlmostEqual(yEnd, math.exp(1), 5, 49 | msg="Unable to reproduce one dimensional ODE solution.") 50 | 51 | 52 | def test2dODE(self): 53 | """ Testing multi-dimesnional ODE """ 54 | 55 | yEnd = ql.RungeKutta(1e-8)(lambda x, y : [y[1], -y[0]], 56 | [0, 1], 0, 0.5*math.pi)[0] 57 | 58 | self.assertAlmostEqual(yEnd, 1.0, 5, 59 | msg="Unable to reproduce multi-dimensional ODE solution.") 60 | 61 | 62 | if __name__ == '__main__': 63 | print("testing QuantLib", ql.__version__) 64 | unittest.main(verbosity=2) 65 | -------------------------------------------------------------------------------- /Python/test/test_solvers1d.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2024 Xcelerit Computing Limited. 4 | 5 | This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 6 | for risk computation using automatic differentiation. It uses XAD, 7 | a fast and comprehensive C++ library for automatic differentiation. 8 | 9 | QuantLib-Risks and XAD are free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Affero General Public License as published 11 | by the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | QuantLib-Risks is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Affero General Public License for more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with this program. If not, see . 21 | 22 | QuantLib is free software: you can redistribute it and/or modify it 23 | under the terms of the QuantLib license. You should have received a 24 | copy of the license along with this program; if not, please email 25 | . The license is also available online at 26 | . 27 | 28 | This program is distributed in the hope that it will be useful, but WITHOUT 29 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 30 | FOR A PARTICULAR PURPOSE. See the license for more details. 31 | """ 32 | 33 | import unittest 34 | import QuantLib_Risks as ql 35 | 36 | 37 | class Foo: 38 | def __call__(self, x): 39 | return x * x - 1.0 40 | 41 | def derivative(self, x): 42 | return 2.0 * x 43 | 44 | 45 | class Solver1DTest(unittest.TestCase): 46 | def test_solve(self): 47 | "Testing 1-D solvers" 48 | for factory in [ql.Brent, ql.Bisection, ql.FalsePosition, ql.Ridder, ql.Secant]: 49 | solver = factory() 50 | for accuracy in [1.0e-4, 1.0e-6, 1.0e-8]: 51 | root = solver.solve(lambda x: x * x - 1.0, accuracy, 1.5, 0.1) 52 | if not (abs(root - 1.0) < accuracy): 53 | self.fail( 54 | """ 55 | %(factory)s 56 | solve(): 57 | expected: 1.0 58 | calculated root: %(root)g 59 | accuracy: %(accuracy)s 60 | """ 61 | % locals() 62 | ) 63 | root = solver.solve(lambda x: x * x - 1.0, accuracy, 1.5, 0.0, 1.0) 64 | if not (abs(root - 1.0) < accuracy): 65 | self.fail( 66 | """ 67 | %(factory)s 68 | bracketed solve(): 69 | expected: 1.0 70 | calculated root: %(root)g 71 | accuracy: %(accuracy)s 72 | """ 73 | % locals() 74 | ) 75 | for factory in [ql.Newton, ql.NewtonSafe]: 76 | solver = factory() 77 | for accuracy in [1.0e-4, 1.0e-6, 1.0e-8]: 78 | root = solver.solve(Foo(), accuracy, 1.5, 0.1) 79 | if not (abs(root - 1.0) < accuracy): 80 | self.fail( 81 | """ 82 | %(factory)s 83 | solve(): 84 | expected: 1.0 85 | calculated root: %(root)g 86 | accuracy: %(accuracy)s 87 | """ 88 | % locals() 89 | ) 90 | root = solver.solve(Foo(), accuracy, 1.5, 0.0, 1.0) 91 | if not (abs(root - 1.0) < accuracy): 92 | self.fail( 93 | """ 94 | %(factory)s 95 | bracketed solve(): 96 | expected: 1.0 97 | calculated root: %(root)g 98 | accuracy: %(accuracy)s 99 | """ 100 | % locals() 101 | ) 102 | 103 | 104 | if __name__ == "__main__": 105 | print("testing QuantLib", ql.__version__) 106 | unittest.main(verbosity=2) 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | QuantLib-Risks: Risk-enabled QuantLib for Python 3 | ================================================ 4 | 5 | [![Download source](https://img.shields.io/github/v/release/auto-differentiation/QuantLib-Risks-Py?label=source&sort=semver)](https://github.com/auto-differentiation/QuantLib-Risks-Py/releases/latest) 6 | [![PyPI version](https://img.shields.io/pypi/v/QuantLib-Risks?label=PyPI)](https://pypi.org/project/QuantLib-Risks) 7 | 8 | --- 9 | 10 | This repository builds QuantLib Python bindings with automatic differentiation, enabling 11 | fast risks calculation with QuantLib in Python. 12 | It wraps [C++ QuantLib-Risks](https://github.com/auto-differentiation/QuantLib-Risks-Cpp) 13 | in Python. 14 | It uses elements from [QuantLib-SWIG](https://github.com/lballabio/QuantLib-SWIG) and 15 | is kept in sync with it. 16 | 17 | ## Getting Started 18 | 19 | You can install it as: 20 | 21 | ``` 22 | pip install QuantLib-Risks 23 | ``` 24 | 25 | ## Getting Help 26 | 27 | For documentation and other resources, see https://auto-differentiation.github.io/quantlib-risks/python/ . 28 | 29 | If you have found an issue, want to report a bug, or have a feature request, please raise a [GitHub issue](https://github.com/auto-differentiation/QuantLib-Risks-Py/issues). 30 | 31 | ## Related Projects 32 | 33 | - XAD Comprehensive automatic differentiation in [Python](https://github.com/auto-differentiation/xad-py) and [C++](https://github.com/auto-differentiation/xad) 34 | - QuantLib-Risks: Fast risk evaluations in [Python](https://github.com/auto-differentiation/QuantLib-Risks-Py) and [C++](https://github.com/auto-differentiation/QuantLib-Risks-Cpp) 35 | 36 | ## Contributing 37 | 38 | Please read [CONTRIBUTING](CONTRIBUTING.md) for the process of contributing to this project. 39 | Please also obey our [Code of Conduct](CODE_OF_CONDUCT.md) in all communication. 40 | 41 | ## Versioning 42 | 43 | This repository follows the QuantLib versions closely. With each new QuantLib release, 44 | a new release of QuantLib-Risks is prepared with the same version number. 45 | 46 | ## License 47 | 48 | This project is licensed under the GNU Affero General Public License - see the [LICENSE.md](LICENSE.md) file for details. 49 | 50 | It contains code from [QuantLib](https://www.quantlib.org) 51 | and [QuantLib-SWIG](https://github.com/lballabio/QuantLib-SWIG), 52 | which are shipped with a different (compatible) license. 53 | Both licenses are included in [LICENSE.md](LICENSE.md) 54 | -------------------------------------------------------------------------------- /SWIG/calibratedmodel.i: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 3 | Copyright (C) 2003, 2007, 2009 StatPro Italia srl 4 | Copyright (C) 2005 Dominic Thuillier 5 | Copyright (C) 2007 Luis Cota 6 | Copyright (C) 2016 Gouthaman Balaraman 7 | Copyright (C) 2016 Peter Caspers 8 | Copyright (C) 2018 Matthias Lungwitz 9 | 10 | This file is part of QuantLib, a free-software/open-source library 11 | for financial quantitative analysts and developers - http://quantlib.org/ 12 | 13 | QuantLib is free software: you can redistribute it and/or modify it 14 | under the terms of the QuantLib license. You should have received a 15 | copy of the license along with this program; if not, please email 16 | . The license is also available online at 17 | . 18 | 19 | This program is distributed in the hope that it will be useful, but WITHOUT 20 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 21 | FOR A PARTICULAR PURPOSE. See the license for more details. 22 | */ 23 | 24 | #ifndef quantlib_calibrated_model_i 25 | #define quantlib_calibrated_model_i 26 | 27 | %include termstructures.i 28 | %include optimizers.i 29 | %include linearalgebra.i 30 | %include types.i 31 | %include vectors.i 32 | 33 | %{ 34 | using QuantLib::CalibrationHelper; 35 | %} 36 | 37 | // calibration helpers 38 | %shared_ptr(CalibrationHelper) 39 | class CalibrationHelper { 40 | public: 41 | Real calibrationError(); 42 | private: 43 | CalibrationHelper(); 44 | }; 45 | 46 | 47 | // allow use of vectors of helpers 48 | #if defined(SWIGCSHARP) 49 | SWIG_STD_VECTOR_ENHANCED( ext::shared_ptr ) 50 | #endif 51 | namespace std { 52 | %template(CalibrationHelperVector) vector >; 53 | } 54 | 55 | // the base class for calibrated models 56 | %{ 57 | using QuantLib::CalibratedModel; 58 | using QuantLib::TermStructureConsistentModel; 59 | %} 60 | 61 | %shared_ptr(CalibratedModel) 62 | class CalibratedModel : public virtual Observable { 63 | #if defined(SWIGCSHARP) 64 | %rename("parameters") params; 65 | #endif 66 | public: 67 | Array params() const; 68 | virtual void calibrate( 69 | const std::vector >&, 70 | OptimizationMethod&, const EndCriteria &, 71 | const Constraint& constraint = Constraint(), 72 | const std::vector& weights = std::vector(), 73 | const std::vector& fixParameters = std::vector()); 74 | 75 | void setParams(const Array& params); 76 | Real value(const Array& params, 77 | const std::vector >&); 78 | const ext::shared_ptr& constraint() const; 79 | EndCriteria::Type endCriteria() const; 80 | const Array& problemValues() const; 81 | Integer functionEvaluation() const; 82 | private: 83 | CalibratedModel(); 84 | }; 85 | 86 | %shared_ptr(TermStructureConsistentModel) 87 | class TermStructureConsistentModel : public virtual Observable{ 88 | public: 89 | const Handle& termStructure() const; 90 | private: 91 | TermStructureConsistentModel(); 92 | }; 93 | 94 | %template(CalibratedModelHandle) Handle; 95 | %template(RelinkableCalibratedModelHandle) RelinkableHandle; 96 | 97 | 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /SWIG/cliquetoptions.i: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2021 Jack Gillett 3 | 4 | This file is part of QuantLib, a free-software/open-source library 5 | for financial quantitative analysts and developers - http://quantlib.org/ 6 | 7 | QuantLib is free software: you can redistribute it and/or modify it 8 | under the terms of the QuantLib license. You should have received a 9 | copy of the license along with this program; if not, please email 10 | . The license is also available online at 11 | . 12 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the license for more details. 16 | */ 17 | 18 | #ifndef quantlib_cliquet_options_i 19 | #define quantlib_cliquet_options_i 20 | 21 | %include options.i 22 | 23 | %{ 24 | using QuantLib::CliquetOption; 25 | %} 26 | 27 | %shared_ptr(CliquetOption) 28 | class CliquetOption : public OneAssetOption { 29 | public: 30 | CliquetOption(const ext::shared_ptr& payoff, 31 | const ext::shared_ptr& maturity, 32 | std::vector resetDates); 33 | }; 34 | 35 | 36 | %{ 37 | using QuantLib::AnalyticCliquetEngine; 38 | using QuantLib::AnalyticPerformanceEngine; 39 | using QuantLib::MCPerformanceEngine; 40 | %} 41 | 42 | 43 | %shared_ptr(AnalyticCliquetEngine) 44 | class AnalyticCliquetEngine : public PricingEngine { 45 | public: 46 | AnalyticCliquetEngine( 47 | const ext::shared_ptr& process); 48 | }; 49 | 50 | 51 | %shared_ptr(AnalyticPerformanceEngine) 52 | class AnalyticPerformanceEngine : public PricingEngine { 53 | public: 54 | AnalyticPerformanceEngine( 55 | const ext::shared_ptr process); 56 | }; 57 | 58 | 59 | %shared_ptr(MCPerformanceEngine); 60 | %shared_ptr(MCPerformanceEngine); 61 | 62 | template 63 | class MCPerformanceEngine : public PricingEngine { 64 | #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) 65 | %feature("kwargs") MCPerformanceEngine; 66 | #endif 67 | public: 68 | %extend { 69 | MCPerformanceEngine(ext::shared_ptr process, 70 | bool brownianBridge = false, 71 | bool antitheticVariate = false, 72 | intOrNull requiredSamples = Null(), 73 | doubleOrNull requiredTolerance = Null(), 74 | intOrNull maxSamples = Null(), 75 | BigInteger seed = 0) { 76 | return new MCPerformanceEngine(process, 77 | brownianBridge, 78 | antitheticVariate, 79 | requiredSamples, 80 | requiredTolerance, 81 | maxSamples, 82 | seed); 83 | } 84 | } 85 | }; 86 | 87 | %template(MCPRPerformanceEngine) MCPerformanceEngine; 88 | %template(MCLDPerformanceEngine) MCPerformanceEngine; 89 | 90 | #if defined(SWIGPYTHON) 91 | %pythoncode %{ 92 | def MCPerformanceEngine(process, 93 | traits, 94 | brownianBridge=False, 95 | antitheticVariate=False, 96 | requiredSamples=None, 97 | requiredTolerance=None, 98 | maxSamples=None, 99 | seed=0): 100 | traits = traits.lower() 101 | if traits == "pr" or traits == "pseudorandom": 102 | cls = MCPRPerformanceEngine 103 | elif traits == "ld" or traits == "lowdiscrepancy": 104 | cls = MCLDPerformanceEngine 105 | else: 106 | raise RuntimeError("unknown MC traits: %s" % traits); 107 | return cls(process, 108 | brownianBridge, 109 | antitheticVariate, 110 | requiredSamples, 111 | requiredTolerance, 112 | maxSamples, 113 | seed) 114 | %} 115 | #endif 116 | 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /SWIG/common.i: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 4 | 5 | This file is part of QuantLib, a free-software/open-source library 6 | for financial quantitative analysts and developers - http://quantlib.org/ 7 | 8 | QuantLib is free software: you can redistribute it and/or modify it 9 | under the terms of the QuantLib license. You should have received a 10 | copy of the license along with this program; if not, please email 11 | . The license is also available online at 12 | . 13 | 14 | This program is distributed in the hope that it will be useful, but WITHOUT 15 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 | FOR A PARTICULAR PURPOSE. See the license for more details. 17 | */ 18 | 19 | #ifndef quantlib_common_i 20 | #define quantlib_common_i 21 | 22 | %{ 23 | namespace QuantLib { namespace ext {} } 24 | namespace ext = QuantLib::ext; 25 | %} 26 | #define SWIG_SHARED_PTR_NAMESPACE ext 27 | 28 | %include stl.i 29 | %include exception.i 30 | %include boost_shared_ptr.i 31 | 32 | %define QL_TYPECHECK_BOOL 7210 %enddef 33 | 34 | %{ 35 | // This is necessary to avoid compile failures on 36 | // GCC 4 37 | // see http://svn.boost.org/trac/boost/ticket/1793 38 | 39 | #if defined(NDEBUG) 40 | #define BOOST_DISABLE_ASSERTS 1 41 | #endif 42 | 43 | #include 44 | %} 45 | 46 | #if defined(SWIGPYTHON) 47 | %typemap(in) ext::optional %{ 48 | if($input == Py_None) 49 | $1 = ext::nullopt; 50 | else if ($input == Py_True) 51 | $1 = true; 52 | else 53 | $1 = false; 54 | %} 55 | %typecheck (QL_TYPECHECK_BOOL) ext::optional { 56 | if (PyBool_Check($input) || Py_None == $input) 57 | $1 = 1; 58 | else 59 | $1 = 0; 60 | } 61 | #else 62 | #if defined(SWIGCSHARP) 63 | %typemap(cscode) ext::optional %{ 64 | public static implicit operator OptionalBool(bool b) => new OptionalBool(b); 65 | %} 66 | #endif 67 | namespace ext { 68 | template 69 | class optional { 70 | public: 71 | optional(T t); 72 | }; 73 | } 74 | %template(OptionalBool) ext::optional; 75 | #endif 76 | 77 | %{ 78 | // generally useful classes 79 | using QuantLib::Error; 80 | using QuantLib::Handle; 81 | using QuantLib::RelinkableHandle; 82 | %} 83 | 84 | namespace ext { 85 | 86 | %extend shared_ptr { 87 | T* operator->() { 88 | return (*self).operator->(); 89 | } 90 | #if defined(SWIGPYTHON) 91 | bool __nonzero__() { 92 | return !!(*self); 93 | } 94 | bool __bool__() { 95 | return !!(*self); 96 | } 97 | #else 98 | bool isNull() { 99 | return !(*self); 100 | } 101 | #endif 102 | } 103 | } 104 | 105 | 106 | template 107 | class Handle { 108 | public: 109 | Handle(const ext::shared_ptr& = ext::shared_ptr()); 110 | ext::shared_ptr operator->(); 111 | ext::shared_ptr currentLink(); 112 | #if defined(SWIGPYTHON) 113 | %extend { 114 | bool __nonzero__() { 115 | return !self->empty(); 116 | } 117 | bool __bool__() { 118 | return !self->empty(); 119 | } 120 | } 121 | #else 122 | bool empty(); 123 | #endif 124 | }; 125 | 126 | template 127 | class RelinkableHandle : public Handle { 128 | public: 129 | RelinkableHandle(const ext::shared_ptr& = ext::shared_ptr()); 130 | void linkTo(const ext::shared_ptr&); 131 | %extend { 132 | // could be defined in C++ class, added here in the meantime 133 | void reset() { 134 | self->linkTo(ext::shared_ptr()); 135 | } 136 | } 137 | }; 138 | 139 | %define swigr_list_converter(ContainerRType, 140 | ContainerCType, ElemCType) 141 | #if defined(SWIGR) 142 | %Rruntime %{ 143 | setMethod('print', 'ContainerCType', 144 | function(x) print(as(x, "ElemCType"))) 145 | 146 | setAs("ContainerCType", "ElemCType", 147 | function(from) {if (from$size()) from[1:from$size()] else NULL} ) 148 | 149 | setAs("ElemCType", "ContainerCType", 150 | function(from) { a <- ContainerRType(length(from)); 151 | sapply(1:length(from), function(n) { 152 | a[n] <- from[n] } ) 153 | a 154 | }) 155 | %} 156 | #endif 157 | %enddef 158 | 159 | 160 | %define deprecate_feature(OldName, NewName) 161 | #if defined(SWIGPYTHON) 162 | %pythoncode %{ 163 | def OldName(*args, **kwargs): 164 | from warnings import warn 165 | warn('%s is deprecated; use %s' % (OldName.__name__, NewName.__name__)) 166 | return NewName(*args, **kwargs) 167 | %} 168 | #endif 169 | %enddef 170 | 171 | 172 | #endif 173 | -------------------------------------------------------------------------------- /SWIG/credit.i: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2008 StatPro Italia srl 3 | 4 | This file is part of QuantLib, a free-software/open-source library 5 | for financial quantitative analysts and developers - http://quantlib.org/ 6 | 7 | QuantLib is free software: you can redistribute it and/or modify it 8 | under the terms of the QuantLib license. You should have received a 9 | copy of the license along with this program; if not, please email 10 | . The license is also available online at 11 | . 12 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | FOR A PARTICULAR PURPOSE. See the license for more details. 16 | */ 17 | 18 | #ifndef quantlib_credit_i 19 | #define quantlib_credit_i 20 | 21 | %include defaultprobability.i 22 | 23 | %{ 24 | using QuantLib::Protection; 25 | %} 26 | 27 | struct Protection { 28 | enum Side { Buyer, Seller }; 29 | }; 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /SWIG/date_extra.i: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Extra type converters for Dates that are needed with QuantLib-Risks in order 3 | * to cover pair and vectors thereof. The functions are declared in 4 | * converters.hpp 5 | * 6 | * This file is part of QuantLib-Risks, a Python wrapper for QuantLib enabled 7 | * for risk computation using automatic differentiation. It uses XAD, 8 | * a fast and comprehensive C++ library for automatic differentiation. 9 | * 10 | * Copyright (C) 2010-2024 Xcelerit Computing Ltd. 11 | * 12 | * This program is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU Affero General Public License as published 14 | * by the Free Software Foundation, either version 3 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU Affero General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Affero General Public License 23 | * along with this program. If not, see . 24 | * 25 | ******************************************************************************/ 26 | 27 | #ifndef quantlib_date_extra_i 28 | #define quantlib_date_extra_i 29 | 30 | %{ 31 | 32 | PyObject* convert_to_SwigDate(const Date& date) { 33 | return SWIG_NewPointerObj( 34 | (new Date(static_cast< const Date& >(date))), 35 | SWIGTYPE_p_Date, 36 | SWIG_POINTER_OWN | 0 ); 37 | } 38 | 39 | Date convert_to_QlDate(PyObject* obj) { 40 | void* argp1 = nullptr; 41 | int res1 = SWIG_ConvertPtr(obj, &argp1,SWIGTYPE_p_Date, 0 | 0 ); 42 | if (!SWIG_IsOK(res1)) { 43 | throw std::runtime_error("error in date conversion"); 44 | } 45 | Date *arg1 = reinterpret_cast(argp1); 46 | return *arg1; 47 | } 48 | 49 | PyObject* make_date_real_pair_tuple(const std::pair& p) { 50 | auto t = PyTuple_New(2); 51 | PyTuple_SET_ITEM(t, 0, convert_to_SwigDate(p.first)); 52 | PyTuple_SET_ITEM(t, 1, make_PyObject(p.second)); 53 | return t; 54 | } 55 | 56 | std::pair make_date_real_pair_from_tuple(PyObject* obj) { 57 | Date d = convert_to_QlDate(PyTuple_GetItem(obj, 0)); 58 | Real r = make_Real(PyTuple_GetItem(obj, 1)); 59 | return {d, r}; 60 | } 61 | 62 | bool check_date_real_pair_input(PyObject* obj) 63 | { 64 | if (!PyTuple_Check(obj)) 65 | return false; 66 | if (PyTuple_Size(obj) != 2) 67 | return false; 68 | if (!check_Real(PyTuple_GetItem(obj, 1))) 69 | return false; 70 | void* argp1 = nullptr; 71 | int res1 = SWIG_ConvertPtr(obj, &argp1,SWIGTYPE_p_Date, 0 | 0 ); 72 | if (!SWIG_IsOK(res1)) 73 | return false; 74 | return true; 75 | } 76 | 77 | %} 78 | 79 | %typemap(in) std::pair { 80 | if (PyTuple_Check($input) && PyTuple_Size($input) == 2) { 81 | $1 = make_date_real_pair_from_tuple($input); 82 | } else { 83 | SWIG_exception(SWIG_TypeError, "Could not convert to date/Real pair") 84 | } 85 | } 86 | 87 | %typemap(in) const std::pair& (std::pair temp) { 88 | if (PyTuple_Check($input) && PyTuple_Size($input) == 2) { 89 | temp = make_date_real_pair_from_tuple($input); 90 | $1 = &temp; 91 | 92 | } else { 93 | SWIG_exception(SWIG_TypeError, "Could not convert to date/Real pair") 94 | } 95 | } 96 | 97 | %typemap(out) std::pair { 98 | $result = make_date_real_pair_tuple($1); 99 | } 100 | 101 | %define QL_TYPECHECK_REALDATEOBJ_PAIR 4993 %enddef 102 | 103 | %typecheck(QL_TYPECHECK_REALDATEOBJ_PAIR) std::pair, const std::pair& { 104 | $1 = check_date_real_pair_input($input) ? 1 : 0; 105 | } 106 | 107 | #endif -------------------------------------------------------------------------------- /SWIG/daycounters.i: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 4 | Copyright (C) 2003, 2004, 2005 StatPro Italia srl 5 | Copyright (C) 2005 Johan Witters 6 | Copyright (C) 2022 Ignacio Anguita 7 | 8 | This file is part of QuantLib, a free-software/open-source library 9 | for financial quantitative analysts and developers - http://quantlib.org/ 10 | 11 | QuantLib is free software: you can redistribute it and/or modify it 12 | under the terms of the QuantLib license. You should have received a 13 | copy of the license along with this program; if not, please email 14 | . The license is also available online at 15 | . 16 | 17 | This program is distributed in the hope that it will be useful, but WITHOUT 18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 | FOR A PARTICULAR PURPOSE. See the license for more details. 20 | */ 21 | 22 | #ifndef quantlib_day_counters_i 23 | #define quantlib_day_counters_i 24 | 25 | %include common.i 26 | %include calendars.i 27 | %include date.i 28 | %include types.i 29 | %include stl.i 30 | %include null.i 31 | 32 | %{ 33 | using QuantLib::DayCounter; 34 | %} 35 | 36 | class DayCounter { 37 | protected: 38 | DayCounter(); 39 | public: 40 | BigInteger dayCount(const Date& d1, const Date& d2) const; 41 | Time yearFraction(const Date& d1, const Date& d2, 42 | const Date& startRef = Date(), 43 | const Date& endRef = Date()) const; 44 | std::string name() const; 45 | %extend { 46 | std::string __str__() { 47 | return self->name()+" day counter"; 48 | } 49 | #if defined(SWIGPYTHON) || defined(SWIGJAVA) 50 | bool __eq__(const DayCounter& other) { 51 | return (*self) == other; 52 | } 53 | bool __ne__(const DayCounter& other) { 54 | return (*self) != other; 55 | } 56 | #endif 57 | } 58 | #if defined(SWIGPYTHON) 59 | %pythoncode %{ 60 | def __hash__(self): 61 | return hash(self.name()) 62 | %} 63 | #endif 64 | }; 65 | 66 | namespace QuantLib { 67 | 68 | class Actual360 : public DayCounter { 69 | public: 70 | Actual360(const bool includeLastDay = false); 71 | }; 72 | class Actual366 : public DayCounter { 73 | public: 74 | Actual366(const bool includeLastDay = false); 75 | }; 76 | class Actual36525 : public DayCounter { 77 | public: 78 | Actual36525(const bool includeLastDay = false); 79 | }; 80 | class Actual364 : public DayCounter {}; 81 | class Actual365Fixed : public DayCounter { 82 | public: 83 | enum Convention { Standard, Canadian, NoLeap }; 84 | Actual365Fixed(Convention c = Standard); 85 | }; 86 | class Thirty360 : public DayCounter { 87 | public: 88 | enum Convention { USA, BondBasis, European, EurobondBasis, Italian, German, ISMA, ISDA, NASD }; 89 | Thirty360(Convention c, const Date& terminationDate = Date()); 90 | }; 91 | class Thirty365 : public DayCounter {}; 92 | class ActualActual : public DayCounter { 93 | public: 94 | enum Convention { ISMA, Bond, ISDA, Historical, Actual365, AFB, Euro }; 95 | ActualActual(Convention c, const Schedule& schedule = Schedule()); 96 | }; 97 | class OneDayCounter : public DayCounter {}; 98 | class SimpleDayCounter : public DayCounter {}; 99 | class Business252 : public DayCounter { 100 | public: 101 | Business252(Calendar c = Brazil()); 102 | }; 103 | 104 | } 105 | 106 | %{ 107 | using QuantLib::yearFractionToDate; 108 | %} 109 | 110 | Date yearFractionToDate( 111 | const DayCounter& dayCounter, const Date& referenceDate, Time t); 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /SWIG/discountcurve.i: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 4 | Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl 5 | Copyright (C) 2015 Matthias Groncki 6 | 7 | This file is part of QuantLib, a free-software/open-source library 8 | for financial quantitative analysts and developers - http://quantlib.org/ 9 | 10 | QuantLib is free software: you can redistribute it and/or modify it 11 | under the terms of the QuantLib license. You should have received a 12 | copy of the license along with this program; if not, please email 13 | . The license is also available online at 14 | . 15 | 16 | This program is distributed in the hope that it will be useful, but WITHOUT 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | FOR A PARTICULAR PURPOSE. See the license for more details. 19 | */ 20 | 21 | #ifndef quantlib_discount_curve_i 22 | #define quantlib_discount_curve_i 23 | 24 | %include termstructures.i 25 | %include interpolation.i 26 | 27 | %{ 28 | using QuantLib::InterpolatedDiscountCurve; 29 | %} 30 | 31 | %shared_ptr(InterpolatedDiscountCurve); 32 | %shared_ptr(InterpolatedDiscountCurve); 33 | %shared_ptr(InterpolatedDiscountCurve); 34 | %shared_ptr(InterpolatedDiscountCurve); 35 | %shared_ptr(InterpolatedDiscountCurve); 36 | %shared_ptr(InterpolatedDiscountCurve); 37 | 38 | template 39 | class InterpolatedDiscountCurve : public YieldTermStructure { 40 | public: 41 | InterpolatedDiscountCurve(const std::vector& dates, 42 | const std::vector& discounts, 43 | const DayCounter& dayCounter, 44 | const Calendar& calendar = Calendar(), 45 | const Interpolator& i = Interpolator()); 46 | const std::vector