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,423 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Monte Carlo pricing engine for European vanilla 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 import EuropeanVanillaOption
|
|
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
|
+
from quantark.util.numerical import safe_exp
|
|
17
|
+
|
|
18
|
+
from quantark.asset.equity.process.bsm.qmc_path_generator import GBMPathGenerator
|
|
19
|
+
from quantark.asset.equity.process.bsm.qmc_sobol import (
|
|
20
|
+
PseudoRandomNormalGenerator,
|
|
21
|
+
SobolNormalGenerator,
|
|
22
|
+
)
|
|
23
|
+
from quantark.asset.equity.process.bsm.qmc_rqmc_driver import run_rqmc
|
|
24
|
+
from quantark.asset.equity.process.bsm.qmc_variance_reduction import VarianceReductionConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class EuropeanMCEngine(BaseEngine):
|
|
28
|
+
"""
|
|
29
|
+
Monte Carlo pricing engine for European vanilla options.
|
|
30
|
+
|
|
31
|
+
Supports three Monte Carlo methods:
|
|
32
|
+
- PSEUDO: Standard Monte Carlo with pseudorandom numbers
|
|
33
|
+
- QUASI: Quasi-Monte Carlo with Sobol sequences
|
|
34
|
+
- RANDOMIZED_QUASI: Randomized QMC with adaptive batching
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
# Preferred: Two-level enum pattern
|
|
38
|
+
engine = EuropeanMCEngine(
|
|
39
|
+
params=MCParams(num_paths=10000, time_steps=252),
|
|
40
|
+
method=EngineType.MONTE_CARLO(MonteCarloMethod.QUASI)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Alternative: Direct method enum
|
|
44
|
+
engine = EuropeanMCEngine(
|
|
45
|
+
params=MCParams(num_paths=10000),
|
|
46
|
+
method=MonteCarloMethod.QUASI
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Backward compatibility: String
|
|
50
|
+
engine = EuropeanMCEngine(method="quasi")
|
|
51
|
+
|
|
52
|
+
The engine creates a GBMPathGenerator internally based on the pricing
|
|
53
|
+
environment and MCParams configuration.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
engine_type = EngineType.MONTE_CARLO
|
|
57
|
+
|
|
58
|
+
DEFAULT_METHOD = MonteCarloMethod.PSEUDO
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
params: Optional[MCParams] = None,
|
|
63
|
+
method: Union[str, MonteCarloMethod, tuple, None] = None,
|
|
64
|
+
):
|
|
65
|
+
"""
|
|
66
|
+
Initialize Monte Carlo engine.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
params: Monte Carlo configuration parameters (MCParams)
|
|
70
|
+
method: Monte Carlo method selection, one of:
|
|
71
|
+
- EngineType.MONTE_CARLO(MonteCarloMethod.XXX) (preferred)
|
|
72
|
+
- MonteCarloMethod.XXX
|
|
73
|
+
- String: "pseudo", "quasi", "randomized_quasi"
|
|
74
|
+
- None: defaults to MonteCarloMethod.PSEUDO
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
ValidationError: If method is invalid or params are invalid
|
|
78
|
+
"""
|
|
79
|
+
if params is None:
|
|
80
|
+
params = MCParams()
|
|
81
|
+
|
|
82
|
+
if not isinstance(params, MCParams):
|
|
83
|
+
raise ValidationError(
|
|
84
|
+
f"params must be MCParams instance, got {type(params).__name__}"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
super().__init__(params)
|
|
88
|
+
|
|
89
|
+
if method is None:
|
|
90
|
+
self.method = self.DEFAULT_METHOD
|
|
91
|
+
elif isinstance(method, tuple):
|
|
92
|
+
engine_type, mc_method = method
|
|
93
|
+
if engine_type != EngineType.MONTE_CARLO:
|
|
94
|
+
raise ValidationError(
|
|
95
|
+
f"Expected EngineType.MONTE_CARLO, got {engine_type}"
|
|
96
|
+
)
|
|
97
|
+
if not isinstance(mc_method, MonteCarloMethod):
|
|
98
|
+
raise ValidationError(
|
|
99
|
+
f"Expected MonteCarloMethod, got {type(mc_method).__name__}"
|
|
100
|
+
)
|
|
101
|
+
self.method = mc_method
|
|
102
|
+
elif isinstance(method, MonteCarloMethod):
|
|
103
|
+
self.method = method
|
|
104
|
+
elif isinstance(method, str):
|
|
105
|
+
try:
|
|
106
|
+
self.method = MonteCarloMethod[method.upper()]
|
|
107
|
+
except KeyError:
|
|
108
|
+
valid_methods = [m.name for m in MonteCarloMethod]
|
|
109
|
+
raise ValidationError(
|
|
110
|
+
f"Invalid method string '{method}'. Valid methods: {valid_methods}"
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
raise ValidationError(
|
|
114
|
+
f"Invalid method type {type(method).__name__}. "
|
|
115
|
+
"Expected MonteCarloMethod, tuple, str, or None"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def price(
|
|
119
|
+
self, product: BaseEquityProduct, pricing_env: PricingEnvironment
|
|
120
|
+
) -> float:
|
|
121
|
+
"""
|
|
122
|
+
Price a European vanilla option using Monte Carlo simulation.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
product: European vanilla option to price
|
|
126
|
+
pricing_env: Pricing environment with market data
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Option price
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
PricingError: If product is not a European vanilla option
|
|
133
|
+
ValidationError: If pricing parameters are invalid
|
|
134
|
+
"""
|
|
135
|
+
if not isinstance(product, EuropeanVanillaOption):
|
|
136
|
+
raise PricingError(
|
|
137
|
+
f"EuropeanMCEngine only supports EuropeanVanillaOption, "
|
|
138
|
+
f"got {type(product).__name__}"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
S = pricing_env.spot
|
|
142
|
+
K = product.strike
|
|
143
|
+
T = product.get_maturity(pricing_env)
|
|
144
|
+
r = pricing_env.get_rate(T)
|
|
145
|
+
q = pricing_env.get_div_yield(T)
|
|
146
|
+
sigma = pricing_env.get_vol(K, T)
|
|
147
|
+
|
|
148
|
+
self._validate_inputs(S, K, T, r, q, sigma)
|
|
149
|
+
|
|
150
|
+
if T < 1e-10:
|
|
151
|
+
return product.get_payoff(S)
|
|
152
|
+
|
|
153
|
+
if self.method == MonteCarloMethod.RANDOMIZED_QUASI:
|
|
154
|
+
price, std_error = self._price_rqmc(
|
|
155
|
+
product, S, K, T, r, q, sigma
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
price, std_error = self._price_mc_or_qmc(
|
|
159
|
+
product, S, K, T, r, q, sigma
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
contract_multiplier = product.contract_multiplier
|
|
163
|
+
price *= contract_multiplier
|
|
164
|
+
std_error *= contract_multiplier
|
|
165
|
+
self._last_std_error = std_error
|
|
166
|
+
|
|
167
|
+
if price < 0:
|
|
168
|
+
raise PricingError(f"Negative price computed: {price}")
|
|
169
|
+
|
|
170
|
+
lower_bound = self._european_lower_bound(product, S, K, T, r, q)
|
|
171
|
+
if price < lower_bound - 1e-6:
|
|
172
|
+
raise PricingError(
|
|
173
|
+
f"Price ({price:.6f}) below discounted European lower bound "
|
|
174
|
+
f"({lower_bound:.6f})"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return price
|
|
178
|
+
|
|
179
|
+
def _european_lower_bound(
|
|
180
|
+
self,
|
|
181
|
+
product: EuropeanVanillaOption,
|
|
182
|
+
S: float,
|
|
183
|
+
K: float,
|
|
184
|
+
T: float,
|
|
185
|
+
r: float,
|
|
186
|
+
q: float,
|
|
187
|
+
) -> float:
|
|
188
|
+
"""Calculate the discounted no-arbitrage lower bound for a European option."""
|
|
189
|
+
spot_pv = S * safe_exp(-q * T)
|
|
190
|
+
strike_pv = K * safe_exp(-r * T)
|
|
191
|
+
if product.is_call():
|
|
192
|
+
lower_bound = max(spot_pv - strike_pv, 0.0)
|
|
193
|
+
else:
|
|
194
|
+
lower_bound = max(strike_pv - spot_pv, 0.0)
|
|
195
|
+
return lower_bound * product.contract_multiplier
|
|
196
|
+
|
|
197
|
+
def _validate_inputs(
|
|
198
|
+
self, S: float, K: float, T: float, r: float, q: float, sigma: float
|
|
199
|
+
) -> None:
|
|
200
|
+
"""Validate pricing inputs."""
|
|
201
|
+
if S <= 0:
|
|
202
|
+
raise ValidationError(f"Spot price must be positive, got {S}")
|
|
203
|
+
if K <= 0:
|
|
204
|
+
raise ValidationError(f"Strike price must be positive, got {K}")
|
|
205
|
+
if T < 0:
|
|
206
|
+
raise ValidationError(f"Time to maturity must be non-negative, got {T}")
|
|
207
|
+
if sigma <= 0:
|
|
208
|
+
raise ValidationError(f"Volatility must be positive, got {sigma}")
|
|
209
|
+
if q < 0:
|
|
210
|
+
raise ValidationError(f"Dividend yield must be non-negative, got {q}")
|
|
211
|
+
|
|
212
|
+
def _create_path_generator(
|
|
213
|
+
self,
|
|
214
|
+
S: float,
|
|
215
|
+
r: float,
|
|
216
|
+
q: float,
|
|
217
|
+
sigma: float,
|
|
218
|
+
T: float,
|
|
219
|
+
num_paths: Optional[int] = None,
|
|
220
|
+
) -> GBMPathGenerator:
|
|
221
|
+
"""
|
|
222
|
+
Create a GBMPathGenerator configured for the current method.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
S: Spot price
|
|
226
|
+
r: Risk-free rate
|
|
227
|
+
q: Dividend yield
|
|
228
|
+
sigma: Volatility
|
|
229
|
+
T: Time to maturity
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Configured GBMPathGenerator
|
|
233
|
+
"""
|
|
234
|
+
params = self.params
|
|
235
|
+
effective_num_paths = params.num_paths if num_paths is None else int(num_paths)
|
|
236
|
+
if effective_num_paths <= 0:
|
|
237
|
+
raise ValidationError(
|
|
238
|
+
f"num_paths must be positive, got {effective_num_paths}"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
if self.method == MonteCarloMethod.PSEUDO:
|
|
242
|
+
random_stream = PseudoRandomNormalGenerator(seed=params.seed)
|
|
243
|
+
is_qmc = False
|
|
244
|
+
elif self.method in (MonteCarloMethod.QUASI, MonteCarloMethod.RANDOMIZED_QUASI):
|
|
245
|
+
random_stream = SobolNormalGenerator(base_seed=params.seed)
|
|
246
|
+
is_qmc = True
|
|
247
|
+
else:
|
|
248
|
+
raise ValidationError(f"Unknown Monte Carlo method: {self.method}")
|
|
249
|
+
|
|
250
|
+
vr_config = None
|
|
251
|
+
if params.use_antithetic and not is_qmc:
|
|
252
|
+
vr_config = VarianceReductionConfig(antithetic=True)
|
|
253
|
+
|
|
254
|
+
generator = GBMPathGenerator(
|
|
255
|
+
initial_value=S,
|
|
256
|
+
vol=sigma,
|
|
257
|
+
rrf=r,
|
|
258
|
+
div=q,
|
|
259
|
+
maturity=T,
|
|
260
|
+
time_steps=params.time_steps,
|
|
261
|
+
num_paths=effective_num_paths,
|
|
262
|
+
model="bsm",
|
|
263
|
+
random_stream=random_stream,
|
|
264
|
+
use_brownian_bridge=False,
|
|
265
|
+
vr_config=vr_config,
|
|
266
|
+
is_qmc=is_qmc,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
return generator
|
|
270
|
+
|
|
271
|
+
def _calculate_payoffs(
|
|
272
|
+
self, product: EuropeanVanillaOption, terminal_prices: np.ndarray
|
|
273
|
+
) -> np.ndarray:
|
|
274
|
+
"""
|
|
275
|
+
Calculate option payoffs from terminal prices.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
product: European vanilla option
|
|
279
|
+
terminal_prices: Array of terminal spot prices, shape (num_paths,)
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Array of payoffs, shape (num_paths,)
|
|
283
|
+
"""
|
|
284
|
+
K = product.strike
|
|
285
|
+
|
|
286
|
+
if product.is_call():
|
|
287
|
+
payoffs = np.maximum(terminal_prices - K, 0.0)
|
|
288
|
+
else:
|
|
289
|
+
payoffs = np.maximum(K - terminal_prices, 0.0)
|
|
290
|
+
|
|
291
|
+
return payoffs
|
|
292
|
+
|
|
293
|
+
def _price_mc_or_qmc(
|
|
294
|
+
self,
|
|
295
|
+
product: EuropeanVanillaOption,
|
|
296
|
+
S: float,
|
|
297
|
+
K: float,
|
|
298
|
+
T: float,
|
|
299
|
+
r: float,
|
|
300
|
+
q: float,
|
|
301
|
+
sigma: float,
|
|
302
|
+
) -> Tuple[float, float]:
|
|
303
|
+
"""
|
|
304
|
+
Price using normal MC or QMC (non-randomized).
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
product: European vanilla option
|
|
308
|
+
S: Spot price
|
|
309
|
+
K: Strike price
|
|
310
|
+
T: Time to maturity
|
|
311
|
+
r: Risk-free rate
|
|
312
|
+
q: Dividend yield
|
|
313
|
+
sigma: Volatility
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Tuple of (price, standard_error)
|
|
317
|
+
"""
|
|
318
|
+
generator = self._create_path_generator(S, r, q, sigma, T)
|
|
319
|
+
|
|
320
|
+
paths, aux = generator.generate_paths(return_aux=True)
|
|
321
|
+
|
|
322
|
+
terminal_prices = paths[:, -1]
|
|
323
|
+
|
|
324
|
+
payoffs = self._calculate_payoffs(product, terminal_prices)
|
|
325
|
+
|
|
326
|
+
discount_factor = math.exp(-r * T)
|
|
327
|
+
discounted_payoffs = discount_factor * payoffs
|
|
328
|
+
|
|
329
|
+
mean_payoff = float(discounted_payoffs.mean())
|
|
330
|
+
std_payoff = float(discounted_payoffs.std(ddof=1))
|
|
331
|
+
|
|
332
|
+
std_error = std_payoff / math.sqrt(len(payoffs))
|
|
333
|
+
|
|
334
|
+
return mean_payoff, std_error
|
|
335
|
+
|
|
336
|
+
def _price_rqmc(
|
|
337
|
+
self,
|
|
338
|
+
product: EuropeanVanillaOption,
|
|
339
|
+
S: float,
|
|
340
|
+
K: float,
|
|
341
|
+
T: float,
|
|
342
|
+
r: float,
|
|
343
|
+
q: float,
|
|
344
|
+
sigma: float,
|
|
345
|
+
) -> Tuple[float, float]:
|
|
346
|
+
"""
|
|
347
|
+
Price using Randomized QMC with adaptive batching.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
product: European vanilla option
|
|
351
|
+
S: Spot price
|
|
352
|
+
K: Strike price
|
|
353
|
+
T: Time to maturity
|
|
354
|
+
r: Risk-free rate
|
|
355
|
+
q: Dividend yield
|
|
356
|
+
sigma: Volatility
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
Tuple of (price, standard_error)
|
|
360
|
+
"""
|
|
361
|
+
discount_factor = math.exp(-r * T)
|
|
362
|
+
|
|
363
|
+
def pricer_fn(paths, aux):
|
|
364
|
+
"""Pricer function for RQMC driver."""
|
|
365
|
+
terminal_prices = paths[:, -1]
|
|
366
|
+
payoffs = self._calculate_payoffs(product, terminal_prices)
|
|
367
|
+
discounted_payoffs = discount_factor * payoffs
|
|
368
|
+
return discounted_payoffs
|
|
369
|
+
|
|
370
|
+
params = self.params
|
|
371
|
+
max_batches = getattr(
|
|
372
|
+
params, "rqmc_max_batches", getattr(params, "max_batches", 32)
|
|
373
|
+
)
|
|
374
|
+
min_batches = getattr(
|
|
375
|
+
params, "rqmc_min_batches", getattr(params, "min_batches", 4)
|
|
376
|
+
)
|
|
377
|
+
if hasattr(params, "resolve_rqmc_target_std"):
|
|
378
|
+
target_std = params.resolve_rqmc_target_std(product=product)
|
|
379
|
+
else:
|
|
380
|
+
target_std = getattr(params, "target_std", 1e-4)
|
|
381
|
+
if hasattr(params, "resolve_rqmc_paths_per_batch"):
|
|
382
|
+
per_batch_paths = params.resolve_rqmc_paths_per_batch(
|
|
383
|
+
max_batches=max_batches
|
|
384
|
+
)
|
|
385
|
+
else:
|
|
386
|
+
per_batch_paths = params.num_paths
|
|
387
|
+
|
|
388
|
+
generator = self._create_path_generator(
|
|
389
|
+
S, r, q, sigma, T, num_paths=per_batch_paths
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
result = run_rqmc(
|
|
393
|
+
pricer_fn=pricer_fn,
|
|
394
|
+
path_generator=generator,
|
|
395
|
+
max_batches=max_batches,
|
|
396
|
+
target_std=target_std,
|
|
397
|
+
min_batches=min_batches,
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
self._last_rqmc_result = result
|
|
401
|
+
|
|
402
|
+
return result.price, result.std_error
|
|
403
|
+
|
|
404
|
+
def get_last_std_error(self) -> Optional[float]:
|
|
405
|
+
"""
|
|
406
|
+
Get the standard error from the last pricing run.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
Standard error, or None if no pricing has been performed yet
|
|
410
|
+
"""
|
|
411
|
+
return getattr(self, '_last_std_error', None)
|
|
412
|
+
|
|
413
|
+
def get_last_rqmc_result(self):
|
|
414
|
+
"""
|
|
415
|
+
Get the full RQMC result from the last RQMC pricing run.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
RQMCResult object, or None if last pricing was not RQMC
|
|
419
|
+
"""
|
|
420
|
+
return getattr(self, '_last_rqmc_result', None)
|
|
421
|
+
|
|
422
|
+
def __repr__(self):
|
|
423
|
+
return f"EuropeanMCEngine(method={self.method.name})"
|