quantark 0.1.0__py3-none-any.whl

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 (399) hide show
  1. quantark/__init__.py +3 -0
  2. quantark/_compat.py +150 -0
  3. quantark/asset/__init__.py +8 -0
  4. quantark/asset/bond/__init__.py +2 -0
  5. quantark/asset/bond/engine/__init__.py +44 -0
  6. quantark/asset/bond/engine/analytical/__init__.py +12 -0
  7. quantark/asset/bond/engine/analytical/black_engine.py +583 -0
  8. quantark/asset/bond/engine/analytical/bond_forward_engine.py +390 -0
  9. quantark/asset/bond/engine/analytical/bond_futures_engine.py +569 -0
  10. quantark/asset/bond/engine/convertible/__init__.py +12 -0
  11. quantark/asset/bond/engine/convertible/convertible_bond_engine.py +800 -0
  12. quantark/asset/bond/engine/discount/__init__.py +10 -0
  13. quantark/asset/bond/engine/discount/bond_discount_engine.py +517 -0
  14. quantark/asset/bond/engine/discount/frn_engine.py +913 -0
  15. quantark/asset/bond/engine/pde/__init__.py +14 -0
  16. quantark/asset/bond/engine/pde/convertible/__init__.py +21 -0
  17. quantark/asset/bond/engine/pde/convertible/jump_diffusion_engine.py +603 -0
  18. quantark/asset/bond/engine/pde/convertible/pde_params.py +59 -0
  19. quantark/asset/bond/engine/pde/convertible/tf_engine.py +546 -0
  20. quantark/asset/bond/engine/tree/__init__.py +14 -0
  21. quantark/asset/bond/engine/tree/convertible/__init__.py +21 -0
  22. quantark/asset/bond/engine/tree/convertible/binomial_engine.py +488 -0
  23. quantark/asset/bond/engine/tree/convertible/tree_params.py +72 -0
  24. quantark/asset/bond/engine/tree/convertible/trinomial_engine.py +1341 -0
  25. quantark/asset/bond/product/__init__.py +37 -0
  26. quantark/asset/bond/product/base_bond_product.py +114 -0
  27. quantark/asset/bond/product/convertible/__init__.py +16 -0
  28. quantark/asset/bond/product/convertible/convertible_bond.py +595 -0
  29. quantark/asset/bond/product/couponbond/__init__.py +12 -0
  30. quantark/asset/bond/product/couponbond/fixed_bond.py +285 -0
  31. quantark/asset/bond/product/couponbond/frn.py +538 -0
  32. quantark/asset/bond/product/forward/__init__.py +9 -0
  33. quantark/asset/bond/product/forward/base_bond_forward.py +92 -0
  34. quantark/asset/bond/product/forward/bond_forward.py +335 -0
  35. quantark/asset/bond/product/futures/__init__.py +8 -0
  36. quantark/asset/bond/product/futures/bond_futures.py +532 -0
  37. quantark/asset/bond/product/option/__init__.py +9 -0
  38. quantark/asset/bond/product/option/euro_short_term_bond_option.py +231 -0
  39. quantark/asset/bond/riskmeasures/__init__.py +13 -0
  40. quantark/asset/bond/riskmeasures/bond_greeks_calculator.py +484 -0
  41. quantark/asset/bond/schedule/__init__.py +21 -0
  42. quantark/asset/bond/schedule/cashflow.py +595 -0
  43. quantark/asset/equity/__init__.py +11 -0
  44. quantark/asset/equity/analysis/__init__.py +4 -0
  45. quantark/asset/equity/analysis/autocallable_path_analyzer.py +257 -0
  46. quantark/asset/equity/engine/__init__.py +84 -0
  47. quantark/asset/equity/engine/analytical/__init__.py +37 -0
  48. quantark/asset/equity/engine/analytical/american_option_engine.py +682 -0
  49. quantark/asset/equity/engine/analytical/asian_option_analytical_engine.py +1102 -0
  50. quantark/asset/equity/engine/analytical/barrier_analytical_engine.py +455 -0
  51. quantark/asset/equity/engine/analytical/black_scholes_engine.py +322 -0
  52. quantark/asset/equity/engine/analytical/deltaone_engine.py +340 -0
  53. quantark/asset/equity/engine/analytical/digital_option_engine.py +168 -0
  54. quantark/asset/equity/engine/analytical/double_barrier_option_engine.py +481 -0
  55. quantark/asset/equity/engine/analytical/double_sharkfin_option_analytical_engine.py +508 -0
  56. quantark/asset/equity/engine/analytical/one_touch_analytical_engine.py +302 -0
  57. quantark/asset/equity/engine/analytical/range_accrual_analytical_engine.py +396 -0
  58. quantark/asset/equity/engine/analytical/single_sharkfin_option_analytical_engine.py +229 -0
  59. quantark/asset/equity/engine/base_engine.py +137 -0
  60. quantark/asset/equity/engine/event_stats.py +85 -0
  61. quantark/asset/equity/engine/mc/__init__.py +31 -0
  62. quantark/asset/equity/engine/mc/american_option_mc_engine.py +485 -0
  63. quantark/asset/equity/engine/mc/asian_option_mc_engine.py +678 -0
  64. quantark/asset/equity/engine/mc/barrier_option_mc_engine.py +726 -0
  65. quantark/asset/equity/engine/mc/digital_option_mc_engine.py +419 -0
  66. quantark/asset/equity/engine/mc/double_sharkfin_option_mc_engine.py +676 -0
  67. quantark/asset/equity/engine/mc/euro_mc_engine.py +423 -0
  68. quantark/asset/equity/engine/mc/phoenix_mc_engine.py +1206 -0
  69. quantark/asset/equity/engine/mc/range_accrual_mc_engine.py +738 -0
  70. quantark/asset/equity/engine/mc/single_sharkfin_option_mc_engine.py +549 -0
  71. quantark/asset/equity/engine/mc/snowball_mc_engine.py +2250 -0
  72. quantark/asset/equity/engine/pde/__init__.py +36 -0
  73. quantark/asset/equity/engine/pde/american_pde_solver.py +211 -0
  74. quantark/asset/equity/engine/pde/barrier_pde_solver.py +692 -0
  75. quantark/asset/equity/engine/pde/base_pde_solver.py +994 -0
  76. quantark/asset/equity/engine/pde/double_barrier_pde_solver.py +510 -0
  77. quantark/asset/equity/engine/pde/double_one_touch_pde_solver.py +435 -0
  78. quantark/asset/equity/engine/pde/european_pde_solver.py +170 -0
  79. quantark/asset/equity/engine/pde/ko_reset_snowball_pde_solver.py +477 -0
  80. quantark/asset/equity/engine/pde/one_touch_pde_solver.py +439 -0
  81. quantark/asset/equity/engine/pde/phoenix_pde_solver.py +613 -0
  82. quantark/asset/equity/engine/pde/snowball_pde_solver.py +1810 -0
  83. quantark/asset/equity/engine/pde/spatial_grid.py +750 -0
  84. quantark/asset/equity/engine/pde/time_grid.py +308 -0
  85. quantark/asset/equity/engine/pde_engine.py +238 -0
  86. quantark/asset/equity/engine/quad/__init__.py +23 -0
  87. quantark/asset/equity/engine/quad/discrete_quad_engine.py +106 -0
  88. quantark/asset/equity/engine/quad/european_quad_engine.py +325 -0
  89. quantark/asset/equity/engine/quad/ko_reset_snowball_quad_engine.py +362 -0
  90. quantark/asset/equity/engine/quad/phoenix_quad_engine.py +614 -0
  91. quantark/asset/equity/engine/quad/quad_adapters.py +1260 -0
  92. quantark/asset/equity/engine/quad/quad_core.py +513 -0
  93. quantark/asset/equity/engine/quad/quad_math.py +219 -0
  94. quantark/asset/equity/engine/quad/snowball_quad_engine.py +1137 -0
  95. quantark/asset/equity/engine/validation/script/benchmark_check_american_analytical.py +117 -0
  96. quantark/asset/equity/engine/validation/script/benchmark_check_american_pde.py +114 -0
  97. quantark/asset/equity/engine/validation/script/benchmark_check_asian_analytical.py +440 -0
  98. quantark/asset/equity/engine/validation/script/benchmark_check_barrier_analytical.py +269 -0
  99. quantark/asset/equity/engine/validation/script/benchmark_check_barrier_pde_solver.py +636 -0
  100. quantark/asset/equity/engine/validation/script/benchmark_check_digital_option.py +256 -0
  101. quantark/asset/equity/engine/validation/script/benchmark_check_snowball_pde_solver.py +807 -0
  102. quantark/asset/equity/engine/validation/script/boundary_check_american_analytical.py +290 -0
  103. quantark/asset/equity/engine/validation/script/boundary_check_american_pde.py +242 -0
  104. quantark/asset/equity/engine/validation/script/boundary_check_asian_analytical.py +612 -0
  105. quantark/asset/equity/engine/validation/script/boundary_check_barrier_analytical.py +434 -0
  106. quantark/asset/equity/engine/validation/script/boundary_check_barrier_pde_solver.py +748 -0
  107. quantark/asset/equity/engine/validation/script/boundary_check_digital_option.py +575 -0
  108. quantark/asset/equity/engine/validation/script/boundary_check_snowball_pde_solver.py +1101 -0
  109. quantark/asset/equity/engine/validation/script/greeks_check_digital_option.py +349 -0
  110. quantark/asset/equity/engine/validation/script/mc_comparison_barrier_pde.py +270 -0
  111. quantark/asset/equity/engine/validation/script/quick_mc_compare.py +51 -0
  112. quantark/asset/equity/engine/validation/script/validation_stepdown_improved.py +97 -0
  113. quantark/asset/equity/param/__init__.py +24 -0
  114. quantark/asset/equity/param/engine_param_profiles.py +325 -0
  115. quantark/asset/equity/param/engine_params.py +728 -0
  116. quantark/asset/equity/process/__init__.py +7 -0
  117. quantark/asset/equity/process/bsm/__init__.py +7 -0
  118. quantark/asset/equity/process/bsm/bsm_process.py +108 -0
  119. quantark/asset/equity/process/bsm/qmc_brownian_bridge.py +401 -0
  120. quantark/asset/equity/process/bsm/qmc_path_generator.py +694 -0
  121. quantark/asset/equity/process/bsm/qmc_rqmc_driver.py +163 -0
  122. quantark/asset/equity/process/bsm/qmc_sobol.py +195 -0
  123. quantark/asset/equity/process/bsm/qmc_variance_reduction.py +292 -0
  124. quantark/asset/equity/product/__init__.py +8 -0
  125. quantark/asset/equity/product/base_equity_product.py +72 -0
  126. quantark/asset/equity/product/deltaone/__init__.py +22 -0
  127. quantark/asset/equity/product/deltaone/base_deltaone_product.py +147 -0
  128. quantark/asset/equity/product/deltaone/futures.py +485 -0
  129. quantark/asset/equity/product/deltaone/spot_instrument.py +118 -0
  130. quantark/asset/equity/product/option/__init__.py +104 -0
  131. quantark/asset/equity/product/option/american_option.py +114 -0
  132. quantark/asset/equity/product/option/asian_option.py +531 -0
  133. quantark/asset/equity/product/option/barrier_option.py +289 -0
  134. quantark/asset/equity/product/option/base_equity_option.py +659 -0
  135. quantark/asset/equity/product/option/digital_option.py +102 -0
  136. quantark/asset/equity/product/option/double_barrier_option.py +286 -0
  137. quantark/asset/equity/product/option/double_one_touch_option.py +310 -0
  138. quantark/asset/equity/product/option/double_sharkfin_option.py +466 -0
  139. quantark/asset/equity/product/option/european_vanilla_option.py +103 -0
  140. quantark/asset/equity/product/option/ko_reset_snowball_option.py +563 -0
  141. quantark/asset/equity/product/option/observation_schedule.py +530 -0
  142. quantark/asset/equity/product/option/one_touch_option.py +287 -0
  143. quantark/asset/equity/product/option/phoenix_config.py +116 -0
  144. quantark/asset/equity/product/option/phoenix_helpers.py +576 -0
  145. quantark/asset/equity/product/option/phoenix_option.py +1167 -0
  146. quantark/asset/equity/product/option/range_accrual_config.py +288 -0
  147. quantark/asset/equity/product/option/range_accrual_helpers.py +608 -0
  148. quantark/asset/equity/product/option/range_accrual_option.py +526 -0
  149. quantark/asset/equity/product/option/single_sharkfin_option.py +420 -0
  150. quantark/asset/equity/product/option/snowball_config.py +261 -0
  151. quantark/asset/equity/product/option/snowball_helpers.py +977 -0
  152. quantark/asset/equity/product/option/snowball_option.py +1242 -0
  153. quantark/asset/equity/report/__init__.py +15 -0
  154. quantark/asset/equity/report/autocallable_risk_report.py +2118 -0
  155. quantark/asset/equity/report/plotting.py +87 -0
  156. quantark/asset/equity/report/snowball_risk_comparison_report.py +2230 -0
  157. quantark/asset/equity/report/surfaces.py +123 -0
  158. quantark/asset/equity/report/term_structure.py +126 -0
  159. quantark/asset/equity/riskmeasures/__init__.py +7 -0
  160. quantark/asset/equity/riskmeasures/greeks_calculator.py +1204 -0
  161. quantark/asset/rate/__init__.py +58 -0
  162. quantark/asset/rate/engine/__init__.py +25 -0
  163. quantark/asset/rate/engine/cap_floor_engine.py +514 -0
  164. quantark/asset/rate/engine/fra_engine.py +286 -0
  165. quantark/asset/rate/engine/irs_discount_engine.py +891 -0
  166. quantark/asset/rate/engine/swaption_engine.py +587 -0
  167. quantark/asset/rate/product/__init__.py +67 -0
  168. quantark/asset/rate/product/cap_floor.py +550 -0
  169. quantark/asset/rate/product/fra.py +219 -0
  170. quantark/asset/rate/product/irs.py +1223 -0
  171. quantark/asset/rate/product/swaption.py +372 -0
  172. quantark/backtest/__init__.py +153 -0
  173. quantark/backtest/base.py +263 -0
  174. quantark/backtest/dashboard.py +874 -0
  175. quantark/backtest/equity/__init__.py +35 -0
  176. quantark/backtest/equity/config.py +118 -0
  177. quantark/backtest/equity/engine.py +408 -0
  178. quantark/backtest/equity/hedge_executor.py +374 -0
  179. quantark/backtest/equity/metrics.py +396 -0
  180. quantark/backtest/equity/results.py +232 -0
  181. quantark/backtest/equity/state.py +252 -0
  182. quantark/backtest/examples/__init__.py +4 -0
  183. quantark/backtest/examples/advanced_backtest.py +345 -0
  184. quantark/backtest/examples/basic_delta_hedge.py +246 -0
  185. quantark/backtest/examples/fi_dv01_hedge.py +267 -0
  186. quantark/backtest/fi/__init__.py +30 -0
  187. quantark/backtest/fi/config.py +114 -0
  188. quantark/backtest/fi/engine.py +378 -0
  189. quantark/backtest/fi/hedge_executor.py +254 -0
  190. quantark/backtest/fi/metrics.py +308 -0
  191. quantark/backtest/fi/results.py +193 -0
  192. quantark/backtest/fi/state.py +212 -0
  193. quantark/backtest/logger.py +393 -0
  194. quantark/backtest/otc/__init__.py +74 -0
  195. quantark/backtest/otc/_replay.py +637 -0
  196. quantark/backtest/otc/book_engine.py +587 -0
  197. quantark/backtest/otc/config.py +175 -0
  198. quantark/backtest/otc/dashboard.py +1006 -0
  199. quantark/backtest/otc/engine.py +420 -0
  200. quantark/backtest/otc/engine_factory.py +138 -0
  201. quantark/backtest/otc/market.py +216 -0
  202. quantark/backtest/otc/results.py +107 -0
  203. quantark/backtest/otc/state.py +166 -0
  204. quantark/backtest/report_generator.py +608 -0
  205. quantark/backtest/strategy/__init__.py +28 -0
  206. quantark/backtest/strategy/base_strategy.py +235 -0
  207. quantark/backtest/strategy/convexity_neutral_strategy.py +247 -0
  208. quantark/backtest/strategy/delta_neutral_strategy.py +283 -0
  209. quantark/backtest/strategy/dv01_neutral_strategy.py +283 -0
  210. quantark/backtest/transaction_costs.py +485 -0
  211. quantark/backtest/visualizer.py +1019 -0
  212. quantark/cashleg/__init__.py +31 -0
  213. quantark/cashleg/accrual_leg.py +120 -0
  214. quantark/cashleg/base.py +48 -0
  215. quantark/cashleg/base_amount.py +60 -0
  216. quantark/cashleg/deterministic_leg.py +39 -0
  217. quantark/cashleg/event_distribution.py +262 -0
  218. quantark/cashleg/fixed_payoff_leg.py +92 -0
  219. quantark/cashleg/leg_schedule.py +95 -0
  220. quantark/cashleg/leg_valuator.py +40 -0
  221. quantark/dynamicscenario/__init__.py +97 -0
  222. quantark/dynamicscenario/base.py +297 -0
  223. quantark/dynamicscenario/config.py +122 -0
  224. quantark/dynamicscenario/engine.py +703 -0
  225. quantark/dynamicscenario/equity/__init__.py +14 -0
  226. quantark/dynamicscenario/fi/__init__.py +24 -0
  227. quantark/dynamicscenario/fi/config.py +149 -0
  228. quantark/dynamicscenario/fi/engine.py +500 -0
  229. quantark/dynamicscenario/fi/results.py +503 -0
  230. quantark/dynamicscenario/path/__init__.py +17 -0
  231. quantark/dynamicscenario/path/day_path.py +397 -0
  232. quantark/dynamicscenario/path/fi_path_library.py +488 -0
  233. quantark/dynamicscenario/path/path_builder.py +726 -0
  234. quantark/dynamicscenario/path/path_library.py +620 -0
  235. quantark/dynamicscenario/report/__init__.py +12 -0
  236. quantark/dynamicscenario/report/dynamic_report.py +1175 -0
  237. quantark/dynamicscenario/report/visualizer.py +1586 -0
  238. quantark/dynamicscenario/results/__init__.py +19 -0
  239. quantark/dynamicscenario/results/dynamic_results.py +579 -0
  240. quantark/dynamicscenario/results/result_exporter.py +438 -0
  241. quantark/param/__init__.py +75 -0
  242. quantark/param/basis/__init__.py +19 -0
  243. quantark/param/basis/basis_yield.py +301 -0
  244. quantark/param/div/__init__.py +16 -0
  245. quantark/param/div/dividend_yield.py +123 -0
  246. quantark/param/index/__init__.py +52 -0
  247. quantark/param/index/rate_index.py +568 -0
  248. quantark/param/quote/__init__.py +7 -0
  249. quantark/param/quote/spot_quote.py +35 -0
  250. quantark/param/rrf/__init__.py +22 -0
  251. quantark/param/rrf/rate_curve.py +436 -0
  252. quantark/param/vol/__init__.py +6 -0
  253. quantark/param/vol/vol_surface.py +118 -0
  254. quantark/portfolio/__init__.py +61 -0
  255. quantark/portfolio/base.py +203 -0
  256. quantark/portfolio/equity/__init__.py +17 -0
  257. quantark/portfolio/equity/portfolio.py +391 -0
  258. quantark/portfolio/equity/position.py +368 -0
  259. quantark/portfolio/fi/__init__.py +14 -0
  260. quantark/portfolio/fi/portfolio.py +424 -0
  261. quantark/portfolio/fi/position.py +272 -0
  262. quantark/portfolio/portfolio_snapshot.py +221 -0
  263. quantark/portfolio/portfolio_storage.py +414 -0
  264. quantark/priceenv/__init__.py +7 -0
  265. quantark/priceenv/pricing_environment.py +196 -0
  266. quantark/rfq/__init__.py +32 -0
  267. quantark/rfq/builders.py +102 -0
  268. quantark/rfq/models.py +214 -0
  269. quantark/rfq/registry.py +611 -0
  270. quantark/rfq/service.py +237 -0
  271. quantark/simm/__init__.py +155 -0
  272. quantark/simm/calibration/__init__.py +206 -0
  273. quantark/simm/calibration/accessors.py +439 -0
  274. quantark/simm/calibration/commodity.py +156 -0
  275. quantark/simm/calibration/credit_non_qualifying.py +79 -0
  276. quantark/simm/calibration/credit_qualifying.py +130 -0
  277. quantark/simm/calibration/cross_risk.py +39 -0
  278. quantark/simm/calibration/equity.py +125 -0
  279. quantark/simm/calibration/fx.py +92 -0
  280. quantark/simm/calibration/ir.py +152 -0
  281. quantark/simm/calibration/version.py +33 -0
  282. quantark/simm/config.py +186 -0
  283. quantark/simm/crif/__init__.py +35 -0
  284. quantark/simm/crif/models.py +230 -0
  285. quantark/simm/crif/parser.py +585 -0
  286. quantark/simm/engines/__init__.py +62 -0
  287. quantark/simm/engines/aggregation/__init__.py +67 -0
  288. quantark/simm/engines/aggregation/addon.py +141 -0
  289. quantark/simm/engines/aggregation/bucket_aggregator.py +298 -0
  290. quantark/simm/engines/aggregation/concentration.py +349 -0
  291. quantark/simm/engines/aggregation/product_class_aggregator.py +183 -0
  292. quantark/simm/engines/aggregation/risk_class_aggregator.py +403 -0
  293. quantark/simm/engines/aggregation/simm_calculator.py +430 -0
  294. quantark/simm/engines/aggregation/weighted_sensitivity.py +272 -0
  295. quantark/simm/engines/base.py +231 -0
  296. quantark/simm/engines/classification/__init__.py +10 -0
  297. quantark/simm/engines/classification/bucket_mapper.py +347 -0
  298. quantark/simm/engines/factory.py +137 -0
  299. quantark/simm/engines/portfolio_adapter.py +336 -0
  300. quantark/simm/engines/result.py +176 -0
  301. quantark/simm/engines/risk_class/__init__.py +18 -0
  302. quantark/simm/engines/risk_class/equity_engine.py +263 -0
  303. quantark/simm/engines/risk_class/ir_engine.py +264 -0
  304. quantark/simm/report/__init__.py +17 -0
  305. quantark/simm/report/crif_export.py +284 -0
  306. quantark/simm/report/excel_generator.py +401 -0
  307. quantark/simm/report/html_generator.py +840 -0
  308. quantark/simm/results/__init__.py +38 -0
  309. quantark/simm/results/attribution.py +313 -0
  310. quantark/simm/results/simm_result.py +339 -0
  311. quantark/simm/results/whatif.py +268 -0
  312. quantark/simm/sensitivity.py +533 -0
  313. quantark/simm/taxonomy.py +416 -0
  314. quantark/stresstest/__init__.py +67 -0
  315. quantark/stresstest/base.py +116 -0
  316. quantark/stresstest/config.py +5 -0
  317. quantark/stresstest/engine.py +5 -0
  318. quantark/stresstest/equity/__init__.py +17 -0
  319. quantark/stresstest/equity/config.py +69 -0
  320. quantark/stresstest/equity/engine.py +272 -0
  321. quantark/stresstest/equity/report/__init__.py +7 -0
  322. quantark/stresstest/equity/report/report_generator.py +423 -0
  323. quantark/stresstest/equity/report/visualizer.py +328 -0
  324. quantark/stresstest/equity/results.py +145 -0
  325. quantark/stresstest/fi/__init__.py +15 -0
  326. quantark/stresstest/fi/config.py +59 -0
  327. quantark/stresstest/fi/engine.py +213 -0
  328. quantark/stresstest/fi/metrics.py +60 -0
  329. quantark/stresstest/fi/results.py +64 -0
  330. quantark/stresstest/report/__init__.py +12 -0
  331. quantark/stresstest/report/report_generator.py +5 -0
  332. quantark/stresstest/report/visualizer.py +5 -0
  333. quantark/stresstest/results/__init__.py +16 -0
  334. quantark/stresstest/results/result_aggregator.py +325 -0
  335. quantark/stresstest/results/result_exporter.py +286 -0
  336. quantark/stresstest/results/stress_results.py +5 -0
  337. quantark/stresstest/scenario/__init__.py +13 -0
  338. quantark/stresstest/scenario/scenario.py +242 -0
  339. quantark/stresstest/scenario/scenario_builder.py +376 -0
  340. quantark/stresstest/scenario/scenario_library.py +435 -0
  341. quantark/stresstest/scenario/scenario_storage.py +224 -0
  342. quantark/stresstest/stress/__init__.py +13 -0
  343. quantark/stresstest/stress/stress_applicator.py +590 -0
  344. quantark/stresstest/stress/stress_types.py +142 -0
  345. quantark/util/__init__.py +23 -0
  346. quantark/util/barrier_shift.py +44 -0
  347. quantark/util/calendar/__init__.py +27 -0
  348. quantark/util/calendar/business_calendar.py +584 -0
  349. quantark/util/calendar/day_counter.py +517 -0
  350. quantark/util/calendar/holidayfile/china.csv +1920 -0
  351. quantark/util/calendar/holidayfile/china_sse.csv +1462 -0
  352. quantark/util/enum/__init__.py +81 -0
  353. quantark/util/enum/bond_enums.py +112 -0
  354. quantark/util/enum/deltaone_enums.py +16 -0
  355. quantark/util/enum/engine_enums.py +137 -0
  356. quantark/util/enum/greeks_enums.py +29 -0
  357. quantark/util/enum/option_enums.py +221 -0
  358. quantark/util/exceptions.py +66 -0
  359. quantark/util/marketdata/__init__.py +39 -0
  360. quantark/util/marketdata/adapter/base_adapter.py +203 -0
  361. quantark/util/marketdata/adapter/mock_adapter.py +265 -0
  362. quantark/util/marketdata/converter.py +289 -0
  363. quantark/util/marketdata/example_usage.py +314 -0
  364. quantark/util/marketdata/generator/__init__.py +7 -0
  365. quantark/util/marketdata/generator/mock_generator.py +466 -0
  366. quantark/util/marketdata/models.py +358 -0
  367. quantark/util/marketdata/storage/__init__.py +7 -0
  368. quantark/util/marketdata/storage/parquet_storage.py +340 -0
  369. quantark/util/numerical/__init__.py +98 -0
  370. quantark/util/numerical/comparison.py +219 -0
  371. quantark/util/numerical/constants.py +98 -0
  372. quantark/util/numerical/formatting.py +380 -0
  373. quantark/util/numerical/pnl.py +17 -0
  374. quantark/util/numerical/safe_math.py +238 -0
  375. quantark/util/numerical/validation.py +315 -0
  376. quantark/var/__init__.py +39 -0
  377. quantark/var/attribution.py +398 -0
  378. quantark/var/backtest/__init__.py +7 -0
  379. quantark/var/backtest/var_backtester.py +309 -0
  380. quantark/var/base.py +63 -0
  381. quantark/var/config.py +219 -0
  382. quantark/var/engines/__init__.py +13 -0
  383. quantark/var/engines/historical.py +925 -0
  384. quantark/var/engines/monte_carlo.py +870 -0
  385. quantark/var/engines/parametric.py +1199 -0
  386. quantark/var/results/__init__.py +16 -0
  387. quantark/var/results/incremental_var_result.py +131 -0
  388. quantark/var/results/var_report.py +346 -0
  389. quantark/var/results/var_result.py +134 -0
  390. quantark/var/risk_factors/__init__.py +22 -0
  391. quantark/var/risk_factors/base.py +41 -0
  392. quantark/var/risk_factors/equity_factors.py +158 -0
  393. quantark/var/risk_factors/fi_factors.py +99 -0
  394. quantark-0.1.0.dist-info/METADATA +351 -0
  395. quantark-0.1.0.dist-info/RECORD +399 -0
  396. quantark-0.1.0.dist-info/WHEEL +4 -0
  397. quantark-0.1.0.dist-info/licenses/LICENSE +202 -0
  398. quantark-0.1.0.dist-info/licenses/NOTICE +2 -0
  399. quantark_compat.pth +1 -0
