Initial commit

This commit is contained in:
Thomas Rijpstra 2025-03-05 19:37:27 +01:00
commit 909846e3ac
Signed by: thomas
SSH Key Fingerprint: SHA256:au5M4TrfxCxk778HDa1d+VB33vzyetoOvL8zrsDkJt0
11 changed files with 1752 additions and 0 deletions

174
.gitignore vendored Normal file
View File

@ -0,0 +1,174 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc

File diff suppressed because it is too large Load Diff

2
pyproject.toml Normal file
View File

@ -0,0 +1,2 @@
[tool.ruff]
line-length = 100

4
pytest.ini Normal file
View File

@ -0,0 +1,4 @@
[pytest]
pythonpath = .
testpaths = src
python_files = *_test.py

0
src/__init__.py Normal file
View File

35
src/assignment.ipynb Normal file
View File

@ -0,0 +1,35 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "initial_id",
"metadata": {
"collapsed": true
},
"outputs": [],
"source": "import options"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

261
src/data/var_fx_prices.csv Normal file
View File

@ -0,0 +1,261 @@
date,ccy-1,ccy-2
14-11-2019,1.1684427,0.886564121
13-11-2019,1.165976797,0.884329678
12-11-2019,1.16603118,0.883470271
11-11-2019,1.166901992,0.87753938
8-11-2019,1.160725686,0.877658927
7-11-2019,1.160712213,0.876270592
6-11-2019,1.162466288,0.877654906
5-11-2019,1.162020521,0.876693114
4-11-2019,1.158050769,0.881600987
1-11-2019,1.159084323,0.881911985
31-10-2019,1.160995205,0.885700368
30-10-2019,1.156992283,0.886839305
29-10-2019,1.160671797,0.878271562
28-10-2019,1.159164938,0.879816998
25-10-2019,1.157420803,0.881290209
24-10-2019,1.157126161,0.880902044
23-10-2019,1.158761979,0.88163985
22-10-2019,1.15928588,0.878464444
21-10-2019,1.164903779,0.87788605
18-10-2019,1.157889862,0.879198171
17-10-2019,1.155081202,0.883197174
16-10-2019,1.158426394,0.879700902
15-10-2019,1.157836236,0.881329044
14-10-2019,1.141630705,0.885151582
11-10-2019,1.148791471,0.88210647
10-10-2019,1.115299681,0.879971841
9-10-2019,1.112743134,0.875465091
8-10-2019,1.114876918,0.876001927
7-10-2019,1.12083749,0.876270592
4-10-2019,1.119870991,0.876193814
3-10-2019,1.129318231,0.876616261
2-10-2019,1.124062813,0.876923751
1-10-2019,1.119733056,0.874431619
30-9-2019,1.128935752,0.873667657
27-9-2019,1.124492573,0.880824452
26-9-2019,1.12731946,0.877654906
25-9-2019,1.129496809,0.876424189
24-9-2019,1.130867236,0.872600349
23-9-2019,1.133758437,0.873896705
20-9-2019,1.135151089,0.868809731
19-9-2019,1.129484052,0.867829558
18-9-2019,1.128579006,0.871269876
17-9-2019,1.129905201,0.872105699
16-9-2019,1.129292724,0.874087671
13-9-2019,1.124151266,0.87753938
12-9-2019,1.123458883,0.878734622
11-9-2019,1.122258883,0.87966221
10-9-2019,1.118918677,0.879894413
9-9-2019,1.116220922,0.88051422
6-9-2019,1.11477749,0.878811846
5-9-2019,1.116245842,0.880630531
4-9-2019,1.105534305,0.877308418
3-9-2019,1.103046615,0.874469853
2-9-2019,1.099601944,0.87507623
30-8-2019,1.103022281,0.875273523
29-8-2019,1.10282765,0.87001914
28-8-2019,1.103387399,0.871991629
27-8-2019,1.010123245,0.874928912
26-8-2019,1.099747058,0.876501008
23-8-2019,1.104899123,0.878889084
22-8-2019,1.105546527,0.880630531
21-8-2019,1.093469798,0.882768362
20-8-2019,1.094235567,0.886839305
19-8-2019,1.093637219,0.884955752
16-8-2019,1.093744873,0.886014265
15-8-2019,1.090655266,0.886839305
14-8-2019,1.082508822,0.887941751
13-8-2019,1.078865034,0.884564352
12-8-2019,1.077156737,0.882339966
9-8-2019,1.07820199,0.881057269
8-8-2019,1.083247576,0.881290209
7-8-2019,1.083505791,0.881911985
6-8-2019,1.087961704,0.881367883
5-8-2019,1.085422772,0.88028169
2-8-2019,1.091381361,0.878618811
1-8-2019,1.098490674,0.876232202
31-7-2019,1.096234287,0.878194432
30-7-2019,1.090905124,0.883119177
29-7-2019,1.098719991,0.884603476
26-7-2019,1.113337787,0.883587365
25-7-2019,1.119670369,0.890194507
24-7-2019,1.121642084,0.890234132
23-7-2019,1.11564808,0.890947969
22-7-2019,1.113647753,0.88691796
19-7-2019,1.114243373,0.884173298
18-7-2019,1.112978442,0.884642604
17-7-2019,1.107162232,0.883002208
16-7-2019,1.106304831,0.882028666
15-7-2019,1.111296327,0.881406725
12-7-2019,1.116196004,0.880902044
11-7-2019,1.114293037,0.88028169
10-7-2019,1.1105805,0.886367665
9-7-2019,1.112433671,0.883197174
8-7-2019,1.115672974,0.886485528
5-7-2019,1.114504157,0.888967908
4-7-2019,1.114789918,0.88999644
3-7-2019,1.113635351,0.890323
2-7-2019,1.115038525,0.891067053
1-7-2019,1.117006423,0.893535272
28-6-2019,1.114050958,0.890511599
27-6-2019,1.115050958,0.891583452
26-6-2019,1.114541422,0.89098766
25-6-2019,1.117355889,0.887981175
24-6-2019,1.117218573,0.88711466
21-6-2019,1.121453404,0.888809884
20-6-2019,1.124985938,0.88711466
19-6-2019,1.126164172,0.883821645
18-6-2019,1.120925436,0.884407889
17-6-2019,1.118480656,0.884955752
14-6-2019,1.123204277,0.884760009
13-6-2019,1.125365744,0.889363216
12-6-2019,1.124163903,0.889086464
11-6-2019,1.124075448,0.888533475
10-6-2019,1.121239643,0.892299456
7-6-2019,1.125163149,0.892538379
6-6-2019,1.127116161,0.8942312
5-6-2019,1.130467222,0.89512332
4-6-2019,1.12847712,0.89561596
3-6-2019,1.127471982,0.8952134
31-5-2019,1.1281843,0.889600569
30-5-2019,1.131528922,0.894134478
29-5-2019,1.133542661,0.893894699
28-5-2019,1.134404211,0.893255918
27-5-2019,1.132964742,0.893854749
24-5-2019,1.132618274,0.892538379
23-5-2019,1.135976372,0.89047195
22-5-2019,1.134803282,0.889263216
21-5-2019,1.14310536,0.889363216
20-5-2019,1.140706097,0.891901534
17-5-2019,1.14087528,0.892259648
16-5-2019,1.144348065,0.89465444
15-5-2019,1.147802532,0.896137647
14-5-2019,1.152113552,0.89561596
13-5-2019,1.154921119,0.894374385
10-5-2019,1.158842548,0.896619744
9-5-2019,1.159393405,0.896901206
8-5-2019,1.160294715,0.892458724
7-5-2019,1.16638479,0.893575194
6-5-2019,1.169590643,0.894854586
3-5-2019,1.172525385,0.897504936
2-5-2019,1.165324601,0.898714838
1-5-2019,1.163995297,0.897021887
30-4-2019,1.16132379,0.892618049
29-4-2019,1.157407407,0.89031339
26-4-2019,1.57284634,0.887862914
25-4-2019,1.568324628,0.886406949
24-4-2019,1.156590833,0.882067566
23-4-2019,1.154227937,0.883704489
22-4-2019,1.152963693,0.883743538
19-4-2019,1.156122826,0.883431247
18-4-2019,1.156925355,0.887232721
17-4-2019,1.154521105,0.890868597
16-4-2019,1.155214639,0.890789239
15-4-2019,1.159729551,0.894054537
12-4-2019,1.158158065,0.891583452
11-4-2019,1.160739159,0.885778821
10-4-2019,1.163277651,0.883314195
9-4-2019,1.157420803,0.878040214
8-4-2019,1.158721698,0.878425861
5-4-2019,1.159218687,0.879043601
4-4-2019,1.166412,0.879584836
3-4-2019,1.171687347,0.878889084
2-4-2019,1.164225674,0.883041194
1-4-2019,1.170686022,0.885269122
29-3-2019,1.168346532,0.885367665
28-3-2019,1.164646006,0.886367665
27-3-2019,1.172374175,0.891106755
26-3-2019,1.171440286,0.891543708
25-3-2019,1.165555504,0.892379083
22-3-2019,1.171550078,0.888888889
21-3-2019,1.150483203,0.888730892
20-3-2019,1.161737029,0.888691402
19-3-2019,1.169057389,0.887862914
18-3-2019,1.165949608,0.891106755
15-3-2019,1.17249789,0.890828916
14-3-2019,1.174853437,0.891662951
13-3-2019,1.169590643,0.891106755
12-3-2019,1.161642563,0.891027355
11-3-2019,1.166520852,0.896860987
8-3-2019,1.158506916,0.897424392
7-3-2019,1.16780138,0.896097495
6-3-2019,1.162007019,0.898795614
5-3-2019,1.159810255,0.898311175
4-3-2019,1.163372384,0.897786955
1-3-2019,1.16295297,0.90244334
28-2-2019,1.16512094,0.90440445
27-2-2019,1.171508903,0.900738606
26-2-2019,1.165311022,0.894054537
25-2-2019,1.151768541,0.893974611
22-2-2019,1.151330939,0.891662951
21-2-2019,1.151410478,0.89273758
20-2-2019,1.151012891,0.892777431
19-2-2019,1.149729239,0.89146423
18-2-2019,1.143301397,0.893694982
15-2-2019,1.140693085,0.896860987
14-2-2019,1.133118796,0.900252071
13-2-2019,1.14153948,0.900576369
12-2-2019,1.140133852,0.901225667
11-2-2019,1.140914329,0.901794571
8-2-2019,1.142739604,0.901388138
7-2-2019,1.142400183,0.902445628
6-2-2019,1.139211666,0.900009
5-2-2019,1.134198349,0.899806542
4-2-2019,1.144885225,0.901243
1-2-2019,1.14187839,0.902934537
31-1-2019,1.143379831,0.903628067
30-1-2019,1.144112398,0.906043309
29-1-2019,1.148349572,0.911701691
28-1-2019,1.15036409,0.912325518
25-1-2019,1.155374804,0.906618314
24-1-2019,1.148567162,0.905387053
23-1-2019,1.14825064,0.905223138
22-1-2019,1.140797189,0.904486252
21-1-2019,1.134751773,0.905715062
18-1-2019,1.135383078,0.909338911
17-1-2019,1.134134032,0.906700517
16-1-2019,1.128515325,0.902282775
15-1-2019,1.119482351,0.909256228
14-1-2019,1.125707789,0.904977376
11-1-2019,1.117143687,0.90424089
10-1-2019,1.108696616,0.904568069
9-1-2019,1.107125459,0.908265213
8-1-2019,1.112644087,0.90962735
7-1-2019,1.1141813,0.91124248
4-1-2019,1.115026092,0.912575287
3-1-2019,1.106060103,0.913993236
2-1-2019,1.110592834,0.913408842
31-12-2018,1.117156167,0.916674306
28-12-2018,1.109299256,0.916086479
27-12-2018,1.107910481,0.913575735
26-12-2018,1.110975325,0.910332271
24-12-2018,1.114305453,0.910829766
21-12-2018,1.1105805,0.909545682
20-12-2018,1.106831363,0.912825194
19-12-2018,1.10702741,0.910705341
18-12-2018,1.111716379,0.908182726
17-12-2018,1.112334679,0.905879156
14-12-2018,1.111790539,0.907029478
13-12-2018,1.112099644,0.906084356
12-12-2018,1.113833816,0.904813608
11-12-2018,1.106427236,0.899523253
10-12-2018,1.101770545,0.897585495
7-12-2018,1.12027245,0.897182846
6-12-2018,1.123048133,0.898391879
5-12-2018,1.123078133,0.899523253
4-12-2018,1.1212145,0.900414191
3-12-2018,1.122498232,0.901631954
30-11-2018,1.122384843,0.901550667
29-11-2018,1.122120359,0.899604174
28-11-2018,1.130671732,0.899118864
27-11-2018,1.128387985,0.896539358
26-11-2018,1.130965845,0.895255148
23-11-2018,1.128795575,0.896458987
22-11-2018,1.128349788,0.903097625
21-11-2018,1.121730157,0.903056847
20-11-2018,1.123898579,0.912825194
19-11-2018,1.247645328,0.910705341
16-11-2018,1.126722477,0.900414191
15-11-2018,1.129598879,0.905879156
14-11-2018,1.14998045,0.895255148
1 date ccy-1 ccy-2
2 14-11-2019 1.1684427 0.886564121
3 13-11-2019 1.165976797 0.884329678
4 12-11-2019 1.16603118 0.883470271
5 11-11-2019 1.166901992 0.87753938
6 8-11-2019 1.160725686 0.877658927
7 7-11-2019 1.160712213 0.876270592
8 6-11-2019 1.162466288 0.877654906
9 5-11-2019 1.162020521 0.876693114
10 4-11-2019 1.158050769 0.881600987
11 1-11-2019 1.159084323 0.881911985
12 31-10-2019 1.160995205 0.885700368
13 30-10-2019 1.156992283 0.886839305
14 29-10-2019 1.160671797 0.878271562
15 28-10-2019 1.159164938 0.879816998
16 25-10-2019 1.157420803 0.881290209
17 24-10-2019 1.157126161 0.880902044
18 23-10-2019 1.158761979 0.88163985
19 22-10-2019 1.15928588 0.878464444
20 21-10-2019 1.164903779 0.87788605
21 18-10-2019 1.157889862 0.879198171
22 17-10-2019 1.155081202 0.883197174
23 16-10-2019 1.158426394 0.879700902
24 15-10-2019 1.157836236 0.881329044
25 14-10-2019 1.141630705 0.885151582
26 11-10-2019 1.148791471 0.88210647
27 10-10-2019 1.115299681 0.879971841
28 9-10-2019 1.112743134 0.875465091
29 8-10-2019 1.114876918 0.876001927
30 7-10-2019 1.12083749 0.876270592
31 4-10-2019 1.119870991 0.876193814
32 3-10-2019 1.129318231 0.876616261
33 2-10-2019 1.124062813 0.876923751
34 1-10-2019 1.119733056 0.874431619
35 30-9-2019 1.128935752 0.873667657
36 27-9-2019 1.124492573 0.880824452
37 26-9-2019 1.12731946 0.877654906
38 25-9-2019 1.129496809 0.876424189
39 24-9-2019 1.130867236 0.872600349
40 23-9-2019 1.133758437 0.873896705
41 20-9-2019 1.135151089 0.868809731
42 19-9-2019 1.129484052 0.867829558
43 18-9-2019 1.128579006 0.871269876
44 17-9-2019 1.129905201 0.872105699
45 16-9-2019 1.129292724 0.874087671
46 13-9-2019 1.124151266 0.87753938
47 12-9-2019 1.123458883 0.878734622
48 11-9-2019 1.122258883 0.87966221
49 10-9-2019 1.118918677 0.879894413
50 9-9-2019 1.116220922 0.88051422
51 6-9-2019 1.11477749 0.878811846
52 5-9-2019 1.116245842 0.880630531
53 4-9-2019 1.105534305 0.877308418
54 3-9-2019 1.103046615 0.874469853
55 2-9-2019 1.099601944 0.87507623
56 30-8-2019 1.103022281 0.875273523
57 29-8-2019 1.10282765 0.87001914
58 28-8-2019 1.103387399 0.871991629
59 27-8-2019 1.010123245 0.874928912
60 26-8-2019 1.099747058 0.876501008
61 23-8-2019 1.104899123 0.878889084
62 22-8-2019 1.105546527 0.880630531
63 21-8-2019 1.093469798 0.882768362
64 20-8-2019 1.094235567 0.886839305
65 19-8-2019 1.093637219 0.884955752
66 16-8-2019 1.093744873 0.886014265
67 15-8-2019 1.090655266 0.886839305
68 14-8-2019 1.082508822 0.887941751
69 13-8-2019 1.078865034 0.884564352
70 12-8-2019 1.077156737 0.882339966
71 9-8-2019 1.07820199 0.881057269
72 8-8-2019 1.083247576 0.881290209
73 7-8-2019 1.083505791 0.881911985
74 6-8-2019 1.087961704 0.881367883
75 5-8-2019 1.085422772 0.88028169
76 2-8-2019 1.091381361 0.878618811
77 1-8-2019 1.098490674 0.876232202
78 31-7-2019 1.096234287 0.878194432
79 30-7-2019 1.090905124 0.883119177
80 29-7-2019 1.098719991 0.884603476
81 26-7-2019 1.113337787 0.883587365
82 25-7-2019 1.119670369 0.890194507
83 24-7-2019 1.121642084 0.890234132
84 23-7-2019 1.11564808 0.890947969
85 22-7-2019 1.113647753 0.88691796
86 19-7-2019 1.114243373 0.884173298
87 18-7-2019 1.112978442 0.884642604
88 17-7-2019 1.107162232 0.883002208
89 16-7-2019 1.106304831 0.882028666
90 15-7-2019 1.111296327 0.881406725
91 12-7-2019 1.116196004 0.880902044
92 11-7-2019 1.114293037 0.88028169
93 10-7-2019 1.1105805 0.886367665
94 9-7-2019 1.112433671 0.883197174
95 8-7-2019 1.115672974 0.886485528
96 5-7-2019 1.114504157 0.888967908
97 4-7-2019 1.114789918 0.88999644
98 3-7-2019 1.113635351 0.890323
99 2-7-2019 1.115038525 0.891067053
100 1-7-2019 1.117006423 0.893535272
101 28-6-2019 1.114050958 0.890511599
102 27-6-2019 1.115050958 0.891583452
103 26-6-2019 1.114541422 0.89098766
104 25-6-2019 1.117355889 0.887981175
105 24-6-2019 1.117218573 0.88711466
106 21-6-2019 1.121453404 0.888809884
107 20-6-2019 1.124985938 0.88711466
108 19-6-2019 1.126164172 0.883821645
109 18-6-2019 1.120925436 0.884407889
110 17-6-2019 1.118480656 0.884955752
111 14-6-2019 1.123204277 0.884760009
112 13-6-2019 1.125365744 0.889363216
113 12-6-2019 1.124163903 0.889086464
114 11-6-2019 1.124075448 0.888533475
115 10-6-2019 1.121239643 0.892299456
116 7-6-2019 1.125163149 0.892538379
117 6-6-2019 1.127116161 0.8942312
118 5-6-2019 1.130467222 0.89512332
119 4-6-2019 1.12847712 0.89561596
120 3-6-2019 1.127471982 0.8952134
121 31-5-2019 1.1281843 0.889600569
122 30-5-2019 1.131528922 0.894134478
123 29-5-2019 1.133542661 0.893894699
124 28-5-2019 1.134404211 0.893255918
125 27-5-2019 1.132964742 0.893854749
126 24-5-2019 1.132618274 0.892538379
127 23-5-2019 1.135976372 0.89047195
128 22-5-2019 1.134803282 0.889263216
129 21-5-2019 1.14310536 0.889363216
130 20-5-2019 1.140706097 0.891901534
131 17-5-2019 1.14087528 0.892259648
132 16-5-2019 1.144348065 0.89465444
133 15-5-2019 1.147802532 0.896137647
134 14-5-2019 1.152113552 0.89561596
135 13-5-2019 1.154921119 0.894374385
136 10-5-2019 1.158842548 0.896619744
137 9-5-2019 1.159393405 0.896901206
138 8-5-2019 1.160294715 0.892458724
139 7-5-2019 1.16638479 0.893575194
140 6-5-2019 1.169590643 0.894854586
141 3-5-2019 1.172525385 0.897504936
142 2-5-2019 1.165324601 0.898714838
143 1-5-2019 1.163995297 0.897021887
144 30-4-2019 1.16132379 0.892618049
145 29-4-2019 1.157407407 0.89031339
146 26-4-2019 1.57284634 0.887862914
147 25-4-2019 1.568324628 0.886406949
148 24-4-2019 1.156590833 0.882067566
149 23-4-2019 1.154227937 0.883704489
150 22-4-2019 1.152963693 0.883743538
151 19-4-2019 1.156122826 0.883431247
152 18-4-2019 1.156925355 0.887232721
153 17-4-2019 1.154521105 0.890868597
154 16-4-2019 1.155214639 0.890789239
155 15-4-2019 1.159729551 0.894054537
156 12-4-2019 1.158158065 0.891583452
157 11-4-2019 1.160739159 0.885778821
158 10-4-2019 1.163277651 0.883314195
159 9-4-2019 1.157420803 0.878040214
160 8-4-2019 1.158721698 0.878425861
161 5-4-2019 1.159218687 0.879043601
162 4-4-2019 1.166412 0.879584836
163 3-4-2019 1.171687347 0.878889084
164 2-4-2019 1.164225674 0.883041194
165 1-4-2019 1.170686022 0.885269122
166 29-3-2019 1.168346532 0.885367665
167 28-3-2019 1.164646006 0.886367665
168 27-3-2019 1.172374175 0.891106755
169 26-3-2019 1.171440286 0.891543708
170 25-3-2019 1.165555504 0.892379083
171 22-3-2019 1.171550078 0.888888889
172 21-3-2019 1.150483203 0.888730892
173 20-3-2019 1.161737029 0.888691402
174 19-3-2019 1.169057389 0.887862914
175 18-3-2019 1.165949608 0.891106755
176 15-3-2019 1.17249789 0.890828916
177 14-3-2019 1.174853437 0.891662951
178 13-3-2019 1.169590643 0.891106755
179 12-3-2019 1.161642563 0.891027355
180 11-3-2019 1.166520852 0.896860987
181 8-3-2019 1.158506916 0.897424392
182 7-3-2019 1.16780138 0.896097495
183 6-3-2019 1.162007019 0.898795614
184 5-3-2019 1.159810255 0.898311175
185 4-3-2019 1.163372384 0.897786955
186 1-3-2019 1.16295297 0.90244334
187 28-2-2019 1.16512094 0.90440445
188 27-2-2019 1.171508903 0.900738606
189 26-2-2019 1.165311022 0.894054537
190 25-2-2019 1.151768541 0.893974611
191 22-2-2019 1.151330939 0.891662951
192 21-2-2019 1.151410478 0.89273758
193 20-2-2019 1.151012891 0.892777431
194 19-2-2019 1.149729239 0.89146423
195 18-2-2019 1.143301397 0.893694982
196 15-2-2019 1.140693085 0.896860987
197 14-2-2019 1.133118796 0.900252071
198 13-2-2019 1.14153948 0.900576369
199 12-2-2019 1.140133852 0.901225667
200 11-2-2019 1.140914329 0.901794571
201 8-2-2019 1.142739604 0.901388138
202 7-2-2019 1.142400183 0.902445628
203 6-2-2019 1.139211666 0.900009
204 5-2-2019 1.134198349 0.899806542
205 4-2-2019 1.144885225 0.901243
206 1-2-2019 1.14187839 0.902934537
207 31-1-2019 1.143379831 0.903628067
208 30-1-2019 1.144112398 0.906043309
209 29-1-2019 1.148349572 0.911701691
210 28-1-2019 1.15036409 0.912325518
211 25-1-2019 1.155374804 0.906618314
212 24-1-2019 1.148567162 0.905387053
213 23-1-2019 1.14825064 0.905223138
214 22-1-2019 1.140797189 0.904486252
215 21-1-2019 1.134751773 0.905715062
216 18-1-2019 1.135383078 0.909338911
217 17-1-2019 1.134134032 0.906700517
218 16-1-2019 1.128515325 0.902282775
219 15-1-2019 1.119482351 0.909256228
220 14-1-2019 1.125707789 0.904977376
221 11-1-2019 1.117143687 0.90424089
222 10-1-2019 1.108696616 0.904568069
223 9-1-2019 1.107125459 0.908265213
224 8-1-2019 1.112644087 0.90962735
225 7-1-2019 1.1141813 0.91124248
226 4-1-2019 1.115026092 0.912575287
227 3-1-2019 1.106060103 0.913993236
228 2-1-2019 1.110592834 0.913408842
229 31-12-2018 1.117156167 0.916674306
230 28-12-2018 1.109299256 0.916086479
231 27-12-2018 1.107910481 0.913575735
232 26-12-2018 1.110975325 0.910332271
233 24-12-2018 1.114305453 0.910829766
234 21-12-2018 1.1105805 0.909545682
235 20-12-2018 1.106831363 0.912825194
236 19-12-2018 1.10702741 0.910705341
237 18-12-2018 1.111716379 0.908182726
238 17-12-2018 1.112334679 0.905879156
239 14-12-2018 1.111790539 0.907029478
240 13-12-2018 1.112099644 0.906084356
241 12-12-2018 1.113833816 0.904813608
242 11-12-2018 1.106427236 0.899523253
243 10-12-2018 1.101770545 0.897585495
244 7-12-2018 1.12027245 0.897182846
245 6-12-2018 1.123048133 0.898391879
246 5-12-2018 1.123078133 0.899523253
247 4-12-2018 1.1212145 0.900414191
248 3-12-2018 1.122498232 0.901631954
249 30-11-2018 1.122384843 0.901550667
250 29-11-2018 1.122120359 0.899604174
251 28-11-2018 1.130671732 0.899118864
252 27-11-2018 1.128387985 0.896539358
253 26-11-2018 1.130965845 0.895255148
254 23-11-2018 1.128795575 0.896458987
255 22-11-2018 1.128349788 0.903097625
256 21-11-2018 1.121730157 0.903056847
257 20-11-2018 1.123898579 0.912825194
258 19-11-2018 1.247645328 0.910705341
259 16-11-2018 1.126722477 0.900414191
260 15-11-2018 1.129598879 0.905879156
261 14-11-2018 1.14998045 0.895255148

