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,114 @@
1
+ """
2
+ American option implementation.
3
+
4
+ American options can be exercised at any time before maturity.
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+ from typing import Optional
9
+ from datetime import datetime
10
+ from .base_equity_option import BaseEquityOption
11
+ from quantark.util.enum import OptionType, ExerciseType
12
+ from quantark.util.exceptions import ValidationError
13
+
14
+
15
+ @dataclass
16
+ class AmericanOption(BaseEquityOption):
17
+ """
18
+ American call or put option.
19
+
20
+ An American option can be exercised at any time up to and including
21
+ the expiration date. This early exercise feature makes American options
22
+ more valuable than their European counterparts (or at least as valuable).
23
+
24
+ For calls on non-dividend-paying stocks, early exercise is never optimal,
25
+ so American calls equal European calls. However, for puts or when there
26
+ are dividends, early exercise may be optimal.
27
+
28
+ Attributes:
29
+ strike: Strike price
30
+ maturity: Time to maturity in years
31
+ option_type: CALL or PUT
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ strike: float,
37
+ option_type: OptionType,
38
+ maturity: Optional[float] = None,
39
+ exercise_date: Optional[datetime] = None,
40
+ settlement_date: Optional[datetime] = None,
41
+ contract_multiplier: float = 1.0,
42
+ ):
43
+ """
44
+ Initialize American option.
45
+
46
+ Args:
47
+ strike: Strike price
48
+ option_type: CALL or PUT
49
+ maturity: Time to maturity in years (optional if exercise_date provided)
50
+ exercise_date: Date when option expires (optional if maturity provided)
51
+ settlement_date: Date when settlement occurs (optional, defaults to exercise_date)
52
+
53
+ Note:
54
+ Either maturity OR exercise_date must be provided (not both).
55
+ """
56
+ # Default maturity to 0 if not provided (will be validated)
57
+ if maturity is None and exercise_date is None:
58
+ maturity = 0.0 # Will trigger validation error
59
+ elif maturity is None:
60
+ maturity = 0.0 # Placeholder when using dates
61
+
62
+ super().__init__(
63
+ strike=strike,
64
+ maturity=maturity,
65
+ option_type=option_type,
66
+ exercise_type=ExerciseType.AMERICAN,
67
+ exercise_date=exercise_date,
68
+ settlement_date=settlement_date,
69
+ contract_multiplier=contract_multiplier,
70
+ )
71
+
72
+ def get_payoff(self, spot: float) -> float:
73
+ """
74
+ Calculate the option payoff at exercise.
75
+
76
+ For a call: max(S - K, 0)
77
+ For a put: max(K - S, 0)
78
+
79
+ Args:
80
+ spot: Spot price at exercise
81
+
82
+ Returns:
83
+ Option payoff
84
+ """
85
+ if spot < 0:
86
+ raise ValidationError(f"Spot price must be non-negative, got {spot}")
87
+
88
+ if self.is_call():
89
+ intrinsic = max(spot - self.strike, 0.0)
90
+ else: # put
91
+ intrinsic = max(self.strike - spot, 0.0)
92
+
93
+ return intrinsic * self.contract_multiplier
94
+
95
+ def intrinsic_value(self, spot: float) -> float:
96
+ """
97
+ Calculate the intrinsic value of the option.
98
+
99
+ For American options, this is the value that could be obtained
100
+ by exercising immediately.
101
+
102
+ Args:
103
+ spot: Current spot price
104
+
105
+ Returns:
106
+ Intrinsic value
107
+ """
108
+ return self.get_payoff(spot)
109
+
110
+ def __repr__(self):
111
+ return (
112
+ f"AmericanOption("
113
+ f"{self.option_type}, K={self.strike:.2f}, T={self.maturity:.4f})"
114
+ )
@@ -0,0 +1,531 @@
1
+ """
2
+ Asian option product definition.
3
+
4
+ Asian options are path-dependent options where the payoff depends on the average
5
+ price of the underlying asset over a specified observation period.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from datetime import datetime
10
+ from typing import List, Optional, Tuple, Union, TYPE_CHECKING
11
+ import numpy as np
12
+
13
+ from quantark.util.enum import (
14
+ OptionType,
15
+ ExerciseType,
16
+ AveragingType,
17
+ AsianStrikeType,
18
+ )
19
+ from quantark.util.exceptions import ValidationError
20
+ from quantark.util.numerical import is_zero, safe_log, safe_exp
21
+
22
+ from .base_equity_option import BaseEquityOption
23
+
24
+ if TYPE_CHECKING:
25
+ from quantark.priceenv import PricingEnvironment
26
+
27
+ try:
28
+ from quantark.util.calendar import calculate_year_fraction
29
+ except ImportError:
30
+ calculate_year_fraction = None
31
+
32
+
33
+ @dataclass
34
+ class AsianObservationRecord:
35
+ """
36
+ Single observation entry for Asian option averaging.
37
+
38
+ For past observations (before valuation_date), observed_price should be set.
39
+ For future observations, observed_price should be None.
40
+
41
+ Attributes:
42
+ observation_time: Observation time as year fraction from initial date
43
+ observation_date: Observation date (alternative to observation_time)
44
+ observed_price: Actual observed price (for past observations only)
45
+ """
46
+
47
+ observation_time: Optional[float] = None
48
+ observation_date: Optional[datetime] = None
49
+ observed_price: Optional[float] = None
50
+
51
+ def resolve_time(self, pricing_env: "PricingEnvironment") -> float:
52
+ """
53
+ Resolve observation time relative to valuation date.
54
+
55
+ Args:
56
+ pricing_env: Pricing environment with valuation date
57
+
58
+ Returns:
59
+ Year fraction from valuation date to observation date
60
+ (negative if observation is in the past)
61
+
62
+ Raises:
63
+ ValidationError: If observation time/date cannot be resolved
64
+ """
65
+ if self.observation_time is not None:
66
+ return self.observation_time
67
+ if self.observation_date is not None:
68
+ if pricing_env is None or calculate_year_fraction is None:
69
+ raise ValidationError(
70
+ "PricingEnvironment is required to resolve observation_date."
71
+ )
72
+
73
+ # Handle past, current and future dates correctly
74
+ if self.observation_date == pricing_env.valuation_date:
75
+ return 0.0
76
+ elif self.observation_date > pricing_env.valuation_date:
77
+ # Future date: positive year fraction
78
+ return calculate_year_fraction(
79
+ pricing_env.valuation_date,
80
+ self.observation_date,
81
+ pricing_env.day_count_convention,
82
+ pricing_env.bus_days_in_year,
83
+ calendar=getattr(pricing_env, "calendar", None),
84
+ )
85
+ else:
86
+ # Past date: negative year fraction
87
+ # We reverse dates for calculate_year_fraction and negate result
88
+ return -calculate_year_fraction(
89
+ self.observation_date,
90
+ pricing_env.valuation_date,
91
+ pricing_env.day_count_convention,
92
+ pricing_env.bus_days_in_year,
93
+ calendar=getattr(pricing_env, "calendar", None),
94
+ )
95
+ raise ValidationError(
96
+ "AsianObservationRecord requires observation_time or observation_date."
97
+ )
98
+
99
+ def is_observed(self) -> bool:
100
+ """Check if this observation has an observed price."""
101
+ return self.observed_price is not None
102
+
103
+ def validate(self) -> None:
104
+ """Validate the observation record."""
105
+ if self.observation_time is None and self.observation_date is None:
106
+ raise ValidationError(
107
+ "AsianObservationRecord must provide observation_time or observation_date."
108
+ )
109
+ if self.observed_price is not None and self.observed_price <= 0:
110
+ raise ValidationError(
111
+ f"observed_price must be positive, got {self.observed_price}"
112
+ )
113
+
114
+
115
+ @dataclass
116
+ class AsianOption(BaseEquityOption):
117
+ """
118
+ Asian option with arithmetic or geometric averaging.
119
+
120
+ Asian options are path-dependent options where the payoff depends on the
121
+ average price of the underlying asset over a specified observation period.
122
+
123
+ Two main variants:
124
+ - Fixed strike (average price option): payoff based on average vs strike
125
+ - Floating strike (average strike option): payoff based on final spot vs average
126
+
127
+ Attributes:
128
+ strike: Strike price (required for fixed strike, optional for floating)
129
+ option_type: CALL or PUT
130
+ asian_strike_type: FIXED or FLOATING
131
+ averaging_type: ARITHMETIC or GEOMETRIC
132
+ observation_times: List of observation times as year fractions (legacy)
133
+ observation_dates: List of observation dates (legacy, alternative to times)
134
+ observation_records: List of AsianObservationRecord (preferred, supports historical prices)
135
+ num_observations: Number of observations for uniform schedule (default: 12).
136
+ Set to None for continuous averaging.
137
+ maturity: Time to maturity in years
138
+ """
139
+
140
+ # Asian-specific parameters
141
+ asian_strike_type: AsianStrikeType = AsianStrikeType.FIXED
142
+ averaging_type: AveragingType = AveragingType.ARITHMETIC
143
+ observation_times: Optional[List[float]] = None
144
+ observation_dates: Optional[List[datetime]] = None
145
+ observation_records: Optional[List[AsianObservationRecord]] = None
146
+ num_observations: Optional[int] = 12
147
+
148
+ def __init__(
149
+ self,
150
+ strike: float = 0.0,
151
+ option_type: OptionType = OptionType.CALL,
152
+ asian_strike_type: AsianStrikeType = AsianStrikeType.FIXED,
153
+ averaging_type: AveragingType = AveragingType.ARITHMETIC,
154
+ maturity: Optional[float] = None,
155
+ exercise_date: Optional[datetime] = None,
156
+ observation_times: Optional[List[float]] = None,
157
+ observation_dates: Optional[List[datetime]] = None,
158
+ observation_records: Optional[List[AsianObservationRecord]] = None,
159
+ num_observations: Optional[int] = 12,
160
+ initial_price: float = 0.0,
161
+ contract_multiplier: float = 1.0,
162
+ ):
163
+ """
164
+ Initialize Asian option.
165
+
166
+ Args:
167
+ strike: Strike price (required for fixed strike options)
168
+ option_type: CALL or PUT
169
+ asian_strike_type: FIXED (average price) or FLOATING (average strike)
170
+ averaging_type: ARITHMETIC or GEOMETRIC
171
+ maturity: Time to maturity in years (optional if exercise_date provided)
172
+ exercise_date: Date when option expires (optional if maturity provided)
173
+ observation_times: List of observation times as year fractions (legacy)
174
+ observation_dates: List of observation dates (legacy, alternative to times)
175
+ observation_records: List of AsianObservationRecord with optional observed prices
176
+ num_observations: Number of observations for uniform schedule (default: 12)
177
+ initial_price: Reference/initial underlying price
178
+ contract_multiplier: Underlying units represented by one contract
179
+ """
180
+ self.asian_strike_type = asian_strike_type
181
+ self.averaging_type = averaging_type
182
+ self.observation_times = observation_times
183
+ self.observation_dates = observation_dates
184
+ self.observation_records = observation_records
185
+ self.num_observations = num_observations
186
+
187
+ # For floating strike, strike can be zero (strike is the average)
188
+ if asian_strike_type == AsianStrikeType.FLOATING and strike == 0.0:
189
+ strike = 1.0 # Placeholder, won't be used in payoff
190
+
191
+ super().__init__(
192
+ strike=strike,
193
+ option_type=option_type,
194
+ exercise_type=ExerciseType.EUROPEAN, # Asian options are European-style
195
+ maturity=maturity,
196
+ exercise_date=exercise_date,
197
+ initial_price=initial_price,
198
+ contract_multiplier=contract_multiplier,
199
+ )
200
+
201
+ def validate(self) -> None:
202
+ """
203
+ Validate Asian option parameters.
204
+
205
+ Raises:
206
+ ValidationError: If any parameter is invalid
207
+ """
208
+ # Skip strike validation for floating strike options
209
+ if self.asian_strike_type == AsianStrikeType.FIXED:
210
+ self._validate_strike()
211
+
212
+ self._validate_maturity_dates()
213
+ self._validate_date_ordering()
214
+ self._validate_types()
215
+ self._validate_tenor_end()
216
+ self._validate_contract_multiplier()
217
+ self._validate_asian_parameters()
218
+
219
+ def _validate_asian_parameters(self) -> None:
220
+ """Validate Asian-specific parameters."""
221
+ # Validate asian_strike_type
222
+ if not isinstance(self.asian_strike_type, AsianStrikeType):
223
+ raise ValidationError(f"Invalid asian_strike_type: {self.asian_strike_type}")
224
+
225
+ # Validate averaging_type
226
+ if not isinstance(self.averaging_type, AveragingType):
227
+ raise ValidationError(f"Invalid averaging_type: {self.averaging_type}")
228
+
229
+ # Validate observation times if provided
230
+ if self.observation_times is not None:
231
+ if len(self.observation_times) == 0:
232
+ raise ValidationError("observation_times cannot be empty")
233
+ if any(t < 0 for t in self.observation_times):
234
+ raise ValidationError("observation_times must be non-negative")
235
+ if self.observation_times != sorted(self.observation_times):
236
+ raise ValidationError("observation_times must be sorted in ascending order")
237
+
238
+ # Validate observation dates if provided
239
+ if self.observation_dates is not None:
240
+ if len(self.observation_dates) == 0:
241
+ raise ValidationError("observation_dates cannot be empty")
242
+ if self.observation_dates != sorted(self.observation_dates):
243
+ raise ValidationError("observation_dates must be sorted in ascending order")
244
+
245
+ # Validate observation records if provided
246
+ if self.observation_records is not None:
247
+ if len(self.observation_records) == 0:
248
+ raise ValidationError("observation_records cannot be empty")
249
+ for rec in self.observation_records:
250
+ rec.validate()
251
+
252
+ # Validate num_observations
253
+ if self.num_observations is not None and self.num_observations < 1:
254
+ raise ValidationError(f"num_observations must be >= 1, got {self.num_observations}")
255
+
256
+ def get_observation_times(self, maturity: Optional[float] = None) -> List[float]:
257
+ """
258
+ Get observation times as year fractions (legacy method).
259
+
260
+ If observation_times is specified, returns it directly.
261
+ Otherwise, generates uniform observations from 0 to maturity.
262
+
263
+ Note: For options with historical observations, use resolve_observations() instead.
264
+
265
+ Args:
266
+ maturity: Time to maturity (used if generating uniform schedule)
267
+
268
+ Returns:
269
+ List of observation times as year fractions
270
+ """
271
+ if self.observation_times is not None:
272
+ return self.observation_times
273
+
274
+ # Generate uniform schedule
275
+ T = maturity if maturity is not None else self.maturity
276
+ if T is None or T <= 0:
277
+ raise ValidationError("Cannot generate observation schedule: maturity not set")
278
+
279
+ # If num_observations is None, signify continuous schedule
280
+ if self.num_observations is None:
281
+ return []
282
+
283
+ # Generate n equally-spaced observations from 0 to T (inclusive of T)
284
+ return list(np.linspace(0, T, self.num_observations + 1)[1:])
285
+
286
+ def resolve_observations(
287
+ self,
288
+ pricing_env: "PricingEnvironment",
289
+ ) -> Tuple[List[float], List[float], int]:
290
+ """
291
+ Resolve observation records into past and future observations.
292
+
293
+ This method separates already-observed prices from future observation times,
294
+ accounting for the valuation date in pricing_env.
295
+
296
+ For observations with observation_time (year fractions from initial date):
297
+ - Times <= 0 are considered past (already observed)
298
+ - Times > 0 are considered future (to be simulated)
299
+
300
+ Args:
301
+ pricing_env: Pricing environment with valuation date
302
+
303
+ Returns:
304
+ Tuple of:
305
+ - past_prices: List of already-observed prices
306
+ - future_times: List of future observation times (relative to valuation date)
307
+ - total_observations: Total number of observations for averaging
308
+ """
309
+ if self.observation_records is not None:
310
+ return self._resolve_from_records(pricing_env)
311
+ else:
312
+ return self._resolve_from_legacy(pricing_env)
313
+
314
+ def _resolve_from_records(
315
+ self,
316
+ pricing_env: "PricingEnvironment",
317
+ ) -> Tuple[List[float], List[float], int]:
318
+ """Resolve observations from observation_records."""
319
+ past_prices: List[float] = []
320
+ future_times: List[float] = []
321
+
322
+ for rec in self.observation_records:
323
+ t = rec.resolve_time(pricing_env)
324
+
325
+ if t <= 0:
326
+ # Past observation - must have observed price
327
+ if rec.observed_price is None:
328
+ raise ValidationError(
329
+ f"Past observation (t={t}) must have observed_price set"
330
+ )
331
+ past_prices.append(rec.observed_price)
332
+ else:
333
+ # Future observation
334
+ if rec.observed_price is not None:
335
+ raise ValidationError(
336
+ f"Future observation (t={t}) should not have observed_price set"
337
+ )
338
+ future_times.append(t)
339
+
340
+ total_observations = len(past_prices) + len(future_times)
341
+ return past_prices, future_times, total_observations
342
+
343
+ def _resolve_from_legacy(
344
+ self,
345
+ pricing_env: "PricingEnvironment",
346
+ ) -> Tuple[List[float], List[float], int]:
347
+ """Resolve observations from legacy observation_times/observation_dates."""
348
+ T = self.get_maturity(pricing_env)
349
+ obs_times = self.get_observation_times(T)
350
+
351
+ # All observations are future (no historical prices in legacy mode)
352
+ past_prices: List[float] = []
353
+
354
+ if self.num_observations is None:
355
+ # Continuous mode
356
+ future_times = []
357
+ total_observations = 0 # Signifies continuous
358
+ else:
359
+ # Legacy mode has no historical prices, so times at valuation (t=0)
360
+ # are treated as known-at-start observations (deterministic under spot).
361
+ future_times = [t for t in obs_times if t >= 0]
362
+ total_observations = len(obs_times)
363
+
364
+ return past_prices, future_times, total_observations
365
+
366
+ def has_past_observations(self, pricing_env: "PricingEnvironment") -> bool:
367
+ """
368
+ Check if there are any past observations with recorded prices.
369
+
370
+ Args:
371
+ pricing_env: Pricing environment with valuation date
372
+
373
+ Returns:
374
+ True if there are past observations, False otherwise
375
+ """
376
+ past_prices, _, _ = self.resolve_observations(pricing_env)
377
+ return len(past_prices) > 0
378
+
379
+ def get_past_average(self, pricing_env: "PricingEnvironment") -> Optional[float]:
380
+ """
381
+ Get the average of past observations if any exist.
382
+
383
+ Args:
384
+ pricing_env: Pricing environment with valuation date
385
+
386
+ Returns:
387
+ Average of past observations, or None if no past observations
388
+ """
389
+ past_prices, _, _ = self.resolve_observations(pricing_env)
390
+ if len(past_prices) == 0:
391
+ return None
392
+ return self.get_average(past_prices)
393
+
394
+ def get_average(
395
+ self,
396
+ prices: Union[List[float], np.ndarray],
397
+ ) -> float:
398
+ """
399
+ Compute the average of observed prices.
400
+
401
+ Args:
402
+ prices: List or array of observed prices
403
+
404
+ Returns:
405
+ Average price (arithmetic or geometric based on averaging_type)
406
+
407
+ Raises:
408
+ ValidationError: If prices is empty or contains invalid values
409
+ """
410
+ if len(prices) == 0:
411
+ raise ValidationError("prices cannot be empty")
412
+
413
+ prices_arr = np.asarray(prices)
414
+
415
+ if self.averaging_type == AveragingType.ARITHMETIC:
416
+ return float(np.mean(prices_arr))
417
+ else: # GEOMETRIC
418
+ if np.any(prices_arr <= 0):
419
+ raise ValidationError("All prices must be positive for geometric averaging")
420
+ # Use log-sum-exp for numerical stability
421
+ log_prices = np.log(prices_arr)
422
+ return float(safe_exp(np.mean(log_prices)))
423
+
424
+ def get_payoff(
425
+ self,
426
+ spot: float,
427
+ observed_prices: Optional[Union[List[float], np.ndarray]] = None,
428
+ average: Optional[float] = None,
429
+ ) -> float:
430
+ """
431
+ Calculate the option payoff at maturity.
432
+
433
+ For fixed strike (average price option):
434
+ Call: max(average - K, 0)
435
+ Put: max(K - average, 0)
436
+
437
+ For floating strike (average strike option):
438
+ Call: max(spot - average, 0)
439
+ Put: max(average - spot, 0)
440
+
441
+ Args:
442
+ spot: Spot price at maturity
443
+ observed_prices: List of observed prices (used to compute average)
444
+ average: Pre-computed average (alternative to observed_prices)
445
+
446
+ Returns:
447
+ Option payoff
448
+
449
+ Raises:
450
+ ValidationError: If neither observed_prices nor average is provided
451
+ """
452
+ if spot < 0:
453
+ raise ValidationError(f"Spot price must be non-negative, got {spot}")
454
+
455
+ # Get average price
456
+ if average is not None:
457
+ avg = average
458
+ elif observed_prices is not None:
459
+ avg = self.get_average(observed_prices)
460
+ else:
461
+ raise ValidationError("Either observed_prices or average must be provided")
462
+
463
+ # Calculate payoff based on strike type
464
+ if self.asian_strike_type == AsianStrikeType.FIXED:
465
+ # Fixed strike (average price option)
466
+ if self.is_call():
467
+ payoff = max(avg - self.strike, 0.0)
468
+ else:
469
+ payoff = max(self.strike - avg, 0.0)
470
+ else:
471
+ # Floating strike (average strike option)
472
+ if self.is_call():
473
+ payoff = max(spot - avg, 0.0)
474
+ else:
475
+ payoff = max(avg - spot, 0.0)
476
+
477
+ return payoff * self.contract_multiplier
478
+
479
+ def intrinsic_value(
480
+ self,
481
+ spot: float,
482
+ observed_prices: Optional[Union[List[float], np.ndarray]] = None,
483
+ average: Optional[float] = None,
484
+ ) -> float:
485
+ """
486
+ Calculate the intrinsic value of the option.
487
+
488
+ For Asian options, intrinsic value equals payoff since they're European-style.
489
+
490
+ Args:
491
+ spot: Current spot price
492
+ observed_prices: List of observed prices
493
+ average: Pre-computed average
494
+
495
+ Returns:
496
+ Intrinsic value
497
+ """
498
+ return self.get_payoff(spot, observed_prices, average)
499
+
500
+ def is_fixed_strike(self) -> bool:
501
+ """Check if this is a fixed strike (average price) option."""
502
+ return self.asian_strike_type == AsianStrikeType.FIXED
503
+
504
+ def is_floating_strike(self) -> bool:
505
+ """Check if this is a floating strike (average strike) option."""
506
+ return self.asian_strike_type == AsianStrikeType.FLOATING
507
+
508
+ def is_arithmetic(self) -> bool:
509
+ """Check if this uses arithmetic averaging."""
510
+ return self.averaging_type == AveragingType.ARITHMETIC
511
+
512
+ def is_geometric(self) -> bool:
513
+ """Check if this uses geometric averaging."""
514
+ return self.averaging_type == AveragingType.GEOMETRIC
515
+
516
+ def is_continuous(self) -> bool:
517
+ """Check if this uses continuous averaging."""
518
+ return self.num_observations is None and self.observation_times is None and self.observation_dates is None and self.observation_records is None
519
+
520
+ def __repr__(self) -> str:
521
+ """Return string representation of the Asian option."""
522
+ strike_str = f"K={self.strike:.2f}" if self.is_fixed_strike() else "floating"
523
+ maturity_str = (
524
+ f"T={self.maturity:.4f}"
525
+ if self.maturity is not None
526
+ else f"exp={self.exercise_date}"
527
+ )
528
+ return (
529
+ f"AsianOption({self.option_type}, {strike_str}, {maturity_str}, "
530
+ f"{self.asian_strike_type}, {self.averaging_type})"
531
+ )