Initial commit
This commit is contained in:
commit
909846e3ac
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[pytest]
|
||||
pythonpath = .
|
||||
testpaths = src
|
||||
python_files = *_test.py
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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]
|
||||
|
|
@ -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)
|
||||
Loading…
Reference in New Issue