60
src/options.py Normal file
View File

@ -0,0 +1,60 @@
import pandas as pd
import numpy as np
from scipy.stats import norm
def as_df(option):
"""Creates a dataframe holding the option, and calculates time to maturity"""
df = pd.DataFrame([option])
df["T"] = (df["t1"] - df["t0"]) / np.timedelta64(365, "D")
return df
def black_scholes_option_price_spot(S, K, T, r, sigma, option_type="call"):
"""Calculates option price using Black-Scholes formula with spot price assuming zero dividend"""
sigma_scaled = sigma * np.sqrt(T)
d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / sigma_scaled
d2 = d1 - sigma_scaled
if option_type == "call":
return S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
return K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1) # put
def black_scholes_option_price_forward(F, K, T, r, sigma, option_type="call"):
"""Calculates option price using Black-Scholes formula with forward price assuming zero dividend"""
sigma_scaled = sigma * np.sqrt(T)
d1 = (np.log(F / K) + (0.5 * sigma**2) * T) / sigma_scaled
d2 = d1 - sigma_scaled
discount = np.exp(-r * T)
if option_type == "call":
return discount * (F * norm.cdf(d1) - K * norm.cdf(d2))
return discount * (K * norm.cdf(-d2) - F * norm.cdf(-d1)) # put
def forward_price(S, T, r):
"""Calculates the forward price assuming zero dividend"""
return S * np.exp(r * T)
def moneyness(strike_price, current_price, option_type="call", threshold=0.005):
"""Calculates if an option is ITM, ATM, or OTM"""
fuzzy_price = threshold * strike_price
if option_type == "put":
if current_price < strike_price - fuzzy_price:
return "ITM"
if current_price > strike_price + fuzzy_price:
return "OTM"
return "ATM"
if option_type == "call":
if current_price > strike_price + fuzzy_price:
return "ITM"
if current_price < strike_price - fuzzy_price:
return "OTM"
return "ATM"
return ""

