sdevpy 1.0.9__tar.gz → 1.1__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.
Files changed (203) hide show
  1. sdevpy-1.1/LICENSE +21 -0
  2. {sdevpy-1.0.9 → sdevpy-1.1}/PKG-INFO +25 -2
  3. {sdevpy-1.0.9 → sdevpy-1.1}/pyproject.toml +17 -8
  4. sdevpy-1.1/sdevpy/__init__.py +26 -0
  5. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/analytics/bachelier.py +1 -4
  6. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/analytics/black.py +15 -3
  7. sdevpy-1.1/sdevpy/instruments/constants.py +20 -0
  8. sdevpy-1.1/sdevpy/logger.py +42 -0
  9. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/keras/learningschedules.py +1 -1
  10. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/correlations.py +4 -2
  11. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/eqforward.py +14 -21
  12. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/eqvolsurface.py +52 -36
  13. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/yieldcurve.py +14 -16
  14. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/constants.py +3 -0
  15. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/integration.py +0 -1
  16. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/interpolation.py +14 -7
  17. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/optimization.py +26 -6
  18. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/rand/pathconstruction.py +2 -1
  19. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/specialfunctions.py +3 -3
  20. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/models/assetmodels.py +10 -14
  21. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/models/multiasset_heston.py +1 -1
  22. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/mcpricer.py +59 -11
  23. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/payoffs/basic.py +1 -1
  24. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/payoffs/vanillas.py +10 -29
  25. sdevpy-1.1/sdevpy/montecarlo/smoothers.py +23 -0
  26. sdevpy-1.1/sdevpy/pde/forwardpde.py +303 -0
  27. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/pde/pdeschemes.py +61 -57
  28. sdevpy-1.1/sdevpy/tensorflow/tf_analytics.py +19 -0
  29. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tensorflow/tf_metrics.py +6 -4
  30. sdevpy-1.1/sdevpy/tests/test_algos.py +112 -0
  31. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_analytics.py +10 -9
  32. sdevpy-1.1/sdevpy/tests/test_backtesting.py +58 -0
  33. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_dates.py +10 -11
  34. sdevpy-1.1/sdevpy/tests/test_files.py +93 -0
  35. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_impliedvol.py +70 -29
  36. sdevpy-1.1/sdevpy/tests/test_impliedvol_ml.py +135 -0
  37. sdevpy-1.1/sdevpy/tests/test_integration.py +24 -0
  38. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_interpolation.py +4 -4
  39. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_localvol.py +92 -97
  40. sdevpy-1.1/sdevpy/tests/test_localvol_calib.py +200 -0
  41. sdevpy-1.1/sdevpy/tests/test_marketdata.py +90 -0
  42. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_mc.py +11 -6
  43. sdevpy-1.1/sdevpy/tests/test_meanreversion.py +161 -0
  44. sdevpy-1.1/sdevpy/tests/test_models.py +49 -0
  45. sdevpy-1.1/sdevpy/tests/test_pde.py +186 -0
  46. sdevpy-1.1/sdevpy/tests/test_restapi.py +77 -0
  47. sdevpy-1.1/sdevpy/tests/test_specialfunctions.py +43 -0
  48. sdevpy-1.1/sdevpy/tests/test_timegrids.py +98 -0
  49. sdevpy-1.1/sdevpy/tests/test_tree.py +77 -0
  50. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_yieldcurves.py +36 -3
  51. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/timeseries/backtesting.py +1 -1
  52. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tree/trees.py +9 -9
  53. sdevpy-1.1/sdevpy/utilities/algos.py +81 -0
  54. sdevpy-1.1/sdevpy/utilities/constants.py +2 -0
  55. sdevpy-1.1/sdevpy/utilities/dates.py +54 -0
  56. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/filemanager.py +0 -12
  57. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/jsonmanager.py +6 -7
  58. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/pydotnet.py +1 -0
  59. sdevpy-1.1/sdevpy/utilities/restapi.py +42 -0
  60. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/scalendar.py +9 -15
  61. sdevpy-1.1/sdevpy/utilities/timegrids.py +217 -0
  62. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/tools.py +2 -2
  63. sdevpy-1.1/sdevpy/utilities/xmlmanager.py +29 -0
  64. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/impliedvol.py +33 -44
  65. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/impliedvol_calib.py +14 -28
  66. sdevpy-1.1/sdevpy/volatility/impliedvol/impliedvol_factory.py +66 -0
  67. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/biexp.py +14 -4
  68. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/cubicvol.py +9 -6
  69. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/fbsabr.py +2 -2
  70. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/logmix.py +219 -74
  71. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/mcheston.py +2 -2
  72. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/mcsabr.py +3 -3
  73. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/mczabr.py +2 -2
  74. sdevpy-1.1/sdevpy/volatility/impliedvol/models/svi.py +122 -0
  75. sdevpy-1.1/sdevpy/volatility/impliedvol/models/tssvi1.py +276 -0
  76. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/tssvi2.py +76 -37
  77. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/vsvi.py +43 -31
  78. sdevpy-1.1/sdevpy/volatility/impliedvol/numerical_impliedvol.py +134 -0
  79. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/optionsurface.py +16 -6
  80. sdevpy-1.1/sdevpy/volatility/impliedvol/parametric_impliedvol.py +29 -0
  81. sdevpy-1.1/sdevpy/volatility/localvol/black_calib.py +66 -0
  82. sdevpy-1.0.9/sdevpy/volatility/localvol/dupire.py → sdevpy-1.1/sdevpy/volatility/localvol/dupire_calib.py +125 -35
  83. sdevpy-1.1/sdevpy/volatility/localvol/localvol.py +336 -0
  84. sdevpy-1.1/sdevpy/volatility/localvol/localvol_factory.py +244 -0
  85. sdevpy-1.1/sdevpy/volatility/localvol/lvsection_calib.py +352 -0
  86. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/sabrgenerator.py +2 -1
  87. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy.egg-info/PKG-INFO +25 -2
  88. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy.egg-info/SOURCES.txt +22 -32
  89. sdevpy-1.0.9/sdevpy/__init__.py +0 -21
  90. sdevpy-1.0.9/sdevpy/montecarlo/mcrun.py +0 -102
  91. sdevpy-1.0.9/sdevpy/montecarlo/smoothers.py +0 -40
  92. sdevpy-1.0.9/sdevpy/pde/forwardpde.py +0 -267
  93. sdevpy-1.0.9/sdevpy/projects/aad/aad_mc.py +0 -282
  94. sdevpy-1.0.9/sdevpy/projects/aad/aad_mc_nd.py +0 -349
  95. sdevpy-1.0.9/sdevpy/projects/chat_gpt2.py +0 -76
  96. sdevpy-1.0.9/sdevpy/projects/datafiles.py +0 -28
  97. sdevpy-1.0.9/sdevpy/projects/raschka/ch2_working_with_text.py +0 -161
  98. sdevpy-1.0.9/sdevpy/projects/raschka/ch3_coding_attention.py +0 -259
  99. sdevpy-1.0.9/sdevpy/projects/raschka/ch4_gpt_model.py +0 -200
  100. sdevpy-1.0.9/sdevpy/projects/raschka/ch5_loadgpt2.py +0 -119
  101. sdevpy-1.0.9/sdevpy/projects/raschka/ch5_pretraining.py +0 -263
  102. sdevpy-1.0.9/sdevpy/projects/raschka/ch7_instruction_finetuning.py +0 -26
  103. sdevpy-1.0.9/sdevpy/projects/raschka/raschka_datasetloader.py +0 -80
  104. sdevpy-1.0.9/sdevpy/projects/raschka/raschka_dnn.py +0 -40
  105. sdevpy-1.0.9/sdevpy/projects/raschka/raschka_gpt_download.py +0 -155
  106. sdevpy-1.0.9/sdevpy/projects/set_limits.py +0 -24
  107. sdevpy-1.0.9/sdevpy/projects/stovol/stovolgen.py +0 -87
  108. sdevpy-1.0.9/sdevpy/projects/stovol/stovolplot.py +0 -81
  109. sdevpy-1.0.9/sdevpy/projects/stovol/stovoltrain.py +0 -269
  110. sdevpy-1.0.9/sdevpy/projects/stovolinverse/stovolinvgen.py +0 -82
  111. sdevpy-1.0.9/sdevpy/projects/stovolinverse/stovolinvtrain.py +0 -374
  112. sdevpy-1.0.9/sdevpy/projects/update_db.py +0 -26
  113. sdevpy-1.0.9/sdevpy/tests/test_algos.py +0 -125
  114. sdevpy-1.0.9/sdevpy/tests/test_marketdata.py +0 -48
  115. sdevpy-1.0.9/sdevpy/tests/test_pde.py +0 -116
  116. sdevpy-1.0.9/sdevpy/tests/test_timegrids.py +0 -49
  117. sdevpy-1.0.9/sdevpy/utilities/algos.py +0 -115
  118. sdevpy-1.0.9/sdevpy/utilities/constants.py +0 -6
  119. sdevpy-1.0.9/sdevpy/utilities/dates.py +0 -31
  120. sdevpy-1.0.9/sdevpy/utilities/network.py +0 -95
  121. sdevpy-1.0.9/sdevpy/utilities/speriods.py +0 -25
  122. sdevpy-1.0.9/sdevpy/utilities/timegrids.py +0 -142
  123. sdevpy-1.0.9/sdevpy/volatility/__init__.py +0 -0
  124. sdevpy-1.0.9/sdevpy/volatility/impliedvol/__init__.py +0 -0
  125. sdevpy-1.0.9/sdevpy/volatility/impliedvol/models/__init__.py +0 -0
  126. sdevpy-1.0.9/sdevpy/volatility/impliedvol/models/gsvi.py +0 -67
  127. sdevpy-1.0.9/sdevpy/volatility/impliedvol/models/svi.py +0 -96
  128. sdevpy-1.0.9/sdevpy/volatility/impliedvol/models/tssvi1.py +0 -198
  129. sdevpy-1.0.9/sdevpy/volatility/localvol/__init__.py +0 -0
  130. sdevpy-1.0.9/sdevpy/volatility/localvol/localvol.py +0 -192
  131. sdevpy-1.0.9/sdevpy/volatility/localvol/localvol_calib.py +0 -307
  132. sdevpy-1.0.9/sdevpy/volatility/localvol/localvol_factory.py +0 -201
  133. sdevpy-1.0.9/sdevpy/volatility/mlsurfacegen/__init__.py +0 -0
  134. {sdevpy-1.0.9 → sdevpy-1.1}/README.md +0 -0
  135. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/analytics/__init__.py +0 -0
  136. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/analytics/americantree.py +0 -0
  137. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/__init__.py +0 -0
  138. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/datasets.py +0 -0
  139. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/keras/__init__.py +0 -0
  140. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/keras/callbacks.py +0 -0
  141. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/keras/learningmodel.py +0 -0
  142. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/keras/topology.py +0 -0
  143. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/__init__.py +0 -0
  144. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/attention.py +0 -0
  145. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/chat.py +0 -0
  146. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/datasets.py +0 -0
  147. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/gpt.py +0 -0
  148. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/instructions.py +0 -0
  149. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/modelconverter.py +0 -0
  150. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/textgen.py +0 -0
  151. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/tokenizers.py +0 -0
  152. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/machinelearning/llms/training.py +0 -0
  153. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/__init__.py +0 -0
  154. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/fixings.py +0 -0
  155. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/market/spot.py +0 -0
  156. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/__init__.py +0 -0
  157. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/metrics.py +0 -0
  158. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/rand/__init__.py +0 -0
  159. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/rand/correlations.py +0 -0
  160. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/rand/rng.py +0 -0
  161. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/regression.py +0 -0
  162. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/sets.py +0 -0
  163. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/maths/tridiag.py +0 -0
  164. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/models/__init__.py +0 -0
  165. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/__init__.py +0 -0
  166. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/pathgenerator.py +0 -0
  167. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/payoffs/__init__.py +0 -0
  168. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/payoffs/cashflows.py +0 -0
  169. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/montecarlo/payoffs/exotics.py +0 -0
  170. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/pde/__init__.py +0 -0
  171. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/settings.py +0 -0
  172. {sdevpy-1.0.9/sdevpy/projects → sdevpy-1.1/sdevpy/tensorflow}/__init__.py +0 -0
  173. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tensorflow/tf_black.py +0 -0
  174. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/__init__.py +0 -0
  175. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test.py +0 -0
  176. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_cointegration.py +0 -0
  177. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/tests/test_utils.py +0 -0
  178. {sdevpy-1.0.9/sdevpy/projects/aad → sdevpy-1.1/sdevpy/thirdparty}/__init__.py +0 -0
  179. {sdevpy-1.0.9/sdevpy/projects/raschka → sdevpy-1.1/sdevpy/timeseries}/__init__.py +0 -0
  180. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/timeseries/cointegration.py +0 -0
  181. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/timeseries/meanreversion.py +0 -0
  182. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/timeseries/timeseriestools.py +0 -0
  183. {sdevpy-1.0.9/sdevpy/projects/stovol → sdevpy-1.1/sdevpy/tree}/__init__.py +0 -0
  184. {sdevpy-1.0.9/sdevpy/projects/stovolinverse → sdevpy-1.1/sdevpy/utilities}/__init__.py +0 -0
  185. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/book.py +0 -0
  186. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/clipboard.py +0 -0
  187. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/utilities/timer.py +0 -0
  188. {sdevpy-1.0.9/sdevpy/tensorflow → sdevpy-1.1/sdevpy/volatility}/__init__.py +0 -0
  189. {sdevpy-1.0.9/sdevpy/thirdparty → sdevpy-1.1/sdevpy/volatility/impliedvol}/__init__.py +0 -0
  190. {sdevpy-1.0.9/sdevpy/timeseries → sdevpy-1.1/sdevpy/volatility/impliedvol/models}/__init__.py +0 -0
  191. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/impliedvol/models/sabr.py +0 -0
  192. {sdevpy-1.0.9/sdevpy/tree → sdevpy-1.1/sdevpy/volatility/localvol}/__init__.py +0 -0
  193. {sdevpy-1.0.9/sdevpy/utilities → sdevpy-1.1/sdevpy/volatility/mlsurfacegen}/__init__.py +0 -0
  194. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/fbsabrgenerator.py +0 -0
  195. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/mchestongenerator.py +0 -0
  196. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/mcsabrgenerator.py +0 -0
  197. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/mczabrgenerator.py +0 -0
  198. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/smilegenerator.py +0 -0
  199. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy/volatility/mlsurfacegen/stovolfactory.py +0 -0
  200. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy.egg-info/dependency_links.txt +0 -0
  201. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy.egg-info/requires.txt +0 -0
  202. {sdevpy-1.0.9 → sdevpy-1.1}/sdevpy.egg-info/top_level.txt +0 -0
  203. {sdevpy-1.0.9 → sdevpy-1.1}/setup.cfg +0 -0
