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.
- quantark/__init__.py +3 -0
- quantark/_compat.py +150 -0
- quantark/asset/__init__.py +8 -0
- quantark/asset/bond/__init__.py +2 -0
- quantark/asset/bond/engine/__init__.py +44 -0
- quantark/asset/bond/engine/analytical/__init__.py +12 -0
- quantark/asset/bond/engine/analytical/black_engine.py +583 -0
- quantark/asset/bond/engine/analytical/bond_forward_engine.py +390 -0
- quantark/asset/bond/engine/analytical/bond_futures_engine.py +569 -0
- quantark/asset/bond/engine/convertible/__init__.py +12 -0
- quantark/asset/bond/engine/convertible/convertible_bond_engine.py +800 -0
- quantark/asset/bond/engine/discount/__init__.py +10 -0
- quantark/asset/bond/engine/discount/bond_discount_engine.py +517 -0
- quantark/asset/bond/engine/discount/frn_engine.py +913 -0
- quantark/asset/bond/engine/pde/__init__.py +14 -0
- quantark/asset/bond/engine/pde/convertible/__init__.py +21 -0
- quantark/asset/bond/engine/pde/convertible/jump_diffusion_engine.py +603 -0
- quantark/asset/bond/engine/pde/convertible/pde_params.py +59 -0
- quantark/asset/bond/engine/pde/convertible/tf_engine.py +546 -0
- quantark/asset/bond/engine/tree/__init__.py +14 -0
- quantark/asset/bond/engine/tree/convertible/__init__.py +21 -0
- quantark/asset/bond/engine/tree/convertible/binomial_engine.py +488 -0
- quantark/asset/bond/engine/tree/convertible/tree_params.py +72 -0
- quantark/asset/bond/engine/tree/convertible/trinomial_engine.py +1341 -0
- quantark/asset/bond/product/__init__.py +37 -0
- quantark/asset/bond/product/base_bond_product.py +114 -0
- quantark/asset/bond/product/convertible/__init__.py +16 -0
- quantark/asset/bond/product/convertible/convertible_bond.py +595 -0
- quantark/asset/bond/product/couponbond/__init__.py +12 -0
- quantark/asset/bond/product/couponbond/fixed_bond.py +285 -0
- quantark/asset/bond/product/couponbond/frn.py +538 -0
- quantark/asset/bond/product/forward/__init__.py +9 -0
- quantark/asset/bond/product/forward/base_bond_forward.py +92 -0
- quantark/asset/bond/product/forward/bond_forward.py +335 -0
- quantark/asset/bond/product/futures/__init__.py +8 -0
- quantark/asset/bond/product/futures/bond_futures.py +532 -0
- quantark/asset/bond/product/option/__init__.py +9 -0
- quantark/asset/bond/product/option/euro_short_term_bond_option.py +231 -0
- quantark/asset/bond/riskmeasures/__init__.py +13 -0
- quantark/asset/bond/riskmeasures/bond_greeks_calculator.py +484 -0
- quantark/asset/bond/schedule/__init__.py +21 -0
- quantark/asset/bond/schedule/cashflow.py +595 -0
- quantark/asset/equity/__init__.py +11 -0
- quantark/asset/equity/analysis/__init__.py +4 -0
- quantark/asset/equity/analysis/autocallable_path_analyzer.py +257 -0
- quantark/asset/equity/engine/__init__.py +84 -0
- quantark/asset/equity/engine/analytical/__init__.py +37 -0
- quantark/asset/equity/engine/analytical/american_option_engine.py +682 -0
- quantark/asset/equity/engine/analytical/asian_option_analytical_engine.py +1102 -0
- quantark/asset/equity/engine/analytical/barrier_analytical_engine.py +455 -0
- quantark/asset/equity/engine/analytical/black_scholes_engine.py +322 -0
- quantark/asset/equity/engine/analytical/deltaone_engine.py +340 -0
- quantark/asset/equity/engine/analytical/digital_option_engine.py +168 -0
- quantark/asset/equity/engine/analytical/double_barrier_option_engine.py +481 -0
- quantark/asset/equity/engine/analytical/double_sharkfin_option_analytical_engine.py +508 -0
- quantark/asset/equity/engine/analytical/one_touch_analytical_engine.py +302 -0
- quantark/asset/equity/engine/analytical/range_accrual_analytical_engine.py +396 -0
- quantark/asset/equity/engine/analytical/single_sharkfin_option_analytical_engine.py +229 -0
- quantark/asset/equity/engine/base_engine.py +137 -0
- quantark/asset/equity/engine/event_stats.py +85 -0
- quantark/asset/equity/engine/mc/__init__.py +31 -0
- quantark/asset/equity/engine/mc/american_option_mc_engine.py +485 -0
- quantark/asset/equity/engine/mc/asian_option_mc_engine.py +678 -0
- quantark/asset/equity/engine/mc/barrier_option_mc_engine.py +726 -0
- quantark/asset/equity/engine/mc/digital_option_mc_engine.py +419 -0
- quantark/asset/equity/engine/mc/double_sharkfin_option_mc_engine.py +676 -0
- quantark/asset/equity/engine/mc/euro_mc_engine.py +423 -0
- quantark/asset/equity/engine/mc/phoenix_mc_engine.py +1206 -0
- quantark/asset/equity/engine/mc/range_accrual_mc_engine.py +738 -0
- quantark/asset/equity/engine/mc/single_sharkfin_option_mc_engine.py +549 -0
- quantark/asset/equity/engine/mc/snowball_mc_engine.py +2250 -0
- quantark/asset/equity/engine/pde/__init__.py +36 -0
- quantark/asset/equity/engine/pde/american_pde_solver.py +211 -0
- quantark/asset/equity/engine/pde/barrier_pde_solver.py +692 -0
- quantark/asset/equity/engine/pde/base_pde_solver.py +994 -0
- quantark/asset/equity/engine/pde/double_barrier_pde_solver.py +510 -0
- quantark/asset/equity/engine/pde/double_one_touch_pde_solver.py +435 -0
- quantark/asset/equity/engine/pde/european_pde_solver.py +170 -0
- quantark/asset/equity/engine/pde/ko_reset_snowball_pde_solver.py +477 -0
- quantark/asset/equity/engine/pde/one_touch_pde_solver.py +439 -0
- quantark/asset/equity/engine/pde/phoenix_pde_solver.py +613 -0
- quantark/asset/equity/engine/pde/snowball_pde_solver.py +1810 -0
- quantark/asset/equity/engine/pde/spatial_grid.py +750 -0
- quantark/asset/equity/engine/pde/time_grid.py +308 -0
- quantark/asset/equity/engine/pde_engine.py +238 -0
- quantark/asset/equity/engine/quad/__init__.py +23 -0
- quantark/asset/equity/engine/quad/discrete_quad_engine.py +106 -0
- quantark/asset/equity/engine/quad/european_quad_engine.py +325 -0
- quantark/asset/equity/engine/quad/ko_reset_snowball_quad_engine.py +362 -0
- quantark/asset/equity/engine/quad/phoenix_quad_engine.py +614 -0
- quantark/asset/equity/engine/quad/quad_adapters.py +1260 -0
- quantark/asset/equity/engine/quad/quad_core.py +513 -0
- quantark/asset/equity/engine/quad/quad_math.py +219 -0
- quantark/asset/equity/engine/quad/snowball_quad_engine.py +1137 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_american_analytical.py +117 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_american_pde.py +114 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_asian_analytical.py +440 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_barrier_analytical.py +269 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_barrier_pde_solver.py +636 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_digital_option.py +256 -0
- quantark/asset/equity/engine/validation/script/benchmark_check_snowball_pde_solver.py +807 -0
- quantark/asset/equity/engine/validation/script/boundary_check_american_analytical.py +290 -0
- quantark/asset/equity/engine/validation/script/boundary_check_american_pde.py +242 -0
- quantark/asset/equity/engine/validation/script/boundary_check_asian_analytical.py +612 -0
- quantark/asset/equity/engine/validation/script/boundary_check_barrier_analytical.py +434 -0
- quantark/asset/equity/engine/validation/script/boundary_check_barrier_pde_solver.py +748 -0
- quantark/asset/equity/engine/validation/script/boundary_check_digital_option.py +575 -0
- quantark/asset/equity/engine/validation/script/boundary_check_snowball_pde_solver.py +1101 -0
- quantark/asset/equity/engine/validation/script/greeks_check_digital_option.py +349 -0
- quantark/asset/equity/engine/validation/script/mc_comparison_barrier_pde.py +270 -0
- quantark/asset/equity/engine/validation/script/quick_mc_compare.py +51 -0
- quantark/asset/equity/engine/validation/script/validation_stepdown_improved.py +97 -0
- quantark/asset/equity/param/__init__.py +24 -0
- quantark/asset/equity/param/engine_param_profiles.py +325 -0
- quantark/asset/equity/param/engine_params.py +728 -0
- quantark/asset/equity/process/__init__.py +7 -0
- quantark/asset/equity/process/bsm/__init__.py +7 -0
- quantark/asset/equity/process/bsm/bsm_process.py +108 -0
- quantark/asset/equity/process/bsm/qmc_brownian_bridge.py +401 -0
- quantark/asset/equity/process/bsm/qmc_path_generator.py +694 -0
- quantark/asset/equity/process/bsm/qmc_rqmc_driver.py +163 -0
- quantark/asset/equity/process/bsm/qmc_sobol.py +195 -0
- quantark/asset/equity/process/bsm/qmc_variance_reduction.py +292 -0
- quantark/asset/equity/product/__init__.py +8 -0
- quantark/asset/equity/product/base_equity_product.py +72 -0
- quantark/asset/equity/product/deltaone/__init__.py +22 -0
- quantark/asset/equity/product/deltaone/base_deltaone_product.py +147 -0
- quantark/asset/equity/product/deltaone/futures.py +485 -0
- quantark/asset/equity/product/deltaone/spot_instrument.py +118 -0
- quantark/asset/equity/product/option/__init__.py +104 -0
- quantark/asset/equity/product/option/american_option.py +114 -0
- quantark/asset/equity/product/option/asian_option.py +531 -0
- quantark/asset/equity/product/option/barrier_option.py +289 -0
- quantark/asset/equity/product/option/base_equity_option.py +659 -0
- quantark/asset/equity/product/option/digital_option.py +102 -0
- quantark/asset/equity/product/option/double_barrier_option.py +286 -0
- quantark/asset/equity/product/option/double_one_touch_option.py +310 -0
- quantark/asset/equity/product/option/double_sharkfin_option.py +466 -0
- quantark/asset/equity/product/option/european_vanilla_option.py +103 -0
- quantark/asset/equity/product/option/ko_reset_snowball_option.py +563 -0
- quantark/asset/equity/product/option/observation_schedule.py +530 -0
- quantark/asset/equity/product/option/one_touch_option.py +287 -0
- quantark/asset/equity/product/option/phoenix_config.py +116 -0
- quantark/asset/equity/product/option/phoenix_helpers.py +576 -0
- quantark/asset/equity/product/option/phoenix_option.py +1167 -0
- quantark/asset/equity/product/option/range_accrual_config.py +288 -0
- quantark/asset/equity/product/option/range_accrual_helpers.py +608 -0
- quantark/asset/equity/product/option/range_accrual_option.py +526 -0
- quantark/asset/equity/product/option/single_sharkfin_option.py +420 -0
- quantark/asset/equity/product/option/snowball_config.py +261 -0
- quantark/asset/equity/product/option/snowball_helpers.py +977 -0
- quantark/asset/equity/product/option/snowball_option.py +1242 -0
- quantark/asset/equity/report/__init__.py +15 -0
- quantark/asset/equity/report/autocallable_risk_report.py +2118 -0
- quantark/asset/equity/report/plotting.py +87 -0
- quantark/asset/equity/report/snowball_risk_comparison_report.py +2230 -0
- quantark/asset/equity/report/surfaces.py +123 -0
- quantark/asset/equity/report/term_structure.py +126 -0
- quantark/asset/equity/riskmeasures/__init__.py +7 -0
- quantark/asset/equity/riskmeasures/greeks_calculator.py +1204 -0
- quantark/asset/rate/__init__.py +58 -0
- quantark/asset/rate/engine/__init__.py +25 -0
- quantark/asset/rate/engine/cap_floor_engine.py +514 -0
- quantark/asset/rate/engine/fra_engine.py +286 -0
- quantark/asset/rate/engine/irs_discount_engine.py +891 -0
- quantark/asset/rate/engine/swaption_engine.py +587 -0
- quantark/asset/rate/product/__init__.py +67 -0
- quantark/asset/rate/product/cap_floor.py +550 -0
- quantark/asset/rate/product/fra.py +219 -0
- quantark/asset/rate/product/irs.py +1223 -0
- quantark/asset/rate/product/swaption.py +372 -0
- quantark/backtest/__init__.py +153 -0
- quantark/backtest/base.py +263 -0
- quantark/backtest/dashboard.py +874 -0
- quantark/backtest/equity/__init__.py +35 -0
- quantark/backtest/equity/config.py +118 -0
- quantark/backtest/equity/engine.py +408 -0
- quantark/backtest/equity/hedge_executor.py +374 -0
- quantark/backtest/equity/metrics.py +396 -0
- quantark/backtest/equity/results.py +232 -0
- quantark/backtest/equity/state.py +252 -0
- quantark/backtest/examples/__init__.py +4 -0
- quantark/backtest/examples/advanced_backtest.py +345 -0
- quantark/backtest/examples/basic_delta_hedge.py +246 -0
- quantark/backtest/examples/fi_dv01_hedge.py +267 -0
- quantark/backtest/fi/__init__.py +30 -0
- quantark/backtest/fi/config.py +114 -0
- quantark/backtest/fi/engine.py +378 -0
- quantark/backtest/fi/hedge_executor.py +254 -0
- quantark/backtest/fi/metrics.py +308 -0
- quantark/backtest/fi/results.py +193 -0
- quantark/backtest/fi/state.py +212 -0
- quantark/backtest/logger.py +393 -0
- quantark/backtest/otc/__init__.py +74 -0
- quantark/backtest/otc/_replay.py +637 -0
- quantark/backtest/otc/book_engine.py +587 -0
- quantark/backtest/otc/config.py +175 -0
- quantark/backtest/otc/dashboard.py +1006 -0
- quantark/backtest/otc/engine.py +420 -0
- quantark/backtest/otc/engine_factory.py +138 -0
- quantark/backtest/otc/market.py +216 -0
- quantark/backtest/otc/results.py +107 -0
- quantark/backtest/otc/state.py +166 -0
- quantark/backtest/report_generator.py +608 -0
- quantark/backtest/strategy/__init__.py +28 -0
- quantark/backtest/strategy/base_strategy.py +235 -0
- quantark/backtest/strategy/convexity_neutral_strategy.py +247 -0
- quantark/backtest/strategy/delta_neutral_strategy.py +283 -0
- quantark/backtest/strategy/dv01_neutral_strategy.py +283 -0
- quantark/backtest/transaction_costs.py +485 -0
- quantark/backtest/visualizer.py +1019 -0
- quantark/cashleg/__init__.py +31 -0
- quantark/cashleg/accrual_leg.py +120 -0
- quantark/cashleg/base.py +48 -0
- quantark/cashleg/base_amount.py +60 -0
- quantark/cashleg/deterministic_leg.py +39 -0
- quantark/cashleg/event_distribution.py +262 -0
- quantark/cashleg/fixed_payoff_leg.py +92 -0
- quantark/cashleg/leg_schedule.py +95 -0
- quantark/cashleg/leg_valuator.py +40 -0
- quantark/dynamicscenario/__init__.py +97 -0
- quantark/dynamicscenario/base.py +297 -0
- quantark/dynamicscenario/config.py +122 -0
- quantark/dynamicscenario/engine.py +703 -0
- quantark/dynamicscenario/equity/__init__.py +14 -0
- quantark/dynamicscenario/fi/__init__.py +24 -0
- quantark/dynamicscenario/fi/config.py +149 -0
- quantark/dynamicscenario/fi/engine.py +500 -0
- quantark/dynamicscenario/fi/results.py +503 -0
- quantark/dynamicscenario/path/__init__.py +17 -0
- quantark/dynamicscenario/path/day_path.py +397 -0
- quantark/dynamicscenario/path/fi_path_library.py +488 -0
- quantark/dynamicscenario/path/path_builder.py +726 -0
- quantark/dynamicscenario/path/path_library.py +620 -0
- quantark/dynamicscenario/report/__init__.py +12 -0
- quantark/dynamicscenario/report/dynamic_report.py +1175 -0
- quantark/dynamicscenario/report/visualizer.py +1586 -0
- quantark/dynamicscenario/results/__init__.py +19 -0
- quantark/dynamicscenario/results/dynamic_results.py +579 -0
- quantark/dynamicscenario/results/result_exporter.py +438 -0
- quantark/param/__init__.py +75 -0
- quantark/param/basis/__init__.py +19 -0
- quantark/param/basis/basis_yield.py +301 -0
- quantark/param/div/__init__.py +16 -0
- quantark/param/div/dividend_yield.py +123 -0
- quantark/param/index/__init__.py +52 -0
- quantark/param/index/rate_index.py +568 -0
- quantark/param/quote/__init__.py +7 -0
- quantark/param/quote/spot_quote.py +35 -0
- quantark/param/rrf/__init__.py +22 -0
- quantark/param/rrf/rate_curve.py +436 -0
- quantark/param/vol/__init__.py +6 -0
- quantark/param/vol/vol_surface.py +118 -0
- quantark/portfolio/__init__.py +61 -0
- quantark/portfolio/base.py +203 -0
- quantark/portfolio/equity/__init__.py +17 -0
- quantark/portfolio/equity/portfolio.py +391 -0
- quantark/portfolio/equity/position.py +368 -0
- quantark/portfolio/fi/__init__.py +14 -0
- quantark/portfolio/fi/portfolio.py +424 -0
- quantark/portfolio/fi/position.py +272 -0
- quantark/portfolio/portfolio_snapshot.py +221 -0
- quantark/portfolio/portfolio_storage.py +414 -0
- quantark/priceenv/__init__.py +7 -0
- quantark/priceenv/pricing_environment.py +196 -0
- quantark/rfq/__init__.py +32 -0
- quantark/rfq/builders.py +102 -0
- quantark/rfq/models.py +214 -0
- quantark/rfq/registry.py +611 -0
- quantark/rfq/service.py +237 -0
- quantark/simm/__init__.py +155 -0
- quantark/simm/calibration/__init__.py +206 -0
- quantark/simm/calibration/accessors.py +439 -0
- quantark/simm/calibration/commodity.py +156 -0
- quantark/simm/calibration/credit_non_qualifying.py +79 -0
- quantark/simm/calibration/credit_qualifying.py +130 -0
- quantark/simm/calibration/cross_risk.py +39 -0
- quantark/simm/calibration/equity.py +125 -0
- quantark/simm/calibration/fx.py +92 -0
- quantark/simm/calibration/ir.py +152 -0
- quantark/simm/calibration/version.py +33 -0
- quantark/simm/config.py +186 -0
- quantark/simm/crif/__init__.py +35 -0
- quantark/simm/crif/models.py +230 -0
- quantark/simm/crif/parser.py +585 -0
- quantark/simm/engines/__init__.py +62 -0
- quantark/simm/engines/aggregation/__init__.py +67 -0
- quantark/simm/engines/aggregation/addon.py +141 -0
- quantark/simm/engines/aggregation/bucket_aggregator.py +298 -0
- quantark/simm/engines/aggregation/concentration.py +349 -0
- quantark/simm/engines/aggregation/product_class_aggregator.py +183 -0
- quantark/simm/engines/aggregation/risk_class_aggregator.py +403 -0
- quantark/simm/engines/aggregation/simm_calculator.py +430 -0
- quantark/simm/engines/aggregation/weighted_sensitivity.py +272 -0
- quantark/simm/engines/base.py +231 -0
- quantark/simm/engines/classification/__init__.py +10 -0
- quantark/simm/engines/classification/bucket_mapper.py +347 -0
- quantark/simm/engines/factory.py +137 -0
- quantark/simm/engines/portfolio_adapter.py +336 -0
- quantark/simm/engines/result.py +176 -0
- quantark/simm/engines/risk_class/__init__.py +18 -0
- quantark/simm/engines/risk_class/equity_engine.py +263 -0
- quantark/simm/engines/risk_class/ir_engine.py +264 -0
- quantark/simm/report/__init__.py +17 -0
- quantark/simm/report/crif_export.py +284 -0
- quantark/simm/report/excel_generator.py +401 -0
- quantark/simm/report/html_generator.py +840 -0
- quantark/simm/results/__init__.py +38 -0
- quantark/simm/results/attribution.py +313 -0
- quantark/simm/results/simm_result.py +339 -0
- quantark/simm/results/whatif.py +268 -0
- quantark/simm/sensitivity.py +533 -0
- quantark/simm/taxonomy.py +416 -0
- quantark/stresstest/__init__.py +67 -0
- quantark/stresstest/base.py +116 -0
- quantark/stresstest/config.py +5 -0
- quantark/stresstest/engine.py +5 -0
- quantark/stresstest/equity/__init__.py +17 -0
- quantark/stresstest/equity/config.py +69 -0
- quantark/stresstest/equity/engine.py +272 -0
- quantark/stresstest/equity/report/__init__.py +7 -0
- quantark/stresstest/equity/report/report_generator.py +423 -0
- quantark/stresstest/equity/report/visualizer.py +328 -0
- quantark/stresstest/equity/results.py +145 -0
- quantark/stresstest/fi/__init__.py +15 -0
- quantark/stresstest/fi/config.py +59 -0
- quantark/stresstest/fi/engine.py +213 -0
- quantark/stresstest/fi/metrics.py +60 -0
- quantark/stresstest/fi/results.py +64 -0
- quantark/stresstest/report/__init__.py +12 -0
- quantark/stresstest/report/report_generator.py +5 -0
- quantark/stresstest/report/visualizer.py +5 -0
- quantark/stresstest/results/__init__.py +16 -0
- quantark/stresstest/results/result_aggregator.py +325 -0
- quantark/stresstest/results/result_exporter.py +286 -0
- quantark/stresstest/results/stress_results.py +5 -0
- quantark/stresstest/scenario/__init__.py +13 -0
- quantark/stresstest/scenario/scenario.py +242 -0
- quantark/stresstest/scenario/scenario_builder.py +376 -0
- quantark/stresstest/scenario/scenario_library.py +435 -0
- quantark/stresstest/scenario/scenario_storage.py +224 -0
- quantark/stresstest/stress/__init__.py +13 -0
- quantark/stresstest/stress/stress_applicator.py +590 -0
- quantark/stresstest/stress/stress_types.py +142 -0
- quantark/util/__init__.py +23 -0
- quantark/util/barrier_shift.py +44 -0
- quantark/util/calendar/__init__.py +27 -0
- quantark/util/calendar/business_calendar.py +584 -0
- quantark/util/calendar/day_counter.py +517 -0
- quantark/util/calendar/holidayfile/china.csv +1920 -0
- quantark/util/calendar/holidayfile/china_sse.csv +1462 -0
- quantark/util/enum/__init__.py +81 -0
- quantark/util/enum/bond_enums.py +112 -0
- quantark/util/enum/deltaone_enums.py +16 -0
- quantark/util/enum/engine_enums.py +137 -0
- quantark/util/enum/greeks_enums.py +29 -0
- quantark/util/enum/option_enums.py +221 -0
- quantark/util/exceptions.py +66 -0
- quantark/util/marketdata/__init__.py +39 -0
- quantark/util/marketdata/adapter/base_adapter.py +203 -0
- quantark/util/marketdata/adapter/mock_adapter.py +265 -0
- quantark/util/marketdata/converter.py +289 -0
- quantark/util/marketdata/example_usage.py +314 -0
- quantark/util/marketdata/generator/__init__.py +7 -0
- quantark/util/marketdata/generator/mock_generator.py +466 -0
- quantark/util/marketdata/models.py +358 -0
- quantark/util/marketdata/storage/__init__.py +7 -0
- quantark/util/marketdata/storage/parquet_storage.py +340 -0
- quantark/util/numerical/__init__.py +98 -0
- quantark/util/numerical/comparison.py +219 -0
- quantark/util/numerical/constants.py +98 -0
- quantark/util/numerical/formatting.py +380 -0
- quantark/util/numerical/pnl.py +17 -0
- quantark/util/numerical/safe_math.py +238 -0
- quantark/util/numerical/validation.py +315 -0
- quantark/var/__init__.py +39 -0
- quantark/var/attribution.py +398 -0
- quantark/var/backtest/__init__.py +7 -0
- quantark/var/backtest/var_backtester.py +309 -0
- quantark/var/base.py +63 -0
- quantark/var/config.py +219 -0
- quantark/var/engines/__init__.py +13 -0
- quantark/var/engines/historical.py +925 -0
- quantark/var/engines/monte_carlo.py +870 -0
- quantark/var/engines/parametric.py +1199 -0
- quantark/var/results/__init__.py +16 -0
- quantark/var/results/incremental_var_result.py +131 -0
- quantark/var/results/var_report.py +346 -0
- quantark/var/results/var_result.py +134 -0
- quantark/var/risk_factors/__init__.py +22 -0
- quantark/var/risk_factors/base.py +41 -0
- quantark/var/risk_factors/equity_factors.py +158 -0
- quantark/var/risk_factors/fi_factors.py +99 -0
- quantark-0.1.0.dist-info/METADATA +351 -0
- quantark-0.1.0.dist-info/RECORD +399 -0
- quantark-0.1.0.dist-info/WHEEL +4 -0
- quantark-0.1.0.dist-info/licenses/LICENSE +202 -0
- quantark-0.1.0.dist-info/licenses/NOTICE +2 -0
- quantark_compat.pth +1 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Monte Carlo pricing engine for cash-or-nothing digital options.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from typing import Optional, Union, Tuple
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from quantark.asset.equity.engine.base_engine import BaseEngine
|
|
10
|
+
from quantark.asset.equity.product.option.digital_option import CashOrNothingDigitalOption
|
|
11
|
+
from quantark.asset.equity.product.base_equity_product import BaseEquityProduct
|
|
12
|
+
from quantark.asset.equity.param import MCParams
|
|
13
|
+
from quantark.priceenv import PricingEnvironment
|
|
14
|
+
from quantark.util.enum.engine_enums import MonteCarloMethod, EngineType
|
|
15
|
+
from quantark.util.exceptions import ValidationError, PricingError
|
|
16
|
+
|
|
17
|
+
from quantark.asset.equity.process.bsm.qmc_path_generator import GBMPathGenerator
|
|
18
|
+
from quantark.asset.equity.process.bsm.qmc_sobol import (
|
|
19
|
+
PseudoRandomNormalGenerator,
|
|
20
|
+
SobolNormalGenerator,
|
|
21
|
+
)
|
|
22
|
+
from quantark.asset.equity.process.bsm.qmc_rqmc_driver import run_rqmc
|
|
23
|
+
from quantark.asset.equity.process.bsm.qmc_variance_reduction import VarianceReductionConfig
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DigitalOptionMCEngine(BaseEngine):
|
|
27
|
+
"""
|
|
28
|
+
Monte Carlo pricing engine for cash-or-nothing digital options.
|
|
29
|
+
|
|
30
|
+
Supports three Monte Carlo methods:
|
|
31
|
+
- PSEUDO: Standard Monte Carlo with pseudorandom numbers
|
|
32
|
+
- QUASI: Quasi-Monte Carlo with Sobol sequences
|
|
33
|
+
- RANDOMIZED_QUASI: Randomized QMC with adaptive batching
|
|
34
|
+
|
|
35
|
+
Digital options pay a fixed cash amount if the terminal spot is on the
|
|
36
|
+
paying side of the strike (S > K for calls, S < K for puts).
|
|
37
|
+
|
|
38
|
+
Usage:
|
|
39
|
+
# Preferred: Two-level enum pattern
|
|
40
|
+
engine = DigitalOptionMCEngine(
|
|
41
|
+
params=MCParams(num_paths=100000, time_steps=252),
|
|
42
|
+
method=EngineType.MONTE_CARLO(MonteCarloMethod.QUASI)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Alternative: Direct method enum
|
|
46
|
+
engine = DigitalOptionMCEngine(
|
|
47
|
+
params=MCParams(num_paths=100000),
|
|
48
|
+
method=MonteCarloMethod.QUASI
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Backward compatibility: String
|
|
52
|
+
engine = DigitalOptionMCEngine(method="quasi")
|
|
53
|
+
|
|
54
|
+
The engine creates a GBMPathGenerator internally based on the pricing
|
|
55
|
+
environment and MCParams configuration.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
engine_type = EngineType.MONTE_CARLO
|
|
59
|
+
|
|
60
|
+
DEFAULT_METHOD = MonteCarloMethod.PSEUDO
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
params: Optional[MCParams] = None,
|
|
65
|
+
method: Union[str, MonteCarloMethod, tuple, None] = None,
|
|
66
|
+
):
|
|
67
|
+
"""
|
|
68
|
+
Initialize Monte Carlo engine for digital options.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
params: Monte Carlo configuration parameters (MCParams)
|
|
72
|
+
method: Monte Carlo method selection, one of:
|
|
73
|
+
- EngineType.MONTE_CARLO(MonteCarloMethod.XXX) (preferred)
|
|
74
|
+
- MonteCarloMethod.XXX
|
|
75
|
+
- String: "pseudo", "quasi", "randomized_quasi"
|
|
76
|
+
- None: defaults to MonteCarloMethod.PSEUDO
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ValidationError: If method is invalid or params are invalid
|
|
80
|
+
"""
|
|
81
|
+
if params is None:
|
|
82
|
+
params = MCParams()
|
|
83
|
+
|
|
84
|
+
if not isinstance(params, MCParams):
|
|
85
|
+
raise ValidationError(
|
|
86
|
+
f"params must be MCParams instance, got {type(params).__name__}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
super().__init__(params)
|
|
90
|
+
|
|
91
|
+
if method is None:
|
|
92
|
+
self.method = self.DEFAULT_METHOD
|
|
93
|
+
elif isinstance(method, tuple):
|
|
94
|
+
engine_type, mc_method = method
|
|
95
|
+
if engine_type != EngineType.MONTE_CARLO:
|
|
96
|
+
raise ValidationError(
|
|
97
|
+
f"Expected EngineType.MONTE_CARLO, got {engine_type}"
|
|
98
|
+
)
|
|
99
|
+
if not isinstance(mc_method, MonteCarloMethod):
|
|
100
|
+
raise ValidationError(
|
|
101
|
+
f"Expected MonteCarloMethod, got {type(mc_method).__name__}"
|
|
102
|
+
)
|
|
103
|
+
self.method = mc_method
|
|
104
|
+
elif isinstance(method, MonteCarloMethod):
|
|
105
|
+
self.method = method
|
|
106
|
+
elif isinstance(method, str):
|
|
107
|
+
try:
|
|
108
|
+
self.method = MonteCarloMethod[method.upper()]
|
|
109
|
+
except KeyError:
|
|
110
|
+
valid_methods = [m.name for m in MonteCarloMethod]
|
|
111
|
+
raise ValidationError(
|
|
112
|
+
f"Invalid method string '{method}'. Valid methods: {valid_methods}"
|
|
113
|
+
)
|
|
114
|
+
else:
|
|
115
|
+
raise ValidationError(
|
|
116
|
+
f"Invalid method type {type(method).__name__}. "
|
|
117
|
+
"Expected MonteCarloMethod, tuple, str, or None"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def price(
|
|
121
|
+
self, product: BaseEquityProduct, pricing_env: PricingEnvironment
|
|
122
|
+
) -> float:
|
|
123
|
+
"""
|
|
124
|
+
Price a cash-or-nothing digital option using Monte Carlo simulation.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
product: Cash-or-nothing digital option to price
|
|
128
|
+
pricing_env: Pricing environment with market data
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Option price
|
|
132
|
+
|
|
133
|
+
Raises:
|
|
134
|
+
PricingError: If product is not a cash-or-nothing digital option
|
|
135
|
+
ValidationError: If pricing parameters are invalid
|
|
136
|
+
"""
|
|
137
|
+
if not isinstance(product, CashOrNothingDigitalOption):
|
|
138
|
+
raise PricingError(
|
|
139
|
+
f"DigitalOptionMCEngine only supports CashOrNothingDigitalOption, "
|
|
140
|
+
f"got {type(product).__name__}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
S = pricing_env.spot
|
|
144
|
+
K = product.strike
|
|
145
|
+
payout = product.payout
|
|
146
|
+
T = product.get_maturity(pricing_env)
|
|
147
|
+
r = pricing_env.get_rate(T)
|
|
148
|
+
q = pricing_env.get_div_yield(T)
|
|
149
|
+
sigma = pricing_env.get_vol(K, T)
|
|
150
|
+
|
|
151
|
+
self._validate_inputs(S, K, T, r, q, sigma, payout)
|
|
152
|
+
|
|
153
|
+
if T < 1e-10:
|
|
154
|
+
return product.get_payoff(S)
|
|
155
|
+
|
|
156
|
+
if self.method == MonteCarloMethod.RANDOMIZED_QUASI:
|
|
157
|
+
price, std_error = self._price_rqmc(
|
|
158
|
+
product, S, K, payout, T, r, q, sigma
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
price, std_error = self._price_mc_or_qmc(
|
|
162
|
+
product, S, K, payout, T, r, q, sigma
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
self._last_std_error = std_error
|
|
166
|
+
|
|
167
|
+
if price < 0:
|
|
168
|
+
raise PricingError(f"Negative price computed: {price}")
|
|
169
|
+
|
|
170
|
+
# Digital options: price must be in [0, payout * exp(-r*T)]
|
|
171
|
+
# The upper bound is the discounted payout (certainty case)
|
|
172
|
+
max_price = payout * math.exp(-r * T)
|
|
173
|
+
if price > max_price + 1e-6:
|
|
174
|
+
raise PricingError(
|
|
175
|
+
f"Price ({price:.6f}) exceeds discounted payout ({max_price:.6f})"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return price
|
|
179
|
+
|
|
180
|
+
def _validate_inputs(
|
|
181
|
+
self, S: float, K: float, T: float, r: float, q: float,
|
|
182
|
+
sigma: float, payout: float
|
|
183
|
+
) -> None:
|
|
184
|
+
"""Validate pricing inputs."""
|
|
185
|
+
if S <= 0:
|
|
186
|
+
raise ValidationError(f"Spot price must be positive, got {S}")
|
|
187
|
+
if K <= 0:
|
|
188
|
+
raise ValidationError(f"Strike price must be positive, got {K}")
|
|
189
|
+
if T < 0:
|
|
190
|
+
raise ValidationError(f"Time to maturity must be non-negative, got {T}")
|
|
191
|
+
if sigma <= 0:
|
|
192
|
+
raise ValidationError(f"Volatility must be positive, got {sigma}")
|
|
193
|
+
if q < 0:
|
|
194
|
+
raise ValidationError(f"Dividend yield must be non-negative, got {q}")
|
|
195
|
+
if payout <= 0:
|
|
196
|
+
raise ValidationError(f"Payout must be positive, got {payout}")
|
|
197
|
+
|
|
198
|
+
def _create_path_generator(
|
|
199
|
+
self,
|
|
200
|
+
S: float,
|
|
201
|
+
r: float,
|
|
202
|
+
q: float,
|
|
203
|
+
sigma: float,
|
|
204
|
+
T: float,
|
|
205
|
+
num_paths: Optional[int] = None,
|
|
206
|
+
) -> GBMPathGenerator:
|
|
207
|
+
"""
|
|
208
|
+
Create a GBMPathGenerator configured for the current method.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
S: Spot price
|
|
212
|
+
r: Risk-free rate
|
|
213
|
+
q: Dividend yield
|
|
214
|
+
sigma: Volatility
|
|
215
|
+
T: Time to maturity
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Configured GBMPathGenerator
|
|
219
|
+
"""
|
|
220
|
+
params = self.params
|
|
221
|
+
effective_num_paths = params.num_paths if num_paths is None else int(num_paths)
|
|
222
|
+
if effective_num_paths <= 0:
|
|
223
|
+
raise ValidationError(
|
|
224
|
+
f"num_paths must be positive, got {effective_num_paths}"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if self.method == MonteCarloMethod.PSEUDO:
|
|
228
|
+
random_stream = PseudoRandomNormalGenerator(seed=params.seed)
|
|
229
|
+
is_qmc = False
|
|
230
|
+
elif self.method in (MonteCarloMethod.QUASI, MonteCarloMethod.RANDOMIZED_QUASI):
|
|
231
|
+
random_stream = SobolNormalGenerator(base_seed=params.seed)
|
|
232
|
+
is_qmc = True
|
|
233
|
+
else:
|
|
234
|
+
raise ValidationError(f"Unknown Monte Carlo method: {self.method}")
|
|
235
|
+
|
|
236
|
+
vr_config = None
|
|
237
|
+
if params.use_antithetic and not is_qmc:
|
|
238
|
+
vr_config = VarianceReductionConfig(antithetic=True)
|
|
239
|
+
|
|
240
|
+
generator = GBMPathGenerator(
|
|
241
|
+
initial_value=S,
|
|
242
|
+
vol=sigma,
|
|
243
|
+
rrf=r,
|
|
244
|
+
div=q,
|
|
245
|
+
maturity=T,
|
|
246
|
+
time_steps=params.time_steps,
|
|
247
|
+
num_paths=effective_num_paths,
|
|
248
|
+
model="bsm",
|
|
249
|
+
random_stream=random_stream,
|
|
250
|
+
use_brownian_bridge=False,
|
|
251
|
+
vr_config=vr_config,
|
|
252
|
+
is_qmc=is_qmc,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
return generator
|
|
256
|
+
|
|
257
|
+
def _calculate_payoffs(
|
|
258
|
+
self, product: CashOrNothingDigitalOption, terminal_prices: np.ndarray
|
|
259
|
+
) -> np.ndarray:
|
|
260
|
+
"""
|
|
261
|
+
Calculate digital option payoffs from terminal prices.
|
|
262
|
+
|
|
263
|
+
For a call: payout if S > K else 0
|
|
264
|
+
For a put: payout if S < K else 0
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
product: Cash-or-nothing digital option
|
|
268
|
+
terminal_prices: Array of terminal spot prices, shape (num_paths,)
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Array of payoffs, shape (num_paths,)
|
|
272
|
+
"""
|
|
273
|
+
K = product.strike
|
|
274
|
+
payout = product.payout
|
|
275
|
+
|
|
276
|
+
if product.is_call():
|
|
277
|
+
# Call pays out if terminal price > strike
|
|
278
|
+
payoffs = np.where(terminal_prices > K, payout, 0.0)
|
|
279
|
+
else:
|
|
280
|
+
# Put pays out if terminal price < strike
|
|
281
|
+
payoffs = np.where(terminal_prices < K, payout, 0.0)
|
|
282
|
+
|
|
283
|
+
return payoffs
|
|
284
|
+
|
|
285
|
+
def _price_mc_or_qmc(
|
|
286
|
+
self,
|
|
287
|
+
product: CashOrNothingDigitalOption,
|
|
288
|
+
S: float,
|
|
289
|
+
K: float,
|
|
290
|
+
payout: float,
|
|
291
|
+
T: float,
|
|
292
|
+
r: float,
|
|
293
|
+
q: float,
|
|
294
|
+
sigma: float,
|
|
295
|
+
) -> Tuple[float, float]:
|
|
296
|
+
"""
|
|
297
|
+
Price using normal MC or QMC (non-randomized).
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
product: Cash-or-nothing digital option
|
|
301
|
+
S: Spot price
|
|
302
|
+
K: Strike price
|
|
303
|
+
payout: Fixed cash payout
|
|
304
|
+
T: Time to maturity
|
|
305
|
+
r: Risk-free rate
|
|
306
|
+
q: Dividend yield
|
|
307
|
+
sigma: Volatility
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
Tuple of (price, standard_error)
|
|
311
|
+
"""
|
|
312
|
+
generator = self._create_path_generator(S, r, q, sigma, T)
|
|
313
|
+
|
|
314
|
+
paths, aux = generator.generate_paths(return_aux=True)
|
|
315
|
+
|
|
316
|
+
terminal_prices = paths[:, -1]
|
|
317
|
+
|
|
318
|
+
payoffs = self._calculate_payoffs(product, terminal_prices)
|
|
319
|
+
|
|
320
|
+
discount_factor = math.exp(-r * T)
|
|
321
|
+
discounted_payoffs = discount_factor * payoffs
|
|
322
|
+
|
|
323
|
+
mean_payoff = float(discounted_payoffs.mean())
|
|
324
|
+
std_payoff = float(discounted_payoffs.std(ddof=1))
|
|
325
|
+
|
|
326
|
+
std_error = std_payoff / math.sqrt(len(payoffs))
|
|
327
|
+
|
|
328
|
+
return mean_payoff, std_error
|
|
329
|
+
|
|
330
|
+
def _price_rqmc(
|
|
331
|
+
self,
|
|
332
|
+
product: CashOrNothingDigitalOption,
|
|
333
|
+
S: float,
|
|
334
|
+
K: float,
|
|
335
|
+
payout: float,
|
|
336
|
+
T: float,
|
|
337
|
+
r: float,
|
|
338
|
+
q: float,
|
|
339
|
+
sigma: float,
|
|
340
|
+
) -> Tuple[float, float]:
|
|
341
|
+
"""
|
|
342
|
+
Price using Randomized QMC with adaptive batching.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
product: Cash-or-nothing digital option
|
|
346
|
+
S: Spot price
|
|
347
|
+
K: Strike price
|
|
348
|
+
payout: Fixed cash payout
|
|
349
|
+
T: Time to maturity
|
|
350
|
+
r: Risk-free rate
|
|
351
|
+
q: Dividend yield
|
|
352
|
+
sigma: Volatility
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
Tuple of (price, standard_error)
|
|
356
|
+
"""
|
|
357
|
+
discount_factor = math.exp(-r * T)
|
|
358
|
+
|
|
359
|
+
def pricer_fn(paths, aux):
|
|
360
|
+
"""Pricer function for RQMC driver."""
|
|
361
|
+
terminal_prices = paths[:, -1]
|
|
362
|
+
payoffs = self._calculate_payoffs(product, terminal_prices)
|
|
363
|
+
discounted_payoffs = discount_factor * payoffs
|
|
364
|
+
return discounted_payoffs
|
|
365
|
+
|
|
366
|
+
params = self.params
|
|
367
|
+
max_batches = getattr(
|
|
368
|
+
params, "rqmc_max_batches", getattr(params, "max_batches", 32)
|
|
369
|
+
)
|
|
370
|
+
min_batches = getattr(
|
|
371
|
+
params, "rqmc_min_batches", getattr(params, "min_batches", 4)
|
|
372
|
+
)
|
|
373
|
+
if hasattr(params, "resolve_rqmc_target_std"):
|
|
374
|
+
target_std = params.resolve_rqmc_target_std(product=product)
|
|
375
|
+
else:
|
|
376
|
+
target_std = getattr(params, "target_std", 1e-4)
|
|
377
|
+
if hasattr(params, "resolve_rqmc_paths_per_batch"):
|
|
378
|
+
per_batch_paths = params.resolve_rqmc_paths_per_batch(
|
|
379
|
+
max_batches=max_batches
|
|
380
|
+
)
|
|
381
|
+
else:
|
|
382
|
+
per_batch_paths = params.num_paths
|
|
383
|
+
|
|
384
|
+
generator = self._create_path_generator(
|
|
385
|
+
S, r, q, sigma, T, num_paths=per_batch_paths
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
result = run_rqmc(
|
|
389
|
+
pricer_fn=pricer_fn,
|
|
390
|
+
path_generator=generator,
|
|
391
|
+
max_batches=max_batches,
|
|
392
|
+
target_std=target_std,
|
|
393
|
+
min_batches=min_batches,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
self._last_rqmc_result = result
|
|
397
|
+
|
|
398
|
+
return result.price, result.std_error
|
|
399
|
+
|
|
400
|
+
def get_last_std_error(self) -> Optional[float]:
|
|
401
|
+
"""
|
|
402
|
+
Get the standard error from the last pricing run.
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
Standard error, or None if no pricing has been performed yet
|
|
406
|
+
"""
|
|
407
|
+
return getattr(self, '_last_std_error', None)
|
|
408
|
+
|
|
409
|
+
def get_last_rqmc_result(self):
|
|
410
|
+
"""
|
|
411
|
+
Get the full RQMC result from the last RQMC pricing run.
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
RQMCResult object, or None if last pricing was not RQMC
|
|
415
|
+
"""
|
|
416
|
+
return getattr(self, '_last_rqmc_result', None)
|
|
417
|
+
|
|
418
|
+
def __repr__(self):
|
|
419
|
+
return f"DigitalOptionMCEngine(method={self.method.name})"
|