114
src/options_test.py Normal file
View File

@ -0,0 +1,114 @@
import pytest
import pandas as pd
from pandas.testing import assert_series_equal
from . import options
# https://analystprep.com/study-notes/actuarial-exams/soa/ifm-investment-and-financial-markets/black-scholes-option-pricing-model/
@pytest.mark.parametrize(
"S, K, T, r, sigma, option_type, expected", [(100, 90, 0.5, 0.10, 0.25, "call", 16.11)]
)
def test_black_scholes_option_price_spot(S, K, T, r, sigma, option_type, expected):
assert (
abs(options.black_scholes_option_price_spot(S, K, T, r, sigma, option_type)) - expected
< 0.05
)
@pytest.mark.parametrize(
"F, K, T, r, sigma, option_type, expected", [(100, 90, 0.5, 0.10, 0.25, "call", 16.11)]
)
def test_black_scholes_option_price_forward(F, K, T, r, sigma, option_type, expected):
assert (
abs(options.black_scholes_option_price_forward(F, K, T, r, sigma, option_type)) - expected
< 0.05
)
@pytest.mark.parametrize(
"current_price, strike_price, option_type, expected",
[
(1, 10, "call", "ITM"),
(10, 1, "call", "OTM"),
(10, 10, "call", "ATM"),
(1, 10, "put", "OTM"),
(10, 1, "put", "ITM"),
(10, 10, "put", "ATM"),
],
)
def test_moneyness(current_price, strike_price, option_type, expected):
assert options.moneyness(current_price, strike_price, option_type) == expected
def test_end_to_end():
option = {
"t0": pd.Timestamp("2024-11-23"),
"t1": pd.Timestamp("2025-05-10"),
"S": 19,
"K": 17,
"r": 0.005,
"sigma": 0.3,
}
options_df = options.as_df(option)
expected = {
"F": 19.04367,
"C_F": 2.70,
"C_S": 2.70,
"P_F": 0.66,
"P_PCP": 0.66,
}
expected_df = pd.DataFrame([expected])
assert_series_equal(
options.forward_price(options_df["S"], options_df["T"], options_df["r"]),
expected_df["F"],
check_names=False,
check_exact=False,
)
assert_series_equal(
options.black_scholes_option_price_spot(
options_df["S"],
options_df["K"],
options_df["T"],
options_df["r"],
options_df["sigma"],
"call",
),
expected_df["C_S"],
rtol=0.01,
check_names=False,
check_exact=False,
)
assert_series_equal(
options.black_scholes_option_price_forward(
options.forward_price(options_df["S"], options_df["T"], options_df["r"]),
options_df["K"],
options_df["T"],
options_df["r"],
options_df["sigma"],
"call",
),
expected_df["C_F"],
rtol=0.01,
check_names=False,
check_exact=False,
)
assert_series_equal(
options.black_scholes_option_price_forward(
options.forward_price(options_df["S"], options_df["T"], options_df["r"]),
options_df["K"],
options_df["T"],
options_df["r"],
options_df["sigma"],
"put",
),
expected_df["P_F"],
rtol=0.01,
check_names=False,
check_exact=False,
)