@@ -0,0 +1,477 @@
1
+ """
2
+ PDE solver for KO-reset Snowball options using the Two-Surface method.
3
+
4
+ Applies the pre-KI KO schedule to the V0 surface and the post-KI KO schedule
5
+ to the V1 surface (ABSOLUTE post-KO mode only).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from collections import OrderedDict
11
+ from time import perf_counter
12
+ from typing import Dict, List, Optional, Tuple
13
+
14
+ import numpy as np
15
+
16
+ from quantark.asset.equity.engine.pde.base_pde_solver import PDESolutionResult
17
+ from quantark.asset.equity.engine.pde.snowball_pde_solver import SnowballPDESolver
18
+ from quantark.asset.equity.product.option.ko_reset_snowball_option import (
19
+ KnockOutResetSnowballOption,
20
+ )
21
+ from quantark.asset.equity.product.option.observation_schedule import ResolvedObservationRecord
22
+ from quantark.priceenv import PricingEnvironment
23
+ from quantark.util.enum import CouponPayType, ObservationType, PostKOScheduleMode
24
+ from quantark.util.exceptions import PricingError, ValidationError
25
+ from quantark.util.numerical import is_close, is_zero
26
+
27
+
28
+ class KOResetSnowballPDESolver(SnowballPDESolver):
29
+ """
30
+ PDE solver for KO-reset Snowball options using the two-surface method.
31
+
32
+ - V0 surface uses pre-KI KO schedule
33
+ - V1 surface uses post-KI KO schedule
34
+ """
35
+
36
+ # Override class attributes for product type checking
37
+ _supported_product_type: type = KnockOutResetSnowballOption
38
+ _solver_name: str = "KOResetSnowballPDESolver"
39
+
40
+ def __init__(self, params=None):
41
+ super().__init__(params=params)
42
+ self._pre_ko_records_cache: "OrderedDict[Tuple, List[ResolvedObservationRecord]]" = (
43
+ OrderedDict()
44
+ )
45
+ self._post_ko_records_cache: "OrderedDict[Tuple, List[ResolvedObservationRecord]]" = (
46
+ OrderedDict()
47
+ )
48
+ self._pre_ko_observation_indices: Dict[int, ResolvedObservationRecord] = {}
49
+ self._post_ko_observation_indices: Dict[int, ResolvedObservationRecord] = {}
50
+ self._pre_ko_terminal_record: Optional[ResolvedObservationRecord] = None
51
+ self._post_ko_terminal_record: Optional[ResolvedObservationRecord] = None
52
+ self._has_pre_terminal_ko: bool = False
53
+ self._has_post_terminal_ko: bool = False
54
+
55
+ # price() is inherited from SnowballPDESolver using _check_product_type()
56
+
57
+ def calculate_event_stats(
58
+ self, product: KnockOutResetSnowballOption, pricing_env: PricingEnvironment
59
+ ) -> Optional[object]:
60
+ return None
61
+
62
+ def _validate_product(self, product: KnockOutResetSnowballOption) -> None:
63
+ super()._validate_product(product)
64
+ if product.post_ko_mode != PostKOScheduleMode.ABSOLUTE:
65
+ raise ValidationError(
66
+ "KOResetSnowballPDESolver only supports PostKOScheduleMode.ABSOLUTE"
67
+ )
68
+ if product.post_barrier_config.ko_observation_type != ObservationType.DISCRETE:
69
+ raise ValidationError("Post-KO monitoring must be discrete for PDE solver.")
70
+ if product.post_barrier_config.ko_observation_schedule is None:
71
+ raise ValidationError("Post-KO observation schedule is required.")
72
+
73
+ def _resolve_ko_records(
74
+ self,
75
+ product: KnockOutResetSnowballOption,
76
+ pricing_env: PricingEnvironment,
77
+ config,
78
+ ) -> List[ResolvedObservationRecord]:
79
+ resolved_schedule, rates, schedule_records = product._resolve_ko_schedule(
80
+ config, pricing_env
81
+ )
82
+ principal_component = (
83
+ product.initial_price * product.contract_multiplier
84
+ if product.payoff_config.include_principal
85
+ else 0.0
86
+ )
87
+ maturity_time: Optional[float] = None
88
+ ko_records: List[ResolvedObservationRecord] = []
89
+ for idx, rec in enumerate(resolved_schedule):
90
+ rate = rates[idx]
91
+ schedule_record = schedule_records[idx]
92
+ accrual_factor = product.compute_ko_accrual_factor(
93
+ rec.observation_time, schedule_record, pricing_env
94
+ )
95
+ coupon_payoff = (
96
+ product.initial_price
97
+ * product.contract_multiplier
98
+ * float(rate)
99
+ * float(accrual_factor)
100
+ )
101
+ payoff = principal_component + coupon_payoff
102
+
103
+ settlement_time = rec.settlement_time
104
+ if product.accrual_config.coupon_pay_type == CouponPayType.EXPIRY:
105
+ maturity_time = (
106
+ maturity_time
107
+ if maturity_time is not None
108
+ else product.get_maturity(pricing_env)
109
+ )
110
+ settlement_time = maturity_time
111
+
112
+ ko_records.append(
113
+ ResolvedObservationRecord(
114
+ observation_time=rec.observation_time,
115
+ barrier=rec.barrier,
116
+ payoff=payoff,
117
+ settlement_time=settlement_time,
118
+ )
119
+ )
120
+ return ko_records
121
+
122
+ def _get_cached_pre_ko_records(
123
+ self, pricing_env: PricingEnvironment, product: KnockOutResetSnowballOption
124
+ ) -> List[ResolvedObservationRecord]:
125
+ if not self._is_cache_enabled():
126
+ return self._resolve_ko_records(
127
+ product, pricing_env, product.barrier_config
128
+ )
129
+ key = self._observation_cache_key(pricing_env, product, "pre_ko")
130
+ cached = self._pre_ko_records_cache.get(key)
131
+ if cached is not None:
132
+ self._pre_ko_records_cache.move_to_end(key)
133
+ return cached
134
+ records = self._resolve_ko_records(
135
+ product, pricing_env, product.barrier_config
136
+ )
137
+ self._pre_ko_records_cache[key] = records
138
+ self._pre_ko_records_cache.move_to_end(key)
139
+ if len(self._pre_ko_records_cache) > self.params.grid_cache_max_entries:
140
+ self._pre_ko_records_cache.popitem(last=False)
141
+ return records
142
+
143
+ def _get_cached_post_ko_records(
144
+ self, pricing_env: PricingEnvironment, product: KnockOutResetSnowballOption
145
+ ) -> List[ResolvedObservationRecord]:
146
+ if not self._is_cache_enabled():
147
+ return self._resolve_ko_records(
148
+ product, pricing_env, product.post_barrier_config
149
+ )
150
+ key = self._observation_cache_key(pricing_env, product, "post_ko")
151
+ cached = self._post_ko_records_cache.get(key)
152
+ if cached is not None:
153
+ self._post_ko_records_cache.move_to_end(key)
154
+ return cached
155
+ records = self._resolve_ko_records(
156
+ product, pricing_env, product.post_barrier_config
157
+ )
158
+ self._post_ko_records_cache[key] = records
159
+ self._post_ko_records_cache.move_to_end(key)
160
+ if len(self._post_ko_records_cache) > self.params.grid_cache_max_entries:
161
+ self._post_ko_records_cache.popitem(last=False)
162
+ return records
163
+
164
+ def _get_cached_ko_records(
165
+ self, pricing_env: PricingEnvironment, product: KnockOutResetSnowballOption
166
+ ) -> List[ResolvedObservationRecord]:
167
+ return self._get_cached_pre_ko_records(pricing_env, product)
168
+
169
+ def _build_grids(
170
+ self,
171
+ product: KnockOutResetSnowballOption,
172
+ pricing_env: PricingEnvironment,
173
+ spot: float,
174
+ sigma: float,
175
+ tau: float,
176
+ r: float,
177
+ q: float,
178
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
179
+ result = super()._build_grids(product, pricing_env, spot, sigma, tau, r, q)
180
+ x_vec, s_vec, dx_vec, t_vec, dt_vec = result
181
+
182
+ # Copy pre-KO indices built by parent.
183
+ self._pre_ko_observation_indices = dict(self._ko_observation_indices)
184
+ self._pre_ko_terminal_record = self._ko_terminal_record
185
+ self._has_pre_terminal_ko = self._has_terminal_ko
186
+
187
+ # Build post-KO indices.
188
+ self._post_ko_observation_indices.clear()
189
+ self._post_ko_terminal_record = None
190
+ self._has_post_terminal_ko = False
191
+
192
+ post_records = self._filter_observations_by_tau(
193
+ self._get_cached_post_ko_records(pricing_env, product), tau
194
+ )
195
+
196
+ for rec in post_records:
197
+ obs_time = rec.observation_time
198
+ if is_close(obs_time, 0.0):
199
+ self._post_ko_observation_indices[0] = rec
200
+ elif is_close(obs_time, tau):
201
+ self._post_ko_terminal_record = rec
202
+ self._has_post_terminal_ko = True
203
+ elif 0.0 < obs_time < tau:
204
+ idx = self._aligned_time_index(t_vec, obs_time, "Post-KO observation")
205
+ self._post_ko_observation_indices[idx] = rec
206
+
207
+ return result
208
+
209
+ def _get_event_times(
210
+ self, product: KnockOutResetSnowballOption, tau: float
211
+ ) -> Optional[List[float]]:
212
+ event_times = super()._get_event_times(product, tau) or []
213
+ post_schedule = product.post_barrier_config.ko_observation_schedule
214
+ if post_schedule is not None:
215
+ for rec in post_schedule.records:
216
+ if rec.observation_time is not None:
217
+ t = rec.observation_time
218
+ if 0 < t < tau:
219
+ event_times.append(t)
220
+ elif product.post_barrier_config.ko_observation_dates is not None:
221
+ for t in product.post_barrier_config.ko_observation_dates:
222
+ if 0 < t < tau:
223
+ event_times.append(t)
224
+ return sorted(set(event_times)) if event_times else None
225
+
226
+ def get_critical_points(
227
+ self, product: KnockOutResetSnowballOption, pricing_env: PricingEnvironment
228
+ ) -> List[float]:
229
+ points = super().get_critical_points(product, pricing_env)
230
+ post_barrier = product.post_barrier_config.ko_barrier
231
+ if isinstance(post_barrier, list):
232
+ points.extend([b for b in post_barrier if b > 0])
233
+ elif post_barrier > 0:
234
+ points.append(post_barrier)
235
+ return sorted(set([p for p in points if p > 0]))
236
+
237
+ def _get_barriers(self, product: KnockOutResetSnowballOption) -> List[float]:
238
+ barriers = super()._get_barriers(product)
239
+ post_barrier = product.post_barrier_config.ko_barrier
240
+ if isinstance(post_barrier, list):
241
+ barriers.extend(post_barrier)
242
+ elif post_barrier > 0:
243
+ barriers.append(post_barrier)
244
+ return barriers
245
+
246
+ def _grid_cache_key(
247
+ self,
248
+ product: KnockOutResetSnowballOption,
249
+ pricing_env: PricingEnvironment,
250
+ spot: float,
251
+ sigma: float,
252
+ tau: float,
253
+ r: float,
254
+ q: float,
255
+ ) -> Tuple:
256
+ base_key = super()._grid_cache_key(product, pricing_env, spot, sigma, tau, r, q)
257
+ post_records = self._get_cached_post_ko_records(pricing_env, product)
258
+ post_key = tuple(
259
+ sorted(
260
+ (
261
+ round(rec.observation_time, 12),
262
+ round(rec.barrier if rec.barrier is not None else 0.0, 12),
263
+ )
264
+ for rec in post_records
265
+ )
266
+ )
267
+ return base_key + (post_key,)
268
+
269
+ def _solve(
270
+ self, product: KnockOutResetSnowballOption, pricing_env: PricingEnvironment
271
+ ) -> PDESolutionResult:
272
+ spot = pricing_env.spot
273
+ tau = product.get_maturity(pricing_env)
274
+
275
+ ki_continuous = (
276
+ product.barrier_config.ki_continuous
277
+ or product.barrier_config.ki_observation_type == ObservationType.CONTINUOUS
278
+ )
279
+ knocked_in_at_valuation = self._is_knocked_in_at_valuation(
280
+ product, spot, pricing_env, ki_continuous=ki_continuous
281
+ )
282
+ self._knocked_in_at_valuation = knocked_in_at_valuation
283
+
284
+ strike = product.strike
285
+ r = pricing_env.get_rate(tau)
286
+ q = pricing_env.get_div_yield(tau)
287
+ sigma = pricing_env.get_vol(strike, tau)
288
+
289
+ self._is_reverse = product.is_reverse
290
+ self._ki_continuous = ki_continuous
291
+ if product.has_ki_barrier:
292
+ ki_barrier = product.barrier_config.ki_barrier
293
+ if isinstance(ki_barrier, list):
294
+ self._ki_barrier = ki_barrier[0]
295
+ else:
296
+ self._ki_barrier = ki_barrier
297
+
298
+ if self._profile_enabled:
299
+ self._reset_profile_stats()
300
+
301
+ if self._profile_enabled:
302
+ t0 = perf_counter()
303
+ x_vec, s_vec, dx_vec, t_vec, dt_vec = self._build_grids(
304
+ product, pricing_env, spot, sigma, tau, r, q
305
+ )
306
+ if self._profile_enabled:
307
+ self._profile_stats["grid_build"] += perf_counter() - t0
308
+
309
+ num_x, num_t = len(x_vec), len(t_vec)
310
+ self._grid_v0 = np.zeros((num_x, num_t))
311
+ self._grid_v1 = np.zeros((num_x, num_t))
312
+
313
+ self._set_terminal_condition_v0(
314
+ self._grid_v0, x_vec, s_vec, product, pricing_env
315
+ )
316
+ self._set_terminal_condition_v1(
317
+ self._grid_v1, x_vec, s_vec, product, pricing_env
318
+ )
319
+
320
+ if self._has_pre_terminal_ko and self._pre_ko_terminal_record is not None:
321
+ self._apply_terminal_ko_single(
322
+ self._grid_v0,
323
+ s_vec,
324
+ product,
325
+ pricing_env,
326
+ self._pre_ko_terminal_record,
327
+ )
328
+
329
+ if (
330
+ self._has_post_terminal_ko
331
+ and self._post_ko_terminal_record is not None
332
+ and not product.barrier_config.disable_ko_after_ki
333
+ ):
334
+ self._apply_terminal_ko_single(
335
+ self._grid_v1,
336
+ s_vec,
337
+ product,
338
+ pricing_env,
339
+ self._post_ko_terminal_record,
340
+ )
341
+
342
+ if product.has_ki_barrier:
343
+ is_terminal_ki = self._ki_continuous
344
+ if not is_terminal_ki:
345
+ if (num_t - 1) in self._ki_observation_indices:
346
+ is_terminal_ki = True
347
+ if is_terminal_ki:
348
+ self._apply_ki_jump(
349
+ self._grid_v0, self._grid_v1, s_vec, num_t - 1, product
350
+ )
351
+
352
+ l, c, u = self._calculate_coefficients(r, q, sigma, dx_vec, num_x)
353
+ A = self._build_operator_matrix(l, c, u, num_x)
354
+
355
+ self._time_stepping_two_surface(
356
+ self._grid_v0,
357
+ self._grid_v1,
358
+ A,
359
+ l,
360
+ c,
361
+ u,
362
+ x_vec,
363
+ s_vec,
364
+ t_vec,
365
+ dt_vec,
366
+ product,
367
+ pricing_env,
368
+ r,
369
+ q,
370
+ sigma,
371
+ tau,
372
+ )
373
+
374
+ spot_log = np.log(spot)
375
+ if knocked_in_at_valuation:
376
+ solution_vec = self._grid_v1[:, 0]
377
+ else:
378
+ solution_vec = self._grid_v0[:, 0]
379
+
380
+ return PDESolutionResult(
381
+ solution_vec=solution_vec,
382
+ x_vec=x_vec,
383
+ s_vec=s_vec,
384
+ spot_log=spot_log,
385
+ )
386
+
387
+ def _apply_step_modifications_two_surface(
388
+ self,
389
+ grid_v0: np.ndarray,
390
+ grid_v1: np.ndarray,
391
+ x_vec: np.ndarray,
392
+ s_vec: np.ndarray,
393
+ t_idx: int,
394
+ tau: float,
395
+ product: KnockOutResetSnowballOption,
396
+ pricing_env: PricingEnvironment,
397
+ ) -> None:
398
+ current_time = self._total_tau - tau
399
+
400
+ pre_record = self._pre_ko_observation_indices.get(t_idx)
401
+ if pre_record is not None:
402
+ self._apply_ko_jump_single(
403
+ grid_v0,
404
+ s_vec,
405
+ t_idx,
406
+ current_time,
407
+ product,
408
+ pricing_env,
409
+ pre_record,
410
+ )
411
+
412
+ post_record = self._post_ko_observation_indices.get(t_idx)
413
+ if (
414
+ post_record is not None
415
+ and not product.barrier_config.disable_ko_after_ki
416
+ ):
417
+ self._apply_ko_jump_single(
418
+ grid_v1,
419
+ s_vec,
420
+ t_idx,
421
+ current_time,
422
+ product,
423
+ pricing_env,
424
+ post_record,
425
+ )
426
+
427
+ if product.has_ki_barrier:
428
+ should_apply_ki = (
429
+ self._ki_continuous or t_idx in self._ki_observation_indices
430
+ )
431
+ if should_apply_ki:
432
+ self._apply_ki_jump(grid_v0, grid_v1, s_vec, t_idx, product)
433
+
434
+ def _apply_ko_jump_single(
435
+ self,
436
+ grid: np.ndarray,
437
+ s_vec: np.ndarray,
438
+ t_idx: int,
439
+ current_time: float,
440
+ product: KnockOutResetSnowballOption,
441
+ pricing_env: PricingEnvironment,
442
+ ko_record: ResolvedObservationRecord,
443
+ ) -> None:
444
+ barrier = ko_record.barrier
445
+ payoff = ko_record.payoff if ko_record.payoff is not None else 0.0
446
+ cashflow_value = self._cashflow_value_at_time(
447
+ pricing_env=pricing_env,
448
+ cashflow=payoff,
449
+ current_time=current_time,
450
+ settlement_time=ko_record.settlement_time,
451
+ )
452
+
453
+ mask = self._get_barrier_mask(s_vec, barrier, product.is_reverse, is_up_barrier=True)
454
+ grid[mask, t_idx] = cashflow_value
455
+
456
+ def _apply_terminal_ko_single(
457
+ self,
458
+ grid: np.ndarray,
459
+ s_vec: np.ndarray,
460
+ product: KnockOutResetSnowballOption,
461
+ pricing_env: PricingEnvironment,
462
+ ko_record: ResolvedObservationRecord,
463
+ ) -> None:
464
+ barrier = ko_record.barrier
465
+ payoff = ko_record.payoff if ko_record.payoff is not None else 0.0
466
+ cashflow_value = self._cashflow_value_at_time(
467
+ pricing_env=pricing_env,
468
+ cashflow=payoff,
469
+ current_time=self._total_tau,
470
+ settlement_time=ko_record.settlement_time,
471
+ )
472
+
473
+ mask = self._get_barrier_mask(s_vec, barrier, product.is_reverse, is_up_barrier=True)
474
+ grid[mask, -1] = cashflow_value
475
+
476
+ def __repr__(self) -> str:
477
+ return "KOResetSnowballPDESolver()"