Initial commit

This commit is contained in:
Thomas Rijpstra 2025-03-05 19:37:27 +01:00
commit 9767adb7de
Signed by: thomas
SSH Key Fingerprint: SHA256:sFF5HPNPaaW14qykTkmRi1FGGO0YMUPBenlKOqepUpw
13 changed files with 1794 additions and 0 deletions

39
.github/workflows/test.yaml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Test
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
on:
pull_request:
workflow_call:
jobs:
test:
name: run tests
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10" ]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Test with pytest
run: |
coverage run -m pytest -v -s
- name: Generate Coverage Report
run: |
coverage report -m

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

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
numpy==2.2.3
pandas==2.2.3
pytest==8.3.5
scipy==1.15.2

0
src/__init__.py Normal file
View File

30
src/assignment.md Normal file
View File

@ -0,0 +1,30 @@
#%% md
## Answer 1 - Option
* Implied Volatility (IV) provides a prediction of the future, while Historical Volatility (HV) provides an observation of the past.
* IV is derived from option pricing models while HV is calculated directly from historical price data.
* IV provides a subjective measure on future volatility, while HV provides an objective measure of baseline volatility.
## Answer 2 - VaR
Value-at-Risk (VaR) is a measurement of the maximum potential loss in value of a portfolio over a defined period (e.g. 1 day) and for a given confidence interval (e.g. 95%).
There are various methods of calculation that mainly differ in the way they approximate portfolio volatility.
The simplest method (parametric) assumes that portfolio volatility is constant and thus return variability can be approximated using a normal distribution. It requires very little data (only the current portfolio value and a measure of volatility, e.g. annual volatility of the portfolio) and is easily computed but has practical limitations due to its assumptions.
A more complex method is the Peaks Over Threshold (POT) method. This method requires more data, specifically containing sufficient extreme events, as it uses historical excesses in portfolio returns to extrapolate risk beyond historical observations.
In other words, it estimates the chance of future excesses in returns.
This estimation is dependent on the method's parameters, so stress testing is needed make sure the parameters are aptly chosen.
Because VaR is used in risk management, and specifically to reduce portfolio risk if it's deemed to large, a method that specifically models extreme events (i.e. "tail focus") is preferable.
## Answer 3 - Option
Refer to `options.py` for the implementation and `options_test.py` for both unit- and end-to-end tests.
## Answer 4 - VaR
Refer to `var.py` for the implementation and `var_test.py` for both unit- and end-to-end tests.
#%%

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
Internal Server Error - Forgejo: Beyond coding. We Forge.

Internal Server Error

Forgejo Version: 1.21.5+0