18
src/var.py Normal file
View File

@ -0,0 +1,18 @@
import numpy as np
def calculate_returns(prices, horizon=1, sort="ascending"):
step = 1 if sort == "ascending" else -1
if horizon == 1:
returns = prices / prices.shift(step) - 1
else:
returns = np.exp(np.log(prices / prices.shift(step)) * np.sqrt(horizon)) - 1
return returns.dropna()
def var(portfolio, prices, horizon=1, sort="ascending"):
returns = calculate_returns(prices, horizon, sort)
pnl = portfolio.dot(returns.T)
daily_pnl = pnl.sum(axis=0)
daily_pnl_asc = daily_pnl.sort_values(ascending=True)
return 0.4 * daily_pnl_asc[1] + 0.6 * daily_pnl_asc[2]

43
src/var_test.py Normal file
View File

@ -0,0 +1,43 @@
import os
import pandas as pd
import pytest
from pandas.testing import assert_series_equal
from . import var
@pytest.mark.parametrize(
"prices, horizon, ascending, expected",
[
(
pd.DataFrame([1, 2, 3, 4, 5]),
1,
"ascending",
pd.Series([1.0, 0.5, 0.33333, 0.25], dtype=float),
)
],
)
def test_calculate_returns(prices, horizon, ascending, expected):
assert_series_equal(
var.calculate_returns(prices, horizon, ascending),
expected,
# rtol=0.01,
# check_names=False,
# check_exact=False,
)
def test_var():
pass
def test_end_to_end():
portfolio = pd.DataFrame([{"ccy-1": 153084.81, "ccy-2": 95891.51}])
fx_prices = pd.read_csv(
os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", "var_fx_prices.csv"),
parse_dates=["date"],
index_col="date",
dtype=float, # All non-date columns as float
)
fx_prices.sort_index(inplace=True, ascending=True)
assert var.var(portfolio, fx_prices) == pytest.approx(-13572.73)