sdevpy 1.0.6__tar.gz → 1.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sdevpy-1.0.6 → sdevpy-1.0.7}/PKG-INFO +7 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/pyproject.toml +14 -6
- sdevpy-1.0.7/sdevpy/__init__.py +21 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/americantree.py +3 -3
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/bachelier.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/black.py +4 -4
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/fbsabr.py +86 -88
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/mcheston.py +76 -80
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/mcsabr.py +92 -95
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/mczabr.py +79 -82
- sdevpy-1.0.7/sdevpy/cointegration/back_testing.py +224 -0
- sdevpy-1.0.7/sdevpy/cointegration/coint_trading.py +677 -0
- sdevpy-1.0.7/sdevpy/cointegration/data_io.py +14 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/cointegration/mean_reversion.py +117 -128
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/cointegration/model_settings.py +6 -5
- sdevpy-1.0.7/sdevpy/cointegration/utils.py +132 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/machinelearning/datasets.py +11 -8
- {sdevpy-1.0.6/sdevpy/machinelearning → sdevpy-1.0.7/sdevpy/machinelearning/keras}/callbacks.py +1 -3
- {sdevpy-1.0.6/sdevpy/machinelearning → sdevpy-1.0.7/sdevpy/machinelearning/keras}/learningmodel.py +6 -4
- {sdevpy-1.0.6/sdevpy/machinelearning → sdevpy-1.0.7/sdevpy/machinelearning/keras}/learningschedules.py +1 -3
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/attention.py +3 -5
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/chat.py +2 -2
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/datasets.py +0 -1
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/gpt.py +7 -6
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/instructions.py +8 -8
- sdevpy-1.0.6/sdevpy/llms/ModelConverter.py → sdevpy-1.0.7/sdevpy/machinelearning/llms/modelconverter.py +3 -5
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/training.py +2 -1
- sdevpy-1.0.7/sdevpy/market/correlations.py +76 -0
- sdevpy-1.0.7/sdevpy/market/eqforward.py +197 -0
- sdevpy-1.0.7/sdevpy/market/eqvolsurface.py +155 -0
- sdevpy-1.0.7/sdevpy/market/fixings.py +181 -0
- sdevpy-1.0.7/sdevpy/market/spot.py +81 -0
- sdevpy-1.0.7/sdevpy/market/yieldcurve.py +246 -0
- sdevpy-1.0.7/sdevpy/maths/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/maths/constants.py +28 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/interpolation.py +73 -35
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/optimization.py +30 -27
- sdevpy-1.0.7/sdevpy/maths/rand/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/maths/rand/correlations.py +44 -0
- sdevpy-1.0.7/sdevpy/maths/rand/pathconstruction.py +180 -0
- sdevpy-1.0.7/sdevpy/maths/rand/rng.py +148 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/regression.py +1 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/specialfunctions.py +1 -0
- sdevpy-1.0.7/sdevpy/models/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/models/assetmodels.py +90 -0
- sdevpy-1.0.7/sdevpy/models/multiasset_heston.py +37 -0
- sdevpy-1.0.7/sdevpy/montecarlo/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/montecarlo/mcpricer.py +188 -0
- sdevpy-1.0.7/sdevpy/montecarlo/mcrun.py +102 -0
- sdevpy-1.0.7/sdevpy/montecarlo/pathgenerator.py +31 -0
- sdevpy-1.0.7/sdevpy/montecarlo/payoffs/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/montecarlo/payoffs/basic.py +669 -0
- sdevpy-1.0.7/sdevpy/montecarlo/payoffs/cashflows.py +32 -0
- sdevpy-1.0.7/sdevpy/montecarlo/payoffs/exotics.py +96 -0
- sdevpy-1.0.7/sdevpy/montecarlo/payoffs/vanillas.py +76 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/montecarlo/smoothers.py +1 -9
- sdevpy-1.0.7/sdevpy/pde/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/pde/forwardpde.py +16 -19
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/pde/pdeschemes.py +1 -4
- sdevpy-1.0.7/sdevpy/projects/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/projects/aad/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/aad/aad_mc_nd.py +3 -3
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/chat_gpt2.py +3 -3
- sdevpy-1.0.7/sdevpy/projects/raschka/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/ch2_working_with_text.py +3 -3
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/ch3_coding_attention.py +3 -3
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/ch4_gpt_model.py +3 -3
- sdevpy-1.0.6/sdevpy/projects/raschka/ch5_loadGPT2.py → sdevpy-1.0.7/sdevpy/projects/raschka/ch5_loadgpt2.py +2 -2
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/ch5_pretraining.py +7 -7
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/ch7_instruction_finetuning.py +2 -2
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/raschka_datasetloader.py +2 -2
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/raschka_dnn.py +1 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/raschka/raschka_gpt_download.py +1 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/set_limits.py +5 -6
- sdevpy-1.0.7/sdevpy/projects/stovol/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/stovol/stovolplot.py +1 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/stovol/stovoltrain.py +0 -1
- sdevpy-1.0.7/sdevpy/projects/stovolinverse/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/stovolinverse/stovolinvtrain.py +5 -5
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/update_db.py +3 -3
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/settings.py +7 -6
- sdevpy-1.0.7/sdevpy/tensorflow/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tensorflow/tf_black.py +4 -4
- sdevpy-1.0.7/sdevpy/tests/test.py +82 -0
- sdevpy-1.0.7/sdevpy/tests/test_algos.py +125 -0
- sdevpy-1.0.7/sdevpy/tests/test_dates.py +58 -0
- sdevpy-1.0.7/sdevpy/tests/test_impliedvol.py +100 -0
- sdevpy-1.0.7/sdevpy/tests/test_interpolation.py +55 -0
- sdevpy-1.0.7/sdevpy/tests/test_localvol.py +0 -0
- sdevpy-1.0.7/sdevpy/tests/test_marketdata.py +48 -0
- sdevpy-1.0.7/sdevpy/tests/test_mc.py +85 -0
- sdevpy-1.0.7/sdevpy/tests/test_pde.py +116 -0
- sdevpy-1.0.7/sdevpy/tests/test_timegrids.py +49 -0
- sdevpy-1.0.7/sdevpy/tests/test_utils.py +67 -0
- sdevpy-1.0.7/sdevpy/tests/test_yieldcurves.py +49 -0
- sdevpy-1.0.7/sdevpy/thirdparty/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/__init__.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/constants.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/erf_cody.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/exceptions.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/lets_be_rational.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/normaldistribution.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/rationalcubic.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/__init__.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black/__init__.py +1 -0
- sdevpy-1.0.7/sdevpy/thirdparty/py_vollib/black/greeks/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black/greeks/analytical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black/greeks/numerical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black/implied_volatility.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes/__init__.py +1 -0
- sdevpy-1.0.7/sdevpy/thirdparty/py_vollib/black_scholes/greeks/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes/greeks/analytical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes/greeks/numerical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes/implied_volatility.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes_merton/__init__.py +1 -0
- sdevpy-1.0.7/sdevpy/thirdparty/py_vollib/black_scholes_merton/greeks/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes_merton/greeks/analytical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes_merton/greeks/numerical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/black_scholes_merton/implied_volatility.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/helpers/__init__.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/helpers/constants.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/helpers/distributions.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/helpers/doctest_helper.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/helpers/exceptions.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/helpers/numerical_greeks.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/__init__.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black/__init__.py +1 -0
- sdevpy-1.0.7/sdevpy/thirdparty/py_vollib/ref_python/black/greeks/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black/greeks/analytical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black/greeks/numerical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black/implied_volatility.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes/__init__.py +1 -0
- sdevpy-1.0.7/sdevpy/thirdparty/py_vollib/ref_python/black_scholes/greeks/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes/greeks/analytical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes/greeks/numerical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes/implied_volatility.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes_merton/__init__.py +1 -0
- sdevpy-1.0.7/sdevpy/thirdparty/py_vollib/ref_python/black_scholes_merton/greeks/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes_merton/greeks/analytical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes_merton/greeks/numerical.py +1 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_vollib/ref_python/black_scholes_merton/implied_volatility.py +1 -0
- sdevpy-1.0.7/sdevpy/timeseries/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/timeseries/backtesting.py +86 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/timeseries/cointegration.py +22 -22
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/timeseries/meanreversion.py +47 -48
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/timeseries/timeseriestools.py +15 -18
- sdevpy-1.0.7/sdevpy/tools/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/algos.py +5 -3
- sdevpy-1.0.7/sdevpy/tools/book.py +51 -0
- sdevpy-1.0.7/sdevpy/tools/dates.py +31 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/network.py +5 -2
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/pydotnet.py +8 -6
- sdevpy-1.0.7/sdevpy/tools/scalendar.py +287 -0
- sdevpy-1.0.7/sdevpy/tools/speriods.py +25 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/timegrids.py +35 -6
- sdevpy-1.0.7/sdevpy/tools/utils.py +52 -0
- sdevpy-1.0.7/sdevpy/tree/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tree/trees.py +1 -16
- sdevpy-1.0.7/sdevpy/volatility/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/__init__.py +0 -0
- {sdevpy-1.0.6/sdevpy/models → sdevpy-1.0.7/sdevpy/volatility/impliedvol}/impliedvol.py +9 -5
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/impliedvol_calib.py +125 -0
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/models/__init__.py +0 -0
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/volatility/impliedvol}/models/biexp.py +57 -64
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/models/cubicvol.py +205 -0
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/models/gsvi.py +63 -0
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/volatility/impliedvol}/models/svi.py +18 -29
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/models/tssvi1.py +143 -0
- sdevpy-1.0.6/sdevpy/models/svivol.py → sdevpy-1.0.7/sdevpy/volatility/impliedvol/models/vsvi.py +51 -50
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/optionsurface.py +167 -0
- sdevpy-1.0.7/sdevpy/volatility/impliedvol/zerosurface.py +251 -0
- sdevpy-1.0.7/sdevpy/volatility/localvol/__init__.py +0 -0
- sdevpy-1.0.7/sdevpy/volatility/localvol/localvol.py +92 -0
- sdevpy-1.0.7/sdevpy/volatility/localvol/localvol_calib.py +303 -0
- sdevpy-1.0.7/sdevpy/volatility/localvol/localvol_factory.py +201 -0
- sdevpy-1.0.7/sdevpy/volsurfacegen/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/mchestongenerator.py +2 -2
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/mczabrgenerator.py +1 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/sabrgenerator.py +24 -34
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/smilegenerator.py +3 -4
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy.egg-info/PKG-INFO +7 -1
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy.egg-info/SOURCES.txt +89 -28
- sdevpy-1.0.7/sdevpy.egg-info/requires.txt +8 -0
- sdevpy-1.0.6/sdevpy/cointegration/back_testing.py +0 -233
- sdevpy-1.0.6/sdevpy/cointegration/black_analytics.py +0 -45
- sdevpy-1.0.6/sdevpy/cointegration/coint_trading.py +0 -839
- sdevpy-1.0.6/sdevpy/cointegration/data_io.py +0 -225
- sdevpy-1.0.6/sdevpy/cointegration/implied_vol.py +0 -116
- sdevpy-1.0.6/sdevpy/cointegration/plotting.py +0 -296
- sdevpy-1.0.6/sdevpy/cointegration/run_unit_test.py +0 -572
- sdevpy-1.0.6/sdevpy/cointegration/utils.py +0 -477
- sdevpy-1.0.6/sdevpy/market/volsurface.py +0 -21
- sdevpy-1.0.6/sdevpy/maths/constants.py +0 -7
- sdevpy-1.0.6/sdevpy/maths/rand.py +0 -99
- sdevpy-1.0.6/sdevpy/models/localvol.py +0 -74
- sdevpy-1.0.6/sdevpy/models/localvol_calib.py +0 -301
- sdevpy-1.0.6/sdevpy/models/localvol_factory.py +0 -109
- sdevpy-1.0.6/sdevpy/montecarlo/singlefactormc.py +0 -11
- sdevpy-1.0.6/sdevpy/test.py +0 -66
- sdevpy-1.0.6/sdevpy/timeseries/backtesting.py +0 -91
- sdevpy-1.0.6/sdevpy/tools/utils.py +0 -42
- sdevpy-1.0.6/sdevpy.egg-info/requires.txt +0 -2
- {sdevpy-1.0.6 → sdevpy-1.0.7}/README.md +0 -0
- {sdevpy-1.0.6/sdevpy/thirdparty/py_vollib/black/greeks → sdevpy-1.0.7/sdevpy/analytics}/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/analytics/sabr.py +0 -0
- {sdevpy-1.0.6/sdevpy/thirdparty/py_vollib/black_scholes/greeks → sdevpy-1.0.7/sdevpy/cointegration}/__init__.py +0 -0
- {sdevpy-1.0.6/sdevpy/thirdparty/py_vollib/black_scholes_merton/greeks → sdevpy-1.0.7/sdevpy/machinelearning}/__init__.py +0 -0
- {sdevpy-1.0.6/sdevpy/thirdparty/py_vollib/ref_python/black/greeks → sdevpy-1.0.7/sdevpy/machinelearning/keras}/__init__.py +0 -0
- {sdevpy-1.0.6/sdevpy/machinelearning → sdevpy-1.0.7/sdevpy/machinelearning/keras}/topology.py +0 -0
- {sdevpy-1.0.6/sdevpy/thirdparty/py_vollib/ref_python/black_scholes/greeks → sdevpy-1.0.7/sdevpy/machinelearning/llms}/__init__.py +0 -0
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/textgen.py +0 -0
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/machinelearning}/llms/tokenizers.py +0 -0
- {sdevpy-1.0.6/sdevpy/thirdparty/py_vollib/ref_python/black_scholes_merton/greeks → sdevpy-1.0.7/sdevpy/market}/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/integration.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/metrics.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/sets.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/maths/tridiag.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/aad/aad_mc.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/datafiles.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/stovol/stovolgen.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/projects/stovolinverse/stovolinvgen.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tensorflow/tf_metrics.py +0 -0
- {sdevpy-1.0.6/sdevpy → sdevpy-1.0.7/sdevpy/tests}/__init__.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/thirdparty/py_lets_be_rational/numba_helper.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/clipboard.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/constants.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/filemanager.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/jsonmanager.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/tools/timer.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/fbsabrgenerator.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/mcsabrgenerator.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy/volsurfacegen/stovolfactory.py +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy.egg-info/dependency_links.txt +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/sdevpy.egg-info/top_level.txt +0 -0
- {sdevpy-1.0.6 → sdevpy-1.0.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sdevpy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: Python package for Finance
|
|
5
5
|
Author-email: Sebastien Gurrieri <sebgur@gmail.com>
|
|
6
6
|
Project-URL: Git page, https://github.com/sebgur/SDev.Python
|
|
@@ -11,6 +11,12 @@ Requires-Python: >=3.6
|
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: pandas
|
|
13
13
|
Requires-Dist: numpy
|
|
14
|
+
Requires-Dist: scipy
|
|
15
|
+
Requires-Dist: matplotlib
|
|
16
|
+
Requires-Dist: holidays
|
|
17
|
+
Requires-Dist: pandas_market_calendars
|
|
18
|
+
Requires-Dist: openpyxl
|
|
19
|
+
Requires-Dist: colorlog
|
|
14
20
|
|
|
15
21
|
# SDev.Python
|
|
16
22
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sdevpy"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.7"
|
|
8
8
|
license-files = []
|
|
9
9
|
authors = [{ name="Sebastien Gurrieri", email="sebgur@gmail.com" }]
|
|
10
10
|
description = "Python package for Finance"
|
|
@@ -14,17 +14,25 @@ classifiers = [
|
|
|
14
14
|
"Programming Language :: Python :: 3",
|
|
15
15
|
"Operating System :: OS Independent",
|
|
16
16
|
]
|
|
17
|
-
dependencies = ["pandas", "numpy"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
#
|
|
21
|
-
#]
|
|
17
|
+
dependencies = ["pandas", "numpy", "scipy", "matplotlib", "holidays",
|
|
18
|
+
"pandas_market_calendars", "openpyxl", "colorlog"
|
|
19
|
+
]
|
|
20
|
+
#dependencies = ["pyperclip", "tensorflow", "scikit-learn",
|
|
21
|
+
# "tensorflow_probability", "silence_tensorflow"]
|
|
22
22
|
|
|
23
23
|
[tool.setuptools.packages.find]
|
|
24
24
|
where = ["."]
|
|
25
25
|
include = ["sdevpy*", "notebooks*"] # Only include these
|
|
26
26
|
#exclude = ["notebooks*", "spreadsheets*"] # Exclude these
|
|
27
27
|
|
|
28
|
+
[tool.ruff]
|
|
29
|
+
line-length = 120
|
|
30
|
+
target-version = "py313"
|
|
31
|
+
|
|
32
|
+
[tool.ruff.lint]
|
|
33
|
+
select = ["E", "F", "N", "W", "UP", "B"]
|
|
34
|
+
ignore = ["E401", "I001"]
|
|
35
|
+
|
|
28
36
|
[project.urls]
|
|
29
37
|
"Git page" = "https://github.com/sebgur/SDev.Python"
|
|
30
38
|
"SDev Finance" = "http://sdev-finance.com/"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
__version__ = '1.0.5'
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import colorlog
|
|
5
|
+
|
|
6
|
+
handler = colorlog.StreamHandler()
|
|
7
|
+
handler.setFormatter(colorlog.ColoredFormatter(
|
|
8
|
+
"%(log_color)s%(levelname)-8s%(reset)s %(name)s - %(message)s",
|
|
9
|
+
log_colors={
|
|
10
|
+
"DEBUG": "cyan",
|
|
11
|
+
"INFO": "green",
|
|
12
|
+
"WARNING": "yellow",
|
|
13
|
+
"ERROR": "red",
|
|
14
|
+
"CRITICAL": "bold_red",
|
|
15
|
+
}
|
|
16
|
+
))
|
|
17
|
+
|
|
18
|
+
root = logging.getLogger()
|
|
19
|
+
root.addHandler(handler)
|
|
20
|
+
root.setLevel(logging.WARNING)
|
|
21
|
+
logging.getLogger("sdevpy").setLevel(logging.DEBUG)
|
|
@@ -4,6 +4,7 @@ import time
|
|
|
4
4
|
import matplotlib.pyplot as plt
|
|
5
5
|
from sdevpy.analytics import black
|
|
6
6
|
from sdevpy.tree import trees
|
|
7
|
+
from sdevpy.tree.trees import Payoff
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def option_price(ttm, strike, is_call, is_american, spot, vol, rf_rate, div_rate, disc_rate,
|
|
@@ -93,11 +94,10 @@ if __name__ == "__main__":
|
|
|
93
94
|
if not payoff.is_american:
|
|
94
95
|
plt.plot(cf_t, cf_p, label='Vanilla CF Price')
|
|
95
96
|
# # plt.plot(steps_range, trinomial_prices, label='Trinomial Tree Price')
|
|
96
|
-
# plt.hlines(bs_price, steps_range[0], steps_range[-1], colors='r', linestyles='dashed',
|
|
97
|
+
# plt.hlines(bs_price, steps_range[0], steps_range[-1], colors='r', linestyles='dashed',
|
|
98
|
+
# label='Black-Scholes Price')
|
|
97
99
|
plt.title('Convergence to Black-Scholes Price for Call Options')
|
|
98
100
|
plt.xlabel('Runtime')
|
|
99
101
|
plt.ylabel('Option Price')
|
|
100
102
|
plt.legend()
|
|
101
103
|
plt.show()
|
|
102
|
-
|
|
103
|
-
|
|
@@ -13,6 +13,7 @@ def price(expiry, strike, is_call, fwd, vol):
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def price_straddles(expiries, strikes, fwd, vols):
|
|
16
|
+
""" Straddle price under the Bachelier model """
|
|
16
17
|
expiries_ = np.asarray(expiries).reshape(-1, 1)
|
|
17
18
|
prices = []
|
|
18
19
|
for i, expiry in enumerate(expiries_):
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
""" Utilities for Black-Scholes model """
|
|
2
2
|
import numpy as np
|
|
3
|
+
# import numpy.typing as npt
|
|
3
4
|
import scipy.stats
|
|
4
5
|
from scipy.optimize import minimize_scalar
|
|
5
6
|
from sdevpy.thirdparty.py_vollib.black import implied_volatility as jaeckel
|
|
6
|
-
from sdevpy import settings
|
|
7
7
|
|
|
8
8
|
N = scipy.stats.norm.cdf
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def price(expiry, strike, is_call, fwd, vol):
|
|
11
|
+
def price(expiry: float, strike: float, is_call: bool, fwd: float, vol: float) -> float:
|
|
12
12
|
""" Option price under the Black-Scholes model """
|
|
13
13
|
w = 1.0 if is_call else -1.0
|
|
14
14
|
s = vol * np.sqrt(expiry)
|
|
@@ -17,7 +17,7 @@ def price(expiry, strike, is_call, fwd, vol):
|
|
|
17
17
|
return w * (fwd * N(w * d1) - strike * N(w * d2))
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def implied_vol_jaeckel(expiry, strike, is_call, fwd, fwd_price):
|
|
20
|
+
def implied_vol_jaeckel(expiry: float, strike: float, is_call: bool, fwd: float, fwd_price: float) -> float:
|
|
21
21
|
""" Black-Scholes implied volatility using P. Jaeckel's 'Let's be rational' method,
|
|
22
22
|
from package py_vollib. Install with pip install py_vollib or at
|
|
23
23
|
https://pypi.org/project/py_vollib/. Unfortunately we found it has instabilities
|
|
@@ -28,7 +28,7 @@ def implied_vol_jaeckel(expiry, strike, is_call, fwd, fwd_price):
|
|
|
28
28
|
return iv
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def implied_vol(expiry, strike, is_call, fwd, fwd_price):
|
|
31
|
+
def implied_vol(expiry: float, strike: float, is_call: bool, fwd: float, fwd_price: float) -> float:
|
|
32
32
|
""" Direct method by numerical inversion using Brent """
|
|
33
33
|
options = {'xtol': 1e-4, 'maxiter': 100, 'disp': False}
|
|
34
34
|
xmin = 1e-6
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
""" Monte-Carlo simulation for Free-Boundary SABR model (vanillas) """
|
|
2
2
|
import numpy as np
|
|
3
|
+
import numpy.typing as npt
|
|
3
4
|
import matplotlib.pyplot as plt
|
|
4
5
|
import scipy.stats as sp
|
|
5
|
-
# from analytics.sabr import calculate_alpha
|
|
6
6
|
from sdevpy.tools.timegrids import SimpleTimeGridBuilder
|
|
7
7
|
from sdevpy.tools import timer
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def price(expiries, strikes, are_calls, fwd
|
|
11
|
-
scheme='Andersen'):
|
|
10
|
+
def price(expiries: npt.ArrayLike, strikes: npt.ArrayLike, are_calls: npt.ArrayLike, fwd: float,
|
|
11
|
+
parameters: list[float], num_mc: int=10000, points_per_year: int=10, scheme: str='Andersen'):
|
|
12
12
|
""" Calculate vanilla prices under Free-Boundary SABR model by Monte-Carlo simulation"""
|
|
13
13
|
floor = 0.00001
|
|
14
14
|
|
|
@@ -16,98 +16,96 @@ def price(expiries, strikes, are_calls, fwd, parameters, num_mc=10000, points_pe
|
|
|
16
16
|
# the spot becomes so close to 0 that Python effectively handles it as 0. This results in
|
|
17
17
|
# a warning when taking a negative power of it. However, this is not an issue as Python
|
|
18
18
|
# correctly finds +infinity and since we use a floor, this case is correctly handled.
|
|
19
|
-
np.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
payoff_count += 1
|
|
98
|
-
|
|
99
|
-
np.seterr(divide='warn')
|
|
19
|
+
with np.errstate(divide='ignore'):
|
|
20
|
+
# Build time grid
|
|
21
|
+
time_grid_builder = SimpleTimeGridBuilder(points_per_year=points_per_year)
|
|
22
|
+
time_grid_builder.add_grid(expiries)
|
|
23
|
+
time_grid = time_grid_builder.complete_grid()
|
|
24
|
+
num_factors = 2
|
|
25
|
+
|
|
26
|
+
# Find payoff times
|
|
27
|
+
is_payoff = np.in1d(time_grid, expiries)
|
|
28
|
+
|
|
29
|
+
# Retrieve parameters
|
|
30
|
+
lnvol = parameters['LnVol']
|
|
31
|
+
beta = parameters['Beta']
|
|
32
|
+
nu = parameters['Nu']
|
|
33
|
+
rho = parameters['Rho']
|
|
34
|
+
alpha = calculate_fbsabr_alpha(lnvol, fwd, beta)
|
|
35
|
+
nu2 = nu**2
|
|
36
|
+
sqrtmrho2 = np.sqrt(1.0 - rho**2)
|
|
37
|
+
|
|
38
|
+
# Draw all gaussians
|
|
39
|
+
# gaussians = rand.gaussians(num_steps, num_mc, num_factors, rand_method)
|
|
40
|
+
|
|
41
|
+
# Define dimensions
|
|
42
|
+
mean = np.zeros(num_factors)
|
|
43
|
+
corr = np.zeros((num_factors, num_factors))
|
|
44
|
+
for c in range(num_factors):
|
|
45
|
+
corr[c, c] = 1.0
|
|
46
|
+
|
|
47
|
+
# Draw for each step
|
|
48
|
+
seed = 42
|
|
49
|
+
rng = np.random.RandomState(seed)
|
|
50
|
+
|
|
51
|
+
# Initialize paths
|
|
52
|
+
spot = np.ones((2 * num_mc, 1)) * fwd
|
|
53
|
+
vol = np.ones((2 * num_mc, 1)) * 1.0
|
|
54
|
+
|
|
55
|
+
# Loop over time grid
|
|
56
|
+
ts = te = 0
|
|
57
|
+
payoff_count = 0
|
|
58
|
+
mc_prices = []
|
|
59
|
+
for i, t in enumerate(time_grid):
|
|
60
|
+
# print("time iteration " + str(i))
|
|
61
|
+
ts = te
|
|
62
|
+
te = t
|
|
63
|
+
dt = te - ts
|
|
64
|
+
sqrt_dt = np.sqrt(dt)
|
|
65
|
+
|
|
66
|
+
# Evolve
|
|
67
|
+
dz = rng.multivariate_normal(mean, corr, size=num_mc) * sqrt_dt
|
|
68
|
+
dz = np.concatenate((dz, -dz), axis=0) # Antithetic paths
|
|
69
|
+
dz0 = dz[:, 0].reshape(-1, 1)
|
|
70
|
+
dz1 = dz[:, 1].reshape(-1, 1)
|
|
71
|
+
|
|
72
|
+
vols = vol
|
|
73
|
+
abs_f = np.maximum(np.abs(spot), floor)
|
|
74
|
+
|
|
75
|
+
# Evolve vol
|
|
76
|
+
vol *= np.exp(-0.5 * nu2 * dt + nu * dz1)
|
|
77
|
+
|
|
78
|
+
# Evolve spot
|
|
79
|
+
if scheme == 'Euler':
|
|
80
|
+
dw = rho * dz1 + sqrtmrho2 * dz0
|
|
81
|
+
spot = spot + alpha * abs_f**beta * dw * vols
|
|
82
|
+
elif scheme == 'Andersen':
|
|
83
|
+
vole = vol
|
|
84
|
+
spot = spot + alpha * abs_f**beta * (sqrtmrho2 * vols * dz0 + rho / nu * (vole - vols))
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError("Unknown scheme in FBSABR: " + scheme)
|
|
87
|
+
|
|
88
|
+
# Calculate payoff
|
|
89
|
+
if is_payoff[i]:
|
|
90
|
+
w = [1.0 if is_call else -1.0 for is_call in are_calls[payoff_count]]
|
|
91
|
+
w = np.asarray(w).reshape(1, -1)
|
|
92
|
+
k = np.asarray(strikes[payoff_count]).reshape(1, -1)
|
|
93
|
+
payoff = np.maximum(w * (spot - k), 0.0)
|
|
94
|
+
rpayoff = np.mean(payoff, axis=0)
|
|
95
|
+
mc_prices.append(rpayoff)
|
|
96
|
+
payoff_count += 1
|
|
100
97
|
|
|
101
98
|
return np.asarray(mc_prices)
|
|
102
99
|
|
|
103
100
|
|
|
104
|
-
def calculate_fbsabr_alpha(ln_vol, fwd, beta):
|
|
101
|
+
def calculate_fbsabr_alpha(ln_vol: float, fwd: float, beta: float) -> float:
|
|
105
102
|
""" Calculate parameter alpha with our definition in terms of ln_vol, i.e.
|
|
106
103
|
alpha = ln_vol * fwd ^ (1.0 - beta) """
|
|
107
104
|
floor = 0.00001
|
|
108
105
|
abs_f = np.maximum(np.abs(fwd), floor)
|
|
109
106
|
return ln_vol * abs_f ** (1.0 - beta)
|
|
110
107
|
|
|
108
|
+
|
|
111
109
|
if __name__ == "__main__":
|
|
112
110
|
EXPIRIES = [3.0, 8.0, 13, 19, 22, 31, 34]
|
|
113
111
|
NSTRIKES = 50
|
|
@@ -151,12 +149,12 @@ if __name__ == "__main__":
|
|
|
151
149
|
# print(MC_PRICES)
|
|
152
150
|
|
|
153
151
|
# Convert to IV and compare against approximate closed-form
|
|
154
|
-
# import black
|
|
155
|
-
import bachelier
|
|
152
|
+
# import sdevpy.analytics.black as black
|
|
153
|
+
import sdevpy.analytics.bachelier as bachelier
|
|
156
154
|
mc_ivs = []
|
|
157
155
|
for a, expiry in enumerate(EXPIRIES):
|
|
158
156
|
mc_iv = []
|
|
159
|
-
for j,
|
|
157
|
+
for j, _ in enumerate(SSTRIKES[a]):
|
|
160
158
|
# mc_iv.append(black.implied_vol(expiry, sstrike, IS_CALL, SFWD, MC_PRICES[a, j]))
|
|
161
159
|
mc_iv.append(bachelier.implied_vol(expiry, STRIKES[a, j], IS_CALL, FWD,
|
|
162
160
|
MC_PRICES[a, j]))
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import matplotlib.pyplot as plt
|
|
7
7
|
import scipy.stats as sp
|
|
8
|
-
# from analytics.sabr import calculate_alpha
|
|
9
8
|
from sdevpy.tools.timegrids import SimpleTimeGridBuilder
|
|
10
9
|
from sdevpy.tools import timer
|
|
11
10
|
|
|
@@ -20,83 +19,80 @@ def price(expiries, strikes, are_calls, fwd, parameters, num_mc=10000, points_pe
|
|
|
20
19
|
# the spot becomes so close to 0 that Python effectively handles it as 0. This results in
|
|
21
20
|
# a warning when taking a negative power of it. However, this is not an issue as Python
|
|
22
21
|
# correctly finds +infinity and since we use a floor, this case is correctly handled.
|
|
23
|
-
np.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
payoff_count += 1
|
|
98
|
-
|
|
99
|
-
np.seterr(divide='warn')
|
|
22
|
+
with np.errstate(divide='ignore'):
|
|
23
|
+
# Build time grid
|
|
24
|
+
time_grid_builder = SimpleTimeGridBuilder(points_per_year=points_per_year)
|
|
25
|
+
time_grid_builder.add_grid(expiries)
|
|
26
|
+
time_grid = time_grid_builder.complete_grid()
|
|
27
|
+
num_factors = 2
|
|
28
|
+
|
|
29
|
+
# Find payoff times
|
|
30
|
+
is_payoff = np.in1d(time_grid, expiries)
|
|
31
|
+
|
|
32
|
+
# Retrieve parameters
|
|
33
|
+
lnvol = parameters['LnVol']
|
|
34
|
+
kappa = parameters['Kappa']
|
|
35
|
+
theta = parameters['Theta']
|
|
36
|
+
xi = parameters['Xi']
|
|
37
|
+
rho = parameters['Rho']
|
|
38
|
+
sqrtmrho2 = np.sqrt(1.0 - rho**2)
|
|
39
|
+
v0 = calculate_v0(lnvol)
|
|
40
|
+
|
|
41
|
+
# Draw all gaussians
|
|
42
|
+
# gaussians = rand.gaussians(num_steps, num_mc, num_factors, rand_method)
|
|
43
|
+
|
|
44
|
+
# Define dimensions
|
|
45
|
+
mean = np.zeros(num_factors)
|
|
46
|
+
corr = np.zeros((num_factors, num_factors))
|
|
47
|
+
for c in range(num_factors):
|
|
48
|
+
corr[c, c] = 1.0
|
|
49
|
+
|
|
50
|
+
# Draw for each step
|
|
51
|
+
seed = 42
|
|
52
|
+
rng = np.random.RandomState(seed)
|
|
53
|
+
|
|
54
|
+
# Initialize paths
|
|
55
|
+
spot = np.ones((2 * num_mc, 1)) * fwd
|
|
56
|
+
vol2 = np.ones((2 * num_mc, 1)) * v0
|
|
57
|
+
|
|
58
|
+
# Loop over time grid
|
|
59
|
+
ts = te = 0
|
|
60
|
+
payoff_count = 0
|
|
61
|
+
mc_prices = []
|
|
62
|
+
for i, t in enumerate(time_grid):
|
|
63
|
+
ts = te
|
|
64
|
+
te = t
|
|
65
|
+
dt = te - ts
|
|
66
|
+
sqrt_dt = np.sqrt(dt)
|
|
67
|
+
|
|
68
|
+
# Evolve
|
|
69
|
+
dz = rng.multivariate_normal(mean, corr, size=num_mc) * sqrt_dt
|
|
70
|
+
dz = np.concatenate((dz, -dz), axis=0) # Antithetic paths
|
|
71
|
+
dz0 = dz[:, 0].reshape(-1, 1)
|
|
72
|
+
dz1 = dz[:, 1].reshape(-1, 1)
|
|
73
|
+
|
|
74
|
+
# Evolve vol
|
|
75
|
+
vol2s = np.abs(vol2)
|
|
76
|
+
sqrt_vol2s = np.sqrt(vol2s)
|
|
77
|
+
vol2e = vol2s + kappa * (theta - vol2s) * dt + xi * sqrt_vol2s * dz1
|
|
78
|
+
vol2e = np.abs(vol2e)
|
|
79
|
+
vol2 = vol2e
|
|
80
|
+
|
|
81
|
+
# Evolve spot
|
|
82
|
+
intvol2 = 0.5 * (vol2s + vol2e) * dt
|
|
83
|
+
ito = 0.5 * intvol2
|
|
84
|
+
dw = rho * dz1 + sqrtmrho2 * dz0
|
|
85
|
+
spot *= np.exp(-ito + sqrt_vol2s * dw)
|
|
86
|
+
|
|
87
|
+
# Calculate payoff
|
|
88
|
+
if is_payoff[i]:
|
|
89
|
+
w = [1.0 if is_call else -1.0 for is_call in are_calls[payoff_count]]
|
|
90
|
+
w = np.asarray(w).reshape(1, -1)
|
|
91
|
+
k = np.asarray(strikes[payoff_count]).reshape(1, -1)
|
|
92
|
+
payoff = np.maximum(w * (spot - k), 0.0)
|
|
93
|
+
rpayoff = np.mean(payoff, axis=0)
|
|
94
|
+
mc_prices.append(rpayoff)
|
|
95
|
+
payoff_count += 1
|
|
100
96
|
|
|
101
97
|
return np.asarray(mc_prices)
|
|
102
98
|
|
|
@@ -147,8 +143,8 @@ if __name__ == "__main__":
|
|
|
147
143
|
mc_timer.print()
|
|
148
144
|
|
|
149
145
|
# Convert to IV and compare against approximate closed-form
|
|
150
|
-
import black
|
|
151
|
-
import bachelier
|
|
146
|
+
import sdevpy.analytics.black as black
|
|
147
|
+
import sdevpy.analytics.bachelier as bachelier
|
|
152
148
|
mc_ivs = []
|
|
153
149
|
n_ivs = []
|
|
154
150
|
for a, expiry in enumerate(EXPIRIES):
|