├── .gitignore
├── LICENSE
├── README.md
├── apt.txt
├── environment.yml
├── images
├── favicon.png
├── pricing.drawio
├── pricing.png
├── rivacon_frontmark_combined_header.png
├── rivacon_frontmark_combined_header.svg
└── rivacon_logo.png
├── inputdata
└── inputQuotes.csv
├── instruments
├── american_plain_vanilla_option.ipynb
├── asian_on_riskcontrol.ipynb
├── asian_option.ipynb
├── barrier_options.ipynb
├── binomial_trees.ipynb
├── bond.ipynb
├── dop.ipynb
├── european_plain_vanilla_option.ipynb
├── ir_swap.ipynb
└── multi_memory_express.ipynb
├── marketdata
├── daycounter_rollconventions_schedules.ipynb
├── discount_curves.ipynb
├── equity_forwardcurve.ipynb
├── equity_volatilities.ipynb
├── interest_rate_converter.ipynb
├── ir_curve_bootstrapping.ipynb
└── ir_swap_simulation.ipynb
├── overview.ipynb
├── postBuild
└── tests.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints/
2 | __pycache__
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020 frontmark GmbH
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://mybinder.org/v2/gh/frontmark/jupyter-notebooks/master)
2 | [](https://opensource.org/licenses/MIT)
3 | [](https://www.frontmark.de/)
4 | [](https://www.rivacon.com/en/)
5 |
6 | # Jupyter Notebooks
7 |
8 | This is a collection of jupyter notebooks to illustrate the basic concepts of mathematical finance:
9 |
10 | ## Market Data
11 | ### Roll Conventions, Day Counters and Schedule Generation
12 | The most important day counters and roll conventions are explained here. This notebook shows how to roll out schedules.
13 |
14 | ### Discount Curves
15 | You can learn how to create and work with discount curves including plotting functionality in this notebook. How to bootstrap in a multi-curve framework is explained here.
16 |
17 | ### Equity Forward Curves
18 | Create and work with equity forward curves including plotting functionality here.
19 |
20 | ### Equity Volatility Surfaces
21 | Create and work with equity volatility surfaces here.
22 |
23 | ## Pricing
24 |
25 | A variety of different derivative products from various asset classes are introduced and their pricing is discussed.
26 |
27 | ## Conventions
28 |
29 | - use Title Case for H1 (#) and H2 (##) headers
30 | - use Sentence case for H3 (###), H4 (####) etc. headers (maybe except if only 2 - 3 linked words)
31 | - use snake_case for filenames
32 |
33 | # Tribute
34 |
35 | Thanks to our sponsors [frontmark](https://www.frontmark.de/) and [RIVACON](https://www.rivacon.com/).
36 |
37 | [
](https://www.frontmark.de/)
38 |
39 | [
](https://www.rivacon.com/)
40 |
--------------------------------------------------------------------------------
/apt.txt:
--------------------------------------------------------------------------------
1 | libboost-date-time1.62.0
2 | libboost-system1.62.0
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | # generate from notebook: !conda env export > environment.yml
2 | name: notebook_python_3.5
3 |
4 | channel:
5 | - conda-forge
6 |
7 | dependencies:
8 | - python=3.5
9 | - ipywidgets=7.2.1
10 | - matplotlib=3.0.0
11 | - numpy=1.15.2
12 | - pandas=0.23.4
13 | - scipy=1.1.0
14 | - seaborn=0.9.0
15 | - time=1.8
16 | - pip:
17 | - pyvacon==0.1.0
18 | - jupyter-contrib-nbextensions==0.5.1
--------------------------------------------------------------------------------
/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frontmark/jupyter-notebooks/556a01bc4d3f2dc9b44af9c167aaabf35d23f5ba/images/favicon.png
--------------------------------------------------------------------------------
/images/pricing.drawio:
--------------------------------------------------------------------------------
1 | 7Vtbc+o2EP41PJ6OLWGDHxMSepmTyZky0zaPAiugHmMRWQTIr69ky1cZYye2IaSTB6y1bt799O2upAzgZL3/laHN6oG62BsAw90P4N0AABM6jviRkkMksWwYCZaMuKpSKpiRN6yEhpJuiYuDXEVOqcfJJi9cUN/HC56TIcboLl/tmXr5UTdoiTXBbIE8Xfo3cflKSS3DSF/8hslypYYeW+rFGsWVlSBYIZfuMiJ4P4ATRimPntb7Cfak8mK9RO2mR94mE2PY53UaPP6+Ad//eLt9mD3OH1+sB2vl7L6ZQE2OH+Ivxq5QgCpSxld0SX3k3afSW0a3votlt4YopXW+U7oRQlMI/8WcH5Q10ZZTIVrxtafe4j3h/8jmv1iq9JR5c7dXPYeFgyo8U59P0Zp4UvAXZi7ykRKrcUxblAPO6M/EVDCRTKhHWfiBcDp1HCjfRJ8uv/eoSpUooFu2wFV6VNBEbIl5RT07MbxYMZiuMWcH0Y5hD3Hymp8HUtBdJvVS64oHZeAmxo76fUXeVo00ALbHlRZzKLBftjR+8S0I9XsjKpijzT5UXPxePC3l7wNiPzG/Qxw9CLssMYt7FhONOo/qaWhLsSTNv1sRjmcbFOp6Jxglj5saGBjVw8Bo7EzvUwy8YsbxvhoFutVUg6Fa4Id8cZfSRcJmqwxT2EZXZoZXtqaFHdgh07csPsX9yULae1iKuz8TF4CeuEA1/UFJuHhjNAIrB0eziLNoXqpVCrUbxtAhU20jKwQNxhkW3E+hvjmsrC8eohmkuE908v6lALpjvB+IITE9zL4e4UFwaYxnVzIe9uZ091nI7jhFYd+9kRGtEPvUx5FkSqSqogHEY6bdsyX/StHRItkNOyKxPMJismibxEbGGUhp2B0pTZBH5kxonvozTpnMbVTXc/ahjr8Qu9nGhbGbpeHlFgVCrXhBnskiNPY12sExL8wO8QR6jqvfGfxmvMXCQ0FAFjmHYVa6Gt3UNTAC2vUsds0wetyGB2rqOIrRLDSro19oVdbvxtHYGnFIn8nIgvhLmapfI2vYedIAhs4a5qhP1gDVO2wtxaZhN6IodSd8gvfxcPXz8I7dLu+MeuKdj/mi8+zbnshAOnAogbAD1wEVijOQatv+rWc0o2JGM6qX0bTlC0aaL1gjfyuI4gp9gGXUcAKwVydQvSWrFlNr2xLx81OO84/xfHO+tu3JxCjfYe2fr8c1+do0ykHTD2FDq1cENPP0zRGQLNdLyBTqIgCeFQFjjYFvqe9ecji+pq9oHk5GDsBwQN6yZcrFpNOyiz2cLWOXZIvqgD4jaYHpgZVnemife5PAHPcR7pet+I45Pwnl3n0Q3+KKd2qu+I6O2Ibvi+UaH7EV4xhYvcnQuD4oj5M63ZSA/YZCeUdonFgW5Slvsg3XYsp7UQ607nKyzuk/Hc1/xocSLnn90OGG9MOF7fTktCPs+3oPO4qb7ObZd9nB8IJTpZgfsuyQIYsW+eGiUqwYAKdzrCNo6+l+m6FRxEaE1/gaF65dPIAoiXxN0Gvkq18vVMnNnzjYelGgc21mcODpBKTf8wYISvxkQfFLofnN0a/PZ2qD5AJzfa2YTh6cwxKtwDJwapfV2lOLzg3yFL3P9Lvm9eRm8KzAgG6eM6q/7O5xKSrzOqvUQx2gNtJPvKtQTIv0kGhcpj3QWUykXwFJqPVliwP+MeyW5Pp3jq3DFTRNTt6F3SPUcsqvFW+Itad8/Rg9jCrYF1B63E3d4KI7I+jnV02zP3Ak+5uR9darTPvaGSfyMY1u4x3rqov89FPgUTHy+Oxw1Dfz24LJBHmLvvDY9Hbo/3g8wY/d41MU038ZjPZk03+8hPf/AQ==
--------------------------------------------------------------------------------
/images/pricing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frontmark/jupyter-notebooks/556a01bc4d3f2dc9b44af9c167aaabf35d23f5ba/images/pricing.png
--------------------------------------------------------------------------------
/images/rivacon_frontmark_combined_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frontmark/jupyter-notebooks/556a01bc4d3f2dc9b44af9c167aaabf35d23f5ba/images/rivacon_frontmark_combined_header.png
--------------------------------------------------------------------------------
/images/rivacon_frontmark_combined_header.svg:
--------------------------------------------------------------------------------
1 |
2 |
163 |
--------------------------------------------------------------------------------
/images/rivacon_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frontmark/jupyter-notebooks/556a01bc4d3f2dc9b44af9c167aaabf35d23f5ba/images/rivacon_logo.png
--------------------------------------------------------------------------------
/inputdata/inputQuotes.csv:
--------------------------------------------------------------------------------
1 | Maturity;Instrument;Currency;Quote;UnderlyingIndex;UnderlyingTenor;UnderlyingPaymentFrequency;BasisIndex;BasisTenor;BasisPaymentFrequency;PaymentFrequencyFixed;DayCountFixed;DayCountFloat;DayCountBasis;RollConventionFixed;RollConventionFloat;RollConventionBasis;SpotLag
2 | 1D;DEPOSIT;EUR;-0,00345;EONIA;1D;1D;;;;1D;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;0D
3 | 7D;OIS;EUR;-0,00359;EONIA;7D;7D;;;;7D;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
4 | 14D;OIS;EUR;-0,00359;EONIA;14D;14D;;;;14D;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
5 | 21D;OIS;EUR;-0,003585;EONIA;21D;21D;;;;21D;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
6 | 1M;OIS;EUR;-0,00358;EONIA;1M;1M;;;;1M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
7 | 2M;OIS;EUR;-0,00358;EONIA;2M;2M;;;;2M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
8 | 3M;OIS;EUR;-0,00358;EONIA;3M;3M;;;;3M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
9 | 4M;OIS;EUR;-0,00358;EONIA;4M;4M;;;;4M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
10 | 5M;OIS;EUR;-0,00358;EONIA;5M;5M;;;;5M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
11 | 6M;OIS;EUR;-0,00358;EONIA;6M;6M;;;;6M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
12 | 7M;OIS;EUR;-0,00358;EONIA;7M;7M;;;;7M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
13 | 8M;OIS;EUR;-0,003575;EONIA;8M;8M;;;;8M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
14 | 9M;OIS;EUR;-0,00357;EONIA;9M;9M;;;;9M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
15 | 1Y;OIS;EUR;-0,00354;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
16 | 15M;OIS;EUR;-0,00348;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
17 | 18M;OIS;EUR;-0,003395;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
18 | 21M;OIS;EUR;-0,003285;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
19 | 2Y;OIS;EUR;-0,00315;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
20 | 3Y;OIS;EUR;-0,002425;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
21 | 4Y;OIS;EUR;-0,00149;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
22 | 5Y;OIS;EUR;-0,0004;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
23 | 6Y;OIS;EUR;0,00082;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
24 | 7Y;OIS;EUR;0,00209;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
25 | 8Y;OIS;EUR;0,00338;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
26 | 9Y;OIS;EUR;0,00462;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
27 | 10Y;OIS;EUR;0,00579;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
28 | 11Y;OIS;EUR;0,00684;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
29 | 12Y;OIS;EUR;0,00779;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
30 | 15Y;OIS;EUR;0,00999;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
31 | 20Y;OIS;EUR;0,0119775;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
32 | 25Y;OIS;EUR;0,01283;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
33 | 30Y;OIS;EUR;0,01325;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
34 | 40Y;OIS;EUR;0,01343;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
35 | 50Y;OIS;EUR;0,01313;EONIA;1Y;1Y;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
36 | 3M;DEPOSIT;EUR;-0,00329;EURIBOR;3M;3M;;;;3M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
37 | 6M;DEPOSIT;EUR;-0,00327672;EURIBOR;3M;3M;;;;6M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
38 | 9M;DEPOSIT;EUR;-0,00323786;EURIBOR;3M;3M;;;;9M;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
39 | 1Y;IRS;EUR;-0,00320387;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
40 | 15M;IRS;EUR;-0,00309763;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
41 | 18M;IRS;EUR;-0,00295003;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
42 | 21M;IRS;EUR;-0,00278604;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
43 | 2Y;IRS;EUR;-0,0026145;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
44 | 3Y;IRS;EUR;-0,00173;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
45 | 4Y;IRS;EUR;-0,0006475;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
46 | 5Y;IRS;EUR;0,00057;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
47 | 6Y;IRS;EUR;0,00185;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
48 | 7Y;IRS;EUR;0,003165;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
49 | 8Y;IRS;EUR;0,00447;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
50 | 9Y;IRS;EUR;0,0057275;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
51 | 10Y;IRS;EUR;0,006905;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
52 | 12Y;IRS;EUR;0,0089225;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
53 | 15Y;IRS;EUR;0,0111025;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
54 | 20Y;IRS;EUR;0,01305;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
55 | 25Y;IRS;EUR;0,0138425;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
56 | 30Y;IRS;EUR;0,0142175;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
57 | 40Y;IRS;EUR;0,014415;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
58 | 50Y;IRS;EUR;0,01408;EURIBOR;3M;3M;;;;1Y;Act360;Act360;;ModifiedFollowing;ModifiedFollowing;;2D
59 | 6M;TBS;EUR;0,000546719;EURIBOR;6M;6M;EURIBOR;3M;3M;6M;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
60 | 1Y;TBS;EUR;0,000601083;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
61 | 15M;TBS;EUR;0,000633961;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
62 | 18M;TBS;EUR;0,00065857;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
63 | 2Y;TBS;EUR;0,0007395;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
64 | 3Y;TBS;EUR;0,0008635;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
65 | 4Y;TBS;EUR;0,000955;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
66 | 5Y;TBS;EUR;0,001045;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
67 | 6Y;TBS;EUR;0,00109;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
68 | 7Y;TBS;EUR;0,0011025;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
69 | 8Y;TBS;EUR;0,0010975;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
70 | 9Y;TBS;EUR;0,0010725;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
71 | 10Y;TBS;EUR;0,0010375;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
72 | 15Y;TBS;EUR;0,000845;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
73 | 20Y;TBS;EUR;0,00069;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
74 | 30Y;TBS;EUR;0,000515;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
75 | 40Y;TBS;EUR;0,00041;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
76 | 50Y;TBS;EUR;0,00034;EURIBOR;6M;6M;EURIBOR;3M;3M;1Y;Act360;Act360;Act360;ModifiedFollowing;ModifiedFollowing;ModifiedFollowing;2D
77 |
--------------------------------------------------------------------------------
/instruments/american_plain_vanilla_option.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | ""
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# American Plain Vanilla Option"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {
21 | "ExecuteTime": {
22 | "end_time": "2020-05-03T10:49:10.279829Z",
23 | "start_time": "2020-05-03T10:49:01.401592Z"
24 | }
25 | },
26 | "outputs": [],
27 | "source": [
28 | "import pyvacon.analytics as analytics\n",
29 | "import math\n",
30 | "import numpy as np\n",
31 | "import pandas as pd\n",
32 | "import pyvacon.marketdata.plot as mkt_plot #import module for plotting functionality\n",
33 | "#the next lin is a jupyter internal command to show the matplotlib graphs within the notebook\n",
34 | "%matplotlib inline"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": null,
40 | "metadata": {
41 | "ExecuteTime": {
42 | "end_time": "2020-05-03T10:49:10.296188Z",
43 | "start_time": "2020-05-03T10:49:10.282822Z"
44 | }
45 | },
46 | "outputs": [],
47 | "source": [
48 | "def exp(x):\n",
49 | " return math.exp(x)\n",
50 | "def sqrt(x):\n",
51 | " return math.sqrt(x)"
52 | ]
53 | },
54 | {
55 | "cell_type": "markdown",
56 | "metadata": {},
57 | "source": [
58 | "## Definition of an American Plain Vanilla Option\n",
59 | "\n",
60 | "In contrast to an European plain vanilla option, American plain vanilla options can be exercised at any time before expiry which gives the holder of the option more rights than in the case of an European option. As a consequence, American options can never be less valuable than European options. In order to price an American options and incorporate the possibility of an early exercise, we need to be familiar with the concept of binomial trees which was described in the [binomial tree](binomial_trees.ipynb) notebook.\n",
61 | "\n",
62 | "When pricing American options, the parameters $u$ and $d$ should match the volatility of the stock price (Hull, *Options, futures, and other derivatives, 8th Edition,* 2012, p. 265 ff.). The parameters for matching volatility $u$ and $d$ are defined as follows:\n",
63 | "\n",
64 | "$$u = e^{\\sigma\\sqrt{\\Delta{t}}}$$\n",
65 | "$$d = e^{-\\sigma\\sqrt{\\Delta{t}}}$$\n",
66 | "\n",
67 | "with $\\sigma$ as the standard deviation of the underlying's stock and $\\Delta{t}$ as a small time step. \n",
68 | "The probability of an upward movement $p$ is defined as \n",
69 | "\n",
70 | "$$p=\\frac{a-d}{u-d}$$\n",
71 | "\n",
72 | "with\n",
73 | "\n",
74 | "$$a=e^{r\\Delta{t}}.$$\n"
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {},
80 | "source": [
81 | "## Pricing an American Plain Vanilla Option\n",
82 | "\n",
83 | "The code for the pricing an American plain vanilla option on a non-dividend paying stock using a binomial tree is shown in the following code cell. "
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": null,
89 | "metadata": {
90 | "ExecuteTime": {
91 | "end_time": "2020-05-03T10:49:10.333506Z",
92 | "start_time": "2020-05-03T10:49:10.302624Z"
93 | }
94 | },
95 | "outputs": [],
96 | "source": [
97 | "def AmericanPlainVanillaOption(_type, F0, K, r_f, r_b, r_dsc, sigma, N, T, array=False):\n",
98 | " dt = T/N\n",
99 | " a = exp((r_f-r_b)*dt)\n",
100 | " u = exp(sigma*sqrt(dt))\n",
101 | " d = 1/u\n",
102 | " p = (a-d)/(u-d) # Probability for an upward movement of the stock price\n",
103 | " \n",
104 | " #Price tree\n",
105 | " price_tree = np.zeros([N+1, N+1]) # Creating an array for the binomial tree\n",
106 | " \n",
107 | " for i in range(N+1):\n",
108 | " for j in range(i+1):\n",
109 | " price_tree[j, i] = F0*(d**j)*(u**(i-j)) ## Calculating the paths for the stock price\n",
110 | " \n",
111 | " # Option value (payoff tree)\n",
112 | " option = np.zeros([N+1, N+1])\n",
113 | " if _type =='CALL':\n",
114 | " # Calculating the payoff at maturity, i.e. calculating (S_T-K) for each final stock price (last column)\n",
115 | " option[:, N] = np.maximum(np.zeros(N+1), price_tree[:, N]-K) \n",
116 | " if _type =='PUT':\n",
117 | " option[:, N] = np.maximum(np.zeros(N+1), K-price_tree[:, N])\n",
118 | " \n",
119 | " # Calculate option price at t=0\n",
120 | " # Calculating the option prices at the different nodes going backward from the last nodes\n",
121 | " for i in np.arange(N-1, -1, -1):\n",
122 | " for j in np.arange(0, i+1):\n",
123 | " option[j, i] = exp(-r_dsc*dt)*(p*option[j, i+1]+(1-p)*option[j+1, i+1])\n",
124 | " \n",
125 | " #Return\n",
126 | " # if array: return also price tree and option price tree\n",
127 | " if array:\n",
128 | " return [option[0,0], price_tree, option]\n",
129 | " # otherwise return only option price at t=0\n",
130 | " else: \n",
131 | " return option[0,0]"
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": null,
137 | "metadata": {
138 | "ExecuteTime": {
139 | "end_time": "2020-05-03T10:49:10.361231Z",
140 | "start_time": "2020-05-03T10:49:10.338422Z"
141 | }
142 | },
143 | "outputs": [],
144 | "source": [
145 | "S0 = 50\n",
146 | "K = 50\n",
147 | "r_dsc = 0.05\n",
148 | "r_f = 0.01\n",
149 | "r_b = 0.00\n",
150 | "sigma = 0.3\n",
151 | "N = 2\n",
152 | "T = 1\n",
153 | "t=0\n",
154 | "F0 = F0 = S0*exp((r_f-r_b)*(T-t))\n",
155 | "\n",
156 | "AmericanPlainVanillaOption('CALL',F0, K, r_f, r_b, r_dsc, sigma, N, T)"
157 | ]
158 | },
159 | {
160 | "cell_type": "markdown",
161 | "metadata": {},
162 | "source": [
163 | "## Plotting the Option Price"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {
170 | "ExecuteTime": {
171 | "end_time": "2020-05-03T10:49:11.144484Z",
172 | "start_time": "2020-05-03T10:49:10.366450Z"
173 | }
174 | },
175 | "outputs": [],
176 | "source": [
177 | "spots = []\n",
178 | "#strikes = [0,10,20,30,40,50,60,70,80,90,100]\n",
179 | "#ttm = [0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0]\n",
180 | "#vols = [0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5]\n",
181 | "\n",
182 | "n=0.5\n",
183 | "while n<=100:\n",
184 | " spots.append(n)\n",
185 | " n=n+0.1\n",
186 | " \n",
187 | "call_prices = []\n",
188 | "for i in range(len(spots)):\n",
189 | " call_prices.append(AmericanPlainVanillaOption('CALL', spots[i], K, r_f, r_b, r_dsc, sigma, N, T))\n",
190 | " \n",
191 | "put_prices = []\n",
192 | "for i in range(len(spots)):\n",
193 | " put_prices.append(AmericanPlainVanillaOption('PUT', spots[i], K, r_f, r_b, r_dsc, sigma, N, T))\n",
194 | "\n",
195 | "#Plot the prices\n",
196 | "prices_list = {'Spots': spots, \n",
197 | " 'Call Prices': call_prices,\n",
198 | " 'Put Prices': put_prices}\n",
199 | "\n",
200 | "prices = pd.DataFrame(prices_list, index = spots) \n",
201 | "\n",
202 | "fig, ax = mkt_plot.plt.subplots(figsize=(20,10))\n",
203 | "ax.plot(prices['Spots'],prices['Call Prices'],label='Call Prices')\n",
204 | "ax.plot(prices['Spots'],prices['Put Prices'],label = 'Put Prices')\n",
205 | "ax.tick_params(axis=\"x\", labelsize=12)\n",
206 | "ax.tick_params(axis=\"y\", labelsize=12)\n",
207 | "ax.axvline(x=K, label='Strike', ls= '--', c='g')\n",
208 | "ax.set_title('American Plain Vanilla Option',fontsize=30,y=1.02)\n",
209 | "ax.set_xlabel('Spot',fontsize=20)\n",
210 | "ax.set_ylabel('Price',fontsize=20)\n",
211 | "legend = ax.legend(loc='best', shadow=True, fontsize='15')"
212 | ]
213 | },
214 | {
215 | "cell_type": "markdown",
216 | "metadata": {},
217 | "source": [
218 | "---"
219 | ]
220 | }
221 | ],
222 | "metadata": {
223 | "kernelspec": {
224 | "display_name": "Python 3",
225 | "language": "python",
226 | "name": "python3"
227 | },
228 | "language_info": {
229 | "codemirror_mode": {
230 | "name": "ipython",
231 | "version": 3
232 | },
233 | "file_extension": ".py",
234 | "mimetype": "text/x-python",
235 | "name": "python",
236 | "nbconvert_exporter": "python",
237 | "pygments_lexer": "ipython3",
238 | "version": "3.7.4"
239 | },
240 | "toc": {
241 | "base_numbering": 1,
242 | "nav_menu": {},
243 | "number_sections": true,
244 | "sideBar": true,
245 | "skip_h1_title": true,
246 | "title_cell": "Table of Contents",
247 | "title_sidebar": "Contents",
248 | "toc_cell": false,
249 | "toc_position": {},
250 | "toc_section_display": true,
251 | "toc_window_display": true
252 | },
253 | "varInspector": {
254 | "cols": {
255 | "lenName": 16,
256 | "lenType": 16,
257 | "lenVar": 40
258 | },
259 | "kernels_config": {
260 | "python": {
261 | "delete_cmd_postfix": "",
262 | "delete_cmd_prefix": "del ",
263 | "library": "var_list.py",
264 | "varRefreshCmd": "print(var_dic_list())"
265 | },
266 | "r": {
267 | "delete_cmd_postfix": ") ",
268 | "delete_cmd_prefix": "rm(",
269 | "library": "var_list.r",
270 | "varRefreshCmd": "cat(var_dic_list()) "
271 | }
272 | },
273 | "types_to_exclude": [
274 | "module",
275 | "function",
276 | "builtin_function_or_method",
277 | "instance",
278 | "_Feature"
279 | ],
280 | "window_display": false
281 | }
282 | },
283 | "nbformat": 4,
284 | "nbformat_minor": 2
285 | }
286 |
--------------------------------------------------------------------------------
/instruments/asian_on_riskcontrol.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | ""
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Example Notebook for Asian on Risk Control"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {
21 | "ExecuteTime": {
22 | "end_time": "2020-05-01T09:41:34.226883Z",
23 | "start_time": "2020-05-01T09:41:31.254209Z"
24 | }
25 | },
26 | "outputs": [],
27 | "source": [
28 | "import pandas as pd\n",
29 | "import math\n",
30 | "import pyvacon.analytics as analytics\n",
31 | "import datetime as dt\n",
32 | "import pyvacon.tools.converter as converter\n",
33 | "import pyvacon.tools.enums as enums\n",
34 | "import pyvacon.marketdata.testdata as mkt_testdata\n",
35 | "import pyvacon.marketdata.converter as mkt_converter\n",
36 | "import pyvacon.instruments.testdata as ins_testdata"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": null,
42 | "metadata": {
43 | "ExecuteTime": {
44 | "end_time": "2020-05-01T09:41:34.233864Z",
45 | "start_time": "2020-05-01T09:41:34.229877Z"
46 | }
47 | },
48 | "outputs": [],
49 | "source": [
50 | "refdate = converter.getLTime(dt.datetime(2017,2,20))\n",
51 | "udl = 'DBK'"
52 | ]
53 | },
54 | {
55 | "cell_type": "markdown",
56 | "metadata": {},
57 | "source": [
58 | "### Create the necessary market data\n",
59 | "We just use the test data defined in the module analyticsTestData. To construct your own data or using the database, see the example sheets for market data."
60 | ]
61 | },
62 | {
63 | "cell_type": "code",
64 | "execution_count": null,
65 | "metadata": {
66 | "ExecuteTime": {
67 | "end_time": "2020-05-01T09:41:34.310664Z",
68 | "start_time": "2020-05-01T09:41:34.236857Z"
69 | },
70 | "code_folding": [
71 | 1,
72 | 26,
73 | 74,
74 | 98,
75 | 122,
76 | 146,
77 | 170,
78 | 195
79 | ]
80 | },
81 | "outputs": [],
82 | "source": [
83 | "underlying={\n",
84 | " 'ADS':{\n",
85 | " 'SPOT': 184.15,\n",
86 | " 'DIVIDENDS': \n",
87 | " pd.DataFrame({ \n",
88 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
89 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
90 | " 'CASH': [8.0, 8.0, 4.0, 4.0],\n",
91 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
92 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
93 | " }),\n",
94 | " 'BORROW':\n",
95 | " {\n",
96 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
97 | " 'RATES' : [0.01, 0.01]\n",
98 | " },\n",
99 | " 'VOLATILITY':{\n",
100 | " 'TYPE': 'SSVI',\n",
101 | " 'EXPIRIES': [10, 100, 365, 730], \n",
102 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
103 | " 'RHO':-0.65, \n",
104 | " 'ETA':0.8, \n",
105 | " 'GAMMA': 0.5\n",
106 | " }\n",
107 | " },\n",
108 | " \n",
109 | " 'BN':{\n",
110 | " 'SPOT': 65.01,\n",
111 | " 'DIVIDENDS': \n",
112 | " pd.DataFrame({ \n",
113 | " 'EXDATES': [dt.datetime(2017,2,1), dt.datetime(2018,2,1), dt.datetime(2019,2,1), dt.datetime(2020,2,1)],\n",
114 | " 'PAYDATES': [dt.datetime(2017,2,1), dt.datetime(2018,2,1), dt.datetime(2019,2,1), dt.datetime(2020,2,1)],\n",
115 | " 'CASH': [2.0, 2.0, 1.0, 1.0],\n",
116 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
117 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
118 | " }),\n",
119 | " 'BORROW':\n",
120 | " {\n",
121 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
122 | " 'RATES' : [0.01, 0.01]\n",
123 | " },\n",
124 | " 'VOLATILITY':{\n",
125 | " 'TYPE': 'SSVI',\n",
126 | " 'EXPIRIES': [10, 100, 365, 730], \n",
127 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
128 | " 'RHO':-0.65, \n",
129 | " 'ETA':0.8, \n",
130 | " 'GAMMA': 0.5\n",
131 | " }\n",
132 | " },\n",
133 | " 'DBK':{\n",
134 | " 'SPOT': 17.415,\n",
135 | " 'DIVIDENDS': \n",
136 | " pd.DataFrame({ \n",
137 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
138 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
139 | " 'CASH': [0.5, 0.5, 0.3, 0.2],\n",
140 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
141 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
142 | " }),\n",
143 | " 'BORROW':\n",
144 | " {\n",
145 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
146 | " 'RATES' : [0.01, 0.01]\n",
147 | " },\n",
148 | " 'VOLATILITY':{\n",
149 | " 'TYPE': 'SSVI',\n",
150 | " 'EXPIRIES': [10, 100, 365, 730], \n",
151 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
152 | " 'RHO':-0.65, \n",
153 | " 'ETA':0.8, \n",
154 | " 'GAMMA': 0.5\n",
155 | " }\n",
156 | " },\n",
157 | " 'EOAN_UNO1':{\n",
158 | " 'SPOT': 8.683,\n",
159 | " 'DIVIDENDS': \n",
160 | " pd.DataFrame({ \n",
161 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
162 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
163 | " 'CASH': [0.5, 0.5, 0.3, 0.2],\n",
164 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
165 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
166 | " }),\n",
167 | " 'BORROW':\n",
168 | " {\n",
169 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
170 | " 'RATES' : [0.01, 0.01]\n",
171 | " },\n",
172 | " 'VOLATILITY':{\n",
173 | " 'TYPE': 'SSVI',\n",
174 | " 'EXPIRIES': [10, 100, 365, 730], \n",
175 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
176 | " 'RHO':-0.65, \n",
177 | " 'ETA':0.8, \n",
178 | " 'GAMMA': 0.5\n",
179 | " }\n",
180 | " },\n",
181 | " 'SDF': {\n",
182 | " 'SPOT': 22.68,\n",
183 | " 'DIVIDENDS': \n",
184 | " pd.DataFrame({ \n",
185 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
186 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
187 | " 'CASH': [1.0, 1.0, 0.5, 0.3],\n",
188 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
189 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
190 | " }),\n",
191 | " 'BORROW':\n",
192 | " {\n",
193 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
194 | " 'RATES' : [0.01, 0.01]\n",
195 | " },\n",
196 | " 'VOLATILITY':{\n",
197 | " 'TYPE': 'SSVI',\n",
198 | " 'EXPIRIES': [10, 100, 365, 730], \n",
199 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
200 | " 'RHO':-0.65, \n",
201 | " 'ETA':0.8, \n",
202 | " 'GAMMA': 0.5\n",
203 | " }\n",
204 | " },\n",
205 | " 'SAP':{\n",
206 | " 'SPOT': 93.84,\n",
207 | " 'DIVIDENDS': \n",
208 | " pd.DataFrame({ \n",
209 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
210 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
211 | " 'CASH': [5.0, 5.0, 3.0, 2.0],\n",
212 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
213 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
214 | " }),\n",
215 | " 'BORROW':\n",
216 | " {\n",
217 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
218 | " 'RATES' : [0.01, 0.01]\n",
219 | " },\n",
220 | " 'VOLATILITY':{\n",
221 | " 'TYPE': 'SSVI',\n",
222 | " 'EXPIRIES': [10, 100, 365, 730], \n",
223 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
224 | " 'RHO':-0.65, \n",
225 | " 'ETA':0.8, \n",
226 | " 'GAMMA': 0.5\n",
227 | " }\n",
228 | " },\n",
229 | " 'SIE':{\n",
230 | " 'SPOT': 132,\n",
231 | " 'DIVIDENDS': \n",
232 | " pd.DataFrame({ \n",
233 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
234 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
235 | " 'CASH': [5.0, 5.0, 3.0, 2.0],\n",
236 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
237 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
238 | " }),\n",
239 | " 'BORROW':\n",
240 | " {\n",
241 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
242 | " 'RATES' : [0.01, 0.01]\n",
243 | " },\n",
244 | " 'VOLATILITY':{\n",
245 | " 'TYPE': 'SSVI',\n",
246 | " 'EXPIRIES': [10, 100, 365, 730], \n",
247 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
248 | " 'RHO':-0.65, \n",
249 | " 'ETA':0.8, \n",
250 | " 'GAMMA': 0.5\n",
251 | " }\n",
252 | " },\n",
253 | " 'TKA':{\n",
254 | " 'SPOT': 22.515,\n",
255 | " 'DIVIDENDS': \n",
256 | " pd.DataFrame({ \n",
257 | " 'EXDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
258 | " 'PAYDATES': [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
259 | " 'CASH': [1.0, 1.0, 0.5, 0.3],\n",
260 | " 'YIELD': [0.0, 0.0, 0.02, 0.03],\n",
261 | " 'TAX': [0.8, 0.8, 0.8, 0.8]\n",
262 | " }),\n",
263 | " 'BORROW':\n",
264 | " {\n",
265 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2020,1,1)],\n",
266 | " 'RATES' : [0.01, 0.01]\n",
267 | " },\n",
268 | " 'VOLATILITY':{\n",
269 | " 'TYPE': 'SSVI',\n",
270 | " 'EXPIRIES': [10, 100, 365, 730], \n",
271 | " 'ATMVOLS': [0.2, 0.25, 0.28, 0.3], \n",
272 | " 'RHO':-0.65, \n",
273 | " 'ETA':0.8, \n",
274 | " 'GAMMA': 0.5\n",
275 | " }\n",
276 | " }\n",
277 | "}\n",
278 | "discount = {\n",
279 | " 'EUR':{\n",
280 | " 'DATES' : [dt.datetime(2018,1,1), dt.datetime(2019,1,1), dt.datetime(2020,1,1), dt.datetime(2021,1,1)],\n",
281 | " 'RATES' : [-.002, 0.002, 0.004, 0.006]\n",
282 | " }\n",
283 | "}"
284 | ]
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "metadata": {},
289 | "source": [
290 | "### Setup the specification\n",
291 | "#### Risk control index\n",
292 | "The risk control index is a basket of an Index and a risk free account where the basket weights are rebalanced each day with the aim that the baskets volatility is as close as possible to a fixed target volatility. There may be different strategies (using historic or implied vols), where up to now the following strategy is implemented.\n",
293 | "\n",
294 | "The value $RC(t+\\delta t)$ of the risk control index at a new timestep $t+\\delta t$ is determined by\n",
295 | "$$ RC(t+\\delta t) = RC(t)\\left(1.0+ w(t)(\\frac{I(t+\\delta t)}{I(t)}-1.0) +(1.0-w(t))acc\\right)(1-acc) $$\n",
296 | "where \n",
297 | "- $acc$ is the accrued interest between in interval $\\delta t$\n",
298 | "- $I(t)$ is the vlue of the underlying index at time $t$\n",
299 | "- $w(t+\\delta t) = \\left\\{\\begin{array}{l} \n",
300 | " w(t) \\mbox{ if } \\| 1-w^T/w(t)\\|\\leq \\varepsilon \\\\\n",
301 | " \\min(w^T,w^{max}) \n",
302 | " \\end{array}\\right.$\n",
303 | " where \n",
304 | " - $\\varepsilon$ is a given threshold and $ w^{max}$ a given maximum weight\n",
305 | " - $w^T=\\frac{\\sigma^{target}}{\\max_i\\{\\sigma_i\\}}$ where $\\sigma_i$ is the historic $n_i$-days volatility computed by $\\sigma_i =\\sqrt{\\mbox{volfactor}\\cdot \\frac{\\sum_{1\\leq j \\leq n_i} \\log\\left(I(t-j\\delta t)/I(t-(j-1)\\delta )\\right)^2}{ n_i}}$\n"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": null,
311 | "metadata": {
312 | "ExecuteTime": {
313 | "end_time": "2020-05-01T09:41:34.326617Z",
314 | "start_time": "2020-05-01T09:41:34.312653Z"
315 | }
316 | },
317 | "outputs": [],
318 | "source": [
319 | "target_vol = 0.3 / math.sqrt(365.0)\n",
320 | "vol_factor = 1.0\n",
321 | "n_voldays = analytics.vectorInt([10, 15])\n",
322 | "max_weight = 5.0\n",
323 | "update_threshold = 1e-10\n",
324 | "excess_return = False\n",
325 | "rc_strategy = analytics.RiskControlStrategy(target_vol, vol_factor, n_voldays, max_weight, update_threshold, excess_return)\n",
326 | "expiry = converter.getLTime(365, refdate)\n",
327 | "strike = 19.0\n",
328 | "asian_dates = converter.createPTimeList(refdate,[100, 200, 300, 364])\n",
329 | "asian_type = \"ARITHMETIC\"\n",
330 | "\n",
331 | "asian_rc = analytics.AsianRiskControlSpecification(rc_strategy, \"ASIAN_RC\", \"ISSUER\", \n",
332 | " enums.SecuritizationLevel.COLLATERALIZED,\"EUR\", udl, \n",
333 | " \"Call\", expiry, strike, asian_dates, asian_type)"
334 | ]
335 | },
336 | {
337 | "cell_type": "markdown",
338 | "metadata": {},
339 | "source": [
340 | "### Setup the pricing data\n",
341 | "A product may be priced in two different ways: One may either fill the respective pricing data needed for a special pricer (which inherits from th BasePricingData) and use the respective price method where just the pricing data is given. Another possibility is to use the price-method where the storages are given. In this case, the pricer will fill the needed pricing data according to the underlying and other data as specified in the product specification."
342 | ]
343 | },
344 | {
345 | "cell_type": "code",
346 | "execution_count": null,
347 | "metadata": {
348 | "ExecuteTime": {
349 | "end_time": "2020-05-01T09:41:34.344568Z",
350 | "start_time": "2020-05-01T09:41:34.328609Z"
351 | }
352 | },
353 | "outputs": [],
354 | "source": [
355 | "pricing_data = analytics.AsianRiskControlPricingData()\n",
356 | "pricing_data.valDate = refdate\n",
357 | "pricing_data.spec = asian_rc\n",
358 | "pricing_data.dsc = mkt_converter.discount_from_dict('EUR', discount['EUR'], refdate)\n",
359 | "pricing_data.param = analytics.MonteCarloPricingParameter()\n",
360 | "pricing_data.param.mcParam.numberOfSimulations = 1000\n",
361 | "pricing_data.vol = mkt_converter.vol_from_dict(underlying, discount, udl,'EUR', refdate)\n",
362 | "pricing_data.pricingRequest = analytics.PricingRequest()\n",
363 | "pricing_data.qtoCorr = 0.0\n",
364 | "pricing_data.spotFixings = analytics.vectorDouble([17.0]*15)\n",
365 | "pricing_data.indexFixings = analytics.vectorDouble()\n",
366 | "pricing_data.lastWeight = 1.0\n",
367 | "pricing_data.currentRCI = 17"
368 | ]
369 | },
370 | {
371 | "cell_type": "markdown",
372 | "metadata": {},
373 | "source": [
374 | "### Pricing\n",
375 | "#### Local volatility"
376 | ]
377 | },
378 | {
379 | "cell_type": "code",
380 | "execution_count": null,
381 | "metadata": {
382 | "ExecuteTime": {
383 | "end_time": "2020-05-01T09:41:34.756587Z",
384 | "start_time": "2020-05-01T09:41:34.348557Z"
385 | }
386 | },
387 | "outputs": [],
388 | "source": [
389 | "analytics.setLogLevel('DEBUG')\n",
390 | "#uncomment the line below if you want to serialize the complete pricing data\n",
391 | "#pricing_data.save('rc_pricing_data.json', pricing_data)\n",
392 | "pr = analytics.price(pricing_data)\n",
393 | "#plot the price\n",
394 | "pr.getPrice()"
395 | ]
396 | },
397 | {
398 | "cell_type": "markdown",
399 | "metadata": {},
400 | "source": [
401 | "#### Stochastic volatility"
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "execution_count": null,
407 | "metadata": {
408 | "ExecuteTime": {
409 | "end_time": "2020-05-01T09:41:34.775536Z",
410 | "start_time": "2020-05-01T09:41:34.761573Z"
411 | }
412 | },
413 | "outputs": [],
414 | "source": [
415 | "S0 = 1.0\n",
416 | "kappa = 2.0\n",
417 | "theta = 0.04\n",
418 | "alpha = 0.10\n",
419 | "v0 = 0.01\n",
420 | "rho = -0.8\n",
421 | "heston = analytics.HestonModel('HESTON', refdate, S0, v0, theta, kappa, alpha, rho)\n",
422 | "pricing_data.model = heston"
423 | ]
424 | },
425 | {
426 | "cell_type": "code",
427 | "execution_count": null,
428 | "metadata": {
429 | "ExecuteTime": {
430 | "end_time": "2020-05-01T09:41:35.093685Z",
431 | "start_time": "2020-05-01T09:41:34.778528Z"
432 | }
433 | },
434 | "outputs": [],
435 | "source": [
436 | "analytics.setLogLevel('DEBUG')\n",
437 | "#uncomment the line below if you want to serialize the complete pricing data\n",
438 | "#pricing_data.save('rc_pricing_data.json', pricing_data)\n",
439 | "pr = analytics.price(pricing_data)\n",
440 | "#plot the price\n",
441 | "pr.getPrice()"
442 | ]
443 | },
444 | {
445 | "cell_type": "markdown",
446 | "metadata": {},
447 | "source": [
448 | "---"
449 | ]
450 | }
451 | ],
452 | "metadata": {
453 | "kernelspec": {
454 | "display_name": "Python 3",
455 | "language": "python",
456 | "name": "python3"
457 | },
458 | "language_info": {
459 | "codemirror_mode": {
460 | "name": "ipython",
461 | "version": 3
462 | },
463 | "file_extension": ".py",
464 | "mimetype": "text/x-python",
465 | "name": "python",
466 | "nbconvert_exporter": "python",
467 | "pygments_lexer": "ipython3",
468 | "version": "3.7.4"
469 | },
470 | "toc": {
471 | "base_numbering": 1,
472 | "nav_menu": {
473 | "height": "118px",
474 | "width": "252px"
475 | },
476 | "number_sections": true,
477 | "sideBar": true,
478 | "skip_h1_title": true,
479 | "title_cell": "Table of Contents",
480 | "title_sidebar": "Contents",
481 | "toc_cell": false,
482 | "toc_position": {},
483 | "toc_section_display": "block",
484 | "toc_window_display": true
485 | },
486 | "varInspector": {
487 | "cols": {
488 | "lenName": 16,
489 | "lenType": 16,
490 | "lenVar": 40
491 | },
492 | "kernels_config": {
493 | "python": {
494 | "delete_cmd_postfix": "",
495 | "delete_cmd_prefix": "del ",
496 | "library": "var_list.py",
497 | "varRefreshCmd": "print(var_dic_list())"
498 | },
499 | "r": {
500 | "delete_cmd_postfix": ") ",
501 | "delete_cmd_prefix": "rm(",
502 | "library": "var_list.r",
503 | "varRefreshCmd": "cat(var_dic_list()) "
504 | }
505 | },
506 | "types_to_exclude": [
507 | "module",
508 | "function",
509 | "builtin_function_or_method",
510 | "instance",
511 | "_Feature"
512 | ],
513 | "window_display": false
514 | }
515 | },
516 | "nbformat": 4,
517 | "nbformat_minor": 2
518 | }
519 |
--------------------------------------------------------------------------------
/instruments/asian_option.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | ""
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Asian Options"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {
21 | "ExecuteTime": {
22 | "end_time": "2020-05-03T11:34:54.652160Z",
23 | "start_time": "2020-05-03T11:34:40.893864Z"
24 | }
25 | },
26 | "outputs": [],
27 | "source": [
28 | "import pandas as pd\n",
29 | "import math\n",
30 | "import numpy as np\n",
31 | "import random\n",
32 | "from scipy.stats import norm\n",
33 | "import pyvacon.analytics as analytics\n",
34 | "import datetime as dt\n",
35 | "import pyvacon.tools.converter as converter\n",
36 | "import pyvacon.tools.enums as enums\n",
37 | "import pyvacon.marketdata.testdata as mkt_testdata\n",
38 | "import pyvacon.marketdata.converter as mkt_converter\n",
39 | "import pyvacon.instruments.testdata as ins_testdata\n",
40 | "import pyvacon.marketdata.plot as mkt_plot #import module for plotting functionality\n",
41 | "#the next lin is a jupyter internal command to show the matplotlib graphs within the notebook\n",
42 | "%matplotlib inline"
43 | ]
44 | },
45 | {
46 | "cell_type": "markdown",
47 | "metadata": {},
48 | "source": [
49 | "## Definition of an Asian Option\n",
50 | "\n",
51 | "An Asian option is an option where the payoff depends on the arithmetic mean of the underling asset's price during the life of the option. Asian options can be of American or European style. Thus, Asian options are appropriate for corporations that, for example, want to ensure that an average exchange rate over a certain period can be realized.\n",
52 | "\n",
53 | "The payoff of an Asian call option is given as $$max(S_{avg}-K, 0),$$ the payoff of an Asian put option is $$max(K-S_{avg}, 0).$$\n",
54 | "\n",
55 | "The average can thereby be an arithmetic or geometric average."
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "## Pricing an Asian Option – One Observation\n",
63 | "\n",
64 | "The price of an (European) Asian option can be calculated applying the Back-76 model which is explained [here](european_plain_vanilla_option.ipynb) with \n",
65 | "\n",
66 | "$$F_0 = M_1$$ \n",
67 | "and \n",
68 | "$$\\sigma^2=\\frac{1}{T}\\ln\\left(\\frac{M_2}{M_1^2}\\right).$$\n",
69 | "\n",
70 | "This leads to the following modified Black-76 model:\n",
71 | "\n",
72 | "$$c=e^{-rT}[M_1N(d_1)-KN(d_2)] \\quad \\text{resp.} \\quad p=e^{-rT}[KN(-d_2)-M_1N(-d_1)]$$\n",
73 | "\n",
74 | "with $$d_1=\\frac{\\ln(M_1/K)+(\\frac{\\frac{1}{T}\\ln\\left(\\frac{M_2}{M_1^2}\\right)}{2})T}{\\sqrt{\\frac{1}{T}\\ln\\left(\\frac{M_2}{M_1^2}\\right)}\\sqrt{T}} \\quad \\text{and} \\quad d_2 = \\frac{\\ln(M_1/K)+(\\frac{\\frac{1}{T}\\ln\\left(\\frac{M_2}{M_1^2}\\right)}{2})T}{\\sqrt{\\frac{1}{T}\\ln\\left(\\frac{M_2}{M_1^2}\\right)}\\sqrt{T}}= d_1-\\sqrt{\\frac{1}{T}\\ln\\left(\\frac{M_2}{M_1^2}\\right)}\\sqrt{T}.$$\n",
75 | "\n",
76 | "When the average is calculated continuously, and $\\sigma$, $r$ and $q$ are constant, the first two moments $M_1$ and $M_2$ of the underlying asset's average stock price $S_{avg}$ are\n",
77 | "\n",
78 | "$$M_1 = \\frac{e^{(r-q)T}-1}{(r-q)T}S_0,$$\n",
79 | "\n",
80 | "and\n",
81 | "\n",
82 | "$$M_2 = \\frac{2e^{[2(r-q)+\\sigma^2]T}S_0^2}{(r-q+\\sigma^2)(2r-2q+\\sigma^2)T^2}+\\frac{2S_0^2}{(r-q)T^2}\\left(\\frac{1}{2(r-q)+\\sigma^2}-\\frac{e^{(r-q)T}}{r-q+\\sigma^2} \\right).$$"
83 | ]
84 | },
85 | {
86 | "cell_type": "code",
87 | "execution_count": null,
88 | "metadata": {
89 | "ExecuteTime": {
90 | "end_time": "2020-05-03T11:34:54.685385Z",
91 | "start_time": "2020-05-03T11:34:54.656150Z"
92 | }
93 | },
94 | "outputs": [],
95 | "source": [
96 | "def exp(x):\n",
97 | " return math.exp(x)\n",
98 | "def sqrt(x):\n",
99 | " return math.sqrt(x)\n",
100 | "def cdf(x):\n",
101 | " return norm.cdf(x)\n",
102 | "def ln(x):\n",
103 | " return math.log(x)\n",
104 | "\n",
105 | "def AsianOptionPricer_single(_type, S0, K, r_f, r_b_f,r_br_dsc, sigma, T):\n",
106 | " M1 = (exp((r_f-r_b)*T)-1)/((r_f-r_b)*T)*S0\n",
107 | " M2 = (2*exp((2*(r_f-r_b)+sigma**2)*T)*S0**2)/((r_f-r_b+sigma**2)*(2*r_f-2*r_b+sigma**2)*T**2)+(2*S0**2)/((r_f-r_b)*T**2)*((1/(2*(r_f-r_b)+sigma**2))-((exp((r_f-r_b)*T))/(r_f-r_b+sigma**2)))\n",
108 | " sig_n = sqrt(1/T*ln(M2/M1**2))\n",
109 | " d1 = (ln(M1/K)+(sig_n**2/2)*(T))/(sig_n*sqrt(T))\n",
110 | " d2 = d1-sig_n*sqrt(T)\n",
111 | " if _type == 'c':\n",
112 | " cp = 1\n",
113 | " if _type =='p':\n",
114 | " cp = -1\n",
115 | " return cp*exp(-r_dsc*(T))*(M1*cdf(cp*d1)-K*cdf(cp*d2)), M1, M2"
116 | ]
117 | },
118 | {
119 | "cell_type": "code",
120 | "execution_count": null,
121 | "metadata": {
122 | "ExecuteTime": {
123 | "end_time": "2020-05-03T11:34:54.809328Z",
124 | "start_time": "2020-05-03T11:34:54.710333Z"
125 | }
126 | },
127 | "outputs": [],
128 | "source": [
129 | "S0 = 50\n",
130 | "K = 50\n",
131 | "r_dsc = 0.05\n",
132 | "r_f = 0.05\n",
133 | "r_b = 0.00\n",
134 | "sigma = 0.4\n",
135 | "T = 1\n",
136 | "\n",
137 | "AsianOptionPricer_single('c', S0, K, r_f, r_b, r_dsc, sigma, T)"
138 | ]
139 | },
140 | {
141 | "cell_type": "markdown",
142 | "metadata": {},
143 | "source": [
144 | "## Pricing an Asian Option – Multiple Observations\n",
145 | "\n",
146 | "When the average is calculated from multiple observations at times $T_i$ $(1\\leq i\\leq m)$, the first two moments of $S_{avg}$, $M_1$ and $M_2$, are \n",
147 | "\n",
148 | "$$M_1 = \\frac{1}{m}\\sum_{i=1}^mF_i$$\n",
149 | "and\n",
150 | "$$M_2 = \\frac{1}{m^2}\\left(\\sum_{i=1}^mF_i^2e^{\\sigma_i^2T_i}+2\\sum_{j=1}^m\\sum_{i=1}^{j-1}F_iF_je^{\\sigma_i^2T_i}\\right).$$\n",
151 | "\n",
152 | "$F_i$ is the forward price for maturity $T_i$, $\\sigma_i$ is the implied volatility for maturity $T_i$."
153 | ]
154 | },
155 | {
156 | "cell_type": "code",
157 | "execution_count": null,
158 | "metadata": {
159 | "ExecuteTime": {
160 | "end_time": "2020-05-03T11:34:54.865755Z",
161 | "start_time": "2020-05-03T11:34:54.813584Z"
162 | }
163 | },
164 | "outputs": [],
165 | "source": [
166 | "def AsianOptionPricer(_type, S0, K, r_f, r_b, r_dsc, sigma_i, T_i, T):\n",
167 | " F = []\n",
168 | " for i in range(len(T_i)):\n",
169 | " F.append(S0*exp((r_f-r_b)*T_i[i]))\n",
170 | " m = len(T_i)\n",
171 | " M1 = sum(F)/m\n",
172 | " sum1 = 0\n",
173 | " for i in range(m):\n",
174 | " sum1 += F[i]**2 * exp(sigma_i[i]**2 * T_i[i])\n",
175 | " sum2 = 0\n",
176 | " for j in range(m):\n",
177 | " for i in range(j):\n",
178 | " sum2 += F[i]*F[j] * exp( sigma_i[i]**2 * T_i[i] ) \n",
179 | " M2 = ( sum1 + 2*sum2 ) / m**2\n",
180 | " sig_n = sqrt(1/T*ln(M2/M1**2))\n",
181 | " d1 = (ln(M1/K)+(sig_n**2/2)*(T))/(sig_n*sqrt(T))\n",
182 | " d2 = d1-sig_n*sqrt(T)\n",
183 | " if _type=='c':\n",
184 | " cp = 1\n",
185 | " if _type =='p':\n",
186 | " cp = -1\n",
187 | " return cp*math.exp(-r_dsc*(T))*(M1*cdf(cp*d1)-K*cdf(cp*d2)) "
188 | ]
189 | },
190 | {
191 | "cell_type": "code",
192 | "execution_count": null,
193 | "metadata": {
194 | "ExecuteTime": {
195 | "end_time": "2020-05-03T11:34:54.931796Z",
196 | "start_time": "2020-05-03T11:34:54.870683Z"
197 | }
198 | },
199 | "outputs": [],
200 | "source": [
201 | "S0 = 50\n",
202 | "K = 50\n",
203 | "r_dsc = 0.05\n",
204 | "r_f = 0.05\n",
205 | "r_b = 0.00\n",
206 | "T = 1\n",
207 | "sigma_i = []\n",
208 | "T_i = []\n",
209 | "x = 0.01\n",
210 | "while x <= 1.0:\n",
211 | " T_i.append(x)\n",
212 | " sigma_i.append(0.4)\n",
213 | " x += 0.01"
214 | ]
215 | },
216 | {
217 | "cell_type": "code",
218 | "execution_count": null,
219 | "metadata": {
220 | "ExecuteTime": {
221 | "end_time": "2020-05-03T11:34:55.016583Z",
222 | "start_time": "2020-05-03T11:34:54.937781Z"
223 | }
224 | },
225 | "outputs": [],
226 | "source": [
227 | "AsianOptionPricer('c', S0, K, r_f, r_b, r_dsc, sigma_i, T_i, T)"
228 | ]
229 | },
230 | {
231 | "cell_type": "markdown",
232 | "metadata": {},
233 | "source": [
234 | "## Plotting the Option Price"
235 | ]
236 | },
237 | {
238 | "cell_type": "code",
239 | "execution_count": null,
240 | "metadata": {
241 | "ExecuteTime": {
242 | "end_time": "2020-05-03T11:35:13.745807Z",
243 | "start_time": "2020-05-03T11:34:55.022565Z"
244 | }
245 | },
246 | "outputs": [],
247 | "source": [
248 | "spots = []\n",
249 | "\n",
250 | "n=0.5\n",
251 | "while n<=100:\n",
252 | " spots.append(n)\n",
253 | " n=n+0.1\n",
254 | " \n",
255 | "call_prices = []\n",
256 | "for i in range(len(spots)):\n",
257 | " call_prices.append(AsianOptionPricer('c', spots[i], K, r_f, r_b, r_dsc, sigma_i, T_i, T))\n",
258 | " \n",
259 | "put_prices = []\n",
260 | "for i in range(len(spots)):\n",
261 | " put_prices.append(AsianOptionPricer('p', spots[i], K, r_f, r_b, r_dsc, sigma_i, T_i, T))\n",
262 | "\n",
263 | "#Plot the prices\n",
264 | "prices_list = {'Spots': spots, \n",
265 | " 'Call Prices': call_prices,\n",
266 | " 'Put Prices': put_prices}\n",
267 | "\n",
268 | "prices = pd.DataFrame(prices_list, index = spots) \n",
269 | "\n",
270 | "fig, ax = mkt_plot.plt.subplots(figsize=(20,10))\n",
271 | "# fig.figure(gifsize=(20,10))\n",
272 | "ax.plot(prices['Spots'],prices['Call Prices'],label='Call Prices')\n",
273 | "ax.plot(prices['Spots'],prices['Put Prices'],label = 'Put Prices')\n",
274 | "ax.tick_params(axis=\"x\", labelsize=12)\n",
275 | "ax.tick_params(axis=\"y\", labelsize=12)\n",
276 | "ax.axvline(x=K, label='Strike', ls= '--', c='g')\n",
277 | "ax.set_title('Asian Option Prices',fontsize=30,y=1.02)\n",
278 | "ax.set_xlabel('Spot',fontsize=20)\n",
279 | "ax.set_ylabel('Price',fontsize=20)\n",
280 | "legend = ax.legend(loc='best', shadow=True, fontsize='15')"
281 | ]
282 | },
283 | {
284 | "cell_type": "markdown",
285 | "metadata": {},
286 | "source": [
287 | "## Asian Option Pricing Using Monte-Carlo Simulation"
288 | ]
289 | },
290 | {
291 | "cell_type": "code",
292 | "execution_count": null,
293 | "metadata": {
294 | "ExecuteTime": {
295 | "end_time": "2020-05-03T11:35:13.774967Z",
296 | "start_time": "2020-05-03T11:35:13.749149Z"
297 | }
298 | },
299 | "outputs": [],
300 | "source": [
301 | "def MCAsianOptionPricer(Type, S0, K, r_f, r_b, r_dsc, sigma, T,m, n):\n",
302 | " if Type=='c':\n",
303 | " cp = 1\n",
304 | " if Type =='p':\n",
305 | " cp = -1\n",
306 | " PV_total = 0\n",
307 | " Dt = T/m\n",
308 | " for j in range(1,n):\n",
309 | " S_total = 0\n",
310 | " S = S0\n",
311 | " for i in range(m):\n",
312 | " S = S*exp(((r_f-r_b)-sigma**2/2)*Dt+sigma*norm.ppf(random.random())*sqrt(Dt))\n",
313 | " S_total += S\n",
314 | " PV_path = max(cp*(S_total/m-K, 0))*exp(-r_dsc*T)\n",
315 | " PV_total +=PV_path\n",
316 | " return PV_total/n"
317 | ]
318 | },
319 | {
320 | "cell_type": "code",
321 | "execution_count": null,
322 | "metadata": {
323 | "ExecuteTime": {
324 | "end_time": "2020-05-03T11:37:00.256614Z",
325 | "start_time": "2020-05-03T11:35:13.781115Z"
326 | }
327 | },
328 | "outputs": [],
329 | "source": [
330 | "S0 = 50\n",
331 | "K = 50\n",
332 | "r_f = 0.05\n",
333 | "r_dsc = 0.05\n",
334 | "r_b = 0.00\n",
335 | "sigma = 0.4\n",
336 | "T = 1\n",
337 | "m = 365 # no steps - mit n = 1 sollte es preis von europ. plain vanilla option sein\n",
338 | "n =1000 # no of simulations\n",
339 | "\n",
340 | "MCAsianOptionPricer('c', S0, K, r_f, r_b, r_dsc, sigma, T,m, n)"
341 | ]
342 | },
343 | {
344 | "cell_type": "markdown",
345 | "metadata": {},
346 | "source": [
347 | "Alternatively, the following code can be used."
348 | ]
349 | },
350 | {
351 | "cell_type": "code",
352 | "execution_count": null,
353 | "metadata": {
354 | "ExecuteTime": {
355 | "end_time": "2020-05-03T11:37:00.274108Z",
356 | "start_time": "2020-05-03T11:37:00.259558Z"
357 | }
358 | },
359 | "outputs": [],
360 | "source": [
361 | "def MC2AsianOptionPricer(T, r_f, r_b, r_dsc, K, sigma, S0, m, n):\n",
362 | " sumavg_path = 0\n",
363 | " for i in range(1,n):\n",
364 | " D = T / m\n",
365 | " S = np.random.normal(((r_f-r_b)-sigma**2/2)*D, sigma*D**0.5, m) # normal distributed with mu, sigma and m\n",
366 | " PV_avg_path = math.exp(-r_dsc*T)*max(np.mean(np.exp(np.cumsum(S)))*S0 - K, 0)\n",
367 | " sumavg_path = sumavg_path+PV_avg_path\n",
368 | " return sumavg_path/n, S"
369 | ]
370 | },
371 | {
372 | "cell_type": "code",
373 | "execution_count": null,
374 | "metadata": {
375 | "ExecuteTime": {
376 | "end_time": "2020-05-03T11:37:01.087542Z",
377 | "start_time": "2020-05-03T11:37:00.277128Z"
378 | }
379 | },
380 | "outputs": [],
381 | "source": [
382 | "S0 = 50\n",
383 | "K = 50\n",
384 | "r_f = 0.05\n",
385 | "r_dsc = 0.05\n",
386 | "r_b = 0.00\n",
387 | "sigma = 0.4\n",
388 | "T = 1\n",
389 | "m=10000\n",
390 | "n = 1000\n",
391 | "\n",
392 | "MC2AsianOptionPricer(T, r_f, r_b, r_dsc, K, sigma, S0, m, n)"
393 | ]
394 | },
395 | {
396 | "cell_type": "markdown",
397 | "metadata": {},
398 | "source": [
399 | "---"
400 | ]
401 | }
402 | ],
403 | "metadata": {
404 | "kernelspec": {
405 | "display_name": "Python 3",
406 | "language": "python",
407 | "name": "python3"
408 | },
409 | "language_info": {
410 | "codemirror_mode": {
411 | "name": "ipython",
412 | "version": 3
413 | },
414 | "file_extension": ".py",
415 | "mimetype": "text/x-python",
416 | "name": "python",
417 | "nbconvert_exporter": "python",
418 | "pygments_lexer": "ipython3",
419 | "version": "3.7.4"
420 | },
421 | "toc": {
422 | "base_numbering": 1,
423 | "nav_menu": {
424 | "height": "118px",
425 | "width": "252px"
426 | },
427 | "number_sections": true,
428 | "sideBar": true,
429 | "skip_h1_title": true,
430 | "title_cell": "Table of Contents",
431 | "title_sidebar": "Contents",
432 | "toc_cell": false,
433 | "toc_position": {},
434 | "toc_section_display": "block",
435 | "toc_window_display": true
436 | },
437 | "varInspector": {
438 | "cols": {
439 | "lenName": 16,
440 | "lenType": 16,
441 | "lenVar": 40
442 | },
443 | "kernels_config": {
444 | "python": {
445 | "delete_cmd_postfix": "",
446 | "delete_cmd_prefix": "del ",
447 | "library": "var_list.py",
448 | "varRefreshCmd": "print(var_dic_list())"
449 | },
450 | "r": {
451 | "delete_cmd_postfix": ") ",
452 | "delete_cmd_prefix": "rm(",
453 | "library": "var_list.r",
454 | "varRefreshCmd": "cat(var_dic_list()) "
455 | }
456 | },
457 | "types_to_exclude": [
458 | "module",
459 | "function",
460 | "builtin_function_or_method",
461 | "instance",
462 | "_Feature"
463 | ],
464 | "window_display": false
465 | }
466 | },
467 | "nbformat": 4,
468 | "nbformat_minor": 2
469 | }
470 |
--------------------------------------------------------------------------------
/instruments/binomial_trees.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | ""
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Binomial Trees"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {
21 | "ExecuteTime": {
22 | "end_time": "2020-05-03T11:38:27.214283Z",
23 | "start_time": "2020-05-03T11:38:27.209856Z"
24 | }
25 | },
26 | "outputs": [],
27 | "source": [
28 | "import math"
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": null,
34 | "metadata": {
35 | "ExecuteTime": {
36 | "end_time": "2020-05-03T11:38:27.242864Z",
37 | "start_time": "2020-05-03T11:38:27.218989Z"
38 | }
39 | },
40 | "outputs": [],
41 | "source": [
42 | "def exp(x):\n",
43 | " return math.exp(x)"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "## Application of Binomial Trees\n",
51 | "\n",
52 | "Binomial trees are a popular technique for pricing options. This method relies on the assumption that stock prices follow a random walk and at each time step, it has a certain probability of moving up or down by a certain percentage. Furthermore, it requires the assumption that no arbitrage opportunities exist. The binomial tree represents the different paths a stock price can follow. In the limit, this model converges to the Black-Scholes-Merton model, which is described [here](european_plain_vanilla_option.ipynb).\n",
53 | "\n",
54 | "## Example - One-Step Binomial Tree\n",
55 | "\n",
56 | "Consider a stock which currently trades at 50. We are interested in pricing a European call option with a strike of 50 and maturity in six months from now. We know that at maturity, the stock will either move up to 55 or move down to 45. Hence, if the stock price moves up, the option will have a value of 5; if the stock price moves down, the option will have the value zero. \n",
57 | "\n",
58 | "Assuming a risk neutral world, we can set up a portfolio of the stock itself and the option so that we already know the value of the portfolio at maturity. Therefore, we need to calculate the delta of shares we need to hold to make the portfolio riskless. We can calculate delta as \n",
59 | "\n",
60 | "$$\\Delta=\\frac{c_u-c_d}{S_0u-S_0d},$$\n",
61 | "\n",
62 | "\n",
63 | "where $c_u$ and $c_d$ is the value of the option assuming the stock moves up respectively down and $S_0u$ and $S_0d$ is the value of the stock if it moves up respectively down. Hence, delta is given as \n",
64 | "\n",
65 | "$$\\Delta=\\frac{5-0}{55-45}=0.5.$$\n",
66 | "\n",
67 | "\n",
68 | "Now, we can create a riskless portfolio by holding a long position in $\\Delta$ shares and short one call option. If the stock price moves up to 55, the value of the portfolio is $55\\cdot0.5-5=22.5$; if the stock price moves down to 45, the value of the portfolio is $45\\cdot0.5-0=22.5$. Discounting the portfolio value at maturity assuming a risk-free interest rate $r$ of 0.05 gives as a present value of the portfolio of \n",
69 | "\n",
70 | "$$22.5e^{-0.05\\cdot6/12}=21.94.$$\n",
71 | "\n",
72 | "In order to determine the option price today, we know that the portfolio value is the value of the long position in $\\Delta$ shares and the short position in one option and we further now that this value is $21.94$. Hence, it follows that \n",
73 | "\n",
74 | "$$50\\cdot0.5-c=21.94$$ or $$c = 3.06.$$\n",
75 | "\n",
76 | "The following code shows how the option value can be calculated."
77 | ]
78 | },
79 | {
80 | "cell_type": "code",
81 | "execution_count": null,
82 | "metadata": {
83 | "ExecuteTime": {
84 | "end_time": "2020-05-03T11:38:27.266046Z",
85 | "start_time": "2020-05-03T11:38:27.247851Z"
86 | }
87 | },
88 | "outputs": [],
89 | "source": [
90 | "S0 = 50\n",
91 | "K = 50\n",
92 | "S0_u = 55\n",
93 | "S0_d = 45\n",
94 | "r= 0.05\n",
95 | "T = 0.5\n",
96 | "\n",
97 | "c_u = max(S0_u-K,0)\n",
98 | "c_d = max(S0_d-K, 0)\n",
99 | "\n",
100 | "delta = (c_u-c_d)/(S0_u-S0_d)\n",
101 | "\n",
102 | "pf_value_u = (S0_u*delta-c_u)*exp(-r*T)\n",
103 | "pf_value_d = (S0_d*delta-c_d)*exp(-r*T)\n",
104 | "\n",
105 | "c = -(pf_value_u-(S0*delta))\n",
106 | "print(c)"
107 | ]
108 | },
109 | {
110 | "cell_type": "markdown",
111 | "metadata": {},
112 | "source": [
113 | "## Generalization of the One-Step Binomial Tree\n",
114 | "\n",
115 | "The following formula allows the pricing of an option using a one-step binomial tree. The value of an option $o$ is defined as\n",
116 | "\n",
117 | "$$ o = e^{-rT}[po_u+(1-p)o_d]$$\n",
118 | "\n",
119 | "where $o_u$ describes the value of the option in case of an upward-movement of the stock and $o_d$ in case of a downward-movement of the stock with the probability of an upward-movement $p$ defined as\n",
120 | "\n",
121 | "$$p=\\frac{e^{rT}-d}{u-d}$$\n",
122 | "\n",
123 | "where $u$ is the upward-moving factor and $d$ is the downward-moving factor, i.e. $u-1$ is the percentage increase in case of an upward-movement and $1-d$ is the percentage decrease in case of an downward-movement.\n",
124 | "\n",
125 | "For a detailed description how the formulas are derived please refer to Hull, *Options, futures, and other derivatives, 8th Edition,* 2012, p. 265.\n",
126 | "\n",
127 | "We now can take the example from before using these formulas."
128 | ]
129 | },
130 | {
131 | "cell_type": "code",
132 | "execution_count": null,
133 | "metadata": {
134 | "ExecuteTime": {
135 | "end_time": "2020-05-03T11:38:27.281245Z",
136 | "start_time": "2020-05-03T11:38:27.268703Z"
137 | }
138 | },
139 | "outputs": [],
140 | "source": [
141 | "S0 = 50\n",
142 | "K = 50\n",
143 | "r = 0.05\n",
144 | "T = 0.5\n",
145 | "u = 1.1\n",
146 | "d = 0.9\n",
147 | "S0_u = S0*u\n",
148 | "S0_d = S0*d\n",
149 | "\n",
150 | "#Call\n",
151 | "o_u = max(S0_u-K,0)\n",
152 | "o_d = max(S0_d-K, 0)\n",
153 | "\n",
154 | "#Put - uncomment the following lines to calculate the value of a put option instead of a call option\n",
155 | "#o_u = max(K-S0_u,0)\n",
156 | "#o_d = max(K-S0_d, 0)\n",
157 | "\n",
158 | "p = (exp(r*T)-d)/(u-d)\n",
159 | "\n",
160 | "o = exp(-r*T)*(p*o_u+(1-p)*o_d)\n",
161 | "print(o)"
162 | ]
163 | },
164 | {
165 | "cell_type": "markdown",
166 | "metadata": {},
167 | "source": [
168 | "## Two-Step Binomial Tree\n",
169 | "\n",
170 | "The analysis of the option value using the one-step binomial tree can be extended to a two-step binomial tree. Hence, let A denote the node at start $S_0$. In the first step, the stock price either moves up by $u$ or down by $d$ to $S_0u$ or $S_0d$ where $S_0u$ is node B and $S_0d$ is node C of the binomial tree. In the second step, the stock price again goes up by $u$ or down by $d$ from each node. Hence from node B, the stock price goes up to $S_0uu$ (node D), or down to $S_0ud$ (node E). From node C, the stock price either goes up to $S_0du$ which equals $S_0ud$ (node E) or down to $S_0dd$ node (F). Hence, we derive the following nodes from the two-step binomial model.\n",
171 | "\n",
172 | "\n",
173 | "$A = S_0$,\n",
174 | "$B = S_0u$,\n",
175 | "$C = S_0d$,\n",
176 | "$D = S_0uu$,\n",
177 | "$E = S_0ud/S_0du$,\n",
178 | "$F = S_0dd$.\n",
179 | "\n",
180 | "In order to determine the option price today, we need to go backwards starting at the nodes at maturity to determine the option prices at the previous nodes. Therefore, we need the stock prices at each node A to F which are given as \n",
181 | "\n",
182 | "$A = 50.00$,\n",
183 | "$B = 55.00$,\n",
184 | "$C = 45.00$,\n",
185 | "$D = 60.50$,\n",
186 | "$E = 49.50$,\n",
187 | "$F = 40.50$.\n",
188 | "\n",
189 | "Hence, at nodes D to F the option price is either $max(S_T-K, 0)$ in case of call option or $max(K-S_T, 0)$ in case of a put option. This leads to the following option values at the terminal nodes D to F in case of a call option:\n",
190 | "\n",
191 | "$o_D = 10.50$,\n",
192 | "$o_E = 0.00$,\n",
193 | "$o_F = 0.00$.\n",
194 | "\n",
195 | "Having calculated the payoffs at maturity, we can determine the option values at nodes B and C. The values are calculated using the formula given in section 1.3 as \n",
196 | "\n",
197 | "$$o = e^{-rT}[po_u+(1-p)o_d].$$\n",
198 | "\n",
199 | "The probability of an upward-movement $p$ is defined as shown in section 1.2 as \n",
200 | "\n",
201 | "$$p=\\frac{e^{rT}-d}{u-d}$$ which is approximately 0.63.\n",
202 | "\n",
203 | "Using this probability of an upward movement, the option value at node B is $o_B=e^{-0.05\\cdot{0.5}}[0.63\\cdot{10.50}+(1-0.63)\\cdot{0}]=6.42$ and the option value at node C is $o_C=e^{-0.05\\cdot{0.5}}[0.63\\cdot{0}+(1-0.63)\\cdot{0}]=0$.\n",
204 | "\n",
205 | "$o_B = 6.42$,\n",
206 | "$o_C = 0.00$.\n",
207 | "\n",
208 | "The same can be done for the last node A which is $o_A=e^{-0.05\\cdot{0.5}}[0.63\\cdot{6.42}+(1-0.63)\\cdot{0}]=3.92$.\n",
209 | "\n",
210 | "Hence, the option value today at node A is 3.92.\n",
211 | "\n",
212 | "The procedure for deriving the option value can be reproduced using the following code cell."
213 | ]
214 | },
215 | {
216 | "cell_type": "code",
217 | "execution_count": null,
218 | "metadata": {
219 | "ExecuteTime": {
220 | "end_time": "2020-05-03T11:38:27.302917Z",
221 | "start_time": "2020-05-03T11:38:27.284395Z"
222 | }
223 | },
224 | "outputs": [],
225 | "source": [
226 | "S0 = 50\n",
227 | "K = 50\n",
228 | "r = 0.05\n",
229 | "T = 0.5\n",
230 | "u = 1.1\n",
231 | "d = 0.9\n",
232 | "\n",
233 | "S0_u = S0*u\n",
234 | "S0_d = S0*d\n",
235 | "\n",
236 | "S0_uu = S0*u**2\n",
237 | "S0_ud = S0*u*d #Equals S0_du == S0*d*u\n",
238 | "S0_dd = S0*d**2\n",
239 | "\n",
240 | "p = (exp(r*T)-d)/(u-d)\n",
241 | "\n",
242 | "\n",
243 | "o_F = max(S0_dd-K, 0) #In the case of a put option this needs to be max(K-S0_dd, 0)\n",
244 | "o_E = max(S0_ud-K, 0)\n",
245 | "o_D = max(S0_uu-K, 0)\n",
246 | "\n",
247 | "o_C = exp(-r*T)*(o_E*p+o_F*(1-p))\n",
248 | "o_B = exp(-r*T)*(o_D*p+o_E*(1-p))\n",
249 | "\n",
250 | "o_A = exp(-r*T)*(o_B*p+o_C*(1-p))\n",
251 | "\n",
252 | "print('Value of the call option = ',o_A)"
253 | ]
254 | },
255 | {
256 | "cell_type": "markdown",
257 | "metadata": {},
258 | "source": [
259 | "## Generalization of the Two-Step Binomial Tree\n",
260 | "\n",
261 | "The formula for the two-step binomial tree can be generalized as follows: Let $r$ denote the risk-free interest rate and $\\Delta{t}$ denote the length of a time step. The probability of an upward movement is $p$ and the option value is $o$ (e.g. the option value after an upward movement is $o_u$). The option value at each time step $\\Delta{t}$ is defined as\n",
262 | "\n",
263 | "$$o = e^{-r\\Delta{t}}[po_u+(1-p)o_d]$$\n",
264 | "with\n",
265 | "$$p=\\frac{e^{r\\Delta{t}}-d}{u-d}$$\n",
266 | "\n",
267 | "Repeating this step for the relevant nodes gives\n",
268 | "\n",
269 | "\\begin{align}\n",
270 | "o_u &= e^{-r\\Delta{t}}[po_uu+(1-p)o_ud] \\\\\n",
271 | "\\\\\n",
272 | "o_d &= e^{-r\\Delta{t}}[po_ud+(1-p)o_dd] \\\\\n",
273 | "\\\\\n",
274 | "o &= e^{-r\\Delta{t}}[po_u+(1-p)o_d] \\\\\n",
275 | "\\end{align}\n",
276 | "\n",
277 | "which can be summarized to \n",
278 | "\n",
279 | "$$o = e^{-2r\\Delta{t}}[p^2o_{uu}+2p(1-p)o_{ud}+(1-p^2)o_{dd}].$$"
280 | ]
281 | },
282 | {
283 | "cell_type": "markdown",
284 | "metadata": {},
285 | "source": [
286 | "## Application of Binomial Trees in Option Pricing\n",
287 | "\n",
288 | "The most commonly application of binomial trees in option pricing is the case of American options. In contrast to European options, American options can be exercised at any time before expiry, and this give the holder of the option more rights than in the case of an European option. The valuation of American options using binomial trees is explained in the [American Plain Vanilla Option](american_plain_vanilla_option.ipynb) notebook."
289 | ]
290 | },
291 | {
292 | "cell_type": "markdown",
293 | "metadata": {},
294 | "source": [
295 | "---"
296 | ]
297 | }
298 | ],
299 | "metadata": {
300 | "kernelspec": {
301 | "display_name": "Python 3",
302 | "language": "python",
303 | "name": "python3"
304 | },
305 | "language_info": {
306 | "codemirror_mode": {
307 | "name": "ipython",
308 | "version": 3
309 | },
310 | "file_extension": ".py",
311 | "mimetype": "text/x-python",
312 | "name": "python",
313 | "nbconvert_exporter": "python",
314 | "pygments_lexer": "ipython3",
315 | "version": "3.7.4"
316 | },
317 | "toc": {
318 | "base_numbering": 1,
319 | "nav_menu": {},
320 | "number_sections": true,
321 | "sideBar": true,
322 | "skip_h1_title": true,
323 | "title_cell": "Table of Contents",
324 | "title_sidebar": "Contents",
325 | "toc_cell": false,
326 | "toc_position": {},
327 | "toc_section_display": true,
328 | "toc_window_display": true
329 | },
330 | "varInspector": {
331 | "cols": {
332 | "lenName": 16,
333 | "lenType": 16,
334 | "lenVar": 40
335 | },
336 | "kernels_config": {
337 | "python": {
338 | "delete_cmd_postfix": "",
339 | "delete_cmd_prefix": "del ",
340 | "library": "var_list.py",
341 | "varRefreshCmd": "print(var_dic_list())"
342 | },
343 | "r": {
344 | "delete_cmd_postfix": ") ",
345 | "delete_cmd_prefix": "rm(",
346 | "library": "var_list.r",
347 | "varRefreshCmd": "cat(var_dic_list()) "
348 | }
349 | },
350 | "types_to_exclude": [
351 | "module",
352 | "function",
353 | "builtin_function_or_method",
354 | "instance",
355 | "_Feature"
356 | ],
357 | "window_display": false
358 | }
359 | },
360 | "nbformat": 4,
361 | "nbformat_minor": 2
362 | }
363 |
--------------------------------------------------------------------------------
/instruments/dop.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | ""
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Down-And-Out Put"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": null,
20 | "metadata": {
21 | "ExecuteTime": {
22 | "end_time": "2020-05-01T09:44:36.919004Z",
23 | "start_time": "2020-05-01T09:44:33.150987Z"
24 | }
25 | },
26 | "outputs": [],
27 | "source": [
28 | "import pyvacon.analytics as analytics\n",
29 | "import datetime as dt\n",
30 | "import pyvacon.tools.converter as converter\n",
31 | "import pyvacon.tools.enums as enums\n",
32 | "import pyvacon.marketdata.testdata as mkt_testdata\n",
33 | "import pyvacon.instruments.testdata as ins_testdata\n",
34 | "import math\n",
35 | "import pandas as pd\n",
36 | "from scipy.stats import norm\n",
37 | "import pyvacon.marketdata.plot as mkt_plot #import module for plotting functionality\n",
38 | "#the next lin is a jupyter internal command to show the matplotlib graphs within the notebook\n",
39 | "%matplotlib inline\n",
40 | "# alternative library for plots (offline version)"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "## Definition of a Down-And-Out Put\n",
48 | "\n",
49 | "\n",
50 | "A down-and-out put belongs to the class of barrier options. It is a put option that ceases to exist if the underlying's spot prices reaches a barrier which is less that the current asset price.\n",
51 | "\n",
52 | "## Down-And-Out Put Pricing Formulas\n",
53 | "\n",
54 | "\n",
55 | "The value of a down-and-out put in the case of a barrier which es less than the strike price can be calculated subtracting the price of a down-and-in put from a plain vanilla put. In the case of a barrier which is greater than or equal to the strike price, the price of the down-and-out put is by definition zero. Because the value of a down-and-in put with a barrier greater or equal than the strike equals the value of a plain vanilla put option, the formula proves this finding.\n",
56 | "\n",
57 | "$$p_{do} = p - p_{di}$$ \n",
58 | "\n",
59 | "The price of a down-and-in put $p_{di}$ is defined as:\n",
60 | "\n",
61 | "$$p_{di}=-S_0N(-x_1)e^{-qT}+Ke^{-rT}N(-x_1+\\sigma\\sqrt{T})+S_0e^{-qT}(H/S_0)^{2\\lambda}[N(y)-N(y_1)]-Ke^{-rT}(H/S_0)^{2\\lambda-2}[N(y-\\sigma\\sqrt{T})-N(y_1-\\sigma\\sqrt{T})]$$\n",
62 | "\n",
63 | "with $S_0$ as the underlying asset's spot price, $K$ as the option's strike price, $H$ as the option's barrier, $N(x)$ as the cumulative probability distribution function for a standardized normal distribution, $r$ as the risk-free interest rate, $q$ as the borrowing rate, $\\sigma$ as the underlying's volatility and $T$ as the option's maturity as year fraction\n",
64 | "\n",
65 | "where \n",
66 | "\n",
67 | "\\begin{align}\n",
68 | "\\lambda &=\\frac{r-q+\\sigma^2/2}{\\sigma^2} \\\\\n",
69 | "\\\\\n",
70 | "y &=\\frac{\\ln[H^2/(S_0K)]}{\\sigma\\sqrt{T}}+\\lambda\\sigma\\sqrt{T} \\\\\n",
71 | "\\\\\n",
72 | "x_1 &=\\frac{\\ln(S_0/H)}{\\sigma\\sqrt{T}}+\\lambda\\sigma\\sqrt{T} \\\\\n",
73 | "\\\\\n",
74 | "y_1 &=\\frac{\\ln(H/S_0)}{\\sigma\\sqrt{T}}+\\lambda\\sigma\\sqrt{T} \\\\\n",
75 | "\\end{align}\n",
76 | "\n",
77 | "The following code defines the formula to value an down-and-out put."
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "execution_count": null,
83 | "metadata": {
84 | "ExecuteTime": {
85 | "end_time": "2020-05-01T09:44:36.942472Z",
86 | "start_time": "2020-05-01T09:44:36.921527Z"
87 | }
88 | },
89 | "outputs": [],
90 | "source": [
91 | "def dopPricer(S0, K, H, r, sigma, T, q=0, t=0):\n",
92 | " _lambda = (r-q+sigma**2/2)/sigma**2\n",
93 | " y = (math.log(H**2/(S0*K)))/(sigma*math.sqrt(T-t))+_lambda*sigma*math.sqrt(T-t)\n",
94 | " x1 = (math.log(S0/H))/(sigma*math.sqrt(T-t))+_lambda*sigma*math.sqrt(T-t)\n",
95 | " y1 = (math.log(H/S0))/(sigma*math.sqrt(T-t))+_lambda*sigma*math.sqrt(T-t)\n",
96 | " pdi = -S0*norm.cdf(-x1)*math.exp(-q*(T-t))+K*math.exp(-r*(T-t))*norm.cdf(-x1+sigma*math.sqrt(T-t))+S0*math.exp(-q*(T-t))*(H/S0)**(2*_lambda)*(norm.cdf(y)-norm.cdf(y1))-K*math.exp(-r*(T-t))*(H/S0)**(2*_lambda-2)*(norm.cdf(y-sigma*math.sqrt(T-t))-norm.cdf(y1-sigma*math.sqrt(T-t)))\n",
97 | " d1= (math.log(S0/K)+(r+sigma**2/2)*(T-t))/(sigma*math.sqrt(T-t))\n",
98 | " d2 = d1-sigma*math.sqrt(T-t)\n",
99 | " p = -1*(S0*norm.cdf(-1*d1)-K*math.exp(-r*(T-t))*norm.cdf(-1*d2))\n",
100 | " pdo = p - pdi\n",
101 | " if H>=K:\n",
102 | " return 0\n",
103 | " if HH:\n",
104 | " return pdo\n",
105 | " if H\n",
37 | "\n",
38 | "# Product Overview\n",
39 | "\n",
40 | "## Equity\n",
41 | "- European Plain Vanilla Option [here](instruments/european_plain_vanilla_option.ipynb)\n",
42 | "- Binomial Trees [here](instruments/binomial_trees.ipynb)\n",
43 | "- American Plain Vanilla Option [here](instruments/american_plain_vanilla_option.ipynb)\n",
44 | "- Barrier Options [here](instruments/barrier_options.ipynb)\n",
45 | "- Down-and-Out Put [here](instruments/dop.ipynb)\n",
46 | "- Asian Options [here](instruments/asian_option.ipynb)\n",
47 | "- Asian on Risk Control [here](instruments/asian_on_riskcontrol.ipynb)\n",
48 | "- Multi-Memory-Express (Equity-Rainbows) [here](instruments/multi_memory_express.ipynb) notebook shows a presentation of the library functionality w.r.t. a Multi-Memory-Express. It shows how to fill the specification, choose a model, compute expected exposures for Rainbow products.\n",
49 | "\n",
50 | "## Fixed Income\n",
51 | "- Interest Rate Swap [here](instruments/ir_swap.ipynb)\n",
52 | "- Swaptions [here](to be done)\n",
53 | "- Caps and Floors [here](to be done)\n",
54 | "\n",
55 | "\n",
56 | "## Bonds\n",
57 | "- Plain Vanilla Fixed Coupon Bonds [here](instruments/bond.ipynb)\n",
58 | "- Plain Vanilla Floating Coupon Bonds [here](instruments/bond.ipynb)\n",
59 | "- Plain Vanilla Fixed-to-Float [here](instruments/bond.ipynb)\n",
60 | "- Inflation Linked Bond [here](instruments/bond.ipynb)"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {},
66 | "source": [
67 | "# Current Version"
68 | ]
69 | },
70 | {
71 | "cell_type": "code",
72 | "execution_count": null,
73 | "metadata": {
74 | "ExecuteTime": {
75 | "end_time": "2020-05-01T09:33:31.015422Z",
76 | "start_time": "2020-05-01T09:33:28.954840Z"
77 | }
78 | },
79 | "outputs": [],
80 | "source": [
81 | "import pyvacon.analytics as analytics\n",
82 | "print(analytics.getVersionInfo())"
83 | ]
84 | },
85 | {
86 | "cell_type": "markdown",
87 | "metadata": {},
88 | "source": [
89 | "---"
90 | ]
91 | }
92 | ],
93 | "metadata": {
94 | "kernelspec": {
95 | "display_name": "Python 3",
96 | "language": "python",
97 | "name": "python3"
98 | },
99 | "language_info": {
100 | "codemirror_mode": {
101 | "name": "ipython",
102 | "version": 3
103 | },
104 | "file_extension": ".py",
105 | "mimetype": "text/x-python",
106 | "name": "python",
107 | "nbconvert_exporter": "python",
108 | "pygments_lexer": "ipython3",
109 | "version": "3.7.4"
110 | },
111 | "toc": {
112 | "base_numbering": 1,
113 | "nav_menu": {
114 | "height": "136px",
115 | "width": "252px"
116 | },
117 | "number_sections": true,
118 | "sideBar": true,
119 | "skip_h1_title": false,
120 | "title_cell": "Table of Contents",
121 | "title_sidebar": "Contents",
122 | "toc_cell": false,
123 | "toc_position": {},
124 | "toc_section_display": "block",
125 | "toc_window_display": true
126 | },
127 | "varInspector": {
128 | "cols": {
129 | "lenName": 16,
130 | "lenType": 16,
131 | "lenVar": 40
132 | },
133 | "kernels_config": {
134 | "python": {
135 | "delete_cmd_postfix": "",
136 | "delete_cmd_prefix": "del ",
137 | "library": "var_list.py",
138 | "varRefreshCmd": "print(var_dic_list())"
139 | },
140 | "r": {
141 | "delete_cmd_postfix": ") ",
142 | "delete_cmd_prefix": "rm(",
143 | "library": "var_list.r",
144 | "varRefreshCmd": "cat(var_dic_list()) "
145 | }
146 | },
147 | "types_to_exclude": [
148 | "module",
149 | "function",
150 | "builtin_function_or_method",
151 | "instance",
152 | "_Feature"
153 | ],
154 | "window_display": false
155 | }
156 | },
157 | "nbformat": 4,
158 | "nbformat_minor": 2
159 | }
160 |
--------------------------------------------------------------------------------
/postBuild:
--------------------------------------------------------------------------------
1 | jupyter contrib nbextension install --user
2 | jupyter nbextension enable --py widgetsnbextension
3 |
--------------------------------------------------------------------------------
/tests.py:
--------------------------------------------------------------------------------
1 | import os
2 | import unittest
3 | import subprocess
4 | import nbformat
5 |
6 |
7 | class NotebookTestsMeta(type):
8 |
9 | @staticmethod
10 | def get_notebooks():
11 | result = []
12 | for r, d, f in os.walk('.'):
13 | if '.git' in d:
14 | continue
15 | for file in f:
16 | if '.ipynb' in file and not '-checkpoint' in file:
17 | test_name = str.replace(str.replace(str.replace(str(os.path.join(r, file)),'.ipynb',''),'.',''),'\\','_')
18 | result.append( (os.path.join(r, file), test_name,))
19 | return result
20 |
21 | def __new__(cls, name, bases, attrs):
22 | notebooks = NotebookTestsMeta.get_notebooks()
23 | for x in notebooks:
24 | attrs['test_%s' % x[1]] = cls.gen(x[0])
25 | return super(NotebookTestsMeta, cls).__new__(cls, name, bases, attrs)
26 |
27 | @staticmethod
28 | def _notebook_run(path):
29 | """Execute a notebook via nbconvert and collect output.
30 | :returns (parsed nb object, execution errors)
31 | """
32 | dirname, nb_name = os.path.split(path)
33 | curr_dir = os.getcwd()
34 | os.chdir(dirname)
35 | args = ["jupyter", "nbconvert", "--to", "notebook", "--execute",
36 | "--ExecutePreprocessor.timeout=600",
37 | "--output", 'tmp.ipynb', nb_name] # fout.name, path]
38 | FNULL = open(os.devnull, 'w')
39 | try:
40 | subprocess.check_call(args, stdout=FNULL, stderr=subprocess.STDOUT)
41 | except:
42 | os.chdir(curr_dir)
43 | return ['An error occured converting notebook with nbconvert']
44 | f = open('tmp.ipynb', 'r')
45 | nb = nbformat.read(f, nbformat.current_nbformat)
46 | errors = [output for cell in nb.cells if "outputs" in cell
47 | for output in cell["outputs"]
48 | if output.output_type == "error"]
49 | f.close()
50 | os.remove('tmp.ipynb')
51 | os.chdir(curr_dir)
52 | return errors
53 |
54 | @classmethod
55 | def gen(cls, notebook_file):
56 | # Return a testcase that tests ``x``.
57 | def fn(self):
58 | errors = NotebookTestsMeta._notebook_run(notebook_file)
59 | self.assertTrue(errors == [])
60 | return fn
61 |
62 |
63 |
64 | class NotebookTests(unittest.TestCase, metaclass = NotebookTestsMeta):
65 |
66 | def test_depp(self):
67 | self.assertEqual(0,0)
68 |
69 | if __name__ == '__main__':
70 | unittest.main()
71 |
--------------------------------------------------------------------------------