sdevpy-1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2023] [Sebastien Gurrieri]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,14 +1,36 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdevpy
3
- Version: 1.0.9
3
+ Version: 1.1
4
4
  Summary: Python package for Finance
5
5
  Author-email: Sebastien Gurrieri <sebgur@gmail.com>
6
- Project-URL: Git page, https://github.com/sebgur/SDev.Python
6
+ License: MIT License
7
+
8
+ Copyright (c) [2023] [Sebastien Gurrieri]
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Git, https://github.com/sebgur/SDev.Python
7
28
  Project-URL: SDev Finance, http://sdev-finance.com/
8
29
  Classifier: Programming Language :: Python :: 3
9
30
  Classifier: Operating System :: OS Independent
10
31
  Requires-Python: >=3.6
11
32
  Description-Content-Type: text/markdown
33
+ License-File: LICENSE
12
34
  Requires-Dist: pandas
13
35
  Requires-Dist: numpy
14
36
  Requires-Dist: scipy
@@ -18,6 +40,7 @@ Requires-Dist: pandas_market_calendars
18
40
  Requires-Dist: openpyxl
19
41
  Requires-Dist: colorlog
20
42
  Requires-Dist: scikit-learn
43
+ Dynamic: license-file
21
44
 
22
45
  # SDev.Python
