pax_global_header00006660000000000000000000000064150374120610014511gustar00rootroot0000000000000052 comment=9c4164cefb8272ed6c08babd2693c2c1f1dc5ea0 QuantLib-SWIG-1.39/000077500000000000000000000000001503741206100137335ustar00rootroot00000000000000QuantLib-SWIG-1.39/.ci/000077500000000000000000000000001503741206100144045ustar00rootroot00000000000000QuantLib-SWIG-1.39/.ci/csharp.build000077500000000000000000000001641503741206100167110ustar00rootroot00000000000000#!/bin/bash set -e ./autogen.sh ./configure CC=clang CXX=clang++ CXXFLAGS='-O2' make -C CSharp SWIGFLAGS='-Werror' QuantLib-SWIG-1.39/.ci/csharp.check000077500000000000000000000000511503741206100166620ustar00rootroot00000000000000#!/bin/bash set -e make -C CSharp check QuantLib-SWIG-1.39/.ci/csharp.install000077500000000000000000000000231503741206100172520ustar00rootroot00000000000000#!/bin/bash set -e QuantLib-SWIG-1.39/.ci/java-new.build000077500000000000000000000005101503741206100171340ustar00rootroot00000000000000#!/bin/bash set -e ./autogen.sh ./configure --disable-java-finalizer --enable-java-autocloseable \ --with-jdk-include=/usr/lib/jvm/default-java/include \ --with-jdk-system-include=/usr/lib/jvm/default-java/include/linux \ CC=clang CXX=clang++ CXXFLAGS='-O2' make -C Java SWIGFLAGS='-Werror' QuantLib-SWIG-1.39/.ci/java-new.check000077500000000000000000000000471503741206100171170ustar00rootroot00000000000000#!/bin/bash set -e make -C Java check QuantLib-SWIG-1.39/.ci/java-new.install000077500000000000000000000000231503741206100175020ustar00rootroot00000000000000#!/bin/bash set -e QuantLib-SWIG-1.39/.ci/java-old.build000077500000000000000000000004051503741206100171240ustar00rootroot00000000000000#!/bin/bash set -e ./autogen.sh ./configure --with-jdk-include=/usr/lib/jvm/default-java/include \ --with-jdk-system-include=/usr/lib/jvm/default-java/include/linux \ CC=clang CXX=clang++ CXXFLAGS='-O2' make -C Java SWIGFLAGS='-Werror' QuantLib-SWIG-1.39/.ci/java-old.check000077500000000000000000000000471503741206100171040ustar00rootroot00000000000000#!/bin/bash set -e make -C Java check QuantLib-SWIG-1.39/.ci/java-old.install000077500000000000000000000000231503741206100174670ustar00rootroot00000000000000#!/bin/bash set -e QuantLib-SWIG-1.39/.ci/python.build000077500000000000000000000003021503741206100167440ustar00rootroot00000000000000#!/bin/bash set -e python3 -m venv .venv . .venv/bin/activate pip install setuptools build tox ./autogen.sh ./configure CC=clang CXX=clang++ CXXFLAGS='-O1' make -C Python SWIGFLAGS='-Werror' QuantLib-SWIG-1.39/.ci/python.check000077500000000000000000000002201503741206100167210ustar00rootroot00000000000000#!/bin/bash set -e . .venv/bin/activate make -C Python check for i in Python/examples/*.py do echo "$i" python "$i" || break -1 done QuantLib-SWIG-1.39/.ci/python.install000077500000000000000000000003041503741206100173150ustar00rootroot00000000000000#!/bin/bash set -e . .venv/bin/activate pip install Python/dist/*.whl grep -v QuantLib binder/requirements.txt > Python/examples/requirements.txt pip install -r Python/examples/requirements.txt QuantLib-SWIG-1.39/.ci/r.build000077500000000000000000000002551503741206100156730ustar00rootroot00000000000000#!/bin/bash set -e mkdir -p ~/.R echo 'CC=clang' > ~/.R/Makevars echo 'CXX=clang++' >> ~/.R/Makevars ./autogen.sh ./configure CXXFLAGS='-O0' make -C R SWIGFLAGS='-Werror' QuantLib-SWIG-1.39/.ci/r.check000077500000000000000000000002031503741206100156420ustar00rootroot00000000000000#!/bin/bash set -e echo Execute Scripts in demo folder for fn in ./R/demo/*.R do echo $fn Rscript "$fn" || break -1 done QuantLib-SWIG-1.39/.ci/r.install000077500000000000000000000000661503741206100162420ustar00rootroot00000000000000#!/bin/bash set -e R CMD INSTALL ./R.Rcheck/QuantLib QuantLib-SWIG-1.39/.ci/scala.build000077500000000000000000000003421503741206100165120ustar00rootroot00000000000000#!/bin/bash set -e ./autogen.sh ./configure --with-jdk-include=/usr/lib/jvm/default-java/include \ --with-jdk-system-include=/usr/lib/jvm/default-java/include/linux CXXFLAGS='-O2' make -C Java SWIGFLAGS='-Werror' QuantLib-SWIG-1.39/.ci/scala.check000077500000000000000000000000501503741206100164640ustar00rootroot00000000000000#!/bin/bash set -e make -C Scala check QuantLib-SWIG-1.39/.ci/scala.install000077500000000000000000000000231503741206100170550ustar00rootroot00000000000000#!/bin/bash set -e QuantLib-SWIG-1.39/.github/000077500000000000000000000000001503741206100152735ustar00rootroot00000000000000QuantLib-SWIG-1.39/.github/boring-cyborg.yml000066400000000000000000000011451503741206100205620ustar00rootroot00000000000000 # Comment to be posted to welcome users when they open their first PR firstPRWelcomeComment: > Thanks for opening this pull request! It might take a while before we look at it, so don't worry if there seems to be no feedback. We'll get to it. # Comment to be posted to congratulate user on their first merged PR firstPRMergeComment: > Congratulations on your first merged pull request! # Comment to be posted to on first time issues firstIssueWelcomeComment: > Thanks for posting! It might take a while before we look at your issue, so don't worry if there seems to be no feedback. We'll get to it. QuantLib-SWIG-1.39/.github/dependabot.yml000066400000000000000000000002611503741206100201220ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: # Check for updates to GitHub Actions every weekday interval: "weekly" QuantLib-SWIG-1.39/.github/workflows/000077500000000000000000000000001503741206100173305ustar00rootroot00000000000000QuantLib-SWIG-1.39/.github/workflows/copyrights.yml000066400000000000000000000011501503741206100222430ustar00rootroot00000000000000name: Update copyright list on: push: branches: - '**' jobs: copyrights: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check run: | ./tools/check_copyrights.sh - uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} branch: update-copyright-list-${{ github.ref_name }} delete-branch: true commit-message: 'Update copyright list in license' title: 'Update copyright list in license' author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> QuantLib-SWIG-1.39/.github/workflows/devenv-images.yml000066400000000000000000000060241503741206100226070ustar00rootroot00000000000000name: Build quantlib-swig-devenv Docker images on: schedule: - cron: '0 0 * * 6' workflow_dispatch: jobs: docker-images-base: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Checkout latest QuantLib master uses: actions/checkout@v4 with: repository: lballabio/QuantLib path: dockerfiles/QuantLib - name: Build Docker images working-directory: dockerfiles run: | rm -rf QuantLib/.git docker build -f ci.base.Dockerfile --build-arg tag=noble -t ghcr.io/lballabio/quantlib-swig-devenv:base . - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GHCR_PAT }} - name: Push Docker images run: | docker push ghcr.io/lballabio/quantlib-swig-devenv:base docker-images-ql: runs-on: ubuntu-latest needs: docker-images-base strategy: matrix: tag: [default, threadsafe] steps: - uses: actions/checkout@v4 - name: Build Docker images working-directory: dockerfiles run: | docker build -f ci.${{ matrix.tag }}.Dockerfile -t ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.tag }} . - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GHCR_PAT }} - name: Push Docker images run: | docker push ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.tag }} docker-images-base-languages: runs-on: ubuntu-latest needs: docker-images-ql strategy: matrix: lang: [python, csharp, java, r] steps: - uses: actions/checkout@v4 - name: Build Docker images working-directory: dockerfiles run: | docker build -f ci.${{ matrix.lang }}.Dockerfile -t ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.lang }} . - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GHCR_PAT }} - name: Push Docker images run: | docker push ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.lang }} docker-images-dependent-languages: runs-on: ubuntu-latest needs: docker-images-base-languages strategy: matrix: lang: [scala] steps: - uses: actions/checkout@v4 - name: Build Docker images working-directory: dockerfiles run: | docker build -f ci.${{ matrix.lang }}.Dockerfile -t ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.lang }} . - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GHCR_PAT }} - name: Push Docker images run: | docker push ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.lang }} QuantLib-SWIG-1.39/.github/workflows/linux.yml000066400000000000000000000015011503741206100212070ustar00rootroot00000000000000name: Linux build on: push: pull_request: schedule: - cron: '0 0 * * 0' workflow_dispatch: jobs: build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - language: python - language: java config: -old - language: java config: -new - language: csharp - language: r - language: scala container: ghcr.io/lballabio/quantlib-swig-devenv:${{ matrix.language }} steps: - uses: actions/checkout@v4 - name: Build run: | ./.ci/${{ matrix.language }}${{ matrix.config }}.build - name: Install run: | ./.ci/${{ matrix.language }}${{ matrix.config }}.install - name: Check run: | ./.ci/${{ matrix.language }}${{ matrix.config }}.check QuantLib-SWIG-1.39/.github/workflows/misspell.yml000066400000000000000000000010701503741206100217010ustar00rootroot00000000000000name: Misspell fixer on: push: branches: - '**' jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: sobolevn/misspell-fixer-action@master - uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} branch: misspell-fixes-${{ github.ref_name }} delete-branch: true commit-message: 'Fixes by misspell-fixer' title: 'Typos fixed by misspell-fixer' author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> QuantLib-SWIG-1.39/.github/workflows/namespaces.yml000066400000000000000000000026641503741206100222020ustar00rootroot00000000000000name: Fix uses of boost and/or ext namespace on: push: branches: - '**' jobs: namespaces: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check run: | sed -i -e 's/boost::shared_ptr\b/ext::shared_ptr/g' SWIG/* sed -i -e 's/boost::make_shared\b/ext::make_shared/g' SWIG/* sed -i -e 's/boost::dynamic_pointer_cast\b/ext::dynamic_pointer_cast/g' SWIG/* sed -i -e 's/ext::tuple\b/std::tuple/g' SWIG/* sed -i -e 's/ext::make_tuple\b/std::make_tuple/g' SWIG/* sed -i -e 's/ext::get\b/std::get/g' SWIG/* sed -i -e 's/ext::tie\b/std::tie/g' SWIG/* sed -i -e 's/ext::function\b/std::function/g' SWIG/* sed -i -e 's/ext::bind\b/std::bind/g' SWIG/* sed -i -e 's/ext::ref\b/std::ref/g' SWIG/* sed -i -e 's/ext::cref\b/std::cref/g' SWIG/* sed -i -e 's/ext::placeholders\b/std::placeholders/g' SWIG/* sed -i -e 's/boost::optional\b/ext::optional/g' SWIG/* sed -i -e 's/boost::none\b/ext::nullopt/g' SWIG/* - uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} branch: fix-boost-namespace-${{ github.ref_name }} delete-branch: true commit-message: 'Fix uses of boost and/or ext namespace' title: 'Fix uses of boost and/or ext namespace' author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> QuantLib-SWIG-1.39/.github/workflows/stale.yml000066400000000000000000000022231503741206100211620ustar00rootroot00000000000000name: Close stale issues and PR on: schedule: - cron: '30 1 * * *' jobs: staleness-check: runs-on: ubuntu-latest steps: - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.' close-issue-message: 'This issue was automatically closed because it has been stalled for two weeks with no further activity.' stale-pr-message: 'This PR was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.' close-pr-message: 'This PR was automatically closed because it has been stalled for two weeks with no further activity.' days-before-stale: 60 days-before-close: 14 stale-issue-label: 'stale' stale-pr-label: 'stale' exempt-issue-labels: 'help wanted,in progress' exempt-pr-labels: 'help wanted,in progress' exempt-all-milestones: true QuantLib-SWIG-1.39/.gitignore000066400000000000000000000010111503741206100157140ustar00rootroot00000000000000# Compilation artifacts configure aclocal.m4 autom4te.cache config.log config.status config/ # Build outputs **/x64/Debug **/x64/Release **/Debug **/Release **/bin/*.xml **/bin/*.manifest # IDEs .idea .vscode cmake-build-debug # Artifacts created in multiple directories Makefile Makefile.in .build-stamp testCaseCollection.xml .deps .libs *.la *.lo *.o *.so *.dylib *.exe *.dll *.exp *.lib *.pdb *.ilk *.class *~ *.ncb *.suo *.vcproj.*.user *.vcxproj.user *.VC.db *.VC.opendb *.log *.sdf *.opensdf *.pch *.idb *.ipch QuantLib-SWIG-1.39/.misspell-fixer.ignore000066400000000000000000000000221503741206100201530ustar00rootroot00000000000000^./ChangeLog.txt QuantLib-SWIG-1.39/CSharp/000077500000000000000000000000001503741206100151135ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/.gitignore000066400000000000000000000001741503741206100171050ustar00rootroot00000000000000cpp/quantlib_wrap.cpp cpp/quantlib_wrap.h csharp/*.cs NQuantLib.dll cpp/build csharp/obj examples/*/bin examples/*/obj .vs/ QuantLib-SWIG-1.39/CSharp/Makefile.am000066400000000000000000000060171503741206100171530ustar00rootroot00000000000000 CLEANFILES = cpp/quantlib_wrap.* cpp/*.so cpp/*.dylib csharp/*.cs *.dll BUILT_SOURCES = cpp/quantlib_wrap.cpp cpp/quantlib_wrap.h if HAVE_DOTNET if BUILD_DOTNET all-local: cpp/libNQuantLibc.@SHARED_LIB_EXTENSION@ csharp/bin/Release/net6.0/NQuantLib.dll cpp/libNQuantLibc.@SHARED_LIB_EXTENSION@: cpp/quantlib_wrap.o $(CXX) -shared cpp/quantlib_wrap.o -o cpp/libNQuantLibc.@SHARED_LIB_EXTENSION@ `quantlib-config --libs` cpp/quantlib_wrap.o: $(BUILT_SOURCES) $(CXX) -c -fpic $(CXXFLAGS) cpp/quantlib_wrap.cpp -o cpp/quantlib_wrap.o `quantlib-config --cflags` csharp/bin/Release/net6.0/NQuantLib.dll: $(BUILT_SOURCES) $(DOTNET) build --nologo -c Release -p:Version=$(PACKAGE_VERSION) csharp/NQuantLib.csproj nupkg: cpp/libNQuantLibc.@SHARED_LIB_EXTENSION@ csharp/bin/Release/net6.0/NQuantLib.dll $(DOTNET) pack --no-build -c Release -p:PackageVersion=$(PACKAGE_VERSION) --include-symbols --include-source csharp/NQuantLib.csproj check-local: cpp/libNQuantLibc.@SHARED_LIB_EXTENSION@ csharp/bin/Release/net6.0/NQuantLib.dll ln -f cpp/libNQuantLibc.@SHARED_LIB_EXTENSION@ examples/ cd examples && LD_LIBRARY_PATH=. $(DOTNET) run -c Release --project BermudanSwaption/BermudanSwaption.csproj cd examples && LD_LIBRARY_PATH=. $(DOTNET) run -c Release --project EquityOption/EquityOption.csproj cd examples && LD_LIBRARY_PATH=. $(DOTNET) run -c Release --project FiniteDifferenceMethods/FiniteDifferenceMethods.csproj cd examples && LD_LIBRARY_PATH=. $(DOTNET) run -c Release --project Times/Times.csproj rm -f examples/libNQuantLibc.@SHARED_LIB_EXTENSION@ clean-local: rm -rf csharp/bin csharp/obj examples/*/bin examples/*/obj endif endif $(BUILT_SOURCES): ../SWIG/*.i rm -f csharp/*.cs $(SWIG) $(SWIGFLAGS) -csharp -c++ -outdir csharp \ -namespace QuantLib -o cpp/quantlib_wrap.cpp ../SWIG/quantlib.i dist-hook: $(BUILT_SOURCES) mkdir -p $(distdir)/cpp cp ./cpp/*.vcxproj $(distdir)/cpp cp ./cpp/quantlib_wrap.cpp $(distdir)/cpp cp ./cpp/quantlib_wrap.h $(distdir)/cpp mkdir -p $(distdir)/csharp cp ./csharp/*.csproj $(distdir)/csharp cp ./csharp/*.cs $(distdir)/csharp mkdir -p $(distdir)/examples mkdir -p $(distdir)/examples/BermudanSwaption cp ./examples/BermudanSwaption/BermudanSwaption.csproj $(distdir)/examples/BermudanSwaption cp ./examples/BermudanSwaption/BermudanSwaption.cs $(distdir)/examples/BermudanSwaption mkdir -p $(distdir)/examples/EquityOption cp ./examples/EquityOption/EquityOption.csproj $(distdir)/examples/EquityOption cp ./examples/EquityOption/EquityOption.cs $(distdir)/examples/EquityOption mkdir -p $(distdir)/examples/FiniteDifferenceMethods cp ./examples/FiniteDifferenceMethods/FiniteDifferenceMethods.csproj $(distdir)/examples/FiniteDifferenceMethods cp ./examples/FiniteDifferenceMethods/FiniteDifferenceMethods.cs $(distdir)/examples/FiniteDifferenceMethods mkdir -p $(distdir)/examples/Times cp ./examples/Times/Times.csproj $(distdir)/examples/Times cp ./examples/Times/Times.cs $(distdir)/examples/Times EXTRA_DIST = \ QuantLib.sln \ QuantLib.props \ swig.cmd \ README.txt QuantLib-SWIG-1.39/CSharp/QuantLib.props000066400000000000000000000016531503741206100177240ustar00rootroot00000000000000 v100 v110 v120 v130 v140 v141 v142 v143 QuantLib-SWIG-1.39/CSharp/QuantLib.sln000066400000000000000000000137461503741206100173630ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31515.178 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BermudanSwaption", "examples\BermudanSwaption\BermudanSwaption.csproj", "{1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}" ProjectSection(ProjectDependencies) = postProject {21183104-9963-4D4F-B7E8-C8A6169FD053} = {21183104-9963-4D4F-B7E8-C8A6169FD053} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EquityOption", "examples\EquityOption\EquityOption.csproj", "{1FD947F1-D99E-46FB-8890-04E11E8340C2}" ProjectSection(ProjectDependencies) = postProject {21183104-9963-4D4F-B7E8-C8A6169FD053} = {21183104-9963-4D4F-B7E8-C8A6169FD053} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FiniteDifferenceMethods", "examples\FiniteDifferenceMethods\FiniteDifferenceMethods.csproj", "{EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}" ProjectSection(ProjectDependencies) = postProject {21183104-9963-4D4F-B7E8-C8A6169FD053} = {21183104-9963-4D4F-B7E8-C8A6169FD053} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NQuantLib", "csharp\NQuantLib.csproj", "{928F98EE-7D50-457F-9304-A6818DCF1079}" ProjectSection(ProjectDependencies) = postProject {21183104-9963-4D4F-B7E8-C8A6169FD053} = {21183104-9963-4D4F-B7E8-C8A6169FD053} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NQuantLibc", "cpp\QuantLibWrapper.vcxproj", "{21183104-9963-4D4F-B7E8-C8A6169FD053}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Times", "examples\Times\Times.csproj", "{C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Debug|Win32.ActiveCfg = Debug|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Debug|Win32.Build.0 = Debug|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Debug|x64.ActiveCfg = Debug|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Debug|x64.Build.0 = Debug|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Release|Win32.ActiveCfg = Release|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Release|Win32.Build.0 = Release|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Release|x64.ActiveCfg = Release|Any CPU {1BEC49E8-122D-4CC9-9DAC-DD59F551E5E9}.Release|x64.Build.0 = Release|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Debug|Win32.ActiveCfg = Debug|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Debug|Win32.Build.0 = Debug|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Debug|x64.ActiveCfg = Debug|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Debug|x64.Build.0 = Debug|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Release|Win32.ActiveCfg = Release|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Release|Win32.Build.0 = Release|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Release|x64.ActiveCfg = Release|Any CPU {1FD947F1-D99E-46FB-8890-04E11E8340C2}.Release|x64.Build.0 = Release|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Debug|Win32.ActiveCfg = Debug|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Debug|Win32.Build.0 = Debug|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Debug|x64.ActiveCfg = Debug|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Debug|x64.Build.0 = Debug|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Release|Win32.ActiveCfg = Release|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Release|Win32.Build.0 = Release|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Release|x64.ActiveCfg = Release|Any CPU {EF2AFADF-B632-4E95-BEB5-7B7109A9E4FD}.Release|x64.Build.0 = Release|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Debug|Win32.ActiveCfg = Debug|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Debug|Win32.Build.0 = Debug|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Debug|x64.ActiveCfg = Debug|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Debug|x64.Build.0 = Debug|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Release|Win32.ActiveCfg = Release|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Release|Win32.Build.0 = Release|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Release|x64.ActiveCfg = Release|Any CPU {928F98EE-7D50-457F-9304-A6818DCF1079}.Release|x64.Build.0 = Release|Any CPU {21183104-9963-4D4F-B7E8-C8A6169FD053}.Debug|Win32.ActiveCfg = Debug|Win32 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Debug|Win32.Build.0 = Debug|Win32 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Debug|x64.ActiveCfg = Debug|x64 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Debug|x64.Build.0 = Debug|x64 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Release|Win32.ActiveCfg = Release|Win32 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Release|Win32.Build.0 = Release|Win32 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Release|x64.ActiveCfg = Release|x64 {21183104-9963-4D4F-B7E8-C8A6169FD053}.Release|x64.Build.0 = Release|x64 {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Debug|Win32.ActiveCfg = Debug|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Debug|Win32.Build.0 = Debug|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Debug|x64.ActiveCfg = Debug|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Debug|x64.Build.0 = Debug|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Release|Win32.ActiveCfg = Release|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Release|Win32.Build.0 = Release|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Release|x64.ActiveCfg = Release|Any CPU {C93F5204-5BC9-4AB3-AC06-C2CCE166CEBD}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D5A8DD18-AC31-4E40-A70A-11339ED8FAE8} EndGlobalSection EndGlobal QuantLib-SWIG-1.39/CSharp/README.txt000066400000000000000000000006061503741206100166130ustar00rootroot00000000000000 Visual Studio .NET projects are provided; note that before launching the IDE, you'll have to define an environment variable QL_DIR whose value must equal the path to your QuantLib installation, e.g., "C:\Lib\QuantLib". The interfaces also work with .Net on Linux and macOS; run 'make' in this directory after running './autogen.sh' and './configure' in the main QuantLib-SWIG directory. QuantLib-SWIG-1.39/CSharp/cpp/000077500000000000000000000000001503741206100156755ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/cpp/QuantLibWrapper.vcxproj000066400000000000000000000266041503741206100224020ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 NQuantLibc {21183104-9963-4D4F-B7E8-C8A6169FD053} NQuantLibc Win32Proj DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte DynamicLibrary MultiByte <_ProjectFileVersion>10.0.30319.1 bin\$(Platform)\Debug\ build\$(Platform)\Debug\ true bin\$(Platform)\Release\ build\$(Platform)\Release\ false AllRules.ruleset AllRules.ruleset Disabled stdcpp17 $(QL_DIR);%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;QUANTLIBWRAPPER_EXPORTS;_cplusplus;NOMINMAX;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL true Level3 EditAndContinue /bigobj %(AdditionalOptions) $(OutDir)NQuantLibc.dll $(QL_DIR)\lib;%(AdditionalLibraryDirectories) true $(OutDir)QuantlibWrapper.pdb Windows false $(OutDir)NQuantLibc.lib MachineX86 copy "$(OutDir)NQuantLibc.dll" "$(ProjectDir)" Disabled stdcpp17 $(QL_DIR);%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;QUANTLIBWRAPPER_EXPORTS;_cplusplus;NOMINMAX;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL true Level3 ProgramDatabase /bigobj %(AdditionalOptions) $(OutDir)NQuantLibc.dll $(QL_DIR)\lib;%(AdditionalLibraryDirectories) true $(OutDir)QuantlibWrapper.pdb Windows false $(OutDir)NQuantLibc.lib copy "$(OutDir)NQuantLibc.dll" "$(ProjectDir)" stdcpp17 $(QL_DIR);%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;QUANTLIBWRAPPER_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true true Level3 ProgramDatabase 4244;%(DisableSpecificWarnings) /bigobj %(AdditionalOptions) $(OutDir)NQuantLibc.dll $(QL_DIR)\lib;%(AdditionalLibraryDirectories) true Windows true true false $(OutDir)NQuantLibc.lib MachineX86 copy "$(OutDir)NQuantLibc.dll" "$(ProjectDir)" stdcpp17 $(QL_DIR);%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;QUANTLIBWRAPPER_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true true Level3 ProgramDatabase 4244;%(DisableSpecificWarnings) /bigobj %(AdditionalOptions) $(OutDir)NQuantLibc.dll $(QL_DIR)\lib;%(AdditionalLibraryDirectories) true Windows true true false $(OutDir)NQuantLibc.lib copy "$(OutDir)NQuantLibc.dll" "$(ProjectDir)" QuantLib-SWIG-1.39/CSharp/cpp/QuantLibWrapper.vcxproj.filters000066400000000000000000000020411503741206100240360ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx Source Files Header Files QuantLib-SWIG-1.39/CSharp/csharp/000077500000000000000000000000001503741206100163735ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/csharp/NQuantLib.csproj000066400000000000000000000021101503741206100214440ustar00rootroot00000000000000 net6.0 QuantLib runtimes/win-x64/native runtimes/linux-x64/native runtimes/osx-x64/native QuantLib-SWIG-1.39/CSharp/examples/000077500000000000000000000000001503741206100167315ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/examples/BermudanSwaption/000077500000000000000000000000001503741206100222135ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/examples/BermudanSwaption/BermudanSwaption.cs000066400000000000000000000275201503741206100260320ustar00rootroot00000000000000/* Copyright (C) 2005 Dominic Thuillier This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ using System; using QuantLib; namespace BermudanSwaption { class Run { private const int numRows = 5; private const int numCols = 5; private static int[] swapLengths = { 1, 2, 3, 4, 5 }; private static double[] swaptionVols = { 0.1490, 0.1340, 0.1228, 0.1189, 0.1148, 0.1290, 0.1201, 0.1146, 0.1108, 0.1040, 0.1149, 0.1112, 0.1070, 0.1010, 0.0957, 0.1047, 0.1021, 0.0980, 0.0951, 0.1270, 0.1000, 0.0950, 0.0900, 0.1230, 0.1160 }; private static void calibrateModel( ShortRateModel model, CalibrationHelperVector helpers, double lambda ) { Simplex om = new Simplex( lambda ); model.calibrate(helpers, om, new EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7)); // Output the implied Black volatilities for (int i=0; i /// The main entry point for the application. /// [STAThread] static void Main(string[] args) { DateTime startTime = DateTime.Now; Date todaysDate = new Date(15, Month.February, 2002); Calendar calendar = new TARGET(); Date settlementDate = new Date(19, Month.February, 2002); Settings.instance().setEvaluationDate( todaysDate ); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); FlatForward myTermStructure = new FlatForward( settlementDate, new QuoteHandle( flatRate ), new Actual365Fixed() ); RelinkableYieldTermStructureHandle rhTermStructure = new RelinkableYieldTermStructureHandle(); rhTermStructure.linkTo( myTermStructure ); // Define the ATM/OTM/ITM swaps Period fixedLegTenor = new Period(1,TimeUnit.Years); BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360( Thirty360.Convention.European ); Period floatingLegTenor = new Period(6,TimeUnit.Months); double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M( rhTermStructure ); Date startDate = calendar.advance(settlementDate,1,TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate,5,TimeUnit.Years, floatingLegConvention); Schedule fixedSchedule = new Schedule(startDate,maturity, fixedLegTenor,calendar,fixedLegConvention,fixedLegConvention, DateGeneration.Rule.Forward,false); Schedule floatSchedule = new Schedule(startDate,maturity, floatingLegTenor,calendar,floatingLegConvention, floatingLegConvention,DateGeneration.Rule.Forward,false); VanillaSwap swap = new VanillaSwap( Swap.Type.Payer, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); DiscountingSwapEngine swapEngine = new DiscountingSwapEngine(rhTermStructure); swap.setPricingEngine(swapEngine); double fixedATMRate = swap.fairRate(); double fixedOTMRate = fixedATMRate * 1.2; double fixedITMRate = fixedATMRate * 0.8; VanillaSwap atmSwap = new VanillaSwap( Swap.Type.Payer, 1000.0, fixedSchedule, fixedATMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter() ); VanillaSwap otmSwap = new VanillaSwap( Swap.Type.Payer, 1000.0, fixedSchedule, fixedOTMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap itmSwap = new VanillaSwap( Swap.Type.Payer, 1000.0, fixedSchedule, fixedITMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); atmSwap.setPricingEngine(swapEngine); otmSwap.setPricingEngine(swapEngine); itmSwap.setPricingEngine(swapEngine); // defining the swaptions to be used in model calibration PeriodVector swaptionMaturities = new PeriodVector(); swaptionMaturities.Add( new Period(1, TimeUnit.Years) ); swaptionMaturities.Add( new Period(2, TimeUnit.Years) ); swaptionMaturities.Add( new Period(3, TimeUnit.Years) ); swaptionMaturities.Add( new Period(4, TimeUnit.Years) ); swaptionMaturities.Add( new Period(5, TimeUnit.Years) ); CalibrationHelperVector swaptions = new CalibrationHelperVector(); // List of times that have to be included in the timegrid DoubleVector times = new DoubleVector(); for ( int i=0; i net6.0 false Exe QuantLib-SWIG-1.39/CSharp/examples/EquityOption/000077500000000000000000000000001503741206100214025ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/examples/EquityOption/EquityOption.cs000066400000000000000000000443131503741206100244070ustar00rootroot00000000000000/* Copyright (C) 2007 Eric H. Jensen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ using System; using System.Collections.Generic; using System.Text; using QuantLib; namespace EquityOptionTest { class EquityOption { /// /// The main entry point for the application. /// [STAThread] static void Main(string[] args) { DateTime startTime = DateTime.Now; Option.Type optionType = Option.Type.Put; double underlyingPrice = 36; double strikePrice = 40; double dividendYield = 0.0; double riskFreeRate = 0.06; double volatility = 0.2; Date todaysDate = new Date(15, Month.May, 1998); Settings.instance().setEvaluationDate(todaysDate); Date settlementDate = new Date(17, Month.May, 1998); Date maturityDate = new Date(17, Month.May, 1999); Calendar calendar = new TARGET(); DateVector exerciseDates = new DateVector(4); for (int i = 1; i <= 4; i++) { Period forwardPeriod = new Period(3 * i, TimeUnit.Months); Date forwardDate = settlementDate.Add(forwardPeriod); exerciseDates.Add(forwardDate); } EuropeanExercise europeanExercise = new EuropeanExercise(maturityDate); BermudanExercise bermudanExercise = new BermudanExercise(exerciseDates); AmericanExercise americanExercise = new AmericanExercise(settlementDate, maturityDate); // bootstrap the yield/dividend/vol curves and create a // BlackScholesMerton stochastic process DayCounter dayCounter = new Actual365Fixed(); YieldTermStructureHandle flatRateTSH = new YieldTermStructureHandle( new FlatForward(settlementDate, riskFreeRate, dayCounter)); YieldTermStructureHandle flatDividendTSH = new YieldTermStructureHandle( new FlatForward(settlementDate, dividendYield, dayCounter)); BlackVolTermStructureHandle flatVolTSH = new BlackVolTermStructureHandle( new BlackConstantVol(settlementDate, calendar, volatility, dayCounter)); QuoteHandle underlyingQuoteH = new QuoteHandle(new SimpleQuote(underlyingPrice)); BlackScholesMertonProcess stochasticProcess = new BlackScholesMertonProcess(underlyingQuoteH, flatDividendTSH, flatRateTSH, flatVolTSH); PlainVanillaPayoff payoff = new PlainVanillaPayoff(optionType, strikePrice); // options VanillaOption europeanOption = new VanillaOption(payoff, europeanExercise); VanillaOption bermudanOption = new VanillaOption(payoff, bermudanExercise); VanillaOption americanOption = new VanillaOption(payoff, americanExercise); // report the parameters we are using ReportParameters(optionType, underlyingPrice, strikePrice, dividendYield, riskFreeRate, volatility, maturityDate); // write out the column headings ReportHeadings(); #region Analytic Formulas // Black-Scholes for European try { europeanOption.setPricingEngine( new AnalyticEuropeanEngine(stochasticProcess)); ReportResults("Black-Scholes", europeanOption.NPV(), null, null); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Barone-Adesi and Whaley approximation for American try { americanOption.setPricingEngine( new BaroneAdesiWhaleyApproximationEngine(stochasticProcess)); ReportResults("Barone-Adesi/Whaley", null, null, americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Bjerksund and Stensland approximation for American try { americanOption.setPricingEngine( new BjerksundStenslandApproximationEngine(stochasticProcess)); ReportResults("Bjerksund/Stensland", null, null, americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Integral try { europeanOption.setPricingEngine( new IntegralEngine(stochasticProcess)); ReportResults("Integral", europeanOption.NPV(), null, null); } catch (Exception e) { Console.WriteLine(e.ToString()); } uint timeSteps = 801; // Finite differences try { europeanOption.setPricingEngine( new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps - 1)); bermudanOption.setPricingEngine( new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps - 1)); americanOption.setPricingEngine( new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps - 1)); ReportResults("Finite differences", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } //Variance Gamma try { VarianceGammaProcess vgProcess = new VarianceGammaProcess(underlyingQuoteH, flatDividendTSH, flatRateTSH, volatility, 0.01, 0.0 ); europeanOption.setPricingEngine( new VarianceGammaEngine(vgProcess)); ReportResults("Variance-Gamma", europeanOption.NPV(), null, null); } catch (Exception e) { Console.WriteLine(e.ToString()); } #endregion Analytic Formulas #region Binomial Methods // Binomial Jarrow-Rudd try { europeanOption.setPricingEngine( new BinomialJRVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialJRVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialJRVanillaEngine(stochasticProcess, timeSteps)); ReportResults("Binomial Jarrow-Rudd", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Binomial Cox-Ross-Rubinstein try { europeanOption.setPricingEngine( new BinomialCRRVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialCRRVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialCRRVanillaEngine(stochasticProcess, timeSteps)); ReportResults("Binomial Cox-Ross-Rubinstein", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Additive Equiprobabilities try { europeanOption.setPricingEngine( new BinomialEQPVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialEQPVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialEQPVanillaEngine(stochasticProcess, timeSteps)); ReportResults("Additive Equiprobabilities", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Binomial Trigeorgis try { europeanOption.setPricingEngine( new BinomialTrigeorgisVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialTrigeorgisVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialTrigeorgisVanillaEngine(stochasticProcess, timeSteps)); ReportResults("Binomial Trigeorgis", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Binomial Tian try { europeanOption.setPricingEngine( new BinomialTianVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialTianVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialTianVanillaEngine(stochasticProcess, timeSteps)); ReportResults("Binomial Tian", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Binomial Leisen-Reimer try { europeanOption.setPricingEngine( new BinomialLRVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialLRVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialLRVanillaEngine(stochasticProcess, timeSteps)); ReportResults("Binomial Leisen-Reimer", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Binomial Joshi try { europeanOption.setPricingEngine( new BinomialJ4VanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialJ4VanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialJ4VanillaEngine(stochasticProcess, timeSteps)); ReportResults("Binomial Joshi", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV()); } catch (Exception e) { Console.WriteLine(e.ToString()); } #endregion Binomial Methods #region Monte Carlo Methods // quantlib appears to use max numeric (int and real) values to test for 'null' (or rather 'default') values // MC (crude) try { int mcTimeSteps = 1; int timeStepsPerYear = int.MaxValue; bool brownianBridge = false; bool antitheticVariate = false; int requiredSamples = int.MaxValue; double requiredTolerance = 0.02; int maxSamples = int.MaxValue; int seed = 42; europeanOption.setPricingEngine( new MCPREuropeanEngine(stochasticProcess, mcTimeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed)); ReportResults("MC (crude)", europeanOption.NPV(), null, null); } catch (Exception e) { Console.WriteLine(e.ToString()); } // MC (Sobol) try { int mcTimeSteps = 1; int timeStepsPerYear = int.MaxValue; bool brownianBridge = false; bool antitheticVariate = false; int requiredSamples = 32768; // 2^15 double requiredTolerance = double.MaxValue; int maxSamples = int.MaxValue; int seed = 0; europeanOption.setPricingEngine( new MCLDEuropeanEngine(stochasticProcess, mcTimeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed)); ReportResults("MC (Sobol)", europeanOption.NPV(), null, null); } catch (Exception e) { Console.WriteLine(e.ToString()); } #endregion Monte Carlo Methods DateTime endTime = DateTime.Now; TimeSpan delta = endTime - startTime; Console.WriteLine(); Console.WriteLine("Run completed in {0} s", delta.TotalSeconds); Console.WriteLine(); } private static void ReportParameters(Option.Type optionType, double underlyingPrice, double strikePrice, double dividendYield, double riskFreeRate, double volatility, Date maturityDate) { Console.WriteLine(); Console.WriteLine("Option type = {0}", optionType); Console.WriteLine("Maturity = {0} {1} {2}", maturityDate.year(), maturityDate.month(), maturityDate.dayOfMonth()); Console.WriteLine("Underlying price = ${0}", underlyingPrice); Console.WriteLine("Strike = ${0}", strikePrice); Console.WriteLine("Risk-free interest rate = {0}%", riskFreeRate * 100.0); Console.WriteLine("Dividend yield = {0}%", dividendYield * 100.0); Console.WriteLine("Volatility = {0}%", volatility * 100); Console.WriteLine(); } private static int[] columnWidths = { 35, 14, 14, 14 }; private static void ReportHeadings() { Console.Write("Method".PadRight(columnWidths[0])); Console.Write("European".PadRight(columnWidths[1])); Console.Write("Bermudan".PadRight(columnWidths[2])); Console.Write("American".PadRight(columnWidths[3])); Console.WriteLine(); } private static void ReportResults(string methodName, double? european, double? bermudan, double? american) { string strNA = "N/A"; string format = "{0:N6}"; Console.Write(methodName.PadRight(columnWidths[0])); Console.Write(String.Format((european == null) ? strNA : format, european).PadRight(columnWidths[1])); Console.Write(String.Format((bermudan == null) ? strNA : format, bermudan).PadRight(columnWidths[2])); Console.Write(String.Format((american == null) ? strNA : format, american).PadRight(columnWidths[3])); Console.WriteLine(); } } } QuantLib-SWIG-1.39/CSharp/examples/EquityOption/EquityOption.csproj000066400000000000000000000010141503741206100252710ustar00rootroot00000000000000 net6.0 false Exe QuantLib-SWIG-1.39/CSharp/examples/FiniteDifferenceMethods/000077500000000000000000000000001503741206100234465ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/examples/FiniteDifferenceMethods/FiniteDifferenceMethods.cs000066400000000000000000000121371503741206100305160ustar00rootroot00000000000000/* Copyright (C) 2020 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ using System; using QuantLib; using static QuantLib.NQuantLibc; namespace FiniteDifferenceMethods { class FdmDemo { // test class for the operator delegate and proxy public class FdmBSDelegate : FdmLinearOpCompositeDelegate { private readonly FdmLinearOpComposite op; public FdmBSDelegate(FdmLinearOpComposite op) { this.op = op; } override public uint size() { return op.size(); } override public void setTime(double t1, double t2) { op.setTime(t1, t2); } override public QlArray apply(QlArray r) { return op.apply(r); } override public QlArray apply_direction(uint i, QlArray r) { return op.apply_direction(i, r); } override public QlArray solve_splitting(uint i, QlArray r, double s) { return op.solve_splitting(i, r, s); } }; static void Main(string[] args) { const int xSteps = 100; const int tSteps = 25; const int dampingSteps = 0; Date today = new Date(15, Month.January, 2020); Settings.instance().setEvaluationDate(today); DayCounter dc = new Actual365Fixed(); YieldTermStructureHandle rTS = new YieldTermStructureHandle( new FlatForward(today, 0.06, dc)); YieldTermStructureHandle qTS = new YieldTermStructureHandle( new FlatForward(today, 0.02, dc)); const double strike = 110.0; StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Put, strike); Date maturityDate = today.Add(new Period(1, TimeUnit.Years)); double maturity = dc.yearFraction(today, maturityDate); Exercise exercise = new AmericanExercise(today, maturityDate); Instrument vanillaOption = new VanillaOption(payoff, exercise); QuoteHandle spot = new QuoteHandle(new SimpleQuote(100.0)); BlackVolTermStructureHandle volatility = new BlackVolTermStructureHandle( new BlackConstantVol(today, new TARGET(), 0.20, dc)); BlackScholesMertonProcess process = new BlackScholesMertonProcess(spot, qTS, rTS, volatility); vanillaOption.setPricingEngine(new FdBlackScholesVanillaEngine( process, tSteps, xSteps, dampingSteps)); double expected = vanillaOption.NPV(); // build an PDE engine from scratch Fdm1dMesher equityMesher = new FdmBlackScholesMesher( xSteps, process, maturity, strike, nullDouble(), nullDouble(), 0.0001, 1.5, new DoublePair(strike, 0.1)); FdmMesherComposite mesher = new FdmMesherComposite(equityMesher); FdmLinearOpComposite op = new FdmBlackScholesOp(mesher, process, strike); FdmInnerValueCalculator calc = new FdmLogInnerValue(payoff, mesher, 0); QlArray x = new QlArray(equityMesher.size()); QlArray rhs = new QlArray(equityMesher.size()); FdmLinearOpIterator iter = mesher.layout().begin(); for (uint i = 0; i < rhs.size(); ++i, iter.increment()) { x.set(i, mesher.location(iter, 0)); rhs.set(i, calc.avgInnerValue(iter, maturity)); } FdmBoundaryConditionSet bcSet = new FdmBoundaryConditionSet(); FdmStepConditionComposite stepCondition = FdmStepConditionComposite.vanillaComposite( new DividendSchedule(), exercise, mesher, calc, today, dc); FdmLinearOpComposite proxyOp = new FdmLinearOpCompositeProxy( new FdmBSDelegate(op)); FdmBackwardSolver solver = new FdmBackwardSolver( proxyOp, bcSet, stepCondition, FdmSchemeDesc.Douglas()); solver.rollback(rhs, maturity, 0.0, tSteps, dampingSteps); double logS = Math.Log(spot.value()); double calculated = new CubicNaturalSpline(x, rhs).call(logS); Console.WriteLine("Homebrew PDE engine : {0:0.0000}", calculated); Console.WriteLine("FdBlackScholesVanillaEngine: {0:0.0000}", expected); } } }QuantLib-SWIG-1.39/CSharp/examples/FiniteDifferenceMethods/FiniteDifferenceMethods.csproj000066400000000000000000000010141503741206100314010ustar00rootroot00000000000000 net6.0 false Exe QuantLib-SWIG-1.39/CSharp/examples/Times/000077500000000000000000000000001503741206100200125ustar00rootroot00000000000000QuantLib-SWIG-1.39/CSharp/examples/Times/Times.cs000066400000000000000000000161431503741206100214270ustar00rootroot00000000000000/* Copyright (C) 2021 Ralf Konrad Eckel This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #pragma warning disable CS1718 // Comparison made to same variable using System; using System.Collections.Generic; using System.Diagnostics; using QL = QuantLib; namespace TimesTest { class Times { class TestCaseException : Exception { } /// /// The main entry point for the application. /// [STAThread] static void Main(string[] args) { try { DateTime startTime = DateTime.Now; RunTestCases(); DateTime endTime = DateTime.Now; TimeSpan delta = endTime - startTime; Console.WriteLine(); Console.WriteLine("Run completed in {0} s", delta.TotalSeconds); Console.WriteLine(); } catch (TestCaseException exc) { Console.Error.WriteLine(exc); throw; } } private static void RunTestCases() { Action> writePeriods = (heading, periods2Write) => { Console.Write($" {heading}: "); foreach (var item in periods2Write) { var itemAsString = item != null ? item.ToString() : "null"; Console.Write($"{itemAsString} "); } Console.WriteLine(); }; Action testCase = (testResult) => { if (!testResult) throw new TestCaseException(); }; var tenorNull = null as QL.Period; var tenor91D = new QL.Period("91D"); var tenor03M = new QL.Period("03M"); var tenor06M = new QL.Period("06M"); var tenor12M = new QL.Period("12M"); var tenor01Y = new QL.Period("01Y"); var tenor02Y = new QL.Period("02Y"); var periods = new List() { tenor01Y, tenorNull, tenor02Y, tenor06M, tenor03M }; Console.WriteLine("Testing sorting of a list."); writePeriods("Before sorting", periods); periods.Sort(); writePeriods(" After sorting", periods); testCase(periods[0] == tenorNull); testCase(periods[1] == tenor03M); testCase(periods[2] == tenor06M); testCase(periods[3] == tenor01Y); testCase(periods[4] == tenor02Y); #region test Period.CompareTo(Period) Console.WriteLine("test Period.CompareTo(Period)"); testCase(tenor12M.CompareTo(tenorNull) > 0); testCase(tenor12M.CompareTo(tenor03M) > 0); testCase(tenor12M.CompareTo(tenor06M) > 0); testCase(tenor12M.CompareTo(tenor01Y) == 0); testCase(tenor01Y.CompareTo(tenor01Y) == 0); testCase(tenor12M.CompareTo(tenor02Y) < 0); #endregion #region test Period == Period Console.WriteLine("test Period == Period"); testCase(tenorNull == null); testCase(null == tenorNull); testCase(!(tenorNull == tenor12M)); testCase(!(tenor12M == null)); testCase(tenor12M == tenor12M); testCase(tenor12M == tenor01Y); testCase(!(tenor12M == tenor06M)); testCase(!(tenor06M == tenor12M)); #endregion #region test Period != Period Console.WriteLine("test Period != Period"); testCase(!(tenorNull != null)); testCase(!(null != tenorNull)); testCase(tenorNull != tenor12M); testCase(tenor12M != null); testCase(!(tenor12M != tenor12M)); testCase(!(tenor12M != tenor01Y)); testCase(tenor12M != tenor06M); #endregion #region test Period < Period Console.WriteLine("test Period < Period"); testCase(!(tenorNull < null)); testCase(!(null < tenorNull)); testCase(tenorNull < tenor12M); testCase(!(tenor12M < null)); testCase(!(tenor12M < tenor12M)); testCase(!(tenor12M < tenor01Y)); testCase(!(tenor12M < tenor06M)); testCase(tenor06M < tenor12M); #endregion #region test Period <= Period Console.WriteLine("test Period <= Period"); testCase(tenorNull <= null); testCase(null <= tenorNull); testCase(tenorNull <= tenor12M); testCase(!(tenor12M <= null)); testCase(tenor12M <= tenor12M); testCase(tenor12M <= tenor01Y); testCase(!(tenor12M <= tenor06M)); testCase(tenor06M <= tenor12M); #endregion #region test Period > Period Console.WriteLine("test Period > Period"); testCase(!(tenorNull > null)); testCase(!(null > tenorNull)); testCase(!(tenorNull > tenor12M)); testCase(tenor12M > null); testCase(!(tenor12M > tenor12M)); testCase(!(tenor12M > tenor01Y)); testCase(tenor12M > tenor06M); testCase(!(tenor06M > tenor12M)); #endregion #region test Period >= Period Console.WriteLine("test Period >= Period"); testCase(tenorNull >= null); testCase(null >= tenorNull); testCase(!(tenorNull >= tenor12M)); testCase(tenor12M >= null); testCase(tenor12M >= tenor12M); testCase(tenor12M >= tenor01Y); testCase(tenor12M >= tenor06M); testCase(!(tenor06M >= tenor12M)); #endregion Console.WriteLine("test Period.GetHashCode()"); testCase(tenor01Y.GetHashCode() == tenor12M.GetHashCode()); Console.WriteLine("test that uncomparable periods throw"); Func compare91Dversus03MthrowsApplicationException = () => { bool hasThrown = false; try { tenor91D.CompareTo(tenor03M); } catch (System.ApplicationException) { hasThrown = true; } return hasThrown; }; testCase(compare91Dversus03MthrowsApplicationException()); } } } #pragma warning restore CS1718 // Comparison made to same variable QuantLib-SWIG-1.39/CSharp/examples/Times/Times.csproj000066400000000000000000000010141503741206100223110ustar00rootroot00000000000000 net6.0 false Exe QuantLib-SWIG-1.39/CSharp/swig.cmd000066400000000000000000000001461503741206100165520ustar00rootroot00000000000000swig.exe -csharp -c++ -outdir csharp -namespace QuantLib -o cpp\quantlib_wrap.cpp ..\SWIG\quantlib.i QuantLib-SWIG-1.39/ChangeLog.txt000066400000000000000000000305461503741206100163330ustar00rootroot00000000000000commit 139e7f9489a981798d238edb659d047de2a97f25 Author: Luigi Ballabio Date: Mon, 20 Jan 2025 09:53:26 +0100 Set version to 1.39 final Python/setup.py | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) commit ecc5102de0b28da72bb9d87dc9ae09ca5fad3b4e Author: Luigi Ballabio Date: Mon, 7 Oct 2024 14:29:46 +0200 Set version to 1.39-rc Python/setup.py | 2 +- SWIG/ql.i | 4 ++-- configure.ac | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) commit 72bbed45047ee2602cbba3f282a89f11005f95cb Author: Luigi Ballabio Date: Tue, 8 Jul 2025 13:25:51 +0200 Update news and changelog ChangeLog.txt | 480 ++++++++++++++++++++++++++++++---------------------------- News.md | 64 ++++---- 2 files changed, 285 insertions(+), 259 deletions(-) commit 4443531b301dad8306b6da280f3f43f435ac0f16 Merge: fdc13359 e7511bd2 Author: Luigi Ballabio Date: Mon, 7 Jul 2025 17:29:47 +0200 Export SHIR calendar (#748) commit e7511bd282e80a5af0d4a202f41105f4e14459f2 Author: Luigi Ballabio Date: Mon, 7 Jul 2025 15:51:29 +0200 Export SHIR calendar SWIG/calendars.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) commit fdc13359ddfb4e058c71f329f86a6320c01104a3 Merge: 5277f4c1 06d93e1d Author: Luigi Ballabio Date: Tue, 1 Jul 2025 16:49:42 +0200 Add optional frequency to optionlet stripper (#746) commit 06d93e1d0d0af065f5f12bf2b7c42bdcfe317fe5 Author: Luigi Ballabio Date: Tue, 1 Jul 2025 14:38:40 +0200 Add optional frequency to optionlet stripper SWIG/old_volatility.i | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) commit 5277f4c16455f0ca833ac364514ac236539d35b0 Merge: b5ca9192 feab90aa Author: Luigi Ballabio Date: Mon, 23 Jun 2025 11:17:42 +0200 Expose FxSwapRateHelper.forDates() (#745) commit feab90aaa36095ed013ecdf1c84651a99d437401 Author: Eugene Toder Date: Sat, 21 Jun 2025 13:03:17 -0400 Expose FxSwapRateHelper.forDates() SWIG/ratehelpers.i | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) commit b5ca91929f2dfe1486a2697ae38f5226a20ad161 Merge: 5c68dcf3 56b835d7 Author: Luigi Ballabio Date: Thu, 5 Jun 2025 11:00:23 +0200 Use a Python typemap for `std::variant>` (#744) commit 56b835d746863fce9b75d34ac3b35dbbb20a72f1 Author: Luigi Ballabio Date: Thu, 5 Jun 2025 09:01:51 +0200 Use a Python typemap for variant> SWIG/defaultprobability.i | 44 ++++++++++++++++++++++++++++++++++ SWIG/marketelements.i | 56 +++++++++++++++++++++++++++++++++++++++++++ SWIG/ratehelpers.i | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) commit 5c68dcf37ca40c32cb92067e9340d3099bbe9aa0 Merge: aba15e46 12c40d24 Author: Luigi Ballabio Date: Tue, 3 Jun 2025 18:02:30 +0200 Make nominal curve optional in zero-coupon inflation helper (#743) commit aba15e464b21a3b32bc97895272692e8b8509dba Merge: a57d3a0c 4ec22f1c Author: Luigi Ballabio Date: Tue, 3 Jun 2025 17:28:39 +0200 Export SARON index (#742) commit a57d3a0c0f596eb95ecf00b4204b0a5a65d817fc Merge: ef9a5ada ede8097f Author: Luigi Ballabio Date: Tue, 3 Jun 2025 17:23:50 +0200 Export sabrGuess function (#741) commit 12c40d24a89df5cc2927a90c1fc781b912b649b9 Author: Luigi Ballabio Date: Tue, 3 Jun 2025 16:45:34 +0200 Make nominal curve optional in zero-coupon inflation helper SWIG/inflation.i | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) commit 4ec22f1ccfad62ebb8e0892f03657ef978224ef2 Author: Luigi Ballabio Date: Tue, 3 Jun 2025 16:15:34 +0200 Export SARON index SWIG/indexes.i | 1 + 1 file changed, 1 insertion(+) commit ede8097f6cb5180cbfa82016f1d8128beb06f519 Author: Luigi Ballabio Date: Tue, 3 Jun 2025 15:16:51 +0200 Export sabrGuess function SWIG/volatilities.i | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) commit ef9a5ada3f7cc51d558edaaeba6a10e6a08c9338 Merge: e29aed2c c522f399 Author: Luigi Ballabio Date: Tue, 20 May 2025 15:04:49 +0200 Expose CustomIborIndex (#739) commit e29aed2c06b4772d8137049e663502136a7b521f Author: Luigi Ballabio Date: Tue, 20 May 2025 11:14:10 +0200 Let git ignore generated setup.cfg Python/.gitignore | 1 + 1 file changed, 1 insertion(+) commit c522f399a9acf464af8daf9c370c912c29de664e Author: Eugene Toder Date: Mon, 19 May 2025 23:36:34 -0400 Expose CustomIborIndex SWIG/indexes.i | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) commit 4b0dc5987f7775a7221e46887cf4b2d67a965612 Merge: acd697a9 047104e1 Author: Luigi Ballabio Date: Mon, 19 May 2025 11:50:45 +0200 Expose overnight calendar in OISRateHelper (#737) commit 047104e1a5ef988bcf67ac38c8cbed5d66fae10d Author: Eugene Toder Date: Fri, 16 May 2025 10:02:36 -0400 Expose overnight calendar in OISRateHelper SWIG/ratehelpers.i | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) commit acd697a9a6906969febeac007e1c5b808b89ccf8 Author: Luigi Ballabio Date: Thu, 15 May 2025 15:52:27 +0200 Relax tolerance when indexed coupons are used Python/test/test_volatilities.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) commit 14ecd4616d7d096d904c0cae9ac672a8bf047d1d Merge: c20f0368 c2d03c13 Author: Luigi Ballabio Date: Thu, 15 May 2025 15:19:46 +0200 added support to build a free threading python package (aka no GIL) (#734) commit c20f0368b01e176e84ac0dea6a065a0f283af102 Merge: d57204b7 6fe91f1f Author: Luigi Ballabio Date: Fri, 9 May 2025 15:00:10 +0200 In Python wrap constructor for VanillaSwap directly (#735) commit 6fe91f1ffd693d06ba61b625406152bfd451011f Author: Eugene Toder Date: Tue, 6 May 2025 00:33:54 -0400 In Python wrap constructor for VanillaSwap directly In Python there is a typemap for ext::optional. It's used by Schedule. SWIG/swap.i | 15 +++++++++++++++ 1 file changed, 15 insertions(+) commit c2d03c1332d709ce1a18227833bae40b0ba0e310 Author: klaus spanderen Date: Sun, 4 May 2025 17:29:09 +0200 remove empty init code SWIG/quantlib.i | 4 ---- 1 file changed, 4 deletions(-) commit 0dfa1b9c3cb6cc1ff9529174c9be984f5938af09 Author: klaus spanderen Date: Sun, 4 May 2025 16:50:11 +0200 align with swig 4.4 Python/examples/no-gil-scaling.py | 4 ++-- Python/setup.py | 5 +++-- Python/setup.py.in | 9 +++++++-- SWIG/quantlib.i | 4 ---- 4 files changed, 12 insertions(+), 10 deletions(-) commit d57204b7b041bcef23ded985dd05fa053cda9c5e Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 11:43:19 +0000 Update copyright list in license LICENSE.TXT | 80 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) commit d25595d8ad9ca6848a7cd09bde4e85e5b828c50f Author: Luigi Ballabio Date: Tue, 29 Apr 2025 13:09:33 +0200 Reformat copyright attribution in license tools/collect_copyrights.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) commit 75472c57dbf0312bb989ba2c318305b172904e6b Author: Luigi Ballabio Date: Tue, 29 Apr 2025 13:07:23 +0200 Update or remove some obsolete information CSharp/README.txt | 5 +++-- Java/README.txt | 5 +---- README.md | 27 ++------------------------- Scala/README.txt | 15 ++------------- tools/version_number.txt | 11 ----------- 5 files changed, 8 insertions(+), 55 deletions(-) commit 94913d5dc837c43f5be4364506eaffa9947e6142 Merge: 33ebd559 df0abe7e Author: Luigi Ballabio Date: Mon, 28 Apr 2025 17:08:32 +0200 Allow passing JAVAC_FLAGS for javac compilation (#731) commit df0abe7e4d4069e59cb5b881c85e6889fa529220 Author: Luigi Ballabio Date: Mon, 28 Apr 2025 14:31:26 +0200 Allow passing JAVAC_FLAGS for javac compilation Java/Makefile.am | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) commit 33ebd559547f0bb8a3f73a6387b7145caf4e5f5d Merge: 5c162269 8450f53b Author: Luigi Ballabio Date: Thu, 24 Apr 2025 09:01:15 +0200 Expose data on PiecewiseYieldCurve (#726) commit 5c162269074c5b486e6183f88a072f6200b20cd4 Merge: d80ae866 e464956d Author: Luigi Ballabio Date: Thu, 24 Apr 2025 09:00:11 +0200 Expose convexityAdjustment on FuturesRateHelper (#721) commit d80ae8664b243ff11bd15e9cb391ebf615fcd238 Author: Luigi Ballabio Date: Thu, 24 Apr 2025 08:17:10 +0200 Use SWIG 4.3.1 in CI builds dockerfiles/ci.base.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) commit 2093c0baf56e1d48b8bc4f36e65c120c5ef19c56 Author: Luigi Ballabio Date: Fri, 20 Oct 2023 11:34:41 +0200 Set version to 1.39-dev Python/setup.py | 2 +- R/DESCRIPTION | 2 +- configure.ac | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) commit ee4dbff5d26329207b46692a0927d6196e9d30ef Merge: 2decc178 cf1943c5 Author: Luigi Ballabio Date: Wed, 23 Apr 2025 15:38:43 +0200 Remove features deprecated in version 1.34 and no longer in the underlying C++ library (#727) commit cf1943c535c2a32d7f584362136e987448ecbbdc Author: Luigi Ballabio Date: Wed, 23 Apr 2025 12:36:56 +0200 Fix obsolete method calls in tests Java/examples/Bonds.java | 3 ++- Python/examples/bonds.py | 7 +++++-- Python/test/test_bondfunctions.py | 11 ++++++++--- R/demo/bonds.R | 2 +- Scala/examples/CPIBond.scala | 4 ++-- 5 files changed, 18 insertions(+), 9 deletions(-) commit c23f2d430808c3f434336c65fe22c73e7bbac200 Author: Luigi Ballabio Date: Wed, 23 Apr 2025 11:44:29 +0200 Remove features deprecated in version 1.34 and no longer in C++ library SWIG/bondfunctions.i | 43 ------------------------------------------- SWIG/bonds.i | 7 ------- SWIG/calibrationhelpers.i | 7 +++---- SWIG/inflation.i | 45 +++------------------------------------------ SWIG/ratehelpers.i | 2 -- SWIG/swaption.i | 1 - 6 files changed, 6 insertions(+), 99 deletions(-) commit 8450f53b609007057f982481fd42a197d16a4059 Author: Eugene Toder Date: Mon, 21 Apr 2025 12:13:47 -0400 Expose data on PiecewiseYieldCurve SWIG/piecewiseyieldcurve.i | 1 + 1 file changed, 1 insertion(+) commit e464956de4c85bc0742a6600ec46ec91a203b080 Author: Eugene Toder Date: Thu, 10 Apr 2025 12:12:59 -0400 Expose convexityAdjustment on FuturesRateHelper And on OvernightIndexFutureRateHelper. SWIG/ratehelpers.i | 4 ++++ 1 file changed, 4 insertions(+) commit 4f0f87898651ffe53925911bddc163e78ef7097d Author: klaus spanderen Date: Sun, 9 Mar 2025 16:44:53 +0100 let the setup.py write the config file Python/setup.cfg | 2 -- Python/setup.py | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) commit 42e310a3a8eefac132085819af897c71f9ea3948 Author: klaus spanderen Date: Mon, 3 Mar 2025 09:47:47 +0100 add mt scaling example Python/examples/no-gil-scaling.py | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) commit 249e3986c3a069706354cba7660c664a48050a76 Author: klaus spanderen Date: Sun, 2 Mar 2025 15:27:33 +0100 changes to use QuantLib with Python 3.13s free-threading. Also changes to SWIG itself are necessary Python/setup.cfg | 2 +- Python/setup.py | 4 ++-- SWIG/ode.i | 2 +- SWIG/quantlib.i | 8 ++++++++ 4 files changed, 12 insertions(+), 4 deletions(-) QuantLib-SWIG-1.39/Java/000077500000000000000000000000001503741206100146145ustar00rootroot00000000000000QuantLib-SWIG-1.39/Java/.gitignore000066400000000000000000000001021503741206100165750ustar00rootroot00000000000000bin/ quantlib_wrap.cpp quantlib_wrap.h QuantLib.jar *.jnilib org/ QuantLib-SWIG-1.39/Java/Makefile.am000066400000000000000000000042131503741206100166500ustar00rootroot00000000000000 CLEANFILES = quantlib_wrap.cpp libQuantLibJNI.@JNILIB_EXTENSION@ QuantLib.jar BUILT_SOURCES = quantlib_wrap.cpp quantlib_wrap.h EXAMPLES = Bonds CallableBonds CallableBondsOAS DiscreteHedging EquityOptions FRA FunctionDelegates Time SWIGJAVAFLAGS = if JAVA_AUTOLOAD SWIGJAVAFLAGS += -DJAVA_AUTOLOAD endif if JAVA_FINALIZER SWIGJAVAFLAGS += -DJAVA_FINALIZER endif if JAVA_AUTOCLOSEABLE SWIGJAVAFLAGS += -DJAVA_AUTOCLOSEABLE endif if HAVE_JAVA if BUILD_JAVA JAVAC_FLAGS ?= -O -g -source 8 -target 8 examples/%.class: examples/%.java QuantLib.jar $(JAVAC) -cp QuantLib.jar ${JAVAC_FLAGS} examples/$*.java .PHONY: $(EXAMPLES) all-local: libQuantLibJNI.@JNILIB_EXTENSION@ QuantLib.jar quantlib_wrap.o: quantlib_wrap.cpp quantlib_wrap.h $(CXX) -c quantlib_wrap.cpp -fno-strict-aliasing -fPIC $(CXXFLAGS) @JDK_INCLUDE@ @JDK_SYSTEM_INCLUDE@ `quantlib-config --cflags` -o quantlib_wrap.o libQuantLibJNI.@JNILIB_EXTENSION@: quantlib_wrap.o $(CXX) $(CXXFLAGS) $(LDFLAGS) @SHARED_LIB@ quantlib_wrap.o -o libQuantLibJNI.@JNILIB_EXTENSION@ `quantlib-config --libs` QuantLib.jar: quantlib_wrap.cpp org/quantlib/*.java mkdir -p bin find org/quantlib -name '*.java' | xargs $(JAVAC) ${JAVAC_FLAGS} -d bin $(JAR) cf QuantLib.jar -C bin org install-exec-local: mkdir -p $(DESTDIR)/$(libdir) cp -p libQuantLibJNI.@JNILIB_EXTENSION@ $(DESTDIR)/$(libdir)/libQuantLibJNI.@JNILIB_EXTENSION@ cp -p QuantLib.jar $(DESTDIR)/$(libdir)/QuantLib.jar check-local: $(EXAMPLES) $(EXAMPLES): $(EXAMPLES:%=examples/%.class) LD_LIBRARY_PATH=. $(JAVA) -cp ".:QuantLib.jar" examples.$@ endif endif quantlib_wrap.cpp: ../SWIG/*.i mkdir -p org/quantlib rm -f org/quantlib/*.java $(SWIG) $(SWIGFLAGS) $(SWIGJAVAFLAGS) -java -c++ -outdir org/quantlib \ -package org.quantlib -o quantlib_wrap.cpp ../SWIG/quantlib.i dist-hook: mkdir -p $(distdir)/org/quantlib cp ./org/quantlib/*.java $(distdir)/org/quantlib touch $(distdir)/quantlib_wrap.cpp touch $(distdir)/quantlib_wrap.h mkdir -p $(distdir)/examples cp ./examples/*.java $(distdir)/examples clean-local: rm -rf org rm -f examples/*.class rm -f quantlib_wrap.o rm -rf bin EXTRA_DIST = README.txt $(BUILT_SOURCES) QuantLib-SWIG-1.39/Java/README.txt000066400000000000000000000005001503741206100163050ustar00rootroot00000000000000 On Linux systems, the module can be build by supplying the location of the JDK to configure, as in (for example) ./autogen.sh ./configure --with-jdk-include=/usr/lib/jvm/java-1.5.0-sun-1.5.0.08/include \ --with-jdk-system-include=usr/lib/jvm/java-1.5.0-sun-1.5.0.08/include/linux and by running 'make' afterwards. QuantLib-SWIG-1.39/Java/examples/000077500000000000000000000000001503741206100164325ustar00rootroot00000000000000QuantLib-SWIG-1.39/Java/examples/Bonds.java000066400000000000000000000535341503741206100203540ustar00rootroot00000000000000 /* Copyright (C) 2014 Wondersys Srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ package examples; import java.util.ArrayList; import org.quantlib.Actual360; import org.quantlib.Actual365Fixed; import org.quantlib.ActualActual; import org.quantlib.BlackIborCouponPricer; import org.quantlib.BondPrice; import org.quantlib.BusinessDayConvention; import org.quantlib.Calendar; import org.quantlib.Compounding; import org.quantlib.ConstantOptionletVolatility; import org.quantlib.Date; import org.quantlib.DateGeneration; import org.quantlib.DayCounter; import org.quantlib.DepositRateHelper; import org.quantlib.DiscountingBondEngine; import org.quantlib.DoubleVector; import org.quantlib.Euribor6M; import org.quantlib.FixedRateBond; import org.quantlib.FixedRateBondHelper; import org.quantlib.FloatingRateBond; import org.quantlib.FloatingRateCouponPricer; import org.quantlib.Frequency; import org.quantlib.IborCouponPricer; import org.quantlib.IborIndex; import org.quantlib.Month; import org.quantlib.OptionletVolatilityStructureHandle; import org.quantlib.Period; import org.quantlib.PiecewiseFlatForward; import org.quantlib.PiecewiseLinearForward; import org.quantlib.PricingEngine; import org.quantlib.QuantLib; import org.quantlib.QuantLibJNI; import org.quantlib.QuoteHandle; import org.quantlib.QuoteVector; import org.quantlib.RateHelper; import org.quantlib.RateHelperVector; import org.quantlib.QuoteHandleVector; import org.quantlib.RelinkableYieldTermStructureHandle; import org.quantlib.Schedule; import org.quantlib.Settings; import org.quantlib.SimpleQuote; import org.quantlib.SwapRateHelper; import org.quantlib.TARGET; import org.quantlib.Thirty360; import org.quantlib.TimeUnit; import org.quantlib.USDLibor; import org.quantlib.UnitedStates; import org.quantlib.YieldTermStructure; import org.quantlib.YieldTermStructureHandle; import org.quantlib.ZeroCouponBond; public class Bonds { public static void main(String[] args) throws Exception { // MARKET DATA Calendar cal = new TARGET(); Date settlementDate = new Date(18, Month.September, 2008); // must be a business day settlementDate = cal.adjust(settlementDate); int fixingDays = 3; int settlementdays = 3; Date todayDate = cal.advance(settlementDate, -fixingDays, TimeUnit.Days); Settings.instance().setEvaluationDate(todayDate); System.out.println("Today: " + todayDate.weekday() + ", " + todayDate); System.out.println("Settlement date: " + settlementDate.weekday() + ", " + settlementDate); // Building of the bonds discounting yield curve // RATE HELPERS // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // Common data // ZC rates for the short end QuoteHandle zc3mRate = new QuoteHandle(new SimpleQuote(0.0096)); QuoteHandle zc6mRate = new QuoteHandle(new SimpleQuote(0.0145)); QuoteHandle zc1yRate = new QuoteHandle(new SimpleQuote(0.0194)); DayCounter zcBondsDayCounter = new Actual365Fixed(); DepositRateHelper zc3m = new DepositRateHelper(zc3mRate, new Period(3, TimeUnit.Months), fixingDays, cal, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); DepositRateHelper zc6m = new DepositRateHelper(zc6mRate, new Period(6, TimeUnit.Months), fixingDays, cal, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); DepositRateHelper zc1y = new DepositRateHelper(zc1yRate, new Period(1, TimeUnit.Years), fixingDays, cal, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); // setup bonds double redemption = 100.0; final int numberOfBonds = 5; Date issueDates[] = { new Date(15, Month.March, 2005), new Date(15, Month.June, 2005), new Date(30, Month.June, 2006), new Date(15, Month.November, 2002), new Date(15, Month.May, 1987), }; Date maturities[] = { new Date(31, Month.August, 2010), new Date(31, Month.August, 2011), new Date(31, Month.August, 2013), new Date(15, Month.August, 2018), new Date(15, Month.May, 2038), }; double couponRates[] = { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; SimpleQuote marketQuotes[] = { new SimpleQuote(100.390625), new SimpleQuote(106.21875), new SimpleQuote(100.59375), new SimpleQuote(101.6875), new SimpleQuote(102.140625) }; QuoteHandleVector quoteHandle = new QuoteHandleVector(); for (int i=0; i bondHelpers = new ArrayList(); for (int i=0; i. The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ package examples; import org.quantlib.CallableFixedRateBond; import org.quantlib.Date; import org.quantlib.Period; import org.quantlib.Settings; import org.quantlib.DayCounter; import org.quantlib.ActualActual; import org.quantlib.Compounding; import org.quantlib.Frequency; import org.quantlib.FlatForward; import org.quantlib.QuoteHandle; import org.quantlib.Quote; import org.quantlib.SimpleQuote; import org.quantlib.YieldTermStructure; import org.quantlib.YieldTermStructureHandle; import org.quantlib.InterestRate; import org.quantlib.Month; import org.quantlib.Date; import org.quantlib.CallabilitySchedule; import org.quantlib.Schedule; import org.quantlib.NullCalendar; import org.quantlib.UnitedStates; import org.quantlib.Calendar; import org.quantlib.Callability; import org.quantlib.BondPrice; import org.quantlib.TimeUnit; import org.quantlib.BusinessDayConvention; import org.quantlib.DateGeneration; import org.quantlib.ShortRateModel; import org.quantlib.HullWhite; import org.quantlib.PricingEngine; import org.quantlib.TreeCallableFixedRateBondEngine; import org.quantlib.DoubleVector; public class CallableBonds { public static YieldTermStructure flatRate(Date today, Quote forward, DayCounter dc, Compounding compounding, Frequency frequency) { return new FlatForward(today, new QuoteHandle(forward), dc, compounding, frequency); } public static void priceCallable(double sigma, YieldTermStructureHandle termStructure, CallableFixedRateBond callableBond, Frequency frequency, DayCounter bondDayCounter) { long maxIterations = 1000; double accuracy = 1e-8; long gridIntervals = 40; double reversionParameter = .03; ShortRateModel hw0 = new HullWhite(termStructure, reversionParameter, sigma); PricingEngine engine0 = new TreeCallableFixedRateBondEngine(hw0, gridIntervals); callableBond.setPricingEngine(engine0); System.out.printf("sigma/vol (%%) = %6.2f \n", 100.*sigma); System.out.printf("QuantLib price/yld (%%) %10.2f / %10.2f \n", callableBond.cleanPrice(), 100.0 * callableBond.yield(bondDayCounter, Compounding.Compounded, frequency, accuracy, maxIterations)); System.out.printf("QuantLib OAS from model clean price (bp) %10.2f \n", 10000.0 * callableBond.OAS(callableBond.cleanPrice(), termStructure, bondDayCounter, Compounding.Compounded, frequency)); double cp=callableBond.cleanPriceOAS(10*1e-4, termStructure, bondDayCounter, Compounding.Compounded, frequency); System.out.printf("QuantLib spreaded clean price with 10bp OAS %f \n", cp); System.out.printf("QuantLib OAS from spreaded clean price (bp) %10.2f \n", 10000.0 * callableBond.OAS(cp, termStructure, bondDayCounter, Compounding.Compounded, frequency)); System.out.printf("QuantLib effectiveDuration / convexity for 10bp OAS %f / %f \n", callableBond.effectiveDuration(10*1e-4, termStructure, bondDayCounter, Compounding.Compounded, frequency), callableBond.effectiveConvexity(10*1e-4, termStructure, bondDayCounter, Compounding.Compounded, frequency)); } public static void main(String[] args) throws Exception { System.out.println("Callable Bonds example:"); Date today = new Date(16, Month.October, 2007); Settings.instance().setEvaluationDate(today); double bbCurveRate = 0.055; DayCounter bbDayCounter = new ActualActual(ActualActual.Convention.Bond); InterestRate bbIR = new InterestRate(bbCurveRate, bbDayCounter, Compounding.Compounded, Frequency.Semiannual); YieldTermStructureHandle termStructure = new YieldTermStructureHandle(flatRate(today, new SimpleQuote(bbIR.rate()), bbIR.dayCounter(), bbIR.compounding(), bbIR.frequency())); // set up the call schedule CallabilitySchedule callSchedule = new CallabilitySchedule(); double callPrice = 100.; long numberOfCallDates = 24; Date callDate = new Date(15, Month.September, 2006); Calendar nullCalendar = new NullCalendar(); for (long i=0; i< numberOfCallDates; ++i) { BondPrice myPrice= new BondPrice(callPrice, BondPrice.Type.Clean); callSchedule.add(new Callability(myPrice, Callability.Type.Call, callDate)); callDate = nullCalendar.advance(callDate, 3, TimeUnit.Months); } // set up the callable bond Date dated = new Date(16, Month.September, 2004); Date issue = dated; Date maturity = new Date(15, Month.September, 2012); int settlementDays = 3; // Bloomberg OAS1 settle is Oct 19, 2007 Calendar bondCalendar = new UnitedStates(UnitedStates.Market.GovernmentBond); double coupon = .0465; Frequency frequency = Frequency.Quarterly; double redemption = 100.0; double faceAmount = 100.0; /* The 30/360 day counter Bloomberg uses for this bond cannot reproduce the US Bond/ISMA (constant) cashflows used in PFC1. Therefore use ActAct(Bond) */ DayCounter bondDayCounter = new ActualActual(ActualActual.Convention.Bond); // PFC1 shows no indication dates are being adjusted // for weekends/holidays for vanilla bonds BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention paymentConvention = BusinessDayConvention.Unadjusted; Schedule sch = new Schedule(dated, maturity, new Period(frequency), bondCalendar, accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false); DoubleVector couponsVector = new DoubleVector(); couponsVector.add(coupon); CallableFixedRateBond callableBond = new CallableFixedRateBond(settlementDays, faceAmount, sch, couponsVector, bondDayCounter, paymentConvention, redemption, issue, callSchedule); priceCallable(1e-20, termStructure, callableBond, frequency, bondDayCounter); System.out.printf("Bloomberg price/yld (%%) 96.50 / 5.47 \n"); priceCallable(0.01, termStructure, callableBond, frequency, bondDayCounter); System.out.printf("Bloomberg price/yld (%%) 95.68 / 5.66 \n"); priceCallable(0.03, termStructure, callableBond, frequency, bondDayCounter); System.out.printf("Bloomberg price/yld (%%) 92.34 / 6.49 \n"); priceCallable(0.06, termStructure, callableBond, frequency, bondDayCounter); System.out.printf("Bloomberg price/yld (%%) 87.16 / 7.83 \n"); priceCallable(0.12, termStructure, callableBond, frequency, bondDayCounter); System.out.printf("Bloomberg price/yld (%%) 77.31 / 10.65 \n"); System.out.println("Done"); } } QuantLib-SWIG-1.39/Java/examples/CallableBondsOAS.java000066400000000000000000000271261503741206100223350ustar00rootroot00000000000000/* Copyright (C) 2017 BN Algorithms Ltd This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ package examples; import java.util.stream.IntStream; import org.quantlib.Settings; import org.quantlib.CallableFixedRateBond; import org.quantlib.CallabilitySchedule; import org.quantlib.BondPrice; import org.quantlib.Callability; import org.quantlib.TreeCallableFixedRateBondEngine; import org.quantlib.HullWhite; import org.quantlib.YieldTermStructure; import org.quantlib.YieldTermStructureHandle; import org.quantlib.RelinkableYieldTermStructureHandle; import org.quantlib.PiecewiseFlatForward; import org.quantlib.TimeUnit; import org.quantlib.RateHelperVector; import org.quantlib.Calendar; import org.quantlib.Compounding; import org.quantlib.UnitedStates; import org.quantlib.NullCalendar; import org.quantlib.BusinessDayConvention; import org.quantlib.DateGeneration; import org.quantlib.Period; import org.quantlib.Schedule; import org.quantlib.DoubleVector; import org.quantlib.ZeroCouponBond; import org.quantlib.FlatForward; import org.quantlib.Actual360; import org.quantlib.Thirty360; import org.quantlib.ActualActual; import org.quantlib.Month; import org.quantlib.Frequency; import org.quantlib.Date; import org.quantlib.DiscountingBondEngine; import org.quantlib.BondHelper; import org.quantlib.QuoteHandle; import org.quantlib.SimpleQuote; /** Examples focusing on the OAS and related functions of callable * bonds. */ public class CallableBondsOAS { static public final Date today = new Date(28, Month.March, 2017); static public YieldTermStructure mkYC() { Calendar cal = new UnitedStates(UnitedStates.Market.GovernmentBond); final int np = 12; double ycrate[] = { 0.772, 0.917, 1.011, 1.302, 1.549, 1.822, 1.964, 2.242, 2.418, 2.763, 3.025, 3.025}; int ycInt[] = { 3, 6, 1, 2, 3, 4, 5, 7, 10, 20, 30, 50 }; TimeUnit ycUnit[] = { TimeUnit.Months, TimeUnit.Months, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years, TimeUnit.Years}; RateHelperVector helpers = new RateHelperVector(); for (int i=0; i { return valuePar(558.8-0.0000001*e, yc); }) .forEachOrdered( e -> { System.out.print( e +" ");} ); } } QuantLib-SWIG-1.39/Java/examples/DiscreteHedging.java000066400000000000000000000335611503741206100223350ustar00rootroot00000000000000 /* Copyright (C) 2008 Tito Ingargiola This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ package examples; import org.quantlib.Actual365Fixed; import org.quantlib.BlackCalculator; import org.quantlib.BlackConstantVol; import org.quantlib.BlackScholesMertonProcess; import org.quantlib.BlackVolTermStructureHandle; import org.quantlib.Calendar; import org.quantlib.Date; import org.quantlib.DayCounter; import org.quantlib.FlatForward; import org.quantlib.GaussianPathGenerator; import org.quantlib.GaussianRandomSequenceGenerator; import org.quantlib.Option; import org.quantlib.Path; import org.quantlib.PlainVanillaPayoff; import org.quantlib.QuoteHandle; import org.quantlib.SamplePath; import org.quantlib.SimpleQuote; import org.quantlib.Statistics; import org.quantlib.TARGET; import org.quantlib.UniformRandomGenerator; import org.quantlib.UniformRandomSequenceGenerator; import org.quantlib.YieldTermStructureHandle; /** * DiscreteHedging Test app - java version of QuantLib/Examples/DiscreteHedging * to illustrate use of Quantlib's MonteCarlo functionality through supplied * SWIG interfaces. * * You need to run this with a correctly set library path and something like: * * -Djava.library.path=/usr/local/lib * * @author Tito Ingargiola **/ public class DiscreteHedging { public static void main(String[] args) throws Exception { long begin = System.currentTimeMillis(); double maturity = 1.0/12.0; // 1 month double strike = 100; double underlying = 100; double volatility = 0.20; // 20% double riskFreeRate = 0.05; // 5% ReplicationError rp = new ReplicationError(Option.Type.Call, maturity, strike, underlying, volatility, riskFreeRate); long scenarios = 50000; long hedgesNum = 21; rp.compute(hedgesNum, scenarios); hedgesNum = 84; rp.compute(hedgesNum, scenarios); long msecs = (System.currentTimeMillis()-begin); System.out.println("\nRun completed in "+msecs+" ms."); } /** * The ReplicationError class carries out Monte Carlo simulations to * evaluate the outcome (the replication error) of the discrete hedging * strategy over different, randomly generated scenarios of future stock * price evolution. **/ public static class ReplicationError { public ReplicationError(Option.Type type, double maturity, double strike, double s0, double sigma, double r ) { type_ = type; maturity_ = maturity; strike_ = strike; s0_ = s0; sigma_ = sigma; r_ = r; // value of the option double rDiscount = Math.exp(-r_ * maturity_); double qDiscount = 1.0; double forward = s0_ * qDiscount/rDiscount; double stdDev = Math.sqrt(sigma_*sigma_*maturity); BlackCalculator black = new BlackCalculator (new PlainVanillaPayoff(type,strike),forward,stdDev,rDiscount); System.out.printf("Option value: %2.5f \n\n",black.value()); // store option's vega, since Derman and Kamal's formula needs it vega_ = black.vega(maturity_); String fmt ="%-8s | %-8s | %-8s | %-8s | %-12s | %-8s | %-8s \n"; System.out.printf (fmt, " ", " ", "P&L", "P&L", "Derman&Kamal", "P&L","P&L" ); System.out.printf(fmt, " samples", "trades", "mean", "std.dev", "formula", "skewness","kurtosis" ); for (int i = 0; i < 78; i++) System.out.print("-"); System.out.println("-"); } void compute(long nTimeSteps, long nSamples) { assert nTimeSteps>0 : "the number of steps must be > 0"; /* Black-Scholes framework: the underlying stock price evolves lognormally with a fixed known volatility that stays constant throughout time. */ Calendar calendar = new TARGET(); Date today = Date.todaysDate(); DayCounter dayCounter = new Actual365Fixed(); QuoteHandle stateVariable = new QuoteHandle(new SimpleQuote(s0_)); YieldTermStructureHandle riskFreeRate = new YieldTermStructureHandle (new FlatForward(today, r_, dayCounter)); YieldTermStructureHandle dividendYield = new YieldTermStructureHandle (new FlatForward(today, 0.0, dayCounter)); BlackVolTermStructureHandle volatility = new BlackVolTermStructureHandle( new BlackConstantVol(today, calendar, sigma_, dayCounter)); BlackScholesMertonProcess diffusion = new BlackScholesMertonProcess (stateVariable,dividendYield, riskFreeRate, volatility); // Black Scholes equation rules the path generator: // at each step the log of the stock // will have drift and sigma^2 variance boolean brownianBridge = false; GaussianRandomSequenceGenerator rsg = new GaussianRandomSequenceGenerator (new UniformRandomSequenceGenerator (nTimeSteps,new UniformRandomGenerator(0))); GaussianPathGenerator myPathGenerator = new GaussianPathGenerator (diffusion,maturity_,nTimeSteps,rsg, brownianBridge); /* Alternately you can modify the MonteCarloModel to take a * GaussianSobolPathGenerator and uncomment these lines and * comment those just above * GaussianLowDiscrepancySequenceGenerator rsg = new GaussianLowDiscrepancySequenceGenerator (new UniformLowDiscrepancySequenceGenerator (nTimeSteps)); GaussianSobolPathGenerator myPathGenerator = new GaussianSobolPathGenerator (diffusion,maturity_,nTimeSteps,rsg, brownianBridge);*/ ReplicationPathPricer myPathPricer = new ReplicationPathPricer (type_,strike_, r_, maturity_, sigma_); MonteCarloModel mcSimulation = new MonteCarloModel (myPathGenerator, myPathPricer); mcSimulation.addSamples(nSamples); // the sampleAccumulator method // gives access to all the methods of statisticsAccumulator double PLMean = mcSimulation.sampleAccumulator().mean(); double PLStDev = mcSimulation.sampleAccumulator().standardDeviation(); double PLSkew = mcSimulation.sampleAccumulator().skewness(); double PLKurt = mcSimulation.sampleAccumulator().kurtosis(); // Derman and Kamal's formula double theorStD = Math.sqrt(Math.PI/4/nTimeSteps)*vega_*sigma_; String fmt = "%-8d | %-8d | %-8.3f | %-8.2f | %-12.2f | %-8.2f | %-8.2f \n"; System.out.printf(fmt, nSamples, nTimeSteps, PLMean, PLStDev, theorStD, PLSkew, PLKurt ); } double maturity_; Option.Type type_; double strike_; double s0_; double sigma_; double r_; double vega_; } /** * We pull the interface for a PathPricer into Java so we can * support its implementation in Java while still relying upon QuantLib's * powerful RNGs. */ public static interface JPathPricer { public double price(Path path); } // The key for the MonteCarlo simulation is to have a PathPricer that // implements a value(const Path& path) method. // This method prices the portfolio for each Path of the random variable public static class ReplicationPathPricer implements JPathPricer { public ReplicationPathPricer(Option.Type type, double strike, double r, double maturity, double sigma) { assert strike > 0 : "Strike must be positive!"; assert maturity > 0 : "Risk free rate must be positive!"; assert r >= 0 : "Risk free rate must be positive or Zero!"; assert sigma >= 0 : "Volatility must be positive or Zero!"; type_ = type; strike_ = strike; r_ = r; maturity_ = maturity; sigma_ = sigma; } public double price(Path path) { long n = path.length() - 1; assert n > 0 : "The path can't be empty!"; // discrete hedging interval double dt = maturity_ / n; // For simplicity, we assume the stock pays no dividends. double stockDividendYield = 0.0; // let's start double t = 0; // stock value at t=0 double stock = path.front(); // money account at t=0 double money_account = 0.0; /************************/ /*** the initial deal ***/ /************************/ // option fair price (Black-Scholes) at t=0 double rDiscount = Math.exp(-r_*maturity_); double qDiscount = Math.exp(-stockDividendYield*maturity_); double forward = stock*qDiscount/rDiscount; double stdDev = Math.sqrt(sigma_*sigma_*maturity_); PlainVanillaPayoff payoff = new PlainVanillaPayoff(type_,strike_); BlackCalculator black = new BlackCalculator (payoff,forward,stdDev,rDiscount); // sell the option, cash in its premium money_account += black.value(); // compute delta double delta = black.delta(stock); // delta-hedge the option buying stock double stockAmount = delta; money_account -= stockAmount*stock; /**********************************/ /*** hedging during option life ***/ /**********************************/ for (long step = 0; step < n-1; step++){ // time flows t += dt; // accruing on the money account money_account *= Math.exp( r_*dt ); // stock growth: stock = path.value(step+1); // recalculate option value at the current stock value, // and the current time to maturity rDiscount = Math.exp(-r_*(maturity_-t)); qDiscount = Math.exp(-stockDividendYield*(maturity_-t)); forward = stock*(qDiscount/rDiscount); stdDev = Math.sqrt(sigma_*sigma_*(maturity_-t)); black = new BlackCalculator (new PlainVanillaPayoff(type_,strike_),forward,stdDev,rDiscount); // recalculate delta delta = black.delta(stock); // re-hedging money_account -= (delta - stockAmount)*stock; stockAmount = delta; } /*************************/ /*** option expiration ***/ /*************************/ // last accrual on my money account money_account *= Math.exp( r_*dt ); // last stock growth stock = path.value(n); // the hedger delivers the option payoff to the option holder double optionPayoff = (new PlainVanillaPayoff(type_, strike_)).getValue(stock); money_account -= optionPayoff; // and unwinds the hedge selling his stock position money_account += stockAmount*stock; // final Profit&Loss return money_account; } double maturity_; Option.Type type_; double strike_; double sigma_; double r_; } /** * We pull the MonteCarloModel into Java so that we can enable the * implementation in java of our PathPricer */ public static class MonteCarloModel { /** convenience ctor **/ public MonteCarloModel (GaussianPathGenerator gpg, JPathPricer pathpricer) { this(gpg,pathpricer,false, null); } /** complete ctor **/ public MonteCarloModel(GaussianPathGenerator gpg, JPathPricer pathpricer, boolean antitheticVariate, Statistics stats ) { assert gpg != null : "PathGenerator must not be null!"; assert pathpricer != null : "PathPricer must not be null!"; gpg_ = gpg; ppricer_ = pathpricer; stats_ = (stats==null) ? new Statistics() : stats; av_ = antitheticVariate; } public Statistics sampleAccumulator () { return stats_; } public void addSamples( long samples ) { for(long j = 0; j < samples; j++) { SamplePath path = gpg_.next(); double price = ppricer_.price(path.value()); if ( av_ ) { path = gpg_.antithetic(); double price2 = ppricer_.price(path.value()); stats_.add((price+price2)/2.0, path.weight()); } else { stats_.add(price, path.weight()); } } } final boolean av_; final GaussianPathGenerator gpg_; final JPathPricer ppricer_; final Statistics stats_; } } QuantLib-SWIG-1.39/Java/examples/EquityOptions.java000066400000000000000000000456741503741206100221510ustar00rootroot00000000000000 /* Copyright (C) 2007 Richard Gomes Copyright (C) 2007 Tito Ingargiola This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ package examples; import org.quantlib.QuantLib; import org.quantlib.Actual365Fixed; import org.quantlib.AmericanExercise; import org.quantlib.AnalyticEuropeanEngine; import org.quantlib.AnalyticHestonEngine; import org.quantlib.AnalyticHestonEngine_Integration; import org.quantlib.AnalyticPTDHestonEngine; import org.quantlib.BaroneAdesiWhaleyApproximationEngine; import org.quantlib.BatesEngine; import org.quantlib.BatesModel; import org.quantlib.BatesProcess; import org.quantlib.BermudanExercise; import org.quantlib.BinomialCRRVanillaEngine; import org.quantlib.BinomialEQPVanillaEngine; import org.quantlib.BinomialJ4VanillaEngine; import org.quantlib.BinomialJRVanillaEngine; import org.quantlib.BinomialLRVanillaEngine; import org.quantlib.BinomialTianVanillaEngine; import org.quantlib.BinomialTrigeorgisVanillaEngine; import org.quantlib.BjerksundStenslandApproximationEngine; import org.quantlib.BlackConstantVol; import org.quantlib.BlackScholesMertonProcess; import org.quantlib.BlackVolTermStructureHandle; import org.quantlib.BoundaryConstraint; import org.quantlib.Calendar; import org.quantlib.ConstantParameter; import org.quantlib.COSHestonEngine; import org.quantlib.Date; import org.quantlib.DateVector; import org.quantlib.DayCounter; import org.quantlib.EuropeanExercise; import org.quantlib.Exercise; import org.quantlib.FdBlackScholesVanillaEngine; import org.quantlib.HestonModel; import org.quantlib.HestonProcess; import org.quantlib.FlatForward; import org.quantlib.IntegralEngine; import org.quantlib.MCLDEuropeanEngine; import org.quantlib.MCPREuropeanEngine; import org.quantlib.MCPREuropeanHestonEngine; import org.quantlib.Month; import org.quantlib.Option; import org.quantlib.Payoff; import org.quantlib.Period; import org.quantlib.PiecewiseTimeDependentHestonModel; import org.quantlib.PlainVanillaPayoff; import org.quantlib.PositiveConstraint; import org.quantlib.QuoteHandle; import org.quantlib.Settings; import org.quantlib.SimpleQuote; import org.quantlib.TARGET; import org.quantlib.TimeGrid; import org.quantlib.TimeUnit; import org.quantlib.VanillaOption; import org.quantlib.YieldTermStructureHandle; /** * EquityOption Test app - java version of QuantLib/Examples/EquityOption * to illustrate use of Quantlib through supplied SWIG interfaces. * * You need to run this with a correctly set library path and something like: * * -Djava.library.path=/usr/local/lib * * @author Richard Gomes * @author Tito Ingargiola */ public class EquityOptions { public static void main(String[] args) throws Exception { long beginTime = System.currentTimeMillis(); // our option Option.Type type = Option.Type.Put; double strike = 40.0; double underlying = 36.0; double riskFreeRate = 0.06; double dividendYield = 0.00; double volatility = 0.2; Date todaysDate = new Date(15, Month.May, 1998); Date settlementDate = new Date(17, Month.May, 1998); Settings.instance().setEvaluationDate(todaysDate); Date maturity = new Date(17, Month.May, 1999); DayCounter dayCounter = new Actual365Fixed(); Calendar calendar = new TARGET(); // write column headings String fmt = "\n%-35s %-14s %-14s %-14s\n"; System.out.printf(fmt, "Method", "European", "Bermudan", "American"); System.out.println("============================================================================"); // define European, Bermudan, and American exercises DateVector exerciseDates = new DateVector(); for (int i = 1; i <= 4; i++) { Date forward = settlementDate.add(new Period(3*i, TimeUnit.Months)); exerciseDates.add(forward); } Exercise europeanExercise = new EuropeanExercise(maturity); Exercise bermudanExercise = new BermudanExercise(exerciseDates); Exercise americanExercise = new AmericanExercise(settlementDate, maturity); // define the underlying asset and the yield/dividend/volatility curves QuoteHandle underlyingH = new QuoteHandle(new SimpleQuote(underlying)); YieldTermStructureHandle flatTermStructure = new YieldTermStructureHandle(new FlatForward( settlementDate, riskFreeRate, dayCounter)); YieldTermStructureHandle flatDividendYield = new YieldTermStructureHandle(new FlatForward( settlementDate, dividendYield, dayCounter)); BlackVolTermStructureHandle flatVolatility = new BlackVolTermStructureHandle(new BlackConstantVol( settlementDate, calendar, volatility, dayCounter)); BlackScholesMertonProcess stochasticProcess = new BlackScholesMertonProcess(underlyingH, flatDividendYield, flatTermStructure, flatVolatility); // options PlainVanillaPayoff payoff = new PlainVanillaPayoff(type, strike); VanillaOption europeanOption = new VanillaOption(payoff, europeanExercise); VanillaOption bermudanOption = new VanillaOption(payoff, bermudanExercise); VanillaOption americanOption = new VanillaOption(payoff, americanExercise); fmt = "%34s %13.9f %13.9f %13.9f\n"; // Analytic formulas: // Black-Scholes for European String method = "Black-Scholes"; europeanOption.setPricingEngine( new AnalyticEuropeanEngine(stochasticProcess)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); // Heston method = "Heston Semi-Analytic"; HestonProcess hestonProcess = new HestonProcess(flatTermStructure, flatDividendYield, underlyingH, volatility*volatility, 1.0, volatility*volatility, 0.0001, 0.0); HestonModel hestonModel = new HestonModel(hestonProcess); europeanOption.setPricingEngine(new AnalyticHestonEngine(hestonModel)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); method = "Heston COS Method"; europeanOption.setPricingEngine(new COSHestonEngine(hestonModel)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); method = "Heston time dependent parameter"; europeanOption.setPricingEngine( new AnalyticPTDHestonEngine( new PiecewiseTimeDependentHestonModel( flatTermStructure, flatDividendYield, underlyingH, volatility*volatility, new ConstantParameter(volatility*volatility, new PositiveConstraint()), new ConstantParameter(1.0, new PositiveConstraint()), new ConstantParameter(1e-4, new PositiveConstraint()), new ConstantParameter(0.0, new BoundaryConstraint(-1.0, 1.0)), new TimeGrid(dayCounter.yearFraction(todaysDate, maturity), 10) ), AnalyticPTDHestonEngine.ComplexLogFormula.AndersenPiterbarg, AnalyticHestonEngine_Integration.gaussLaguerre(32)) ); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); // Bates method = "Bates Semi-Analytic"; BatesProcess batesProcess = new BatesProcess(flatTermStructure, flatDividendYield, underlyingH, volatility*volatility, 1.0, volatility*volatility, 0.0001, 0.0, 1e-14, 1e-14, 1e-14); BatesModel batesModel = new BatesModel(batesProcess); europeanOption.setPricingEngine(new BatesEngine(batesModel)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); // Barone-Adesi and Whaley approximation for American method = "Barone-Adesi/Whaley"; americanOption.setPricingEngine( new BaroneAdesiWhaleyApproximationEngine(stochasticProcess)); System.out.printf(fmt, new Object[] { method, Double.NaN, Double.NaN, americanOption.NPV() } ); // Bjerksund and Stensland approximation for American method = "Bjerksund/Stensland"; americanOption.setPricingEngine( new BjerksundStenslandApproximationEngine(stochasticProcess)); System.out.printf(fmt, new Object[] { method, Double.NaN, Double.NaN, americanOption.NPV() } ); // Integral method = "Integral"; europeanOption.setPricingEngine(new IntegralEngine(stochasticProcess)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); // Finite differences int timeSteps = 801; method = "Finite differences"; europeanOption.setPricingEngine( new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps-1)); bermudanOption.setPricingEngine( new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps-1)); americanOption.setPricingEngine( new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps-1)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() }); // Binomial method method = "Binomial Jarrow-Rudd"; europeanOption.setPricingEngine(new BinomialJRVanillaEngine( stochasticProcess, timeSteps)); bermudanOption.setPricingEngine(new BinomialJRVanillaEngine( stochasticProcess, timeSteps)); americanOption.setPricingEngine(new BinomialJRVanillaEngine( stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); method = "Binomial Cox-Ross-Rubinstein"; europeanOption.setPricingEngine( new BinomialCRRVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialCRRVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialCRRVanillaEngine(stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); method = "Additive equiprobabilities"; europeanOption.setPricingEngine( new BinomialEQPVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialEQPVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialEQPVanillaEngine(stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); method = "Binomial Trigeorgis"; europeanOption.setPricingEngine( new BinomialTrigeorgisVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialTrigeorgisVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialTrigeorgisVanillaEngine(stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); method = "Binomial Tian"; europeanOption.setPricingEngine( new BinomialTianVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialTianVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialTianVanillaEngine(stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); method = "Binomial Leisen-Reimer"; europeanOption.setPricingEngine( new BinomialLRVanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialLRVanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialLRVanillaEngine(stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); method = "Binomial Joshi"; europeanOption.setPricingEngine( new BinomialJ4VanillaEngine(stochasticProcess, timeSteps)); bermudanOption.setPricingEngine( new BinomialJ4VanillaEngine(stochasticProcess, timeSteps)); americanOption.setPricingEngine( new BinomialJ4VanillaEngine(stochasticProcess, timeSteps)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV() } ); // Monte Carlo Method timeSteps = 1; int mcSeed = 42; int nSamples = 32768; // 2^15 int maxSamples = 1048576; // 2^20 method = "MC (crude)"; europeanOption.setPricingEngine( new MCPREuropeanEngine(stochasticProcess, timeSteps, QuantLib.nullInt(), false, false, nSamples, 0.02, maxSamples, mcSeed)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); method = "MC (Sobol)"; europeanOption.setPricingEngine( new MCLDEuropeanEngine(stochasticProcess, timeSteps, QuantLib.nullInt(), false, false, nSamples, 0.02, maxSamples, mcSeed)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); method = "Heston Monte-Carlo"; europeanOption.setPricingEngine( new MCPREuropeanHestonEngine(hestonProcess, 25, QuantLib.nullInt(), true, nSamples)); System.out.printf(fmt, new Object[] { method, europeanOption.NPV(), Double.NaN, Double.NaN } ); /* method = "MC (Longstaff Schwartz)"; // This is the original C++ code: // MakeMCAmericanEngine().withSteps(100) // .withAntitheticVariate() // .withCalibrationSamples(4096) // .withTolerance(0.02) // .withSeed(mcSeed); System.out.printf(fmt, new Object[] { method, Double.NaN, Double.NaN, americanOption.NPV() }); */ long msecs = (System.currentTimeMillis()-beginTime); System.out.println("Run completed in "+msecs+" ms."); } } QuantLib-SWIG-1.39/Java/examples/FRA.java000066400000000000000000000025261503741206100177120ustar00rootroot00000000000000package examples; import org.quantlib.Actual360; import org.quantlib.Date; import org.quantlib.DayCounter; import org.quantlib.FlatForward; import org.quantlib.Month; import org.quantlib.Settings; import org.quantlib.YieldTermStructureHandle; import org.quantlib.ForwardRateAgreement; import org.quantlib.Position; import org.quantlib.IborIndex; import org.quantlib.Euribor3M; public class FRA { public static void main(String[] args) throws Exception { Date todaysDate = new Date(23, Month.May, 2006); Settings.instance().setEvaluationDate(todaysDate); Date startDate = new Date(23, Month.August, 2006); Position.Type type = Position.Type.Long; double strike = 0.02; double notional = 100.0; double riskFreeRate = 0.06; DayCounter dayCounter = new Actual360(); // define the underlying asset and the yield/dividend/volatility curves YieldTermStructureHandle flatTermStructure = new YieldTermStructureHandle(new FlatForward(todaysDate, riskFreeRate, dayCounter)); IborIndex euribor3m = new Euribor3M(flatTermStructure); ForwardRateAgreement myFra = new ForwardRateAgreement(euribor3m, startDate, type, strike, notional, flatTermStructure); System.out.println(myFra.amount()); System.out.println(myFra.NPV()); } } QuantLib-SWIG-1.39/Java/examples/FunctionDelegates.java000066400000000000000000000060621503741206100227040ustar00rootroot00000000000000package examples; import org.quantlib.Brent; import org.quantlib.Newton; import org.quantlib.DoubleVector; import org.quantlib.OdeFctDelegate; import org.quantlib.GaussKronrodAdaptive; import org.quantlib.UnaryFunctionDelegate; import org.quantlib.BinaryFunctionDelegate; import org.quantlib.RichardsonExtrapolation; import org.quantlib.RungeKutta; public class FunctionDelegates { public static void main(String[] args) { System.out.println("Integration result " + new GaussKronrodAdaptive(1e-8).calculate( new UnaryFunctionDelegate() { public double value(double x) { return Math.sin(x); } }, 0.0, Math.PI ) ); System.out.println("Brent Solver result " + new Brent().solve( new UnaryFunctionDelegate() { public double value(double x) { return Math.cos(x)-x; } }, 1e-8, 0.5, 0.0, Math.PI ) ); System.out.println("Newton Solver result " + new Newton().solve( new UnaryFunctionDelegate() { public double value(double x) { return x*x-1.0; } }, new UnaryFunctionDelegate() { public double value(double x) { return 2*x; } }, 1e-4, 0.25, 0.1 ) ); System.out.println("Richardson Extrapolation, known order " + new RichardsonExtrapolation( new UnaryFunctionDelegate() { public double value(double x) { return Math.exp(1 + x); } }, 0.1, 1.0).getValue(2.0) ); System.out.println("Richardson Extrapolation, unknown order " + new RichardsonExtrapolation( new UnaryFunctionDelegate() { public double value(double x) { return Math.exp(1 + x); } }, 0.1).getValue(4.0, 2.0) ); System.out.println("One dimensional adaptive Runge-Kutta result " + // y'=y and y[0] = 1 new RungeKutta().getValue( new BinaryFunctionDelegate() { public double value(double x, double y) { return y; } }, 1.0, 0.0, 1.0 ) ); DoubleVector startVal = new DoubleVector(); startVal.add(0.0); startVal.add(1.0); System.out.println("Two dimensional adaptive Runge-Kutta result " + // y_0'=y_1 & y_1'=-y_0 and y_0[0]=0 & y_1[0]=1 new RungeKutta().getValue( new OdeFctDelegate() { public DoubleVector value(double x, DoubleVector y) { DoubleVector retVal = new DoubleVector(); retVal.add(y.get(1)); retVal.add(-y.get(0)); return retVal; } }, startVal, 0.0, 0.5*Math.PI ).get(0) ); } } QuantLib-SWIG-1.39/Java/examples/Time.java000066400000000000000000000012771503741206100202020ustar00rootroot00000000000000package examples; import org.quantlib.Date; import org.quantlib.Month; import java.time.LocalDate; public class Time { public static void main(String[] args) throws Exception { Date qlDate = new Date(18, Month.April, 2023); LocalDate localDate = LocalDate.of(2023, 4, 18); Date qlDateFromLocalDate = Date.of(localDate); LocalDate localDateFromQlDate = qlDate.toLocalDate(); System.out.println("qlDate: " + qlDate); System.out.println("qlDateFromLocalDate: " + qlDateFromLocalDate); System.out.println("localDate: " + localDate); System.out.println("localDateFromQlDate: " + localDateFromQlDate); } } QuantLib-SWIG-1.39/LICENSE.TXT000066400000000000000000000061421503741206100154210ustar00rootroot00000000000000 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2002, 2003 Ferdinando Ametrano Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2020, 2022, 2023 StatPro Italia srl Copyright (C) 2005 Dominic Thuillier Copyright (C) 2005 Johan Witters Copyright (C) 2007 Eric H. Jensen Copyright (C) 2007 Luis Cota Copyright (C) 2007 Richard Gomes Copyright (C) 2007, 2008 Tito Ingargiola Copyright (C) 2007, 2010 Joseph Wang Copyright (C) 2008 Allen Kuo Copyright (C) 2008 Florent Grenier Copyright (C) 2009 Joseph Malicki Copyright (C) 2010 Andrea Odetti Copyright (C) 2010, 2011 Lluis Pujol Bajador Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Klaus Spanderen Copyright (C) 2011, 2012 Tawanda Gwena Copyright (C) 2012 Francis Duffy Copyright (C) 2013 Simon Shakeshaft Copyright (C) 2014 Bitquant Research Laboratories (Asia) Ltd. Copyright (C) 2014 Simon Mazzucca Copyright (C) 2014 Wondersys Srl Copyright (C) 2014, 2015 Thema Consulting SA Copyright (C) 2014, 2015, 2018 Matthias Groncki Copyright (C) 2015, 2016 Gouthaman Balaraman Copyright (C) 2016 Peter Caspers Copyright (C) 2016, 2017, 2018, 2019 Wojciech Åšlusarski Copyright (C) 2017 BN Algorithms Ltd Copyright (C) 2017, 2018, 2019, 2020 Matthias Lungwitz Copyright (C) 2018 Angus Lee Copyright (C) 2019 Pedro Coelho Copyright (C) 2019 Prasad Somwanshi Copyright (C) 2020 Gorazd Brumen Copyright (C) 2020, 2021, 2022 Jack Gillett Copyright (C) 2020, 2021, 2023 Marcin Rybacki Copyright (C) 2021, 2024 Ralf Konrad Eckel Copyright (C) 2022 Ignacio Anguita Copyright (C) 2022, 2023, 2024 Skandinaviska Enskilda Banken AB (publ) Copyright (C) 2023 Francois Botha Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the names of the copyright holders nor the names of the QuantLib Group and its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. QuantLib-SWIG-1.39/Makefile.am000066400000000000000000000004001503741206100157610ustar00rootroot00000000000000 SUBDIRS = CSharp Java Python R Scala EXTRA_DIST = \ ChangeLog.txt \ LICENSE.TXT \ News.md \ README.md \ autogen.sh dist-hook: mkdir -p $(distdir)/SWIG cp -p ./SWIG/*.i $(distdir)/SWIG cp -p ./binder/requirements.txt $(distdir)/Python/examples/ QuantLib-SWIG-1.39/News.md000066400000000000000000000037701503741206100152000ustar00rootroot00000000000000Main changes for QuantLib-SWIG 1.39 =================================== More details on the changes are available in ChangeLog.txt and at . - **Removed** features deprecated in version 1.34 and no longer available in the underlying C++ library: - the overloads of `Bond::yield`, `BondFunctions::atmRate`, `BondFunctions::yield` and `BondFunctions::zSpread` taking a price as a `Real` instead of a `Bond::Price` instance; - the `Swaption::underlyingSwap` and `SwaptionHelper::underlyingSwap` methods; - the constructors of `InterpolatedZeroInflationCurve`, `InterpolatedYoYInflationCurve`, `PiecewiseZeroInflationCurve` and `PiecewiseYoYInflationCurve` taking an observation lag; - the overload of `InflationTermStructure::setSeasonality` taking no arguments; - the `fixedRateBond` method of the `FixedRateBondHelper` class. - Added preliminary support for the new free-threading Python interpreter; thanks to Klaus Spanderen (@Klausspanderen). No wheels are provided for it at this time. - Java compilation flags can now be passed by setting the `JAVAC_FLAGS` environment variable; thanks to @UnitedMarsupials. - Exported `convexityAdjustment` method for `FuturesRateHelper` and `OvernightIndexFutureRateHelper` classes; thanks to Eugene Toder (@eltoder). - Passing a nominal curve to the `ZeroCouponInflationSwapHelper` constructor is now optional (@lballabio). - The `OISRateHelper` constructor can now take a calendar for the overnight leg; thanks to Eugene Toder (@eltoder). - Exported the `CustomIborIndex` class; thanks to Eugene Toder (@eltoder). - Exported the `sabrGuess` function (@lballabio). - Exported the `SARON` index (@lballabio). - Exported the static `FxSwapRateHelper.forDates` method; thanks to Eugene Toder (@eltoder). - The `OptionletStripper1` constructor can be passed a frequency so that it can be used with overnight indexes (@lballabio). - Exported the SHIR calendar (@lballabio). QuantLib-SWIG-1.39/Python/000077500000000000000000000000001503741206100152145ustar00rootroot00000000000000QuantLib-SWIG-1.39/Python/.gitignore000066400000000000000000000002471503741206100172070ustar00rootroot00000000000000src/QuantLib/quantlib_wrap.cpp src/QuantLib/QuantLib.py src/QuantLib.egg-info setup.cfg build dist examples/*.ipynb examples/.ipynb_checkpoints *.pyc .cache/ **/.venv QuantLib-SWIG-1.39/Python/Makefile.am000066400000000000000000000017021503741206100172500ustar00rootroot00000000000000 CLEANFILES = src/QuantLib/quantlib_wrap.cpp src/QuantLib/QuantLib.py .build-stamp BUILT_SOURCES = src/QuantLib/quantlib_wrap.cpp src/QuantLib/QuantLib.py if HAVE_PYTHON if BUILD_PYTHON all-local: .build-stamp .build-stamp: src/QuantLib/quantlib_wrap.cpp src/QuantLib/QuantLib.py setup.py CXXFLAGS="$(CXXFLAGS) $(CXXWARNINGFLAGS)" CC="$(CC)" CXX="$(CXX)" $(PYTHON) -m build --wheel rm -f LICENSE.TXT touch .build-stamp check-local: .build-stamp tox run wheel: .build-stamp clean-local: rm -rf build dist endif endif src/QuantLib/quantlib_wrap.cpp src/QuantLib/QuantLib.py: ../SWIG/*.i $(SWIG) $(SWIGFLAGS) -python -c++ -outdir src/QuantLib -o src/QuantLib/quantlib_wrap.cpp ../SWIG/quantlib.i dist-hook: mkdir -p $(distdir)/examples cp ./examples/*.py $(distdir)/examples mkdir -p $(distdir)/test cp ./test/*.py $(distdir)/test EXTRA_DIST = README.md pytest.ini setup.cfg setup.py swig.cmd tox.ini src/QuantLib/__init__.py $(BUILT_SOURCES) QuantLib-SWIG-1.39/Python/README.md000066400000000000000000000023071503741206100164750ustar00rootroot00000000000000 The C++ wrappers for the QuantLib-Python extension module are created by means of SWIG (Simplified Wrapper and Interface Generator) available from ; the latest version is suggested. Building the wrappers requires the `setuptools` and `build` packages; both can be installed (preferably in a virtual environment) by means of `pip install`. Generating the wrappers is not required if you are using a distributed tarball. If you're building from a Git checkout, instead, use the command `swig.cmd` on Windows or `make` on other platforms. Running `make` also builds the wrappers as a wheel; on Windows, this requires the explicit command `python -m build --wheel` instead. The build step requires that the QuantLib headers and library can be found by the compiler. On Unix-like platforms, this requires that `quantlib-config` is in your path. On the Windows platform, instead, it requires you to define a `QL_DIR` environment variable pointing to your QuantLib directory (e.g., `C:\Lib\QuantLib`.) Once built, the resulting wheel can be installed with `pip`. Finally, testing the wheel requires `tox`, also available via `pip install`. Once available, running `tox run` will run the test suite. QuantLib-SWIG-1.39/Python/examples/000077500000000000000000000000001503741206100170325ustar00rootroot00000000000000QuantLib-SWIG-1.39/Python/examples/README.md000066400000000000000000000015461503741206100203170ustar00rootroot00000000000000# QuantLib Python examples [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/lballabio/QuantLib-SWIG/binder?urlpath=lab/tree/Python/examples) This directory contains a number of examples of using QuantLib from Python. They can also run as Jupyter notebooks by means of [Jupytext](https://jupytext.readthedocs.io/). You can try them online thanks to [Binder](https://mybinder.org/). If you're seeing this file as a notebook, you're probably there already. If not, you can click the "Launch Binder" badge at the top of this file. If you want to run these examples locally, you'll need the modules listed in the `requirements.txt` file in the `binder` folder at the root of the [QuantLib-SWIG repository](https://github.com/lballabio/QuantLib-SWIG); to install them, you can execute pip install -r requirements.txt from that directory. QuantLib-SWIG-1.39/Python/examples/american-option.py000066400000000000000000000073051503741206100224760ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # American options # # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% import QuantLib as ql import pandas as pd # %% [markdown] # ### Global parameters # %% todaysDate = ql.Date(15, ql.May, 1998) ql.Settings.instance().evaluationDate = todaysDate # %% interactive = "get_ipython" in globals() # %% [markdown] # ### Option construction # %% exercise = ql.AmericanExercise(todaysDate, ql.Date(17, ql.May, 1999)) payoff = ql.PlainVanillaPayoff(ql.Option.Put, 40.0) # %% option = ql.VanillaOption(payoff, exercise) # %% [markdown] # ### Market data # %% underlying = ql.SimpleQuote(36.0) dividendYield = ql.FlatForward(todaysDate, 0.00, ql.Actual365Fixed()) volatility = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.20, ql.Actual365Fixed()) riskFreeRate = ql.FlatForward(todaysDate, 0.06, ql.Actual365Fixed()) # %% process = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility), ) # %% [markdown] # ### Pricing # # We'll collect tuples of method name, option value, and estimated error from the analytic formula. # %% results = [] # %% [markdown] # #### Analytic approximations # %% option.setPricingEngine(ql.BaroneAdesiWhaleyApproximationEngine(process)) results.append(("Barone-Adesi-Whaley", option.NPV())) # %% option.setPricingEngine(ql.BjerksundStenslandApproximationEngine(process)) results.append(("Bjerksund-Stensland", option.NPV())) # %% [markdown] # #### Finite-difference method # %% timeSteps = 801 gridPoints = 800 # %% option.setPricingEngine(ql.FdBlackScholesVanillaEngine(process, timeSteps, gridPoints)) results.append(("finite differences", option.NPV())) # %% [markdown] # #### Li, M. QD+ American engine # %% option.setPricingEngine(ql.QdPlusAmericanEngine(process)) results.append(("QD+", option.NPV())) # %% [markdown] # #### Leif Andersen, Mark Lake and Dimitri Offengenden high performance American engine # %% option.setPricingEngine( ql.QdFpAmericanEngine(process, ql.QdFpAmericanEngine.accurateScheme()) ) results.append(("QD+ fixed point", option.NPV())) # %% [markdown] # #### Binomial method # %% timeSteps = 801 # %% for tree in ["JR", "CRR", "EQP", "Trigeorgis", "Tian", "LR", "Joshi4"]: option.setPricingEngine(ql.BinomialVanillaEngine(process, tree, timeSteps)) results.append(("Binomial (%s)" % tree, option.NPV())) # %% [markdown] # ### Results # %% df = pd.DataFrame(results, columns=["Method", "Option value"]) df.style.hide(axis="index") # %% [markdown] # The following displays the results when this is run as a Python script (in which case the cell above is not displayed). # %% if not interactive: print(df) QuantLib-SWIG-1.39/Python/examples/basket-option.py000066400000000000000000000073111503741206100221650ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # # Basket options # # Copyright (©) 2004, 2005, 2006 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. import QuantLib as ql # ### Global data todaysDate = ql.Date(15, ql.May, 1998) ql.Settings.instance().evaluationDate = todaysDate settlementDate = ql.Date(17, ql.May, 1998) riskFreeRate = ql.FlatForward(settlementDate, 0.05, ql.Actual365Fixed()) # ### Option parameters exercise = ql.EuropeanExercise(ql.Date(17, ql.May, 1999)) payoff = ql.PlainVanillaPayoff(ql.Option.Call, 8.0) # ### Market data underlying1 = ql.SimpleQuote(7.0) volatility1 = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.10, ql.Actual365Fixed()) dividendYield1 = ql.FlatForward(settlementDate, 0.05, ql.Actual365Fixed()) underlying2 = ql.SimpleQuote(7.0) volatility2 = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.10, ql.Actual365Fixed()) dividendYield2 = ql.FlatForward(settlementDate, 0.05, ql.Actual365Fixed()) process1 = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying1), ql.YieldTermStructureHandle(dividendYield1), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility1), ) process2 = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying2), ql.YieldTermStructureHandle(dividendYield2), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility2), ) matrix = ql.Matrix(2, 2) matrix[0][0] = 1.0 matrix[1][1] = 1.0 matrix[0][1] = 0.5 matrix[1][0] = 0.5 process = ql.StochasticProcessArray([process1, process2], matrix) # ### Pricing basketoption = ql.BasketOption(ql.MaxBasketPayoff(payoff), exercise) basketoption.setPricingEngine( ql.MCEuropeanBasketEngine(process, "pseudorandom", timeStepsPerYear=1, requiredTolerance=0.02, seed=42) ) print("Maximum Basket Payoff: ", basketoption.NPV()) basketoption = ql.BasketOption(ql.MinBasketPayoff(payoff), exercise) basketoption.setPricingEngine( ql.MCEuropeanBasketEngine(process, "pseudorandom", timeStepsPerYear=1, requiredTolerance=0.02, seed=42) ) print("Minimum Basket Payoff: ", basketoption.NPV()) basketoption = ql.BasketOption(ql.AverageBasketPayoff(payoff, 2), exercise) basketoption.setPricingEngine( ql.MCEuropeanBasketEngine(process, "pseudorandom", timeStepsPerYear=1, requiredTolerance=0.02, seed=42) ) print("Average Basket Payoff: ", basketoption.NPV()) americanExercise = ql.AmericanExercise(settlementDate, ql.Date(17, ql.May, 1999)) americanbasketoption = ql.BasketOption(ql.MaxBasketPayoff(payoff), americanExercise) americanbasketoption.setPricingEngine( ql.MCAmericanBasketEngine( process, "pseudorandom", timeSteps=10, requiredTolerance=0.02, seed=42, polynomOrder=5, polynomType=ql.LsmBasisSystem.Hermite, ) ) print("Basket American Exercise: ", americanbasketoption.NPV()) QuantLib-SWIG-1.39/Python/examples/bermudan-swaption.py000066400000000000000000000161031503741206100230440ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # # Bermudan swaptions # # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. import QuantLib as ql import pandas as pd # ### Setup todaysDate = ql.Date(15, ql.February, 2002) ql.Settings.instance().evaluationDate = todaysDate calendar = ql.TARGET() settlementDate = ql.Date(19, ql.February, 2002) def calibrate(model, helpers, l, name): print("Model: %s" % name) method = ql.Simplex(l) model.calibrate(helpers, method, ql.EndCriteria(1000, 250, 1e-7, 1e-7, 1e-7)) print("Parameters: %s" % model.params()) totalError = 0.0 data = [] for swaption, helper in zip(swaptionVols, helpers): maturity, length, vol = swaption NPV = helper.modelValue() implied = helper.impliedVolatility(NPV, 1.0e-4, 1000, 0.05, 0.50) error = implied - vol totalError += abs(error) data.append((maturity, length, vol, implied, error)) averageError = totalError / len(helpers) print(pd.DataFrame(data, columns=["maturity", "length", "volatility", "implied", "error"])) print("Average error: %.4f" % averageError) # ### Market data swaptionVols = [ # maturity, length, volatility (ql.Period(1, ql.Years), ql.Period(5, ql.Years), 0.1148), (ql.Period(2, ql.Years), ql.Period(4, ql.Years), 0.1108), (ql.Period(3, ql.Years), ql.Period(3, ql.Years), 0.1070), (ql.Period(4, ql.Years), ql.Period(2, ql.Years), 0.1021), (ql.Period(5, ql.Years), ql.Period(1, ql.Years), 0.1000), ] # This is a flat yield term structure implying a 1x5 swap at 5%. rate = ql.makeQuoteHandle(0.04875825) termStructure = ql.YieldTermStructureHandle(ql.FlatForward(settlementDate, rate, ql.Actual365Fixed())) # Define the ATM/OTM/ITM swaps: swapEngine = ql.DiscountingSwapEngine(termStructure) fixedLegFrequency = ql.Annual fixedLegTenor = ql.Period(1, ql.Years) fixedLegConvention = ql.Unadjusted floatingLegConvention = ql.ModifiedFollowing fixedLegDayCounter = ql.Thirty360(ql.Thirty360.European) floatingLegFrequency = ql.Semiannual floatingLegTenor = ql.Period(6, ql.Months) payFixed = ql.Swap.Payer fixingDays = 2 index = ql.Euribor6M(termStructure) floatingLegDayCounter = index.dayCounter() swapStart = calendar.advance(settlementDate, 1, ql.Years, floatingLegConvention) swapEnd = calendar.advance(swapStart, 5, ql.Years, floatingLegConvention) fixedSchedule = ql.Schedule( swapStart, swapEnd, fixedLegTenor, calendar, fixedLegConvention, fixedLegConvention, ql.DateGeneration.Forward, False, ) floatingSchedule = ql.Schedule( swapStart, swapEnd, floatingLegTenor, calendar, floatingLegConvention, floatingLegConvention, ql.DateGeneration.Forward, False, ) dummy = ql.VanillaSwap( payFixed, 100.0, fixedSchedule, 0.0, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter ) dummy.setPricingEngine(swapEngine) atmRate = dummy.fairRate() atmSwap = ql.VanillaSwap( payFixed, 1000.0, fixedSchedule, atmRate, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter ) otmSwap = ql.VanillaSwap( payFixed, 1000.0, fixedSchedule, atmRate * 1.2, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter ) itmSwap = ql.VanillaSwap( payFixed, 1000.0, fixedSchedule, atmRate * 0.8, fixedLegDayCounter, floatingSchedule, index, 0.0, floatingLegDayCounter ) atmSwap.setPricingEngine(swapEngine) otmSwap.setPricingEngine(swapEngine) itmSwap.setPricingEngine(swapEngine) helpers = [ ql.SwaptionHelper( maturity, length, ql.makeQuoteHandle(vol), index, index.tenor(), index.dayCounter(), index.dayCounter(), termStructure, ) for maturity, length, vol in swaptionVols ] times = {} for h in helpers: for t in h.times(): times[t] = 1 times = sorted(times.keys()) grid = ql.TimeGrid(times, 30) G2model = ql.G2(termStructure) HWmodel = ql.HullWhite(termStructure) HWmodel2 = ql.HullWhite(termStructure) BKmodel = ql.BlackKarasinski(termStructure) # ### Calibrations for h in helpers: h.setPricingEngine(ql.G2SwaptionEngine(G2model, 6.0, 16)) calibrate(G2model, helpers, 0.05, "G2 (analytic formulae)") for h in helpers: h.setPricingEngine(ql.JamshidianSwaptionEngine(HWmodel)) calibrate(HWmodel, helpers, 0.05, "Hull-White (analytic formulae)") for h in helpers: h.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, grid)) calibrate(HWmodel2, helpers, 0.05, "Hull-White (numerical calibration)") for h in helpers: h.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, grid)) calibrate(BKmodel, helpers, 0.05, "Black-Karasinski (numerical calibration)") # ### Price Bermudan swaptions on defined swaps bermudanDates = [d for d in fixedSchedule][:-1] exercise = ql.BermudanExercise(bermudanDates) atmSwaption = ql.Swaption(atmSwap, exercise) otmSwaption = ql.Swaption(otmSwap, exercise) itmSwaption = ql.Swaption(itmSwap, exercise) data = [] # + atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50)) otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50)) itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(G2model, 50)) data.append(("G2 analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV())) # + atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50)) otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50)) itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel, 50)) data.append(("HW analytic", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV())) # + atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50)) otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50)) itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(HWmodel2, 50)) data.append(("HW numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV())) # + atmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50)) otmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50)) itmSwaption.setPricingEngine(ql.TreeSwaptionEngine(BKmodel, 50)) data.append(("BK numerical", itmSwaption.NPV(), atmSwaption.NPV(), otmSwaption.NPV())) # - print(pd.DataFrame(data, columns=["model", "in-the-money", "at-the-money", "out-of-the-money"])) QuantLib-SWIG-1.39/Python/examples/bonds.py000066400000000000000000000211771503741206100205210ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # # Bonds # # Copyright (©) 2008 Florent Grenier # Copyright (©) 2010 Lluis Pujol Bajador # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it # under the terms of the QuantLib license. You should have received a # # copy of the license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # This example shows how to set up a term structure and then price # some simple bonds. The last part is dedicated to peripherical # computations such as "Yield to Price" or "Price to Yield" import QuantLib as ql import pandas as pd interactive = 'get_ipython' in globals() # ### Global data calendar = ql.TARGET() settlementDate = ql.Date(18, ql.September, 2008) settlementDate = calendar.adjust(settlementDate) fixingDays = 3 settlementDays = 3 todaysDate = calendar.advance(settlementDate, -fixingDays, ql.Days) ql.Settings.instance().evaluationDate = todaysDate print("Today: " + str(todaysDate)) print("Settlement Date: " + str(settlementDate)) # ### Market quotes zcQuotes = [(0.0096, ql.Period(3, ql.Months)), (0.0145, ql.Period(6, ql.Months)), (0.0194, ql.Period(1, ql.Years))] zcBondsDayCounter = ql.Actual365Fixed() zcHelpers = [ ql.DepositRateHelper( ql.makeQuoteHandle(r), tenor, fixingDays, calendar, ql.ModifiedFollowing, True, zcBondsDayCounter ) for (r, tenor) in zcQuotes ] # ### Setup bonds redemption = 100.0 numberOfBonds = 5 bondQuotes = [ (ql.Date(15, ql.March, 2005), ql.Date(31, ql.August, 2010), 0.02375, 100.390625), (ql.Date(15, ql.June, 2005), ql.Date(31, ql.August, 2011), 0.04625, 106.21875), (ql.Date(30, ql.June, 2006), ql.Date(31, ql.August, 2013), 0.03125, 100.59375), (ql.Date(15, ql.November, 2002), ql.Date(15, ql.August, 2018), 0.04000, 101.6875), (ql.Date(15, ql.May, 1987), ql.Date(15, ql.May, 2038), 0.04500, 102.140625), ] # ### Definition of the rate helpers bondsHelpers = [] for issueDate, maturity, couponRate, marketQuote in bondQuotes: schedule = ql.Schedule( issueDate, maturity, ql.Period(ql.Semiannual), ql.UnitedStates(ql.UnitedStates.GovernmentBond), ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False, ) bondsHelpers.append( ql.FixedRateBondHelper( ql.makeQuoteHandle(marketQuote), settlementDays, 100.0, schedule, [couponRate], ql.ActualActual(ql.ActualActual.Bond), ql.Unadjusted, redemption, issueDate, ) ) # ### Curve building termStructureDayCounter = ql.ActualActual(ql.ActualActual.ISDA) bondInstruments = zcHelpers + bondsHelpers bondDiscountingTermStructure = ql.PiecewiseFlatForward(settlementDate, bondInstruments, termStructureDayCounter) # ### Building of the LIBOR forecasting curve dQuotes = [ (0.043375, ql.Period(1, ql.Weeks)), (0.031875, ql.Period(1, ql.Months)), (0.0320375, ql.Period(3, ql.Months)), (0.03385, ql.Period(6, ql.Months)), (0.0338125, ql.Period(9, ql.Months)), (0.0335125, ql.Period(1, ql.Years)), ] sQuotes = [ (0.0295, ql.Period(2, ql.Years)), (0.0323, ql.Period(3, ql.Years)), (0.0359, ql.Period(5, ql.Years)), (0.0412, ql.Period(10, ql.Years)), (0.0433, ql.Period(15, ql.Years)), ] depositDayCounter = ql.Actual360() depositHelpers = [ ql.DepositRateHelper( ql.makeQuoteHandle(rate), tenor, fixingDays, calendar, ql.ModifiedFollowing, True, depositDayCounter ) for rate, tenor in dQuotes ] swFixedLegFrequency = ql.Annual swFixedLegConvention = ql.Unadjusted swFixedLegDayCounter = ql.Thirty360(ql.Thirty360.European) swFloatingLegIndex = ql.Euribor6M() forwardStart = ql.Period(1, ql.Days) swapHelpers = [ ql.SwapRateHelper( ql.makeQuoteHandle(rate), tenor, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, ql.QuoteHandle(), forwardStart, ) for rate, tenor in sQuotes ] depoSwapInstruments = depositHelpers + swapHelpers depoSwapTermStructure = ql.PiecewiseFlatForward(settlementDate, depoSwapInstruments, termStructureDayCounter) # ### Pricing # # Term structures that will be used for pricing: # the one used for discounting cash flows... discountingTermStructure = ql.RelinkableYieldTermStructureHandle() # ...and the one used for forward rate forecasting. forecastingTermStructure = ql.RelinkableYieldTermStructureHandle() # Bonds to be priced: faceAmount = 100 bondEngine = ql.DiscountingBondEngine(discountingTermStructure) # a zero coupon bond... zeroCouponBond = ql.ZeroCouponBond( settlementDays, ql.UnitedStates(ql.UnitedStates.GovernmentBond), faceAmount, ql.Date(15, ql.August, 2013), ql.Following, 116.92, ql.Date(15, ql.August, 2003), ) zeroCouponBond.setPricingEngine(bondEngine) # ...a fixed 4.5% US Treasury note... fixedBondSchedule = ql.Schedule( ql.Date(15, ql.May, 2007), ql.Date(15, ql.May, 2017), ql.Period(ql.Semiannual), ql.UnitedStates(ql.UnitedStates.GovernmentBond), ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False, ) fixedRateBond = ql.FixedRateBond( settlementDays, faceAmount, fixedBondSchedule, [0.045], ql.ActualActual(ql.ActualActual.Bond), ql.ModifiedFollowing, 100.0, ql.Date(15, ql.May, 2007), ) fixedRateBond.setPricingEngine(bondEngine) # ...and a floating rate bond paying 3M USD Libor + 0.1% # (should and will be priced on another curve later). liborTermStructure = ql.RelinkableYieldTermStructureHandle() libor3m = ql.USDLibor(ql.Period(3, ql.Months), liborTermStructure) libor3m.addFixing(ql.Date(17, ql.April, 2008), 0.028175) libor3m.addFixing(ql.Date(17, ql.July, 2008), 0.0278625) floatingBondSchedule = ql.Schedule( ql.Date(21, ql.October, 2005), ql.Date(21, ql.October, 2010), ql.Period(ql.Quarterly), ql.UnitedStates(ql.UnitedStates.NYSE), ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, True, ) floatingRateBond = ql.FloatingRateBond( settlementDays, faceAmount, floatingBondSchedule, libor3m, ql.Actual360(), ql.ModifiedFollowing, spreads=[0.001], issueDate=ql.Date(21, ql.October, 2005), ) floatingRateBond.setPricingEngine(bondEngine) forecastingTermStructure.linkTo(depoSwapTermStructure) discountingTermStructure.linkTo(bondDiscountingTermStructure) liborTermStructure.linkTo(depoSwapTermStructure) # + data = [] data.append( (zeroCouponBond.cleanPrice(), fixedRateBond.cleanPrice(), floatingRateBond.cleanPrice()) ) data.append( (zeroCouponBond.dirtyPrice(), fixedRateBond.dirtyPrice(), floatingRateBond.dirtyPrice()) ) data.append( (zeroCouponBond.accruedAmount(), fixedRateBond.accruedAmount(), floatingRateBond.accruedAmount()) ) data.append( (None, fixedRateBond.previousCouponRate(), floatingRateBond.previousCouponRate()) ) data.append( (None, fixedRateBond.nextCouponRate(), floatingRateBond.nextCouponRate()) ) data.append( (zeroCouponBond.bondYield(ql.Actual360(), ql.Compounded, ql.Annual), fixedRateBond.bondYield(ql.Actual360(), ql.Compounded, ql.Annual), floatingRateBond.bondYield(ql.Actual360(), ql.Compounded, ql.Annual)) ) df = pd.DataFrame(data, columns=["ZC", "Fixed", "Floating"], index=["Clean price", "Dirty price", "Accrued coupon", "Previous coupon rate", "Next coupon rate", "Yield"]) if not interactive: print(df) df # - # A few other computations: # Yield to clean price: floatingRateBond.cleanPrice( floatingRateBond.bondYield(ql.Actual360(), ql.Compounded, ql.Annual), ql.Actual360(), ql.Compounded, ql.Annual, settlementDate, ) # Clean price to yield: floatingRateBond.bondYield( ql.BondPrice( floatingRateBond.cleanPrice(), ql.BondPrice.Clean, ), ql.Actual360(), ql.Compounded, ql.Annual, settlementDate, ) QuantLib-SWIG-1.39/Python/examples/callablebonds.py000066400000000000000000000055101503741206100221720ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.14.5 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- # # Callable bonds # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. import QuantLib as ql import numpy as np calcDate = ql.Date(16, 8, 2006) ql.Settings.instance().evaluationDate = calcDate dayCount = ql.ActualActual(ql.ActualActual.Bond) rate = 0.0465 termStructure = ql.FlatForward(calcDate, rate, dayCount, ql.Compounded, ql.Semiannual) term_structure_handle = ql.RelinkableYieldTermStructureHandle(termStructure) callabilitySchedule = ql.CallabilitySchedule() callPrice = 100.0 callDate = ql.Date(15, ql.September, 2006); nc = ql.NullCalendar() # Number of calldates is 24 for i in range(0, 24): callabilityPrice = ql.BondPrice(callPrice, ql.BondPrice.Clean) callabilitySchedule.append(ql.Callability(callabilityPrice, ql.Callability.Call, callDate)) callDate = nc.advance(callDate, 3, ql.Months) issueDate = ql.Date(16, ql.September, 2004) maturityDate = ql.Date(15, ql.September, 2012) calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) tenor = ql.Period(ql.Quarterly) accrualConvention = ql.Unadjusted schedule = ql.Schedule(issueDate, maturityDate, tenor, calendar, accrualConvention, accrualConvention, ql.DateGeneration.Backward, False) settlement_days = 3 faceAmount = 100 accrual_daycount = ql.ActualActual(ql.ActualActual.Bond) coupon = 0.025 bond = ql.CallableFixedRateBond(settlement_days, faceAmount, schedule, [coupon], accrual_daycount, ql.Following, faceAmount, issueDate, callabilitySchedule) def engine(a, s, grid_points): model = ql.HullWhite(term_structure_handle, a, s) return ql.TreeCallableFixedRateBondEngine(model, grid_points) # 6% mean reversion and 20% volatility bond.setPricingEngine(engine(0.06, 0.20, 40)) print("Bond price: ", bond.cleanPrice()) # 3% mean reversion and 15% volatility bond.setPricingEngine(engine(0.03, 0.15, 40)) print("Bond price: ", bond.cleanPrice()) QuantLib-SWIG-1.39/Python/examples/capsfloors.py000066400000000000000000000050171503741206100215620ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.14.5 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- # # Caps and Floors # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. import QuantLib as ql calcDate = ql.Date(14, 6, 2016) ql.Settings.instance().evaluationDate = calcDate dates = [ql.Date(14,6,2016), ql.Date(14,9,2016), ql.Date(14,12,2016), ql.Date(14,6,2017), ql.Date(14,6,2019), ql.Date(14,6,2021), ql.Date(15,6,2026), ql.Date(16,6,2031), ql.Date(16,6,2036), ql.Date(14,6,2046)] yields = [0.000000, 0.006616, 0.007049, 0.007795, 0.009599, 0.011203, 0.015068, 0.017583, 0.018998, 0.020080] dayCount = ql.ActualActual(ql.ActualActual.Bond) calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) interpolation = ql.Linear() compounding = ql.Compounded compoundingFrequency = ql.Annual term_structure = ql.ZeroCurve(dates, yields, dayCount, calendar, interpolation, compounding, compoundingFrequency) ts_handle = ql.YieldTermStructureHandle(term_structure) start_date = ql.Date(14, 6, 2016) end_date = ql.Date(14, 6 , 2026) period = ql.Period(3, ql.Months) buss_convention = ql.ModifiedFollowing rule = ql.DateGeneration.Forward end_of_month = False schedule = ql.Schedule(start_date, end_date, period, calendar, buss_convention, buss_convention, rule, end_of_month) iborIndex = ql.USDLibor(ql.Period(3, ql.Months), ts_handle) iborIndex.addFixing(ql.Date(10,6,2016), 0.0065560) ibor_leg = ql.IborLeg([1000000], schedule, iborIndex) strike = 0.02 cap = ql.Cap(ibor_leg, [strike]) vols = ql.makeQuoteHandle(0.547295) engine = ql.BlackCapFloorEngine(ts_handle, vols) cap.setPricingEngine(engine) print("Value of Caps given constant volatility:", cap.NPV()) QuantLib-SWIG-1.39/Python/examples/cashflows.py000066400000000000000000000106421503741206100214000ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.6.0 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # Cash-flow analysis # # Copyright (©) 2020 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% import QuantLib as ql import pandas as pd # %% interactive = "get_ipython" in globals() # %% today = ql.Date(19, ql.October, 2020) ql.Settings.instance().evaluationDate = today # %% [markdown] # ### Term structure construction # %% dates = [ ql.Date(19,10,2020), ql.Date(19,11,2020), ql.Date(19, 1,2021), ql.Date(19, 4,2021), ql.Date(19,10,2021), ql.Date(19, 4,2022), ql.Date(19,10,2022), ql.Date(19,10,2023), ql.Date(19,10,2025), ql.Date(19,10,2030), ql.Date(19,10,2035), ql.Date(19,10,2040), ] rates = [ -0.004, -0.002, 0.001, 0.005, 0.009, 0.010, 0.010, 0.012, 0.017, 0.019, 0.028, 0.032, ] forecast_curve = ql.ZeroCurve(dates, rates, ql.Actual365Fixed()) # %% forecast_handle = ql.YieldTermStructureHandle(forecast_curve) # %% [markdown] # ### Swap construction # # We'll use an overnight swap as an example. We're keeping the initialization simple, but the analysis work in the same way for more complex ones, as well as for other kinds of swaps and bonds (once we extract the cashflows from them using the proper methods). # %% swap = ql.MakeOIS(swapTenor=ql.Period(5, ql.Years), overnightIndex=ql.Eonia(forecast_handle), fixedRate=0.002) # %% [markdown] # ### Cash-flow analysis # # The fixed-rate coupons can be extracted from the swap using the `fixedLeg` method. They are returned as instances of the base `Cashflow` class, so the only methods we have directly available are from that class interface: # %% fixed_leg = swap.fixedLeg() # %% df = pd.DataFrame([(c.date(), c.amount()) for c in fixed_leg if c.date() > today], columns=['date', 'amount']) df # %% [markdown] # The following displays the results when this is run as a Python script (in which case the cell above is not displayed). # %% if not interactive: print(df) # %% [markdown] # If we want to extract more information, we need to upcast the coupons to a more specific class. This can be done by using the `as_fixed_rate_coupon` method. In this case, the upcast works by construction; but in the general case we might have cashflows for which the upcast fails (e.g., the redemption for a bond) so we have to check for nulls. # %% coupons = [] for cf in fixed_leg: c = ql.as_fixed_rate_coupon(cf) if c: coupons.append(c) # %% [markdown] # We can now access methods from the coupon class. # %% df = pd.DataFrame([(c.date(), c.amount(), c.rate(), c.accrualStartDate(), c.accrualEndDate(), c.accrualPeriod()) for c in coupons if c.date() > today], columns=['payment date', 'amount', 'rate', 'start date', 'end date', 'accrual period']) df # %% if not interactive: print(df) # %% [markdown] # The same goes for the floating leg: in this case, we need to upcast to floating-rate coupons in order to access the specific methods we'll need. # %% floating_leg = swap.overnightLeg() # %% coupons = [] for cf in floating_leg: c = ql.as_floating_rate_coupon(cf) if c: coupons.append(c) # %% df = pd.DataFrame([(c.date(), c.amount(), c.rate(), c.accrualStartDate(), c.accrualEndDate(), c.accrualPeriod()) for c in coupons if c.date() > today], columns=['payment date', 'amount', 'rate', 'start date', 'end date', 'accrual period']) df # %% if not interactive: print(df) QuantLib-SWIG-1.39/Python/examples/cds.py000066400000000000000000000066311503741206100201630ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # # Credit default swaps # # Copyright (©) 2014 Thema Consulting SA # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # ### Setup import QuantLib as ql calendar = ql.TARGET() todaysDate = ql.Date(15, ql.May, 2007) ql.Settings.instance().evaluationDate = todaysDate risk_free_rate = ql.YieldTermStructureHandle(ql.FlatForward(todaysDate, 0.01, ql.Actual365Fixed())) # ### CDS parameters recovery_rate = 0.5 quoted_spreads = [0.0150, 0.0150, 0.0150, 0.0150] tenors = [ql.Period(3, ql.Months), ql.Period(6, ql.Months), ql.Period(1, ql.Years), ql.Period(2, ql.Years)] maturities = [calendar.adjust(todaysDate + x, ql.Following) for x in tenors] instruments = [ ql.SpreadCdsHelper( ql.makeQuoteHandle(s), tenor, 0, calendar, ql.Quarterly, ql.Following, ql.DateGeneration.TwentiethIMM, ql.Actual365Fixed(), recovery_rate, risk_free_rate, ) for s, tenor in zip(quoted_spreads, tenors) ] hazard_curve = ql.PiecewiseFlatHazardRate(todaysDate, instruments, ql.Actual365Fixed()) print("Calibrated hazard rate values: ") for x in hazard_curve.nodes(): print("hazard rate on %s is %.7f" % x) print("Some survival probability values: ") print( "1Y survival probability: %.4g, \n\t\texpected %.4g" % (hazard_curve.survivalProbability(todaysDate + ql.Period("1Y")), 0.9704) ) print( "2Y survival probability: %.4g, \n\t\texpected %.4g" % (hazard_curve.survivalProbability(todaysDate + ql.Period("2Y")), 0.9418) ) # ### Reprice instruments nominal = 1000000.0 probability = ql.DefaultProbabilityTermStructureHandle(hazard_curve) # We'll create a cds for every maturity: all_cds = [] for maturity, s in zip(maturities, quoted_spreads): schedule = ql.Schedule( todaysDate, maturity, ql.Period(ql.Quarterly), calendar, ql.Following, ql.Unadjusted, ql.DateGeneration.TwentiethIMM, False, ) cds = ql.CreditDefaultSwap(ql.Protection.Seller, nominal, s, schedule, ql.Following, ql.Actual365Fixed()) engine = ql.MidPointCdsEngine(probability, recovery_rate, risk_free_rate) cds.setPricingEngine(engine) all_cds.append(cds) print("Repricing of quoted CDSs employed for calibration: ") for cds, tenor in zip(all_cds, tenors): print("%s fair spread: %.7g" % (tenor, cds.fairSpread())) print(" NPV: %g" % cds.NPV()) print(" default leg: %.7g" % cds.defaultLegNPV()) print(" coupon leg: %.7g" % cds.couponLegNPV()) print("") QuantLib-SWIG-1.39/Python/examples/european-option.py000066400000000000000000000114321503741206100225310ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # European options # # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% import QuantLib as ql import pandas as pd # %% [markdown] # ### Global parameters # %% todaysDate = ql.Date(15, ql.May, 1998) ql.Settings.instance().evaluationDate = todaysDate # %% interactive = 'get_ipython' in globals() # %% [markdown] # ### Option construction # %% exercise = ql.EuropeanExercise(ql.Date(17, ql.May, 1999)) payoff = ql.PlainVanillaPayoff(ql.Option.Call, 8.0) # %% option = ql.VanillaOption(payoff, exercise) # %% [markdown] # ### Market data # %% underlying = ql.SimpleQuote(7.0) dividendYield = ql.FlatForward(todaysDate, 0.05, ql.Actual365Fixed()) volatility = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.10, ql.Actual365Fixed()) riskFreeRate = ql.FlatForward(todaysDate, 0.05, ql.Actual365Fixed()) # %% [markdown] # ### Processes and models # %% process = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility), ) # %% hestonProcess = ql.HestonProcess( ql.YieldTermStructureHandle(riskFreeRate), ql.YieldTermStructureHandle(dividendYield), ql.QuoteHandle(underlying), 0.1 * 0.1, 1.0, 0.1 * 0.1, 0.0001, 0.0, ) hestonModel = ql.HestonModel(hestonProcess) # %% [markdown] # ### Pricing # # We'll collect tuples of method name, option value, estimated error, and discrepancy from the analytic formula. # %% results = [] # %% [markdown] # #### Analytic formula # %% option.setPricingEngine(ql.AnalyticEuropeanEngine(process)) value = option.NPV() refValue = value results.append(('Analytic', value, None, None)) # %% [markdown] # #### Heston semi-analytic formula # %% option.setPricingEngine(ql.AnalyticHestonEngine(hestonModel)) value = option.NPV() results.append(('Heston analytic', value, None, abs(value - refValue))) # %% [markdown] # #### Heston COS method # %% option.setPricingEngine(ql.COSHestonEngine(hestonModel)) value = option.NPV() results.append(('Heston COS', value, None, abs(value - refValue))) # %% [markdown] # #### Integral method # %% option.setPricingEngine(ql.IntegralEngine(process)) value = option.NPV() results.append(('Integral', value, None, abs(value - refValue))) # %% [markdown] # #### Finite-difference method # %% timeSteps = 801 gridPoints = 800 # %% option.setPricingEngine(ql.FdBlackScholesVanillaEngine(process, timeSteps, gridPoints)) value = option.NPV() results.append(('Finite diff.', value, None, abs(value - refValue))) # %% [markdown] # #### Binomial method # %% timeSteps = 801 # %% for tree in ["JR", "CRR", "EQP", "Trigeorgis", "Tian", "LR", "Joshi4"]: option.setPricingEngine(ql.BinomialVanillaEngine(process, tree, timeSteps)) value = option.NPV() results.append(('Binomial (%s)' % tree, value, None, abs(value - refValue))) # %% [markdown] # #### Monte Carlo method # %% option.setPricingEngine(ql.MCEuropeanEngine(process, "pseudorandom", timeSteps=1, requiredTolerance=0.02, seed=42)) value = option.NPV() results.append(("Monte Carlo (pseudo-random)", value, option.errorEstimate(), abs(value - refValue))) # %% option.setPricingEngine(ql.MCEuropeanEngine(process, "lowdiscrepancy", timeSteps=1, requiredSamples=32768)) value = option.NPV() results.append(("Monte Carlo (low-discrepancy)", value, None, abs(value - refValue))) # %% [markdown] # ### Results # %% df = pd.DataFrame(results, columns=["Method", "Option value", "Error estimate", "Actual error"]) # %% df.style.hide(axis="index") # %% [markdown] # The following displays the results when this is run as a Python script (in which case the cell above is not displayed). # %% if not interactive: print(df) QuantLib-SWIG-1.39/Python/examples/gaussian1d-models.py000066400000000000000000000423641503741206100227350ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # Gaussian 1D models # # Copyright (©) 2018 Angus Lee # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% [markdown] # ### Setup # %% import QuantLib as ql import pandas as pd # %% interactive = "get_ipython" in globals() def show(x): if not interactive: print(x) return x # %% def basket_data(basket): data = [] for helper in basket: h = ql.as_swaption_helper(helper) data.append( ( h.swaptionExpiryDate().to_date(), h.swaptionMaturityDate().to_date(), h.swaptionNominal(), h.volatility().value(), h.swaptionStrike(), ) ) return pd.DataFrame(data, columns=["Expiry", "Maturity", "Nominal", "Rate", "Market vol"]) # %% def calibration_data(basket, volatilities): data = [] for helper, sigma in zip(basket, volatilities): h = ql.as_swaption_helper(helper) modelValue = h.modelValue() data.append( ( h.swaptionExpiryDate().to_date(), sigma, modelValue, h.marketValue(), h.impliedVolatility(modelValue, 1e-6, 1000, 0.0, 2.0), h.volatility().value(), ) ) return pd.DataFrame( data, columns=["Expiry", "Model sigma", "Model price", "Market price", "Model imp.vol", "Market imp.vol"] ) # %% [markdown] # ### Calculations # %% [markdown] # This exercise tries to replicate the Quantlib C++ `Gaussian1dModel` example on how to use the GSR and Markov Functional model. # %% refDate = ql.Date(30, 4, 2014) ql.Settings.instance().evaluationDate = refDate # %% [markdown] # We assume a multicurve setup, for simplicity with flat yield term structures. # # The discounting curve is an Eonia curve at a level of 2% and the forwarding curve is an Euribor 6m curve at a level of 2.5%. # # For the volatility we assume a flat swaption volatility at 20%. # %% forward6mQuote = ql.makeQuoteHandle(0.025) oisQuote = ql.makeQuoteHandle(0.02) volQuote = ql.makeQuoteHandle(0.2) # %% dc = ql.Actual365Fixed() yts6m = ql.FlatForward(refDate, forward6mQuote, dc) ytsOis = ql.FlatForward(refDate, oisQuote, dc) yts6m.enableExtrapolation() ytsOis.enableExtrapolation() hyts6m = ql.RelinkableYieldTermStructureHandle(yts6m) t0_curve = ql.YieldTermStructureHandle(yts6m) t0_Ois = ql.YieldTermStructureHandle(ytsOis) euribor6m = ql.Euribor6M(hyts6m) swaptionVol = ql.ConstantSwaptionVolatility(0, ql.TARGET(), ql.ModifiedFollowing, volQuote, ql.Actual365Fixed()) # %% effectiveDate = ql.TARGET().advance(refDate, ql.Period('2D')) maturityDate = ql.TARGET().advance(effectiveDate, ql.Period('10Y')) # %% fixedSchedule = ql.Schedule(effectiveDate, maturityDate, ql.Period('1Y'), ql.TARGET(), ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False) # %% floatSchedule = ql.Schedule(effectiveDate, maturityDate, ql.Period('6M'), ql.TARGET(), ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False) # %% [markdown] # We consider a standard 10-years Bermudan payer swaption with yearly exercises at a strike of 4%. # %% fixedNominal = [1]*(len(fixedSchedule)-1) floatingNominal = [1]*(len(floatSchedule)-1) strike = [0.04]*(len(fixedSchedule)-1) gearing = [1]*(len(floatSchedule)-1) spread = [0]*(len(floatSchedule)-1) # %% underlying = ql.NonstandardSwap( ql.Swap.Payer, fixedNominal, floatingNominal, fixedSchedule, strike, ql.Thirty360(ql.Thirty360.BondBasis), floatSchedule, euribor6m, gearing, spread, ql.Actual360(), False, False, ql.ModifiedFollowing) # %% exerciseDates = [ql.TARGET().advance(x, -ql.Period('2D')) for x in fixedSchedule] exerciseDates = exerciseDates[1:-1] exercise = ql.BermudanExercise(exerciseDates) swaption = ql.NonstandardSwaption(underlying,exercise,ql.Settlement.Physical) # %% [markdown] # The model is a one factor Hull White model with piecewise volatility adapted to our exercise dates. # # The reversion is just kept constant at a level of 1%. # %% stepDates = exerciseDates[:-1] sigmas = [ql.makeQuoteHandle(0.01) for x in range(1, 10)] reversion = [ql.makeQuoteHandle(0.01)] # %% [markdown] # The model's curve is set to the 6m forward curve. Note that the model adapts automatically to other curves where appropriate (e.g. if an index requires a different forwarding curve) or where explicitly specified (e.g. in a swaption pricing engine). # %% gsr = ql.Gsr(t0_curve, stepDates, sigmas, reversion) swaptionEngine = ql.Gaussian1dSwaptionEngine(gsr, 64, 7.0, True, False, t0_Ois) nonstandardSwaptionEngine = ql.Gaussian1dNonstandardSwaptionEngine( gsr, 64, 7.0, True, False, ql.makeQuoteHandle(0.0), t0_Ois) # %% swaption.setPricingEngine(nonstandardSwaptionEngine) # %% swapBase = ql.EuriborSwapIsdaFixA(ql.Period('10Y'), t0_curve, t0_Ois) basket = swaption.calibrationBasket(swapBase, swaptionVol, 'Naive') # %% for basket_i in basket: ql.as_black_helper(basket_i).setPricingEngine(swaptionEngine) # %% method = ql.LevenbergMarquardt() ec = ql.EndCriteria(1000, 10, 1e-8, 1e-8, 1e-8) # %% gsr.calibrateVolatilitiesIterative(basket, method, ec) # %% [markdown] # The engine can generate a calibration basket in two modes. # # The first one is called Naive and generates ATM swaptions adapted to the exercise dates of the swaption and its maturity date. The resulting basket looks as follows: # %% show(basket_data(basket)) # %% [markdown] # Let's calibrate our model to this basket. We use a specialized calibration method calibrating the sigma function one by one to the calibrating vanilla swaptions. The result of this is as follows: # %% show(calibration_data(basket, gsr.volatility())) # %% [markdown] # Bermudan swaption NPV (ATM calibrated GSR): # %% print(swaption.NPV()) # %% [markdown] # There is another mode to generate a calibration basket called `MaturityStrikeByDeltaGamma`. This means that the maturity, the strike and the nominal of the calibrating swaptions are obtained matching the NPV, first derivative and second derivative of the swap you will exercise into at at each bermudan call date. The derivatives are taken with respect to the model's state variable. # # Let's try this in our case. # %% basket = swaption.calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') show(basket_data(basket)) # %% for basket_i in basket: ql.as_black_helper(basket_i).setPricingEngine(swaptionEngine) # %% [markdown] # The calibrated nominal is close to the exotics nominal. The expiries and maturity dates of the vanillas are the same as in the case above. The difference is the strike which is now equal to the exotics strike. # # Let's see how this affects the exotics NPV. The recalibrated model is: # %% gsr.calibrateVolatilitiesIterative(basket, method, ec) show(calibration_data(basket, gsr.volatility())) # %% [markdown] # Bermudan swaption NPV (deal strike calibrated GSR): # %% print(swaption.NPV()) # %% [markdown] # We can do more complicated things. Let's e.g. modify the nominal schedule to be linear amortizing and see what the effect on the generated calibration basket is: # %% for i in range(0,len(fixedSchedule)-1): tmp = 1 - i/ (len(fixedSchedule)-1) fixedNominal[i] = tmp floatingNominal[i*2] = tmp floatingNominal[i*2+1] = tmp # %% underlying2 = ql.NonstandardSwap(ql.Swap.Payer, fixedNominal, floatingNominal, fixedSchedule, strike, ql.Thirty360(ql.Thirty360.BondBasis), floatSchedule, euribor6m, gearing, spread, ql.Actual360(), False, False, ql.ModifiedFollowing) # %% swaption2 = ql.NonstandardSwaption(underlying2,exercise,ql.Settlement.Physical) # %% swaption2.setPricingEngine(nonstandardSwaptionEngine) basket = swaption2.calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') # %% show(basket_data(basket)) # %% [markdown] # The notional is weighted over the underlying exercised into and the maturity is adjusted downwards. The rate, on the other hand, is not affected. # %% [markdown] # You can also price exotic bond's features. If you have e.g. a Bermudan callable fixed bond you can set up the call right as a swaption to enter into a one leg swap with notional reimbursement at maturity. The exercise should then be written as a rebated exercise paying the notional in case of exercise. The calibration basket looks like this: # %% fixedNominal2 = [1]*(len(fixedSchedule)-1) floatingNominal2 = [0]*(len(floatSchedule)-1) #null the second leg # %% underlying3 = ql.NonstandardSwap(ql.Swap.Receiver, fixedNominal2, floatingNominal2, fixedSchedule, strike, ql.Thirty360(ql.Thirty360.BondBasis), floatSchedule, euribor6m, gearing, spread, ql.Actual360(), False, True, ql.ModifiedFollowing) # %% rebateAmount = [-1]*len(exerciseDates) exercise2 = ql.RebatedExercise(exercise, rebateAmount, 2, ql.TARGET()) swaption3 = ql.NonstandardSwaption(underlying3,exercise2,ql.Settlement.Physical) # %% oas0 = ql.SimpleQuote(0) oas100 = ql.SimpleQuote(0.01) oas = ql.RelinkableQuoteHandle(oas0) # %% nonstandardSwaptionEngine2 = ql.Gaussian1dNonstandardSwaptionEngine( gsr, 64, 7.0, True, False, oas, t0_curve) # Change discounting to 6m # %% swaption3.setPricingEngine(nonstandardSwaptionEngine2) basket = swaption3.calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') # %% show(basket_data(basket)) # %% [markdown] # Note that nominals are not exactly 1.0 here. This is because we do our bond discounting on 6m level while the swaptions are still discounted on OIS level. (You can try this by changing the OIS level to the 6m level, which will produce nominals near 1.0). # # The NPV of the call right is (after recalibrating the model): # %% for basket_i in basket: ql.as_black_helper(basket_i).setPricingEngine(swaptionEngine) # %% gsr.calibrateVolatilitiesIterative(basket, method, ec) # %% print(swaption3.NPV()) # %% [markdown] # Up to now, no credit spread is included in the pricing. We can do so by specifying an oas in the pricing engine. Let's set the spread level to 100bp and regenerate the calibration basket. # %% oas.linkTo(oas100) basket = swaption3.calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') show(basket_data(basket)) # %% [markdown] # The adjusted basket takes the credit spread into account. This is consistent to a hedge where you would have a margin on the float leg around 100bp,too. # %% for basket_i in basket: ql.as_black_helper(basket_i).setPricingEngine(swaptionEngine) # %% gsr.calibrateVolatilitiesIterative(basket, method, ec) # %% print(swaption3.NPV()) # %% [markdown] # The next instrument we look at is a CMS 10Y vs Euribor 6M swaption. The maturity is again 10 years and the option is exercisable on a yearly basis. # %% CMSNominal = [1]*(len(fixedSchedule)-1) CMSgearing = [1]*(len(fixedSchedule)-1) CMSspread = [0]*(len(fixedSchedule)-1) EuriborNominal = [1]*(len(floatSchedule)-1) Euriborgearing = [1]*(len(floatSchedule)-1) Euriborspread = [0.001]*(len(floatSchedule)-1) underlying4 = ql.FloatFloatSwap(ql.Swap.Payer, CMSNominal, EuriborNominal, fixedSchedule, swapBase, ql.Thirty360(ql.Thirty360.BondBasis), floatSchedule, euribor6m, ql.Actual360(), False, False, CMSgearing, CMSspread, [], [], Euriborgearing, Euriborspread) # %% swaption4 = ql.FloatFloatSwaption(underlying4, exercise) floatSwaptionEngine = ql.Gaussian1dFloatFloatSwaptionEngine( gsr, 64, 7.0, True, False, ql.makeQuoteHandle(0.0), t0_Ois, True) swaption4.setPricingEngine(floatSwaptionEngine) # %% [markdown] # Since the underlying is quite exotic already, we start with pricing this using the `LinearTsrPricer` for CMS coupon estimation. # %% leg0 = underlying4.leg(0) leg1 = underlying4.leg(1) reversionQuote = ql.makeQuoteHandle(0.01) swaptionVolHandle = ql.SwaptionVolatilityStructureHandle(swaptionVol) cmsPricer = ql.LinearTsrPricer(swaptionVolHandle, reversionQuote) iborPricer = ql.BlackIborCouponPricer() # %% ql.setCouponPricer(leg0, cmsPricer) ql.setCouponPricer(leg1, iborPricer) # %% swapPricer = ql.DiscountingSwapEngine(t0_Ois) underlying4.setPricingEngine(swapPricer) # %% print("Underlying CMS Swap NPV = %f" % underlying4.NPV()) print("Underlying CMS Leg NPV = %f" % underlying4.legNPV(0)) print("Underlying Euribor NPV = %f" % underlying4.legNPV(1)) # %% [markdown] # We generate a naive calibration basket and calibrate the GSR model to it: # %% basket = swaption4.calibrationBasket(swapBase, swaptionVol, 'Naive') # %% for basket_i in basket: ql.as_black_helper(basket_i).setPricingEngine(swaptionEngine) # %% gsr.calibrateVolatilitiesIterative(basket, method, ec) show(basket_data(basket)) # %% show(calibration_data(basket, gsr.volatility())) # %% [markdown] # The npv of the bermudan swaption is: # %% print(swaption4.NPV()) # %% [markdown] # In this case it is also interesting to look at the underlying swap NPV in the GSR model. # %% print(swaption4.underlyingValue()) # %% [markdown] # Not surprisingly, the underlying is priced differently compared to the `LinearTsrPricer`, since a different smile is implied by the GSR model. # # This is exactly where the Markov functional model comes into play, because it can calibrate to any given underlying smile (as long as it is arbitrage free). We try this now. Of course the usual use case is not to calibrate to a flat smile as in our simple example, still it should be possible, of course... # %% markovStepDates = exerciseDates cmsFixingDates = markovStepDates markovSimgas = [0.01]* (len(markovStepDates)+1) tenors = [ql.Period('10Y')]*len(cmsFixingDates) markov = ql.MarkovFunctional(t0_curve, reversionQuote.value(), markovStepDates, markovSimgas, swaptionVolHandle, cmsFixingDates, tenors, swapBase) # %% swaptionEngineMarkov = ql.Gaussian1dSwaptionEngine(markov, 8, 5.0, True, False, t0_Ois) # %% floatEngineMarkov = ql.Gaussian1dFloatFloatSwaptionEngine( markov, 16, 7.0, True, False, ql.makeQuoteHandle(0.0), t0_Ois, True) # %% [markdown] # The option npv is the markov model is: # %% swaption4.setPricingEngine(floatEngineMarkov) print(swaption4.NPV()) # %% [markdown] # This is not too far from the GSR price. More interesting is the question how well the Markov model did its job to match our input smile. For this we look at the underlying npv under the Markov model. # %% print(swaption4.underlyingValue()) # %% [markdown] # This is closer to our terminal swap rate model price. A perfect match is not expected anyway, because the dynamics of the underlying rate in the linear model is different from the Markov model, of course. # # The Markov model can not only calibrate to the underlying smile, but has at the same time a sigma function (similar to the GSR model) which can be used to calibrate to a second instrument set. We do this here to calibrate to our coterminal ATM swaptions from above. # # This is a computationally demanding task, so depending on your machine, this may take a while now... # %% for basket_i in basket: ql.as_black_helper(basket_i).setPricingEngine(swaptionEngineMarkov) # %% markov.calibrate(basket, method, ec) show(calibration_data(basket, markov.volatility())) # %% [markdown] # Now let's have a look again at the underlying pricing. It shouldn't have changed much, because the underlying smile is still matched. # %% print(swaption4.underlyingValue()) # %% [markdown] # This is close to the previous value as expected. # # As a final remark we note that the calibration to coterminal swaptions is not particularly reasonable here, because the European call rights are not well represented by these swaptions. Secondly, our CMS swaption is sensitive to the correlation between the 10y swap rate and the Euribor 6M rate. Since the Markov model is one factor it will most probably underestimate the market value by construction. # # That was it. Thank you for running this demo. Bye. QuantLib-SWIG-1.39/Python/examples/global-bootstrap.py000066400000000000000000000072421503741206100226640ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # Global curve bootstrap # # Copyright (©) 2020 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% import QuantLib as ql import pandas as pd # %% interactive = "get_ipython" in globals() # %% [markdown] # ### Setup # %% today = ql.Date(26, 9, 2019) spot = ql.TARGET().advance(today, 2, ql.Days) # %% ql.Settings.instance().evaluationDate = today # %% [markdown] # ### Data # # We'll use the following data as input: # %% refMktRates = [ -0.373, -0.388, -0.402, -0.418, -0.431, -0.441, -0.45, -0.457, -0.463, -0.469, -0.461, -0.463, -0.479, -0.4511, -0.45418, -0.439, -0.4124, -0.37703, -0.3335, -0.28168, -0.22725, -0.1745, -0.12425, -0.07746, 0.0385, 0.1435, 0.17525, 0.17275, 0.1515, 0.1225, 0.095, 0.0644, ] # %% [markdown] # ### Market instruments # %% index = ql.Euribor6M() # %% [markdown] # The first market rate is for the 6-months deposit... # %% helpers = [ ql.DepositRateHelper( refMktRates[0] / 100.0, ql.Period(6, ql.Months), 2, ql.TARGET(), ql.ModifiedFollowing, True, ql.Actual360() ) ] # %% [markdown] # ...the next 12 are for FRAs... # %% helpers += [ql.FraRateHelper(r / 100.0, i + 1, index) for i, r in enumerate(refMktRates[1:13])] # %% [markdown] # ...and the others are swap rates. # %% swapTenors = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 20, 25, 30, 35, 40, 45, 50] helpers += [ ql.SwapRateHelper( r / 100.0, ql.Period(T, ql.Years), ql.TARGET(), ql.Annual, ql.ModifiedFollowing, ql.Thirty360(ql.Thirty360.BondBasis), index ) for r, T in zip(refMktRates[13:32], swapTenors) ] # %% [markdown] # We'll also add a few synthetic helpers: # %% additional_helpers = [ql.FraRateHelper(-0.004, 12 + i, index) for i in range(7)] additional_dates = [ql.TARGET().advance(spot, 1 + i, ql.Months) for i in range(5)] # %% [markdown] # ### Global bootstrap # # This curve takes into account the market instruments, as well as the passed additional ones. # %% curve = ql.GlobalLinearSimpleZeroCurve( spot, helpers, ql.Actual365Fixed(), ql.GlobalBootstrap(additional_helpers, additional_dates, 1.0e-12) ) curve.enableExtrapolation() # %% [markdown] # ### Report # %% data = [] for i, h in enumerate(helpers): pillar = h.pillarDate() if i < 13: day_counter = ql.Actual360() compounding = ql.Simple else: day_counter = ql.Thirty360(ql.Thirty360.BondBasis) compounding = ql.SimpleThenCompounded r = curve.zeroRate(pillar, day_counter, compounding, ql.Annual).rate() data.append((pillar.to_date(), r * 100)) # %% df = pd.DataFrame(data, columns=["pillar", "zero rate"]) if not interactive: print(df) df QuantLib-SWIG-1.39/Python/examples/isda-engine.py000066400000000000000000000144651503741206100216010ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.11.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # # ISDA CDS engine # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. import QuantLib as ql import pandas as pd interactive = 'get_ipython' in globals() trade_date = ql.Date(21,5,2009) ql.Settings.instance().evaluationDate = trade_date ql.IborCoupon.createAtParCoupons() dep_tenors = [1,2,3,6,9,12] dep_quotes = [0.003081,0.005525,0.007163,0.012413,0.014,0.015488] isdaRateHelpers = [ql.DepositRateHelper(dep_quotes[i], dep_tenors[i]*ql.Period(ql.Monthly), 2,ql.WeekendsOnly(), ql.ModifiedFollowing, False,ql.Actual360()) for i in range(len(dep_tenors))] swap_tenors = [2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25, 30] swap_quotes = [0.011907, 0.01699, 0.021198, 0.02444, 0.026937, 0.028967, 0.030504, 0.031719, 0.03279, 0.034535, 0.036217, 0.036981, 0.037246, 0.037605] isda_ibor = ql.IborIndex('IsdaIbor',3*ql.Period(ql.Monthly),2, ql.USDCurrency(),ql.WeekendsOnly(), ql.ModifiedFollowing,False,ql.Actual360()) isdaRateHelpers = isdaRateHelpers + [ ql.SwapRateHelper(swap_quotes[i],swap_tenors[i]*ql.Period(ql.Annual), ql.WeekendsOnly(),ql.Semiannual,ql.ModifiedFollowing, ql.Thirty360(ql.Thirty360.BondBasis),isda_ibor) for i in range(len(swap_tenors))] spot_date = ql.WeekendsOnly().advance(trade_date, 2 * ql.Period(ql.Daily)) # Technically, the model requires the discount factor to be 1 at spot; # but we can't do that and also have the discount curve extend back to # the trade date. For the time being, we'll keep discount = 1 at trade. # The results match anyway. swap_curve = ql.PiecewiseFlatForward(trade_date, isdaRateHelpers, ql.Actual365Fixed()) discountCurve = ql.YieldTermStructureHandle(swap_curve) probabilityCurve = ql.RelinkableDefaultProbabilityTermStructureHandle() termDates = [ql.Date(20, 6, 2010), ql.Date(20, 6, 2011), ql.Date(20, 6, 2012), ql.Date(20, 6, 2016), ql.Date(20, 6, 2019)] spreads = [0.001, 0.1] recoveries = [0.2, 0.4] markitValues = [97798.29358, #0.001 97776.11889, #0.001 -914971.5977, #0.1 -894985.6298, #0.1 186921.3594, #0.001 186839.8148, #0.001 -1646623.672, #0.1 -1579803.626, #0.1 274298.9203, 274122.4725, -2279730.93, -2147972.527, 592420.2297, 591571.2294, -3993550.206, -3545843.418, 797501.1422, 795915.9787, -4702034.688, -4042340.999] tolerance = 1.0e-2 l = 0 distance = 0 data = [] upfront_date = ql.WeekendsOnly().advance(trade_date, 3 * ql.Period(ql.Daily)) for termDate in termDates: for spread in spreads: for recovery in recoveries: cdsSchedule = ql.Schedule(trade_date, termDate, 3*ql.Period(ql.Monthly), ql.WeekendsOnly(), ql.Following, ql.Unadjusted, ql.DateGeneration.CDS, False) quotedTrade = ql.CreditDefaultSwap( ql.Protection.Buyer,10000000,0,spread,cdsSchedule, ql.Following,ql.Actual360(),True,True,trade_date, upfront_date, ql.FaceValueClaim(), ql.Actual360(True)) h = quotedTrade.impliedHazardRate(0,discountCurve,ql.Actual365Fixed(), recovery,1e-10, ql.CreditDefaultSwap.ISDA) probabilityCurve.linkTo( ql.FlatHazardRate(0,ql.WeekendsOnly(), ql.makeQuoteHandle(h), ql.Actual365Fixed())) engine = ql.IsdaCdsEngine(probabilityCurve,recovery,discountCurve) conventionalTrade = ql.CreditDefaultSwap( ql.Protection.Buyer,10000000,0,0.01,cdsSchedule, ql.Following,ql.Actual360(),True,True,trade_date, upfront_date, ql.FaceValueClaim(), ql.Actual360(True)) conventionalTrade.setPricingEngine(engine) upfront = conventionalTrade.notional() * conventionalTrade.fairUpfront() data.append( (termDate, spread, recovery, h, upfront, markitValues[l], abs(upfront-markitValues[l]), abs(upfront-markitValues[l]) float: todaysDate = ql.Date(15, ql.May, 2025) ql.Settings.instance().evaluationDate = todaysDate underlying = ql.SimpleQuote(7.0) dividendYield = ql.FlatForward(todaysDate, 0.05, ql.Actual365Fixed()) volatility = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.10, ql.Actual365Fixed()) riskFreeRate = ql.FlatForward(todaysDate, 0.05, ql.Actual365Fixed()) process = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility), ) option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, 8.0), ql.EuropeanExercise(ql.Date(17, ql.May, 2026)) ) engine = ql.FdBlackScholesVanillaEngine(process, 100, 8000) option.setPricingEngine(engine) return option.NPV() print("GIL is disabled: ", bool(sysconfig.get_config_var("Py_GIL_DISABLED"))) for w in [1, 2, 4, 8, 16, 32, 64]: start = time.time() with concurrent.futures.ThreadPoolExecutor(max_workers=w) as executor: retVals = [executor.submit(pricing) for i in range(400)] for val in retVals: val.result() print(f"{w:2} threads, {400/(time.time()-start):5.1f} NPVs per sec") QuantLib-SWIG-1.39/Python/examples/slv.py000066400000000000000000000066231503741206100202170ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # Leverage function for the Heston SLV model # # Copyright (©) 2019 Klaus Spanderen # # This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% [markdown] # This notebook only works with Python 3, at least on Travis. # %% import sys if sys.version_info.major < 3: sys.exit() # %% import QuantLib as ql from matplotlib import pyplot as plt import numpy as np import math # %matplotlib inline # %% is_interactive = 'get_ipython' in globals() # %% todaysDate = ql.Date(15, ql.May, 2019) ql.Settings.instance().evaluationDate = todaysDate # %% settlementDate = todaysDate + ql.Period(2, ql.Days) exerciseDate = todaysDate + ql.Period(4, ql.Years) # %% dc = ql.Actual365Fixed() spot = 100 underlying = ql.makeQuoteHandle(spot) riskFreeRate = ql.YieldTermStructureHandle(ql.FlatForward(settlementDate, 0.05, dc)) dividendYield = ql.YieldTermStructureHandle(ql.FlatForward(settlementDate, 0.025, dc)) vol = 0.30 blackVol = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(settlementDate, ql.TARGET(), vol, dc)) # %% localVol = ql.LocalVolSurface( blackVol, riskFreeRate, dividendYield, underlying, ) hestonProcess = ql.HestonProcess(riskFreeRate, dividendYield, underlying, 0.09, 1.0, 0.06, 0.4, -0.75) hestonModel = ql.HestonModel(hestonProcess) # %% leverageFct = ql.HestonSLVMCModel( localVol, hestonModel, ql.MTBrownianGeneratorFactory(1234), exerciseDate, 91 ).leverageFunction() # %% tSteps = 40 uSteps = 30 tv = np.linspace(0.1, dc.yearFraction(settlementDate, exerciseDate), tSteps) t = np.empty(tSteps * uSteps) s = np.empty(tSteps * uSteps) z = np.empty(tSteps * uSteps) for i in range(0, tSteps): scale = min(4, math.exp(3 * math.sqrt(tv[i]) * vol)) sv = np.linspace(spot / scale, spot * scale, uSteps) for j in range(0, uSteps): idx = i * uSteps + j t[idx] = tv[i] s[idx] = math.log(sv[j]) z[idx] = leverageFct.localVol(t[idx], sv[j]) # %% fig = plt.figure(figsize=(12,8)) ax = plt.axes(projection="3d") surf = ax.plot_trisurf(s, t, z, cmap=plt.cm.viridis, linewidth=0, antialiased=False, edgecolor="none") ax.view_init(30, -120) ax.set_xlabel("ln(S)") ax.set_ylabel("Time") ax.text2D(0.225, 0.985, "Leverage Function with $\eta=1.0$", transform=ax.transAxes) fig.colorbar(surf, shrink=0.75, aspect=14) plt.show(block=False) # %% [markdown] # When this is run as a Python script (i.e., from Travis), we need to close the figure in order to terminate. # %% if not is_interactive: plt.pause(3) plt.close() QuantLib-SWIG-1.39/Python/examples/swap.py000066400000000000000000000174201503741206100203620ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # %% [markdown] # # Interest-rate swaps # # Copyright (©) 2004, 2005, 2006, 2007 StatPro Italia srl # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. # %% import QuantLib as ql # %% [markdown] # ### Global data # %% calendar = ql.TARGET() todaysDate = ql.Date(6, ql.November, 2001) ql.Settings.instance().evaluationDate = todaysDate settlementDate = ql.Date(8, ql.November, 2001) # %% [markdown] # ### Market quotes # %% deposits = { (3, ql.Months): 0.0363, } # %% FRAs = {(3, 6): 0.037125, (6, 9): 0.037125, (9, 12): 0.037125} # %% futures = { ql.Date(19, 12, 2001): 96.2875, ql.Date(20, 3, 2002): 96.7875, ql.Date(19, 6, 2002): 96.9875, ql.Date(18, 9, 2002): 96.6875, ql.Date(18, 12, 2002): 96.4875, ql.Date(19, 3, 2003): 96.3875, ql.Date(18, 6, 2003): 96.2875, ql.Date(17, 9, 2003): 96.0875, } # %% swaps = { (2, ql.Years): 0.037125, (3, ql.Years): 0.0398, (5, ql.Years): 0.0443, (10, ql.Years): 0.05165, (15, ql.Years): 0.055175, } # %% [markdown] # We'll convert them to `Quote` objects... # %% for n, unit in deposits.keys(): deposits[(n, unit)] = ql.SimpleQuote(deposits[(n, unit)]) for n, m in FRAs.keys(): FRAs[(n, m)] = ql.SimpleQuote(FRAs[(n, m)]) for d in futures.keys(): futures[d] = ql.SimpleQuote(futures[d]) for n, unit in swaps.keys(): swaps[(n, unit)] = ql.SimpleQuote(swaps[(n, unit)]) # %% [markdown] # ...and build rate helpers. # %% dayCounter = ql.Actual360() settlementDays = 2 depositHelpers = [ ql.DepositRateHelper( ql.QuoteHandle(deposits[(n, unit)]), ql.Period(n, unit), settlementDays, calendar, ql.ModifiedFollowing, False, dayCounter, ) for n, unit in deposits.keys() ] # %% dayCounter = ql.Actual360() settlementDays = 2 fraHelpers = [ ql.FraRateHelper( ql.QuoteHandle(FRAs[(n, m)]), n, m, settlementDays, calendar, ql.ModifiedFollowing, False, dayCounter ) for n, m in FRAs.keys() ] # %% dayCounter = ql.Actual360() months = 3 futuresHelpers = [ ql.FuturesRateHelper( ql.QuoteHandle(futures[d]), d, months, calendar, ql.ModifiedFollowing, True, dayCounter, ql.makeQuoteHandle(0.0), ) for d in futures.keys() ] # %% [markdown] # The discount curve for the swaps will come from elsewhere. A real application would use some kind of risk-free curve; here we're using a flat one for convenience. # %% discountTermStructure = ql.YieldTermStructureHandle( ql.FlatForward(settlementDate, 0.04, ql.Actual360())) # %% settlementDays = 2 fixedLegFrequency = ql.Annual fixedLegTenor = ql.Period(1, ql.Years) fixedLegAdjustment = ql.Unadjusted fixedLegDayCounter = ql.Thirty360(ql.Thirty360.BondBasis) floatingLegFrequency = ql.Quarterly floatingLegTenor = ql.Period(3, ql.Months) floatingLegAdjustment = ql.ModifiedFollowing swapHelpers = [ ql.SwapRateHelper( ql.QuoteHandle(swaps[(n, unit)]), ql.Period(n, unit), calendar, fixedLegFrequency, fixedLegAdjustment, fixedLegDayCounter, ql.Euribor3M(), ql.QuoteHandle(), ql.Period("0D"), discountTermStructure, ) for n, unit in swaps.keys() ] # %% [markdown] # ### Term structure construction # %% forecastTermStructure = ql.RelinkableYieldTermStructureHandle() # %% helpers = depositHelpers + futuresHelpers + swapHelpers[1:] depoFuturesSwapCurve = ql.PiecewiseFlatForward(settlementDate, helpers, ql.Actual360()) # %% helpers = depositHelpers + fraHelpers + swapHelpers depoFraSwapCurve = ql.PiecewiseFlatForward(settlementDate, helpers, ql.Actual360()) # %% [markdown] # ### Swap pricing # %% swapEngine = ql.DiscountingSwapEngine(discountTermStructure) # %% nominal = 1000000 length = 5 maturity = calendar.advance(settlementDate, length, ql.Years) payFixed = True # %% fixedLegFrequency = ql.Annual fixedLegAdjustment = ql.Unadjusted fixedLegDayCounter = ql.Thirty360(ql.Thirty360.BondBasis) fixedRate = 0.04 # %% floatingLegFrequency = ql.Quarterly spread = 0.0 fixingDays = 2 index = ql.Euribor3M(forecastTermStructure) floatingLegAdjustment = ql.ModifiedFollowing floatingLegDayCounter = index.dayCounter() # %% fixedSchedule = ql.Schedule( settlementDate, maturity, fixedLegTenor, calendar, fixedLegAdjustment, fixedLegAdjustment, ql.DateGeneration.Forward, False, ) floatingSchedule = ql.Schedule( settlementDate, maturity, floatingLegTenor, calendar, floatingLegAdjustment, floatingLegAdjustment, ql.DateGeneration.Forward, False, ) # %% [markdown] # We'll build a 5-years swap starting spot... # %% spot = ql.VanillaSwap( ql.Swap.Payer, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatingSchedule, index, spread, floatingLegDayCounter, ) spot.setPricingEngine(swapEngine) # %% [markdown] # ...and one starting 1 year forward. # %% forwardStart = calendar.advance(settlementDate, 1, ql.Years) forwardEnd = calendar.advance(forwardStart, length, ql.Years) fixedSchedule = ql.Schedule( forwardStart, forwardEnd, fixedLegTenor, calendar, fixedLegAdjustment, fixedLegAdjustment, ql.DateGeneration.Forward, False, ) floatingSchedule = ql.Schedule( forwardStart, forwardEnd, floatingLegTenor, calendar, floatingLegAdjustment, floatingLegAdjustment, ql.DateGeneration.Forward, False, ) # %% forward = ql.VanillaSwap( ql.Swap.Payer, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatingSchedule, index, spread, floatingLegDayCounter, ) forward.setPricingEngine(swapEngine) # %% [markdown] # We'll price them both on the bootstrapped curves. # # This is the quoted 5-years market rate; we expect the fair rate of the spot swap to match it. # %% print(swaps[(5, ql.Years)].value()) # %% def show(swap): print("NPV = %.2f" % swap.NPV()) print("Fair spread = %.4f %%" % (swap.fairSpread()*100)) print("Fair rate = %.4f %%" % (swap.fairRate()*100)) # %% [markdown] # These are the results for the 5-years spot swap on the deposit/futures/swap curve... # %% forecastTermStructure.linkTo(depoFuturesSwapCurve) show(spot) # %% [markdown] # ...and these are on the deposit/fra/swap curve. # %% forecastTermStructure.linkTo(depoFraSwapCurve) show(spot) # %% [markdown] # The same goes for the 1-year forward swap, except for the fair rate not matching the spot rate. # %% forecastTermStructure.linkTo(depoFuturesSwapCurve) show(forward) # %% forecastTermStructure.linkTo(depoFraSwapCurve) show(forward) # %% [markdown] # Modifying the 5-years swap rate and repricing will change the results: # %% swaps[(5, ql.Years)].setValue(0.046) # %% forecastTermStructure.linkTo(depoFuturesSwapCurve) # %% show(spot) # %% show(forward) # %% forecastTermStructure.linkTo(depoFraSwapCurve) # %% show(spot) # %% show(forward) QuantLib-SWIG-1.39/Python/examples/swing.py000066400000000000000000000054001503741206100205320ustar00rootroot00000000000000# --- # jupyter: # jupytext: # formats: py:light # text_representation: # extension: .py # format_name: light # format_version: '1.5' # jupytext_version: 1.4.2 # kernelspec: # display_name: Python 3 # language: python # name: python3 # --- # # Swing options # # Copyright (©) 2018 Klaus Spanderen # # This file is part of QuantLib, a free-software/open-source library # for financial quantitative analysts and developers - https://www.quantlib.org/ # # QuantLib is free software: you can redistribute it and/or modify it under the # terms of the QuantLib license. You should have received a copy of the # license along with this program; if not, please email # . The license is also available online at # . # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the license for more details. import QuantLib as ql import math todaysDate = ql.Date(30, ql.September, 2018) ql.Settings.instance().evaluationDate = todaysDate settlementDate = todaysDate riskFreeRate = ql.FlatForward(settlementDate, 0.0, ql.Actual365Fixed()) dividendYield = ql.FlatForward(settlementDate, 0.0, ql.Actual365Fixed()) underlying = ql.SimpleQuote(30.0) volatility = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.20, ql.Actual365Fixed()) exerciseDates = [ql.Date(1, ql.January, 2019) + i for i in range(31)] swingOption = ql.VanillaSwingOption( ql.VanillaForwardPayoff(ql.Option.Call, underlying.value()), ql.SwingExercise(exerciseDates), 0, len(exerciseDates) ) bsProcess = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility), ) swingOption.setPricingEngine(ql.FdSimpleBSSwingEngine(bsProcess)) print("Black Scholes Price: %f" % swingOption.NPV()) x0 = 0.0 x1 = 0.0 beta = 4.0 eta = 4.0 jumpIntensity = 1.0 speed = 1.0 volatility = 0.1 curveShape = [] for d in exerciseDates: t = ql.Actual365Fixed().yearFraction(todaysDate, d) gs = ( math.log(underlying.value()) - volatility * volatility / (4 * speed) * (1 - math.exp(-2 * speed * t)) - jumpIntensity / beta * math.log((eta - math.exp(-beta * t)) / (eta - 1.0)) ) curveShape.append((t, gs)) ouProcess = ql.ExtendedOrnsteinUhlenbeckProcess(speed, volatility, x0, lambda x: x0) jProcess = ql.ExtOUWithJumpsProcess(ouProcess, x1, beta, jumpIntensity, eta) swingOption.setPricingEngine(ql.FdSimpleExtOUJumpSwingEngine(jProcess, riskFreeRate, 25, 25, 200, curveShape)) print("Kluge Model Price : %f" % swingOption.NPV()) QuantLib-SWIG-1.39/Python/pytest.ini000066400000000000000000000001401503741206100172400ustar00rootroot00000000000000[pytest] filterwarnings = ignore:builtin type .* has no __module__ attribute:DeprecationWarning QuantLib-SWIG-1.39/Python/setup.py000066400000000000000000000155071503741206100167360ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 StatPro Italia srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import os, sys, math, platform, sysconfig from setuptools import setup, Extension from setuptools._distutils.ccompiler import get_default_compiler def define_macros(py_limited_api): define_macros = [] if py_limited_api: define_macros += [("Py_LIMITED_API", "0x03080000")] compiler = get_default_compiler() if compiler == "msvc": define_macros += [ ("__WIN32__", None), ("WIN32", None), ("NDEBUG", None), ("_WINDOWS", None), ("NOMINMAX", None), ] elif compiler == "unix": ql_compile_args = os.popen("quantlib-config --cflags").read()[:-1].split() define_macros += [ (arg[2:], None) for arg in ql_compile_args if arg.startswith("-D") ] define_macros += [("NDEBUG", None)] return define_macros def include_dirs(): include_dirs = [] compiler = get_default_compiler() if compiler == "msvc": try: QL_INSTALL_DIR = os.environ["QL_DIR"] include_dirs += [QL_INSTALL_DIR] except KeyError: print("warning: unable to detect QuantLib installation") if "INCLUDE" in os.environ: include_dirs += [ d.strip() for d in os.environ["INCLUDE"].split(";") if d.strip() ] elif compiler == "unix": ql_compile_args = os.popen("quantlib-config --cflags").read()[:-1].split() include_dirs += [arg[2:] for arg in ql_compile_args if arg.startswith("-I")] return include_dirs def library_dirs(): library_dirs = [] compiler = get_default_compiler() if compiler == "msvc": try: QL_INSTALL_DIR = os.environ["QL_DIR"] library_dirs += [os.path.join(QL_INSTALL_DIR, "lib")] except KeyError: print("warning: unable to detect QuantLib installation") if "LIB" in os.environ: dirs = [dir for dir in os.environ["LIB"].split(";")] library_dirs += [d for d in dirs if d.strip()] elif compiler == "unix": ql_link_args = os.popen("quantlib-config --libs").read()[:-1].split() library_dirs += [arg[2:] for arg in ql_link_args if arg.startswith("-L")] return library_dirs def libraries(): libraries = [] compiler = get_default_compiler() if compiler == "unix": ql_link_args = os.popen("quantlib-config --libs").read()[:-1].split() libraries += [arg[2:] for arg in ql_link_args if arg.startswith("-l")] return libraries def extra_compile_args(): extra_compile_args = [] compiler = get_default_compiler() if compiler == "msvc": extra_compile_args = ["/GR", "/FD", "/Zm250", "/EHsc", "/bigobj", "/std:c++17"] if "QL_STATIC_RUNTIME" in os.environ: extra_compile_args.append("/MT") else: extra_compile_args.append("/MD") elif compiler == "unix": ql_compile_args = os.popen("quantlib-config --cflags").read()[:-1].split() extra_compile_args = [ arg for arg in ql_compile_args if not arg.startswith("-D") if not arg.startswith("-I") ] + ["-Wno-unused"] if "CXXFLAGS" in os.environ: extra_compile_args += os.environ["CXXFLAGS"].split() return extra_compile_args def extra_link_args(): extra_link_args = [] compiler = get_default_compiler() if compiler == "msvc": dbit = round(math.log(sys.maxsize, 2) + 1) if dbit == 64: machinetype = "/machine:x64" else: machinetype = "/machine:x86" extra_link_args = ["/subsystem:windows", machinetype] elif compiler == "unix": ql_link_args = os.popen("quantlib-config --libs").read()[:-1].split() extra_link_args = [ arg for arg in ql_link_args if not arg.startswith("-L") if not arg.startswith("-l") ] if "LDFLAGS" in os.environ: extra_link_args += os.environ["LDFLAGS"].split() return extra_link_args classifiers = [ "Development Status :: 6 - Mature", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: End Users/Desktop", "Intended Audience :: Financial and Insurance Industry", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: C++", "Programming Language :: Python", "Topic :: Office/Business :: Financial", "Topic :: Scientific/Engineering", ] long_description = """ QuantLib (https://www.quantlib.org/) is a free/open-source C++ library for financial quantitative analysts and developers, aimed at providing a comprehensive software framework for quantitative finance. """ py_limited_api = platform.python_implementation() == "CPython" and not sysconfig.get_config_var("Py_GIL_DISABLED") with open("./setup.cfg", "w") as f: if py_limited_api: f.write('[bdist_wheel]' + os.linesep + 'py_limited_api=cp38' + os.linesep) setup( name="QuantLib", version="1.39", description="Python bindings for the QuantLib library", long_description=long_description, long_description_content_type="text/x-rst", author="QuantLib Team", author_email="quantlib-users@lists.sourceforge.net", url="https://www.quantlib.org", license="BSD 3-Clause", classifiers=classifiers, package_dir={"": "src"}, py_modules=["QuantLib.__init__", "QuantLib.QuantLib"], ext_modules=[ Extension( name="QuantLib._QuantLib", sources=["src/QuantLib/quantlib_wrap.cpp"], py_limited_api=py_limited_api, define_macros=define_macros(py_limited_api), include_dirs=include_dirs(), library_dirs=library_dirs(), libraries=libraries(), extra_compile_args=extra_compile_args(), extra_link_args=extra_link_args(), ) ], data_files=[("share/doc/quantlib", ["../LICENSE.TXT"])], ) QuantLib-SWIG-1.39/Python/setup.py.in000066400000000000000000000155241503741206100173420ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 StatPro Italia srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import os, sys, math, platform, sysconfig from setuptools import setup, Extension from setuptools._distutils.ccompiler import get_default_compiler def define_macros(py_limited_api): define_macros = [] if py_limited_api: define_macros += [("Py_LIMITED_API", "0x03080000")] compiler = get_default_compiler() if compiler == "msvc": define_macros += [ ("__WIN32__", None), ("WIN32", None), ("NDEBUG", None), ("_WINDOWS", None), ("NOMINMAX", None), ] elif compiler == "unix": ql_compile_args = os.popen("quantlib-config --cflags").read()[:-1].split() define_macros += [ (arg[2:], None) for arg in ql_compile_args if arg.startswith("-D") ] define_macros += [("NDEBUG", None)] return define_macros def include_dirs(): include_dirs = [] compiler = get_default_compiler() if compiler == "msvc": try: QL_INSTALL_DIR = os.environ["QL_DIR"] include_dirs += [QL_INSTALL_DIR] except KeyError: print("warning: unable to detect QuantLib installation") if "INCLUDE" in os.environ: include_dirs += [ d.strip() for d in os.environ["INCLUDE"].split(";") if d.strip() ] elif compiler == "unix": ql_compile_args = os.popen("quantlib-config --cflags").read()[:-1].split() include_dirs += [arg[2:] for arg in ql_compile_args if arg.startswith("-I")] return include_dirs def library_dirs(): library_dirs = [] compiler = get_default_compiler() if compiler == "msvc": try: QL_INSTALL_DIR = os.environ["QL_DIR"] library_dirs += [os.path.join(QL_INSTALL_DIR, "lib")] except KeyError: print("warning: unable to detect QuantLib installation") if "LIB" in os.environ: dirs = [dir for dir in os.environ["LIB"].split(";")] library_dirs += [d for d in dirs if d.strip()] elif compiler == "unix": ql_link_args = os.popen("quantlib-config --libs").read()[:-1].split() library_dirs += [arg[2:] for arg in ql_link_args if arg.startswith("-L")] return library_dirs def libraries(): libraries = [] compiler = get_default_compiler() if compiler == "unix": ql_link_args = os.popen("quantlib-config --libs").read()[:-1].split() libraries += [arg[2:] for arg in ql_link_args if arg.startswith("-l")] return libraries def extra_compile_args(): extra_compile_args = [] compiler = get_default_compiler() if compiler == "msvc": extra_compile_args = ["/GR", "/FD", "/Zm250", "/EHsc", "/bigobj", "/std:c++17"] if "QL_STATIC_RUNTIME" in os.environ: extra_compile_args.append("/MT") else: extra_compile_args.append("/MD") elif compiler == "unix": ql_compile_args = os.popen("quantlib-config --cflags").read()[:-1].split() extra_compile_args = [ arg for arg in ql_compile_args if not arg.startswith("-D") if not arg.startswith("-I") ] + ["-Wno-unused"] if "CXXFLAGS" in os.environ: extra_compile_args += os.environ["CXXFLAGS"].split() return extra_compile_args def extra_link_args(): extra_link_args = [] compiler = get_default_compiler() if compiler == "msvc": dbit = round(math.log(sys.maxsize, 2) + 1) if dbit == 64: machinetype = "/machine:x64" else: machinetype = "/machine:x86" extra_link_args = ["/subsystem:windows", machinetype] elif compiler == "unix": ql_link_args = os.popen("quantlib-config --libs").read()[:-1].split() extra_link_args = [ arg for arg in ql_link_args if not arg.startswith("-L") if not arg.startswith("-l") ] if "LDFLAGS" in os.environ: extra_link_args += os.environ["LDFLAGS"].split() return extra_link_args classifiers = [ "Development Status :: 6 - Mature", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: End Users/Desktop", "Intended Audience :: Financial and Insurance Industry", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: C++", "Programming Language :: Python", "Topic :: Office/Business :: Financial", "Topic :: Scientific/Engineering", ] long_description = """ QuantLib (https://www.quantlib.org/) is a free/open-source C++ library for financial quantitative analysts and developers, aimed at providing a comprehensive software framework for quantitative finance. """ py_limited_api = platform.python_implementation() == "CPython" and not sysconfig.get_config_var("Py_GIL_DISABLED") with open("./setup.cfg", "w") as f: if py_limited_api: f.write('[bdist_wheel]' + os.linesep + 'py_limited_api=cp38' + os.linesep) setup( name="QuantLib", version="@PACKAGE_VERSION@", description="Python bindings for the QuantLib library", long_description=long_description, long_description_content_type="text/x-rst", author="QuantLib Team", author_email="quantlib-users@lists.sourceforge.net", url="https://www.quantlib.org", license="BSD 3-Clause", classifiers=classifiers, package_dir={"": "src"}, py_modules=["QuantLib.__init__", "QuantLib.QuantLib"], ext_modules=[ Extension( name="QuantLib._QuantLib", sources=["src/QuantLib/quantlib_wrap.cpp"], py_limited_api=py_limited_api, define_macros=define_macros(py_limited_api), include_dirs=include_dirs(), library_dirs=library_dirs(), libraries=libraries(), extra_compile_args=extra_compile_args(), extra_link_args=extra_link_args(), ) ], data_files=[("share/doc/quantlib", ["../LICENSE.TXT"])], ) QuantLib-SWIG-1.39/Python/src/000077500000000000000000000000001503741206100160035ustar00rootroot00000000000000QuantLib-SWIG-1.39/Python/src/QuantLib/000077500000000000000000000000001503741206100175225ustar00rootroot00000000000000QuantLib-SWIG-1.39/Python/src/QuantLib/__init__.py000066400000000000000000000025271503741206100216410ustar00rootroot00000000000000# -*- coding: iso-8859-1 -*- """ Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ from .QuantLib import * from . import _QuantLib __author__ = 'The QuantLib Group' __email__ = 'quantlib-users@lists.sourceforge.net' if hasattr(_QuantLib,'__version__'): __version__ = _QuantLib.__version__ elif hasattr(_QuantLib.cvar,'__version__'): __version__ = _QuantLib.cvar.__version__ else: print('Could not find __version__ attribute') if hasattr(_QuantLib,'__hexversion__'): __hexversion__ = _QuantLib.__hexversion__ elif hasattr(_QuantLib.cvar,'__hexversion__'): __hexversion__ = _QuantLib.cvar.__hexversion__ else: print('Could not find __hexversion__ attribute') QuantLib-SWIG-1.39/Python/swig.cmd000066400000000000000000000001411503741206100166460ustar00rootroot00000000000000swig.exe -python -c++ -outdir src\QuantLib -o src\QuantLib\quantlib_wrap.cpp ..\SWIG\quantlib.i QuantLib-SWIG-1.39/Python/test/000077500000000000000000000000001503741206100161735ustar00rootroot00000000000000QuantLib-SWIG-1.39/Python/test/__init__.py000066400000000000000000000000001503741206100202720ustar00rootroot00000000000000QuantLib-SWIG-1.39/Python/test/test_americanquantooption.py000066400000000000000000000066441503741206100240560ustar00rootroot00000000000000""" Copyright (C) 2019 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql class AmericanQuantoOptionTest(unittest.TestCase): def setUp(self): self.today = ql.Date(21, ql.April, 2019) self.dc = ql.Actual365Fixed() ql.Settings.instance().evaluationDate = self.today self.domesticTS = ql.FlatForward(self.today, 0.025, self.dc) self.foreignTS = ql.FlatForward(self.today, 0.075, self.dc) self.fxVolTS = ql.BlackConstantVol(self.today, ql.TARGET(), 0.15, self.dc) self.quantoHelper = ql.FdmQuantoHelper( self.domesticTS, self.foreignTS, self.fxVolTS, -0.75, 1.0) self.divYieldTS = ql.FlatForward(self.today, 0.03, self.dc) self.dividends = [ql.FixedDividend(8.0, self.today + ql.Period(6, ql.Months))] maturityDate = self.today + ql.Period(9, ql.Months) self.option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, 105), ql.AmericanExercise(self.today, maturityDate)) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def testAmericanBSQuantoOption(self): """ Testing American Black-Scholes quanto option """ volTS = ql.BlackConstantVol(self.today, ql.TARGET(), 0.3, self.dc) bsmProcess = ql.BlackScholesMertonProcess( ql.makeQuoteHandle(100), ql.YieldTermStructureHandle(self.divYieldTS), ql.YieldTermStructureHandle(self.domesticTS), ql.BlackVolTermStructureHandle(volTS)) fdmBlackScholesEngine = ql.FdBlackScholesVanillaEngine( bsmProcess, self.dividends, self.quantoHelper, 100, 400, 1) self.option.setPricingEngine(fdmBlackScholesEngine) fdmPrice = self.option.NPV() expected = 8.90611734 self.assertAlmostEqual(fdmPrice, expected, 3, msg="Unable to reproduce American BS quanto option price.") def testAmericanHestonQuantoOption(self): """ Testing American Heston quanto option """ hestonModel = ql.HestonModel( ql.HestonProcess( ql.YieldTermStructureHandle(self.domesticTS), ql.YieldTermStructureHandle(self.divYieldTS), ql.makeQuoteHandle(100), 0.09, 1.0, 0.09, 1e-4, 0.0)) fdmHestonVanillaEngine = ql.FdHestonVanillaEngine( hestonModel, self.dividends, self.quantoHelper, 100, 400, 3, 1) self.option.setPricingEngine(fdmHestonVanillaEngine) fdmPrice = self.option.NPV() expected = 8.90611734 self.assertAlmostEqual(fdmPrice, expected, 3, msg="Unable to reproduce American Heston quanto option price.") if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_basket_option.py000066400000000000000000000144321503741206100224510ustar00rootroot00000000000000""" Copyright (C) 2024 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql class BasketOptionTest(unittest.TestCase): def setUp(self): self.todaysDate = ql.Date(26, ql.October, 2024) ql.Settings.instance().evaluationDate = self.todaysDate def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def testThreeAssetSpreadOption(self): """Testing three asset spread option""" def build_process(s: float, q: float, v: float) -> ql.BlackScholesMertonProcess: return ql.BlackScholesMertonProcess( ql.QuoteHandle(ql.SimpleQuote(s)), ql.YieldTermStructureHandle( ql.FlatForward(self.todaysDate, q, ql.Actual365Fixed()) ), ql.YieldTermStructureHandle( ql.FlatForward(self.todaysDate, 0.05, ql.Actual365Fixed()) ), ql.BlackVolTermStructureHandle( ql.BlackConstantVol( self.todaysDate, ql.TARGET(), v, ql.Actual365Fixed() ) ), ) processes = [ build_process(100, 0.05, 0.3), build_process(50, 0.07, 0.45), build_process(50, 0.025, 0.2), ] processes_vector = ql.GeneralizedBlackScholesProcessVector(processes) rho = ql.Matrix([[1.0, 0.2, -0.1], [0.2, 1.0, -0.3], [-0.1, -0.3, 1.0]]) exercise = ql.EuropeanExercise(self.todaysDate + ql.Period(1, ql.Years)) payoff = ql.PlainVanillaPayoff(ql.Option.Call, 2.0) basket_option = ql.BasketOption( ql.AverageBasketPayoff(payoff, ql.Array([1, -1, -1])), exercise ) expected = 11.932739641 basket_option.setPricingEngine(ql.ChoiBasketEngine(processes_vector, rho, 10)) self.assertAlmostEqual(basket_option.NPV(), expected) basket_option.setPricingEngine(ql.DengLiZhouBasketEngine(processes_vector, rho)) self.assertAlmostEqual(basket_option.NPV(), expected, 1) basket_option.setPricingEngine( ql.MCEuropeanBasketEngine( ql.StochasticProcessArray(processes, rho), "lowdiscrepancy", timeSteps=1, requiredTolerance=0.1, ) ) self.assertAlmostEqual(basket_option.NPV(), expected, 1) basket_option.setPricingEngine( ql.FdndimBlackScholesVanillaEngine( processes_vector, rho, ql.UnsignedIntVector([25, 15, 15]), 15 ) ) self.assertAlmostEqual(basket_option.NPV(), expected, 1) def testTwoAssetSpreadOption(self): """Testing two asset spread option""" def build_process(s: float, v: float) -> ql.BlackProcess: return ql.BlackProcess( ql.QuoteHandle(ql.SimpleQuote(s)), ql.YieldTermStructureHandle( ql.FlatForward(self.todaysDate, 0.05, ql.Actual365Fixed()) ), ql.BlackVolTermStructureHandle( ql.BlackConstantVol( self.todaysDate, ql.TARGET(), v, ql.Actual365Fixed() ) ), ) p1 = build_process(100, 0.3) p2 = build_process(90, 0.45) rho = -0.75 rho_m = ql.Matrix([[1, rho], [rho, 1]]) processes_vector = ql.GeneralizedBlackScholesProcessVector([p1, p2]) exercise = ql.EuropeanExercise(self.todaysDate + ql.Period(6, ql.Months)) payoff = ql.PlainVanillaPayoff(ql.Option.Put, 10.0) basket_option = ql.BasketOption(ql.SpreadBasketPayoff(payoff), exercise) expected = 17.96241322097977 basket_option.setPricingEngine(ql.ChoiBasketEngine(processes_vector, rho_m, 15)) self.assertAlmostEqual(basket_option.NPV(), expected, 10) basket_option.setPricingEngine( ql.DengLiZhouBasketEngine(processes_vector, rho_m) ) self.assertAlmostEqual(basket_option.NPV(), expected, 4) basket_option.setPricingEngine(ql.KirkEngine(p1, p2, rho)) self.assertAlmostEqual(basket_option.NPV(), expected, 1) basket_option.setPricingEngine(ql.BjerksundStenslandSpreadEngine(p1, p2, rho)) self.assertAlmostEqual(basket_option.NPV(), expected, 2) basket_option.setPricingEngine( ql.OperatorSplittingSpreadEngine( p1, p2, rho, ql.OperatorSplittingSpreadEngine.First ) ) self.assertAlmostEqual(basket_option.NPV(), expected, 1) basket_option.setPricingEngine( ql.OperatorSplittingSpreadEngine( p1, p2, rho, ql.OperatorSplittingSpreadEngine.Second ) ) self.assertAlmostEqual(basket_option.NPV(), expected, 2) basket_option.setPricingEngine( ql.FdndimBlackScholesVanillaEngine( processes_vector, rho_m, ql.UnsignedIntVector([25, 25]), 15 ) ) self.assertAlmostEqual(basket_option.NPV(), expected, 1) basket_option.setPricingEngine( ql.Fd2dBlackScholesVanillaEngine(p1, p2, rho, xGrid=25, yGrid=25, tGrid=15) ) self.assertAlmostEqual(basket_option.NPV(), expected, 1) basket_option.setPricingEngine( ql.MCEuropeanBasketEngine( ql.StochasticProcessArray([p1, p2], rho_m), "lowdiscrepancy", timeSteps=1, requiredTolerance=0.1, ) ) self.assertAlmostEqual(basket_option.NPV(), expected, 1) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_blackformula.py000066400000000000000000000131271503741206100222520ustar00rootroot00000000000000# coding=utf-8-unix """ Copyright (C) 2017 Wojciech Åšlusarski This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import math import QuantLib as ql class BlackFormulaTest(unittest.TestCase): def setUp(self): # define the market and option parameters self.option_type = ql.Option.Call self.spot = 100.0 self.strike = 100.0 self.risk_free_rate = 0.05 self.expiry = 1.0 self.forward = self.spot * math.exp(self.risk_free_rate * self.expiry) self.df = math.exp(-self.risk_free_rate * self.expiry) self.vol = 0.2 * math.sqrt(self.expiry) self.displacement = 0.0 def test_blackFormula(self): """Testing blackFormula in a simple Black-Scholes World...""" #Anyone interested, feel free to provide more accurate number expected = 10.4506 res = ql.blackFormula(self.option_type, self.strike, self.forward, self.vol, self.df, self.displacement) self.assertAlmostEqual(expected, res, delta=1e-4, msg="Failed to calculate simple " "Black-Scholes-Merton price rounded to " "four decimal places.") def test_black_formula_implied_stdev(self): """Testing implied volatility calculator""" expected = 0.2 * math.sqrt(self.expiry) black_price = 10.4506 res = ql.blackFormulaImpliedStdDev(self.option_type, self.strike, self.forward, black_price, self.df) self.assertAlmostEqual(expected, res, delta=1e-4, msg="Failed to determine Implied Vol rounded " "to a single vol bps.") class BlackDeltaCalculatorTest(unittest.TestCase): def setUp(self): self.todaysDate = ql.Date(5, ql.September, 2017) ql.Settings.instance().evaluationDate = self.todaysDate self.spotDate = ql.Date(7, ql.September, 2017) self.domestic_rate = ql.FlatForward(self.spotDate, 0.017, ql.Actual365Fixed()) self.foreign_rate = ql.FlatForward(self.spotDate, 0.013, ql.Actual365Fixed()) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def test_single_spot_delta(self): """Test for a single strike for call spot delta 75""" volatility = 0.2 expiry = 2 spot_price = 3.6 domDf = self.domestic_rate.discount(expiry) forDf = self.foreign_rate.discount(expiry) forward = spot_price * forDf / domDf spot_delta_level = 0.75 stDev = volatility * expiry ** 0.5 inv_norm_dist = ql.InverseCumulativeNormal() expected_strike = inv_norm_dist(spot_delta_level / forDf) expected_strike *= stDev expected_strike -= 0.5 * stDev ** 2 expected_strike = math.exp(expected_strike) / forward expected_strike = 1 / expected_strike option_type = ql.Option.Call delta_type = ql.DeltaVolQuote.Spot black_calculator = ql.BlackDeltaCalculator(option_type, delta_type, spot_price, domDf, forDf, stDev) strike = black_calculator.strikeFromDelta(spot_delta_level) self.assertAlmostEqual(expected_strike, strike, delta=1e-4) def test_spot_atm_delta_calculator(self): """Test for 0-delta straddle strike""" volatility = 0.2 expiry = 2 spot_price = 3.6 domDf = self.domestic_rate.discount(expiry) forDf = self.foreign_rate.discount(expiry) forward = spot_price * forDf / domDf expected_strike = forward * math.exp(-0.5 * volatility ** 2 * expiry) option_type = ql.Option.Call delta_type = ql.DeltaVolQuote.AtmDeltaNeutral stDev = volatility * expiry ** 0.5 black_calculator = ql.BlackDeltaCalculator(option_type, delta_type, spot_price, domDf, forDf, stDev) strike = black_calculator.atmStrike(ql.DeltaVolQuote.AtmDeltaNeutral) self.assertAlmostEqual(expected_strike, strike, delta=1e-4) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_bondfunctions.py000066400000000000000000000256151503741206100224700ustar00rootroot00000000000000""" Copyright (C) 2009 Joseph Malicki Copyright (C) 2019 Prasad Somwanshi Copyright (C) 2023 Francois Botha This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest class BondFunctionsTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = ql.Date(2, 1, 2010) self.settlement_days = 3 self.face_amount = 100.0 self.redemption = 100.0 self.issue_date = ql.Date(2, 1, 2008) self.maturity_date = ql.Date(2, 1, 2018) self.calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) self.settlement_date = self.calendar.advance( ql.Settings.instance().evaluationDate, self.settlement_days, ql.Days) self.day_counter = ql.ActualActual(ql.ActualActual.Bond) self.sched = ql.Schedule( self.issue_date, self.maturity_date, ql.Period(ql.Semiannual), self.calendar, ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False, ) self.coupons = [0.05] self.bond = ql.FixedRateBond( self.settlement_days, self.face_amount, self.sched, self.coupons, self.day_counter, ql.Following, self.redemption, self.issue_date, ) self.flat_forward = ql.FlatForward( self.issue_date, self.coupons[0], self.day_counter, ql.Compounded, ql.Semiannual ) self.term_structure_handle = ql.RelinkableYieldTermStructureHandle( self.flat_forward) bondEngine = ql.DiscountingBondEngine(self.term_structure_handle) self.bond.setPricingEngine(bondEngine) def testStartDate(self): """ Testing BondFunctions startDate. """ self.assertEqual(ql.BondFunctions.startDate( self.bond), self.issue_date) def testMaturityDate(self): """ Testing BondFunctions maturityDate. """ self.assertEqual(ql.BondFunctions.maturityDate( self.bond), self.maturity_date) def testIsTradable(self): """ Testing BondFunctions isTradable. """ self.assertTrue(ql.BondFunctions.isTradable( self.bond, ql.Date(1, 6, 2010))) self.assertFalse(ql.BondFunctions.isTradable( self.bond, ql.Date(1, 1, 2028))) def testPreviousCashFlowDate(self): """ Testing BondFunctions previousCashFlowDate. """ self.assertEqual(ql.BondFunctions.previousCashFlowDate(self.bond, ql.Date(1, 6, 2010)), ql.Date(4, 1, 2010)) def testNextCashFlowDate(self): """ Testing BondFunctions nextCashFlowDate. """ self.assertEqual(ql.BondFunctions.nextCashFlowDate(self.bond, ql.Date(1, 6, 2010)), ql.Date(2, 7, 2010)) def testPreviousCashFlowAmount(self): """ Testing BondFunctions previousCashFlowAmount. """ self.assertEqual(round(ql.BondFunctions.previousCashFlowAmount( self.bond, ql.Date(1, 6, 2010)), 4), 2.5) def testNextCashFlowAmount(self): """ Testing BondFunctions nextCashFlowAmount. """ self.assertEqual(round(ql.BondFunctions.nextCashFlowAmount( self.bond, ql.Date(1, 6, 2010)), 4), 2.5) def testPreviousCouponRate(self): """ Testing BondFunctions previousCouponRate. """ self.assertEqual(ql.BondFunctions.previousCouponRate(self.bond), 0.05) def testNextCouponRate(self): """ Testing BondFunctions nextCouponRate. """ self.assertEqual(ql.BondFunctions.nextCouponRate(self.bond), 0.05) def testAccrualStartDate(self): """ Testing BondFunctions accrualStartDate. """ self.assertEqual(ql.BondFunctions.accrualStartDate(self.bond, ql.Date(1, 6, 2010)), ql.Date(2, 1, 2010)) def testAccrualEndDate(self): """ Testing BondFunctions accrualEndDate. """ self.assertEqual(ql.BondFunctions.accrualEndDate(self.bond, ql.Date(1, 6, 2010)), ql.Date(2, 7, 2010)) def testAccrualPeriod(self): """ Testing BondFunctions accrualPeriod. """ self.assertEqual(ql.BondFunctions.accrualPeriod(self.bond, ql.Date(1, 6, 2010)), 0.5) def testAccrualDays(self): """ Testing BondFunctions accrualDays. """ self.assertEqual(ql.BondFunctions.accrualDays(self.bond, ql.Date(1, 10, 2010)), 184) def testAccruedPeriod(self): """ Testing BondFunctions accruedPeriod. """ self.assertEqual(round(ql.BondFunctions.accruedPeriod(self.bond, ql.Date(1, 6, 2010)), 8), 0.41436464) def testAccruedDays(self): """ Testing BondFunctions accruedDays. """ self.assertEqual(ql.BondFunctions.accruedDays(self.bond, ql.Date(1, 6, 2010)), 150) def testAccruedAmount(self): """ Testing BondFunctions accruedAmount. """ self.assertEqual(round(ql.BondFunctions.accruedAmount(self.bond, ql.Date(1, 6, 2010)), 8), 2.0718232) def testBps(self): """ Testing BondFunctions bps. """ self.assertEqual(round(ql.BondFunctions.bps(self.bond, self.flat_forward), 8), 0.06527501) self.assertEqual(round(ql.BondFunctions.bps(self.bond, ql.InterestRate(0.03, self.day_counter, ql.Compounded, ql.Annual)), 8), 0.07071951) self.assertEqual(round(ql.BondFunctions.bps(self.bond, 0.03, self.day_counter, ql.Compounded, ql.Annual), 8), 0.07071951) def testCleanPrice(self): """ Testing BondFunctions cleanPrice. """ self.assertEqual(round(ql.BondFunctions.cleanPrice(self.bond, self.flat_forward), 4), 99.9448) self.assertEqual(round(ql.BondFunctions.cleanPrice(self.bond, ql.InterestRate(0.03, self.day_counter, ql.Compounded, ql.Annual)), 4), 114.2806) self.assertEqual(round(ql.BondFunctions.cleanPrice(self.bond, 0.03, self.day_counter, ql.Compounded, ql.Annual), 4), 114.2806) def testAtmRate(self): """ Testing BondFunctions atmRate. """ self.assertEqual(round(ql.BondFunctions.atmRate(self.bond, self.flat_forward, self.settlement_date, ql.BondPrice(99.94475138121548, ql.BondPrice.Clean)), 4), 0.05) def testBondYield(self): """ Testing BondFunctions bondYield. """ self.assertEqual(round(ql.BondFunctions.bondYield(self.bond, ql.BondPrice(110, ql.BondPrice.Clean), self.day_counter, ql.Compounded, ql.Annual), 8), 0.03582431) def testDuration(self): """ Testing BondFunctions duration. """ self.assertEqual(round(ql.BondFunctions.duration(self.bond, ql.InterestRate(0.03, self.day_counter, ql.Compounded, ql.Annual)), 4), 6.5835) self.assertEqual(round(ql.BondFunctions.duration(self.bond, 0.03, self.day_counter, ql.Compounded, ql.Annual), 4), 6.5835) def testConvexity(self): """ Testing BondFunctions convexity. """ self.assertEqual(round(ql.BondFunctions.convexity(self.bond, ql.InterestRate(0.03, self.day_counter, ql.Compounded, ql.Annual)), 4), 54.3498) self.assertEqual(round(ql.BondFunctions.convexity(self.bond, 0.03, self.day_counter, ql.Compounded, ql.Annual), 4), 54.3498) def testBasisPointValue(self): """ Testing BondFunctions basisPointValue. """ self.assertEqual(round(ql.BondFunctions.basisPointValue(self.bond, 0.03, self.day_counter, ql.Compounded, ql.Annual, self.settlement_date), 8), -0.07527271) self.assertEqual(round(ql.BondFunctions.basisPointValue(self.bond, ql.InterestRate( 0.03, self.day_counter, ql.Compounded, ql.Annual), self.settlement_date), 8), -0.07527271) def testYieldValueBasisPoint(self): """ Testing BondFunctions yieldValueBasisPoint. """ self.assertEqual(round(ql.BondFunctions.yieldValueBasisPoint(self.bond, ql.InterestRate( 0.03, self.day_counter, ql.Compounded, ql.Annual), ql.Date(1, 9, 2010)), 10), -1.44145e-05) self.assertEqual(round(ql.BondFunctions.yieldValueBasisPoint(self.bond, 0.03, self.day_counter, ql.Compounded, ql.Annual, ql.Date(1, 9, 2010)), 10), -1.44145e-05) def testZSpread(self): """ Testing BondFunctions zSpread. """ self.assertEqual(round(ql.BondFunctions.zSpread(self.bond, ql.BondPrice(87.5, ql.BondPrice.Clean), self.flat_forward, self.day_counter, ql.Compounded, ql.Annual), 8), 0.02125053) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_bonds.py000066400000000000000000000316311503741206100207150ustar00rootroot00000000000000""" Copyright (C) 2009 Joseph Malicki Copyright (C) 2019 Prasad Somwanshi This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest class FixedRateBondTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = ql.Date(2, 1, 2010) self.settlement_days = 3 self.face_amount = 100.0 self.redemption = 100.0 self.issue_date = ql.Date(2, 1, 2008) self.maturity_date = ql.Date(2, 1, 2018) self.calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) self.day_counter = ql.ActualActual(ql.ActualActual.Bond) self.sched = ql.Schedule( self.issue_date, self.maturity_date, ql.Period(ql.Semiannual), self.calendar, ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False, ) self.coupons = [0.05] self.bond = ql.FixedRateBond( self.settlement_days, self.face_amount, self.sched, self.coupons, self.day_counter, ql.Following, self.redemption, self.issue_date, ) self.flat_forward = ql.FlatForward( self.issue_date, self.coupons[0], self.day_counter, ql.Compounded, ql.Semiannual ) self.term_structure_handle = ql.RelinkableYieldTermStructureHandle(self.flat_forward) bondEngine = ql.DiscountingBondEngine(self.term_structure_handle) self.bond.setPricingEngine(bondEngine) def testFrequency(self): """ Testing FixedRateBond frequency() method. """ self.assertEqual(self.bond.frequency(), ql.Semiannual) def testDayCounter(self): """ Testing FixedRateBond dayCounter() method. """ self.assertEqual(self.bond.dayCounter(), self.day_counter) def testSimpleInspectors(self): """ Testing FixedRateBond simple inspectors. """ self.assertEqual(self.bond.settlementDays(), self.settlement_days) self.assertEqual(self.bond.notional(), self.face_amount) self.assertEqual(self.bond.issueDate(), self.issue_date) self.assertEqual(self.bond.maturityDate(), self.maturity_date) # def testSettlementValue(self): # """ Testing FixedRateBond settlement value. """ # orig_date = ql.Settings.evaluationDate # ql.Settings.evaluationDate = self.issue_date + 1*ql.Months # self.assertEqual(round(self.bond.settlementValue(100.0), 4), 102.3098) # ql.Settings.evaluationDate = orig_date def testCashFlows(self): """ Testing that the FixedRateBond gives the expected cash flows. """ self.assertEqual( [round(cf.amount(), 4) for cf in self.bond.cashflows()], 20 * [round(self.face_amount * self.coupons[0] / 2, 4)] + [round(self.redemption, 4)], ) def testRedemption(self): """ Testing FixedRateBond redemption value and date. """ self.assertEqual(self.bond.redemption().date(), self.maturity_date) self.assertEqual(self.bond.redemption().amount(), self.redemption) def testRedemptions(self): """ Testing FixedRateBond redemptions. """ redemptions = self.bond.redemptions() self.assertEqual(len(redemptions), 1) self.assertEqual(redemptions[0].date(), self.maturity_date) self.assertEqual(redemptions[0].amount(), self.redemption) def testNotional(self): """ Testing FixedRateBond notional values. """ self.assertEqual(self.bond.notional(), 100.0) self.assertEqual(self.bond.notionals(), (100.0, 0)) def testNextCoupon(self): """ Testing FixedRateBond correct next coupon amount. """ self.assertEqual(self.bond.nextCouponRate(self.issue_date), 0.05) def testPrevCoupon(self): """ Testing FixedRateBond correct previous coupon amount. """ self.assertEqual(self.bond.previousCouponRate(), 0.05) def testCleanPrice(self): """ Testing FixedRateBond clean price. """ self.assertEqual( round(self.bond.cleanPrice(0.05, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date), 4), 99.9964, ) self.assertEqual( round( self.bond.cleanPrice( 0.05, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date + ql.Period(1, ql.Months) ), 4, ), 99.9921, ) self.assertEqual( round( self.bond.cleanPrice( 0.06, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date + ql.Period(1, ql.Months) ), 4, ), 92.5985, ) def testDirtyPrice(self): """ Testing FixedRateBond dirty price. """ self.assertEqual( round(self.bond.dirtyPrice(0.05, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date), 4), 99.9964, ) self.assertEqual( round( self.bond.dirtyPrice( 0.05, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date + ql.Period(1, ql.Months) ), 4, ), 100.4179, ) self.assertEqual( round( self.bond.dirtyPrice( 0.06, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date + ql.Period(1, ql.Months) ), 4, ), 93.0244, ) def testCleanPriceFromZSpread(self): """ Testing FixedRateBond clean price derived from Z-spread. """ self.assertEqual( round( ql.cleanPriceFromZSpread( self.bond, self.flat_forward, 0.01, self.day_counter, ql.Compounded, ql.Semiannual, self.issue_date + ql.Period(1, ql.Months), ), 4, ), 92.5926, ) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() class FixedRateBondKwargsTest(unittest.TestCase): def setUp(self): self.settlement_days = 3 self.face_amount = 100.0 self.redemption = 100.0 self.issue_date = ql.Date(2, 1, 2008) self.maturity_date = ql.Date(2, 1, 2018) self.calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) self.day_counter = ql.ActualActual(ql.ActualActual.Bond) self.sched = ql.Schedule( self.issue_date, self.maturity_date, ql.Period(ql.Semiannual), self.calendar, ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False, ) self.coupons = [0.05] def testConstructor(self): """ Testing FixedRateBond constructor with keyword arguments. """ bond = ql.FixedRateBond( settlementDays=self.settlement_days, schedule=self.sched, paymentDayCounter=self.day_counter, issueDate=self.issue_date, coupons=self.coupons, faceAmount=self.face_amount, ) self.assertTrue(type(bond) is ql.FixedRateBond) self.assertEqual(bond.dayCounter(), self.day_counter) self.assertEqual(bond.settlementDays(), self.settlement_days) self.assertEqual(bond.issueDate(), self.issue_date) self.assertEqual(bond.maturityDate(), self.maturity_date) self.assertEqual(bond.redemption().date(), self.maturity_date) self.assertEqual(bond.redemption().amount(), self.redemption) self.assertEqual(bond.notional(self.issue_date), 100.0) self.assertEqual(bond.notionals(), (100.0, 0)) class AmortizingFixedRateBondTest(unittest.TestCase): def test_interest_rates(self): # see AmortizingBondTest::testBrazilianAmortizingFixedRateBond # in the C++ test suite nominals = [ 1000 , 983.33300000, 966.66648898, 950.00019204, 933.33338867, 916.66685434, 900.00001759, 883.33291726, 866.66619177, 849.99933423, 833.33254728, 816.66589633, 799.99937871, 783.33299165, 766.66601558, 749.99946306, 733.33297499, 716.66651646, 699.99971995, 683.33272661, 666.66624140, 649.99958536, 633.33294599, 616.66615618, 599.99951997, 583.33273330, 566.66633377, 549.99954356, 533.33290739, 516.66625403, 499.99963400, 483.33314619, 466.66636930, 449.99984658, 433.33320226, 416.66634063, 399.99968700, 383.33290004, 366.66635221, 349.99953317, 333.33290539, 316.66626012, 299.99948151, 283.33271031, 266.66594695, 249.99932526, 233.33262024, 216.66590450, 199.99931312, 183.33277035, 166.66617153, 149.99955437, 133.33295388, 116.66633464, 99.99973207, 83.33307672, 66.66646137, 49.99984602, 33.33324734, 16.66662367 ] expected_amortizations = [ 16.66700000, 16.66651102, 16.66629694, 16.66680337, 16.66653432, 16.66683675, 16.66710033, 16.66672548, 16.66685753, 16.66678695, 16.66665095, 16.66651761, 16.66638706, 16.66697606, 16.66655251, 16.66648807, 16.66645852, 16.66679651, 16.66699333, 16.66648520, 16.66665604, 16.66663937, 16.66678981, 16.66663620, 16.66678667, 16.66639952, 16.66679021, 16.66663617, 16.66665336, 16.66662002, 16.66648780, 16.66677688, 16.66652271, 16.66664432, 16.66686163, 16.66665363, 16.66678696, 16.66654783, 16.66681904, 16.66662777, 16.66664527, 16.66677860, 16.66677119, 16.66676335, 16.66662168, 16.66670502, 16.66671573, 16.66659137, 16.66654276, 16.66659882, 16.66661715, 16.66660049, 16.66661924, 16.66660257, 16.66665534, 16.66661534, 16.66661534, 16.66659867, 16.66662367, 16.66662367 ] expected_coupons = [ 5.97950399, 4.85474255, 5.27619136, 5.18522454, 5.33753111, 5.24221882, 4.91231709, 4.59116258, 4.73037674, 4.63940686, 4.54843737, 3.81920094, 4.78359948, 3.86733691, 4.38439657, 4.09359456, 4.00262671, 4.28531030, 3.82068947, 3.55165259, 3.46502778, 3.71720657, 3.62189368, 2.88388676, 3.58769952, 2.72800044, 3.38838360, 3.00196900, 2.91100034, 3.08940793, 2.59877059, 2.63809514, 2.42551945, 2.45615766, 2.59111761, 1.94857222, 2.28751141, 1.79268582, 2.19248291, 1.81913832, 1.90625855, 1.89350716, 1.48110584, 1.62031828, 1.38600825, 1.23425366, 1.39521333, 1.06968563, 1.03950542, 1.00065409, 0.90968563, 0.81871706, 0.79726493, 0.63678002, 0.57187676, 0.49829046, 0.31177086, 0.27290565, 0.19062560, 0.08662552 ] settlementDays = 0 issueDate = ql.Date(2, ql.March, 2020) maturityDate = ql.Date(2, ql.March, 2025) schedule = ql.Schedule(issueDate, maturityDate, ql.Period(ql.Monthly), ql.Brazil(ql.Brazil.Settlement), ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False) coupons = ql.FixedRateLeg( schedule, nominals = nominals, couponRates = [0.0675], dayCount = ql.Business252(ql.Brazil()), compounding = ql.Compounded, compoundingFrequency = ql.Annual, paymentAdjustment = ql.Following, ) bond = ql.Bond( settlementDays, schedule.calendar(), issueDate, coupons ) cashflows = bond.cashflows() self.assertEqual(len(cashflows), 2 * len(nominals)) for k in range(len(nominals)): self.assertEqual(round(expected_coupons[k], 5), round(cashflows[2*k].amount(), 5)) self.assertEqual(round(expected_amortizations[k], 5), round(cashflows[2*k+1].amount(), 5)) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_calendars.py000066400000000000000000000052451503741206100215460ustar00rootroot00000000000000""" Copyright (C) 2023 Skandinaviska Enskilda Banken AB (publ) This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import itertools import unittest import QuantLib as ql class JointCalendarTest(unittest.TestCase): def test_joint_calendar_holidays(self): base_calendars = [ql.Sweden(), ql.Denmark(), ql.Finland(), ql.Norway(), ql.Iceland()] joint_nordics = ql.JointCalendar(base_calendars) start_date = ql.Date(1, ql.January, 2023) end_date = ql.Date(31, ql.December, 2023) joint_holidays = set(joint_nordics.holidayList(start_date, end_date)) base_holidays = set(itertools.chain.from_iterable( calendar.holidayList(start_date, end_date) for calendar in base_calendars )) self.assertEqual(joint_holidays, base_holidays) class BespokeCalendarTest(unittest.TestCase): def test_hash(self): empty1, empty2 = ql.CalendarVector(2) for cal1 in (ql.BespokeCalendar("one"), ql.BespokeCalendar("two"), empty1): for cal2 in (ql.BespokeCalendar("one"), ql.BespokeCalendar("two"), empty2): if cal1.empty() or cal2.empty(): expected = cal1.empty() == cal2.empty() else: expected = cal1.name() == cal2.name() self.assertEqual(cal1 == cal2, expected) self.assertEqual(cal1 != cal2, not expected) self.assertEqual(hash(cal1) == hash(cal2), expected) def test_reset_added_holidays(self): calendar = ql.BespokeCalendar("bespoke thing") test_date = ql.Date(1, ql.January, 2024) self.assertFalse(calendar.isHoliday(test_date)) calendar.addHoliday(test_date) self.assertTrue(calendar.isHoliday(test_date)) # TODO: Can extend test with this, if exposed: # self.assertEqual(len(calendar.addedHolidays()), 1) calendar.resetAddedAndRemovedHolidays() self.assertFalse(calendar.isHoliday(test_date)) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_capfloor.py000066400000000000000000000106441503741206100214160ustar00rootroot00000000000000# coding=utf-8-unix """ Copyright (C) 2016 Wojciech Åšlusarski This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest class CapFloorTest(unittest.TestCase): def setUp(self): self.today_date = ql.Date(9, 9, 2016) self.settlement_days = 2 self.notional = 1e4 self.calendar = ql.TARGET() self.flat_forward_rate = 0.01 self.rate_day_counter = ql.Actual360() self.flat_forward = ql.FlatForward(self.today_date, self.flat_forward_rate, self.rate_day_counter, ql.Continuous, ql.Annual) self.term_structure_handle = \ ql.RelinkableYieldTermStructureHandle(self.flat_forward) self.interpolation = ql.Linear() self.start_date = ql.Date(13, 9, 2016) self.maturity_date = ql.Date(13, 9, 2017) self.period = ql.Period(6, ql.Months) self.buss_convention = ql.ModifiedFollowing self.date_gen_rule = ql.DateGeneration.Forward self.eom_rule = False self.schedule = ql.Schedule(self.start_date, self.maturity_date, self.period, self.calendar, self.buss_convention, self.buss_convention, self.date_gen_rule, self.eom_rule) ql.Settings.instance().evaluationDate = self.today_date self.ibor_index = ql.Euribor(self.period, self.term_structure_handle) self.ibor_index.addFixing(ql.Date(9, 9, 2016), 0.01) self.ibor_leg = ql.IborLeg([self.notional], self.schedule, self.ibor_index) self.strike = 0.01 self.cap = ql.Cap(self.ibor_leg, [self.strike]) self.cap_npv = 8.54 self.black_vol = ql.makeQuoteHandle(0.6) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def testBlackCapFloorEngine(self): """ Testing BlackCapFloorEngine """ black_engine = ql.BlackCapFloorEngine(self.term_structure_handle, self.black_vol) self.cap.setPricingEngine(black_engine) npv = self.cap.NPV() self.assertAlmostEqual(npv, self.cap_npv, places=1, msg="NPV method is broken") vol_guess = 0.5 imp_vol = self.cap.impliedVolatility(npv, self.term_structure_handle, vol_guess) self.assertAlmostEqual(self.black_vol.value(), imp_vol, places=4, msg="Implied volatility method is broken") def testBachelierCapFloorEngine(self): """ Testing BachelierCapFloorEngine """ bpvol = self.black_vol.value() * self.flat_forward_rate bachelier_engine = ql.BachelierCapFloorEngine(self.term_structure_handle, ql.makeQuoteHandle(bpvol)) self.cap.setPricingEngine(bachelier_engine) # 50 bps vol_guess = 50 / 1e4 imp_vol = self.cap.impliedVolatility(self.cap_npv, self.term_structure_handle, vol_guess, type=ql.Normal) self.assertAlmostEqual(bpvol, imp_vol, places=4, msg="Normal Implied volatility method is broken") if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_cms.py000066400000000000000000000255051503741206100203750ustar00rootroot00000000000000""" Copyright (C) 2011 Lluis Pujol Bajador This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest class CmsTest(unittest.TestCase): def setUp(self): # global data self.calendar = ql.TARGET() self.referenceDate = self.calendar.adjust(ql.Date.todaysDate()) ql.Settings.instance().evaluationDate = self.referenceDate self.termStructure = ql.RelinkableYieldTermStructureHandle() self.termStructure.linkTo( ql.FlatForward(self.referenceDate, ql.makeQuoteHandle(0.05), ql.Actual365Fixed()) ) self.yieldCurveModels = [] self.numericalPricers = [] self.analyticPricers = [] # ATM Volatility structure self.atmOptionTenors = [ ql.Period(1, ql.Months), ql.Period(6, ql.Months), ql.Period(1, ql.Years), ql.Period(5, ql.Years), ql.Period(10, ql.Years), ql.Period(30, ql.Years), ] self.atmSwapTenors = [ ql.Period(1, ql.Years), ql.Period(5, ql.Years), ql.Period(10, ql.Years), ql.Period(30, ql.Years), ] self.m = [ [0.1300, 0.1560, 0.1390, 0.1220], [0.1440, 0.1580, 0.1460, 0.1260], [0.1600, 0.1590, 0.1470, 0.1290], [0.1640, 0.1470, 0.1370, 0.1220], [0.1400, 0.1300, 0.1250, 0.1100], [0.1130, 0.1090, 0.1070, 0.0930], ] self.atmVol = ql.SwaptionVolatilityStructureHandle( ql.SwaptionVolatilityMatrix( self.calendar, ql.Following, self.atmOptionTenors, self.atmSwapTenors, ql.Matrix(self.m), ql.Actual365Fixed(), ) ) ###Vol cubes self.optionTenors = [ql.Period(1, ql.Years), ql.Period(10, ql.Years), ql.Period(30, ql.Years)] self.swapTenors = [ql.Period(2, ql.Years), ql.Period(10, ql.Years), ql.Period(30, ql.Years)] self.strikeSpreads = [-0.020, -0.005, +0.000, +0.005, +0.020] self.nRows = len(self.optionTenors) * len(self.swapTenors) self.nCols = len(self.strikeSpreads) self.volSpreadsMatrix = [ [0.0599, 0.0049, 0.0000, -0.0001, 0.0127], [0.0729, 0.0086, 0.0000, -0.0024, 0.0098], [0.0738, 0.0102, 0.0000, -0.0039, 0.0065], [0.0465, 0.0063, 0.0000, -0.0032, -0.0010], [0.0558, 0.0084, 0.0000, -0.0050, -0.0057], [0.0576, 0.0083, 0.0000, -0.0043, -0.0014], [0.0437, 0.0059, 0.0000, -0.0030, -0.0006], [0.0533, 0.0078, 0.0000, -0.0045, -0.0046], [0.0545, 0.0079, 0.0000, -0.0042, -0.0020], ] self.volSpreads = [] for i in range(self.nRows): self.volSpreadsRow = [] for j in range(self.nCols): self.volSpreadsRow.append(ql.makeQuoteHandle(self.volSpreadsMatrix[i][j])) self.volSpreads.append(self.volSpreadsRow) self.iborIndex = ql.Euribor6M(self.termStructure) self.swapIndexBase = ql.EuriborSwapIsdaFixA(ql.Period(10, ql.Years), self.termStructure) self.shortSwapIndexBase = ql.EuriborSwapIsdaFixA(ql.Period(2, ql.Years), self.termStructure) self.vegaWeightedSmileFit = False self.SabrVolCube2 = ql.SwaptionVolatilityStructureHandle( ql.InterpolatedSwaptionVolatilityCube( self.atmVol, self.optionTenors, self.swapTenors, self.strikeSpreads, self.volSpreads, self.swapIndexBase, self.shortSwapIndexBase, self.vegaWeightedSmileFit, ) ) self.SabrVolCube2.enableExtrapolation() self.guess = [] self.guessMatrix = [ [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], [0.2, 0.5, 0.4, 0.0], ] for i in range(self.nRows): self.guessRow = [] for j in range(4): self.guessRow.append(ql.makeQuoteHandle(self.guessMatrix[i][j])) self.guess.append(self.guessRow) self.isParameterFixed = [False, True, False, False] ### FIXME self.isAtmCalibrated = False ## self.SabrVolCube1 = ql.SwaptionVolatilityStructureHandle( ql.SabrSwaptionVolatilityCube( self.atmVol, self.optionTenors, self.swapTenors, self.strikeSpreads, self.volSpreads, self.swapIndexBase, self.shortSwapIndexBase, self.vegaWeightedSmileFit, self.guess, self.isParameterFixed, self.isAtmCalibrated, ) ) ##SabrVolCube1.enableExtrapolation() self.yieldCurveModels = [ ql.GFunctionFactory.Standard, ql.GFunctionFactory.ExactYield, ql.GFunctionFactory.ParallelShifts, ql.GFunctionFactory.NonParallelShifts, ] self.zeroMeanRev = ql.makeQuoteHandle(0.0) self.numericalPricers = {} self.analyticPricers = {} for m in self.yieldCurveModels: self.numericalPricers[m] = ql.NumericHaganPricer(self.atmVol, m, self.zeroMeanRev) self.analyticPricers[m] = ql.AnalyticHaganPricer(self.atmVol, m, self.zeroMeanRev) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def testFairRate(self): """Testing Hagan-pricer flat-vol equivalence for coupons...""" swapIndex = ql.SwapIndex( "EuriborSwapIsdaFixA", ql.Period(10, ql.Years), self.iborIndex.fixingDays(), self.iborIndex.currency(), self.iborIndex.fixingCalendar(), ql.Period(1, ql.Years), ql.Unadjusted, self.iborIndex.dayCounter(), self.iborIndex, ) startDate = self.termStructure.referenceDate() + ql.Period(20, ql.Years) paymentDate = startDate + ql.Period(1, ql.Years) endDate = paymentDate nominal = 1.0 infiniteCap = ql.nullDouble() infiniteFloor = ql.nullDouble() gearing = 1.0 spread = 0.0 coupon = ql.CappedFlooredCmsCoupon( paymentDate, nominal, startDate, endDate, swapIndex.fixingDays(), swapIndex, gearing, spread, infiniteCap, infiniteFloor, startDate, endDate, self.iborIndex.dayCounter(), False, ) for m in self.yieldCurveModels: self.numericalPricers[m].setSwaptionVolatility(self.atmVol) coupon.setPricer(self.numericalPricers[m]) rate0 = coupon.rate() self.analyticPricers[m].setSwaptionVolatility(self.atmVol) coupon.setPricer(self.analyticPricers[m]) rate1 = coupon.rate() difference = abs(rate1 - rate0) tol = 2.0e-4 self.assertTrue(difference < tol) def testParity(self): """Testing put-call parity for capped-floored CMS coupons...""" swaptionVols = [self.atmVol, self.SabrVolCube1, self.SabrVolCube2] swapIndex = ql.EuriborSwapIsdaFixA(ql.Period(10, ql.Years), self.iborIndex.forwardingTermStructure()) startDate = self.termStructure.referenceDate() + ql.Period(20, ql.Years) paymentDate = startDate + ql.Period(1, ql.Years) endDate = paymentDate nominal = 1.0 infiniteCap = ql.nullDouble() infiniteFloor = ql.nullDouble() gearing = 1.0 spread = 0.0 discount = self.termStructure.discount(paymentDate) swaplet = ql.CappedFlooredCmsCoupon( paymentDate, nominal, startDate, endDate, swapIndex.fixingDays(), swapIndex, gearing, spread, infiniteCap, infiniteFloor, startDate, endDate, self.iborIndex.dayCounter(), ) strikes = [0.02, 0.07] for k in strikes: caplet = ql.CappedFlooredCmsCoupon( paymentDate, nominal, startDate, endDate, swapIndex.fixingDays(), swapIndex, gearing, spread, k, infiniteFloor, startDate, endDate, self.iborIndex.dayCounter(), ) floorlet = ql.CappedFlooredCmsCoupon( paymentDate, nominal, startDate, endDate, swapIndex.fixingDays(), swapIndex, gearing, spread, infiniteCap, k, startDate, endDate, self.iborIndex.dayCounter(), ) for vol in swaptionVols: for m in self.yieldCurveModels: self.numericalPricers[m].setSwaptionVolatility(vol) self.analyticPricers[m].setSwaptionVolatility(vol) pricers = [self.numericalPricers[m], self.analyticPricers[m]] for p in pricers: swaplet.setPricer(p) caplet.setPricer(p) floorlet.setPricer(p) swapletPrice = swaplet.price(self.termStructure) + swaplet.accrualPeriod() * k * discount capletPrice = caplet.price(self.termStructure) floorletPrice = floorlet.price(self.termStructure) difference = abs(capletPrice + floorletPrice - swapletPrice) tol = 2.0e-5 self.assertTrue(difference < tol) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_coupons.py000066400000000000000000000465511503741206100213050ustar00rootroot00000000000000""" Copyright (C) 2021 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql EPSILON = 1.e-9 CAL = ql.TARGET() VALUATION_DATE = CAL.adjust(ql.Date(15, ql.March, 2021)) RATE_AVERAGING_MAP = {ql.RateAveraging.Compound: 'Compounded', ql.RateAveraging.Simple: 'Simple'} def flat_rate(rate): return ql.FlatForward( 2, CAL, ql.makeQuoteHandle(rate), ql.Actual365Fixed()) def create_ibor_leg(ibor_idx, start, end, payment_lag=0): bdc = ibor_idx.businessDayConvention() sch = ql.MakeSchedule(effectiveDate=start, terminationDate=end, tenor=ibor_idx.tenor(), calendar=CAL, convention=bdc, backwards=True) return ql.IborLeg([1.0], sch, ibor_idx, paymentDayCounter=ibor_idx.dayCounter(), paymentConvention=bdc, paymentCalendar=CAL, paymentLag=payment_lag) def create_overnight_leg(overnight_idx, start, end, payment_lag=0): sch = ql.MakeSchedule(effectiveDate=start, terminationDate=end, tenor=ql.Period(1, ql.Years), calendar=CAL, convention=ql.Following, backwards=True) return ql.OvernightLeg([1.0], sch, overnight_idx, paymentDayCounter=ql.Actual365Fixed(), paymentConvention=ql.Following, paymentCalendar=CAL, paymentLag=payment_lag) def create_fixed_rate_leg(start, end, payment_lag=0): sch = ql.MakeSchedule(effectiveDate=start, terminationDate=end, tenor=ql.Period(1, ql.Years), calendar=CAL, convention=ql.Following, backwards=True) return ql.FixedRateLeg(sch, ql.Actual365Fixed(), [1.0], [0.005], paymentAdjustment=ql.Following, paymentCalendar=CAL, paymentLag=payment_lag) class CashFlowsTest(unittest.TestCase): def setUp(self): self.cash_flows = [ql.SimpleCashFlow(1.e6, ql.Date(22, 6, 2022)), ql.SimpleCashFlow(5.e4, ql.Date(22, 6, 2022))] def test_previous_cash_flow_amount(self): """Testing previous cash flows amount""" reference_date = ql.Date(28, 6, 2022) expected_amount = 1.05e6 include_settlement_date_flows = False actual_amount = ql.CashFlows.previousCashFlowAmount( self.cash_flows, include_settlement_date_flows, reference_date) fail_msg = """ Unable to replicate previous cash flow amount: calculated: {actual} expected: {expected} """.format(actual=actual_amount, expected=expected_amount) self.assertEqual(actual_amount, expected_amount, msg=fail_msg) def test_next_cash_flow_amount(self): """Testing next cash flows amount""" reference_date = ql.Date(21, 6, 2022) expected_amount = 1.05e6 include_settlement_date_flows = False actual_amount = ql.CashFlows.nextCashFlowAmount( self.cash_flows, include_settlement_date_flows, reference_date) fail_msg = """ Unable to replicate next cash flow amount: calculated: {actual} expected: {expected} """.format(actual=actual_amount, expected=expected_amount) self.assertEqual(actual_amount, expected_amount, msg=fail_msg) class IborCouponTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = VALUATION_DATE self.nominal_ts_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) self.ibor_idx = ql.Euribor6M(self.nominal_ts_handle) def test_payment_lag(self): """Testing payment lag of an Ibor leg""" start = ql.Date(17, ql.March, 2021) end = ql.Date(17, ql.March, 2031) pay_lag = 2 leg_without_lag = create_ibor_leg(self.ibor_idx, start, end) leg_with_lag = create_ibor_leg(self.ibor_idx, start, end, pay_lag) for c_f_without_lag, c_f_with_lag in zip(leg_without_lag, leg_with_lag): actual_payment_date = c_f_with_lag.date() expected_payment_date = CAL.advance( c_f_without_lag.date(), pay_lag, ql.Days, self.ibor_idx.businessDayConvention()) fail_msg = """ Unable to replicate Ibor coupon payment date: calculated: {actual} expected: {expected} """.format(actual=actual_payment_date, expected=expected_payment_date) self.assertEqual(actual_payment_date, expected_payment_date, msg=fail_msg) class OvernightCouponTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = VALUATION_DATE self.nominal_ts_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) self.overnight_idx = ql.Eonia(self.nominal_ts_handle) def test_payment_lag(self): """Testing payment lag of an overnight leg""" start = ql.Date(17, ql.March, 2021) end = ql.Date(17, ql.March, 2031) pay_lag = 2 leg_without_lag = create_overnight_leg(self.overnight_idx, start, end) leg_with_lag = create_overnight_leg( self.overnight_idx, start, end, pay_lag) for c_f_without_lag, c_f_with_lag in zip(leg_without_lag, leg_with_lag): actual_payment_date = c_f_with_lag.date() expected_payment_date = CAL.advance( c_f_without_lag.date(), pay_lag, ql.Days, ql.Following) fail_msg = """ Unable to replicate overnight coupon payment date: calculated: {actual} expected: {expected} """.format(actual=actual_payment_date, expected=expected_payment_date) self.assertEqual(actual_payment_date, expected_payment_date, msg=fail_msg) class FixedRateCouponTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = VALUATION_DATE self.nominal_ts_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) def test_payment_lag(self): """Testing payment lag of a fixed rate leg""" start = ql.Date(17, ql.March, 2021) end = ql.Date(17, ql.March, 2031) pay_lag = 2 leg_without_lag = create_fixed_rate_leg(start, end) leg_with_lag = create_fixed_rate_leg(start, end, pay_lag) for c_f_without_lag, c_f_with_lag in zip(leg_without_lag, leg_with_lag): actual_payment_date = c_f_with_lag.date() expected_payment_date = CAL.advance( c_f_without_lag.date(), pay_lag, ql.Days, ql.Following) fail_msg = """ Unable to replicate fixed rate coupon payment date: calculated: {actual} expected: {expected} """.format(actual=actual_payment_date, expected=expected_payment_date) self.assertEqual(actual_payment_date, expected_payment_date, msg=fail_msg) def create_sub_periods_coupon( ibor_idx, start, end, averaging_method=ql.RateAveraging.Compound): payment_calendar = ibor_idx.fixingCalendar() payment_bdc = ibor_idx.businessDayConvention() payment_date = payment_calendar.adjust(end, payment_bdc) fixing_delay = ibor_idx.fixingDays() cpn = ql.SubPeriodsCoupon( payment_date, 1.0, start, end, fixing_delay, ibor_idx) use_compounded_rate = (averaging_method == ql.RateAveraging.Compound) if use_compounded_rate: cpn.setPricer(ql.CompoundingRatePricer()) else: cpn.setPricer(ql.AveragingRatePricer()) return cpn def create_sub_periods_leg( ibor_idx, start, end, cpn_frequency, averaging_method): sch = ql.MakeSchedule(effectiveDate=start, terminationDate=end, tenor=cpn_frequency, calendar=ibor_idx.fixingCalendar(), convention=ibor_idx.businessDayConvention(), backwards=True) return ql.SubPeriodsLeg( [1.0], sch, ibor_idx, averagingMethod=averaging_method) def sum_leg_payments(leg): return sum([cf.amount() for cf in leg]) def compounded_leg_payment(leg): compound = 1.0 for cf in leg: floating_cf = ql.as_floating_rate_coupon(cf) year_fraction = floating_cf.accrualPeriod() fixing = floating_cf.indexFixing() compound *= (1.0 + year_fraction * fixing) return compound - 1.0 def averaged_leg_payment(leg): acc = 0.0 for cf in leg: floating_cf = ql.as_floating_rate_coupon(cf) year_fraction = floating_cf.accrualPeriod() fixing = floating_cf.indexFixing() acc += year_fraction * fixing return acc class SubPeriodsCouponTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = VALUATION_DATE self.nominal_ts_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) self.ibor_idx = ql.Euribor6M(self.nominal_ts_handle) self.ibor_idx.addFixing(ql.Date(10, ql.February, 2021), 0.0085) def check_single_period_coupon_replication(self, start, end, averaging): ibor_leg = create_ibor_leg(self.ibor_idx, start, end) sub_periods_cpn = create_sub_periods_coupon( self.ibor_idx, start, end, averaging) actual_payment = sub_periods_cpn.amount() expected_payment = sum_leg_payments(ibor_leg) fail_msg = """ Unable to replicate single period coupon payment: calculated: {actual} expected: {expected} start: {start} end: {end} """.format(actual=actual_payment, expected=expected_payment, start=start, end=end) self.assertTrue( abs(actual_payment - expected_payment) < EPSILON, msg=fail_msg) def check_multiple_compounded_sub_periods_coupon_replication( self, start, end): ibor_leg = create_ibor_leg(self.ibor_idx, start, end) sub_periods_cpn = create_sub_periods_coupon( self.ibor_idx, start, end, ql.RateAveraging.Compound) actual_payment = sub_periods_cpn.amount() expected_payment = compounded_leg_payment(ibor_leg) fail_msg = """ Unable to replicate compounded multiple sub-period coupon payment: calculated: {actual} expected: {expected} start: {start} end: {end} """.format(actual=actual_payment, expected=expected_payment, start=start, end=end) self.assertTrue( abs(actual_payment - expected_payment) < EPSILON, msg=fail_msg) def check_multiple_averaged_sub_periods_coupon_replication( self, start, end): ibor_leg = create_ibor_leg(self.ibor_idx, start, end) sub_periods_cpn = create_sub_periods_coupon( self.ibor_idx, start, end, ql.RateAveraging.Simple) actual_payment = sub_periods_cpn.amount() expected_payment = averaged_leg_payment(ibor_leg) fail_msg = """ Unable to replicate averaged multiple sub-period coupon payment: calculated: {actual} expected: {expected} start: {start} end: {end} """.format(actual=actual_payment, expected=expected_payment, start=start, end=end) self.assertTrue( abs(actual_payment - expected_payment) < EPSILON, msg=fail_msg) def check_sub_periods_leg_replication(self, averaging_method): start = ql.Date(18, ql.March, 2021) end = ql.Date(18, ql.March, 2022) sub_periods_cpn = create_sub_periods_coupon( self.ibor_idx, start, end, averaging_method) sub_periods_leg = create_sub_periods_leg( self.ibor_idx, start, end, ql.Period(1, ql.Years), averaging_method) actual_payment = sum_leg_payments(sub_periods_leg) expected_payment = sub_periods_cpn.amount() fail_msg = """ Unable to replicate sub-period leg payments: calculated: {actual} expected: {expected} averaging: {averaging} """.format(actual=actual_payment, expected=expected_payment, averaging=RATE_AVERAGING_MAP[averaging_method]) self.assertTrue( abs(actual_payment - expected_payment) < EPSILON, msg=fail_msg) def test_regular_single_period_forward_starting_coupon(self): """Testing regular single period forward starting coupon""" start = ql.Date(15, ql.April, 2021) end = ql.Date(15, ql.October, 2021) self.check_single_period_coupon_replication( start, end, ql.RateAveraging.Simple) self.check_single_period_coupon_replication( start, end, ql.RateAveraging.Compound) def test_regular_single_period_coupon_after_fixing(self): """Testing regular single period coupon after fixing""" start = ql.Date(12, ql.February, 2021) end = ql.Date(12, ql.August, 2021) self.check_single_period_coupon_replication( start, end, ql.RateAveraging.Simple) self.check_single_period_coupon_replication( start, end, ql.RateAveraging.Compound) def test_irregular_single_period_coupon_after_fixing(self): """Testing irregular single period coupon after fixing""" start = ql.Date(12, ql.February, 2021) end = ql.Date(12, ql.June, 2021) self.check_single_period_coupon_replication( start, end, ql.RateAveraging.Simple) self.check_single_period_coupon_replication( start, end, ql.RateAveraging.Compound) def test_regular_compounded_forward_starting_coupon_with_multiple_sub_periods(self): """Testing regular forward starting coupon with multiple compounded sub-periods""" start = ql.Date(15, ql.April, 2021) end = ql.Date(15, ql.April, 2022) self.check_multiple_compounded_sub_periods_coupon_replication( start, end) def test_regular_averaged_forward_starting_coupon_with_multiple_sub_periods(self): """Testing regular forward starting coupon with multiple averaged sub-periods""" start = ql.Date(15, ql.April, 2021) end = ql.Date(15, ql.April, 2022) self.check_multiple_averaged_sub_periods_coupon_replication(start, end) def test_sub_periods_leg_cash_flows(self): """Testing sub-periods leg replication""" self.check_sub_periods_leg_replication(ql.RateAveraging.Compound) self.check_sub_periods_leg_replication(ql.RateAveraging.Simple) def test_casting(self): """Testing casting to sub periods coupon""" start = ql.Date(18, ql.March, 2021) end = ql.Date(18, ql.March, 2022) sub_periods_leg = create_sub_periods_leg( self.ibor_idx, start, end, ql.Period(1, ql.Years), ql.RateAveraging.Compound) cf = sub_periods_leg[0] self.assertTrue(not isinstance(cf, ql.SubPeriodsCoupon)) self.assertTrue(isinstance( ql.as_sub_periods_coupon(cf), ql.SubPeriodsCoupon)) def test_sub_period_coupon_fixing_dates(self): """Testing sub-period coupon fixing dates""" start = ql.Date(15, ql.April, 2021) end = ql.Date(15, ql.April, 2022) cpn = ql.as_sub_periods_coupon( create_sub_periods_coupon(self.ibor_idx, start, end)) actual_dates = cpn.fixingDates() expected_dates = (ql.Date(13, 4, 2021), ql.Date(13, 10, 2021)) fail_msg = """ Unable to replicate sub-period coupon fixing dates: calculated: {actual} expected: {expected} """.format(actual=actual_dates, expected=expected_dates) self.assertTupleEqual(actual_dates, expected_dates, msg=fail_msg) def test_sub_period_coupon_value_dates(self): """Testing sub-period coupon value dates""" start = ql.Date(15, ql.April, 2021) end = ql.Date(15, ql.April, 2022) cpn = ql.as_sub_periods_coupon( create_sub_periods_coupon(self.ibor_idx, start, end)) actual_dates = cpn.valueDates() expected_dates = (ql.Date(15, 4, 2021), ql.Date(15, 10, 2021), ql.Date(19, 4, 2022)) fail_msg = """ Unable to replicate sub-period coupon value dates: calculated: {actual} expected: {expected} """.format(actual=actual_dates, expected=expected_dates) self.assertTupleEqual(actual_dates, expected_dates, msg=fail_msg) def test_sub_period_coupon_rate_spread(self): """Testing sub-period coupon rate spread""" start = ql.Date(15, ql.April, 2021) end = ql.Date(15, ql.April, 2022) cpn = ql.as_sub_periods_coupon( create_sub_periods_coupon(self.ibor_idx, start, end)) actual_spread = cpn.rateSpread() expected_spread = 0.0 fail_msg = """ Unable to replicate sub-period coupon rate spread: calculated: {actual} expected: {expected} """.format(actual=actual_spread, expected=expected_spread) self.assertEqual(actual_spread, expected_spread, msg=fail_msg) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_currencies.py000066400000000000000000000042531503741206100217520ustar00rootroot00000000000000""" Copyright (C) 2021 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql class CurrencyTest(unittest.TestCase): def test_default_currency_constructor(self): """Testing default currency constructor""" fail_msg = "Failed to create default currency." default_ccy = ql.Currency() self.assertTrue(default_ccy.empty(), fail_msg) def test_eur_constructor(self): """Testing EUR constructor""" fail_msg = "Failed to create EUR currency." eur = ql.EURCurrency() self.assertFalse(eur.empty(), fail_msg) def test_bespoke_currency_constructor(self): """Testing bespoke currency constructor""" fail_msg = "Failed to create bespoke currency." custom_ccy = ql.Currency( "CCY", "CCY", 100, "#", "", 100, ql.Rounding()) self.assertFalse(custom_ccy.empty(), fail_msg) def test_hash(self): for ccy1 in (ql.EURCurrency(), ql.USDCurrency(), ql.Currency()): for ccy2 in (ql.EURCurrency(), ql.USDCurrency(), ql.Currency()): if ccy1.empty() or ccy2.empty(): expected = ccy1.empty() == ccy2.empty() else: expected = ccy1.name() == ccy2.name() self.assertEqual(ccy1 == ccy2, expected) self.assertEqual(ccy1 != ccy2, not expected) self.assertEqual(hash(ccy1) == hash(ccy2), expected) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_date.py000066400000000000000000000111621503741206100205220ustar00rootroot00000000000000""" Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import datetime import operator import QuantLib as ql import unittest class DateTest(unittest.TestCase): def testArithmetics(self): "Testing date arithmetics" today = ql.Date.todaysDate() date = today - ql.Period(30, ql.Years) end_date = today + ql.Period(30, ql.Years) dold = date.dayOfMonth() mold = date.month() yold = date.year() while date < end_date: date += 1 d = date.dayOfMonth() m = date.month() y = date.year() # check if skipping any date if not ( (d == dold + 1 and m == mold and y == yold) or (d == 1 and m == mold + 1 and y == yold) or (d == 1 and m == 1 and y == yold + 1) ): self.fail( """ wrong day, month, year increment date: %(t)s day, month, year: %(d)d, %(m)d, %(y)d previous: %(dold)d, %(mold)d, %(yold)d """ % locals() ) dold = d mold = m yold = y def test_hash(self): for date1 in (ql.Date(1, 2, 2020), ql.Date(3, 4, 2022), ql.Date()): for date2 in (ql.Date(1, 2, 2020), ql.Date(3, 4, 2022), ql.Date()): expected = str(date1) == str(date2) self.assertEqual(date1 == date2, expected) self.assertEqual(date1 != date2, not expected) self.assertEqual(hash(date1) == hash(date2), expected) def test_order(self): ops = [operator.eq, operator.ne, operator.lt, operator.le, operator.gt, operator.ge] for date1 in (ql.Date(1, 2, 2020), ql.Date(3, 4, 2022), ql.Date()): for date2 in (ql.Date(1, 2, 2020), ql.Date(3, 4, 2022), ql.Date()): for op in ops: self.assertEqual(op(date1, date2), op(date1.serialNumber(), date2.serialNumber())) def testHolidayList(self): """ Testing Calendar testHolidayList() method. """ holidayLstFunction = ql.Calendar.holidayList(ql.Poland(), ql.Date(31, 12, 2014), ql.Date(3, 4, 2015), False) holidayLstManual = (ql.Date(1, 1, 2015), ql.Date(6, 1, 2015)) # check if dates both from function and from manual input are the same self.assertTrue(all([(a == b) for a, b in zip(holidayLstFunction, holidayLstManual)])) def testConversion(self): for m in range(1, 13): ql_date = ql.Date(m * 2, m, 2020) py_date = datetime.date(2020, m, m * 2) self.assertEqual(ql_date.to_date(), py_date) self.assertEqual(ql.Date.from_date(py_date), ql_date) # datetime works as well py_dt = datetime.datetime(2020, m, m * 2) self.assertEqual(ql.Date.from_date(py_dt), ql_date) with self.assertRaisesRegex(RuntimeError, "from_date requires a date"): ql.Date.from_date("2020-01-02") class PeriodTest(unittest.TestCase): def test_hash(self): for per1 in (ql.Period("1D"), ql.Period("1W"), ql.Period("12M"), ql.Period()): for per2 in (ql.Period("1D"), ql.Period("1Y"), ql.Period()): expected = str(per1.normalized()) == str(per2.normalized()) self.assertEqual(per1 == per2, expected) self.assertEqual(per1 != per2, not expected) self.assertEqual(hash(per1) == hash(per2), expected) def test_order(self): ops = [operator.eq, operator.ne, operator.lt, operator.le, operator.gt, operator.ge] for per1 in (ql.Period("1D"), ql.Period("1W"), ql.Period("12M")): for per2 in (ql.Period("1D"), ql.Period("1Y")): for op in ops: self.assertEqual(op(per1, per2), op(per2.frequency(), per1.frequency())) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_daycounters.py000066400000000000000000000022341503741206100221450ustar00rootroot00000000000000import QuantLib as ql import unittest class DayCountersTest(unittest.TestCase): def test_bus252(self): """Test Business252 daycounter""" calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) # # Check that SWIG signature for Business252 calendar allows to # pass custom calendar into the class constructor. Old # QuantLib-SWIG versions allow only to create Business252 # calendar with default constructor parameter (Brazil # calendar), and generate an exception when trying to pass a # custom calendar as a parameter. So we just check here that # no exception occurs. # ql.Business252(calendar) def test_hash(self): for dc1 in (ql.Actual360(), ql.Thirty365()): for dc2 in (ql.Actual360(), ql.Thirty365()): expected = dc1.name() == dc2.name() self.assertEqual(dc1 == dc2, expected) self.assertEqual(dc1 != dc2, not expected) self.assertEqual(hash(dc1) == hash(dc2), expected) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_equityindex.py000066400000000000000000000045041503741206100221570ustar00rootroot00000000000000""" Copyright (C) 2023 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest EPSILON = 1.e-2 CAL = ql.TARGET() DCT = ql.Actual365Fixed() VALUATION_DATE = CAL.adjust(ql.Date(31, ql.January, 2023)) def flat_rate(rate): return ql.FlatForward( 2, CAL, ql.makeQuoteHandle(rate), DCT) class EquityIndexTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = VALUATION_DATE self.interest_handle = ql.YieldTermStructureHandle(flat_rate(0.03)) self.dividend_handle = ql.YieldTermStructureHandle(flat_rate(0.01)) spot_handle = ql.makeQuoteHandle(8690.0) ql.IndexManager.instance().clearHistory("eq_idx") self.equity_idx = ql.EquityIndex( "eq_idx", CAL, self.interest_handle, self.dividend_handle, spot_handle) def test_equity_index_inspectors(self): """Testing equity index inspectors""" fail_msg = "Unable to replicate the properties of an equity index." self.assertEqual(self.equity_idx.name(), "eq_idx", msg=fail_msg) self.assertEqual(self.equity_idx.fixingCalendar(), CAL, msg=fail_msg) def test_equity_index_projections(self): """Testing equity index projections""" fail_msg = "Failed to calculate the expected index projection." self.assertAlmostEqual( self.equity_idx.fixing(VALUATION_DATE), 8690.0, delta=EPSILON, msg=fail_msg) future_dt = ql.Date(20, ql.May, 2030) self.assertAlmostEqual( self.equity_idx.fixing(future_dt), 10055.76, delta=EPSILON, msg=fail_msg) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_extrapolation.py000066400000000000000000000031031503741206100224720ustar00rootroot00000000000000""" Copyright (C) 2019 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import math import unittest import QuantLib as ql class ExtrapolationTest(unittest.TestCase): def testKnownExpExtrapolation(self): """Testing Richardson extrapolation of e^x at x->1 with known order of convergence""" f = lambda x: math.exp(1+x) x = ql.RichardsonExtrapolation(f, 0.01, 1.0)(4.0) self.assertAlmostEqual(x, math.exp(1), 4, msg="Unable to extrapolate exp(x) at x->1") def testUnknownExpExtrapolation(self): """Testing Richardson extrapolation of e^x at x->1 with unknown order of convergence""" f = lambda x: math.exp(1+x) x = ql.RichardsonExtrapolation(f, 0.01)(4.0, 2.0) self.assertAlmostEqual(x, math.exp(1), 4, msg="Unable to extrapolate exp(x) at x->1") if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_fdm.py000066400000000000000000000450601503741206100203570ustar00rootroot00000000000000""" Copyright (C) 2020 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import math import unittest import QuantLib as ql class FdmTest(unittest.TestCase): def setUp(self): self.todaysDate = ql.Date(15, ql.May, 2019) ql.Settings.instance().evaluationDate = self.todaysDate def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def test1dMesher(self): """Testing one dimensional mesher""" m = ql.Concentrating1dMesher(0, 1, 10) self.assertEqual(m.size(), 10) for i in range(0,10): self.assertAlmostEqual(m.location(i), i/9.0, 14) m = ql.Concentrating1dMesher(0, 1, 10, [ql.Concentrating1dMesherPoint(0.75, 0.01,False), ql.Concentrating1dMesherPoint(0.5, 0.01, True)]) self.assertEqual(m.size(), 10) self.assertAlmostEqual(m.location(0), 0.0, 14) self.assertAlmostEqual(m.location(9), 1.0, 14) p = [x for x in m.locations() if ql.close_enough(x, 0.5)] self.assertEqual(len(p), 1) p = [x for x in m.locations() if ql.close_enough(x, 0.75)] self.assertEqual(len(p), 0) m = ql.Predefined1dMesher([0,2,4]) self.assertEqual(m.size(), 3) self.assertEqual(m.location(0), 0) self.assertEqual(m.location(1), 2) self.assertEqual(m.location(2), 4) def testFdmLinearOpIterator(self): """Testing iterators for linear operators""" dim = [2,2,3] pos = [0,0,0] idx = 0 opIter = ql.FdmLinearOpIterator(dim, pos, idx) self.assertEqual(opIter.index(), 0) opIter.increment() self.assertEqual(opIter.index(), 1) self.assertEqual(opIter.coordinates(), (1, 0, 0)) opIter.increment() self.assertEqual(opIter.coordinates(), (0, 1, 0)) opIter2 = ql.FdmLinearOpIterator(dim, pos, idx) self.assertEqual(opIter.notEqual(opIter2), True) self.assertEqual(opIter.notEqual(opIter), False) def testFdmLinearOpLayout(self): """Testing memory layout for linear operators""" dim = [2,2,3] m = ql.FdmLinearOpLayout(dim) self.assertEqual(m.size(), 2*2*3) self.assertEqual(m.dim(), (2, 2, 3)) self.assertEqual(m.spacing(), (1, 2, 4)) self.assertEqual(m.index((0,1,2)), 10) self.assertEqual(m.neighbourhood(m.begin(), 0, 1), 1) self.assertEqual(m.neighbourhood(m.begin(), 2, 2), 8) self.assertEqual(m.neighbourhood(m.begin(), 0, 1, 2, 2), 9) n = m.iter_neighbourhood(m.begin(), 0, 1) opIter = m.begin() opIter.increment() self.assertEqual(opIter.notEqual(n), False) def testFdmMesherComposite(self): """Testing mesher composites""" m1 = ql.Concentrating1dMesher(0, 1, 2) m2 = ql.Uniform1dMesher(0, 2, 3) m = ql.FdmMesherComposite(m1, m2) self.assertEqual(len(m.getFdm1dMeshers()), 2) locations = m.locations(0) self.assertEqual(len(locations), 6) self.assertEqual(list(map(round, locations)), [0, 1, 0, 1, 0, 1]) locations = m.locations(1) self.assertEqual(list(map(round, locations)), [0, 0, 1, 1, 2, 2]) def testFdmLinearOpComposite(self): """Testing linear operator composites""" class Foo: t1 = 0.0 t2 = 0.0 @classmethod def size(self): return 42 def setTime(self, t1, t2): self.t1 = t1 self.t2 = t2 @classmethod def apply(self, r): return 2*r @classmethod def apply_mixed(self, r): return 3*r @classmethod def apply_direction(self, direction , r): return direction*r @classmethod def solve_splitting(self, direction , r, s): return direction*s*r @classmethod def preconditioner(self, r, s): return s*r foo = Foo() c = ql.FdmLinearOpCompositeProxy(foo) self.assertEqual(c.size(), foo.size()) c.setTime(1.0, 2.0) self.assertAlmostEqual(foo.t1, 1.0, 14) self.assertAlmostEqual(foo.t2, 2.0, 14) r = ql.Array([1,2,3,4]) self.assertEqual(c.apply(r), 2*r) self.assertEqual(c.apply_mixed(r), 3*r) self.assertEqual(c.apply_direction(7, r), 7*r) s = c.solve_splitting(7, r, 0.5) self.assertEqual(len(s), len(r)) for i, x in enumerate(s): self.assertAlmostEqual(x, 3.5*r[i], 14) self.assertEqual(c.preconditioner(r, 4), 4*r) class Bar: @classmethod def apply(self, r): return 1 def apply_mixed(self, r): pass with self.assertRaises(RuntimeError): ql.FdmLinearOpCompositeProxy(Bar()).apply(r) with self.assertRaises(RuntimeError): ql.FdmLinearOpCompositeProxy(Bar()).apply_mixed(r) def testFdmBlackScholesOp(self): """Testing linear Black-Scholes operator""" todaysDate = ql.Date(1, ql.January, 2020) ql.Settings.instance().evaluationDate = todaysDate dc = ql.Actual365Fixed() settlementDate = todaysDate + 2 riskFreeRate = ql.FlatForward(settlementDate, 0.05, dc) exercise = ql.EuropeanExercise(ql.Date(27, ql.December, 2020)) maturity = dc.yearFraction(todaysDate, exercise.lastDate()) strike = 110.0 payoff = ql.PlainVanillaPayoff(ql.Option.Call, strike) underlying = ql.SimpleQuote(100.0) volatility = ql.BlackConstantVol(settlementDate, ql.TARGET(), 0.10, dc) dividendYield = ql.FlatForward(settlementDate, 0.05, dc) process = ql.BlackScholesMertonProcess( ql.QuoteHandle(underlying), ql.YieldTermStructureHandle(dividendYield), ql.YieldTermStructureHandle(riskFreeRate), ql.BlackVolTermStructureHandle(volatility) ) mesher = ql.FdmMesherComposite( ql.FdmBlackScholesMesher(10, process, maturity, strike)) op = ql.FdmBlackScholesOp(mesher, process, strike) self.assertEqual(op.size(), 1) op.setTime(0, 0.1) c = [payoff(math.exp(x)) for x in mesher.locations(0)] p = op.apply(c) e = [ 0.0, 0.0, 0.0, 0.0, 0.0, 3.18353, 0.755402, -1.30583, -2.19881, -4.0271 ] for i, x in enumerate(e): self.assertAlmostEqual(x, p[i], 5) def testFdmFirstOrderOperator(self): """Testing first order operator""" mesher = ql.Uniform1dMesher(0.0, math.pi, 1000) op = ql.FirstDerivativeOp(0, ql.FdmMesherComposite(mesher)) l = mesher.locations() x = list(map(math.sin, l)) y = op.apply(x) for u, v in zip(l, y): self.assertAlmostEqual(v, math.cos(u), 4) def testFdmSecondOrderOperator(self): """Testing second order operator""" mesher = ql.Uniform1dMesher(0.0, math.pi, 1000) op = ql.SecondDerivativeOp(0, ql.FdmMesherComposite(mesher)) x = list(map(math.sin, mesher.locations())) y = op.apply(x) for u, v in zip(x, y): self.assertAlmostEqual(v, -u, 4) def testFdmBoundaryCondition(self): """Testing Dirichlet Boundary conditions""" m = ql.FdmMesherComposite( ql.Uniform1dMesher(0.0, 1.0, 5)) b = ql.FdmDirichletBoundary( m, math.pi, 0, ql.FdmBoundaryCondition.Upper) x = ql.Array(len(m.locations(0)), 0.0) b.applyAfterApplying(x) self.assertEqual(list(x), [0,0,0,0, math.pi]) s = ql.FdmBoundaryConditionSet() s.push_back(b) self.assertEqual(len(s), 1) def testFdmStepConditionCallBack(self): """Testing step condition call back function""" class Foo: @classmethod def applyTo(self, a, t): for i in range(5): a[i] = t+1.0 m = ql.FdmStepConditionProxy(Foo()) x = ql.Array(5) m.applyTo(x, 2.0) self.assertEqual(len(x), 5) self.assertEqual(list(x), [3.0, 3.0, 3.0, 3.0, 3.0]) def testFdmInnerValueCalculatorCallBack(self): """Testing inner value call back function""" class Foo: @classmethod def innerValue(self, opIter, t): return opIter.index() + t @classmethod def avgInnerValue(self, opIter, t): return opIter.index() + 2*t m = ql.FdmInnerValueCalculatorProxy(Foo()) dim = [2,2,3] pos = [0,0,0] opIter = ql.FdmLinearOpIterator(dim, pos, 0) while (opIter.index() < 2*2*3): idx = opIter.index() self.assertEqual(m.innerValue(opIter, 2.0), idx + 2.0) self.assertEqual(m.avgInnerValue(opIter, 2.0), idx + 4.0) opIter.increment() def testFdmLogInnerValueCalculator(self): """Testing log inner value calculator""" m = ql.FdmMesherComposite( ql.Uniform1dMesher(math.log(50), math.log(150), 11)) p = ql.PlainVanillaPayoff(ql.Option.Call, 100) v = ql.FdmLogInnerValue(p, m, 0) opIter = m.layout().begin() while opIter.notEqual(m.layout().end()): x = math.exp(m.location(opIter, 0)); self.assertAlmostEqual(p(x), v.innerValue(opIter, 1.0), 14) opIter.increment() def testAmericanOptionPricing(self): """Testing Black-Scholes and Heston American Option pricing""" xSteps = 100 tSteps = 25 dampingSteps = 0 todaysDate = ql.Date(15, ql.January, 2020) ql.Settings.instance().evaluationDate = todaysDate dc = ql.Actual365Fixed() riskFreeRate = ql.YieldTermStructureHandle( ql.FlatForward(todaysDate, 0.06, dc)) dividendYield = ql.YieldTermStructureHandle( ql.FlatForward(todaysDate, 0.02, dc)) strike = 110.0 payoff = ql.PlainVanillaPayoff(ql.Option.Put, strike) maturityDate = todaysDate + ql.Period(1, ql.Years) maturity = dc.yearFraction(todaysDate, maturityDate) exercise = ql.AmericanExercise(todaysDate, maturityDate) spot = ql.makeQuoteHandle(100.0) volatility = ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.20, dc) process = ql.BlackScholesMertonProcess( spot, dividendYield, riskFreeRate, ql.BlackVolTermStructureHandle(volatility) ) option = ql.VanillaOption(payoff, exercise) option.setPricingEngine(ql.FdBlackScholesVanillaEngine.make( process, xGrid = xSteps, tGrid = tSteps, dampingSteps = dampingSteps) ) expected = option.NPV() equityMesher = ql.FdmBlackScholesMesher( xSteps, process, maturity, strike, cPoint = (strike, 0.1) ) mesher = ql.FdmMesherComposite(equityMesher) op = ql.FdmBlackScholesOp(mesher, process, strike) innerValueCalculator = ql.FdmLogInnerValue(payoff, mesher, 0) x = [] rhs = [] layout = mesher.layout() opIter = layout.begin() while (opIter.notEqual(layout.end())): x.append(mesher.location(opIter, 0)) rhs.append(innerValueCalculator.avgInnerValue(opIter, maturity)) opIter.increment() rhs = ql.Array(rhs) bcSet = ql.FdmBoundaryConditionSet() stepCondition = ql.FdmStepConditionComposite.vanillaComposite( ql.DividendSchedule(), exercise, mesher, innerValueCalculator, todaysDate, dc ) # only to test an Operator defined in python class OperatorProxy: def __init__(self, op): self.op = op def size(self): return self.op.size() def setTime(self, t1, t2): return self.op.setTime(t1, t2) def apply(self, r): return self.op.apply(r) def apply_direction(self, i, r): return self.op.apply_direction(i, r) def solve_splitting(self, i, r, s): return self.op.solve_splitting(i, r, s) proxyOp = ql.FdmLinearOpCompositeProxy(OperatorProxy(op)) solver = ql.FdmBackwardSolver( proxyOp, bcSet, stepCondition, ql.FdmSchemeDesc.Douglas() ) solver.rollback(rhs, maturity, 0.0, tSteps, dampingSteps) spline = ql.CubicNaturalSpline(x, rhs); logS = math.log(spot.value()) calculated = spline(logS) self.assertAlmostEqual(calculated, expected, 1) solverDesc = ql.FdmSolverDesc( mesher, bcSet, stepCondition, innerValueCalculator, maturity, tSteps, dampingSteps) calculated = ql.Fdm1DimSolver( solverDesc, ql.FdmSchemeDesc.Douglas(), op).interpolateAt(logS) self.assertAlmostEqual(calculated, expected, 2) v0 = 0.4*0.4 kappa = 1.0 theta = v0 sigma = 1e-4 rho = 0.0 hestonProcess = ql.HestonProcess( riskFreeRate, dividendYield, spot, v0, kappa, theta, sigma, rho) leverageFct = ql.LocalVolSurface( ql.BlackVolTermStructureHandle( ql.BlackConstantVol(todaysDate, ql.TARGET(), 0.50, dc)), riskFreeRate, dividendYield, spot.value() ) vSteps = 3 vMesher = ql.FdmHestonLocalVolatilityVarianceMesher( vSteps, hestonProcess, leverageFct, maturity) avgVolaEstimate = vMesher.volaEstimate() self.assertAlmostEqual(avgVolaEstimate, 0.2, 5) mesher = ql.FdmMesherComposite(equityMesher, vMesher) innerValueCalculator = ql.FdmLogInnerValue(payoff, mesher, 0) stepCondition = ql.FdmStepConditionComposite.vanillaComposite( ql.DividendSchedule(), exercise, mesher, innerValueCalculator, todaysDate, dc ) solverDesc = ql.FdmSolverDesc( mesher, bcSet, stepCondition, innerValueCalculator, maturity, tSteps, dampingSteps) calculated = ql.FdmHestonSolver( hestonProcess, solverDesc, leverageFct = leverageFct).valueAt( spot.value(), 0.16) self.assertAlmostEqual(calculated, expected, 1) def testBSMRNDCalculator(self): """Testing Black-Scholes risk neutral density calculator""" dc = ql.Actual365Fixed() todaysDate = ql.Date(15, ql.January, 2020) r = 0.0 q = 0.0 vol = 0.2 s0 = 100 process = ql.BlackScholesMertonProcess( ql.makeQuoteHandle(s0), ql.YieldTermStructureHandle( ql.FlatForward(todaysDate, q, dc)), ql.YieldTermStructureHandle( ql.FlatForward(todaysDate, r, dc)), ql.BlackVolTermStructureHandle( ql.BlackConstantVol(todaysDate, ql.TARGET(), vol, dc)) ) rnd = ql.BSMRNDCalculator(process) t = 1.2 x = math.log(80.0) mu = math.log(s0) + (r-q-0.5*vol*vol)*t calculated = rnd.pdf(x, t) stdev = vol * math.sqrt(t) expected = (1.0/(math.sqrt(2*math.pi)*stdev) * math.exp( -0.5*math.pow((x-mu)/stdev, 2.0) )) self.assertAlmostEqual(calculated, expected, 8) def testOrnsteinUhlenbeckVsBachelier(self): """Testing Fdm Ornstein-Uhlenbeck pricing""" todaysDate = ql.Date(15, ql.January, 2020) ql.Settings.instance().evaluationDate = todaysDate dc = ql.Actual365Fixed() rTS = ql.FlatForward(todaysDate, 0.06, dc) strike = 110.0 payoff = ql.PlainVanillaPayoff(ql.Option.Put, strike) maturityDate = todaysDate + ql.Period(2, ql.Years) exercise = ql.EuropeanExercise(maturityDate) option = ql.VanillaOption(payoff, exercise) x0 = 100 sigma = 20.0 speed = 5 pdeEngine = ql.FdOrnsteinUhlenbeckVanillaEngine( ql.OrnsteinUhlenbeckProcess(speed, sigma, x0, x0), rTS, 50 ) option.setPricingEngine(pdeEngine) calculated = option.NPV() stdev = math.sqrt(sigma*sigma/(2*speed)) expected = ql.bachelierBlackFormula( ql.Option.Put, strike, x0, stdev, rTS.discount(maturityDate) ) self.assertAlmostEqual(calculated, expected, 2) def testSparseLinearMatrixSolver(self): """Testing sparse linear matrix solver""" A = ql.Matrix([ [1.0, 0.0, 1.0], [0.0, 1.0, 0.5], [1.0, 0.5, 1.0] ]) b = ql.Array([ 1.0, 0.2, 0.5 ]) expected = ql.inverse(A)*b def foo(x): return A*x calculated = ql.BiCGstab( ql.MatrixMultiplicationProxy(foo), 100, 1e-6).solve(b) for i in range(3): self.assertAlmostEqual(expected[i], calculated[i], 4) calculated = ql.GMRES( ql.MatrixMultiplicationProxy(foo), 100, 1e-6).solve(b) for i in range(3): self.assertAlmostEqual(expected[i], calculated[i], 4) def preconditioner(x): return ql.inverse(A)*x calculated = ql.BiCGstab( ql.MatrixMultiplicationProxy(foo), 100, 1e-6, ql.MatrixMultiplicationProxy(preconditioner)).solve(b) for i in range(3): self.assertAlmostEqual(expected[i], calculated[i], 4) def testGlued1dMesher(self): """Testing sparse linear matrix solver""" m1 = ql.Uniform1dMesher(0, 2, 3) m2 = ql.Uniform1dMesher(2, 4, 3) m3 = ql.Glued1dMesher(m1, m2) self.assertEqual(m3.locations(), (0,1,2,3,4)) def testFdmZeroInnerValue(self): """Testing FdmZeroInnerValue""" opIter = ql.FdmLinearOpIterator([1], [0], 0) self.assertEqual(ql.FdmZeroInnerValue().innerValue(opIter, 1.0), 0.0) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_iborindex.py000066400000000000000000000060211503741206100215660ustar00rootroot00000000000000# coding=utf-8-unix """ Copyright (C) 2018 Wojciech Åšlusarski This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest class IborIndexTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.euribor3m = ql.Euribor3M() def setUp(self): self.euribor3m.clearFixings() # values are not real due to copyrights of the fixing self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.3) self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.3, -0.3]) def testAddFixingFail(self): """Testing for RuntimeError while trying to overwrite fixing value""" with self.assertRaises(RuntimeError): # attempt to overwrite value that is already set at different level self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.4) with self.assertRaises(RuntimeError): # attempt to overwrite value that is already set at different level self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.4, -0.4]) def testAddFixing(self): """Testing for overwriting fixing value""" force_overwrite = True try: # attempt to overwrite value that is already set at different level self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.4, force_overwrite) self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.4, -0.4], force_overwrite) # try clearFixings and repeat with original levels self.euribor3m.clearFixings() self.euribor3m.addFixing(ql.Date(17, 7, 2018), -0.3) self.euribor3m.addFixings([ql.Date(12, 7, 2018), ql.Date(13, 7, 2018)], [-0.3, -0.3]) except RuntimeError as err: raise AssertionError("Failed to overwrite index fixixng " + "{}".format(err)) def testTimeSeries(self): """Testing for getting time series of the fixing""" dates = (ql.Date(12, 7, 2018), ql.Date(13, 7, 2018), ql.Date(17, 7, 2018)) values = (-0.3, -0.3, -0.3) for expected, actual in zip(dates, self.euribor3m.timeSeries().dates()): self.assertTrue(expected == actual) for expected, actual in zip(values, self.euribor3m.timeSeries().values()): self.assertTrue(expected == actual) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_inflation.py000066400000000000000000000277271503741206100216060ustar00rootroot00000000000000""" Copyright (C) 2020 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql EPSILON = 1.e-9 # Hypothetical market data EUR_ZERO_RATES = [(ql.Period(1, ql.Days), 0.0048), (ql.Period(1, ql.Years), 0.0048), (ql.Period(2, ql.Years), 0.00475), (ql.Period(3, ql.Years), 0.005), (ql.Period(5, ql.Years), 0.0055), (ql.Period(10, ql.Years), 0.007)] EUR_BEI_SWAP_RATES = [(ql.Period(1, ql.Years), 0.0301), (ql.Period(2, ql.Years), 0.0299), (ql.Period(3, ql.Years), 0.0305), (ql.Period(5, ql.Years), 0.0315), (ql.Period(10, ql.Years), 0.0355)] # Source: # https://ec.europa.eu/eurostat/web/products-datasets/-/teicp240. EU_FIXING_DATA = [(ql.Date(1, ql.April, 2018), 103.11), (ql.Date(1, ql.May, 2018), 103.64), (ql.Date(1, ql.June, 2018), 103.76), (ql.Date(1, ql.July, 2018), 103.41), (ql.Date(1, ql.August, 2018), 103.58)] CAL = ql.TARGET() DAY_COUNTER = ql.ActualActual(ql.ActualActual.ISDA) BDC = ql.ModifiedFollowing VALUATION_DATE = CAL.adjust(ql.Date(10, ql.September, 2018)) OBSERVATION_LAG = ql.Period(3, ql.Months) def create_inflation_swap_helper( reference_date, inflation_data, inflation_index, interpolation, discount_curve_handle, observation_lag=OBSERVATION_LAG, calendar=CAL, business_day_convention=BDC, day_counter=DAY_COUNTER): maturity = CAL.advance(reference_date, inflation_data[0]) quote = ql.makeQuoteHandle(inflation_data[1]) return ql.ZeroCouponInflationSwapHelper( quote, observation_lag, maturity, calendar, business_day_convention, day_counter, inflation_index, interpolation, discount_curve_handle) def build_nominal_term_structure( reference_date, nominal_data): nominal_dc = ql.Actual365Fixed() dates = [CAL.advance(reference_date, x[0]) for x in nominal_data] rates = [x[1] for x in nominal_data] return ql.ZeroCurve(dates, rates, nominal_dc) def build_hicp_index( fixing_data, inflation_crv_handle): index = ql.EUHICP(inflation_crv_handle) for x in fixing_data: # force override in case of multiple use index.addFixing(x[0], x[1], True) return index SEASONAL = {ql.January: 1.0, ql.February: 1.01, ql.March: 1.011, ql.April: 1.009, ql.May: 1.008, ql.June: 1.012, ql.July: 1.0078, ql.August: 1.006, ql.September: 1.0085, ql.October: 1.0096, ql.November: 1.0067, ql.December: 1.0055} def construct_seasonality(reference_date): frequency = ql.Monthly seasonality_base_date = ql.Date(1, ql.January, reference_date.year()) factors = list(SEASONAL.values()) return ql.MultiplicativePriceSeasonality( seasonality_base_date, frequency, factors) def build_inflation_term_structure( reference_date, zero_coupon_swaps_data, inflation_index, interpolation, nominal_term_structure_handle, observation_lag=OBSERVATION_LAG, include_seasonality=False): helpers = [create_inflation_swap_helper(reference_date, x, inflation_index, interpolation, nominal_term_structure_handle) for x in zero_coupon_swaps_data] base_zero_rate = zero_coupon_swaps_data[0][1] cpi_term_structure = ql.PiecewiseZeroInflation( reference_date, inflation_index.lastFixingDate(), inflation_index.frequency(), DAY_COUNTER, helpers) if include_seasonality: seasonality = construct_seasonality(reference_date) cpi_term_structure.setSeasonality(seasonality) return cpi_term_structure def create_inflation_swap( inflation_idx, start_date, end_date, rate, interpolation, observation_lag=OBSERVATION_LAG, nominal=1.e6, payer=ql.Swap.Payer): return ql.ZeroCouponInflationSwap( payer, nominal, start_date, end_date, CAL, BDC, DAY_COUNTER, rate, inflation_idx, observation_lag, interpolation) def interpolate_historic_index( inflation_idx, fixing_date, observation_lag=OBSERVATION_LAG): first_dt = ql.Date(1, fixing_date.month(), fixing_date.year()) second_dt = ql.Date.endOfMonth(fixing_date) + 1 slope_numerator = fixing_date - first_dt slope_denominator = ( (second_dt + observation_lag) - (first_dt + observation_lag)) slope = float(slope_numerator) / float(slope_denominator) return inflation_idx.fixing(first_dt) + slope * ( inflation_idx.fixing(second_dt) - inflation_idx.fixing(first_dt)) class InflationTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = VALUATION_DATE self.inflation_ts_handle = ql.RelinkableZeroInflationTermStructureHandle() self.nominal_ts_handle = ql.RelinkableYieldTermStructureHandle() self.nominal_ts_handle.linkTo( build_nominal_term_structure(VALUATION_DATE, EUR_ZERO_RATES)) self.discount_engine = ql.DiscountingSwapEngine(self.nominal_ts_handle) def test_par_swap_pricing_fom_indexation_without_seasonality(self): """Testing pricing of par inflation swap for First-Of-Month indexation""" inflation_idx = build_hicp_index( EU_FIXING_DATA, self.inflation_ts_handle) inflation_ts = build_inflation_term_structure( VALUATION_DATE, EUR_BEI_SWAP_RATES, inflation_idx, ql.CPI.Flat, self.nominal_ts_handle) self.inflation_ts_handle.linkTo(inflation_ts) zciis = create_inflation_swap( inflation_idx, VALUATION_DATE, CAL.advance(VALUATION_DATE, ql.Period(10, ql.Years)), 0.0355, ql.CPI.Flat) zciis.setPricingEngine(self.discount_engine) npv = zciis.NPV() # Check whether swap prices to par fail_msg = """ Failed to price zero coupon inflation swap to par: index: {inflation_idx} end date: {end_date} observation lag: {observation_lag} npv: {npv} expected npv: {expected_npv} tolerance: {tolerance} """.format(inflation_idx=inflation_idx.familyName(), end_date=zciis.maturityDate(), observation_lag=OBSERVATION_LAG, npv=npv, expected_npv=0.0, tolerance=EPSILON) self.assertTrue( abs(npv) < EPSILON, msg=fail_msg) def test_inflation_leg_payment_fom_indexation_without_seasonality(self): """Testing inflation leg payment for First-Of-Month indexation""" inflation_idx = build_hicp_index( EU_FIXING_DATA, self.inflation_ts_handle) inflation_ts = build_inflation_term_structure( VALUATION_DATE, EUR_BEI_SWAP_RATES, inflation_idx, ql.CPI.Flat, self.nominal_ts_handle) self.inflation_ts_handle.linkTo(inflation_ts) zciis = create_inflation_swap( inflation_idx, VALUATION_DATE, CAL.advance(VALUATION_DATE, ql.Period(10, ql.Years)), 0.0355, ql.CPI.Flat) zciis.setPricingEngine(self.discount_engine) inflation_cf = ql.as_indexed_cashflow( zciis.inflationLeg()[0]) # Obtaining base index for the inflation swap swap_base_dt = inflation_cf.baseDate() swap_base_fixing = inflation_idx.fixing(swap_base_dt) # Replicate fixing projection fixing_dt = inflation_cf.fixingDate() ts_base_dt = inflation_ts.baseDate() ts_base_fixing = inflation_idx.fixing(ts_base_dt) # Apply FOM indexation rule effective_fixing_dt = ql.Date( 1, fixing_dt.month(), fixing_dt.year()) fraction = inflation_ts.dayCounter().yearFraction( ts_base_dt, effective_fixing_dt) t = inflation_ts.timeFromReference(effective_fixing_dt) zero_rate = inflation_ts.zeroRate(t) expected_fixing = ts_base_fixing * ( 1.0 + zero_rate)**fraction expected_inflation_leg_payment = ( expected_fixing / swap_base_fixing - 1.0) * inflation_cf.notional() actual_inflation_leg_payment = inflation_cf.amount() fail_msg = """ Failed to replicate inflation leg payment for First-Of-Month indexation: index: {inflation_idx} end date: {end_date} observation lag: {observation_lag} inflation leg payment: {actual_payment} replicated payment: {expected_payment} tolerance: {tolerance} """.format(inflation_idx=inflation_idx.familyName(), end_date=zciis.maturityDate(), observation_lag=OBSERVATION_LAG, actual_payment=actual_inflation_leg_payment, expected_payment=expected_inflation_leg_payment, tolerance=EPSILON) self.assertAlmostEqual( first=actual_inflation_leg_payment, second=expected_inflation_leg_payment, delta=EPSILON, msg=fail_msg) def test_lagged_fixing_method(self): """Testing lagged fixing method""" inflation_idx = build_hicp_index( EU_FIXING_DATA, self.inflation_ts_handle) inflation_ts = build_inflation_term_structure( VALUATION_DATE, EUR_BEI_SWAP_RATES, inflation_idx, ql.CPI.Flat, self.nominal_ts_handle) self.inflation_ts_handle.linkTo(inflation_ts) maturity_date = ql.Date(25, ql.October, 2027) lag = ql.Period(3, ql.Months) indexation = ql.CPI.Flat actual_fixing = ql.CPI.laggedFixing(inflation_idx, maturity_date, lag, indexation) expected_fixing = inflation_idx.fixing(ql.Date(1, ql.July, 2027)) fail_msg = """ Failed to replicate lagged fixing: index: {inflation_idx} actual fixing: {actual_fixing} expected fixing: {expected_fixing} tolerance: {tolerance} """.format(inflation_idx=inflation_idx.familyName(), actual_fixing=actual_fixing, expected_fixing=expected_fixing, tolerance=EPSILON) self.assertAlmostEqual( first=actual_fixing, second=expected_fixing, msg=fail_msg, delta=EPSILON) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_instruments.py000066400000000000000000000035231503741206100222020ustar00rootroot00000000000000""" Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest flag = None def raiseFlag(): global flag flag = 1 class InstrumentTest(unittest.TestCase): def testObservable(self): "Testing observability of stocks" global flag flag = None me1 = ql.SimpleQuote(0.0) h = ql.RelinkableQuoteHandle(me1) s = ql.Stock(h) s.NPV() obs = ql.Observer(raiseFlag) obs.registerWith(s) me1.setValue(3.14) if not flag: self.fail("Observer was not notified of instrument change") s.NPV() flag = None me2 = ql.SimpleQuote(0.0) h.linkTo(me2) if not flag: self.fail("Observer was not notified of instrument change") s.NPV() flag = None s.freeze() me2.setValue(2.71) if flag: self.fail("Observer was notified of frozen instrument change") s.unfreeze() if not flag: self.fail("Observer was not notified of instrument change") if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_integrals.py000066400000000000000000000044161503741206100216010ustar00rootroot00000000000000""" Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest import math class IntegralTest(unittest.TestCase): def Gauss(self, x): return math.exp(-x * x / 2.0) / math.sqrt(2 * math.pi) def singleTest(self, I): tolerance = 1e-4 cases = [ ["f(x) = 1", lambda x: 1, 0.0, 1.0, 1.0], ["f(x) = x", lambda x: x, 0.0, 1.0, 0.5], ["f(x) = x^2", lambda x: x * x, 0.0, 1.0, 1.0 / 3.0], ["f(x) = sin(x)", math.sin, 0.0, math.pi, 2.0], ["f(x) = cos(x)", math.cos, 0.0, math.pi, 0.0], ["f(x) = Gauss(x)", self.Gauss, -10.0, 10.0, 1.0], ] for tag, f, a, b, expected in cases: calculated = I(f, a, b) if not (abs(calculated - expected) <= tolerance): self.fail( """ integrating %(tag)s calculated: %(calculated)f expected : %(expected)f """ % locals() ) def testSegment(self): "Testing segment integration" self.singleTest(ql.SegmentIntegral(10000)) def testTrapezoid(self): "Testing trapezoid integration" self.singleTest(ql.TrapezoidIntegralDefault(1.0e-4, 1000)) def testSimpson(self): "Testing Simpson integration" self.singleTest(ql.SimpsonIntegral(1.0e-4, 1000)) def testKronrod(self): "Testing Gauss-Kronrod integration" self.singleTest(ql.GaussKronrodAdaptive(1.0e-4)) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_linear_algebra.py000066400000000000000000000023331503741206100225340ustar00rootroot00000000000000import QuantLib as ql import unittest class ArrayTest(unittest.TestCase): def test_math(self): a = ql.Array([1, 2, 3]) b = ql.Array([4, 5, 6]) self.assertEqual(-a, ql.Array([-1, -2, -3])) self.assertEqual(a + 1, ql.Array([2, 3, 4])) self.assertEqual(a + b, ql.Array([5, 7, 9])) self.assertEqual(b - 1, ql.Array([3, 4, 5])) self.assertEqual(b - a, ql.Array([3, 3, 3])) self.assertEqual(a * 2, ql.Array([2, 4, 6])) self.assertEqual(3 * a, ql.Array([3, 6, 9])) self.assertEqual(a * b, ql.Array([4, 10, 18])) self.assertEqual( a * ql.Matrix([[1, 2], [3, 4], [5, 6]]), ql.Array([22, 28]) ) self.assertEqual(b / 2, ql.Array([2, 2.5, 3])) self.assertEqual(b / a, ql.Array([4, 2.5, 2])) self.assertEqual(a @ b, 32) def test_compare(self): for v1 in ([1, 2], [1, 2, 3], [2, 3, 4]): for v2 in ([1, 2], [1, 2, 3], [2, 3, 4]): self.assertEqual(ql.Array(v1) == ql.Array(v2), v1 == v2) self.assertEqual(ql.Array(v1) != ql.Array(v2), v1 != v2) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_marketelements.py000066400000000000000000000055611503741206100226330ustar00rootroot00000000000000""" Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest flag = None def raiseFlag(): global flag flag = 1 class MarketElementTest(unittest.TestCase): def testObservable(self): "Testing observability of market elements" global flag flag = None me = ql.SimpleQuote(0.0) obs = ql.Observer(raiseFlag) obs.registerWith(me) me.setValue(3.14) if not flag: self.fail("Observer was not notified of market element change") flag = None obs.unregisterWith(me) me.setValue(2.71) if flag: self.fail("Observer was notified after unregistering") def testObservableHandle(self): "Testing observability of market element handles" global flag flag = None me1 = ql.SimpleQuote(0.0) h = ql.RelinkableQuoteHandle(me1) obs = ql.Observer(raiseFlag) obs.registerWith(h) me1.setValue(3.14) if not flag: self.fail("Observer was not notified of market element change") flag = None me2 = ql.SimpleQuote(0.0) h.linkTo(me2) if not flag: self.fail("Observer was not notified of market element change") flag = None obs.unregisterWith(h) me2.setValue(2.71) if flag: self.fail("Observer was notified after unregistering") def testObservableErrors(self): class Handle: def __init__(self, x): self.x = x def asObservable(self): return 10 / self.x obs = ql.Observer(raiseFlag) self.assertRaises(TypeError, obs.registerWith, 123) self.assertRaises(TypeError, obs.registerWith, obs) self.assertRaises(TypeError, obs.registerWith, Handle) self.assertRaises(ZeroDivisionError, obs.registerWith, Handle(0)) self.assertRaises(TypeError, obs.registerWith, Handle(1)) def test_SimpleQuote(self): for value in (100, 2.71, 10**100): self.assertAlmostEqual(ql.SimpleQuote(value).value(), value) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_money.py000066400000000000000000000010541503741206100207330ustar00rootroot00000000000000import QuantLib as ql import operator import unittest class MoneyTest(unittest.TestCase): def test_order(self): ops = [operator.eq, operator.ne, operator.lt, operator.le, operator.gt, operator.ge] usd = lambda v: ql.Money(v, ql.USDCurrency()) for m1 in (usd(1), usd(2)): for m2 in (usd(1), usd(2)): for op in ops: self.assertEqual(op(m1, m2), op(m1.value(), m2.value())) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_ode.py000066400000000000000000000027171503741206100203620ustar00rootroot00000000000000""" Copyright (C) 2019 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import math import unittest import QuantLib as ql class OdeTest(unittest.TestCase): def test1dODE(self): """ Testing one dimesnional ODE """ yEnd = ql.RungeKutta(1e-8)(lambda x, y : y, 1, 0, 1) self.assertAlmostEqual(yEnd, math.exp(1), 5, msg="Unable to reproduce one dimensional ODE solution.") def test2dODE(self): """ Testing multi-dimesnional ODE """ yEnd = ql.RungeKutta(1e-8)(lambda x, y : [y[1], -y[0]], [0, 1], 0, 0.5*math.pi)[0] self.assertAlmostEqual(yEnd, 1.0, 5, msg="Unable to reproduce multi-dimensional ODE solution.") if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_options.py000066400000000000000000000064101503741206100213000ustar00rootroot00000000000000""" Copyright (C) 2021 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql class OptionsTest(unittest.TestCase): def testFdHestonHullWhite(self): """ Testing FDM Heston Hull-White pricing """ dc = ql.Actual365Fixed() todays_date = ql.Date(19, ql.May, 2021) r = ql.YieldTermStructureHandle(ql.FlatForward(todays_date, 0.075, dc)) d = ql.YieldTermStructureHandle(ql.FlatForward(todays_date, 0.01, dc)) s0 = 8.0 v0 = 0.2*0.2 kappa = 1.0 theta = v0 sigma = 0.4 rho = -0.75 a = 0.00883 sig = 0.00631 underlying = ql.makeQuoteHandle(s0) option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, s0), ql.EuropeanExercise(todays_date + ql.Period(1, ql.Years)) ) hull_white_process = ql.HullWhiteProcess(r, a, sig) heston_process = ql.HestonProcess(r, d, underlying, v0, kappa, theta, sigma, rho) option.setPricingEngine( ql.FdHestonHullWhiteVanillaEngine( ql.HestonModel(heston_process), hull_white_process, -0.5, 10, 200, 25, 10, 0, True ) ) self.assertAlmostEqual(0.87628, option.NPV(), 4) def testAnalyticHestonHullWhite(self): """ Testing Analytic Heston Hull-White pricing """ today = ql.Date.todaysDate() dc = ql.Actual365Fixed() maturityDate = today + ql.Period(10 * 365, ql.Days) v0 = 0.04 kappa = 0.5 theta = 0.04 sigma = 1.0 sig = 0.09 rho = -0.9 a = 0.08 r = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, dc)) q = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.03, dc)) option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, 100.0), ql.EuropeanExercise(maturityDate) ) expected = 40.028973 s0 = 100 underlying = ql.makeQuoteHandle(s0) hull_white_model = ql.HullWhite(r, a, sig) heston_model = ql.HestonModel( ql.HestonProcess(r, q, underlying, v0, kappa, theta, sigma, rho) ) option.setPricingEngine( ql.AnalyticHestonHullWhiteEngine(heston_model, hull_white_model) ) self.assertAlmostEqual(expected, option.NPV(), 5) option.setPricingEngine( ql.AnalyticH1HWEngine(heston_model, hull_white_model, 0.0) ) self.assertAlmostEqual(expected, option.NPV(), 5) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_ratehelpers.py000066400000000000000000000705361503741206100221350ustar00rootroot00000000000000# coding=utf-8-unix """ Copyright (C) 2009 Joseph Malicki Copyright (C) 2016, 2019 Wojciech Åšlusarski Copyright (C) 2021 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest class FixedRateBondHelperTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = ql.Date(2, 1, 2010) self.settlement_days = 3 self.face_amount = 100.0 self.redemption = 100.0 self.quote_handle = ql.makeQuoteHandle(100.0) self.issue_date = ql.Date(2, 1, 2008) self.maturity_date = ql.Date(2, 1, 2018) self.calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) self.day_counter = ql.ActualActual(ql.ActualActual.Bond) self.sched = ql.Schedule( self.issue_date, self.maturity_date, ql.Period(ql.Semiannual), self.calendar, ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, False, ) self.coupons = [0.05] self.bond_helper = ql.FixedRateBondHelper( self.quote_handle, self.settlement_days, self.face_amount, self.sched, self.coupons, self.day_counter, ql.Following, self.redemption, self.issue_date, ) def testBond(self): """ Testing FixedRateBondHelper bond() method. """ bond = self.bond_helper.bond() self.assertEqual(bond.issueDate(), self.issue_date) self.assertEqual(bond.nextCouponRate(), self.coupons[0]) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() class OISRateHelperTest(unittest.TestCase): def setUp(self): # Market rates are artificial, just close to real ones. self.default_quote_date = ql.Date(26, 8, 2016) ql.Settings.instance().evaluationDate = self.default_quote_date self.build_eur_curve(self.default_quote_date) def build_eur_curve(self, quotes_date): """ Builds the EUR OIS curve as the collateral currency discount curve :param quotes_date: date from which it is assumed all market data are valid :return: tuple consisting of objects related to EUR OIS discounting curve: ql.PiecewiseFlatForward, ql.YieldTermStructureHandle ql.RelinkableYieldTermStructureHandle """ calendar = ql.TARGET() settlementDays = 2 todaysDate = quotes_date ql.Settings.instance().evaluationDate = todaysDate todays_Eonia_quote = -0.00341 # market quotes # deposits, key structure as (settlement_days_number, number_of_units_ # for_maturity, unit) deposits = {(0, 1, ql.Days): todays_Eonia_quote} self.discounting_yts_handle = ql.RelinkableYieldTermStructureHandle() self.on_index = ql.Eonia(self.discounting_yts_handle) self.on_index.addFixing(todaysDate, todays_Eonia_quote / 100.0) self.ois = { (1, ql.Weeks): -0.342, (1, ql.Months): -0.344, (3, ql.Months): -0.349, (6, ql.Months): -0.363, (1, ql.Years): -0.389, } # convert them to Quote objects for sett_num, n, unit in deposits.keys(): deposits[(sett_num, n, unit)] = ql.SimpleQuote( deposits[(sett_num, n, unit)] / 100.0) for n, unit in self.ois.keys(): self.ois[(n, unit)] = ql.SimpleQuote(self.ois[(n, unit)] / 100.0) # build rate helpers dayCounter = ql.Actual360() # looping left if someone wants two add more deposits to tests, e.g. T/N self.depositHelpers = [ ql.DepositRateHelper( ql.QuoteHandle(deposits[(sett_num, n, unit)]), ql.Period(n, unit), sett_num, calendar, ql.ModifiedFollowing, True, dayCounter, ) for sett_num, n, unit in deposits.keys() ] self.oisHelpers = [ ql.OISRateHelper( settlementDays, ql.Period(n, unit), ql.QuoteHandle(self.ois[(n, unit)]), self.on_index) for n, unit in self.ois.keys() ] rateHelpers = self.depositHelpers + self.oisHelpers # term-structure construction self.oisSwapCurve = ql.PiecewiseFlatForward(todaysDate, rateHelpers, ql.Actual360()) self.oisSwapCurve.enableExtrapolation() self.discounting_yts_handle.linkTo(self.oisSwapCurve) def test_ois_ratehelper_impliedquote(self): """Test if OISRateHelper.impliedQuote provides original quote from curve""" # initiate curves - required due to lazy evaluation self.discounting_yts_handle.discount(0.0) for key, rate_helper in zip(self.ois.keys(), self.oisHelpers): expected = self.ois[key].value() # based on bootstrapped_curve calculated = rate_helper.impliedQuote() self.assertAlmostEqual(expected, calculated, delta=1e-8, msg="Calculated implied quote differes too " "much from original market value") def test_ois_pricing_with_calibrated_discount_curve(self): """Test repricing of swaps built with MakeOIS class""" for n, unit in self.ois.keys(): quote_rate = self.ois.get((n, unit)).value() ois = ql.MakeOIS(ql.Period(n, unit), self.on_index, fixedRate=quote_rate, nominal=10000, discountingTermStructure=self.discounting_yts_handle) calculated_rate = ois.fairRate() diff = (quote_rate - calculated_rate) * 1E4 self.assertAlmostEqual(quote_rate, calculated_rate, delta=1e-10, msg="Failed to reprice swap {n} {unit}" " with a npv difference of {diff}bps" "".format(n=n, unit=unit, diff=diff)) def test_ois_default_calendar(self): """Test if ois built using MakeOIS has proper default calendar MakeOIS class constructor in C++ is hardcoded with default calendar set to the same as of the overnightIndex. The methods available in the class allow for assigning different paymentCalendar, but the start date is already set and additional calendar will have no impact. The test checks if the constructor exposed to Python maintains this desired property and verifies that the start date of a EUR plain vanilla OIS traded on March 29th, 2018 is equal to April 4th, 2018 (due to holiday on March 30th, 2018 in TARGET calendar. """ test_date = ql.Date(29, 3, 2018) ql.Settings.instance().evaluationDate = test_date eonia = ql.Eonia() calendar = eonia.fixingCalendar() expected_date = calendar.advance(test_date, ql.Period('2d'), ql.Following) self.assertEqual(expected_date, ql.Date(4, 4, 2018)) ois = ql.MakeOIS(ql.Period('1Y'), eonia, -0.003, ql.Period(0, ql.Days)) self.assertEqual(expected_date, ois.startDate()) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() class FxSwapRateHelperTest(unittest.TestCase): def setUp(self): # Market rates are artificial, just close to real ones. self.default_quote_date = ql.Date(26, 8, 2016) self.fx_swap_quotes = { (1, ql.Months): 20e-4, (3, ql.Months): 60e-4, (6, ql.Months): 120e-4, (1, ql.Years): 240e-4, } # Valid only for the quote date of ql.Date(26, 8, 2016) self.maturities = [ql.Date(30, 9, 2016), ql.Date(30, 11, 2016), ql.Date(28, 2, 2017), ql.Date(30, 8, 2017)] self.fx_spot_quote_EURPLN = 4.3 self.fx_spot_quote_EURUSD = 1.1 def build_eur_curve(self, quotes_date): """ Builds the EUR OIS curve as the collateral currency discount curve :param quotes_date: date fro which it is assumed all market data are valid :return: tuple consisting of objects related to EUR OIS discounting curve: ql.PiecewiseFlatForward, ql.YieldTermStructureHandle ql.RelinkableYieldTermStructureHandle """ calendar = ql.TARGET() settlementDays = 2 todaysDate = quotes_date ql.Settings.instance().evaluationDate = todaysDate todays_Eonia_quote = -0.00341 # market quotes # deposits, key structure as (settlement_days_number, number_of_units_ # for_maturity, unit) deposits = {(0, 1, ql.Days): todays_Eonia_quote} discounting_yts_handle = ql.RelinkableYieldTermStructureHandle() on_index = ql.Eonia(discounting_yts_handle) on_index.addFixing(todaysDate, todays_Eonia_quote / 100.0) ois = { (1, ql.Weeks): -0.342, (1, ql.Months): -0.344, (3, ql.Months): -0.349, (6, ql.Months): -0.363, (1, ql.Years): -0.389, } # convert them to Quote objects for sett_num, n, unit in deposits.keys(): deposits[(sett_num, n, unit)] = ql.SimpleQuote( deposits[(sett_num, n, unit)] / 100.0) for n, unit in ois.keys(): ois[(n, unit)] = ql.SimpleQuote(ois[(n, unit)] / 100.0) # build rate helpers dayCounter = ql.Actual360() # looping left if somone wants two add more deposits to tests, e.g. T/N depositHelpers = [ ql.DepositRateHelper( ql.QuoteHandle(deposits[(sett_num, n, unit)]), ql.Period(n, unit), sett_num, calendar, ql.ModifiedFollowing, True, dayCounter, ) for sett_num, n, unit in deposits.keys() ] oisHelpers = [ ql.OISRateHelper( settlementDays, ql.Period(n, unit), ql.QuoteHandle(ois[(n, unit)]), on_index ) for n, unit in ois.keys() ] rateHelpers = depositHelpers + oisHelpers # term-structure construction oisSwapCurve = ql.PiecewiseFlatForward(todaysDate, rateHelpers, ql.Actual360()) oisSwapCurve.enableExtrapolation() return ( oisSwapCurve, ql.YieldTermStructureHandle(oisSwapCurve), ql.RelinkableYieldTermStructureHandle(oisSwapCurve), ) def build_pln_fx_swap_curve(self, base_ccy_yts, fx_swaps, fx_spot): """ Build curve implied from fx swap curve. :param base_ccy_yts: Relinkable yield term structure handle to curve in base currency. :param fx_swaps: Dictionary with swap points, already divided by 10,000 :param fx_spot: Float value of fx spot exchange rate. :return: tuple consisting of objects related to fx swap implied curve: ql.PiecewiseFlatForward, ql.YieldTermStructureHandle ql.RelinkableYieldTermStructureHandle list of ql.FxSwapRateHelper """ todaysDate = base_ccy_yts.referenceDate() # I am not sure if that is required, but I guss it is worth setting # up just in case somewhere another thread updates this setting. ql.Settings.instance().evaluationDate = todaysDate calendar = ql.JointCalendar(ql.TARGET(), ql.Poland()) spot_date_lag = 2 trading_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) # build rate helpers spotFx = ql.SimpleQuote(fx_spot) fxSwapHelpers = [ ql.FxSwapRateHelper( ql.makeQuoteHandle(fx_swaps[(n, unit)]), ql.QuoteHandle(spotFx), ql.Period(n, unit), spot_date_lag, calendar, ql.ModifiedFollowing, True, True, base_ccy_yts, trading_calendar, ) for n, unit in fx_swaps.keys() ] # term-structure construction fxSwapCurve = ql.PiecewiseFlatForward(todaysDate, fxSwapHelpers, ql.Actual365Fixed()) fxSwapCurve.enableExtrapolation() return ( fxSwapCurve, ql.YieldTermStructureHandle(fxSwapCurve), ql.RelinkableYieldTermStructureHandle(fxSwapCurve), fxSwapHelpers, ) def build_curves(self, quote_date): """ Build all the curves in one call for a specified quote date :param quote_date: date for which quotes are valid, e.g. ql.Date(26, 8, 2016) """ self.today = quote_date self.eur_ois_curve, self.eur_ois_handle, self.eur_ois_rel_handle = self.build_eur_curve( self.today) self.pln_eur_implied_curve, self.pln_eur_implied_curve_handle, self.pln_eur_implied_curve_relinkable_handle, self.eur_pln_fx_swap_helpers = self.build_pln_fx_swap_curve( self.eur_ois_rel_handle, self.fx_swap_quotes, self.fx_spot_quote_EURPLN ) def testQuote(self): """ Testing FxSwapRateHelper.quote() method. """ self.build_curves(self.default_quote_date) # Not sure if all Python versions and machine will guarantee that the # lists are not messed, probably some ordered maps should be used # here while retrieving values from fx_swap_quotes dictionary original_quotes = list(self.fx_swap_quotes.values()) for n in range(len(original_quotes)): original_quote = original_quotes[n] rate_helper_quote = self.eur_pln_fx_swap_helpers[n].quote().value() self.assertEqual(original_quote, rate_helper_quote) def testLatestDate(self): """ Testing FxSwapRateHelper.latestDate() method. """ self.build_curves(self.default_quote_date) # Check if still the test date is unchanged, otherwise all other # tests here make no sense. self.assertEqual(self.today, ql.Date(26, 8, 2016)) # Hard coded expected maturities of fx swaps for n in range(len(self.maturities)): self.assertEqual(self.maturities[n], self.eur_pln_fx_swap_helpers[n].latestDate()) def testImpliedRates(self): """ Testing if rates implied from the curve are returning fx forwards very close to those used for bootstrapping """ self.build_curves(self.default_quote_date) # Not sure if all Python versions and machine will guarantee that the # lists are not messed, probably some ordered maps should be used # here while retrieving values from fx_swap_quotes dictionary original_quotes = list(self.fx_swap_quotes.values()) spot_date = ql.Date(30, 8, 2016) spot_df = self.eur_ois_curve.discount( spot_date) / self.pln_eur_implied_curve.discount(spot_date) for original_quote, maturity in zip(original_quotes, self.maturities): original_forward = self.fx_spot_quote_EURPLN + original_quote curve_impl_forward = ( self.fx_spot_quote_EURPLN * self.eur_ois_curve.discount(maturity) / self.pln_eur_implied_curve.discount(maturity) / spot_df ) self.assertAlmostEqual(original_forward, curve_impl_forward, places=6) def testFxMarketConventionsForCrossRate(self): """ Testing if ql.FxSwapRateHelper obeys the fx spot market conventions for cross rates. """ today = ql.Date(1, 7, 2016) spot_date = ql.Date(5, 7, 2016) self.build_curves(today) us_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) joint_calendar = ql.JointCalendar(ql.TARGET(), ql.Poland()) settlement_calendar = ql.JointCalendar(joint_calendar, us_calendar) # Settlement should be on a day where all three centers are operating # and follow EndOfMonth rule maturities = [ settlement_calendar.advance(spot_date, n, unit, ql.ModifiedFollowing, True) for n, unit in self.fx_swap_quotes.keys() ] for n in range(len(maturities)): self.assertEqual(maturities[n], self.eur_pln_fx_swap_helpers[n].latestDate()) def testFxMarketConventionsForCrossRateONPeriod(self): """ Testing if ql.FxSwapRateHelper obeys the fx spot market conventions for cross rates' ON Period. """ today = ql.Date(1, 7, 2016) ql.Settings.instance().evaluationDate = today spot_date = ql.Date(5, 7, 2016) fwd_points = 4.0 # critical for ON rate helper on_period = ql.Period("1d") fixing_days = 0 # empty RelinkableYieldTermStructureHandle is sufficient for testing # dates base_ccy_yts = ql.RelinkableYieldTermStructureHandle() us_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) joint_calendar = ql.JointCalendar(ql.TARGET(), ql.Poland()) # Settlement should be on a day where all three centers are operating # and follow EndOfMonth rule on_rate_helper = ql.FxSwapRateHelper( ql.makeQuoteHandle(fwd_points), ql.makeQuoteHandle(self.fx_spot_quote_EURPLN), on_period, fixing_days, joint_calendar, ql.ModifiedFollowing, False, True, base_ccy_yts, us_calendar, ) self.assertEqual(spot_date, on_rate_helper.latestDate()) def testFxMarketConventionsForCrossRateAdjustedSpotDate(self): """ Testing if ql.FxSwapRateHelper obeys the fx spot market conventions """ today = ql.Date(30, 6, 2016) spot_date = ql.Date(5, 7, 2016) self.build_curves(today) us_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) joint_calendar = ql.JointCalendar(ql.TARGET(), ql.Poland()) settlement_calendar = ql.JointCalendar(joint_calendar, us_calendar) # Settlement should be on a day where all three centers are operating # and follow EndOfMonth rule maturities = [ joint_calendar.advance(spot_date, n, unit, ql.ModifiedFollowing, True) for n, unit in self.fx_swap_quotes.keys() ] maturities = [settlement_calendar.adjust(date) for date in maturities] for helper, maturity in zip(self.eur_pln_fx_swap_helpers, maturities): self.assertEqual(maturity, helper.latestDate()) def testFxMarketConventionsForDatesInEURUSD_ON_Period(self): """ Testing if ql.FxSwapRateHelper obeys the fx spot market conventions for EURUSD settlement dates on the ON Period. """ today = ql.Date(1, 7, 2016) ql.Settings.instance().evaluationDate = today spot_date = ql.Date(5, 7, 2016) fwd_points = 4.0 # critical for ON rate helper on_period = ql.Period("1d") fixing_days = 0 # empty RelinkableYieldTermStructureHandle is sufficient for testing # dates base_ccy_yts = ql.RelinkableYieldTermStructureHandle() # In EURUSD, there must be two days to spot date in Target calendar # and one day in US, therefore it is sufficient to pass only Target # as a base calendar calendar = ql.TARGET() trading_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) on_rate_helper = ql.FxSwapRateHelper( ql.makeQuoteHandle(fwd_points), ql.makeQuoteHandle(self.fx_spot_quote_EURUSD), on_period, fixing_days, calendar, ql.ModifiedFollowing, False, True, base_ccy_yts, trading_calendar, ) self.assertEqual(spot_date, on_rate_helper.latestDate()) def testFxMarketConventionsForDatesInEURUSD_ShortEnd(self): """ Testing if ql.FxSwapRateHelper obeys the fx spot market conventions for EURUSD settlement dates on the 3M tenor. """ today = ql.Date(1, 7, 2016) ql.Settings.instance().evaluationDate = today expected_3M_date = ql.Date(5, 10, 2016) fwd_points = 4.0 # critical for ON rate helper period = ql.Period("3M") fixing_days = 2 # empty RelinkableYieldTermStructureHandle is sufficient for testing # dates base_ccy_yts = ql.RelinkableYieldTermStructureHandle() # In EURUSD, there must be two days to spot date in Target calendar # and one day in US, therefore it is sufficient to pass only Target # as a base calendar. Passing joint calendar would result in wrong # spot date of the trade calendar = ql.TARGET() trading_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond) rate_helper = ql.FxSwapRateHelper( ql.makeQuoteHandle(fwd_points), ql.makeQuoteHandle(self.fx_spot_quote_EURUSD), period, fixing_days, calendar, ql.ModifiedFollowing, True, True, base_ccy_yts, trading_calendar, ) self.assertEqual(expected_3M_date, rate_helper.latestDate()) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def flat_rate(rate): return ql.FlatForward( 0, ql.NullCalendar(), ql.makeQuoteHandle(rate), ql.Actual365Fixed()) class CrossCurrencyBasisSwapRateHelperTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = ql.Date(26, 5, 2021) self.basis_point = 1.0e-4 self.settlement_days = 2 self.business_day_convention = ql.Following self.calendar = ql.TARGET() self.day_count = ql.Actual365Fixed() self.end_of_month = False base_ccy_idx_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) quoted_ccy_idx_handle = ql.YieldTermStructureHandle(flat_rate(0.015)) self.base_ccy_idx = ql.Euribor3M(base_ccy_idx_handle) self.quote_ccy_idx = ql.USDLibor( ql.Period(3, ql.Months), quoted_ccy_idx_handle) self.collateral_ccy_handle = ql.YieldTermStructureHandle( flat_rate(0.009)) # Cross currency basis swaps data source: # N. Moreni, A. Pallavicini (2015) # FX Modelling in Collateralized Markets: foreign measures, basis curves # and pricing formulae. # section 4.2.1, Table 2. self.cross_currency_basis_quotes = ((ql.Period(1, ql.Years), -14.5), (ql.Period(18, ql.Months), -18.5), (ql.Period(2, ql.Years), -20.5), (ql.Period(3, ql.Years), -23.75), (ql.Period(4, ql.Years), -25.5), (ql.Period(5, ql.Years), -26.5), (ql.Period(7, ql.Years), -26.75), (ql.Period(10, ql.Years), -26.25), (ql.Period(15, ql.Years), -24.75), (ql.Period(20, ql.Years), -23.25), (ql.Period(30, ql.Years), -20.50)) def buildRateHelper( self, quote_tuple, is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_ccy_leg): tenor, rate = quote_tuple quote_handle = ql.makeQuoteHandle(rate * self.basis_point) return ql.ConstNotionalCrossCurrencyBasisSwapRateHelper( quote_handle, tenor, self.settlement_days, self.calendar, self.business_day_convention, self.end_of_month, self.base_ccy_idx, self.quote_ccy_idx, self.collateral_ccy_handle, is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_ccy_leg) def assertImpliedQuotes( self, is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_ccy_leg): eps = 1.0e-8 helpers = [self.buildRateHelper(q, is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_ccy_leg) for q in self.cross_currency_basis_quotes] term_structure = ql.PiecewiseLogLinearDiscount( self.settlement_days, self.calendar, helpers, self.day_count) settlement_date = term_structure.referenceDate() # Trigger bootstrap discount_at_origin = term_structure.discount(settlement_date) self.assertAlmostEqual( first=discount_at_origin, second=1.0, delta=eps) for q, h in zip(self.cross_currency_basis_quotes, helpers): tenor, expected_rate = q actual_rate = h.impliedQuote() / self.basis_point fail_msg = """ Failed to replicate cross currency basis: tenor: {tenor} actual basis: {actual_rate} expected basis: {expected_rate} tolerance: {tolerance} """.format(tenor=tenor, actual_rate=actual_rate, expected_rate=expected_rate, tolerance=eps) self.assertAlmostEqual( first=actual_rate, second=expected_rate, delta=eps, msg=fail_msg) def testFxBasisSwapsWithCollateralInBaseAndBasisInQuoteCcy(self): """ Testing basis swaps instruments with collateral in base ccy and basis in quote ccy... """ is_fx_base_ccy_collateral_ccy = True is_basis_on_fx_base_currency_leg = False self.assertImpliedQuotes( is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_currency_leg) def testFxBasisSwapsWithCollateralInQuoteAndBasisInBaseCcy(self): """ Testing basis swaps instruments with collateral in quote ccy and basis in base ccy... """ is_fx_base_ccy_collateral_ccy = False is_basis_on_fx_base_currency_leg = True self.assertImpliedQuotes( is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_currency_leg) def testFxBasisSwapsWithCollateralAndBasisInBaseCcy(self): """ Testing basis swaps instruments with collateral and basis in base ccy... """ is_fx_base_ccy_collateral_ccy = True is_basis_on_fx_base_currency_leg = True self.assertImpliedQuotes( is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_currency_leg) def testFxBasisSwapsWithCollateralAndBasisInQuoteCcy(self): """ Testing basis swaps instruments with collateral and basis in quote ccy... """ is_fx_base_ccy_collateral_ccy = False is_basis_on_fx_base_currency_leg = False self.assertImpliedQuotes( is_fx_base_ccy_collateral_ccy, is_basis_on_fx_base_currency_leg) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_sabr.py000066400000000000000000000077361503741206100205500ustar00rootroot00000000000000""" Copyright (C) 2019 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import math import unittest import QuantLib as ql class SabrTest(unittest.TestCase): def testHagenFormula(self): """ Testing Hagen et al. formula """ today = ql.Date(9,1,2019) dc = ql.Actual365Fixed() maturityDate = today + ql.Period(6, ql.Months) maturityTime = dc.yearFraction(today, maturityDate) alpha = 0.35 beta = 0.85 nu = 0.75 rho = 0.85 f0 = 100.0 strike = 110.0 sabrVol = ql.sabrVolatility(strike, f0, maturityTime, alpha, beta, nu, rho) self.assertAlmostEqual(sabrVol, 0.205953, 6, msg="Unable to reproduce Hagen et al. SABR volatility") flochKennedyVol = ql.sabrFlochKennedyVolatility( strike, f0, maturityTime, alpha, beta, nu, rho) self.assertAlmostEqual(flochKennedyVol, 0.205447, 6, msg="Unable to reproduce Le Floc'h-Kennedy SABR volatility") def testPdeSolver(self): """ Testing BENCHOP-SLV SABR example value """ today = ql.Date(8, 1, 2019) dc = ql.Actual365Fixed() maturityDate = today + ql.Period(10 * 365, ql.Days) maturityTime = dc.yearFraction(today, maturityDate) f0 = 0.07 alpha = 0.4 nu = 0.8 beta = 0.5 rho = -0.6 strike = f0 * math.exp(-0.1 * math.sqrt(maturityTime)) rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.0, dc)) # see https://ir.cwi.nl/pub/28249 expected = 0.052450313614407 option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, strike), ql.EuropeanExercise(maturityDate)) option.setPricingEngine(ql.FdSabrVanillaEngine(f0, alpha, beta, nu, rho, rTS, 30, 800, 30, 1, 0.8)) calculated = option.NPV() self.assertAlmostEqual(calculated, expected, 4, msg="Unable to reproduce Le Floc'h-Kennedy SABR volatility") def testSabrPdeVsCevPdeVsAnalyticCev(self): """ Testing SABR PDE vs CEV PDE vs Analytic CEV """ today = ql.Date(1, 3, 2019) dc = ql.Actual365Fixed() maturityDate = today + ql.Period(12, ql.Months) f0 = 1.2 alpha = 0.35 beta = 0.9 nu = 1e-3 rho = 0.25 strike = 1.1 rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, dc)) option = ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, strike), ql.EuropeanExercise(maturityDate)) option.setPricingEngine(ql.FdSabrVanillaEngine(f0, alpha, beta, nu, rho, rTS, 30, 400, 3)) fdSabrNPV = option.NPV() option.setPricingEngine(ql.FdCEVVanillaEngine(f0, alpha, beta, rTS, 30, 400)) fdCevNPV = option.NPV() option.setPricingEngine(ql.AnalyticCEVEngine(f0, alpha, beta, rTS)) analyticCevNPV = option.NPV() self.assertAlmostEqual(fdSabrNPV, analyticCevNPV, 4, msg="Unable to match PDE SABR value with analytic CEV value") self.assertAlmostEqual(fdCevNPV, analyticCevNPV, 4, msg="Unable to match PDE CEV value with analytic CEV value") if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_settings.py000066400000000000000000000025561503741206100214540ustar00rootroot00000000000000import QuantLib as ql import unittest class SettingsTest(unittest.TestCase): def test_properties(self): settings = ql.Settings.instance() with ql.SavedSettings(): for v in (ql.Date(1, 1, 2023), ql.Date(2, 2, 2023)): settings.evaluationDate = v self.assertEqual(settings.evaluationDate, v) for v in (True, False): settings.enforcesTodaysHistoricFixings = v self.assertEqual(settings.enforcesTodaysHistoricFixings, v) for v in (True, False): settings.includeReferenceDateEvents = v self.assertEqual(settings.includeReferenceDateEvents, v) for v in (True, False, None): settings.includeTodaysCashFlows = v self.assertEqual(settings.includeTodaysCashFlows, v) def test_saved_settings(self): settings = ql.Settings.instance() settings.evaluationDate = ql.Date(1, 1, 2023) with ql.SavedSettings(): settings.evaluationDate = ql.Date(2, 2, 2023) self.assertEqual(settings.evaluationDate, ql.Date(2, 2, 2023)) # Test that SavedSettings restores settings on exit. self.assertEqual(settings.evaluationDate, ql.Date(1, 1, 2023)) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_slv.py000066400000000000000000000137761503741206100204260ustar00rootroot00000000000000""" Copyright (C) 2019 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql class SlvTest(unittest.TestCase): def setUp(self): self.todaysDate = ql.Date(15, ql.May, 2019) ql.Settings.instance().evaluationDate = self.todaysDate self.settlementDate = self.todaysDate + ql.Period(2, ql.Days) self.dc = ql.Actual365Fixed() self.riskFreeRate = ql.YieldTermStructureHandle(ql.FlatForward(self.settlementDate, 0.05, self.dc)) self.dividendYield = ql.YieldTermStructureHandle(ql.FlatForward(self.settlementDate, 0.025, self.dc)) self.underlying = ql.makeQuoteHandle(100.0) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def constVol(self, vol): return ql.BlackVolTermStructureHandle(ql.BlackConstantVol(self.settlementDate, ql.TARGET(), vol, self.dc)) def testSlvProcess(self): """ Testing HestonSLVProcess generation """ hestonProcess = ql.HestonProcess( self.riskFreeRate, self.riskFreeRate, self.underlying, 0.1 * 0.1, 1.0, 0.25 * 0.25, 0.15, -0.75 ) localVol = ql.LocalVolSurface( ql.BlackVolTermStructureHandle(ql.BlackConstantVol(self.settlementDate, ql.TARGET(), 0.10, self.dc)), self.riskFreeRate, self.riskFreeRate, self.underlying, ) ql.HestonSLVProcess(hestonProcess, localVol) def testSlvProcessAsBlackScholes(self): """ Testing HestonSLVProcess equal to Black-Scholes process """ hestonProcess = ql.HestonProcess( self.riskFreeRate, self.dividendYield, self.underlying, 0.01, 1.0, 0.01, 1e-4, 0.0 ) exercise = ql.EuropeanExercise(self.todaysDate + ql.Period(1, ql.Years)) payoff = ql.PlainVanillaPayoff(ql.Option.Call, self.underlying.value()) option = ql.VanillaOption(payoff, exercise) hestonModel = ql.HestonModel(hestonProcess) option.setPricingEngine(ql.FdHestonVanillaEngine(hestonModel, 20, 100, 3)) hestonNPV = option.NPV() option.setPricingEngine( ql.AnalyticEuropeanEngine( ql.BlackScholesMertonProcess(self.underlying, self.dividendYield, self.riskFreeRate, self.constVol(0.1)) ) ) bsNPV = option.NPV() self.assertAlmostEqual( hestonNPV, bsNPV, 2, msg="Unable to reproduce Heston vanilla option price with Black-Scholes process" ) leverageFct = ql.LocalVolSurface(self.constVol(2.0), self.riskFreeRate, self.dividendYield, self.underlying) option.setPricingEngine( ql.FdHestonVanillaEngine( hestonModel, 20, 100, 3, 1, ql.FdmSchemeDesc.Hundsdorfer(), leverageFct, ) ) slvNPV = option.NPV() bsmProcess = ql.BlackScholesMertonProcess(self.underlying, self.dividendYield, self.riskFreeRate, self.constVol(0.2)) option.setPricingEngine(ql.AnalyticEuropeanEngine(bsmProcess)) bsNPV = option.NPV() self.assertAlmostEqual( slvNPV, bsNPV, 2, msg="Unable to reproduce Heston plus constant local vol option price with Black-Scholes formula", ) barrier_lo = 70.0 barrier_hi = 130.0 barrierOption = ql.DoubleBarrierOption( ql.DoubleBarrier.KnockOut, barrier_lo, barrier_hi, 0.0, ql.CashOrNothingPayoff(ql.Option.Call, 0.0, 1.0), exercise); barrierOption.setPricingEngine( ql.FdHestonDoubleBarrierEngine( hestonModel, 400, 100, 2, 1, ql.FdmSchemeDesc.Hundsdorfer(), leverageFct, ) ) slvBarrierNPV = barrierOption.NPV() barrierOption.setPricingEngine(ql.AnalyticDoubleBarrierBinaryEngine(bsmProcess)) bsmBarrierNPV = barrierOption.NPV() self.assertAlmostEqual( slvBarrierNPV, bsmBarrierNPV, 2, msg="Unable to reproduce Heston plus constant local vol " "double barrier option price with Black-Scholes Double Barrier Binary Engine", ) def testFixedLocalVolSurface(self): """ Testing FixedLocalVolSurface interpolation """ dc = ql.Actual365Fixed() maturities = [ql.Date(1, 3, 2020), ql.Date(1, 6, 2020)] strikes = [60, 100, 130] local_vols = [[0.2, 0.3], [0.25, 0.4], [0.3, 0.4]] fixed_local_vol_surf = ql.FixedLocalVolSurface( self.todaysDate, [dc.yearFraction(self.todaysDate, d) for d in maturities], strikes, local_vols, dc ) fixed_local_vol_surf.setInterpolation("linear") self.assertEqual(60, fixed_local_vol_surf.minStrike()) self.assertEqual(130, fixed_local_vol_surf.maxStrike()) self.assertAlmostEqual(0.2, fixed_local_vol_surf.localVol(ql.Date(1, 3, 2020), 60)) self.assertAlmostEqual(0.3, fixed_local_vol_surf.localVol(ql.Date(1, 6, 2020), 60)) self.assertAlmostEqual(0.25, fixed_local_vol_surf.localVol(ql.Date(16, 4, 2020), 60)) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_solvers1d.py000066400000000000000000000056521503741206100215360ustar00rootroot00000000000000""" Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql class Foo: def __call__(self, x): return x * x - 1.0 def derivative(self, x): return 2.0 * x class Solver1DTest(unittest.TestCase): def test_solve(self): "Testing 1-D solvers" for factory in [ql.Brent, ql.Bisection, ql.FalsePosition, ql.Ridder, ql.Secant]: solver = factory() for accuracy in [1.0e-4, 1.0e-6, 1.0e-8]: root = solver.solve(lambda x: x * x - 1.0, accuracy, 1.5, 0.1) if not (abs(root - 1.0) < accuracy): self.fail( """ %(factory)s solve(): expected: 1.0 calculated root: %(root)g accuracy: %(accuracy)s """ % locals() ) root = solver.solve(lambda x: x * x - 1.0, accuracy, 1.5, 0.0, 1.0) if not (abs(root - 1.0) < accuracy): self.fail( """ %(factory)s bracketed solve(): expected: 1.0 calculated root: %(root)g accuracy: %(accuracy)s """ % locals() ) for factory in [ql.Newton, ql.NewtonSafe]: solver = factory() for accuracy in [1.0e-4, 1.0e-6, 1.0e-8]: root = solver.solve(Foo(), accuracy, 1.5, 0.1) if not (abs(root - 1.0) < accuracy): self.fail( """ %(factory)s solve(): expected: 1.0 calculated root: %(root)g accuracy: %(accuracy)s """ % locals() ) root = solver.solve(Foo(), accuracy, 1.5, 0.0, 1.0) if not (abs(root - 1.0) < accuracy): self.fail( """ %(factory)s bracketed solve(): expected: 1.0 calculated root: %(root)g accuracy: %(accuracy)s """ % locals() ) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_swap.py000066400000000000000000000242541503741206100205650ustar00rootroot00000000000000""" Copyright (C) 2021 Marcin Rybacki Copyright (C) 2023 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql EPSILON = 1.e-8 CAL = ql.TARGET() DCT = ql.Actual365Fixed() IR_FIXINGS = [(ql.Date(3, ql.January, 2023), 0.033), (ql.Date(4, ql.January, 2023), 0.033), (ql.Date(5, ql.January, 2023), 0.033), (ql.Date(6, ql.January, 2023), 0.033), (ql.Date(9, ql.January, 2023), 0.03), (ql.Date(10, ql.January, 2023), 0.03), (ql.Date(11, ql.January, 2023), 0.03), (ql.Date(12, ql.January, 2023), 0.03), (ql.Date(13, ql.January, 2023), 0.03), (ql.Date(17, ql.January, 2023), 0.03), (ql.Date(20, ql.January, 2023), 0.03), (ql.Date(23, ql.January, 2023), 0.03), (ql.Date(24, ql.January, 2023), 0.03), (ql.Date(25, ql.January, 2023), 0.03), (ql.Date(26, ql.January, 2023), 0.03)] def flat_rate(rate): return ql.FlatForward( 2, CAL, ql.makeQuoteHandle(rate), ql.Actual365Fixed()) class ZeroCouponSwapTest(unittest.TestCase): def setUp(self): valuation_date = CAL.adjust(ql.Date(1, ql.June, 2021)) ql.Settings.instance().evaluationDate = valuation_date self.nominal_ts_handle = ql.YieldTermStructureHandle(flat_rate(0.007)) self.ibor_idx = ql.Euribor6M(self.nominal_ts_handle) self.engine = ql.DiscountingSwapEngine(self.nominal_ts_handle) def build_zcs_from_fixed_payment(self, amount): return ql.ZeroCouponSwap(ql.Swap.Receiver, 1.0e6, ql.Date(3, ql.June, 2021), ql.Date(3, ql.June, 2051), amount, self.ibor_idx, CAL) def build_zcs_from_rate(self, rate): return ql.ZeroCouponSwap(ql.Swap.Receiver, 1.0e6, ql.Date(3, ql.June, 2021), ql.Date(3, ql.June, 2051), rate, DCT, self.ibor_idx, CAL) def test_zero_coupon_swap_inspectors(self): """Testing zero coupon swap inspectors""" swap = self.build_zcs_from_fixed_payment(1.5e6) fail_msg = "Unable to replicate the properties of a ZC swap." self.assertEqual(swap.type(), ql.Swap.Receiver, msg=fail_msg) self.assertEqual(swap.startDate(), ql.Date(3, ql.June, 2021), msg=fail_msg) self.assertEqual(swap.maturityDate(), ql.Date(3, ql.June, 2051), msg=fail_msg) self.assertAlmostEqual(swap.baseNominal(), 1.0e6, delta=EPSILON, msg=fail_msg) self.assertAlmostEqual(swap.fixedPayment(), 1.5e6, delta=EPSILON, msg=fail_msg) def test_npvs_of_par_zero_coupon_swap_with_fixed_payment(self): """Testing NPVs of a zero coupon swap with fixed payment""" swap = self.build_zcs_from_fixed_payment(1.5e6) swap.setPricingEngine(self.engine) fair_payment = swap.fairFixedPayment() par_swap = self.build_zcs_from_fixed_payment(fair_payment) par_swap.setPricingEngine(self.engine) npv = par_swap.NPV() fail_npv_msg = """ Unable to replicate par zero coupon swap NPV: calculated: {actual} expected: {expected} """.format(actual=npv, expected=0.0) self.assertAlmostEqual(npv, 0.0, delta=EPSILON, msg=fail_npv_msg) fxd_leg_npv = par_swap.fixedLegNPV() flt_leg_npv = par_swap.floatingLegNPV() fail_legs_npv_msg = """ Unable to replicate the NPVs of a par zero coupon swap legs: fixed leg NPV: {fxd_leg} floating leg NPV: {flt_leg} """.format(fxd_leg=fxd_leg_npv, flt_leg=flt_leg_npv) self.assertAlmostEqual(abs(fxd_leg_npv), abs(flt_leg_npv), delta=EPSILON, msg=fail_legs_npv_msg) def test_npvs_of_par_zero_coupon_swap_with_fixed_rate(self): """Testing NPVs of a zero coupon swap with fixed rate""" swap = self.build_zcs_from_fixed_payment(1.5e6) swap.setPricingEngine(self.engine) fair_rate = swap.fairFixedRate(DCT) par_swap = self.build_zcs_from_rate(fair_rate) par_swap.setPricingEngine(self.engine) npv = par_swap.NPV() fail_msg = """ Unable to replicate par zero coupon swap NPV: calculated: {actual} expected: {expected} """.format(actual=npv, expected=0.0) self.assertAlmostEqual(npv, 0.0, delta=EPSILON, msg=fail_msg) def test_zero_coupon_swap_legs(self): """Testing zero coupon swap legs""" swap = self.build_zcs_from_rate(0.01) fxd_leg = swap.fixedLeg() fxd_cf = ql.as_fixed_rate_coupon(fxd_leg[0]) fail_msg_fxd = """Fixed leg cash flow type should be FixedRateCoupon but was {actual}. """.format(actual=type(fxd_cf)) self.assertTrue(isinstance(fxd_cf, ql.FixedRateCoupon), msg=fail_msg_fxd) flt_leg = swap.floatingLeg() flt_cf = ql.as_sub_periods_coupon(flt_leg[0]) fail_msg_flt = """Floating leg cash flow type should be SubPeriodsCoupon but was {actual}. """.format(actual=type(flt_cf)) self.assertTrue(isinstance( flt_cf, ql.SubPeriodsCoupon), msg=fail_msg_flt) class EquityTotalReturnSwapTest(unittest.TestCase): def setUp(self): valuation_date = ql.Date(27, ql.January, 2023) ql.Settings.instance().evaluationDate = valuation_date self.interest_handle = ql.YieldTermStructureHandle(flat_rate(0.03)) self.dividend_handle = ql.YieldTermStructureHandle(flat_rate(0.0)) equity_spot = ql.makeQuoteHandle(8690.0) self.equity_idx = ql.EquityIndex( "eq_idx", CAL, self.interest_handle, self.dividend_handle, equity_spot) ql.IndexManager.instance().clearHistory(self.equity_idx.name()) self.equity_idx.addFixing(ql.Date(5, ql.January, 2023), 9010.0) self.ibor_idx = ql.USDLibor( ql.Period(3, ql.Months), self.interest_handle) ql.IndexManager.instance().clearHistory(self.ibor_idx.name()) self.sofr_idx = ql.Sofr(self.interest_handle) ql.IndexManager.instance().clearHistory(self.sofr_idx.name()) for f_dt, f_val in IR_FIXINGS: self.ibor_idx.addFixing(f_dt, f_val) self.sofr_idx.addFixing(f_dt, f_val) def build_trs(self, interest_idx, start, end, margin=0.025): schedule = ql.Schedule( start, end, interest_idx.tenor(), interest_idx.fixingCalendar(), interest_idx.businessDayConvention(), interest_idx.businessDayConvention(), ql.DateGeneration.Backward, False) return ql.EquityTotalReturnSwap(ql.Swap.Receiver, 1.0e6, schedule, self.equity_idx, interest_idx, DCT, margin) def test_trs_interest_rate_index(self): """Testing equity total return swap interest rate index""" start = ql.Date(5, ql.January, 2023) end = ql.Date(5, ql.April, 2023) trs_vs_ibor = self.build_trs(self.ibor_idx, start, end) trs_vs_sofr = self.build_trs(self.sofr_idx, start, end) fail_msg = "Incorrect interest rate index set to TRS." self.assertEqual(trs_vs_ibor.interestRateIndex().name(), "USDLibor3M Actual/360", msg=fail_msg) self.assertEqual(trs_vs_sofr.interestRateIndex().name(), "SOFRON Actual/360", msg=fail_msg) def test_trs_npv(self): """Testing equity total return swap NPV""" start = ql.Date(5, ql.January, 2023) end = ql.Date(5, ql.April, 2023) pricer = ql.DiscountingSwapEngine(self.interest_handle) trs_vs_ibor = self.build_trs(self.ibor_idx, start, end) trs_vs_ibor.setPricingEngine(pricer) trs_vs_sofr = self.build_trs(self.sofr_idx, start, end) trs_vs_sofr.setPricingEngine(pricer) par_trs_vs_ibor = self.build_trs( self.ibor_idx, start, end, trs_vs_ibor.fairMargin()) par_trs_vs_ibor.setPricingEngine(pricer) par_trs_vs_sofr = self.build_trs( self.sofr_idx, start, end, trs_vs_sofr.fairMargin()) par_trs_vs_sofr.setPricingEngine(pricer) fail_msg = "Par TRS expected to have NPV equal to zero." self.assertAlmostEqual( par_trs_vs_ibor.NPV(), 0.0, delta=EPSILON, msg=fail_msg) self.assertAlmostEqual( par_trs_vs_sofr.NPV(), 0.0, delta=EPSILON, msg=fail_msg) if __name__ == '__main__': print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_swaption.py000066400000000000000000000205411503741206100214520ustar00rootroot00000000000000""" Copyright (C) 2020 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import QuantLib as ql BASIS_POINT = 1e-4 EPSILON = 1.e-10 OPTION_TYPE_MAP = {ql.Swap.Receiver: 'Receiver', ql.Swap.Payer: 'Payer'} SETTLEMENT_TYPE_MAP = {ql.Settlement.Physical: 'Physical', ql.Settlement.Cash: 'Cash'} SETTLEMENT_METHOD_MAP = {ql.Settlement.PhysicalOTC: 'Physical OTC', ql.Settlement.CollateralizedCashPrice: ( 'Collateralized Cash Price'), ql.Settlement.ParYieldCurve: 'Par Yield Curve'} def compounded_annual_constant_rate_discount( rate, day_counter): def _calc(start, end): time = day_counter.yearFraction(start, end) return (1.0 + rate) ** (-time) return _calc def par_yield_bps(underlying, discount_handle): fixed_leg = underlying.fixedLeg() first_coupon = ql.as_fixed_rate_coupon(fixed_leg[0]) discount_date = first_coupon.accrualStartDate() discount = discount_handle.discount(discount_date) fixed_rate = underlying.fixedRate() fixed_dct = underlying.fixedDayCount() fair_rate = underlying.fairRate() ir_func = compounded_annual_constant_rate_discount(fair_rate, fixed_dct) bps = sum([ir_func(discount_date, c_f.date()) * c_f.amount() / fixed_rate for c_f in fixed_leg if c_f.date() > discount_date]) return abs(bps) * discount def swap_pv01(underlying): return abs(underlying.fixedLegBPS()) / BASIS_POINT def make_const_black_vol_engine(discount_handle, volatility): h = ql.makeQuoteHandle(volatility) return ql.BlackSwaptionEngine(discount_handle, h) def make_const_bachelier_vol_engine(discount_handle, volatility): h = ql.makeQuoteHandle(volatility) return ql.BachelierSwaptionEngine(discount_handle, h) class SwaptionTest(unittest.TestCase): def setUp(self): self.calendar = ql.TARGET() self.today = self.calendar.adjust(ql.Date.todaysDate()) ql.Settings.instance().evaluationDate = self.today projection_curve_handle = ql.RelinkableYieldTermStructureHandle() self.projection_rate = 0.01 self.projection_quote_handle = ql.RelinkableQuoteHandle() projection_curve = ql.FlatForward( self.today, self.projection_quote_handle, ql.Actual365Fixed()) projection_curve_handle.linkTo(projection_curve) self.discount_handle = ql.YieldTermStructureHandle(ql.FlatForward( self.today, ql.makeQuoteHandle(0.0085), ql.Actual365Fixed())) self.swap_engine = ql.DiscountingSwapEngine(self.discount_handle) self.idx = ql.Euribor6M(projection_curve_handle) self.exercises = [ql.Period(1, ql.Years), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(5, ql.Years), ql.Period(7, ql.Years), ql.Period(10, ql.Years)] self.lengths = [ql.Period(1, ql.Years), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(5, ql.Years), ql.Period(7, ql.Years), ql.Period(10, ql.Years), ql.Period(15, ql.Years), ql.Period(20, ql.Years)] self.swap_type = [ql.Swap.Receiver, ql.Swap.Payer] def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def _assert_swaption_annuity(self, swaption_pricer_func, use_bachelier_vol): self.projection_quote_handle.linkTo( ql.SimpleQuote(self.projection_rate)) settle_type = ql.Settlement.Cash methods = [ql.Settlement.ParYieldCurve, ql.Settlement.CollateralizedCashPrice] for e in self.exercises: for l in self.lengths: for t in self.swap_type: for m in methods: volatility = 0.003 if use_bachelier_vol else 0.3 strike = 0.03 swaption_engine = swaption_pricer_func( self.discount_handle, volatility) exercise_date = self.calendar.advance( self.today, e) start_date = self.calendar.advance( exercise_date, ql.Period(2, ql.Days)) underlying = ql.MakeVanillaSwap( l, self.idx, strike, ql.Period(0, ql.Days), effectiveDate=start_date, fixedLegTenor=ql.Period(1, ql.Years), fixedLegDayCount=ql.Thirty360(ql.Thirty360.BondBasis), floatingLegSpread=0.0, swapType=t) underlying.setPricingEngine(self.swap_engine) swaption = ql.Swaption(underlying, ql.EuropeanExercise( exercise_date), settle_type, m) swaption.setPricingEngine(swaption_engine) annuity = swaption.annuity() expected_annuity = 0.0 if (m == ql.Settlement.CollateralizedCashPrice): expected_annuity = swap_pv01(underlying) if (m == ql.Settlement.ParYieldCurve): expected_annuity = par_yield_bps( underlying, self.discount_handle) fail_msg = """ Swaption annuity test failed for: option tenor: {option_tenor} volatility : {volatility} option type: {option_type} swap tenor: {swap_tenor} strike: {strike} settlement: {settle_type} method: {method} annuity: {annuity} replicated annuity: {expected_annuity} """.format(option_tenor=e, volatility=volatility, option_type=OPTION_TYPE_MAP[t], swap_tenor=l, strike=strike, settle_type=SETTLEMENT_TYPE_MAP[settle_type], method=SETTLEMENT_METHOD_MAP[m], annuity=annuity, expected_annuity=expected_annuity) self.assertAlmostEqual( first=annuity, second=expected_annuity, delta=EPSILON, msg=fail_msg) def test_swaption_annuity_black_model(self): """Testing swaption annuity in Black model""" self._assert_swaption_annuity( swaption_pricer_func=make_const_black_vol_engine, use_bachelier_vol=False) def test_swaption_annuity_bachelier_model(self): """Testing swaption annuity in Bachelier model""" self._assert_swaption_annuity( swaption_pricer_func=make_const_bachelier_vol_engine, use_bachelier_vol=True) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_termstructures.py000066400000000000000000000367001503741206100227250ustar00rootroot00000000000000""" Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2007 StatPro Italia srl Copyright (C) 2020 Marcin Rybacki This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import QuantLib as ql import unittest import math flag = None def raiseFlag(): global flag flag = 1 def binaryFunction(x, y): return 2.0 * x + y def extrapolatedForwardRate( firstSmoothingPoint, lastLiquidForwardRate, ultimateForwardRate, alpha): def calculate(t): deltaT = t - firstSmoothingPoint beta = (1.0 - math.exp(-alpha * deltaT)) / (alpha * deltaT) return ultimateForwardRate + ( lastLiquidForwardRate - ultimateForwardRate) * beta return calculate class TermStructureTest(unittest.TestCase): def setUp(self): self.calendar = ql.TARGET() today = self.calendar.adjust(ql.Date.todaysDate()) ql.Settings.instance().evaluationDate = today self.settlementDays = 2 self.dayCounter = ql.Actual360() self.settlement = self.calendar.advance(today, self.settlementDays, ql.Days) deposits = [ ql.DepositRateHelper( ql.makeQuoteHandle(rate / 100), ql.Period(n, units), self.settlementDays, self.calendar, ql.ModifiedFollowing, False, self.dayCounter, ) for (n, units, rate) in [ (1, ql.Months, 4.581), (2, ql.Months, 4.573), (3, ql.Months, 4.557), (6, ql.Months, 4.496), (9, ql.Months, 4.490), ] ] swaps = [ ql.SwapRateHelper( ql.makeQuoteHandle(rate / 100), ql.Period(years, ql.Years), self.calendar, ql.Annual, ql.Unadjusted, ql.Thirty360(ql.Thirty360.BondBasis), ql.Euribor6M(), ) for (years, rate) in [(1, 4.54), (5, 4.99), (10, 5.47), (20, 5.89), (30, 5.96)] ] self.instruments = deposits + swaps self.termStructure = ql.PiecewiseFlatForward( self.settlement, self.instruments, self.dayCounter) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def testImpliedObs(self): "Testing observability of implied term structure" global flag flag = None h = ql.RelinkableYieldTermStructureHandle() settlement = self.termStructure.referenceDate() new_settlement = self.calendar.advance(settlement, 3, ql.Years) implied = ql.ImpliedTermStructure(h, new_settlement) obs = ql.Observer(raiseFlag) obs.registerWith(implied) h.linkTo(self.termStructure) if not flag: self.fail("Observer was not notified of term structure change") def testFSpreadedObs(self): "Testing observability of forward-spreaded term structure" global flag flag = None me = ql.SimpleQuote(0.01) mh = ql.QuoteHandle(me) h = ql.RelinkableYieldTermStructureHandle() spreaded = ql.ForwardSpreadedTermStructure(h, mh) obs = ql.Observer(raiseFlag) obs.registerWith(spreaded) h.linkTo(self.termStructure) if not flag: self.fail("Observer was not notified of term structure change") flag = None me.setValue(0.005) if not flag: self.fail("Observer was not notified of spread change") def testZSpreadedObs(self): "Testing observability of zero-spreaded term structure" global flag flag = None me = ql.SimpleQuote(0.01) mh = ql.QuoteHandle(me) h = ql.RelinkableYieldTermStructureHandle() spreaded = ql.ZeroSpreadedTermStructure(h, mh) obs = ql.Observer(raiseFlag) obs.registerWith(spreaded) h.linkTo(self.termStructure) if not flag: self.fail("Observer was not notified of term structure change") flag = None me.setValue(0.005) if not flag: self.fail("Observer was not notified of spread change") def testCompositeZeroYieldStructure(self): """Testing composite zero yield structure""" settlement = self.termStructure.referenceDate() compounding = ql.Compounded freq = ql.Semiannual flatTs = ql.FlatForward( settlement, ql.makeQuoteHandle(0.0085), self.dayCounter) firstHandle = ql.YieldTermStructureHandle(flatTs) secondHandle = ql.YieldTermStructureHandle(self.termStructure) compositeTs = ql.CompositeZeroYieldStructure( firstHandle, secondHandle, binaryFunction, compounding, freq) maturity = settlement + ql.Period(20, ql.Years) expectedZeroRate = binaryFunction( firstHandle.zeroRate( maturity, self.dayCounter, compounding, freq).rate(), secondHandle.zeroRate( maturity, self.dayCounter, compounding, freq).rate()) actualZeroRate = compositeTs.zeroRate( maturity, self.dayCounter, compounding, freq).rate() failMsg = """ Composite zero yield structure rate replication failed: expected zero rate: {expected} actual zero rate: {actual} """.format(expected=expectedZeroRate, actual=actualZeroRate) self.assertAlmostEqual( first=expectedZeroRate, second=actualZeroRate, delta=1.0e-12, msg=failMsg) def testUltimateForwardTermStructure(self): """Testing ultimate forward term structure""" settlement = self.termStructure.referenceDate() ufr = ql.makeQuoteHandle(0.06) llfr = ql.makeQuoteHandle(0.05) fsp = ql.Period(20, ql.Years) alpha = 0.05 baseCrvHandle = ql.YieldTermStructureHandle(self.termStructure) ufrCrv = ql.UltimateForwardTermStructure( baseCrvHandle, llfr, ufr, fsp, alpha) cutOff = ufrCrv.timeFromReference(settlement + fsp) forwardCalculator = extrapolatedForwardRate( cutOff, llfr.value(), ufr.value(), alpha) times = [ufrCrv.timeFromReference(settlement + ql.Period(x, ql.Years)) for x in [21, 30, 40, 50, 60, 70, 80, 90, 100]] for t in times: actualForward = ufrCrv.forwardRate( cutOff, t, ql.Continuous, ql.NoFrequency, True).rate() expectedForward = forwardCalculator(t) failMsg = """ UFR term structure forward replication failed for: time to maturity: {timeToMaturity} expected forward rate: {expected} actual forward rate: {actual} """.format(timeToMaturity=t, expected=expectedForward, actual=actualForward) self.assertAlmostEqual( first=expectedForward, second=actualForward, delta=1.0e-12, msg=failMsg) def testTermStructureInterpolationSchemes(self): """Testing different interpolation schemes and their consistency""" args = [self.settlement, self.instruments, self.dayCounter] mapping = [ [ql.PiecewiseParabolicCubicZero, ql.ParabolicCubicZeroCurve, 'Parabolic Zero'], [ql.PiecewiseMonotonicParabolicCubicZero, ql.MonotonicParabolicCubicZeroCurve, 'Monotone Parabolic Zero'], [ql.PiecewiseLogParabolicCubicDiscount, ql.LogParabolicCubicDiscountCurve, 'Log Parabolic Discount'], [ql.PiecewiseMonotonicLogParabolicCubicDiscount, ql.MonotonicLogParabolicCubicDiscountCurve, 'Monotone Log Parabolic Discount'], ] for bootstrap, interp, name in mapping: bootstrap_crv = bootstrap(*args) dates, nodes = zip(*bootstrap_crv.nodes()) equivalent_crv = interp(dates, nodes, self.dayCounter) for d in dates: expected = equivalent_crv.zeroRate( d, self.dayCounter, ql.Continuous, ql.NoFrequency).rate() actual = bootstrap_crv.zeroRate( d, self.dayCounter, ql.Continuous, ql.NoFrequency).rate() failMsg = """ Interpolation check failed for: interpolation: {interpolation} expected zero rate: {expected} actual zero rate: {actual} """.format(interpolation=name, expected=expected, actual=actual) self.assertAlmostEqual( first=expected, second=actual, delta=1.0e-12, msg=failMsg) def testInterpolatedPiecewiseZeroSpreadedTermStructure(self): """Testing different interpolation schemes for zero spreaded term structure""" h = ql.RelinkableYieldTermStructureHandle() h.linkTo(self.termStructure) spreads = [(1, 0.005), (2, 0.008), (3, 0.0103), (4, 0.0145), (5, 0.025)] dates, quotes = zip(*[(h.referenceDate() + ql.Period(t, ql.Years), ql.QuoteHandle(ql.SimpleQuote(s))) for t, s in spreads]) args = [h, quotes, dates] constructors = [ql.SpreadedLinearZeroInterpolatedTermStructure, ql.SpreadedBackwardFlatZeroInterpolatedTermStructure, ql.SpreadedCubicZeroInterpolatedTermStructure, ql.SpreadedKrugerZeroInterpolatedTermStructure, ql.SpreadedSplineCubicZeroInterpolatedTermStructure] for constructor in constructors: spreadedTs = constructor(*args) for d, r in zip(dates, quotes): expected = r.value() zeroFromSpreadTS = spreadedTs.zeroRate( d, self.dayCounter, ql.Continuous, ql.NoFrequency).rate() zeroFromBaseTs = h.zeroRate( d, self.dayCounter, ql.Continuous, ql.NoFrequency).rate() actual = zeroFromSpreadTS - zeroFromBaseTs failMsg = """ Interpolated piecewise zero spreaded term structure zero rate replication failed for: maturity: {maturity} expected zero rate: {expected} actual zero rate: {actual} """.format(maturity=d, expected=expected, actual=actual) self.assertAlmostEqual( first=expected, second=actual, delta=1.0e-12, msg=failMsg) def testQuantoTermStructure(self): """Testing quanto term structure""" today = ql.Date.todaysDate() dividend_ts = ql.YieldTermStructureHandle( ql.FlatForward( today, ql.makeQuoteHandle(0.055), self.dayCounter ) ) r_domestic_ts = ql.YieldTermStructureHandle( ql.FlatForward( today, ql.makeQuoteHandle(-0.01), self.dayCounter ) ) r_foreign_ts = ql.YieldTermStructureHandle( ql.FlatForward( today, ql.makeQuoteHandle(0.02), self.dayCounter ) ) sigma_s = ql.BlackVolTermStructureHandle( ql.BlackConstantVol( today, self.calendar, ql.makeQuoteHandle(0.25), self.dayCounter ) ) sigma_fx = ql.BlackVolTermStructureHandle( ql.BlackConstantVol( today, self.calendar, ql.makeQuoteHandle(0.05), self.dayCounter ) ) rho = ql.makeQuoteHandle(0.3) s_0 = ql.makeQuoteHandle(100.0) exercise = ql.EuropeanExercise(self.calendar.advance(today, 6, ql.Months)) payoff = ql.PlainVanillaPayoff(ql.Option.Call, 95.0) vanilla_option = ql.VanillaOption(payoff, exercise) quanto_ts = ql.YieldTermStructureHandle( ql.QuantoTermStructure( dividend_ts, r_domestic_ts, r_foreign_ts, sigma_s, ql.nullDouble(), sigma_fx, ql.nullDouble(), rho.value() ) ) gbm_quanto = ql.BlackScholesMertonProcess(s_0, quanto_ts, r_domestic_ts, sigma_s) vanilla_engine = ql.AnalyticEuropeanEngine(gbm_quanto) vanilla_option.setPricingEngine(vanilla_engine) quanto_option = ql.QuantoVanillaOption(payoff, exercise) gbm_vanilla = ql.BlackScholesMertonProcess(s_0, dividend_ts, r_domestic_ts, sigma_s) quanto_engine = ql.QuantoEuropeanEngine(gbm_vanilla, r_foreign_ts, sigma_fx, rho) quanto_option.setPricingEngine(quanto_engine) quanto_option_pv = quanto_option.NPV() vanilla_option_pv = vanilla_option.NPV() message = """Failed to reproduce QuantoOption / EuropeanQuantoEngine NPV: {quanto_pv} by using the QuantoTermStructure as the dividend together with VanillaOption / AnalyticEuropeanEngine: {vanilla_pv} """.format( quanto_pv=quanto_option_pv, vanilla_pv=vanilla_option_pv ) self.assertAlmostEqual( quanto_option_pv, vanilla_option_pv, delta=1e-12, msg=message ) def testLazyObject(self): evaluationDate = ql.Settings.instance().evaluationDate nodes = self.termStructure.nodes() self.termStructure.freeze() ql.Settings.instance().evaluationDate = self.calendar.advance(evaluationDate, 100, ql.Days) # Check that dates and rates are unchanged for i in range(len(self.termStructure.nodes())): self.assertEqual(nodes[i][0], self.termStructure.nodes()[i][0]) self.assertEqual(nodes[i][1], self.termStructure.nodes()[i][1]) self.termStructure.recalculate() # Check that dates have changed (except the reference, which is fixed) for i in range(1, len(self.termStructure.nodes())): self.assertNotEqual(nodes[i][0], self.termStructure.nodes()[i][0]) ql.Settings.instance().evaluationDate = evaluationDate self.termStructure.unfreeze() if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/test/test_volatilities.py000066400000000000000000000607031503741206100223220ustar00rootroot00000000000000""" Copyright (C) 2020 Marcin Rybacki Copyright (C) 2022 Skandinaviska Enskilda Banken AB (publ) This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. """ import unittest import math import QuantLib as ql TOLERANCE = 1e-10 if ql.IborCoupon.usingAtParCoupons() else 1e-6 SABR_ATM_TOLERANCE = 3.0e-4 SABR_SPREAD_TOLERANCE = 12.0e-4 CAL = ql.TARGET() # Data source: # https://quantlib-python-docs.readthedocs.io/en/latest/termstructures.html#swaption-volatility ATM_NORM_VOLS = ( (0.0086, 0.00128, 0.00195, 0.00269, 0.00327, 0.00361, 0.00387, 0.00409, 0.00427, 0.00443, 0.00488, 0.00504, 0.00508, 0.00504), (0.0092, 0.00134, 0.00197, 0.00264, 0.00319, 0.00352, 0.00383, 0.00402, 0.00419, 0.00431, 0.00478, 0.00499, 0.00507, 0.00503), (0.00112, 0.00153, 0.00210, 0.00276, 0.00327, 0.00353, 0.00384, 0.00408, 0.00426, 0.00445, 0.00486, 0.00505, 0.00509, 0.00510), (0.00129, 0.00171, 0.00226, 0.00288, 0.00335, 0.00360, 0.00388, 0.00410, 0.00430, 0.00446, 0.00487, 0.00506, 0.00511, 0.00510), (0.00146, 0.00187, 0.00246, 0.00301, 0.00342, 0.00369, 0.00393, 0.00413, 0.00432, 0.00449, 0.00489, 0.00510, 0.00513, 0.00515), (0.00165, 0.00209, 0.00263, 0.00313, 0.00350, 0.00376, 0.00400, 0.00420, 0.00437, 0.00453, 0.00488, 0.00509, 0.00514, 0.00517), (0.00209, 0.00253, 0.00300, 0.00340, 0.00370, 0.00395, 0.00419, 0.00434, 0.00450, 0.00464, 0.00493, 0.00510, 0.00513, 0.00519), (0.00251, 0.00289, 0.00332, 0.00362, 0.00392, 0.00412, 0.00432, 0.00447, 0.00460, 0.00473, 0.00496, 0.00510, 0.00513, 0.00516), (0.00340, 0.00366, 0.00392, 0.00411, 0.00432, 0.00445, 0.00461, 0.00472, 0.00480, 0.00490, 0.00503, 0.00513, 0.00513, 0.00512), (0.00403, 0.00418, 0.00436, 0.00449, 0.00461, 0.00471, 0.00482, 0.00492, 0.00499, 0.00505, 0.00512, 0.00513, 0.00509, 0.00507), (0.00440, 0.00448, 0.00460, 0.00471, 0.00484, 0.00491, 0.00499, 0.00507, 0.00514, 0.00519, 0.00516, 0.00514, 0.00506, 0.00502), (0.00496, 0.00497, 0.00504, 0.00512, 0.00518, 0.00522, 0.00526, 0.00529, 0.00533, 0.00538, 0.00526, 0.00517, 0.00504, 0.00496), (0.00539, 0.00537, 0.00540, 0.00542, 0.00544, 0.00545, 0.00545, 0.00544, 0.00544, 0.00549, 0.00531, 0.00518, 0.00501, 0.00491), (0.00540, 0.00537, 0.00538, 0.00537, 0.00535, 0.00536, 0.00535, 0.00533, 0.00535, 0.00537, 0.00514, 0.00498, 0.00479, 0.00466), (0.00528, 0.00524, 0.00526, 0.00523, 0.00522, 0.00523, 0.00520, 0.00519, 0.00518, 0.00518, 0.00495, 0.00474, 0.00454, 0.00438), (0.00514, 0.00512, 0.00513, 0.00510, 0.00508, 0.00507, 0.00503, 0.00499, 0.00498, 0.00497, 0.00476, 0.00453, 0.00431, 0.00414), (0.00496, 0.00496, 0.00497, 0.00495, 0.00495, 0.00492, 0.00486, 0.00479, 0.00474, 0.00471, 0.00451, 0.00429, 0.00408, 0.00392)) ATM_NORM_VOL_OPT_TENORS = (ql.Period(1, ql.Months), ql.Period(2, ql.Months), ql.Period(3, ql.Months), ql.Period(6, ql.Months), ql.Period(9, ql.Months), ql.Period(1, ql.Years), ql.Period(18, ql.Months), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(4, ql.Years), ql.Period(5, ql.Years), ql.Period(7, ql.Years), ql.Period(10, ql.Years), ql.Period(15, ql.Years), ql.Period(20, ql.Years), ql.Period(25, ql.Years), ql.Period(30, ql.Years)) ATM_NORM_VOL_SWAP_TENORS = (ql.Period(1, ql.Years), ql.Period(2, ql.Years), ql.Period(3, ql.Years), ql.Period(4, ql.Years), ql.Period(5, ql.Years), ql.Period(6, ql.Years), ql.Period(7, ql.Years), ql.Period(8, ql.Years), ql.Period(9, ql.Years), ql.Period(10, ql.Years), ql.Period(15, ql.Years), ql.Period(20, ql.Years), ql.Period(25, ql.Years), ql.Period(30, ql.Years)) ATM_LOGNORM_VOLS = ( (0.1300, 0.1560, 0.1390, 0.1220), (0.1440, 0.1580, 0.1460, 0.1260), (0.1600, 0.1590, 0.1470, 0.1290), (0.1640, 0.1470, 0.1370, 0.1220), (0.1400, 0.1300, 0.1250, 0.1100), (0.1130, 0.1090, 0.1070, 0.0930)) ATM_LOGNORM_VOL_OPT_TENORS = (ql.Period(1, ql.Months), ql.Period(6, ql.Months), ql.Period(3, ql.Years), ql.Period(5, ql.Years), ql.Period(10, ql.Years), ql.Period(25, ql.Years)) ATM_LOGNORM_VOL_SWAP_TENORS = (ql.Period(1, ql.Years), ql.Period(3, ql.Years), ql.Period(10, ql.Years), ql.Period(25, ql.Years)) SMILE_OPT_TENORS = (ql.Period(1, ql.Years), ql.Period(10, ql.Years), ql.Period(30, ql.Years)) SMILE_SWAP_TENORS = (ql.Period(2, ql.Years), ql.Period(10, ql.Years), ql.Period(30, ql.Years)) STRIKE_SPREADS = (-0.02, -0.005, 0.0, 0.005, 0.02) NORM_VOL_SPREADS = ( (-0.0006, 0.0005, 0.0, 0.0006, 0.0006), (-0.0006, 0.0005, 0.0, 0.00065, 0.0006), (-0.0006, 0.0001, 0.0, 0.0006, 0.0006), (-0.0006, 0.0005, 0.0, 0.0006, 0.0006), (-0.0006, 0.0005, 0.0, 0.0006, 0.0006), (-0.0003, 0.0005, 0.0, 0.0003, 0.0003), (-0.0006, 0.0005, 0.0, 0.0006, 0.0006), (-0.0006, 0.0005, 0.0, 0.0006, 0.0006), (-0.0003, 0.0005, 0.0, 0.0003, 0.0003)) LOGNORM_VOL_SPREADS = ( (0.0599, 0.0049, 0.0000, -0.0001, 0.0127), (0.0729, 0.0086, 0.0000, -0.0024, 0.0098), (0.0738, 0.0102, 0.0000, -0.0039, 0.0065), (0.0465, 0.0063, 0.0000, -0.0032, -0.0010), (0.0558, 0.0084, 0.0000, -0.0050, -0.0057), (0.0576, 0.0083, 0.0000, -0.0043, -0.0014), (0.0437, 0.0059, 0.0000, -0.0030, -0.0006), (0.0533, 0.0078, 0.0000, -0.0045, -0.0046), (0.0545, 0.0079, 0.0000, -0.0042, -0.0020)) ZERO_COUPON_DATA = ( (ql.Period(1, ql.Days), 0.013), (ql.Period(1, ql.Years), 0.013), (ql.Period(2, ql.Years), 0.015), (ql.Period(3, ql.Years), 0.016), (ql.Period(4, ql.Years), 0.017), (ql.Period(5, ql.Years), 0.019), (ql.Period(10, ql.Years), 0.021), (ql.Period(15, ql.Years), 0.024), (ql.Period(20, ql.Years), 0.026), (ql.Period(30, ql.Years), 0.029)) NORM_VOL_MATRIX = ql.SwaptionVolatilityMatrix( CAL, ql.ModifiedFollowing, ATM_NORM_VOL_OPT_TENORS, ATM_NORM_VOL_SWAP_TENORS, ql.Matrix(ATM_NORM_VOLS), ql.Actual365Fixed(), False, ql.Normal) LOGNORM_VOL_MATRIX = ql.SwaptionVolatilityMatrix( CAL, ql.ModifiedFollowing, ATM_LOGNORM_VOL_OPT_TENORS, ATM_LOGNORM_VOL_SWAP_TENORS, ql.Matrix(ATM_LOGNORM_VOLS), ql.Actual365Fixed(), False, ql.ShiftedLognormal) def build_euribor_swap_idx( projection_curve_handle): return ql.EuriborSwapIsdaFixA(ql.Period(1, ql.Years), projection_curve_handle) def build_nominal_term_structure(valuation_date, nominal_quotes): dates, rates = zip(*[(CAL.advance(valuation_date, x[0]), x[1]) for x in nominal_quotes]) crv = ql.ZeroCurve(dates, rates, ql.Actual365Fixed()) crv.enableExtrapolation() return crv def build_linear_swaption_cube( volatility_matrix, spread_opt_tenors, spread_swap_tenors, strike_spreads, vol_spreads, swap_index_base, short_swap_index_base=None, vega_weighted_smile_fit=False): vol_spreads = [[ql.makeQuoteHandle(v) for v in row] for row in vol_spreads] cube = ql.InterpolatedSwaptionVolatilityCube( ql.SwaptionVolatilityStructureHandle(volatility_matrix), spread_opt_tenors, spread_swap_tenors, strike_spreads, vol_spreads, swap_index_base, short_swap_index_base if short_swap_index_base else swap_index_base, vega_weighted_smile_fit) cube.enableExtrapolation() return cube def sabr_parameters_guess(number_of_options, number_of_swaps): n_elements = number_of_options * number_of_swaps guess = n_elements * [0] for n in range(n_elements): guess[n] = (ql.makeQuoteHandle(0.2), ql.makeQuoteHandle(0.5), ql.makeQuoteHandle(0.4), ql.makeQuoteHandle(0.0)) return guess def build_sabr_swaption_cube( volatility_matrix, spread_opt_tenors, spread_swap_tenors, strike_spreads, vol_spreads, swap_index_base, short_swap_index_base=None, vega_weighted_smile_fit=False, is_parameter_fixed=(False, False, False, False), is_atm_calibrated=True): v_spreads = [[ql.makeQuoteHandle(v) for v in row] for row in vol_spreads] guess = sabr_parameters_guess( len(spread_opt_tenors), len(spread_swap_tenors)) cube = ql.SabrSwaptionVolatilityCube( ql.SwaptionVolatilityStructureHandle(volatility_matrix), spread_opt_tenors, spread_swap_tenors, strike_spreads, v_spreads, swap_index_base, short_swap_index_base if short_swap_index_base else swap_index_base, vega_weighted_smile_fit, guess, is_parameter_fixed, is_atm_calibrated) cube.enableExtrapolation() return cube class SwaptionVolatilityCubeTest(unittest.TestCase): def setUp(self): self.today = CAL.adjust(ql.Date.todaysDate()) ql.Settings.instance().evaluationDate = self.today curve_handle = ql.RelinkableYieldTermStructureHandle() curve = build_nominal_term_structure(self.today, ZERO_COUPON_DATA) curve_handle.linkTo(curve) self.idx = ql.Euribor6M(curve_handle) self.swap_idx = build_euribor_swap_idx(curve_handle) self.swap_engine = ql.DiscountingSwapEngine(curve_handle) def tearDown(self): ql.Settings.instance().evaluationDate = ql.Date() def _get_fair_rate(self, exercise_date, swap_tenor): start_date = CAL.advance(exercise_date, ql.Period(2, ql.Days)) underlying = ql.MakeVanillaSwap( swap_tenor, self.idx, 0.0, ql.Period(0, ql.Days), effectiveDate=start_date, fixedLegTenor=ql.Period(1, ql.Years), fixedLegDayCount=ql.Thirty360(ql.Thirty360.BondBasis), floatingLegSpread=0.0, swapType=ql.Swap.Receiver) underlying.setPricingEngine(self.swap_engine) return underlying.fairRate() def _assert_atm_strike( self, cube, interpolation, vol_type): opt_tenor = ql.Period(1, ql.Years) swap_tenor = ql.Period(10, ql.Years) exercise_date = cube.optionDateFromTenor(opt_tenor) expected_atm_strike = self._get_fair_rate(exercise_date, swap_tenor) actual_atm_strike = cube.atmStrike(exercise_date, swap_tenor) fail_msg = """ ATM strike test failed for: cube interpolation: {interpolation} volatility_type: {vol_type} option tenor: {option_tenor} swap tenor: {swap_tenor} strike: {strike} replicated strike: {replicated_strike} """.format(interpolation=interpolation, vol_type=vol_type, option_tenor=opt_tenor, swap_tenor=swap_tenor, strike=actual_atm_strike, replicated_strike=expected_atm_strike) self.assertAlmostEqual( first=actual_atm_strike, second=expected_atm_strike, delta=TOLERANCE, msg=fail_msg) def _assert_atm_vol( self, cube, opt_tenor, swap_tenor, expected_vol, interpolation, vol_type, epsilon=TOLERANCE): option_date = cube.optionDateFromTenor(opt_tenor) strike = cube.atmStrike(option_date, swap_tenor) actual_vol = cube.volatility(option_date, swap_tenor, strike) fail_msg = """ ATM vol test failed for: cube interpolation: {interpolation} volatility_type: {vol_type} option tenor: {option_tenor} swap tenor: {swap_tenor} strike: {strike} volatility: {vol} expected volatility: {expected_vol} epsilon: {eps} """.format(interpolation=interpolation, vol_type=vol_type, option_tenor=opt_tenor, swap_tenor=swap_tenor, strike=strike, vol=actual_vol, expected_vol=expected_vol, eps=epsilon) self.assertAlmostEqual( first=actual_vol, second=expected_vol, delta=epsilon, msg=fail_msg) def _assert_vol_spread( self, cube, opt_tenor, swap_tenor, strike_spread, expected_vol, interpolation, vol_type, epsilon=TOLERANCE): option_date = cube.optionDateFromTenor(opt_tenor) strike = cube.atmStrike(option_date, swap_tenor) + strike_spread actual_vol = cube.volatility(option_date, swap_tenor, strike) fail_msg = """ Vol spread test failed for: cube interpolation: {interpolation} volatility_type: {vol_type} option tenor: {option_tenor} swap tenor: {swap_tenor} strike: {strike} volatility: {vol} expected volatility: {expected_vol} epsilon: {eps} """.format(interpolation=interpolation, vol_type=vol_type, option_tenor=opt_tenor, swap_tenor=swap_tenor, strike=strike, vol=actual_vol, expected_vol=expected_vol, eps=epsilon) self.assertAlmostEqual( first=actual_vol, second=expected_vol, delta=epsilon, msg=fail_msg) def test_linear_normal_cube_at_the_money_strike(self): """Testing ATM strike for linearly interpolated normal vol cube""" linear_cube = build_linear_swaption_cube( NORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, NORM_VOL_SPREADS, self.swap_idx) self._assert_atm_strike( cube=linear_cube, interpolation='linear', vol_type='normal') def test_linear_lognormal_cube_at_the_money_strike(self): """Testing ATM strike for linearly interpolated log-normal vol cube""" linear_cube = build_linear_swaption_cube( LOGNORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, LOGNORM_VOL_SPREADS, self.swap_idx) self._assert_atm_strike( cube=linear_cube, interpolation='linear', vol_type='log-normal') def test_sabr_lognormal_cube_at_the_money_strike(self): """Testing ATM strike for SABR interpolated log-normal vol cube""" sabr_cube = build_sabr_swaption_cube( LOGNORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, LOGNORM_VOL_SPREADS, self.swap_idx) self._assert_atm_strike( cube=sabr_cube, interpolation='SABR', vol_type='log-normal') def test_linear_normal_cube_at_the_money_vol(self): """Testing ATM volatility for linearly interpolated normal vol cube""" linear_cube = build_linear_swaption_cube( NORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, NORM_VOL_SPREADS, self.swap_idx) self._assert_atm_vol( cube=linear_cube, opt_tenor=ql.Period(1, ql.Years), swap_tenor=ql.Period(10, ql.Years), expected_vol=0.00453, interpolation='linear', vol_type='normal') def test_linear_lognormal_cube_at_the_money_vol(self): """Testing ATM volatility for linearly interpolated log-normal vol cube""" linear_cube = build_linear_swaption_cube( LOGNORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, LOGNORM_VOL_SPREADS, self.swap_idx) self._assert_atm_vol( cube=linear_cube, opt_tenor=ql.Period(10, ql.Years), swap_tenor=ql.Period(10, ql.Years), expected_vol=0.1250, interpolation='linear', vol_type='log-normal') def test_sabr_lognormal_cube_at_the_money_vol(self): """Testing ATM volatility for SABR interpolated log-normal vol cube""" sabr_cube = build_sabr_swaption_cube( LOGNORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, LOGNORM_VOL_SPREADS, self.swap_idx) self._assert_atm_vol( cube=sabr_cube, opt_tenor=ql.Period(10, ql.Years), swap_tenor=ql.Period(10, ql.Years), expected_vol=0.1250, interpolation='SABR', vol_type='log-normal', epsilon=SABR_ATM_TOLERANCE) def test_linear_normal_cube_spread_vol(self): """Testing spread volatility for linearly interpolated normal cube""" linear_cube = build_linear_swaption_cube( NORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, NORM_VOL_SPREADS, self.swap_idx) self._assert_vol_spread( cube=linear_cube, opt_tenor=ql.Period(1, ql.Years), swap_tenor=ql.Period(10, ql.Years), strike_spread=-0.02, expected_vol=0.00453 - 0.0006, interpolation='linear', vol_type='normal') def test_linear_lognormal_cube_spread_vol(self): """Testing spread volatility for linearly interpolated log-normal cube""" linear_cube = build_linear_swaption_cube( LOGNORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, LOGNORM_VOL_SPREADS, self.swap_idx) self._assert_vol_spread( cube=linear_cube, opt_tenor=ql.Period(10, ql.Years), swap_tenor=ql.Period(10, ql.Years), strike_spread=-0.02, expected_vol=0.125 + 0.0558, interpolation='linear', vol_type='log-normal') def test_sabr_lognormal_cube_spread_vol(self): """Testing spread volatility for SABR interpolated log-normal cube""" sabr_cube = build_sabr_swaption_cube( LOGNORM_VOL_MATRIX, SMILE_OPT_TENORS, SMILE_SWAP_TENORS, STRIKE_SPREADS, LOGNORM_VOL_SPREADS, self.swap_idx) self._assert_vol_spread( cube=sabr_cube, opt_tenor=ql.Period(10, ql.Years), swap_tenor=ql.Period(10, ql.Years), strike_spread=-0.02, expected_vol=0.125 + 0.0558, interpolation='SABR', vol_type='log-normal', epsilon=SABR_SPREAD_TOLERANCE) class SviSmileSectionTest(unittest.TestCase): def setUp(self): ql.Settings.instance().evaluationDate = ql.Date(3, ql.May, 2022) def tearDown(self): # The objects created in this test are not immediately garbage-collected # by PyPy, and can throw errors when the global evaluation date changes. # Thus, we need to force a collection when we're done with them. import gc gc.collect() def test_svi_smile_section(self): """Testing the SviSmileSection against already fitted parameters""" expiry_date = ql.Date(16, ql.December, 2022) forward = 100 atm_vol = 0.325819 # parameters = a, b, sigma, rho, m svi_parameters = [-0.651304, 0.986546, 0.838493, 0.520853, 0.695177] smile = ql.SviSmileSection(expiry_date, forward, svi_parameters) self.assertAlmostEqual(smile.volatility(forward), atm_vol, places=5) self.assertAlmostEqual(smile.volatility(257.328), 0.739775, places=5) def test_svi_interpolated_smile_section(self): """Testing the SviInterpolatedSmileSection's parameter fitting against given vols""" expiry_date = ql.Date(16, ql.December, 2022) forward = 100 strikes = [25.6134, 48.5585, 71.5027, 94.4478, 117.3920, 140.3372, 163.2814, 186.2265, 209.1707, 232.1149] has_floating_strikes = False atm_vol = 0.325819 vols = [0.881504, 0.627807, 0.456964, 0.343740, 0.297482, 0.321816, 0.390772, 0.476758, 0.565635, 0.651507] a = -0.6 b = 0.9 sigma = 0.8 rho = 0.5 m = 0.6 interpolated_smile = ql.SviInterpolatedSmileSection( expiry_date, forward, strikes, has_floating_strikes, atm_vol, vols, a, b, sigma, rho, m, False, False, False, False, False ) self.assertAlmostEqual(interpolated_smile.volatility(forward), atm_vol, places=5) self.assertAlmostEqual(interpolated_smile.volatility(257.328), 0.739775, places=5) class AndreasenHugeVolatilityTest(unittest.TestCase): def testLocalVolCalibration(self): """ Testing Andreasen-Huge Local Volatility calibration""" today = ql.Settings.instance().evaluationDate spot = ql.makeQuoteHandle(100) dc = ql.Actual365Fixed() qTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.025, dc)) rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, dc)) vol_data = [ # maturity in days, strike, volatility (30, 75, 0.13), (30, 100, 0.26), (30, 125, 0.3), (180, 80, 0.4), (180, 150, 0.6), (365, 110, 0.5)] calibration_set = ql.CalibrationSet( [( ql.VanillaOption( ql.PlainVanillaPayoff(ql.Option.Call, strike), ql.EuropeanExercise(today + ql.Period(maturity_in_days, ql.Days)) ), ql.SimpleQuote(volatility) ) for maturity_in_days, strike, volatility in vol_data] ) local_vol = ql.LocalVolTermStructureHandle( ql.AndreasenHugeLocalVolAdapter( ql.AndreasenHugeVolatilityInterpl(calibration_set, spot, rTS, qTS) ) ) option = calibration_set[-2][0] # maturity in days: 180, strike: 150, vol: 0.6 dummy_vol = ql.BlackVolTermStructureHandle() local_vol_process = ql.GeneralizedBlackScholesProcess(spot, qTS, rTS, dummy_vol, local_vol) option.setPricingEngine(ql.MCEuropeanEngine( local_vol_process, "lowdiscrepancy", timeSteps=75, brownianBridge=True, requiredSamples=16000, seed=42) ) t = dc.yearFraction(today, option.exercise().lastDate()) fwd = spot.value() * qTS.discount(t) / rTS.discount(t) vol = calibration_set[-2][1].value() expected = ql.BlackCalculator( ql.as_plain_vanilla_payoff(option.payoff()), fwd, vol * math.sqrt(t), rTS.discount(t)).value() self.assertAlmostEqual(expected, option.NPV(), delta=0.2) if __name__ == "__main__": print("testing QuantLib", ql.__version__) unittest.main(verbosity=2) QuantLib-SWIG-1.39/Python/tox.ini000066400000000000000000000002041503741206100165230ustar00rootroot00000000000000[tox] requires = tox>=4 [testenv] description = run unit tests deps = pytest package = wheel commands = pytest {posargs:test} QuantLib-SWIG-1.39/R/000077500000000000000000000000001503741206100141345ustar00rootroot00000000000000QuantLib-SWIG-1.39/R/.Rinstignore000066400000000000000000000000701503741206100164350ustar00rootroot00000000000000Makefile Makefile.am Makefile.in makeRData.R README.txt QuantLib-SWIG-1.39/R/.gitignore000066400000000000000000000001231503741206100161200ustar00rootroot00000000000000src/QuantLib.cpp makeRData.Rout src/symbols.rds Rcheck R/QuantLib.R QuantLib.RData QuantLib-SWIG-1.39/R/DESCRIPTION000066400000000000000000000005421503741206100156430ustar00rootroot00000000000000Package: QuantLib Title: QuantLib bindings for R Version: 1.39 Date: $Date$ Maintainer: Dirk Eddelbuettel Author: The QuantLib Group Description: This package provides the SWIG-generated QuantLib bindings for R Depends: methods SystemRequirements: QuantLib library, Boost library License: QuantLib License URL: https://www.quantlib.org QuantLib-SWIG-1.39/R/DESCRIPTION.in000066400000000000000000000005651503741206100162550ustar00rootroot00000000000000Package: QuantLib Title: QuantLib bindings for R Version: @PACKAGE_VERSION_FOR_R@ Date: $Date$ Maintainer: Dirk Eddelbuettel Author: The QuantLib Group Description: This package provides the SWIG-generated QuantLib bindings for R Depends: methods SystemRequirements: QuantLib library, Boost library License: QuantLib License URL: https://www.quantlib.org QuantLib-SWIG-1.39/R/Makefile.am000066400000000000000000000016711503741206100161750ustar00rootroot00000000000000QUANTLIB_R_ROOT = QuantLib BUILT_SOURCES = src/$(QUANTLIB_R_ROOT).cpp R/$(QUANTLIB_R_ROOT).R CLEANFILES = $(BUILT_SOURCES) .build-stamp QUANTLIB_CONFIG=quantlib-config if HAVE_R if BUILD_R all-local: .build-stamp .build-stamp: $(BUILT_SOURCES) ## R is better at checking from above than within cd .. && R CMD check R && cd - touch .build-stamp check-local: .build-stamp install-exec-local: .build-stamp R CMD INSTALL . endif endif $(BUILT_SOURCES): ../SWIG/*.i $(SWIG) $(SWIGFLAGS) -r -c++ -o src/$(QUANTLIB_R_ROOT).cpp ../SWIG/quantlib.i mv src/$(QUANTLIB_R_ROOT).R R/ dist-hook: mkdir -p $(distdir)/demo cp ./demo/00Index $(distdir)/demo cp ./demo/*.R $(distdir)/demo clean-local: rm -rf $(BUILT_SOURCES) ../R.Rcheck \ src/symbols.rds src/$(QUANTLIB_R_ROOT).o src/$(QUANTLIB_R_ROOT).so EXTRA_DIST = DESCRIPTION NAMESPACE README.txt cleanup \ $(BUILT_SOURCES) \ R/README src/Makevars QuantLib-SWIG-1.39/R/NAMESPACE000066400000000000000000000002501503741206100153500ustar00rootroot00000000000000 ## This NAMESPACE file declares which symbols are being exported, ## and which dynamic library needs to be loaded. useDynLib(QuantLib) exportPattern("^[[:alpha:]]+") QuantLib-SWIG-1.39/R/R/000077500000000000000000000000001503741206100143355ustar00rootroot00000000000000QuantLib-SWIG-1.39/R/R/README000066400000000000000000000002121503741206100152100ustar00rootroot00000000000000The SWIG build process creates a file QuantLib.R which will be moved into this directory when the package is prepared by the 'make' step. QuantLib-SWIG-1.39/R/README.txt000066400000000000000000000022321503741206100156310ustar00rootroot00000000000000 Updated July 2013 The new build process creates sources for a standard R packages which can be installed from this directory via R CMD INSTALL . Dirk Eddelbuettel edd@debian.org ======================================================================== This is the R interface to QuantLib. The needed C++ bindings are created by means of SWIG (Simplified Wrapper and Interface Generator) available from . SWIG version 1.3.32 is needed. SWIG 1.3.31 generates a .R called QuantLib_wrap.R instead of QuantLib.R. The Makefile.am and makeRData.R has commented sections which can be used with SWIG 1.3.31 The command make generates the R library QuantLib.so and the wrapper script QuantLib_wrap.R and a compiled wrapper QuantLib.RData. Once you've compiled this you can load with dyn.load('QuantLib.so') load('QuantLib.RData') cacheMetaData(1) The last line is to work around a bug that causes S4 methods not to get loaded correctly. You can also load the uncompiled wrapper file dyn.load('QuantLib_wrap.so') source('QuantLib.R') Please contact Joseph Wang - joequant@gmail.org if you have any comments or additions. QuantLib-SWIG-1.39/R/cleanup000077500000000000000000000000531503741206100155070ustar00rootroot00000000000000#!/bin/bash rm -f src/*.o src/*.so src/*~ QuantLib-SWIG-1.39/R/demo/000077500000000000000000000000001503741206100150605ustar00rootroot00000000000000QuantLib-SWIG-1.39/R/demo/00Index000066400000000000000000000005211503741206100162100ustar00rootroot00000000000000european-option European Option fd-option Finite-Differences Option graph Graph demo scatter Scatter plot wireframe Wireframe bonds Zero Coupon, Fixed Rate and Floating Rate Bonds bates_vol_surface Bates Stochastic Volatility curves Sanity check for exported curves QuantLib-SWIG-1.39/R/demo/american-option.R000066400000000000000000000045261503741206100202770ustar00rootroot00000000000000 suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() settlementDate <- Date(15, "May", 1998) settlementDate <- Calendar_adjust(calendar, settlementDate) fixingDays <- 3 settlementDays <- 3 todaysDate <- Calendar_advance(calendar, settlementDate, -fixingDays, "Days") invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) cat('Today : ', todaysDate$`__str__`(), "\n") cat('Settlement Date: ', settlementDate$`__str__`(), "\n") ## option exercise = AmericanExercise(todaysDate, Date(17, "May", 1999)) payoff = PlainVanillaPayoff("Put", 40.0) option = VanillaOption(payoff, exercise) # ### Market data # %% underlying = SimpleQuote(36.0) dividendYield = FlatForward(todaysDate, 0.00, Actual365Fixed()) volatility = BlackConstantVol(todaysDate, calendar, 0.20, Actual365Fixed()) riskFreeRate = FlatForward(todaysDate, 0.06, Actual365Fixed()) # %% process = BlackScholesMertonProcess( QuoteHandle(underlying), YieldTermStructureHandle(dividendYield), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility) ) # ### Pricing # We'll collect tuples of method name, option value, and estimated error from the analytic formula. # %% results = NULL # #### Analytic approximations option$setPricingEngine(BaroneAdesiWhaleyApproximationEngine(process)) results = rbind(results, data.frame("method"="Barone-Adesi-Whaley", "NPV"=option$NPV())) option$setPricingEngine(BjerksundStenslandApproximationEngine(process)) results = rbind(results, data.frame("method"="Bjerksund-Stensland", "NPV"=option$NPV())) # #### Finite-difference method timeSteps = 801 gridPoints = 800 option$setPricingEngine(FdBlackScholesVanillaEngine(process, timeSteps, gridPoints)) results = rbind(results, data.frame("method"="finite differences", "NPV"=option$NPV())) # #### Binomial method timeSteps = 801 # %% listEngineFuncsNames = lsf.str("package:QuantLib") listEngineFuncsNames = listEngineFuncsNames[grepl(pattern = "^Binomial", x = listEngineFuncsNames)] listEngineFuncsNames = listEngineFuncsNames[grepl(pattern = "VanillaEngine$", x = listEngineFuncsNames)] for (engineFuncName in listEngineFuncsNames) { eval(parse(text=paste0("option$setPricingEngine(", engineFuncName, "(process, timeSteps))"))) results = rbind(results, data.frame("method"=engineFuncName, "NPV"=option$NPV())) } # ### Results print(results) QuantLib-SWIG-1.39/R/demo/basket-option.R000066400000000000000000000070021503741206100177610ustar00rootroot00000000000000 # inspired by python example with the same name suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() todaysDate <- Date(15, "May", 1998) invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDays <- 3 settlementDate <- Calendar_advance(calendar, todaysDate, settlementDays, "Days") cat('Today : ', todaysDate$`__str__`(), "\n") cat('Settlement Date: ', settlementDate$`__str__`(), "\n") riskFreeRate = FlatForward(settlementDate, 0.05, Actual365Fixed()) # ### Option parameters exerciseDate = Date(17, "May", 1999) exercise = EuropeanExercise(exerciseDate) payoff = PlainVanillaPayoff("Call", 8.0) # ### Market data underlying1 = SimpleQuote(7.0) volatility1 = BlackConstantVol(todaysDate, calendar, 0.10, Actual365Fixed()) dividendYield1 = FlatForward(settlementDate, 0.05, Actual365Fixed()) underlying2 = SimpleQuote(7.0) volatility2 = BlackConstantVol(todaysDate, calendar, 0.10, Actual365Fixed()) dividendYield2 = FlatForward(settlementDate, 0.05, Actual365Fixed()) process1 = BlackScholesMertonProcess( QuoteHandle(underlying1), YieldTermStructureHandle(dividendYield1), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility1) ) process2 = BlackScholesMertonProcess( QuoteHandle(underlying2), YieldTermStructureHandle(dividendYield2), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility2) ) corrMatrix = Matrix(2, 2) invisible(Matrix_setitem(corrMatrix, 0, 0, 1.0)) invisible(Matrix_setitem(corrMatrix, 1, 1, 1.0)) invisible(Matrix_setitem(corrMatrix, 1, 0, 0.5)) invisible(Matrix_setitem(corrMatrix, 0, 1, 0.5)) cat(corrMatrix$`__str__`()) procVector = StochasticProcess1DVector(2) invisible(StochasticProcess1DVector___setitem__(self = procVector, i = 0, x = process1)) invisible(StochasticProcess1DVector___setitem__(self = procVector, i = 1, x = process2)) process = StochasticProcessArray(array = procVector, correlation = corrMatrix) # ### Pricing - European basketoption = BasketOption(MaxBasketPayoff(payoff), exercise) basketoption$setPricingEngine( MCPREuropeanBasketEngine(process=process, timeSteps=NA, timeStepsPerYear=1, brownianBridge=F, antitheticVariate=F, requiredSamples=NA, requiredTolerance=0.02, maxSamples=10000, seed=42) ) print(basketoption$NPV()) basketoption = BasketOption(MinBasketPayoff(payoff), exercise) basketoption$setPricingEngine( MCPREuropeanBasketEngine(process=process, timeSteps=NA, timeStepsPerYear=1, brownianBridge=F, antitheticVariate=F, requiredSamples=NA, requiredTolerance=0.02, maxSamples=10000, seed=42) ) print(basketoption$NPV()) basketoption = BasketOption(AverageBasketPayoff(payoff, 2), exercise) basketoption$setPricingEngine( MCPREuropeanBasketEngine(process=process, timeSteps=NA, timeStepsPerYear=1, brownianBridge=F, antitheticVariate=F, requiredSamples=NA, requiredTolerance=0.02, maxSamples=10000, seed=42) ) print(basketoption$NPV()) # ### Pricing - American americanExercise = AmericanExercise(settlementDate, exerciseDate) americanbasketoption = BasketOption(MaxBasketPayoff(payoff), americanExercise) americanbasketoption$setPricingEngine( MCPRAmericanBasketEngine( process=process, timeSteps=10, timeStepsPerYear=NA, brownianBridge=F, antitheticVariate=F, requiredSamples=50000, requiredTolerance=0.02, maxSamples=100000, seed=42, nCalibrationSamples=5000, polynomOrder=5, polynomType=LsmBasisSystem_Hermite_get() ) ) print(americanbasketoption$NPV()) QuantLib-SWIG-1.39/R/demo/bates_vol_surface.R000066400000000000000000000041131503741206100206700ustar00rootroot00000000000000 library(QuantLib) library(lattice) todaysDate <- Date(18, "May", 2013) Settings_instance()$setEvaluationDate(d=todaysDate) settlementDate <- Date(18, "May", 2013) riskFreeRate <- YieldTermStructureHandle(FlatForward(settlementDate, 0.01, Actual365Fixed())) dividendYield <- YieldTermStructureHandle(FlatForward(settlementDate, 0.04, Actual365Fixed())) underlying <- QuoteHandle(SimpleQuote(100)) bsProcess <- BlackScholesMertonProcess(underlying, dividendYield, riskFreeRate, BlackVolTermStructureHandle( BlackConstantVol(todaysDate, TARGET(), QuoteHandle(SimpleQuote(0.25)), Actual365Fixed()))) strikes <- seq(20, 200, length=30) maturities <- seq(0.25, 2, length=30) g <- expand.grid(strikes=strikes, maturities=maturities) batesEngine <- BatesEngine(BatesModel(BatesProcess( riskFreeRate, dividendYield, underlying, 0.1, 1.5, 0.25, 0.75, -0.75, 0.75, -0.05, 0.3)), 128) impliedVol <- function(strike, maturity) { exercise <- EuropeanExercise(Date(18, "May", 2013) + Period(maturity*365, "Days")) payoff <- PlainVanillaPayoff("Call", strike) option <- VanillaOption(payoff, exercise) option$setPricingEngine(s_arg2=batesEngine) VanillaOption_impliedVolatility(option, targetValue=option$NPV(), process=bsProcess, accuracy=1e-16, maxEvaluations=100, minVol=0.1, maxVol=5.1) } g$vol <- mapply(impliedVol, g$strikes, g$maturities) newcols <- colorRampPalette(c("grey90", "grey10")) print(wireframe(vol ~ strikes*maturities, g, xlab="Strike",ylab="Maturitiy",zlab="Vol", drape=TRUE,col.regions=rainbow(100,end=0.99,alpha=0.9), screen = list(z = -25, x = -65),scale=list(arrows=FALSE))) QuantLib-SWIG-1.39/R/demo/bonds.R000066400000000000000000000257671503741206100163310ustar00rootroot00000000000000## bonds.R -- following what bonds.py does for the QuantLib bindings for Python suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() settlementDate <- Date(18, "September", 2008) settlementDate <- Calendar_adjust(calendar, settlementDate) fixingDays <- 3 settlementDays <- 3 todaysDate <- Calendar_advance(calendar, settlementDate, -fixingDays, "Days") invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) cat('Today : ', todaysDate$`__str__`(), "\n") cat('Settlement Date: ', settlementDate$`__str__`(), "\n") ## market quotes ## constructing bond yield curve zcQuotes <- list(rates=c(0.0096, 0.0145, 0.0194), tenor=c(Period(3, "Months"), Period(6, "Months"), Period(1, "Years"))) zcBondsDayCounter <- Actual365Fixed() bondInstruments <- RateHelperVector() for (i in 1:3) { r <- zcQuotes[["rates"]][i] tenor <- zcQuotes[["tenor"]][[i]] drh <- DepositRateHelper(QuoteHandle(SimpleQuote(r)), tenor, fixingDays, calendar, "ModifiedFollowing", TRUE, zcBondsDayCounter) RateHelperVector_push_back(bondInstruments, drh) } ## setup bonds redemption <- 100.0 numberOfBonds <- 5 bondQuotes <- list(list(Date(15,"March",2005), Date(31,"August",2010), 0.02375, 100.390625), list(Date(15,"June",2005), Date(31,"August",2011), 0.04625, 106.21875), list(Date(30,"June",2006), Date(31,"August",2013), 0.03125, 100.59375), list(Date(15,"November",2002), Date(15,"August",2018), 0.04000, 101.6875), list(Date(15,"May",1987), Date (15,"May",2038), 0.04500, 102.140625) ) # Definition of the rate helpers for (i in 1:5) { issueDate <- bondQuotes[[i]][[1]] maturity <- bondQuotes[[i]][[2]] couponRate <- bondQuotes[[i]][[3]] marketQuote <- bondQuotes[[i]][[4]] schedule <- Schedule(issueDate, maturity, Period("Semiannual"), UnitedStates("GovernmentBond"), "Unadjusted", "Unadjusted", copyToR(DateGeneration(), "Backward"), FALSE) bh <- FixedRateBondHelper(QuoteHandle(SimpleQuote(marketQuote)), settlementDays, 100.0, schedule, couponRate, ActualActual("Bond"), "Unadjusted", redemption, issueDate) RateHelperVector_push_back(bondInstruments, bh) } termStructureDayCounter <- ActualActual("ISDA") # not needed as defined in the interface file: tolerance = 1.0e-15 bondDiscountingTermStructure <- PiecewiseFlatForward(settlementDate, bondInstruments, termStructureDayCounter) # Building of the Libor forecasting curve # deposits dQuotes <- list(list(0.043375, Period(1,"Weeks")), list(0.031875, Period(1,"Months")), list(0.0320375, Period(3,"Months")), list(0.03385, Period(6,"Months")), list(0.0338125, Period(9,"Months")), list(0.0335125, Period(1,"Years"))) sQuotes <- list(list(0.0295, Period(2,"Years")), list(0.0323, Period(3,"Years")), list(0.0359, Period(5,"Years")), list(0.0412, Period(10,"Years")), list(0.0433, Period(15,"Years"))) ## deposits depositDayCounter <- Actual360() depoSwapInstruments <- RateHelperVector() for (i in 1:length(dQuotes)) { rate <- dQuotes[[i]][[1]] tenor <- dQuotes[[i]][[2]] drh <- DepositRateHelper(QuoteHandle(SimpleQuote(rate)), tenor, fixingDays, calendar, "ModifiedFollowing", TRUE, depositDayCounter) RateHelperVector_push_back(depoSwapInstruments, drh) } ## swaps swFixedLegFrequency <- "Annual" swFixedLegConvention <- "Unadjusted" swFixedLegDayCounter <- Thirty360("European") swFloatingLegIndex <- Euribor6M() forwardStart <- Period(1,"Days") for (i in 1:length(sQuotes)) { rate <- sQuotes[[i]][[1]] tenor <- sQuotes[[i]][[2]] srh <- SwapRateHelper(QuoteHandle(SimpleQuote(rate)), tenor, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, QuoteHandle(),forwardStart) RateHelperVector_push_back(depoSwapInstruments, srh) } depoSwapTermStructure <- PiecewiseFlatForward(settlementDate, depoSwapInstruments, termStructureDayCounter) ## Term structures that will be used for pricing: ## the one used for discounting cash flows discountingTermStructure <- RelinkableYieldTermStructureHandle() ## the one used for forward rate forecasting forecastingTermStructure <- RelinkableYieldTermStructureHandle() ######################################## ## BONDS TO BE PRICED # ######################################## ## common data faceAmount <- 100 ## pricing engine bondEngine <- DiscountingBondEngine(discountingTermStructure) ## zero coupon bond zeroCouponBond <- ZeroCouponBond(settlementDays, UnitedStates("GovernmentBond"), faceAmount, Date(15,"August",2013), "Following", 116.92, Date(15,"August",2003)) invisible(Instrument_setPricingEngine(zeroCouponBond, bondEngine)) ## fixed 4.5% US Treasury note fixedBondSchedule <- Schedule(Date(15, "May", 2007), Date(15, "May",2017), Period("Semiannual"), UnitedStates("GovernmentBond"), "Unadjusted", "Unadjusted", copyToR(DateGeneration(), "Backward"), FALSE) fixedRateBond <- FixedRateBond(settlementDays, faceAmount, fixedBondSchedule, 0.045, ActualActual("Bond"), "ModifiedFollowing", 100.0, Date(15, "May", 2007)) invisible(Instrument_setPricingEngine(fixedRateBond, bondEngine)) ## Floating rate bond (3M USD Libor + 0.1%) ## Should and will be priced on another curve later... liborTermStructure <- RelinkableYieldTermStructureHandle() libor3m <- USDLibor(Period(3,"Months"),liborTermStructure) invisible(Index_addFixing(libor3m, Date(17, "July", 2008), 0.0278625)) floatingBondSchedule <- Schedule(Date(21, "October", 2005), Date(21, "October", 2010), Period("Quarterly"), UnitedStates("NYSE"), "Unadjusted", "Unadjusted", copyToR(DateGeneration(), "Backward"), TRUE) floatingRateBond <- FloatingRateBond(settlementDays, faceAmount, floatingBondSchedule, libor3m, Actual360(), "ModifiedFollowing", 2, 1.0, # Gearings 0.001, # Spreads numeric(0), #[], # Caps numeric(0), #[], # Floors TRUE, # Fixing in arrears 100.0, Date(21, "October", 2005)) invisible(Instrument_setPricingEngine(floatingRateBond, bondEngine)) ## coupon pricers pricer <- BlackIborCouponPricer() ## optionlet volatilities volatility <- 0.0 vol <- ConstantOptionletVolatility(settlementDays, calendar, "ModifiedFollowing", volatility, Actual365Fixed()) invisible(IborCouponPricer_setCapletVolatility(pricer, OptionletVolatilityStructureHandle(vol))) invisible(setCouponPricer(Bond_cashflows(floatingRateBond), pricer)) ## Yield curve bootstrapping invisible(RelinkableYieldTermStructureHandle_linkTo(forecastingTermStructure, depoSwapTermStructure)) invisible(RelinkableYieldTermStructureHandle_linkTo(discountingTermStructure, bondDiscountingTermStructure)) ## We are using the depo & swap curve to estimate the future Libor rates invisible(RelinkableYieldTermStructureHandle_linkTo(liborTermStructure, depoSwapTermStructure)) ## df <- data.frame(zeroCoupon=c(Instrument_NPV(zeroCouponBond), Bond_cleanPrice(zeroCouponBond), Bond_dirtyPrice(zeroCouponBond), Bond_accruedAmount(zeroCouponBond), NA, NA, 100*Bond_yield(zeroCouponBond, Actual360(), "Compounded", "Annual")), fixedRate=c(Instrument_NPV(fixedRateBond), Bond_cleanPrice(fixedRateBond), Bond_dirtyPrice(fixedRateBond), Bond_accruedAmount(fixedRateBond), 100*Bond_previousCouponRate(fixedRateBond), 100*Bond_nextCouponRate(fixedRateBond), 100*Bond_yield(fixedRateBond, Actual360(), "Compounded", "Annual")), floatingRate=c(Instrument_NPV(floatingRateBond), Bond_cleanPrice(floatingRateBond), Bond_dirtyPrice(floatingRateBond), Bond_accruedAmount(floatingRateBond), 100*Bond_previousCouponRate(floatingRateBond), 100*Bond_nextCouponRate(floatingRateBond), 100*Bond_yield(floatingRateBond, Actual360(), "Compounded", "Annual")), row.names=c("NPV", "Clean Price", "Dirty Price", "Accrued Amount", "Previous Coupon", "Next Coupon", "Yield")) cat("\nResults:\n") print(df, digits=5) # Other computations cat("\nSample indirect computations (for the floating rate bond):\n") yld <- Bond_yield(floatingRateBond, Actual360(), "Compounded", "Annual") clnPrc <- Bond_cleanPrice(floatingRateBond, yld, Actual360(), "Compounded", "Annual", settlementDate) cat("Yield to Clean Price: ", clnPrc, "\n") yld <- Bond_yield(floatingRateBond, BondPrice(clnPrc, BondPrice_Clean_get()), Actual360(), "Compounded", "Annual",settlementDate) cat("Clean Price to Yield: ", yld, "\n") QuantLib-SWIG-1.39/R/demo/cashflows.R000066400000000000000000000114361503741206100172010ustar00rootroot00000000000000 # inspired by python example with the same name suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() todaysDate <- Date(19, "October", 2020) invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDays <- 3 settlementDate <- Calendar_advance(calendar, todaysDate, settlementDays, "Days") cat('Today : ', todaysDate$`__str__`(), "\n") cat('Settlement Date: ', settlementDate$`__str__`(), "\n") # ### Term structure construction # %% dates = DateVector() DateVector_append(dates, DateParser_parseISO("2020-10-19")) DateVector_append(dates, DateParser_parseISO("2020-11-19")) DateVector_append(dates, DateParser_parseISO("2021-01-19")) DateVector_append(dates, DateParser_parseISO("2021-04-19")) DateVector_append(dates, DateParser_parseISO("2021-10-19")) DateVector_append(dates, DateParser_parseISO("2022-04-19")) DateVector_append(dates, DateParser_parseISO("2022-10-19")) DateVector_append(dates, DateParser_parseISO("2023-10-19")) DateVector_append(dates, DateParser_parseISO("2025-10-19")) DateVector_append(dates, DateParser_parseISO("2030-10-19")) DateVector_append(dates, DateParser_parseISO("2035-10-19")) DateVector_append(dates, DateParser_parseISO("2040-10-19")) DateVector_size(dates) rates = c( -0.004, -0.002, 0.001, 0.005, 0.009, 0.010, 0.010, 0.012, 0.017, 0.019, 0.028, 0.032 ) length(rates) forecast_curve = ZeroCurve(dates, rates, Actual365Fixed()) forecast_handle = YieldTermStructureHandle(forecast_curve) # ### Swap construction # # We'll use an overnight swap as an example. # We're keeping the initialization simple, # but the analysis work in the same way for more complex ones, # as well as for other kinds of swaps and bonds (once we extract the cashflows from them using the proper methods). # %% swapBuilder = MakeOIS(swapTenor=Period(5, "Years"), overnightIndex=Eonia(forecast_handle), fixedRate=0.002) swap = MakeOIS_makeOIS(swapBuilder) # ### Cash-flow analysis # # The fixed-rate coupons can be extracted from the swap using the `fixedLeg` method. # fixed_leg = swap$fixedLeg() CashFlows_maturityDate(fixed_leg) df = NULL for (i in seq(1, fixed_leg$size())) { cfl = fixed_leg[i][[1]] df = rbind(df, data.frame(date=Date_ISO(CashFlow_date(cfl)), amount=CashFlow_amount(cfl))) } print(df) # # If we want to extract more information, we need to upcast the coupons to a more specific class. # This can be done by using the `as_coupon` or the `as_fixed_rate_coupon` method. # df = NULL for (i in seq(1, fixed_leg$size())) { cfl = fixed_leg[i][[1]] cflCoupon = as_coupon(cfl) cflCouponFix = as_fixed_rate_coupon(cfl) cflCouponFixIr = FixedRateCoupon_interestRate(cflCouponFix) df = rbind(df, data.frame(date=Date_ISO(CashFlow_date(cfl)), amount=CashFlow_amount(cfl), accrualStartDate=Date_ISO(Coupon_accrualStartDate(cflCoupon)), accrualEndDate=Date_ISO(Coupon_accrualEndDate(cflCoupon)), accrualPeriod=Coupon_accrualPeriod(cflCoupon), accrualDays=Coupon_accrualDays(cflCoupon), accrualDayCounter=DayCounter_name(Coupon_dayCounter(cflCoupon)), accruedAmount=Coupon_accruedAmount(self = cflCoupon, todaysDate), rate=InterestRate_rate(cflCouponFixIr), rateDayCount=DayCounter_name(InterestRate_dayCounter(cflCouponFixIr)) )) } print(df) # %% floating_leg = swap$overnightLeg() # %% df = NULL for (i in seq(1, floating_leg$size())) { cfl = floating_leg[i][[1]] cflCoupon = as_coupon(cfl) cflCouponFloat = as_floating_rate_coupon(cfl) cflCouponFloatIdx = FloatingRateCoupon_index(cflCouponFloat) df = rbind(df, data.frame(date=Date_ISO(CashFlow_date(cfl)), amount=CashFlow_amount(cfl), accrualStartDate=Date_ISO(Coupon_accrualStartDate(cflCoupon)), accrualEndDate=Date_ISO(Coupon_accrualEndDate(cflCoupon)), accrualPeriod=Coupon_accrualPeriod(cflCoupon), accrualDays=Coupon_accrualDays(cflCoupon), accrualDayCounter=DayCounter_name(Coupon_dayCounter(cflCoupon)), accruedAmount=Coupon_accruedAmount(self = cflCoupon, todaysDate), spread=FloatingRateCoupon_spread(cflCouponFloat), gearing=FloatingRateCoupon_gearing(cflCouponFloat), adjFix=FloatingRateCoupon_adjustedFixing(cflCouponFloat), dtFix=Date_ISO(FloatingRateCoupon_fixingDate(cflCouponFloat)), convexityAdj=FloatingRateCoupon_convexityAdjustment(cflCouponFloat) )) } print(df) QuantLib-SWIG-1.39/R/demo/cds.R000066400000000000000000000061721503741206100157620ustar00rootroot00000000000000 # inspired by python example with the same name suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() todaysDate <- DateParser_parseISO("2007-05-15") invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDays <- 3 settlementDate <- Calendar_advance(calendar, todaysDate, settlementDays, "Days") cat('Today : ', Date_ISO(todaysDate), "\n") cat('Settlement Date: ', Date_ISO(settlementDate), "\n") risk_free_rate = YieldTermStructureHandle(FlatForward(todaysDate, 0.01, Actual365Fixed())) # ### CDS parameters recovery_rate = 0.5 quoted_spreads = c(0.0150, 0.0150, 0.0150, 0.0150) tenors = PeriodVector() tenors$append(Period(3, "Months")) tenors$append(Period(6, "Months")) tenors$append(Period(1, "Years")) tenors$append(Period(2, "Years")) maturities = DateVector() for (i in seq(1, tenors$size())) { maturities$append( Calendar_adjust(calendar, Calendar_advance(calendar, todaysDate, tenors[i][[1]]), "Following") ) } instruments = DefaultProbabilityHelperVector() for (i in seq(1, length(quoted_spreads))) { s = quoted_spreads[i] tenor = tenors[i][[1]] it = SpreadCdsHelper( QuoteHandle(SimpleQuote(s)), tenor, 0, calendar, "Quarterly", "Following", DateGeneration_TwentiethIMM_get(), Actual365Fixed(), recovery_rate, risk_free_rate ) instruments$append(it) } hazard_curve = PiecewiseFlatHazardRate(todaysDate, instruments, Actual365Fixed()) print("Calibrated hazard rate values: ") for (i in seq(1, hazard_curve$dates()$size())) { print(paste("hazard rate on ", Date_ISO(hazard_curve$dates()[i][[1]]), "is ", HazardRateCurve_hazardRates(hazard_curve)[i])) } print(paste("1Y survival probability:", DefaultProbabilityTermStructure_survivalProbability(hazard_curve, Calendar_advance(calendar, todaysDate, Period(1, "Years"))), "expected 0.9704 " )) print(paste("2Y survival probability:", DefaultProbabilityTermStructure_survivalProbability(hazard_curve, Calendar_advance(calendar, todaysDate, Period(2, "Years"))), "expected 0.9418 " )) # ### Reprice instruments nominal = 1000000.0 probability = DefaultProbabilityTermStructureHandle(hazard_curve) # We'll create a cds for every maturity: print("Repricing of quoted CDSs employed for calibration: ") for (i in seq(1, length(quoted_spreads))) { maturity = maturities[i][[1]] s = quoted_spreads[i] tenor = tenors[i][[1]] schedule = Schedule( todaysDate, maturity, Period(3, "Months"), # "Quarterly", calendar, "Following", "Unadjusted", DateGeneration_TwentiethIMM_get(), F ) cds = CreditDefaultSwap(Protection_Seller_get(), nominal, s, schedule, "Following", Actual365Fixed()) engine = MidPointCdsEngine(probability, recovery_rate, risk_free_rate) cds$setPricingEngine(engine) print(paste("fair spread: ", Period___str__(tenor), cds$fairSpread())) print(paste(" NPV: ", cds$NPV())) print(paste(" default leg: ", cds$defaultLegNPV())) print(paste(" coupon leg: ", cds$couponLegNPV())) print("") } QuantLib-SWIG-1.39/R/demo/curves.R000066400000000000000000000010531503741206100165110ustar00rootroot00000000000000 suppressMessages(library(QuantLib)) bToday = QuantLib::Date(31, "August", 2022) QuantLib::Settings_setEvaluationDate(self = QuantLib::Settings_instance(), d = bToday) print(Settings_instance()$getEvaluationDate()) bufDates = QuantLib::DateVector() QuantLib::DateVector_append(self = bufDates, x = Date(31, "August", 2022)) QuantLib::DateVector_append(self = bufDates, x = Date(30, "September", 2022)) QuantLib::DateVector_size(self = bufDates) bCurve = QuantLib::DiscountCurve(dates = bufDates , discounts = c(1.0, 1.0), dayCounter = Actual360()) QuantLib-SWIG-1.39/R/demo/european-option.R000066400000000000000000000067431503741206100203410ustar00rootroot00000000000000 ## expanded to follow european-option.py suppressMessages(library(QuantLib)) # global data todaysDate <- Date(15, "May", 1998) invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDate <- Date(17, "May", 1998) riskFreeRate <- FlatForward(settlementDate, 0.05, Actual365Fixed()) # option parameters exercise <- EuropeanExercise(Date(17, "May", 1999)) payoff <- PlainVanillaPayoff("Call", 8.0) # market data underlying <- SimpleQuote(7.0) volatility <- BlackConstantVol(todaysDate, TARGET(), 0.10, Actual365Fixed()) dividendYield <- FlatForward(settlementDate, 0.05, Actual365Fixed()) process <- BlackScholesMertonProcess(QuoteHandle(underlying), YieldTermStructureHandle(dividendYield), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility)) cat(sprintf("%17s %8s %6s %6s\n", "method", "value", "errest", "error")) cat(rep("=", 43), "\n", sep="") report <- function(method, x, dx=NA) { err <- abs(x - refValue) # refValue is a global cat(sprintf("%17s %8.5f %6.4f %6.4f\n", method, x, dx, err)) invisible(NULL) } option <- VanillaOption(payoff, exercise) invisible(option$setPricingEngine(AnalyticEuropeanEngine(process))) value <- option$NPV() refValue <- value report("analytic", value) invisible(option$setPricingEngine(IntegralEngine(process))) report('integral', option$NPV()) ## method: finite differences timeSteps <- 801 gridPoints <- 800 invisible(option$setPricingEngine(FdBlackScholesVanillaEngine(process,timeSteps,gridPoints))) report('finite diff.', option$NPV()) ## method: binomial timeSteps <- 801 invisible(option$setPricingEngine(BinomialJRVanillaEngine(process,timeSteps))) report('binomial (JR)', option$NPV()) invisible(option$setPricingEngine(BinomialCRRVanillaEngine(process,timeSteps))) report('binomial (CRR)', option$NPV()) invisible(option$setPricingEngine(BinomialEQPVanillaEngine(process,timeSteps))) report('binomial (EQP)', option$NPV()) invisible(option$setPricingEngine(BinomialTrigeorgisVanillaEngine(process,timeSteps))) report('bin. (Trigeorgis)', option$NPV()) invisible(option$setPricingEngine(BinomialTianVanillaEngine(process,timeSteps))) report('binomial (Tian)', option$NPV()) invisible(option$setPricingEngine(BinomialLRVanillaEngine(process,timeSteps))) report('binomial (LR)', option$NPV()) ## method: Monte Carlo invisible(option$setPricingEngine(MCLDEuropeanEngine(process, timeSteps = 1, timeStepsPerYear=NA, brownianBridge=FALSE, antitheticVariate=FALSE, requiredSamples=NULL, requiredTolerance = 0.02, maxSamples=NULL, seed = 42))) report('MC (crude)', option$NPV()) #, option$errorEstimate()) invisible(option$setPricingEngine(MCLDEuropeanEngine(process, timeSteps = 1, timeStepsPerYear=NA, brownianBridge=FALSE, antitheticVariate=FALSE, requiredSamples = 32768, requiredTolerance = 0.02, maxSamples=NULL, seed=42))) report('MC (Sobol)', option$NPV()) QuantLib-SWIG-1.39/R/demo/fd-option.R000066400000000000000000000020441503741206100171020ustar00rootroot00000000000000 suppressMessages(library(QuantLib)) quote <- function(x) { sapply(x, function(x1) { todaysDate <- Date(15, "May", 1998) invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDate <- Date(17, "May", 1998) riskFreeRate <- FlatForward(settlementDate, 0.05, Actual365Fixed()) exercise <- EuropeanExercise(Date(17, "May", 1999)) payoff <- PlainVanillaPayoff("Call", 8.0) underlying <- SimpleQuote(x1) volatility <- BlackConstantVol(todaysDate, TARGET(), 0.10, Actual365Fixed()) dividendYield <- FlatForward(settlementDate, 0.05, Actual365Fixed()) process <- BlackScholesMertonProcess(QuoteHandle(underlying), YieldTermStructureHandle(dividendYield), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility)) option <- VanillaOption(payoff, exercise) invisible(option$setPricingEngine(s_arg2=FdBlackScholesVanillaEngine(process, 25))) option$NPV() })} curve(quote,xlim=c(1,20)) QuantLib-SWIG-1.39/R/demo/gaussian1d-models.R000066400000000000000000000300031503741206100205170ustar00rootroot00000000000000 # inspired by python example with the same name suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() todaysDate <- DateParser_parseISO("2014-04-30") invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDays <- 3 settlementDate <- Calendar_advance(calendar, todaysDate, settlementDays, "Days") cat('Today : ', Date_ISO(todaysDate), "\n") cat('Settlement Date: ', Date_ISO(settlementDate), "\n") refDate = todaysDate # ### Calculations # This exercise tries to replicate the Quantlib C++ `Gaussian1dModel` example on how to use the GSR and Markov Functional model. # We assume a multicurve setup, for simplicity with flat yield term structures. # # The discounting curve is an Eonia curve at a level of 2% and the forwarding curve is an Euribor 6m curve at a level of 2.5%. # # For the volatility we assume a flat swaption volatility at 20%. forward6mQuote = QuoteHandle(SimpleQuote(0.025)) oisQuote = QuoteHandle(SimpleQuote(0.02)) volQuote = QuoteHandle(SimpleQuote(0.2)) # %% dc = Actual365Fixed() yts6m = FlatForward(refDate, forward6mQuote, dc) ytsOis = FlatForward(refDate, oisQuote, dc) yts6m$enableExtrapolation() ytsOis$enableExtrapolation() hyts6m = RelinkableYieldTermStructureHandle(yts6m) t0_curve = YieldTermStructureHandle(yts6m) t0_Ois = YieldTermStructureHandle(ytsOis) euribor6m = Euribor6M(hyts6m) swaptionVol = ConstantSwaptionVolatility(0, calendar, "ModifiedFollowing", volQuote, Actual365Fixed()) # %% effectiveDate = Calendar_advance(calendar, refDate, 2, "Days") print(Date_ISO(effectiveDate)) maturityDate = Calendar_advance(calendar, effectiveDate, 10, "Years") print(Date_ISO(maturityDate)) # %% fixedSchedule = Schedule(effectiveDate, maturityDate, Period(1, "Years"), calendar, "ModifiedFollowing", "ModifiedFollowing", DateGeneration_Forward_get(), F) # %% floatSchedule = Schedule(effectiveDate, maturityDate, Period(6, "Months"), calendar, "ModifiedFollowing", "ModifiedFollowing", DateGeneration_Forward_get(), F) # We consider a standard 10-years Bermudan payer swaption with yearly exercises at a strike of 4%. # %% fixedNominal = rep(1, fixedSchedule$size()-1) floatingNominal = rep(1, floatSchedule$size()-1) strike = rep(0.04, fixedSchedule$size()-1) gearing = rep(1, floatSchedule$size()-1) spread = rep(0, floatSchedule$size()-1) # %% underlying = NonstandardSwap( Swap_Payer_get(), fixedNominal, floatingNominal, fixedSchedule, strike, Thirty360(Thirty360_BondBasis_get()), floatSchedule, euribor6m, gearing, spread, Actual360(), F, F, "ModifiedFollowing") # %% exerciseDates = Schedule_dates(self = fixedSchedule, .copy = T) for (i in seq(0, exerciseDates$size()-1)) { # C Style vector numbering DateVector___setitem__(exerciseDates, i, Calendar_advance(calendar, DateVector___getitem__(exerciseDates, i), -2, "Days")) } DateVector___delitem__(exerciseDates, 0) DateVector___delitem__(exerciseDates, DateVector___len__(exerciseDates)-1) for (i in seq(1, exerciseDates$size())) { # R style vector numbering print(exerciseDates[i][[1]]) } exercise = BermudanExercise(exerciseDates) swaption = NonstandardSwaption(underlying,exercise,Settlement_Physical_get()) # The model is a one factor Hull White model with piecewise volatility adapted to our exercise dates. # # The reversion is just kept constant at a level of 1%. stepDates = DateVector(exerciseDates) DateVector___delitem__(stepDates, DateVector___len__(stepDates)-1) sigmas = QuoteHandleVector() for (i in seq(1, 9)) { QuoteHandleVector_append(sigmas, QuoteHandle(SimpleQuote(0.01))) } reversion = QuoteHandleVector() QuoteHandleVector_append(reversion, QuoteHandle(SimpleQuote(0.01))) # # The model's curve is set to the 6m forward curve. # Note that the model adapts automatically to other curves where appropriate # (e.g. if an index requires a different forwarding curve) or where explicitly specified (e.g. in a swaption pricing engine). gsr = Gsr(t0_curve, stepDates, sigmas, reversion) swaptionEngine = Gaussian1dSwaptionEngine(gsr, 64, 7.0, T, F, t0_Ois) nonstandardSwaptionEngine = Gaussian1dNonstandardSwaptionEngine( gsr, 64, 7.0, T, F, QuoteHandle(SimpleQuote(0)), t0_Ois) # %% swaption$setPricingEngine(nonstandardSwaptionEngine) # %% swapBase = EuriborSwapIsdaFixA(Period(10, 'Years'), t0_curve, t0_Ois) basket = swaption$calibrationBasket(swapBase, swaptionVol, 'Naive') # %% for (i in seq(1, basket$size())) { basket_i = basket[i][[1]] BlackCalibrationHelper_setPricingEngine(basket_i, swaptionEngine) } # %% method = LevenbergMarquardt() ec = EndCriteria(1000, 10, 1e-8, 1e-8, 1e-8) # %% gsr$calibrateVolatilitiesIterative(basket, method, ec) # %% [markdown] # The engine can generate a calibration basket in two modes. # # The first one is called Naive and generates ATM swaptions adapted to the exercise dates of the swaption and its maturity date. The resulting basket looks as follows: # %% basket_data = function(basket) { df = NULL for (i in seq(1, basket$size())) { basket_i = basket[i][[1]] h = as_swaption_helper(basket_i) hopt = SwaptionHelper_swaption(h) df = rbind(df, data.frame(expiry=Date_ISO(SwaptionHelper_swaptionExpiryDate(h)), maturity=Date_ISO(SwaptionHelper_swaptionMaturityDate(h)), nominal=SwaptionHelper_swaptionNominal(h), strike=SwaptionHelper_swaptionStrike(h), optType=Swaption_type(hopt) )) } df } print(basket_data(basket)) # # Let's calibrate our model to this basket. # We use a specialized calibration method calibrating the sigma function one by one to the calibrating vanilla swaptions. The result of this is as follows: # %% calibration_data = function(basket, volatilities) { # volatilities = gsr$volatility() df = NULL for (i in seq(1, basket$size())) { basket_i = basket[i][[1]] vola_i = volatilities[i][[1]] h = as_swaption_helper(basket_i) hopt = SwaptionHelper_swaption(h) modelPrice = basket_i$modelValue() modelImpVol = BlackCalibrationHelper_impliedVolatility(self = basket_i, targetValue = modelPrice, accuracy = 1e-6, maxEvaluations = 1000, minVol = 0.0, maxVol = 2.0) marketPrice = basket_i$marketValue() df = rbind(df, data.frame(expiry=Date_ISO(SwaptionHelper_swaptionExpiryDate(h)), modelSigma=vola_i, modelPrice=modelPrice, marketPrice=marketPrice, modelImpVol=modelImpVol, marketImpVol=QuoteHandle_value(basket_i$volatility()) )) } df } print(calibration_data(basket, gsr$volatility())) # %% [markdown] # Bermudan swaption NPV (ATM calibrated GSR): # %% print(swaption$NPV()) # # There is another mode to generate a calibration basket called `MaturityStrikeByDeltaGamma`. # This means that the maturity, the strike and the nominal of the calibrating swaptions are obtained matching the NPV, # first derivative and second derivative of the swap you will exercise into at at each bermudan call date. # The derivatives are taken with respect to the model's state variable. # # Let's try this in our case. # %% basket = swaption$calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') print(basket_data(basket)) # %% for (i in seq(1, basket$size())) { basket_i = basket[i][[1]] BlackCalibrationHelper_setPricingEngine(basket_i, swaptionEngine) } # %% [markdown] # The calibrated nominal is close to the exotics nominal. The expiries and maturity dates of the vanillas are the same as in the case above. The difference is the strike which is now equal to the exotics strike. # # Let's see how this affects the exotics NPV. The recalibrated model is: # %% gsr$calibrateVolatilitiesIterative(basket, method, ec) print(calibration_data(basket, gsr$volatility())) # %% [markdown] # Bermudan swaption NPV (deal strike calibrated GSR): # %% print(swaption$NPV()) # # We can do more complicated things. # Let's e.g. modify the nominal schedule to be linear amortizing and see what the effect on the generated calibration basket is: # %% for (i in seq(1,fixedSchedule$size()-1)) { tmp = 1.0 - i/ (fixedSchedule$size()) fixedNominal[i] = tmp floatingNominal[i*2-1] = tmp floatingNominal[i*2] = tmp } # %% underlying2 = NonstandardSwap(Swap_Payer_get(), fixedNominal, floatingNominal, fixedSchedule, strike, Thirty360(Thirty360_BondBasis_get()), floatSchedule, euribor6m, gearing, spread, Actual360(), F, F, "ModifiedFollowing") # %% swaption2 = NonstandardSwaption(underlying2, exercise, Settlement_Physical_get()) # %% swaption2$setPricingEngine(nonstandardSwaptionEngine) basket = swaption2$calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') # %% print(basket_data(basket)) # # The notional is weighted over the underlying exercised into and the maturity is adjusted downwards. The rate, on the other hand, is not affected. # # You can also price exotic bond's features. # If you have e.g. a Bermudan callable fixed bond you can set up the call right as a swaption # to enter into a one leg swap with notional reimbursement at maturity. # The exercise should then be written as a rebated exercise paying the notional in case of exercise. The calibration basket looks like this: # %% fixedNominal2 = rep(1, fixedSchedule$size()-1) floatingNominal2 = rep(0, fixedSchedule$size()*2-2) #null the second leg # %% underlying3 = NonstandardSwap(Swap_Receiver_get(), fixedNominal2, floatingNominal2, fixedSchedule, strike, Thirty360(Thirty360_BondBasis_get()), floatSchedule, euribor6m, gearing, spread, Actual360(), F, T, "ModifiedFollowing") # %% rebateAmount = rep(-1, exerciseDates$size()) exercise2 = RebatedExercise(exercise, rebateAmount, 2, calendar) swaption3 = NonstandardSwaption(underlying3, exercise2, Settlement_Physical_get()) # %% oas0 = SimpleQuote(0) oas100 = SimpleQuote(0.01) oas = RelinkableQuoteHandle(oas0) # %% nonstandardSwaptionEngine2 = Gaussian1dNonstandardSwaptionEngine( gsr, 64, 7.0, T, F, oas, t0_curve) # Change discounting to 6m # %% swaption3$setPricingEngine(nonstandardSwaptionEngine2) basket = swaption3$calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') # %% print(basket_data(basket)) # %% [markdown] # Note that nominals are not exactly 1.0 here. This is because we do our bond discounting on 6m level while the swaptions are still discounted on OIS level. (You can try this by changing the OIS level to the 6m level, which will produce nominals near 1.0). # # The NPV of the call right is (after recalibrating the model): # %% for (i in seq(1, basket$size())) { basket_i = basket[i][[1]] BlackCalibrationHelper_setPricingEngine(basket_i, swaptionEngine) } # %% gsr$calibrateVolatilitiesIterative(basket, method, ec) # %% print(swaption3$NPV()) # %% [markdown] # Up to now, no credit spread is included in the pricing. We can do so by specifying an oas in the pricing engine. Let's set the spread level to 100bp and regenerate the calibration basket. # %% oas$linkTo(oas100) basket = swaption3$calibrationBasket(swapBase, swaptionVol, 'MaturityStrikeByDeltaGamma') print(basket_data(basket)) # %% [markdown] # The adjusted basket takes the credit spread into account. This is consistent to a hedge where you would have a margin on the float leg around 100bp,too. # %% for (i in seq(1, basket$size())) { basket_i = basket[i][[1]] BlackCalibrationHelper_setPricingEngine(basket_i, swaptionEngine) } # %% gsr$calibrateVolatilitiesIterative(basket, method, ec) # %% print(swaption3$NPV()) QuantLib-SWIG-1.39/R/demo/global-bootstrap.R000066400000000000000000000055541503741206100204670ustar00rootroot00000000000000 # inspired by python example with the same name suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() todaysDate <- DateParser_parseISO("2019-09-26") invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDays <- 2 settlementDate <- Calendar_advance(calendar, todaysDate, settlementDays, "Days") cat('Today : ', Date_ISO(todaysDate), "\n") cat('Settlement Date: ', Date_ISO(settlementDate), "\n") spot = settlementDate # %% [markdown] # ### Data # # We'll use the following data as input: # %% refMktRates = c( -0.373, -0.388, -0.402, -0.418, -0.431, -0.441, -0.45, -0.457, -0.463, -0.469, -0.461, -0.463, -0.479, -0.4511, -0.45418, -0.439, -0.4124, -0.37703, -0.3335, -0.28168, -0.22725, -0.1745, -0.12425, -0.07746, 0.0385, 0.1435, 0.17525, 0.17275, 0.1515, 0.1225, 0.095, 0.0644 ) # ### Market instruments # %% index = Euribor6M() # The first market rate is for the 6-months deposit... # %% helpers = RateHelperVector() helpers$append( DepositRateHelper( refMktRates[1] / 100.0, Period(6, "Months"), 2, calendar, "ModifiedFollowing", T, Actual360() ) ) # ...the next 12 are for FRAs... # %% for (i in seq(2, 13)) { helpers$append( FraRateHelper(refMktRates[i] / 100.0, i + 1, index) ) } # ...and the others are swap rates. # %% swapTenors = c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 20, 25, 30, 35, 40, 45, 50) for (i in seq(14, length(refMktRates))) { r = refMktRates[i] tenor = swapTenors[i-13] helpers$append( SwapRateHelper( r / 100.0, Period(tenor, "Years"), calendar, "Annual", "ModifiedFollowing", Thirty360(Thirty360_BondBasis_get()), index ) ) } # We'll also add a few synthetic helpers: # %% additional_helpers = RateHelperVector() for (i in seq(0, 6)){ additional_helpers$append( FraRateHelper(-0.004, 12 + i, index) ) } # %% additional_dates = DateVector() for (i in seq(0, 4)){ additional_dates$append( Calendar_advance(calendar, spot, Period(i+1, "Months")) ) } # ### Global bootstrap # # This curve takes into account the market instruments, as well as the passed additional ones. # %% curve = GlobalLinearSimpleZeroCurve( spot, helpers, Actual365Fixed(), GlobalBootstrap(additional_helpers, additional_dates, 1.0e-4) ) curve$enableExtrapolation() # ### Report df = NULL for (i in seq(1, helpers$size())) { h = helpers[i][[1]] pillar = RateHelper_pillarDate(h) day_counter = Actual360() compounding = "Simple" if (i > 13) { day_counter = Thirty360(Thirty360_BondBasis_get()) compounding = "SimpleThenCompounded" } r = YieldTermStructure_zeroRate(curve, pillar, day_counter, compounding, "Annual") df = rbind(df, data.frame( pillar=Date_ISO(pillar), zeroRate=InterestRate_rate(r)*100.0 )) } print(df) QuantLib-SWIG-1.39/R/demo/graph.R000066400000000000000000000021041503741206100163010ustar00rootroot00000000000000 suppressMessages(library(QuantLib)) quote <- function(x) { sapply(x, function(x1) { todaysDate <- Date(15, "May", 1998) Settings_instance()$setEvaluationDate(d=todaysDate) settlementDate <- Date(17, "May", 1998) riskFreeRate <- FlatForward(settlementDate, 0.05, Actual365Fixed()) exercise <- EuropeanExercise(Date(17, "May", 1999)) payoff <- PlainVanillaPayoff("Call", 8.0) underlying <- SimpleQuote(x1) volatility <- BlackConstantVol(todaysDate, TARGET(), 0.10, Actual365Fixed()) dividendYield <- FlatForward(settlementDate, 0.05, Actual365Fixed()) process <- BlackScholesMertonProcess(QuoteHandle(underlying), YieldTermStructureHandle(dividendYield), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility)) option <- VanillaOption(payoff, exercise) Instrument_setPricingEngine(option, s_arg2=AnalyticEuropeanEngine(process)) value <- option$NPV() value })} curve(quote,xlim=c(1,20)) QuantLib-SWIG-1.39/R/demo/scatter.R000066400000000000000000000032131503741206100166470ustar00rootroot00000000000000 suppressMessages(library(QuantLib)) spot<-seq(10.0,95.00,len=20) vol<-0.5 g<-expand.grid(spot=spot,vol=vol) todaysDate <- Date(15, "May", 1998) Settings_instance()$setEvaluationDate(d=todaysDate) settlementDate <- Date(17, "May", 1998) riskQuote <- SimpleQuote(0.05) riskFreeRate <- FlatForward(settlementDate, QuoteHandle(riskQuote), Actual365Fixed()) exercise <- EuropeanExercise(Date(17, "May", 1999)) payoff <- PlainVanillaPayoff("Call", 50.0) dividendYield <- FlatForward(settlementDate, 0.05, Actual365Fixed()) underlying <- SimpleQuote(10.0) volatilityQuote <- SimpleQuote(0.05) volatility <- BlackConstantVol(todaysDate, TARGET(), QuoteHandle(volatilityQuote), Actual365Fixed()) process <- BlackScholesMertonProcess(QuoteHandle(underlying), YieldTermStructureHandle(dividendYield), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility)) engine <- AnalyticEuropeanEngine(process) option <- VanillaOption(payoff, exercise) option$setPricingEngine(s_arg2=engine) t <- mapply(function(x,y) { underlying$setValue(value=x) volatilityQuote$setValue(value=y) list(NPV=option$NPV(), gamma=option$gamma(), delta=option$delta(), vega=option$vega())}, g$spot, g$vol, SIMPLIFY=FALSE) g$NPV <- sapply(1:length(t), function(x) t[[x]]$NPV) g$gamma <- sapply(1:length(t), function(x) t[[x]]$gamma) g$delta <- sapply(1:length(t), function(x) t[[x]]$delta) g$vega <- sapply(1:length(t), function(x) t[[x]]$vega) pairs(g) QuantLib-SWIG-1.39/R/demo/swap.R000066400000000000000000000160201503741206100161540ustar00rootroot00000000000000 # inspired by python example with the same name suppressMessages(library(QuantLib)) ## global data calendar <- TARGET() todaysDate <- DateParser_parseISO("2001-09-06") invisible(Settings_instance()$setEvaluationDate(d=todaysDate)) settlementDays = 2 settlementDate = Calendar_advance(calendar, todaysDate, settlementDays, "Days") cat('Today : ', Date_ISO(todaysDate), "\n") cat('Settlement Date: ', Date_ISO(settlementDate), "\n") # ### Market quotes # %% deposits = list( "3M" = 0.0363 ) # %% FRAs = list( "3x6" = 0.037125, "6x9" = 0.037125, "9x12" =0.037125 ) # %% futures = list( "2001-12-19" = 96.2875, "2002-03-20" = 96.7875, "2002-06-19" = 96.9875, "2002-09-18" = 96.6875, "2002-12-18" = 96.4875, "2003-03-19" = 96.3875, "2003-06-18" = 96.2875, "2003-09-17" = 96.0875 ) # %% swaps = list( # "2Y" = 0.037125, "3Y" = 0.0398, "5Y" = 0.0443, "10Y" = 0.05165, "15Y" = 0.055175 ) allHelpers_DepoFutSwap = RateHelperVector() allHelpers_DepoFraSwap = RateHelperVector() # Rate Helpers - Depos for (it in names(deposits)) { itVal = deposits[[it]] dayCounter = Actual360() dh = DepositRateHelper( QuoteHandle(SimpleQuote(itVal)), PeriodParser_parse(it), settlementDays, calendar, "ModifiedFollowing", F, dayCounter ) RateHelperVector_append(allHelpers_DepoFutSwap, dh) RateHelperVector_append(allHelpers_DepoFraSwap, dh) } # Rate Helpers - FRAs for (it in names(FRAs)) { itVal = FRAs[[it]] itSplit = strsplit(x = it, split = "x", fixed = T)[[1]] n = as.numeric(itSplit[1]) m = as.numeric(itSplit[2]) dayCounter = Actual360() months = 3 dh = FraRateHelper( QuoteHandle(SimpleQuote(itVal)), n, m, settlementDays, calendar, "ModifiedFollowing", F, dayCounter ) RateHelperVector_append(allHelpers_DepoFraSwap, dh) } # Rate Helpers - Futures for (it in names(futures)) { itVal = futures[[it]] dayCounter = Actual360() months = 3 dh = FuturesRateHelper( QuoteHandle(SimpleQuote(itVal)), DateParser_parseISO(it), months, calendar, "ModifiedFollowing", T, dayCounter, QuoteHandle(SimpleQuote(0.0)) ) RateHelperVector_append(allHelpers_DepoFutSwap, dh) } # # The discount curve for the swaps will come from elsewhere. # -> A real application would use some kind of risk-free curve; here we're using a flat one for convenience. # # %% discountTermStructure = YieldTermStructureHandle(FlatForward(settlementDate, 0.04, Actual360())) # %% fixedLegFrequency = "Annual" fixedLegTenor = PeriodParser_parse("1Y") fixedLegAdjustment = "Unadjusted" fixedLegDayCounter = Thirty360(Thirty360_BondBasis_get()) floatingLegFrequency = "Quarterly" floatingLegTenor = PeriodParser_parse("3M") floatingLegAdjustment = "ModifiedFollowing" for (it in names(swaps)) { itVal = swaps[[it]] dh = SwapRateHelper( QuoteHandle(SimpleQuote(itVal)), PeriodParser_parse(it), calendar, fixedLegFrequency, fixedLegAdjustment, fixedLegDayCounter, Euribor3M(), QuoteHandle(), PeriodParser_parse("0D"), discountTermStructure ) RateHelperVector_append(allHelpers_DepoFutSwap, dh) RateHelperVector_append(allHelpers_DepoFraSwap, dh) } # ### Term structure construction printCurve <- function(curve, helpers) { df = NULL for (i in seq(1, helpers$size())) { h = helpers[i][[1]] pillar = RateHelper_pillarDate(h) day_counter = Actual365Fixed() compounding = "Continuous" r = YieldTermStructure_zeroRate(curve, pillar, day_counter, compounding, "Annual") disc = YieldTermStructure_discount(curve, pillar) df = rbind(df, data.frame( pillar=Date_ISO(pillar), zeroRate=InterestRate_rate(r)*100.0, df=disc, impliedRate=RateHelper_impliedQuote(h) )) } print(df) } # %% forecastTermStructure = RelinkableYieldTermStructureHandle() # %% depoFuturesSwapCurve = PiecewiseFlatForward(settlementDate, allHelpers_DepoFutSwap, Actual360()) printCurve(depoFuturesSwapCurve, allHelpers_DepoFutSwap) # %% depoFraSwapCurve = PiecewiseFlatForward(settlementDate, allHelpers_DepoFraSwap, Actual360()) printCurve(depoFraSwapCurve, allHelpers_DepoFraSwap) # ### Swap pricing # %% swapEngine = DiscountingSwapEngine(discountTermStructure) # %% nominal = 1000000 length = 5 maturity = Calendar_advance(calendar, settlementDate, length, "Years") payFixed = T # %% fixedLegFrequency = "Annual" fixedLegAdjustment = "Unadjusted" fixedLegDayCounter = Thirty360(Thirty360_BondBasis_get()) fixedRate = swaps[["5Y"]] # 0.04 # %% floatingLegFrequency = "Quarterly" spread = 0.0 fixingDays = 2 index = Euribor3M(forecastTermStructure) floatingLegAdjustment = "ModifiedFollowing" floatingLegDayCounter = index$dayCounter() # %% fixedSchedule = Schedule( settlementDate, maturity, fixedLegTenor, calendar, fixedLegAdjustment, fixedLegAdjustment, DateGeneration_Forward_get(), F ) floatingSchedule = Schedule( settlementDate, maturity, floatingLegTenor, calendar, floatingLegAdjustment, floatingLegAdjustment, DateGeneration_Forward_get(), F ) # We'll build a 5-years swap starting spot... # %% spot = VanillaSwap( Swap_Payer_get(), nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatingSchedule, index, spread, floatingLegDayCounter ) spot$setPricingEngine(swapEngine) # ...and one starting 1 year forward. # %% forwardStart = Calendar_advance(calendar, settlementDate, 1, "Years") forwardEnd = Calendar_advance(calendar, forwardStart, length, "Years") fixedSchedule = Schedule( forwardStart, forwardEnd, fixedLegTenor, calendar, fixedLegAdjustment, fixedLegAdjustment, DateGeneration_Forward_get(), F ) floatingSchedule = Schedule( forwardStart, forwardEnd, floatingLegTenor, calendar, floatingLegAdjustment, floatingLegAdjustment, DateGeneration_Forward_get(), F ) # %% forward = VanillaSwap( Swap_Payer_get(), nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatingSchedule, index, spread, floatingLegDayCounter ) forward$setPricingEngine(swapEngine) # We'll price them both on the bootstrapped curves. # # This is the quoted 5-years market rate; we expect the fair rate of the spot swap to match it. # %% print(swaps["5Y"]) showSwap <- function(swap) { print(paste("NPV = ", swap$NPV())) print(paste("Fair spread = ", (swap$fairSpread()*100))) print(paste("Fair rate = ", (swap$fairRate()*100))) } # %% [markdown] # These are the results for the 5-years spot swap on the deposit/futures/swap curve... # %% forecastTermStructure$linkTo(depoFuturesSwapCurve) showSwap(spot) # ...and these are on the deposit/fra/swap curve. # %% forecastTermStructure$linkTo(depoFraSwapCurve) showSwap(spot) # %% [markdown] # The same goes for the 1-year forward swap, except for the fair rate not matching the spot rate. # %% forecastTermStructure$linkTo(depoFuturesSwapCurve) showSwap(forward) # %% forecastTermStructure$linkTo(depoFraSwapCurve) showSwap(forward) QuantLib-SWIG-1.39/R/demo/wireframe.R000066400000000000000000000037541503741206100171750ustar00rootroot00000000000000 suppressMessages(library(QuantLib)) library(lattice) library(grid) spot<-seq(10.0,95.00,len=20) vol<-seq(0.20,1.0,len=20) g<-expand.grid(spot=spot,vol=vol) todaysDate <- Date(15, "May", 1998) Settings_instance()$setEvaluationDate(d=todaysDate) settlementDate <- Date(17, "May", 1998) riskQuote <- SimpleQuote(0.05) riskFreeRate <- FlatForward(settlementDate, QuoteHandle(riskQuote), Actual365Fixed()) exercise <- EuropeanExercise(Date(17, "May", 1999)) payoff <- PlainVanillaPayoff("Call", 50.0) dividendYield <- FlatForward(settlementDate, 0.05, Actual365Fixed()) underlying <- SimpleQuote(10.0) volatilityQuote <- SimpleQuote(0.05) volatility <- BlackConstantVol(todaysDate, TARGET(), QuoteHandle(volatilityQuote), Actual365Fixed()) process <- BlackScholesMertonProcess(QuoteHandle(underlying), YieldTermStructureHandle(dividendYield), YieldTermStructureHandle(riskFreeRate), BlackVolTermStructureHandle(volatility)) engine <- AnalyticEuropeanEngine(process) option <- VanillaOption(payoff, exercise) option$setPricingEngine(s_arg2=engine) t <- mapply(function(x,y) { underlying$setValue(value=x) volatilityQuote$setValue(value=y) list(NPV=option$NPV(), gamma=option$gamma(), delta=option$delta(), vega=option$vega())}, g$spot, g$vol, SIMPLIFY=FALSE) g$NPV <- sapply(1:length(t), function(x) t[[x]]$NPV) g$gamma <- sapply(1:length(t), function(x) t[[x]]$gamma) g$delta <- sapply(1:length(t), function(x) t[[x]]$delta) g$vega <- sapply(1:length(t), function(x) t[[x]]$vega) par(mfrow = c(2,3)) plot <- vector("list",10) plot[[1]] <- wireframe(NPV ~ spot*vol, g, drape=TRUE) plot[[2]] <- wireframe(gamma ~ spot*vol, g, drape=TRUE) plot[[3]] <- wireframe(delta ~ spot*vol, g, drape=TRUE) plot[[4]] <- wireframe(vega ~ spot*vol, g, drape=TRUE) grid.newpage() pushViewport(viewport(layout=grid.layout(2,2))) for (i in 1:4) { pushViewport(viewport(layout.pos.col=((i - 1) %% 2) + 1, layout.pos.row=((i - 1) %/% 2) + 1)) print(plot[[i]], newpage=FALSE) popViewport() } popViewport() QuantLib-SWIG-1.39/R/src/000077500000000000000000000000001503741206100147235ustar00rootroot00000000000000QuantLib-SWIG-1.39/R/src/Makevars000066400000000000000000000001131503741206100164120ustar00rootroot00000000000000PKG_CPPFLAGS=`quantlib-config --cflags` PKG_LIBS=`quantlib-config --libs` QuantLib-SWIG-1.39/README.md000066400000000000000000000053371503741206100152220ustar00rootroot00000000000000 QuantLib-SWIG: language bindings for QuantLib ============================================= [![Download source](https://img.shields.io/github/v/release/lballabio/QuantLib-SWIG?label=source&sort=semver)](https://github.com/lballabio/QuantLib-SWIG/releases/latest) [![PyPI version](https://img.shields.io/pypi/v/quantlib?label=PyPI)](https://pypi.org/project/QuantLib) ![PRs Welcome](https://img.shields.io/badge/PRs%20-welcome-brightgreen.svg) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1441003.svg)](https://doi.org/10.5281/zenodo.1441003) [![Build status](https://github.com/lballabio/QuantLib-SWIG/workflows/Linux%20build/badge.svg?branch=master)](https://github.com/lballabio/QuantLib-SWIG/actions?query=workflow%3A%22Linux+build%22) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/lballabio/QuantLib-SWIG/binder?urlpath=lab/tree/Python/examples) --- The QuantLib project () is aimed at providing a comprehensive software framework for quantitative finance. QuantLib is a free/open-source library for modeling, trading, and risk management in real-life. QuantLib is Non-Copylefted Free Software and OSI Certified Open Source Software. QuantLib-SWIG provides the means to use QuantLib from a number of languages; currently their list includes Python, C#, Java, Scala and R. Questions and feedback ---------------------- Bugs can be reported as a GitHub issue at ; if you have a patch available, you can open a pull request instead (see "Contributing" below). You can also use the `quantlib-users` and `quantlib-dev` mailing lists for feedback, questions, etc. More information and instructions for subscribing are at . Contributing ------------ The easiest way to contribute is through pull requests on GitHub. Get a GitHub account if you don't have it already and clone the repository at with the "Fork" button in the top right corner of the page. Check out your clone to your machine, code away, push your changes to your clone and submit a pull request; instructions are available at . (In case you need them, more detailed instructions for creating pull requests are at , and a basic guide to GitHub is at . It's likely that we won't merge your code right away, and we'll ask for some changes instead. Don't be discouraged! That's normal; the library is complex, and thus it might take some time to become familiar with it and to use it in an idiomatic way. We're looking forward to your contributions. QuantLib-SWIG-1.39/SWIG/000077500000000000000000000000001503741206100145045ustar00rootroot00000000000000QuantLib-SWIG-1.39/SWIG/asianoptions.i000066400000000000000000000471541503741206100174000ustar00rootroot00000000000000/* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 StatPro Italia srl Copyright (C) 2010, 2012, 2018, 2019 Klaus Spanderen Copyright (C) 2018, 2019 Matthias Lungwitz Copyright (C) 2020, 2022 Jack Gillett This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_asian_options_i #define quantlib_asian_options_i %include options.i %include grid.i %{ using QuantLib::Average; using QuantLib::ContinuousAveragingAsianOption; using QuantLib::DiscreteAveragingAsianOption; %} struct Average { enum Type { Arithmetic, Geometric }; }; %shared_ptr(ContinuousAveragingAsianOption) class ContinuousAveragingAsianOption : public OneAssetOption { public: ContinuousAveragingAsianOption( Average::Type averageType, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); }; %shared_ptr(DiscreteAveragingAsianOption) class DiscreteAveragingAsianOption : public OneAssetOption { public: DiscreteAveragingAsianOption( Average::Type averageType, Real runningAccumulator, Size pastFixings, std::vector fixingDates, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); DiscreteAveragingAsianOption( Average::Type averageType, std::vector fixingDates, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise, std::vector allPastFixings = std::vector()); %extend { TimeGrid timeGrid() { return self->result("TimeGrid"); } } }; %{ using QuantLib::AnalyticContinuousGeometricAveragePriceAsianEngine; using QuantLib::AnalyticContinuousGeometricAveragePriceAsianHestonEngine; using QuantLib::AnalyticDiscreteGeometricAveragePriceAsianEngine; using QuantLib::AnalyticDiscreteGeometricAveragePriceAsianHestonEngine; using QuantLib::AnalyticDiscreteGeometricAverageStrikeAsianEngine; %} %shared_ptr(AnalyticContinuousGeometricAveragePriceAsianEngine) class AnalyticContinuousGeometricAveragePriceAsianEngine : public PricingEngine { public: AnalyticContinuousGeometricAveragePriceAsianEngine( const ext::shared_ptr& process); }; %shared_ptr(AnalyticContinuousGeometricAveragePriceAsianHestonEngine) class AnalyticContinuousGeometricAveragePriceAsianHestonEngine : public PricingEngine { public: AnalyticContinuousGeometricAveragePriceAsianHestonEngine( const ext::shared_ptr& process, Size summationCutoff = 50, Real xiRightLimit = 100.0); }; %shared_ptr(AnalyticDiscreteGeometricAveragePriceAsianEngine) class AnalyticDiscreteGeometricAveragePriceAsianEngine : public PricingEngine { public: AnalyticDiscreteGeometricAveragePriceAsianEngine( const ext::shared_ptr& process); }; %shared_ptr(AnalyticDiscreteGeometricAveragePriceAsianHestonEngine) class AnalyticDiscreteGeometricAveragePriceAsianHestonEngine : public PricingEngine { public: AnalyticDiscreteGeometricAveragePriceAsianHestonEngine( const ext::shared_ptr& process, Real xiRightLimit = 100.0); }; %shared_ptr(AnalyticDiscreteGeometricAverageStrikeAsianEngine) class AnalyticDiscreteGeometricAverageStrikeAsianEngine : public PricingEngine { public: AnalyticDiscreteGeometricAverageStrikeAsianEngine( const ext::shared_ptr& process); }; %{ using QuantLib::MCDiscreteArithmeticAPEngine; using QuantLib::MCDiscreteArithmeticAPHestonEngine; using QuantLib::MCDiscreteArithmeticASEngine; using QuantLib::MCDiscreteGeometricAPEngine; using QuantLib::MCDiscreteGeometricAPHestonEngine; %} %shared_ptr(MCDiscreteArithmeticAPEngine); %shared_ptr(MCDiscreteArithmeticAPEngine); template class MCDiscreteArithmeticAPEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCDiscreteArithmeticAPEngine; #endif public: %extend { MCDiscreteArithmeticAPEngine(const ext::shared_ptr& process, bool brownianBridge = false, bool antitheticVariate = false, bool controlVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0) { return new MCDiscreteArithmeticAPEngine(process, brownianBridge, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed); } } }; %template(MCPRDiscreteArithmeticAPEngine) MCDiscreteArithmeticAPEngine; %template(MCLDDiscreteArithmeticAPEngine) MCDiscreteArithmeticAPEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCDiscreteArithmeticAPEngine(process, traits, brownianBridge=False, antitheticVariate=False, controlVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRDiscreteArithmeticAPEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDDiscreteArithmeticAPEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, brownianBridge, antitheticVariate, controlVariate, requiredSamples, requiredTolerance, maxSamples, seed) %} #endif %shared_ptr(MCDiscreteArithmeticAPHestonEngine); %shared_ptr(MCDiscreteArithmeticAPHestonEngine); template class MCDiscreteArithmeticAPHestonEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCDiscreteArithmeticAPHestonEngine; #endif public: %extend { MCDiscreteArithmeticAPHestonEngine(const ext::shared_ptr& process, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0, intOrNull timeSteps = Null(), intOrNull timeStepsPerYear = Null(), bool controlVariate = false) { return new MCDiscreteArithmeticAPHestonEngine(process, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, timeSteps, timeStepsPerYear, controlVariate); } } }; %template(MCPRDiscreteArithmeticAPHestonEngine) MCDiscreteArithmeticAPHestonEngine; %template(MCLDDiscreteArithmeticAPHestonEngine) MCDiscreteArithmeticAPHestonEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCDiscreteArithmeticAPHestonEngine(process, traits, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0, timeSteps=None, timeStepsPerYear=None, controlVariate=False): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRDiscreteArithmeticAPHestonEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDDiscreteArithmeticAPHestonEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, timeSteps, timeStepsPerYear, controlVariate) %} #endif %shared_ptr(MCDiscreteArithmeticASEngine); %shared_ptr(MCDiscreteArithmeticASEngine); template class MCDiscreteArithmeticASEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCDiscreteArithmeticASEngine; #endif public: %extend { MCDiscreteArithmeticASEngine( const ext::shared_ptr& process, bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0) { return new MCDiscreteArithmeticASEngine(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed); } } }; %template(MCPRDiscreteArithmeticASEngine) MCDiscreteArithmeticASEngine; %template(MCLDDiscreteArithmeticASEngine) MCDiscreteArithmeticASEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCDiscreteArithmeticASEngine(process, traits, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRDiscreteArithmeticASEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDDiscreteArithmeticASEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed) %} #endif %shared_ptr(MCDiscreteGeometricAPEngine); %shared_ptr(MCDiscreteGeometricAPEngine); template class MCDiscreteGeometricAPEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCDiscreteGeometricAPEngine; #endif public: %extend { MCDiscreteGeometricAPEngine( const ext::shared_ptr& process, bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0) { return new MCDiscreteGeometricAPEngine(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed); } } }; %template(MCPRDiscreteGeometricAPEngine) MCDiscreteGeometricAPEngine; %template(MCLDDiscreteGeometricAPEngine) MCDiscreteGeometricAPEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCDiscreteGeometricAPEngine(process, traits, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRDiscreteGeometricAPEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDDiscreteGeometricAPEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed) %} #endif %shared_ptr(MCDiscreteGeometricAPHestonEngine); %shared_ptr(MCDiscreteGeometricAPHestonEngine); template class MCDiscreteGeometricAPHestonEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCDiscreteGeometricAPHestonEngine; #endif public: %extend { MCDiscreteGeometricAPHestonEngine(const ext::shared_ptr& process, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0, intOrNull timeSteps = Null(), intOrNull timeStepsPerYear = Null()) { return new MCDiscreteGeometricAPHestonEngine(process, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, timeSteps, timeStepsPerYear); } } }; %template(MCPRDiscreteGeometricAPHestonEngine) MCDiscreteGeometricAPHestonEngine; %template(MCLDDiscreteGeometricAPHestonEngine) MCDiscreteGeometricAPHestonEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCDiscreteGeometricAPHestonEngine(process, traits, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0, timeSteps=None, timeStepsPerYear=None): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRDiscreteGeometricAPHestonEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDDiscreteGeometricAPHestonEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, timeSteps, timeStepsPerYear) %} #endif %{ using QuantLib::ContinuousArithmeticAsianLevyEngine; %} %shared_ptr(ContinuousArithmeticAsianLevyEngine) class ContinuousArithmeticAsianLevyEngine : public PricingEngine { public: ContinuousArithmeticAsianLevyEngine(const ext::shared_ptr& process, const Handle& runningAverage, const Date& startDate); }; %{ using QuantLib::FdBlackScholesAsianEngine; %} %shared_ptr(FdBlackScholesAsianEngine) class FdBlackScholesAsianEngine : public PricingEngine { public: FdBlackScholesAsianEngine(const ext::shared_ptr& process, Size tGrid, Size xGrid, Size aGrid); }; %{ using QuantLib::ChoiAsianEngine; %} %shared_ptr(ChoiAsianEngine) class ChoiAsianEngine : public PricingEngine { public: ChoiAsianEngine( ext::shared_ptr process, Real lambda = 15, Size maxNrIntegrationSteps = 2 << 21); }; %{ using QuantLib::TurnbullWakemanAsianEngine; %} %shared_ptr(TurnbullWakemanAsianEngine) class TurnbullWakemanAsianEngine : public PricingEngine { public: TurnbullWakemanAsianEngine(const ext::shared_ptr& process); }; #endif QuantLib-SWIG-1.39/SWIG/barrieroptions.i000066400000000000000000000567301503741206100177330ustar00rootroot00000000000000/* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 StatPro Italia srl Copyright (C) 2015 Thema Consulting SA Copyright (C) 2018, 2019 Matthias Lungwitz Copyright (C) 2022 Ignacio Anguita This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_barrier_options_i #define quantlib_barrier_options_i %include options.i %include dividends.i %{ using QuantLib::Barrier; %} struct Barrier { enum Type { DownIn, UpIn, DownOut, UpOut }; }; %{ using QuantLib::BarrierOption; using QuantLib::QuantoBarrierOption; %} %shared_ptr(BarrierOption) class BarrierOption : public OneAssetOption { public: BarrierOption( Barrier::Type barrierType, Real barrier, Real rebate, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); Volatility impliedVolatility( Real targetValue, const ext::shared_ptr& process, Real accuracy = 1.0e-4, Size maxEvaluations = 100, Volatility minVol = 1.0e-4, Volatility maxVol = 4.0); Volatility impliedVolatility( Real targetValue, const ext::shared_ptr& process, const DividendSchedule& dividends, Real accuracy = 1.0e-4, Size maxEvaluations = 100, Volatility minVol = 1.0e-4, Volatility maxVol = 4.0); }; %shared_ptr(QuantoBarrierOption) class QuantoBarrierOption : public BarrierOption { public: QuantoBarrierOption( Barrier::Type barrierType, Real barrier, Real rebate, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); }; %{ using QuantLib::PartialBarrier; %} struct PartialBarrier { enum Range { Start = 0, EndB1 = 2, EndB2 = 3 }; }; %{ using QuantLib::PartialTimeBarrierOption; %} %shared_ptr(PartialTimeBarrierOption) class PartialTimeBarrierOption : public OneAssetOption { public: PartialTimeBarrierOption( Barrier::Type barrierType, PartialBarrier::Range barrierRange, Real barrier, Real rebate, Date coverEventDate, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); }; %{ using QuantLib::AnalyticPartialTimeBarrierOptionEngine; %} #if defined(SWIGPYTHON) %feature("docstring") AnalyticPartialTimeBarrierOptionEngine "Partial Time Barrier Option Engine" #endif %shared_ptr(AnalyticPartialTimeBarrierOptionEngine ) class AnalyticPartialTimeBarrierOptionEngine : public PricingEngine { public: AnalyticPartialTimeBarrierOptionEngine ( const ext::shared_ptr& process); }; %{ using QuantLib::AnalyticBarrierEngine; using QuantLib::MCBarrierEngine; %} %shared_ptr(AnalyticBarrierEngine) class AnalyticBarrierEngine : public PricingEngine { public: AnalyticBarrierEngine(const ext::shared_ptr&); }; %shared_ptr(MCBarrierEngine); %shared_ptr(MCBarrierEngine); template class MCBarrierEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCBarrierEngine; #endif public: %extend { MCBarrierEngine(const ext::shared_ptr& process, intOrNull timeSteps = Null(), intOrNull timeStepsPerYear = Null(), bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), bool isBiased = false, BigInteger seed = 0) { return new MCBarrierEngine(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, isBiased, seed); } } }; %template(MCPRBarrierEngine) MCBarrierEngine; %template(MCLDBarrierEngine) MCBarrierEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCBarrierEngine(process, traits, timeSteps=None, timeStepsPerYear=None, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, isBiased=False, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRBarrierEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDBarrierEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, isBiased, seed) %} #endif %{ using QuantLib::QuantoEngine; typedef QuantoEngine QuantoBarrierEngine; %} %shared_ptr(QuantoBarrierEngine); class QuantoBarrierEngine : public PricingEngine { public: QuantoBarrierEngine(ext::shared_ptr, Handle foreignRiskFreeRate, Handle exchangeRateVolatility, Handle correlation); }; %{ using QuantLib::FdBlackScholesBarrierEngine; using QuantLib::FdBlackScholesRebateEngine; using QuantLib::FdHestonBarrierEngine; using QuantLib::FdHestonRebateEngine; %} %shared_ptr(FdBlackScholesBarrierEngine) class FdBlackScholesBarrierEngine : public PricingEngine { public: FdBlackScholesBarrierEngine(const ext::shared_ptr& process, Size tGrid = 100, Size xGrid = 100, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas(), bool localVol = false, Real illegalLocalVolOverwrite = -Null()); FdBlackScholesBarrierEngine(const ext::shared_ptr& process, DividendSchedule dividends, Size tGrid = 100, Size xGrid = 100, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas(), bool localVol = false, Real illegalLocalVolOverwrite = -Null()); }; %shared_ptr(FdBlackScholesRebateEngine) class FdBlackScholesRebateEngine : public PricingEngine { public: FdBlackScholesRebateEngine(const ext::shared_ptr& process, Size tGrid = 100, Size xGrid = 100, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas(), bool localVol = false, Real illegalLocalVolOverwrite = -Null()); FdBlackScholesRebateEngine(const ext::shared_ptr& process, DividendSchedule dividends, Size tGrid = 100, Size xGrid = 100, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas(), bool localVol = false, Real illegalLocalVolOverwrite = -Null()); }; %shared_ptr(FdHestonBarrierEngine) class FdHestonBarrierEngine : public PricingEngine { public: FdHestonBarrierEngine(const ext::shared_ptr& model, Size tGrid = 100, Size xGrid = 100, Size vGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer(), const ext::shared_ptr& leverageFct = {}, const Real mixingFactor = 1.0); FdHestonBarrierEngine(const ext::shared_ptr& model, DividendSchedule dividends, Size tGrid = 100, Size xGrid = 100, Size vGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer(), const ext::shared_ptr& leverageFct = {}, const Real mixingFactor = 1.0); }; %shared_ptr(FdHestonRebateEngine) class FdHestonRebateEngine : public PricingEngine { public: FdHestonRebateEngine(const ext::shared_ptr& model, Size tGrid = 100, Size xGrid = 100, Size vGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer(), const ext::shared_ptr& leverageFct = {}, const Real mixingFactor = 1.0); FdHestonRebateEngine(const ext::shared_ptr& model, DividendSchedule dividends, Size tGrid = 100, Size xGrid = 100, Size vGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer(), const ext::shared_ptr& leverageFct = {}, const Real mixingFactor = 1.0); }; %{ using QuantLib::AnalyticBinaryBarrierEngine; %} %shared_ptr(AnalyticBinaryBarrierEngine) class AnalyticBinaryBarrierEngine : public PricingEngine { public: AnalyticBinaryBarrierEngine( const ext::shared_ptr& process); }; %{ using QuantLib::BinomialBarrierEngine; using QuantLib::DiscretizedDermanKaniBarrierOption; %} #if defined(SWIGPYTHON) %feature("docstring") BinomialBarrierEngine "Binomial Engine for barrier options. Features different binomial models, selected by the type parameters. Uses Boyle-Lau adjustment for optimize steps and Derman-Kani optimization to speed up convergence. Type values: crr or coxrossrubinstein: Cox-Ross-Rubinstein model jr or jarrowrudd: Jarrow-Rudd model eqp or additiveeqpbinomialtree: Additive EQP model trigeorgis: Trigeorgis model tian: Tian model lr or leisenreimer Leisen-Reimer model j4 or joshi4: Joshi 4th (smoothed) model Boyle-Lau adjustment is controlled by parameter max_steps. If max_steps is equal to steps Boyle-Lau is disabled. Il max_steps is 0 (default value), max_steps is calculated by capping it to 5*steps when Boyle-Lau would need more than 1000 steps. If max_steps is specified, it would limit binomial steps to this value. " #endif #if !defined(SWIGR) %shared_ptr(BinomialBarrierEngine); %shared_ptr(BinomialBarrierEngine); %shared_ptr(BinomialBarrierEngine); %shared_ptr(BinomialBarrierEngine); %shared_ptr(BinomialBarrierEngine); %shared_ptr(BinomialBarrierEngine); %shared_ptr(BinomialBarrierEngine); template class BinomialBarrierEngine : public PricingEngine { public: BinomialBarrierEngine(const ext::shared_ptr&, Size steps, Size max_steps = 0); }; %template(BinomialCRRBarrierEngine) BinomialBarrierEngine; %template(BinomialJRBarrierEngine) BinomialBarrierEngine; %template(BinomialEQPBarrierEngine) BinomialBarrierEngine; %template(BinomialTrigeorgisBarrierEngine) BinomialBarrierEngine; %template(BinomialTianBarrierEngine) BinomialBarrierEngine; %template(BinomialLRBarrierEngine) BinomialBarrierEngine; %template(BinomialJ4BarrierEngine) BinomialBarrierEngine; #if defined(SWIGPYTHON) %pythoncode %{ def BinomialBarrierEngine(process, type, steps): type = type.lower() if type == "crr" or type == "coxrossrubinstein": cls = BinomialCRRBarrierEngine elif type == "jr" or type == "jarrowrudd": cls = BinomialJRBarrierEngine elif type == "eqp": cls = BinomialEQPBarrierEngine elif type == "trigeorgis": cls = BinomialTrigeorgisBarrierEngine elif type == "tian": cls = BinomialTianBarrierEngine elif type == "lr" or type == "leisenreimer": cls = BinomialLRBarrierEngine elif type == "j4" or type == "joshi4": cls = BinomialJ4BarrierEngine else: raise RuntimeError("unknown binomial engine type: %s" % type); return cls(process, steps) %} #endif #endif %{ using QuantLib::VannaVolgaBarrierEngine; %} %shared_ptr(VannaVolgaBarrierEngine) class VannaVolgaBarrierEngine : public PricingEngine { public: VannaVolgaBarrierEngine( const Handle& atmVol, const Handle& vol25Put, const Handle& vol25Call, const Handle& spotFX, const Handle& domesticTS, const Handle& foreignTS, const bool adaptVanDelta = false, const Real bsPriceWithSmile = 0.0); }; %{ using QuantLib::DoubleBarrierOption; using QuantLib::DoubleBarrier; %} struct DoubleBarrier { enum Type { KnockIn, KnockOut, KIKO, KOKI }; }; %shared_ptr(DoubleBarrierOption) class DoubleBarrierOption : public OneAssetOption { public: DoubleBarrierOption( DoubleBarrier::Type barrierType, Real barrier_lo, Real barrier_hi, Real rebate, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); }; %{ using QuantLib::QuantoDoubleBarrierOption; %} %shared_ptr(QuantoDoubleBarrierOption) class QuantoDoubleBarrierOption : public DoubleBarrierOption { public: QuantoDoubleBarrierOption( DoubleBarrier::Type barrierType, Real barrier_lo, Real barrier_hi, Real rebate, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); Real qvega(); Real qrho(); Real qlambda(); }; %{ using QuantLib::AnalyticDoubleBarrierEngine; %} #if defined(SWIGPYTHON) %feature("docstring") AnalyticDoubleBarrierEngine "Double barrier engine implementing Ikeda-Kunitomo series." #endif %shared_ptr(AnalyticDoubleBarrierEngine) class AnalyticDoubleBarrierEngine : public PricingEngine { public: AnalyticDoubleBarrierEngine( const ext::shared_ptr& process, int series = 5); }; %{ using QuantLib::FdHestonDoubleBarrierEngine; %} %shared_ptr(FdHestonDoubleBarrierEngine); class FdHestonDoubleBarrierEngine : public PricingEngine { public: FdHestonDoubleBarrierEngine( const ext::shared_ptr& model, Size tGrid = 100, Size xGrid = 100, Size vGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer(), const ext::shared_ptr& leverageFct = ext::shared_ptr(), const Real mixingFactor = 1.0); }; %{ using QuantLib::SuoWangDoubleBarrierEngine; %} %shared_ptr(SuoWangDoubleBarrierEngine) class SuoWangDoubleBarrierEngine : public PricingEngine { public: SuoWangDoubleBarrierEngine( const ext::shared_ptr& process, int series = 5); }; %{ using QuantLib::VannaVolgaDoubleBarrierEngine; %} %shared_ptr(VannaVolgaDoubleBarrierEngine); %shared_ptr(VannaVolgaDoubleBarrierEngine); template class VannaVolgaDoubleBarrierEngine : public PricingEngine { public: VannaVolgaDoubleBarrierEngine( const Handle atmVol, const Handle vol25Put, const Handle vol25Call, const Handle spotFX, const Handle domesticTS, const Handle foreignTS, const bool adaptVanDelta = false, const Real bsPriceWithSmile = 0.0, int series = 5); }; %template(VannaVolgaIKDoubleBarrierEngine) VannaVolgaDoubleBarrierEngine; %template(VannaVolgaWODoubleBarrierEngine) VannaVolgaDoubleBarrierEngine; %{ using QuantLib::AnalyticDoubleBarrierBinaryEngine; %} %shared_ptr(AnalyticDoubleBarrierBinaryEngine) class AnalyticDoubleBarrierBinaryEngine : public PricingEngine { public: AnalyticDoubleBarrierBinaryEngine( const ext::shared_ptr& process); }; %{ using QuantLib::BinomialDoubleBarrierEngine; using QuantLib::DiscretizedDermanKaniDoubleBarrierOption; %} #if defined(SWIGPYTHON) %feature("docstring") BinomialDoubleBarrierEngine "Binomial Engine for double barrier options. Features different binomial models, selected by the type parameters. Uses Derman-Kani optimization to speed up convergence. Type values: crr or coxrossrubinstein: Cox-Ross-Rubinstein model jr or jarrowrudd: Jarrow-Rudd model eqp or additiveeqpbinomialtree: Additive EQP model trigeorgis: Trigeorgis model tian: Tian model lr or leisenreimer Leisen-Reimer model j4 or joshi4: Joshi 4th (smoothed) model " #endif #if !defined(SWIGR) %shared_ptr(BinomialDoubleBarrierEngine); %shared_ptr(BinomialDoubleBarrierEngine); %shared_ptr(BinomialDoubleBarrierEngine); %shared_ptr(BinomialDoubleBarrierEngine); %shared_ptr(BinomialDoubleBarrierEngine); %shared_ptr(BinomialDoubleBarrierEngine); %shared_ptr(BinomialDoubleBarrierEngine); template class BinomialDoubleBarrierEngine : public PricingEngine { public: BinomialDoubleBarrierEngine(const ext::shared_ptr&, Size steps); }; %template(BinomialCRRDoubleBarrierEngine) BinomialDoubleBarrierEngine; %template(BinomialJRDoubleBarrierEngine) BinomialDoubleBarrierEngine; %template(BinomialEQPDoubleBarrierEngine) BinomialDoubleBarrierEngine; %template(BinomialTrigeorgisDoubleBarrierEngine) BinomialDoubleBarrierEngine; %template(BinomialTianDoubleBarrierEngine) BinomialDoubleBarrierEngine; %template(BinomialLRDoubleBarrierEngine) BinomialDoubleBarrierEngine; %template(BinomialJ4DoubleBarrierEngine) BinomialDoubleBarrierEngine; #if defined(SWIGPYTHON) %pythoncode %{ def BinomialDoubleBarrierEngine(process, type, steps): type = type.lower() if type == "crr" or type == "coxrossrubinstein": cls = BinomialCRRDoubleBarrierEngine elif type == "jr" or type == "jarrowrudd": cls = BinomialJRDoubleBarrierEngine elif type == "eqp": cls = BinomialEQPDoubleBarrierEngine elif type == "trigeorgis": cls = BinomialTrigeorgisDoubleBarrierEngine elif type == "tian": cls = BinomialTianDoubleBarrierEngine elif type == "lr" or type == "leisenreimer": cls = BinomialLRDoubleBarrierEngine elif type == "j4" or type == "joshi4": cls = BinomialJ4DoubleBarrierEngine else: raise RuntimeError("unknown binomial engine type: %s" % type); return cls(process, steps) %} #endif #endif %{ using QuantLib::TwoAssetBarrierOption; using QuantLib::AnalyticTwoAssetBarrierEngine; %} %shared_ptr(TwoAssetBarrierOption) class TwoAssetBarrierOption : public Option { public: TwoAssetBarrierOption(Barrier::Type barrierType, Real barrier, const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); }; %shared_ptr(AnalyticTwoAssetBarrierEngine) class AnalyticTwoAssetBarrierEngine : public PricingEngine { public: AnalyticTwoAssetBarrierEngine(ext::shared_ptr process1, ext::shared_ptr process2, Handle rho); }; #endif QuantLib-SWIG-1.39/SWIG/basketoptions.i000066400000000000000000000437701503741206100175560ustar00rootroot00000000000000/* Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 StatPro Italia srl Copyright (C) 2005 Dominic Thuillier Copyright (C) 2007 Joseph Wang Copyright (C) 2018, 2019 Matthias Lungwitz Copyright (C) 2024 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_basket_options_i #define quantlib_basket_options_i %include date.i %include options.i %include payoffs.i %{ using QuantLib::BasketOption; using QuantLib::BasketPayoff; using QuantLib::MinBasketPayoff; using QuantLib::MaxBasketPayoff; using QuantLib::AverageBasketPayoff; using QuantLib::SpreadBasketPayoff; %} %shared_ptr(BasketPayoff) class BasketPayoff : public Payoff { private: BasketPayoff(); }; %shared_ptr(MinBasketPayoff) class MinBasketPayoff : public BasketPayoff { public: MinBasketPayoff(const ext::shared_ptr p); }; %shared_ptr(MaxBasketPayoff) class MaxBasketPayoff : public BasketPayoff { public: MaxBasketPayoff(const ext::shared_ptr p); }; %shared_ptr(AverageBasketPayoff) class AverageBasketPayoff : public BasketPayoff { public: AverageBasketPayoff(const ext::shared_ptr p, const Array &a); AverageBasketPayoff(const ext::shared_ptr p, Size n); }; %shared_ptr(SpreadBasketPayoff) class SpreadBasketPayoff : public BasketPayoff { public: SpreadBasketPayoff(const ext::shared_ptr p); }; %shared_ptr(BasketOption) class BasketOption : public MultiAssetOption { public: BasketOption( const ext::shared_ptr& payoff, const ext::shared_ptr& exercise); }; %{ using QuantLib::MCEuropeanBasketEngine; using QuantLib::MCAmericanBasketEngine; %} %shared_ptr(MCEuropeanBasketEngine); %shared_ptr(MCEuropeanBasketEngine); template class MCEuropeanBasketEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCEuropeanBasketEngine; #endif public: %extend { MCEuropeanBasketEngine(const ext::shared_ptr& process, intOrNull timeSteps = Null(), intOrNull timeStepsPerYear = Null(), bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0) { return new MCEuropeanBasketEngine(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed); } } }; %template(MCPREuropeanBasketEngine) MCEuropeanBasketEngine; %template(MCLDEuropeanBasketEngine) MCEuropeanBasketEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCEuropeanBasketEngine(process, traits, timeSteps=None, timeStepsPerYear=None, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPREuropeanBasketEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDEuropeanBasketEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed) %} #endif %shared_ptr(MCAmericanBasketEngine); %shared_ptr(MCAmericanBasketEngine); template class MCAmericanBasketEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCAmericanBasketEngine; #endif public: %extend { MCAmericanBasketEngine(const ext::shared_ptr& process, intOrNull timeSteps = Null(), intOrNull timeStepsPerYear = Null(), bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0, Size nCalibrationSamples = Null(), Size polynomOrder = 2, LsmBasisSystem::PolynomialType polynomType = LsmBasisSystem::Monomial) { return new MCAmericanBasketEngine(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, nCalibrationSamples, polynomOrder, polynomType); } } }; %template(MCPRAmericanBasketEngine) MCAmericanBasketEngine; %template(MCLDAmericanBasketEngine) MCAmericanBasketEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCAmericanBasketEngine(process, traits, timeSteps=None, timeStepsPerYear=None, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0, nCalibrationSamples=2048, polynomOrder=2, polynomType=LsmBasisSystem.Monomial): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRAmericanBasketEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDAmericanBasketEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed, nCalibrationSamples, polynomOrder, polynomType) %} #endif %{ using QuantLib::StulzEngine; using QuantLib::KirkEngine; using QuantLib::BjerksundStenslandSpreadEngine; using QuantLib::OperatorSplittingSpreadEngine; using QuantLib::Fd2dBlackScholesVanillaEngine; %} %shared_ptr(StulzEngine) class StulzEngine : public PricingEngine { public: StulzEngine(const ext::shared_ptr& process1, const ext::shared_ptr& process2, Real correlation); }; %shared_ptr(KirkEngine) class KirkEngine : public PricingEngine { public: KirkEngine(ext::shared_ptr process1, ext::shared_ptr process2, Real correlation); }; %shared_ptr(BjerksundStenslandSpreadEngine) class BjerksundStenslandSpreadEngine : public PricingEngine { public: BjerksundStenslandSpreadEngine( ext::shared_ptr process1, ext::shared_ptr process2, Real correlation); }; %shared_ptr(OperatorSplittingSpreadEngine) class OperatorSplittingSpreadEngine : public PricingEngine { public: enum Order {First, Second}; OperatorSplittingSpreadEngine( ext::shared_ptr process1, ext::shared_ptr process2, Real correlation, Order order = Second); }; %shared_ptr(Fd2dBlackScholesVanillaEngine) class Fd2dBlackScholesVanillaEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") Fd2dBlackScholesVanillaEngine; #endif public: Fd2dBlackScholesVanillaEngine( const ext::shared_ptr& p1, const ext::shared_ptr& p2, Real correlation, Size xGrid = 100, Size yGrid = 100, Size tGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer(), bool localVol = false, Real illegalLocalVolOverwrite = -Null()); }; %{ using QuantLib::ChoiBasketEngine; using QuantLib::DengLiZhouBasketEngine; using QuantLib::FdndimBlackScholesVanillaEngine; %} #if defined(SWIGCSHARP) SWIG_STD_VECTOR_ENHANCED( ext::shared_ptr ) #endif %template(GeneralizedBlackScholesProcessVector) std::vector >; %shared_ptr(ChoiBasketEngine) class ChoiBasketEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") ChoiBasketEngine; #endif public: ChoiBasketEngine( std::vector > processes, Matrix rho, Real lambda = 10.0, Size maxNrIntegrationSteps = std::numeric_limits::max(), bool calcfwdDelta = false, bool controlVariate = false); }; %shared_ptr(DengLiZhouBasketEngine) class DengLiZhouBasketEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") DengLiZhouBasketEngine; #endif public: DengLiZhouBasketEngine( std::vector > processes, Matrix rho); }; %shared_ptr(FdndimBlackScholesVanillaEngine) class FdndimBlackScholesVanillaEngine : public PricingEngine { public: FdndimBlackScholesVanillaEngine( std::vector > processes, Matrix rho, Size xGrid, Size tGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer()); %extend { FdndimBlackScholesVanillaEngine( std::vector > processes, Matrix rho, const std::vector& dim, Size tGrid = 50, Size dampingSteps = 0, const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Hundsdorfer()) { return new FdndimBlackScholesVanillaEngine( processes, rho, to_vector(dim), tGrid, dampingSteps, schemeDesc ); } } }; %{ using QuantLib::EverestOption; using QuantLib::MCEverestEngine; %} %shared_ptr(EverestOption) class EverestOption : public MultiAssetOption { public: EverestOption(Real notional, Rate guarantee, const ext::shared_ptr& exercise); }; %shared_ptr(MCEverestEngine); %shared_ptr(MCEverestEngine); template class MCEverestEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCEverestEngine; #endif public: %extend { MCEverestEngine(const ext::shared_ptr& process, Size timeSteps = Null(), Size timeStepsPerYear = Null(), bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0) { return new MCEverestEngine(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed); } } }; %template(MCPREverestEngine) MCEverestEngine; %template(MCLDEverestEngine) MCEverestEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCEverestEngine(process, traits, timeSteps=None, timeStepsPerYear=None, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPREverestEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDEverestEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, timeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed) %} #endif %{ using QuantLib::HimalayaOption; using QuantLib::MCHimalayaEngine; %} %shared_ptr(HimalayaOption) class HimalayaOption : public MultiAssetOption { public: HimalayaOption(const std::vector& fixingDates, Real strike); }; %shared_ptr(MCHimalayaEngine); %shared_ptr(MCHimalayaEngine); template class MCHimalayaEngine : public PricingEngine { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") MCHimalayaEngine; #endif public: %extend { MCHimalayaEngine(const ext::shared_ptr& process, bool brownianBridge = false, bool antitheticVariate = false, intOrNull requiredSamples = Null(), doubleOrNull requiredTolerance = Null(), intOrNull maxSamples = Null(), BigInteger seed = 0) { return new MCHimalayaEngine(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed); } } }; %template(MCPRHimalayaEngine) MCHimalayaEngine; %template(MCLDHimalayaEngine) MCHimalayaEngine; #if defined(SWIGPYTHON) %pythoncode %{ def MCHimalayaEngine(process, traits, brownianBridge=False, antitheticVariate=False, requiredSamples=None, requiredTolerance=None, maxSamples=None, seed=0): traits = traits.lower() if traits == "pr" or traits == "pseudorandom": cls = MCPRHimalayaEngine elif traits == "ld" or traits == "lowdiscrepancy": cls = MCLDHimalayaEngine else: raise RuntimeError("unknown MC traits: %s" % traits); return cls(process, brownianBridge, antitheticVariate, requiredSamples, requiredTolerance, maxSamples, seed) %} #endif #endif QuantLib-SWIG-1.39/SWIG/blackformula.i000066400000000000000000000122661503741206100173270ustar00rootroot00000000000000 /* Copyright (C) 2017 Wojciech Åšlusarski Copyright (C) 2019 Matthias Lungwitz This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_black_formula_i #define quantlib_black_formula_i %include payoffs.i %{ using QuantLib::blackFormula; using QuantLib::blackFormulaImpliedStdDev; using QuantLib::blackFormulaImpliedStdDevLiRS; using QuantLib::blackFormulaCashItmProbability; using QuantLib::blackFormulaAssetItmProbability; using QuantLib::bachelierBlackFormula; using QuantLib::bachelierBlackFormulaImpliedVolChoi; using QuantLib::bachelierBlackFormulaImpliedVol; using QuantLib::bachelierBlackFormulaAssetItmProbability; %} Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount = 1.0, Real displacement = 0.0); Real blackFormulaImpliedStdDev(Option::Type optionType, Real strike, Real forward, Real blackPrice, Real discount = 1.0, Real displacement = 0.0, Real guess = Null(), Real accuracy = 1.0e-6, Natural maxIterations = 100); Real blackFormulaImpliedStdDevLiRS( Option::Type optionType, Real strike, Real forward, Real blackPrice, Real discount = 1.0, Real displacement = 0.0, Real guess = Null(), Real omega = 1.0, Real accuracy = 1.0e-6, Natural maxIterations = 100); Real blackFormulaImpliedStdDevLiRS( const ext::shared_ptr& payoff, Real forward, Real blackPrice, Real discount = 1.0, Real displacement = 0.0, Real guess = Null(), Real omega = 1.0, Real accuracy = 1.0e-6, Natural maxIterations = 100); Real blackFormulaCashItmProbability(Option::Type optionType, Real strike, Real forward, Real stdDev, Real displacement = 0.0); Real blackFormulaCashItmProbability( const ext::shared_ptr& payoff, Real forward, Real stdDev, Real displacement = 0.0); Real blackFormulaAssetItmProbability( Option::Type optionType, Real strike, Real forward, Real stdDev, Real displacement = 0.0); Real blackFormulaAssetItmProbability( const ext::shared_ptr& payoff, Real forward, Real stdDev, Real displacement = 0.0); Real bachelierBlackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount = 1.0); Real bachelierBlackFormulaImpliedVol(Option::Type optionType, Real strike, Real forward, Real tte, Real bachelierPrice, Real discount = 1.0); Real bachelierBlackFormulaImpliedVolChoi(Option::Type optionType, Real strike, Real forward, Real tte, Real bachelierPrice, Real discount = 1.0); Real bachelierBlackFormulaAssetItmProbability( Option::Type optionType, Real strike, Real forward, Real stdDev); Real bachelierBlackFormulaAssetItmProbability( const ext::shared_ptr& payoff, Real forward, Real stdDev); %{ using QuantLib::BlackDeltaCalculator; %} class BlackDeltaCalculator{ public: BlackDeltaCalculator( Option::Type ot, DeltaVolQuote::DeltaType dt, Real spot, DiscountFactor dDiscount, DiscountFactor fDiscount, Real stDev); Real deltaFromStrike(Real strike) const; Real strikeFromDelta(Real delta) const; Real atmStrike(DeltaVolQuote::AtmType atmT) const; }; #endif QuantLib-SWIG-1.39/SWIG/bondfunctions.i000066400000000000000000000224411503741206100175340ustar00rootroot00000000000000 /* Copyright (C) 2013 Simon Shakeshaft Copyright (C) 2016 Gouthaman Balaraman This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_bond_functions_i #define quantlib_bond_functions_i %include bonds.i %include common.i %include types.i %include daycounters.i %{ using QuantLib::BondFunctions; %} class BondFunctions { #if defined(SWIGPYTHON) %rename(bondYield) yield; #endif public: static Date startDate(const Bond& bond); static Date maturityDate(const Bond& bond); static bool isTradable(const Bond& bond, Date settlementDate = Date()); static Date previousCashFlowDate(const Bond& bond, Date refDate = Date()); static Date nextCashFlowDate(const Bond& bond, Date refDate = Date()); static Real previousCashFlowAmount(const Bond& bond, Date refDate = Date()); static Real nextCashFlowAmount(const Bond& bond, Date refDate = Date()); static Rate previousCouponRate(const Bond& bond, Date settlementDate = Date()); static Rate nextCouponRate(const Bond& bond, Date settlementDate = Date()); static Date accrualStartDate(const Bond& bond, Date settlementDate = Date()); static Date accrualEndDate(const Bond& bond, Date settlementDate = Date()); static Time accrualPeriod(const Bond& bond, Date settlementDate = Date()); static BigInteger accrualDays(const Bond& bond, Date settlementDate = Date()); static Time accruedPeriod(const Bond& bond, Date settlementDate = Date()); static BigInteger accruedDays(const Bond& bond, Date settlementDate = Date()); static Real accruedAmount(const Bond& bond, Date settlementDate = Date()); static Real cleanPrice(const Bond& bond, const YieldTermStructure& discountCurve, Date settlementDate = Date()); static Real dirtyPrice(const Bond& bond, const YieldTermStructure& discountCurve, Date settlementDate = Date()); static Real bps(const Bond& bond, const YieldTermStructure& discountCurve, Date settlementDate = Date()); static Rate atmRate(const Bond& bond, const YieldTermStructure& discountCurve, Date settlementDate = Date(), BondPrice price = {}); static Real cleanPrice(const Bond& bond, const InterestRate& yield, Date settlementDate = Date()); static Real cleanPrice(const Bond& bond, Rate yield, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Real bps(const Bond& bond, const InterestRate& yield, Date settlementDate = Date()); static Real bps(const Bond& bond, Rate yield, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Rate yield(const Bond& bond, BondPrice price, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date(), Real accuracy = 1.0e-10, Size maxIterations = 100, Rate guess = 0.05); static Time duration(const Bond& bond, const InterestRate& yield, Duration::Type type = Duration::Modified, Date settlementDate = Date()); static Time duration(const Bond& bond, Rate yield, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Duration::Type type = Duration::Modified, Date settlementDate = Date()); static Real convexity(const Bond& bond, const InterestRate& yield, Date settlementDate = Date()); static Real convexity(const Bond& bond, Rate yield, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Real basisPointValue(const Bond& bond, const InterestRate& yield, Date settlementDate = Date()); static Real basisPointValue(const Bond& bond, Rate yield, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Real yieldValueBasisPoint(const Bond& bond, const InterestRate& yield, Date settlementDate = Date()); static Real yieldValueBasisPoint(const Bond& bond, Rate yield, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Real cleanPrice(const Bond& bond, const ext::shared_ptr& discount, Spread zSpread, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Real dirtyPrice(const Bond& bond, const ext::shared_ptr& discount, Spread zSpread, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); static Spread zSpread(const Bond& bond, BondPrice price, const ext::shared_ptr& discountCurve, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date(), Real accuracy = 1.0e-10, Size maxIterations = 100, Rate guess = 0.0); %extend { %define DefineYieldFunctionSolver(SolverType) static Rate yield ## SolverType(SolverType solver, const Bond& bond, BondPrice price, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date(), Real accuracy = 1.0e-10, Rate guess = 0.05) { return QuantLib::BondFunctions::yield( solver, bond, price, dayCounter, compounding, frequency, settlementDate, accuracy, guess); } %enddef // See optimizers.i for solver definitions. DefineYieldFunctionSolver(Brent); DefineYieldFunctionSolver(Bisection); DefineYieldFunctionSolver(FalsePosition); DefineYieldFunctionSolver(Ridder); DefineYieldFunctionSolver(Secant); #if defined(SWIGPYTHON) DefineYieldFunctionSolver(Newton); DefineYieldFunctionSolver(NewtonSafe); #endif } }; #endif QuantLib-SWIG-1.39/SWIG/bonds.i000066400000000000000000000435101503741206100157660ustar00rootroot00000000000000/* Copyright (C) 2004, 2005, 2006, 2007 StatPro Italia srl Copyright (C) 2009 Joseph Malicki Copyright (C) 2011 Lluis Pujol Bajador Copyright (C) 2014 Simon Mazzucca Copyright (C) 2016 Gouthaman Balaraman Copyright (C) 2017 BN Algorithms Ltd Copyright (C) 2018 Matthias Groncki Copyright (C) 2018 Matthias Lungwitz This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_bonds_i #define quantlib_bonds_i %include instruments.i %include calendars.i %include daycounters.i %include cashflows.i %include interestrate.i %include indexes.i %include inflation.i %include shortratemodels.i %{ using QuantLib::Bond; typedef Bond::Price BondPrice; using QuantLib::ZeroCouponBond; using QuantLib::FixedRateBond; using QuantLib::AmortizingFixedRateBond; using QuantLib::FloatingRateBond; using QuantLib::AmortizingFloatingRateBond; using QuantLib::DiscountingBondEngine; using QuantLib::simplifyNotificationGraph; %} class BondPrice { public: enum Type { Dirty, Clean }; BondPrice(Real amount, Type type); Real amount() const; Type type() const; bool isValid() const; }; %shared_ptr(Bond) class Bond : public Instrument { #if defined(SWIGPYTHON) %rename(bondYield) yield; #endif public: Bond(Natural settlementDays, const Calendar& calendar, Real faceAmount, const Date& maturityDate, const Date& issueDate = Date(), const Leg& cashflows = Leg()); Bond(Natural settlementDays, const Calendar& calendar, const Date& issueDate = Date(), const Leg& coupons = Leg()); // public functions Rate nextCouponRate(const Date& d = Date()); Rate previousCouponRate(const Date& d = Date()); // inspectors Natural settlementDays() const; Date settlementDate(Date d = Date()); Date startDate() const; Date maturityDate() const; Date issueDate() const; std::vector > cashflows() const; std::vector > redemptions() const; ext::shared_ptr redemption() const; Calendar calendar() const; std::vector notionals() const; Real notional(Date d = Date()) const; // calculations Real cleanPrice(); Real cleanPrice(Rate yield, const DayCounter &dc, Compounding compounding, Frequency frequency, const Date& settlement = Date()); Real dirtyPrice(); Real dirtyPrice(Rate yield, const DayCounter &dc, Compounding compounding, Frequency frequency, const Date& settlement = Date()); Real yield(const DayCounter& dc, Compounding compounding, Frequency freq, Real accuracy = 1.0e-8, Size maxEvaluations = 100); Real yield(BondPrice price, const DayCounter& dc, Compounding compounding, Frequency freq, const Date& settlement = Date(), Real accuracy = 1.0e-8, Size maxEvaluations = 100, Real guess = 0.05); Real accruedAmount(const Date& settlement = Date()); Real settlementValue() const; Real settlementValue(Real cleanPrice) const; }; void simplifyNotificationGraph(Bond& bond, bool unregisterCoupons = false); %inline %{ Real cleanPriceFromZSpread( const Bond& bond, const ext::shared_ptr& discountCurve, Spread zSpread, const DayCounter& dc, Compounding compounding, Frequency freq, const Date& settlementDate = Date()) { return QuantLib::BondFunctions::cleanPrice( bond, discountCurve, zSpread, dc, compounding, freq, settlementDate); } %} namespace QuantLib { Schedule sinkingSchedule(const Date& startDate, const Period& bondLength, const Frequency& frequency, const Calendar& paymentCalendar); std::vector sinkingNotionals(const Period& bondLength, const Frequency& frequency, Rate couponRate, Real initialNotional); } %shared_ptr(ZeroCouponBond) class ZeroCouponBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") ZeroCouponBond; #endif public: ZeroCouponBond( Natural settlementDays, const Calendar &calendar, Real faceAmount, const Date & maturityDate, BusinessDayConvention paymentConvention = QuantLib::Following, Real redemption = 100.0, const Date& issueDate = Date()); }; %shared_ptr(FixedRateBond) class FixedRateBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") FixedRateBond; #endif public: FixedRateBond( Integer settlementDays, Real faceAmount, const Schedule &schedule, const std::vector& coupons, const DayCounter& paymentDayCounter, BusinessDayConvention paymentConvention = QuantLib::Following, Real redemption = 100.0, Date issueDate = Date(), const Calendar& paymentCalendar = Calendar(), const Period& exCouponPeriod = Period(), const Calendar& exCouponCalendar = Calendar(), BusinessDayConvention exCouponConvention = Unadjusted, bool exCouponEndOfMonth = false); Frequency frequency() const; DayCounter dayCounter() const; }; %shared_ptr(AmortizingFixedRateBond) class AmortizingFixedRateBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") AmortizingFixedRateBond; #endif public: AmortizingFixedRateBond( Integer settlementDays, const std::vector& notionals, const Schedule& schedule, const std::vector& coupons, const DayCounter& accrualDayCounter, BusinessDayConvention paymentConvention = QuantLib::Following, Date issueDate = Date(), const Period& exCouponPeriod = Period(), const Calendar& exCouponCalendar = Calendar(), const BusinessDayConvention exCouponConvention = Unadjusted, bool exCouponEndOfMonth = false, const std::vector& redemptions = { 100.0 }, Integer paymentLag = 0); Frequency frequency() const; DayCounter dayCounter() const; }; %shared_ptr(AmortizingFloatingRateBond) class AmortizingFloatingRateBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") AmortizingFloatingRateBond; #endif public: AmortizingFloatingRateBond( Size settlementDays, const std::vector& notional, const Schedule& schedule, const ext::shared_ptr& index, const DayCounter& accrualDayCounter, BusinessDayConvention paymentConvention = Following, Size fixingDays = Null(), const std::vector& gearings = std::vector(1, 1.0), const std::vector& spreads = std::vector(1, 0.0), const std::vector& caps = std::vector(), const std::vector& floors = std::vector(), bool inArrears = false, const Date& issueDate = Date(), const Period& exCouponPeriod = Period(), const Calendar& exCouponCalendar = Calendar(), const BusinessDayConvention exCouponConvention = Unadjusted, bool exCouponEndOfMonth = false, const std::vector& redemptions = { 100.0 }, Integer paymentLag = 0); }; %shared_ptr(FloatingRateBond) class FloatingRateBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") FloatingRateBond; #endif public: FloatingRateBond( Size settlementDays, Real faceAmount, const Schedule& schedule, const ext::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentConvention = Following, Size fixingDays = Null(), const std::vector& gearings = std::vector(), const std::vector& spreads = std::vector(), const std::vector& caps = std::vector(), const std::vector& floors = std::vector(), bool inArrears = false, Real redemption = 100.0, const Date& issueDate = Date(), const Period& exCouponPeriod = Period(), const Calendar& exCouponCalendar = Calendar(), BusinessDayConvention exCouponConvention = Unadjusted, bool exCouponEndOfMonth = false); }; %{ using QuantLib::CmsRateBond; using QuantLib::AmortizingCmsRateBond; %} %shared_ptr(CmsRateBond) class CmsRateBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") CmsRateBond; #endif public: CmsRateBond(Size settlementDays, Real faceAmount, const Schedule& schedule, const ext::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentConvention, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors, bool inArrears = false, Real redemption = 100.0, const Date& issueDate = Date()); }; %shared_ptr(AmortizingCmsRateBond) class AmortizingCmsRateBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") AmortizingCmsRateBond; #endif public: AmortizingCmsRateBond( Natural settlementDays, const std::vector& notionals, const Schedule& schedule, const ext::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentConvention = Following, Natural fixingDays = Null(), const std::vector& gearings = { 1.0 }, const std::vector& spreads = { 0.0 }, const std::vector& caps = {}, const std::vector& floors = {}, bool inArrears = false, const Date& issueDate = Date()); }; %shared_ptr(DiscountingBondEngine) class DiscountingBondEngine : public PricingEngine { public: DiscountingBondEngine(const Handle& discountCurve); }; %{ using QuantLib::CallableBond; using QuantLib::Callability; using QuantLib::SoftCallability; using QuantLib::CallabilitySchedule; using QuantLib::CallableFixedRateBond; using QuantLib::CallableZeroCouponBond; using QuantLib::TreeCallableFixedRateBondEngine; using QuantLib::BlackCallableFixedRateBondEngine; %} %shared_ptr(Callability) class Callability { public: enum Type { Call, Put }; Callability(const BondPrice& price, Type type, const Date& date); const BondPrice& price() const; Type type() const; Date date() const; }; %shared_ptr(SoftCallability) class SoftCallability : public Callability { public: SoftCallability(const BondPrice& price, const Date& date, Real trigger); }; #if defined(SWIGCSHARP) SWIG_STD_VECTOR_ENHANCED( ext::shared_ptr ) #endif namespace std { %template(CallabilitySchedule) vector >; } %shared_ptr(CallableBond) class CallableBond : public Bond { private: CallableBond(); public: const std::vector >& callability() const; Volatility impliedVolatility(const BondPrice& targetPrice, const Handle& discountCurve, Real accuracy, Size maxEvaluations, Volatility minVol, Volatility maxVol) const; Real OAS(Real cleanPrice, const Handle& engineTS, const DayCounter& dc, Compounding compounding, Frequency freq, const Date& settlementDate = Date(), Real accuracy =1e-10, Size maxIterations = 100, Spread guess = 0.0); Real cleanPriceOAS(Real oas, const Handle& engineTS, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Date settlementDate = Date()); Real effectiveDuration(Real oas, const Handle& engineTS, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Real bump=2e-4); Real effectiveConvexity(Real oas, const Handle& engineTS, const DayCounter& dayCounter, Compounding compounding, Frequency frequency, Real bump=2e-4); }; %shared_ptr(CallableFixedRateBond) class CallableFixedRateBond : public CallableBond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") CallableFixedRateBond; #endif public: CallableFixedRateBond( Integer settlementDays, Real faceAmount, const Schedule &schedule, const std::vector& coupons, const DayCounter& accrualDayCounter, BusinessDayConvention paymentConvention, Real redemption, Date issueDate, const std::vector >& putCallSchedule, const Period& exCouponPeriod = Period(), const Calendar& exCouponCalendar = Calendar(), BusinessDayConvention exCouponConvention = Unadjusted, bool exCouponEndOfMonth = false); }; %shared_ptr(CallableZeroCouponBond) class CallableZeroCouponBond : public CallableBond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") CallableZeroCouponBond; #endif public: CallableZeroCouponBond( Integer settlementDays, Real faceAmount, const Calendar& calendar, const Date& maturityDate, const DayCounter& dayCounter, BusinessDayConvention paymentConvention = Following, Real redemption = 100.0, const Date& issueDate = Date(), const std::vector >& putCallSchedule = std::vector >()); }; %shared_ptr(TreeCallableFixedRateBondEngine) class TreeCallableFixedRateBondEngine : public PricingEngine { public: TreeCallableFixedRateBondEngine( const ext::shared_ptr& model, Size timeSteps, const Handle& termStructure = Handle()); TreeCallableFixedRateBondEngine( const ext::shared_ptr& model, const TimeGrid& grid, const Handle& termStructure = Handle()); }; %shared_ptr(BlackCallableFixedRateBondEngine) class BlackCallableFixedRateBondEngine : public PricingEngine { public: BlackCallableFixedRateBondEngine( const Handle& fwdYieldVol, const Handle& discountCurve); }; %{ using QuantLib::CPIBond; %} %shared_ptr(CPIBond) class CPIBond : public Bond { #if !defined(SWIGJAVA) && !defined(SWIGCSHARP) %feature("kwargs") CPIBond; #endif public: CPIBond( Natural settlementDays, Real faceAmount, bool growthOnly, Real baseCPI, const Period& observationLag, const ext::shared_ptr& cpiIndex, CPI::InterpolationType observationInterpolation, const Schedule& schedule, const std::vector& coupons, const DayCounter& accrualDayCounter, BusinessDayConvention paymentConvention = ModifiedFollowing, const Date& issueDate = Date(), const Calendar& paymentCalendar = Calendar(), const Period& exCouponPeriod = Period(), const Calendar& exCouponCalendar = Calendar(), BusinessDayConvention exCouponConvention = Unadjusted, bool exCouponEndOfMonth = false); }; #endif QuantLib-SWIG-1.39/SWIG/calendars.i000066400000000000000000000226521503741206100166210ustar00rootroot00000000000000 /* Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl Copyright (C) 2005 Johan Witters Copyright (C) 2018 Matthias Groncki Copyright (C) 2023 Skandinaviska Enskilda Banken AB (publ) This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_calendar_i #define quantlib_calendar_i %include common.i %include date.i %include stl.i %define QL_TYPECHECK_BUSINESSDAYCONVENTION 6210 %enddef %{ using QuantLib::Calendar; %} %{ using QuantLib::BusinessDayConvention; using QuantLib::Following; using QuantLib::ModifiedFollowing; using QuantLib::Preceding; using QuantLib::ModifiedPreceding; using QuantLib::Unadjusted; using QuantLib::HalfMonthModifiedFollowing; using QuantLib::Nearest; %} enum BusinessDayConvention { Following, ModifiedFollowing, Preceding, ModifiedPreceding, Unadjusted, HalfMonthModifiedFollowing, Nearest }; %{ using QuantLib::JointCalendarRule; using QuantLib::JoinHolidays; using QuantLib::JoinBusinessDays; %} enum JointCalendarRule { JoinHolidays, JoinBusinessDays }; #if defined(SWIGPYTHON) %typemap(in) ext::optional %{ if ($input == Py_None) $1 = ext::nullopt; else if (PyLong_Check($input)) $1 = (BusinessDayConvention)PyLong_AsLong($input); else SWIG_exception(SWIG_TypeError, "int expected"); %} %typecheck (QL_TYPECHECK_BUSINESSDAYCONVENTION) ext::optional %{ $1 = (PyLong_Check($input) || $input == Py_None) ? 1 : 0; %} #endif class Calendar { protected: Calendar(); public: bool isWeekend(Weekday w); Date startOfMonth(const Date&); Date endOfMonth(const Date&); bool isBusinessDay(const Date&); bool isHoliday(const Date&); bool isEndOfMonth(const Date&); bool isStartOfMonth(const Date&); void addHoliday(const Date&); void removeHoliday(const Date&); void resetAddedAndRemovedHolidays(); Date adjust(const Date& d, BusinessDayConvention convention = QuantLib::Following); Date advance(const Date& d, Integer n, TimeUnit unit, BusinessDayConvention convention = QuantLib::Following, bool endOfMonth = false); Date advance(const Date& d, const Period& period, BusinessDayConvention convention = QuantLib::Following, bool endOfMonth = false); BigInteger businessDaysBetween(const Date& from, const Date& to, bool includeFirst = true, bool includeLast = false); std::vector holidayList(const Date& from, const Date& to, bool includeWeekEnds = false); std::vector businessDayList(const Date& from, const Date& to); std::string name(); bool empty(); %extend { std::string __str__() { return self->name()+" calendar"; } #if defined(SWIGPYTHON) || defined(SWIGJAVA) bool operator==(const Calendar& other) { return (*self) == other; } bool operator!=(const Calendar& other) { return (*self) != other; } hash_t __hash__() { return self->empty() ? 0 : std::hash()(self->name()); } #endif } }; namespace std { %template(CalendarVector) vector; } namespace QuantLib { class Argentina : public Calendar { public: enum Market { Merval }; Argentina(Market m = Merval); }; class Australia : public Calendar { public: enum Market { Settlement, ASX }; Australia(Market market = Settlement); }; class Austria : public Calendar { public: enum Market { Settlement, Exchange }; Austria(Market m = Settlement); }; class Botswana : public Calendar {}; class Brazil : public Calendar { public: enum Market { Settlement, Exchange }; Brazil(Market m = Settlement); }; class Canada : public Calendar { public: enum Market { Settlement, TSX }; Canada(Market m = Settlement); }; class Chile : public Calendar { public: enum Market { SSE }; Chile(Market m = SSE); }; class China : public Calendar { public: enum Market { SSE, IB }; China(Market m = SSE); }; class CzechRepublic : public Calendar { public: enum Market { PSE }; CzechRepublic(Market m = PSE); }; class Denmark : public Calendar {}; class Finland : public Calendar {}; class France : public Calendar { public: enum Market { Settlement, Exchange }; France(Market m = Settlement); }; class Germany : public Calendar { public: enum Market { Settlement, FrankfurtStockExchange, Xetra, Eurex }; Germany(Market m = FrankfurtStockExchange); }; class HongKong : public Calendar { public: enum Market { HKEx }; HongKong(Market m = HKEx); }; class Hungary : public Calendar {}; class Iceland : public Calendar { public: enum Market { ICEX }; Iceland(Market m = ICEX); }; class India : public Calendar { public: enum Market { NSE }; India(Market m = NSE); }; class Indonesia : public Calendar { public: enum Market { BEJ, JSX }; Indonesia(Market m = BEJ); }; class Israel : public Calendar { public: enum Market { Settlement, TASE, SHIR }; Israel(Market m = Settlement); }; class Italy : public Calendar { public: enum Market { Settlement, Exchange }; Italy(Market m = Settlement); }; class Japan : public Calendar {}; class Mexico : public Calendar { public: enum Market { BMV }; Mexico(Market m = BMV); }; class NewZealand : public Calendar { public: enum Market { Wellington, Auckland }; NewZealand(Market m = Wellington); }; class Norway : public Calendar {}; class Poland : public Calendar { public: enum Market { Settlement, WSE }; Poland(Market m = Settlement); }; class Romania : public Calendar { public: enum Market { Public, BVB }; Romania(Market m = BVB); }; class Russia : public Calendar { public: enum Market { Settlement, MOEX }; Russia(Market m = Settlement); }; class SaudiArabia : public Calendar { public: enum Market { Tadawul }; SaudiArabia(Market m = Tadawul); }; class Singapore : public Calendar { public: enum Market { SGX }; Singapore(Market m = SGX); }; class Slovakia : public Calendar { public: enum Market { BSSE }; Slovakia(Market m = BSSE); }; class SouthAfrica : public Calendar {}; class SouthKorea : public Calendar { public: enum Market { Settlement, KRX }; SouthKorea(Market m = KRX); }; class Sweden : public Calendar {}; class Switzerland : public Calendar {}; class Taiwan : public Calendar { public: enum Market { TSEC }; Taiwan(Market m = TSEC); }; class TARGET : public Calendar {}; class Thailand : public Calendar {}; class Turkey : public Calendar {}; class Ukraine : public Calendar { public: enum Market { USE }; Ukraine(Market m = USE); }; class UnitedKingdom : public Calendar { public: enum Market { Settlement, Exchange, Metals }; UnitedKingdom(Market m = Settlement); }; class UnitedStates : public Calendar { public: enum Market { Settlement, NYSE, GovernmentBond, NERC, LiborImpact, FederalReserve, SOFR }; UnitedStates(Market m); }; // others class NullCalendar : public Calendar {}; class WeekendsOnly : public Calendar {}; class JointCalendar : public Calendar { public: JointCalendar(const Calendar&, const Calendar&, JointCalendarRule rule = QuantLib::JoinHolidays); JointCalendar(const Calendar&, const Calendar&, const Calendar&, JointCalendarRule rule = QuantLib::JoinHolidays); JointCalendar(const Calendar&, const Calendar&, const Calendar&, const Calendar&, JointCalendarRule rule = QuantLib::JoinHolidays); explicit JointCalendar(const std::vector&, JointCalendarRule = QuantLib::JoinHolidays); }; class BespokeCalendar : public Calendar { public: BespokeCalendar(const std::string& name); void addWeekend(Weekday); }; } #endif QuantLib-SWIG-1.39/SWIG/calibratedmodel.i000066400000000000000000000056371503741206100200040ustar00rootroot00000000000000/* Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2007, 2009 StatPro Italia srl Copyright (C) 2005 Dominic Thuillier Copyright (C) 2007 Luis Cota Copyright (C) 2016 Gouthaman Balaraman Copyright (C) 2016 Peter Caspers Copyright (C) 2018 Matthias Lungwitz This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_calibrated_model_i #define quantlib_calibrated_model_i %include termstructures.i %include optimizers.i %include linearalgebra.i %include types.i %include vectors.i %{ using QuantLib::CalibrationHelper; %} // calibration helpers %shared_ptr(CalibrationHelper) class CalibrationHelper { public: Real calibrationError(); private: CalibrationHelper(); }; // allow use of vectors of helpers #if defined(SWIGCSHARP) SWIG_STD_VECTOR_ENHANCED( ext::shared_ptr ) #endif namespace std { %template(CalibrationHelperVector) vector >; } // the base class for calibrated models %{ using QuantLib::CalibratedModel; using QuantLib::TermStructureConsistentModel; %} %shared_ptr(CalibratedModel) class CalibratedModel : public virtual Observable { #if defined(SWIGCSHARP) %rename("parameters") params; #endif public: Array params() const; virtual void calibrate( const std::vector >&, OptimizationMethod&, const EndCriteria &, const Constraint& constraint = Constraint(), const std::vector& weights = std::vector(), const std::vector& fixParameters = std::vector()); void setParams(const Array& params); Real value(const Array& params, const std::vector >&); const ext::shared_ptr& constraint() const; EndCriteria::Type endCriteria() const; const Array& problemValues() const; Integer functionEvaluation() const; private: CalibratedModel(); }; %shared_ptr(TermStructureConsistentModel) class TermStructureConsistentModel : public virtual Observable{ public: const Handle& termStructure() const; private: TermStructureConsistentModel(); }; %template(CalibratedModelHandle) Handle; %template(RelinkableCalibratedModelHandle) RelinkableHandle; #endif QuantLib-SWIG-1.39/SWIG/calibrationhelpers.i000066400000000000000000000173001503741206100205310ustar00rootroot00000000000000/* Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2007, 2009 StatPro Italia srl Copyright (C) 2005 Dominic Thuillier Copyright (C) 2007 Luis Cota Copyright (C) 2016 Gouthaman Balaraman Copyright (C) 2016 Peter Caspers Copyright (C) 2018 Matthias Lungwitz This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #ifndef quantlib_calibration_helpers_i #define quantlib_calibration_helpers_i %include calibratedmodel.i %include date.i %include calendars.i %include daycounters.i %include cashflows.i %include marketelements.i %include termstructures.i %include linearalgebra.i %include types.i %include vectors.i %{ using QuantLib::VanillaSwap; using QuantLib::Swaption; using QuantLib::BlackCalibrationHelper; using QuantLib::SwaptionHelper; using QuantLib::CapHelper; using QuantLib::HestonModelHelper; %} %shared_ptr(BlackCalibrationHelper) class BlackCalibrationHelper : public CalibrationHelper { public: enum CalibrationErrorType { RelativePriceError, PriceError, ImpliedVolError }; void setPricingEngine(const ext::shared_ptr& engine); Real marketValue() const; virtual Real modelValue() const; Volatility impliedVolatility(Real targetValue, Real accuracy, Size maxEvaluations, Volatility minVol, Volatility maxVol); Real blackPrice(Volatility volatility); Handle volatility() const; VolatilityType volatilityType() const; Real calibrationError(); private: BlackCalibrationHelper(); }; %inline %{ ext::shared_ptr as_black_helper(const ext::shared_ptr& h) { return ext::dynamic_pointer_cast(h); } ext::shared_ptr as_swaption_helper(const ext::shared_ptr& h) { return ext::dynamic_pointer_cast(h); } %} %shared_ptr(SwaptionHelper) class SwaptionHelper : public BlackCalibrationHelper { public: SwaptionHelper(const Period& maturity, const Period& length, const Handle& volatility, const ext::shared_ptr& index, const Period& fixedLegTenor, const DayCounter& fixedLegDayCounter, const DayCounter& floatingLegDayCounter, const Handle& termStructure, CalibrationErrorType errorType = RelativePriceError, const Real strike = Null(), const Real nominal = 1.0, const VolatilityType type = ShiftedLognormal, const Real shift = 0.0, Natural settlementDays = Null(), RateAveraging::Type averagingMethod = RateAveraging::Compound); SwaptionHelper(const Date& exerciseDate, const Period& length, const Handle& volatility, const ext::shared_ptr& index, const Period& fixedLegTenor, const DayCounter& fixedLegDayCounter, const DayCounter& floatingLegDayCounter, const Handle& termStructure, CalibrationErrorType errorType = RelativePriceError, const Real strike = Null(), const Real nominal = 1.0, const VolatilityType type = ShiftedLognormal, const Real shift = 0.0, Natural settlementDays = Null(), RateAveraging::Type averagingMethod = RateAveraging::Compound); SwaptionHelper(const Date& exerciseDate, const Date& endDate, const Handle& volatility, const ext::shared_ptr& index, const Period& fixedLegTenor, const DayCounter& fixedLegDayCounter, const DayCounter& floatingLegDayCounter, const Handle& termStructure, CalibrationErrorType errorType = RelativePriceError, const Real strike = Null(), const Real nominal = 1.0, const VolatilityType type = ShiftedLognormal, const Real shift = 0.0, Natural settlementDays = Null(), RateAveraging::Type averagingMethod = RateAveraging::Compound); ext::shared_ptr underlying() const; ext::shared_ptr swaption() const; %extend { std::vector