23
46
 
@@ -4,8 +4,9 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sdevpy"
7
- version = "1.0.9"
8
- license-files = []
7
+ version = "1.1"
8
+ license = {file = "LICENSE"}
9
+ #license-files = []
9
10
  authors = [{ name="Sebastien Gurrieri", email="sebgur@gmail.com" }]
10
11
  description = "Python package for Finance"
11
12
  readme = "README.md"
@@ -21,6 +22,10 @@ dependencies = ["pandas", "numpy", "scipy", "matplotlib", "holidays",
21
22
  #dependencies = ["pyperclip", "tensorflow", "scikit-learn",
22
23
  # "tensorflow_probability", "silence_tensorflow"]
23
24
 
25
+ [project.urls]
26
+ "Git" = "https://github.com/sebgur/SDev.Python"
27
+ "SDev Finance" = "http://sdev-finance.com/"
28
+
24
29
  [tool.setuptools.packages.find]
25
30
  where = ["."]
26
31
  include = ["sdevpy*"] # Only include these
@@ -41,14 +46,18 @@ ignore = ["E401", "I001"]
41
46
  [tool.coverage.run]
42
47
  omit = [
43
48
  "sdevpy/**/__init__.py",
44
- "sdevpy/projects/raschka/*"
49
+ "sdevpy/tests/test.py",
50
+ "sdevpy/logger.py",
51
+ "sdevpy/settings.py",
52
+ "sdevpy/utilities/constants.py",
53
+ "sdevpy/utilities/pydotnet.py",
54
+ "sdevpy/tensorflow/*",
55
+ "sdevpy/machinelearning/*",
56
+ "sdevpy/volatility/mlsurfacegen/*"
45
57
  ]
46
58
 
47
59
  [tool.coverage.report]
48
60
  exclude_lines = [
49
- "if __name__ == '__main__':",
61
+ "if __name__ == .__main__.:",
62
+ "pragma: no cov"
50
63
  ]
51
-
52
- [project.urls]
53
- "Git page" = "https://github.com/sebgur/SDev.Python"
54
- "SDev Finance" = "http://sdev-finance.com/"
@@ -0,0 +1,26 @@
1
+ __version__ = '1.0.5'
2
+
3
+ import logging
4
+
5
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
6
+
7
+
8
+
9
+ # import colorlog
10
+
11
+ # handler = colorlog.StreamHandler()
12
+ # handler.setFormatter(colorlog.ColoredFormatter(
13
+ # "%(log_color)s%(levelname)-8s%(reset)s %(name)s - %(message)s",
14
+ # log_colors={
15
+ # "DEBUG": "cyan",
16
+ # "INFO": "green",
17
+ # "WARNING": "yellow",
18
+ # "ERROR": "red",
19
+ # "CRITICAL": "bold_red",
20
+ # }
21
+ # ))
22
+
23
+ # root = logging.getLogger()
24
+ # root.addHandler(handler)
25
+ # root.setLevel(logging.WARNING)
26
+ # logging.getLogger("sdevpy").setLevel(logging.DEBUG)
@@ -8,10 +8,9 @@ from scipy.optimize import minimize_scalar
8
8
  def price(expiry: npt.ArrayLike, strike: npt.ArrayLike, is_call: npt.ArrayLike, fwd: npt.ArrayLike,
9
9
  vol: npt.ArrayLike) -> npt.NDArray[np.float64]:
10
10
  """ Option price under the Bachelier model """
11
- stdev = vol * expiry**0.5
11
+ stdev = vol * np.sqrt(expiry)
12
12
  d = (fwd - strike) / stdev
13
13
  wd = np.where(is_call, d, -d)
14
- # wd = d if is_call else -d
15
14
  return stdev * (wd * norm.cdf(wd) + norm.pdf(d))
16
15
 
17
16
 
@@ -70,8 +69,6 @@ def implied_vol(expiry: npt.ArrayLike, strike: npt.ArrayLike, is_call: npt.Array
70
69
  strike = np.asarray(strike, dtype=float)
71
70
  fwd_price = np.asarray(fwd_price, dtype=float)
72
71
  is_call = np.asarray(is_call, dtype=bool)
73
- # expiry = float(expiry)
74
- # fwd = float(fwd)
75
72
 
76
73
  #### ATM branch ####
77
74
  m = fwd - strike
@@ -9,7 +9,6 @@ from sdevpy.utilities.tools import isiterable
9
9
  def price(expiry: npt.ArrayLike, strike: npt.ArrayLike, is_call: npt.ArrayLike, fwd: npt.ArrayLike,
10
10
  vol: npt.ArrayLike) -> npt.NDArray[np.float64]:
11
11
  """ Option price under the Black-Scholes model """
12
- # w = 1.0 if is_call else -1.0
13
12
  w = np.where(is_call, 1.0, -1.0)
14
13
  s = vol * np.sqrt(expiry)
15
14
  d1 = np.log(fwd / strike) / s + 0.5 * s
@@ -17,12 +16,25 @@ def price(expiry: npt.ArrayLike, strike: npt.ArrayLike, is_call: npt.ArrayLike,
17
16
  return w * (fwd * norm.cdf(w * d1) - strike * norm.cdf(w * d2))
18
17
 
19
18
 
19
+ def price_straddles(expiry: npt.ArrayLike, strike: npt.ArrayLike, fwd: npt.ArrayLike,
20
+ vol: npt.ArrayLike) -> npt.NDArray[np.float64]:
21
+ """ Straddle price under the Black model """
22
+ call = price(expiry, strike, True, fwd, vol)
23
+ put = price(expiry, strike, False, fwd, vol)
24
+ return call + put
25
+
26
+
20
27
  def implied_vol(expiry: float, strike: float, is_call: bool, fwd: float, fwd_price: float) -> float:
21
28
  """ Direct method by numerical inversion using Brent.
22
29
  Non-vectorized due to solver. """
23
- options = {'xtol': 1e-4, 'maxiter': 100, 'disp': False}
30
+ # Trial config
31
+ options = {'xtol': 1e-6, 'maxiter': 100, 'disp': False}
24
32
  xmin = 1e-6
25
- xmax = 1.0
33
+ xmax = 2.0
34
+ # # Original config
35
+ # options = {'xtol': 1e-4, 'maxiter': 100, 'disp': False}
36
+ # xmin = 1e-6
37
+ # xmax = 1.0
26
38
 
27
39
  def error(vol):
28
40
  premium = price(expiry, strike, is_call, fwd, vol)
@@ -0,0 +1,20 @@
1
+ from enum import Enum
2
+
3
+
4
+ class OptionType(Enum):
5
+ CALL = 0
6
+ PUT = 1
7
+ STRADDLE = 2
8
+
9
+
10
+ def string_to_optiontype(s: str) -> OptionType:
11
+ """ Convert string to OptionType """
12
+ match s.lower():
13
+ case 'call':
14
+ return OptionType.CALL
15
+ case 'put':
16
+ return OptionType.PUT
17
+ case 'straddle':
18
+ return OptionType.STRADDLE
19
+ case _:
20
+ raise ValueError(f"Invalid option type: {s}")
@@ -0,0 +1,42 @@
1
+ import logging, colorlog
2
+
3
+
4
+ LOG_COLORS = {"DEBUG": "cyan", "INFO": "green", "WARNING": "yellow", "ERROR": "red",
5
+ "CRITICAL": "bold_red"}
6
+
7
+
8
+ def string_to_logging_level(level_str: str):
9
+ level_str = level_str.lower()
10
+ match level_str:
11
+ case 'debug':
12
+ return logging.DEBUG
13
+ case 'info':
14
+ return logging.INFO
15
+ case 'warning':
16
+ return logging.WARNING
17
+ case 'error':
18
+ return logging.ERROR
19
+ case 'critical':
20
+ return logging.CRITICAL
21
+ case _:
22
+ raise ValueError(f"Unsupported logging level: {level_str}")
23
+
24
+
25
+ def configure(root_level: str='warning', sdevpy_level: str='debug',
26
+ module_display: str='none') -> None:
27
+ """ Configure logger. Levels can be: debug, info, warning, error and critical. """
28
+ handler = colorlog.StreamHandler()
29
+
30
+ match module_display.lower():
31
+ case 'none':
32
+ module_str = "%(log_color)s%(levelname)-1s%(reset)s | %(message)s"
33
+ case 'partial':
34
+ module_str = "%(log_color)s%(levelname)-1s%(reset)s | %(module)s | %(message)s"
35
+ case 'full':
36
+ module_str = "%(log_color)s%(levelname)-1s%(reset)s | %(name)s | %(message)s"
37
+ case _:
38
+ raise ValueError(f"Unsupported module display mode: {module_display}")
39
+
40
+ handler.setFormatter(colorlog.ColoredFormatter(module_str, log_colors=LOG_COLORS))
41
+ logging.basicConfig(level=string_to_logging_level(root_level), handlers=[handler], force=True)
42
+ logging.getLogger("sdevpy").setLevel(string_to_logging_level(sdevpy_level))
@@ -1,7 +1,7 @@
1
1
  """ Custom learning schedules """
2
2
  import numpy as np
3
3
  import tensorflow as tf
4
- from sdevpy.utilities.constants import TWO_PI
4
+ from sdevpy.maths.constants import TWO_PI
5
5
 
6
6
 
7
7
  # Custom learning rate scheduler, exponentially decreases between given values
@@ -57,13 +57,15 @@ def add_correlations(date: dt.datetime, names1: list[str], names2: list[str], va
57
57
  f.write(f"{name1}-{name2},{value}\n")
58
58
 
59
59
 
60
- def data_file(date: dt.datetime, **kwargs):
60
+ def data_file(date: dt.datetime, **kwargs) -> str:
61
+ """ Data file for correlations """
61
62
  folder = kwargs.get('folder', test_data_folder())
62
63
  file = Path(folder) / (date.strftime(dts.DATE_FILE_FORMAT) + ".csv")
63
64
  return file
64
65
 
65
66
 
66
- def test_data_folder():
67
+ def test_data_folder() -> str:
68
+ """ Test data folder for correlations """
67
69
  folder = Path(__file__).parent.parent.parent / "datasets" / "marketdata" / "correlations"
68
70
  folder.mkdir(parents=True, exist_ok=True)
69
71
  return folder
@@ -2,7 +2,8 @@ import os, json
2
2
  import datetime as dt
3
3
  import numpy as np
4
4
  from pathlib import Path
5
- from sdevpy.utilities import dates, timegrids
5
+ from sdevpy.utilities import dates as dts
6
+ from sdevpy.utilities import timegrids
6
7
  from sdevpy.maths import interpolation as itp
7
8
  from sdevpy.market import yieldcurve as ycrv
8
9
  from sdevpy.market.spot import get_spots
@@ -16,17 +17,9 @@ def get_forward_curves(names, valdate, **kwargs):
16
17
  file = data_file(name, valdate, **kwargs)
17
18
  data = eqforwarddata_from_file(file)
18
19
  curve = EqForwardCurve(valdate=valdate, interp_var='forward', interp_type='cubicspline')
19
- # yieldcurve = ycrv.get_yieldcurve('USD.SOFR.1D', valdate)
20
- curve.calibrate(data, spot)#, yieldcurve)
20
+ curve.calibrate(data, spot)
21
21
  fwd_curves.append(curve)
22
22
 
23
- # drifts = np.asarray([0.02, 0.05, 0.04])
24
- # fwd_curves_old = []
25
- # for s, mu in zip(spots, drifts):
26
- # # Use the default variable trick to circumvent late binding in python loops
27
- # # Otherwise, all the lambda functions will effectively be the same
28
- # fwd_curves_old.append(lambda t, s=s, mu=mu: s * np.exp(mu * t))
29
-
30
23
  return fwd_curves
31
24
 
32
25
 
@@ -51,12 +44,12 @@ class EqForwardData:
51
44
  def dump_data(self):
52
45
  pillars = []
53
46
  for expiry, forward in zip(self.expiries, self.forwards, strict=True):
54
- expiry_str = expiry.strftime(dates.DATE_FORMAT)
47
+ expiry_str = expiry.strftime(dts.DATE_FORMAT)
55
48
  pillar = {'expiry': expiry_str, 'forward': forward}
56
49
  pillars.append(pillar)
57
50
 
58
- data = {'name': self.name, 'valdate': self.valdate.strftime(dates.DATE_FORMAT),
59
- 'snapdate': self.snapdate.strftime(dates.DATETIME_FORMAT), 'pillars': pillars}
51
+ data = {'name': self.name, 'valdate': self.valdate.strftime(dts.DATE_FORMAT),
52
+ 'snapdate': self.snapdate.strftime(dts.DATETIME_FORMAT), 'pillars': pillars}
60
53
  return data
61
54
 
62
55
 
@@ -80,7 +73,7 @@ class EqForwardCurve:
80
73
  # Check consistency
81
74
  for d in self.dates:
82
75
  if d <= self.valdate:
83
- raise RuntimeError(f"Expiry before or at valuation date: {d.strftime(dates.DATE_FORMAT)}")
76
+ raise RuntimeError(f"Expiry before or at valuation date: {d.strftime(dts.DATE_FORMAT)}")
84
77
 
85
78
  # Calibrate
86
79
  if self.interp_var == 'yield':
@@ -133,11 +126,11 @@ def eqforwarddata_from_file(file):
133
126
  # Convert date strings into dates
134
127
  for pillar in pillars:
135
128
  date_str = pillar.get('expiry')
136
- date = dt.datetime.strptime(date_str, dates.DATE_FORMAT)
129
+ date = dt.datetime.strptime(date_str, dts.DATE_FORMAT)
137
130
  pillar['expiry'] = date
138
131
 
139
- data = EqForwardData(dt.datetime.strptime(valdate, dates.DATE_FORMAT), pillars,
140
- name=name, snapdate=dt.datetime.strptime(snapdate, dates.DATETIME_FORMAT))
132
+ data = EqForwardData(dt.datetime.strptime(valdate, dts.DATE_FORMAT), pillars,
133
+ name=name, snapdate=dt.datetime.strptime(snapdate, dts.DATETIME_FORMAT))
141
134
  return data
142
135
 
143
136
 
@@ -145,7 +138,7 @@ def data_file(name, date, **kwargs):
145
138
  folder = kwargs.get('folder', test_data_folder())
146
139
  name_folder = os.path.join(folder, name)
147
140
  os.makedirs(name_folder, exist_ok=True)
148
- file = os.path.join(name_folder, date.strftime(dates.DATE_FILE_FORMAT) + ".json")
141
+ file = os.path.join(name_folder, date.strftime(dts.DATE_FILE_FORMAT) + ".json")
149
142
  return file
150
143
 
151
144
 
@@ -161,7 +154,7 @@ if __name__ == "__main__":
161
154
  import matplotlib.pyplot as plt
162
155
 
163
156
  name = "ABC"
164
- valdate = dt.datetime(2026, 2, 15)
157
+ valdate = dt.datetime(2025, 12, 15)
165
158
 
166
159
  # Generate a sample to start from
167
160
  spot = 100.0
@@ -174,7 +167,7 @@ if __name__ == "__main__":
174
167
  pillars = [{'expiry': d, 'forward': f} for d, f in zip(expiries, zfwds, strict=True)]
175
168
  data = EqForwardData(valdate, pillars, name=name)
176
169
  file = data_file(name, valdate)
177
- data.dump(file)
170
+ # data.dump(file)
178
171
 
179
172
  # Get data from existing file
180
173
  test_data = eqforwarddata_from_file(file)
@@ -185,7 +178,7 @@ if __name__ == "__main__":
185
178
  curve.calibrate(test_data, spot, yieldcurve)
186
179
 
187
180
  # Interpolate and display
188
- test_dates = [dates.advance(valdate, months=1*n) for n in range(1, 150)]
181
+ test_dates = [dts.advance(valdate, str(n) + 'm') for n in range(1, 150)]
189
182
  test_fwds = curve.value(test_dates)
190
183
 
191
184
  # Original data
@@ -1,11 +1,13 @@
1
1
  import os, json, logging
2
2
  import datetime as dt
3
3
  import numpy as np
4
+ import numpy.typing as npt
4
5
  from pathlib import Path
5
6
  from sdevpy.utilities import dates
6
7
  from sdevpy.utilities import timegrids
7
8
  from sdevpy.analytics import black
8
- log = logging.getLogger(__name__)
9
+ from sdevpy.market.eqforward import EqForwardCurve, get_forward_curves
10
+ log = logging.getLogger(Path(__file__).stem)
9
11
 
10
12
 
11
13
  class EqVolSurfaceData:
@@ -20,46 +22,58 @@ class EqVolSurfaceData:
20
22
 
21
23
  # Extract
22
24
  self.expiries = np.asarray([s['expiry'] for s in sections])
23
- self.forwards = np.asarray([s['forward'] for s in sections])
24
25
  self.input_strikes = [np.asarray(s['strikes']) for s in sections]
25
26
  self.vols = [np.asarray(s['vols']) for s in sections]
26
27
 
27
28
  # Size checks
28
29
  n_times = len(self.expiries)
29
- if any(len(x) != n_times for x in (self.forwards, self.input_strikes, self.vols)):
30
+ if any(len(x) != n_times for x in (self.input_strikes, self.vols)):
30
31
  raise ValueError("Incompatible size along time direction between expiries, forwards, strikes and vols")
31
32
 
32
- # Calculate missing strike type
33
- if self.strike_input_type == 'absolute':
34
- self.abs_strikes = self.input_strikes
35
- elif self.strike_input_type == 'relative':
36
- # self.abs_strikes = self.forwards * self.input_strikes # Old way assuming numpy matrix
37
- # The code below is a quick non-tested implementation to cater for the non-matrix case.
38
- # To be tested if/when case presents itself.
39
- log.warning("Relative strike conversion should be tested")
40
- self.abs_strikes = []
41
- for i in range(n_times):
42
- self.abs_strikes.append(self.forwards[i] * self.input_strikes[i])
43
- else:
44
- raise ValueError(f"Strike input type not supported yet: {self.strike_input_type}")
45
-
46
- # Calculate prices
47
- self.call_prices = []
33
+ def get_prices(self, fwd_curve: EqForwardCurve, option_type: str='call') -> npt.ArrayLike:
34
+ option_type_lw = option_type.lower()
35
+ prices = []
36
+ abs_strikes = self.get_strikes(fwd_curve, to_type='absolute')
48
37
  for exp_idx, expiry in enumerate(self.expiries):
49
38
  t = timegrids.model_time(self.valdate, expiry)
50
- fwd = self.forwards[exp_idx]
51
- strikes = self.abs_strikes[exp_idx]
39
+ fwd = fwd_curve.value(expiry)
40
+ strikes = abs_strikes[exp_idx]
52
41
  vols = self.vols[exp_idx]
53
- self.call_prices.append(black.price(t, strikes, True, fwd, vols))
54
-
55
- def get_strikes(self, type: str='absolute'):
56
- req_type = type.lower()
57
- if req_type == 'absolute':
58
- return self.abs_strikes
59
- elif req_type == 'relative':
60
- return self.abs_strikes / self.forwards.reshape(-1, 1)
61
- else:
62
- raise ValueError(f"Unknown strike type {req_type}: expected absolute or relative")
42
+ match option_type_lw:
43
+ case 'call':
44
+ price = black.price(t, strikes, True, fwd, vols)
45
+ case 'put':
46
+ price = black.price(t, strikes, False, fwd, vols)
47
+ case 'straddle':
48
+ price = black.price(t, strikes, True, fwd, vols)
49
+ price = price + black.price(t, strikes, False, fwd, vols)
50
+ case _:
51
+ raise ValueError(f"Invalid option type: {option_type}")
52
+
53
+ prices.append(price)
54
+ return prices
55
+
56
+ def get_strikes(self, fwd_curve: EqForwardCurve=None, to_type: str='absolute') -> npt.ArrayLike:
57
+ """ Retrieve strikes, absolute or relative """
58
+ to_type_lw = to_type.lower()
59
+ if to_type_lw == self.strike_input_type:
60
+ return self.input_strikes
61
+ else: # Need conversion
62
+ if fwd_curve is None:
63
+ raise ValueError(f"Forward curve required for strike conversion but None given: {self.name}")
64
+
65
+ # Need to loop over expiries because not all expiries must have the same number of strikes.
66
+ # Therefore we cannot put the strikes into numpy arrays.
67
+ fwds = fwd_curve.value(self.expiries)
68
+ n_times = len(self.expiries)
69
+ if to_type_lw == 'absolute' and self.strike_input_type == 'relative':
70
+ conv_strikes = [self.input_strikes[i] * fwds[i] for i in range(n_times)]
71
+ elif to_type_lw == 'relative' and self.strike_input_type == 'absolute':
72
+ conv_strikes = [self.input_strikes[i] / fwds[i] for i in range(n_times)]
73
+ else:
74
+ raise ValueError(f"Unknown strike type {to_type}: expected absolute or relative")
75
+
76
+ return conv_strikes
63
77
 
64
78
  def dump(self, file, indent=2):
65
79
  data = self.dump_data()
@@ -70,7 +84,7 @@ class EqVolSurfaceData:
70
84
  sections = []
71
85
  for i, expiry in enumerate(self.expiries):
72
86
  expiry_str = expiry.strftime(dates.DATE_FORMAT)
73
- section = {'expiry': expiry_str, 'forward': self.forwards[i], 'strikes': self.input_strikes[i].tolist(),
87
+ section = {'expiry': expiry_str, 'strikes': self.input_strikes[i].tolist(),
74
88
  'vols': self.vols[i].tolist()}
75
89
  sections.append(section)
76
90
 
@@ -93,7 +107,6 @@ class EqVolSurfaceData:
93
107
  for i in range(n_exp):
94
108
  print(sep)
95
109
  print(f"Expiry {i+1}/{n_exp}: {self.expiries[i].strftime(dates.DATE_FORMAT)}")
96
- print(f"Forward: {self.forwards[i]:,.{n_digits}f}")
97
110
  with np.printoptions(precision=n_digits):
98
111
  print("Strikes", self.input_strikes[i])
99
112
  print("Vols", self.vols[i])
@@ -158,9 +171,12 @@ if __name__ == "__main__":
158
171
  # file = data_file(folder, name, valdate)
159
172
  # surface_data.dump(file)
160
173
 
174
+ # Get forward curve
175
+ fwd_curve = get_forward_curves([name], valdate)[0]
176
+
161
177
  # Get data from existing file
162
- file = data_file(folder, name, valdate)
178
+ file = data_file(name, valdate, folder=folder)
163
179
  surface_data = eqvolsurfacedata_from_file(file)
164
- print(surface_data.get_strikes('absolute'))
165
- print(surface_data.get_strikes('relative'))
180
+ print(surface_data.get_strikes(to_type='absolute'))
181
+ print(surface_data.get_strikes(fwd_curve=fwd_curve, to_type='relative'))
166
182
  surface_data.pretty_print(4)
@@ -4,7 +4,8 @@ import datetime as dt
4
4
  import numpy as np
5
5
  from abc import ABC, abstractmethod
6
6
  from enum import Enum
7
- from sdevpy.utilities import timegrids, dates
7
+ from sdevpy.utilities import dates as dts
8
+ from sdevpy.utilities import timegrids
8
9
  from sdevpy.maths import interpolation as itp
9
10
 
10
11
 
@@ -75,13 +76,13 @@ class InterpolatedYieldCurve(YieldCurve):
75
76
  # Set data in interpolation
76
77
  if self.interp_var == YieldCurveVariable.ZERORATE:
77
78
  times = timegrids.model_time(self.valdate, self.dates)
78
- data_y = -np.log(dfs) / times
79
+ data_y = -np.log(self.dfs) / times
79
80
  elif self.interp_var in [YieldCurveVariable.DISCOUNT, YieldCurveVariable.LOG_DISCOUNT]:
80
81
  times = [0.0]
81
82
  times.extend(timegrids.model_time(self.valdate, self.dates))
82
83
  times = np.asarray(times)
83
84
  ext_dfs = [1.0]
84
- ext_dfs.extend(dfs)
85
+ ext_dfs.extend(self.dfs)
85
86
  ext_dfs = np.asarray(ext_dfs)
86
87
  if self.interp_var == YieldCurveVariable.DISCOUNT:
87
88
  data_y = ext_dfs
@@ -128,13 +129,13 @@ class InterpolatedYieldCurve(YieldCurve):
128
129
  raise RuntimeError("Failure to set curve interpolation")
129
130
 
130
131
  def dump_data(self):
131
- data = {'name': self.name, 'valdate': self.valdate.strftime(dates.DATE_FORMAT),
132
- 'snapdate': self.snapdate.strftime(dates.DATETIME_FORMAT),
132
+ data = {'name': self.name, 'valdate': self.valdate.strftime(dts.DATE_FORMAT),
133
+ 'snapdate': self.snapdate.strftime(dts.DATETIME_FORMAT),
133
134
  'interp_var': self.interp_var_str, 'interp_type': self.interp_type}
134
135
 
135
136
  pillars = []
136
137
  for expiry, df in zip(self.dates, self.dfs, strict=True):
137
- pillar = {'expiry': expiry.strftime(dates.DATE_FORMAT), 'df': df}
138
+ pillar = {'expiry': expiry.strftime(dts.DATE_FORMAT), 'df': df}
138
139
  pillars.append(pillar)
139
140
 
140
141
  data['pillars'] = pillars
@@ -147,26 +148,24 @@ class YieldCurveVariable(Enum):
147
148
  LOG_DISCOUNT = 2
148
149
 
149
150
 
150
- def get_yieldcurve(name, date, **kwargs):
151
+ def get_yieldcurve(name: str, date: dt.datetime, **kwargs):
151
152
  file = data_file(name, date, **kwargs)
152
153
  curve = yieldcurve_from_file(file)
153
154
  return curve
154
155
 
155
156
 
156
- def yieldcurve_from_file(file):
157
+ def yieldcurve_from_file(file: str):
157
158
  with open(file) as f:
158
159
  data = json.load(f)
159
160
 
160
161
  name = data.get('name')
161
162
  valdate = data.get('valdate')
162
- snapdate = data.get('snapdate') # Claude says this will be wrong
163
- # Claude says to do the below but this fails in UT
164
- # snapdate = dt.datetime.strptime(data.get('snapdate'), dates.DATE_FILE_FORMAT)
163
+ snapdate = dt.datetime.strptime(data.get('snapdate'), dts.DATETIME_FORMAT)
165
164
  interp_var = data.get('interp_var')
166
165
  interp_type = data.get('interp_type')
167
166
  pillars = data.get('pillars')
168
167
 
169
- valdate = dt.datetime.strptime(valdate, dates.DATE_FORMAT)
168
+ valdate = dt.datetime.strptime(valdate, dts.DATE_FORMAT)
170
169
  curve = InterpolatedYieldCurve(valdate=valdate, interp_var=interp_var, interp_type=interp_type,
171
170
  name=name, snapdate=snapdate)
172
171
 
@@ -174,7 +173,7 @@ def yieldcurve_from_file(file):
174
173
  pillar_dates, pillar_dfs = [], []
175
174
  for pillar in pillars:
176
175
  date_str = pillar.get('expiry')
177
- date = dt.datetime.strptime(date_str, dates.DATE_FORMAT)
176
+ date = dt.datetime.strptime(date_str, dts.DATE_FORMAT)
178
177
  df = pillar.get('df')
179
178
  pillar_dates.append(date)
180
179
  pillar_dfs.append(df)
@@ -187,7 +186,7 @@ def data_file(name, date, **kwargs):
187
186
  folder = kwargs.get('folder', test_data_folder())
188
187
  name_folder = os.path.join(folder, name)
189
188
  os.makedirs(name_folder, exist_ok=True)
190
- file = os.path.join(name_folder, date.strftime(dates.DATE_FILE_FORMAT) + ".json")
189
+ file = os.path.join(name_folder, date.strftime(dts.DATE_FILE_FORMAT) + ".json")
191
190
  return file
192
191
 
193
192
 
@@ -201,7 +200,6 @@ def test_data_folder():
201
200
 
202
201
  if __name__ == "__main__":
203
202
  import matplotlib.pyplot as plt
204
- from sdevpy.utilities import dates
205
203
 
206
204
  valdate = dt.datetime(2026, 2, 15)
207
205
 
@@ -223,7 +221,7 @@ if __name__ == "__main__":
223
221
  curve.set_data(zdates, dfs)
224
222
 
225
223
  # Interpolate and display
226
- test_dates = [dates.advance(valdate, months=1*n) for n in range(1, 600)]
224
+ test_dates = [dts.advance(valdate, str(n) + 'm') for n in range(1, 600)]
227
225
  test_dfs = curve.discount(test_dates)
228
226
  test_times = timegrids.model_time(valdate, test_dates)
229
227
  test_zrs = -np.log(test_dfs) / test_times
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ import math
2
3
 
3
4
 
4
5
  FLOAT_INFTY = float('inf')
@@ -17,6 +18,8 @@ C_SQRT2PI = 2.50662827459518
17
18
  C_2_SQRTPI = 1.12837916709551257390
18
19
  k_2powneg32 = 2.3283064365387e-10 # Normalization factor for Sobol
19
20
 
21
+ TWO_PI = 2.0 * math.pi
22
+
20
23
 
21
24
  if __name__ == "__main__":
22
25
  print(f"FLOAT_INFTY: {FLOAT_INFTY}")
@@ -33,4 +33,3 @@ if __name__ == "__main__":
33
33
  print("In-house")
34
34
  print(sd_int)
35
35
  print(time.time() - start)
36
-