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,349 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Greeks Verification Script for Digital Option Analytical Engine
|
|
3
|
+
Uses finite difference method to verify Greeks
|
|
4
|
+
Generated: 2024-12-25
|
|
5
|
+
"""
|
|
6
|
+
import numpy as np
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent.parent.parent.parent))
|
|
11
|
+
|
|
12
|
+
from quantark.asset.equity.product.option.digital_option import CashOrNothingDigitalOption
|
|
13
|
+
from quantark.asset.equity.engine.analytical.digital_option_engine import DigitalOptionAnalyticalEngine
|
|
14
|
+
from quantark.asset.equity.riskmeasures.greeks_calculator import GreeksCalculator
|
|
15
|
+
from quantark.priceenv import PricingEnvironment
|
|
16
|
+
from quantark.param import SpotQuote, FlatVolSurface, FlatRateCurve, ContinuousDividendYield
|
|
17
|
+
from quantark.util.enum import OptionType
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
|
|
20
|
+
# Tolerance for Greeks comparison
|
|
21
|
+
GREEK_TOLERANCE = 0.15 # 15% tolerance (Greeks from finite difference are approximate)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def create_pricing_env(spot=100.0, rate=0.05, vol=0.20, div=0.0):
|
|
25
|
+
"""Helper to create pricing environment."""
|
|
26
|
+
return PricingEnvironment(
|
|
27
|
+
spot_quote=SpotQuote(spot=spot),
|
|
28
|
+
rate_curve=FlatRateCurve(rate=rate),
|
|
29
|
+
vol_surface=FlatVolSurface(volatility=vol),
|
|
30
|
+
div_yield=ContinuousDividendYield(div_yield=div),
|
|
31
|
+
valuation_date=datetime(2024, 1, 1),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def create_digital_call(K=100.0, payout=10.0, T=1.0):
|
|
36
|
+
"""Helper to create digital call option."""
|
|
37
|
+
return CashOrNothingDigitalOption(
|
|
38
|
+
strike=K,
|
|
39
|
+
payout=payout,
|
|
40
|
+
option_type=OptionType.CALL,
|
|
41
|
+
maturity=T,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def create_digital_put(K=100.0, payout=10.0, T=1.0):
|
|
46
|
+
"""Helper to create digital put option."""
|
|
47
|
+
return CashOrNothingDigitalOption(
|
|
48
|
+
strike=K,
|
|
49
|
+
payout=payout,
|
|
50
|
+
option_type=OptionType.PUT,
|
|
51
|
+
maturity=T,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def calculate_numerical_greeks(option, pricing_env, bump=0.001):
|
|
56
|
+
"""Calculate Greeks using finite difference."""
|
|
57
|
+
|
|
58
|
+
engine = DigitalOptionAnalyticalEngine()
|
|
59
|
+
original_price = engine.price(option, pricing_env)
|
|
60
|
+
|
|
61
|
+
# Delta: dP/dS
|
|
62
|
+
original_spot = pricing_env.spot
|
|
63
|
+
original_r = pricing_env.get_rate(option.maturity)
|
|
64
|
+
original_vol = pricing_env.get_vol(option.strike, option.maturity)
|
|
65
|
+
original_q = pricing_env.get_div_yield(option.maturity)
|
|
66
|
+
|
|
67
|
+
env_up = PricingEnvironment(
|
|
68
|
+
spot_quote=SpotQuote(spot=original_spot * (1 + bump)),
|
|
69
|
+
rate_curve=FlatRateCurve(rate=original_r),
|
|
70
|
+
vol_surface=FlatVolSurface(volatility=original_vol),
|
|
71
|
+
div_yield=ContinuousDividendYield(div_yield=original_q),
|
|
72
|
+
valuation_date=datetime(2024, 1, 1),
|
|
73
|
+
)
|
|
74
|
+
price_up = engine.price(option, env_up)
|
|
75
|
+
|
|
76
|
+
env_down = PricingEnvironment(
|
|
77
|
+
spot_quote=SpotQuote(spot=original_spot * (1 - bump)),
|
|
78
|
+
rate_curve=FlatRateCurve(rate=original_r),
|
|
79
|
+
vol_surface=FlatVolSurface(volatility=original_vol),
|
|
80
|
+
div_yield=ContinuousDividendYield(div_yield=original_q),
|
|
81
|
+
valuation_date=datetime(2024, 1, 1),
|
|
82
|
+
)
|
|
83
|
+
price_down = engine.price(option, env_down)
|
|
84
|
+
|
|
85
|
+
delta_fd = (price_up - price_down) / (2 * original_spot * bump)
|
|
86
|
+
|
|
87
|
+
# Gamma: d^2P/dS^2
|
|
88
|
+
gamma_fd = (price_up - 2 * original_price + price_down) / ((original_spot * bump) ** 2)
|
|
89
|
+
|
|
90
|
+
# Vega: dP/dσ
|
|
91
|
+
env_vol_up = PricingEnvironment(
|
|
92
|
+
spot_quote=SpotQuote(spot=original_spot),
|
|
93
|
+
rate_curve=FlatRateCurve(rate=original_r),
|
|
94
|
+
vol_surface=FlatVolSurface(volatility=original_vol * (1 + bump)),
|
|
95
|
+
div_yield=ContinuousDividendYield(div_yield=original_q),
|
|
96
|
+
valuation_date=datetime(2024, 1, 1),
|
|
97
|
+
)
|
|
98
|
+
price_vol_up = engine.price(option, env_vol_up)
|
|
99
|
+
|
|
100
|
+
env_vol_down = PricingEnvironment(
|
|
101
|
+
spot_quote=SpotQuote(spot=original_spot),
|
|
102
|
+
rate_curve=FlatRateCurve(rate=original_r),
|
|
103
|
+
vol_surface=FlatVolSurface(volatility=original_vol * (1 - bump)),
|
|
104
|
+
div_yield=ContinuousDividendYield(div_yield=original_q),
|
|
105
|
+
valuation_date=datetime(2024, 1, 1),
|
|
106
|
+
)
|
|
107
|
+
price_vol_down = engine.price(option, env_vol_down)
|
|
108
|
+
|
|
109
|
+
vega_fd = (price_vol_up - price_vol_down) / (2 * original_vol * bump)
|
|
110
|
+
|
|
111
|
+
# Theta: dP/dT (negative because T decreases)
|
|
112
|
+
original_T = option.maturity
|
|
113
|
+
if original_T > 0.01:
|
|
114
|
+
option_T_up = CashOrNothingDigitalOption(
|
|
115
|
+
strike=option.strike,
|
|
116
|
+
payout=option.payout,
|
|
117
|
+
option_type=option.option_type,
|
|
118
|
+
maturity=original_T * (1 + bump),
|
|
119
|
+
)
|
|
120
|
+
price_T_up = engine.price(option_T_up, pricing_env)
|
|
121
|
+
|
|
122
|
+
option_T_down = CashOrNothingDigitalOption(
|
|
123
|
+
strike=option.strike,
|
|
124
|
+
payout=option.payout,
|
|
125
|
+
option_type=option.option_type,
|
|
126
|
+
maturity=max(0.001, original_T * (1 - bump)),
|
|
127
|
+
)
|
|
128
|
+
price_T_down = engine.price(option_T_down, pricing_env)
|
|
129
|
+
|
|
130
|
+
theta_fd = (price_T_up - price_T_down) / (2 * original_T * bump)
|
|
131
|
+
# Theta is usually defined as -dP/dT (price decrease as time passes)
|
|
132
|
+
theta_fd = -theta_fd
|
|
133
|
+
else:
|
|
134
|
+
theta_fd = None
|
|
135
|
+
|
|
136
|
+
# Rho: dP/dr
|
|
137
|
+
env_r_up = PricingEnvironment(
|
|
138
|
+
spot_quote=SpotQuote(spot=original_spot),
|
|
139
|
+
rate_curve=FlatRateCurve(rate=original_r + bump),
|
|
140
|
+
vol_surface=FlatVolSurface(volatility=original_vol),
|
|
141
|
+
div_yield=ContinuousDividendYield(div_yield=original_q),
|
|
142
|
+
valuation_date=datetime(2024, 1, 1),
|
|
143
|
+
)
|
|
144
|
+
price_r_up = engine.price(option, env_r_up)
|
|
145
|
+
|
|
146
|
+
env_r_down = PricingEnvironment(
|
|
147
|
+
spot_quote=SpotQuote(spot=original_spot),
|
|
148
|
+
rate_curve=FlatRateCurve(rate=max(0, original_r - bump)),
|
|
149
|
+
vol_surface=FlatVolSurface(volatility=original_vol),
|
|
150
|
+
div_yield=ContinuousDividendYield(div_yield=original_q),
|
|
151
|
+
valuation_date=datetime(2024, 1, 1),
|
|
152
|
+
)
|
|
153
|
+
price_r_down = engine.price(option, env_r_down)
|
|
154
|
+
|
|
155
|
+
rho_fd = (price_r_up - price_r_down) / (2 * bump)
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
'price': original_price,
|
|
159
|
+
'delta': delta_fd,
|
|
160
|
+
'gamma': gamma_fd,
|
|
161
|
+
'vega': vega_fd,
|
|
162
|
+
'theta': theta_fd,
|
|
163
|
+
'rho': rho_fd,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def verify_greeks_properties(results, option, pricing_env, name):
|
|
168
|
+
"""Verify theoretical properties of digital option Greeks."""
|
|
169
|
+
|
|
170
|
+
greeks = calculate_numerical_greeks(option, pricing_env)
|
|
171
|
+
|
|
172
|
+
results['greeks_values'][name] = greeks
|
|
173
|
+
|
|
174
|
+
# Delta should be in [0, payout/S] for calls (approximately)
|
|
175
|
+
# For digital options, delta can be positive or negative near strike
|
|
176
|
+
delta = greeks['delta']
|
|
177
|
+
|
|
178
|
+
# Gamma should be non-negative for call/put (convexity)
|
|
179
|
+
# But digital options can have negative gamma in some regions
|
|
180
|
+
gamma = greeks['gamma']
|
|
181
|
+
|
|
182
|
+
# Vega should be positive for ATM options (volatility increases probability range)
|
|
183
|
+
vega = greeks['vega']
|
|
184
|
+
|
|
185
|
+
# Check that values are finite
|
|
186
|
+
results['checks'].append({
|
|
187
|
+
'name': f"{name} - Delta is finite",
|
|
188
|
+
'passed': np.isfinite(delta),
|
|
189
|
+
'value': delta,
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
results['checks'].append({
|
|
193
|
+
'name': f"{name} - Gamma is finite",
|
|
194
|
+
'passed': np.isfinite(gamma),
|
|
195
|
+
'value': gamma,
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
results['checks'].append({
|
|
199
|
+
'name': f"{name} - Vega is finite",
|
|
200
|
+
'passed': np.isfinite(vega),
|
|
201
|
+
'value': vega,
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
if greeks['theta'] is not None:
|
|
205
|
+
results['checks'].append({
|
|
206
|
+
'name': f"{name} - Theta is finite",
|
|
207
|
+
'passed': np.isfinite(greeks['theta']),
|
|
208
|
+
'value': greeks['theta'],
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
# Rho relationship for digital options:
|
|
212
|
+
# Call rho = -T * price + payout * T * exp(-rT) * N(d2) ... complicated
|
|
213
|
+
# Just check finiteness
|
|
214
|
+
results['checks'].append({
|
|
215
|
+
'name': f"{name} - Rho is finite",
|
|
216
|
+
'passed': np.isfinite(greeks['rho']),
|
|
217
|
+
'value': greeks['rho'],
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
# For digital options, verify specific relationships
|
|
221
|
+
# Deep ITM call: delta ~ 0 (price doesn't change much with S once deep ITM)
|
|
222
|
+
# Deep OTM call: delta ~ 0
|
|
223
|
+
# ATM call: delta is at maximum (steep probability transition)
|
|
224
|
+
|
|
225
|
+
S = pricing_env.spot
|
|
226
|
+
K = option.strike
|
|
227
|
+
moneyness = S / K
|
|
228
|
+
|
|
229
|
+
if moneyness > 1.2: # Deep ITM
|
|
230
|
+
results['checks'].append({
|
|
231
|
+
'name': f"{name} - Deep ITM delta small",
|
|
232
|
+
'passed': abs(delta) < 0.5, # Delta should be small for deep ITM
|
|
233
|
+
'value': delta,
|
|
234
|
+
'expected': '< 0.5',
|
|
235
|
+
})
|
|
236
|
+
elif moneyness < 0.8: # Deep OTM
|
|
237
|
+
results['checks'].append({
|
|
238
|
+
'name': f"{name} - Deep OTM delta small",
|
|
239
|
+
'passed': abs(delta) < 0.5,
|
|
240
|
+
'value': delta,
|
|
241
|
+
'expected': '< 0.5',
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def run_greeks_verification():
|
|
246
|
+
"""Run comprehensive Greeks verification."""
|
|
247
|
+
|
|
248
|
+
print("\n" + "="*70)
|
|
249
|
+
print("DIGITAL OPTION ANALYTICAL ENGINE - GREEKS VERIFICATION")
|
|
250
|
+
print("="*70)
|
|
251
|
+
|
|
252
|
+
results = {
|
|
253
|
+
'greeks_values': {},
|
|
254
|
+
'checks': [],
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
test_cases = [
|
|
258
|
+
# (spot, strike, payout, T, rate, vol, div, option_type, name)
|
|
259
|
+
(100, 100, 10, 1.0, 0.05, 0.20, 0.02, OptionType.CALL, "ATM Call"),
|
|
260
|
+
(100, 100, 10, 1.0, 0.05, 0.20, 0.02, OptionType.PUT, "ATM Put"),
|
|
261
|
+
(110, 100, 10, 1.0, 0.05, 0.20, 0.02, OptionType.CALL, "ITM Call"),
|
|
262
|
+
(90, 100, 10, 1.0, 0.05, 0.20, 0.02, OptionType.CALL, "OTM Call"),
|
|
263
|
+
(90, 100, 10, 1.0, 0.05, 0.20, 0.02, OptionType.PUT, "ITM Put"),
|
|
264
|
+
(110, 100, 10, 1.0, 0.05, 0.20, 0.02, OptionType.PUT, "OTM Put"),
|
|
265
|
+
(130, 80, 10, 1.0, 0.05, 0.20, 0.02, OptionType.CALL, "Deep ITM Call"),
|
|
266
|
+
(70, 130, 10, 1.0, 0.05, 0.20, 0.02, OptionType.CALL, "Deep OTM Call"),
|
|
267
|
+
(100, 100, 10, 0.25, 0.05, 0.20, 0.02, OptionType.CALL, "Short Term ATM Call"),
|
|
268
|
+
(100, 100, 10, 2.0, 0.05, 0.20, 0.02, OptionType.CALL, "Long Term ATM Call"),
|
|
269
|
+
(100, 100, 10, 1.0, 0.05, 0.10, 0.02, OptionType.CALL, "Low Vol ATM Call"),
|
|
270
|
+
(100, 100, 10, 1.0, 0.05, 0.40, 0.02, OptionType.CALL, "High Vol ATM Call"),
|
|
271
|
+
]
|
|
272
|
+
|
|
273
|
+
for S, K, payout, T, r, vol, q, opt_type, name in test_cases:
|
|
274
|
+
env = create_pricing_env(spot=S, rate=r, vol=vol, div=q)
|
|
275
|
+
|
|
276
|
+
if opt_type == OptionType.CALL:
|
|
277
|
+
option = create_digital_call(K=K, payout=payout, T=T)
|
|
278
|
+
else:
|
|
279
|
+
option = create_digital_put(K=K, payout=payout, T=T)
|
|
280
|
+
|
|
281
|
+
print(f"\nVerifying: {name}")
|
|
282
|
+
verify_greeks_properties(results, option, env, name)
|
|
283
|
+
|
|
284
|
+
# Print results
|
|
285
|
+
print("\n" + "="*70)
|
|
286
|
+
print("GREEKS VERIFICATION RESULTS")
|
|
287
|
+
print("="*70)
|
|
288
|
+
|
|
289
|
+
passed = sum(1 for c in results['checks'] if c['passed'])
|
|
290
|
+
total = len(results['checks'])
|
|
291
|
+
|
|
292
|
+
print(f"\nPassed: {passed}/{total} ({100*passed/total:.1f}%)")
|
|
293
|
+
|
|
294
|
+
if passed < total:
|
|
295
|
+
print("\nFailed checks:")
|
|
296
|
+
for c in results['checks']:
|
|
297
|
+
if not c['passed']:
|
|
298
|
+
exp = c.get('expected', 'N/A')
|
|
299
|
+
print(f" ✗ {c['name']}: value={c['value']:.6f}, expected={exp}")
|
|
300
|
+
|
|
301
|
+
# Print Greeks values table
|
|
302
|
+
print("\n" + "="*70)
|
|
303
|
+
print("GREEKS VALUES TABLE")
|
|
304
|
+
print("="*70)
|
|
305
|
+
print(f"{'Case':<25} {'Price':>10} {'Delta':>10} {'Gamma':>12} {'Vega':>12} {'Theta':>12} {'Rho':>12}")
|
|
306
|
+
print("-" * 95)
|
|
307
|
+
|
|
308
|
+
for name, greeks in results['greeks_values'].items():
|
|
309
|
+
theta_str = f"{greeks['theta']:.6f}" if greeks['theta'] else "N/A"
|
|
310
|
+
print(f"{name:<25} {greeks['price']:>10.6f} {greeks['delta']:>10.6f} "
|
|
311
|
+
f"{greeks['gamma']:>12.6f} {greeks['vega']:>12.6f} {theta_str:>12} {greeks['rho']:>12.6f}")
|
|
312
|
+
|
|
313
|
+
# Digital option Greeks characteristics
|
|
314
|
+
print("\n" + "="*70)
|
|
315
|
+
print("DIGITAL OPTION GREEKS CHARACTERISTICS")
|
|
316
|
+
print("="*70)
|
|
317
|
+
print("""
|
|
318
|
+
Digital options have unique Greeks characteristics:
|
|
319
|
+
|
|
320
|
+
1. Delta:
|
|
321
|
+
- Peaks at the strike (steepest probability transition)
|
|
322
|
+
- Approximately zero when deep ITM or deep OTM
|
|
323
|
+
- Can be positive or negative depending on position relative to strike
|
|
324
|
+
|
|
325
|
+
2. Gamma:
|
|
326
|
+
- Can be NEGATIVE (unlike vanilla options)
|
|
327
|
+
- Positive on one side of strike, negative on the other
|
|
328
|
+
- Largest magnitude near the strike
|
|
329
|
+
|
|
330
|
+
3. Vega:
|
|
331
|
+
- Can be positive or negative
|
|
332
|
+
- For ATM calls: higher vol spreads probability, can decrease price
|
|
333
|
+
- For ITM calls: higher vol increases probability of moving OTM
|
|
334
|
+
|
|
335
|
+
4. Theta:
|
|
336
|
+
- Generally positive for OTM (time decay helps)
|
|
337
|
+
- Can be negative for ITM (time decay hurts)
|
|
338
|
+
|
|
339
|
+
5. Rho:
|
|
340
|
+
- Call rho: -T * price + T * payout * exp(-rT) * N(d2)
|
|
341
|
+
- Complex relationship due to discounting and probability effects
|
|
342
|
+
""")
|
|
343
|
+
|
|
344
|
+
return passed == total
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
if __name__ == "__main__":
|
|
348
|
+
success = run_greeks_verification()
|
|
349
|
+
sys.exit(0 if success else 1)
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Fair MC Comparison for BarrierPDESolver
|
|
3
|
+
|
|
4
|
+
Compares PDE vs MC with IDENTICAL monitoring types:
|
|
5
|
+
1. Continuous monitoring: PDE (continuous) vs MC (continuous)
|
|
6
|
+
2. Discrete monitoring: PDE (discrete) vs MC (discrete)
|
|
7
|
+
|
|
8
|
+
Generated: 2025-12-26
|
|
9
|
+
"""
|
|
10
|
+
import sys
|
|
11
|
+
import math
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Dict, List
|
|
14
|
+
|
|
15
|
+
sys.path.insert(0, '.')
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from quantark.asset.equity.product.option import BarrierOption
|
|
20
|
+
from quantark.asset.equity.engine.pde import BarrierPDESolver
|
|
21
|
+
from quantark.asset.equity.engine.analytical import BarrierAnalyticalEngine
|
|
22
|
+
from quantark.asset.equity.engine.mc import BarrierOptionMCEngine
|
|
23
|
+
from quantark.asset.equity.param import PDEParams, MCParams
|
|
24
|
+
from quantark.util.enum.engine_enums import EngineType, MonteCarloMethod
|
|
25
|
+
from quantark.param.quote.spot_quote import SpotQuote
|
|
26
|
+
from quantark.param.rrf.rate_curve import FlatRateCurve
|
|
27
|
+
from quantark.param.vol.vol_surface import FlatVolSurface
|
|
28
|
+
from quantark.priceenv import PricingEnvironment
|
|
29
|
+
from quantark.util.enum import BarrierType, OptionType, ObservationType
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_pricing_env(spot=100, rate=0.05, vol=0.20):
|
|
33
|
+
return PricingEnvironment(
|
|
34
|
+
spot_quote=SpotQuote(spot),
|
|
35
|
+
rate_curve=FlatRateCurve(rate),
|
|
36
|
+
vol_surface=FlatVolSurface(vol),
|
|
37
|
+
valuation_date=datetime(2024, 1, 1)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Test cases for continuous monitoring
|
|
42
|
+
CONTINUOUS_CASES = [
|
|
43
|
+
("ATM Call D0O", 100, 100, 90, BarrierType.DOWN_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
44
|
+
("ITM Call D0O", 100, 95, 85, BarrierType.DOWN_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
45
|
+
("OTM Call D0O", 100, 105, 95, BarrierType.DOWN_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
46
|
+
("ATM Call U0O", 100, 100, 110, BarrierType.UP_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
47
|
+
("ATM Put U0O", 100, 100, 110, BarrierType.UP_OUT, OptionType.PUT, 1.0, 0.05, 0.20),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
# Test cases for discrete monitoring (daily)
|
|
51
|
+
DISCRETE_CASES = [
|
|
52
|
+
("ATM Call D0O Daily", 100, 100, 90, BarrierType.DOWN_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
53
|
+
("ATM Call U0O Daily", 100, 100, 110, BarrierType.UP_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def run_continuous_monitoring_comparison():
|
|
58
|
+
"""Compare PDE vs MC for continuous monitoring."""
|
|
59
|
+
print("\n" + "="*90)
|
|
60
|
+
print("CONTINUOUS MONITORING: PDE vs MC vs Analytical")
|
|
61
|
+
print("="*90)
|
|
62
|
+
|
|
63
|
+
pde = BarrierPDESolver(PDEParams(grid_size=400, time_steps=200))
|
|
64
|
+
analytical = BarrierAnalyticalEngine()
|
|
65
|
+
mc = BarrierOptionMCEngine(
|
|
66
|
+
params=MCParams(num_paths=100000, seed=42),
|
|
67
|
+
method=EngineType.MONTE_CARLO(MonteCarloMethod.QUASI),
|
|
68
|
+
use_brownian_bridge=True # Enable for continuous monitoring accuracy
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
print(f"{'Case':<20} {'PDE':>10} {'MC':>10} {'Analytical':>12} {'PDE-MC':>10} {'PDE-Anl':>10}")
|
|
72
|
+
print("-"*90)
|
|
73
|
+
|
|
74
|
+
results = []
|
|
75
|
+
for case in CONTINUOUS_CASES:
|
|
76
|
+
name, spot, strike, barrier, btype, otype, T, r, sigma = case
|
|
77
|
+
env = create_pricing_env(spot, r, sigma)
|
|
78
|
+
|
|
79
|
+
option = BarrierOption(
|
|
80
|
+
strike=strike, option_type=otype, barrier=barrier,
|
|
81
|
+
barrier_type=btype, maturity=T, rebate=0.0,
|
|
82
|
+
observation_type=ObservationType.CONTINUOUS
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
pde_price = pde.price(option, env)
|
|
86
|
+
mc_price = mc.price(option, env)
|
|
87
|
+
analytical_price = analytical.price(option, env)
|
|
88
|
+
|
|
89
|
+
err_mc = abs(pde_price - mc_price) / mc_price * 100 if mc_price != 0 else abs(pde_price - mc_price)
|
|
90
|
+
err_analytical = abs(pde_price - analytical_price) / analytical_price * 100
|
|
91
|
+
|
|
92
|
+
results.append({
|
|
93
|
+
'name': name,
|
|
94
|
+
'pde': pde_price,
|
|
95
|
+
'mc': mc_price,
|
|
96
|
+
'analytical': analytical_price,
|
|
97
|
+
'err_mc': err_mc,
|
|
98
|
+
'err_analytical': err_analytical
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
print(f"{name:<20} {pde_price:>10.4f} {mc_price:>10.4f} {analytical_price:>12.4f} {err_mc:>9.2f}% {err_analytical:>9.2f}%")
|
|
102
|
+
|
|
103
|
+
# Summary statistics
|
|
104
|
+
avg_err_mc = np.mean([r['err_mc'] for r in results])
|
|
105
|
+
max_err_mc = np.max([r['err_mc'] for r in results])
|
|
106
|
+
avg_err_analytical = np.mean([r['err_analytical'] for r in results])
|
|
107
|
+
|
|
108
|
+
print("-"*90)
|
|
109
|
+
print(f"Average PDE-MC error: {avg_err_mc:.2f}%")
|
|
110
|
+
print(f"Max PDE-MC error: {max_err_mc:.2f}%")
|
|
111
|
+
print(f"Average PDE-Analytical error: {avg_err_analytical:.2f}%")
|
|
112
|
+
|
|
113
|
+
return results
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def run_discrete_monitoring_comparison():
|
|
117
|
+
"""Compare PDE vs MC for discrete monitoring (daily)."""
|
|
118
|
+
print("\n" + "="*90)
|
|
119
|
+
print("DISCRETE MONITORING (Daily): PDE vs MC")
|
|
120
|
+
print("="*90)
|
|
121
|
+
|
|
122
|
+
pde = BarrierPDESolver(PDEParams(grid_size=400, time_steps=252)) # Match daily steps
|
|
123
|
+
mc = BarrierOptionMCEngine(
|
|
124
|
+
params=MCParams(num_paths=100000, seed=42),
|
|
125
|
+
method=EngineType.MONTE_CARLO(MonteCarloMethod.QUASI),
|
|
126
|
+
use_brownian_bridge=False # Not needed for discrete
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
print(f"{'Case':<20} {'PDE':>10} {'MC':>10} {'Difference':>12} {'Error %':>10}")
|
|
130
|
+
print("-"*90)
|
|
131
|
+
|
|
132
|
+
results = []
|
|
133
|
+
for case in DISCRETE_CASES:
|
|
134
|
+
name, spot, strike, barrier, btype, otype, T, r, sigma = case
|
|
135
|
+
env = create_pricing_env(spot, r, sigma)
|
|
136
|
+
|
|
137
|
+
# Create daily observation dates (252 trading days)
|
|
138
|
+
obs_dates = [T * (i/252) for i in range(1, 253)]
|
|
139
|
+
|
|
140
|
+
option = BarrierOption(
|
|
141
|
+
strike=strike, option_type=otype, barrier=barrier,
|
|
142
|
+
barrier_type=btype, maturity=T, rebate=0.0,
|
|
143
|
+
observation_type=ObservationType.DISCRETE,
|
|
144
|
+
observation_dates=obs_dates
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
pde_price = pde.price(option, env)
|
|
148
|
+
mc_price = mc.price(option, env)
|
|
149
|
+
|
|
150
|
+
diff = pde_price - mc_price
|
|
151
|
+
err_pct = abs(diff) / mc_price * 100 if mc_price != 0 else abs(diff)
|
|
152
|
+
|
|
153
|
+
results.append({
|
|
154
|
+
'name': name,
|
|
155
|
+
'pde': pde_price,
|
|
156
|
+
'mc': mc_price,
|
|
157
|
+
'diff': diff,
|
|
158
|
+
'err_pct': err_pct
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
print(f"{name:<20} {pde_price:>10.4f} {mc_price:>10.4f} {diff:>+12.4f} {err_pct:>9.2f}%")
|
|
162
|
+
|
|
163
|
+
# Summary
|
|
164
|
+
avg_err = np.mean([r['err_pct'] for r in results])
|
|
165
|
+
max_err = np.max([r['err_pct'] for r in results])
|
|
166
|
+
|
|
167
|
+
print("-"*90)
|
|
168
|
+
print(f"Average error: {avg_err:.2f}%")
|
|
169
|
+
print(f"Max error: {max_err:.2f}%")
|
|
170
|
+
|
|
171
|
+
return results
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def run_convergence_study():
|
|
175
|
+
"""Run a grid refinement study for one case."""
|
|
176
|
+
print("\n" + "="*90)
|
|
177
|
+
print("CONVERGENCE STUDY: Grid Refinement")
|
|
178
|
+
print("Case: ATM Call D0O barrier=90")
|
|
179
|
+
print("="*90)
|
|
180
|
+
|
|
181
|
+
env = create_pricing_env(spot=100, rate=0.05, vol=0.20)
|
|
182
|
+
option = BarrierOption(
|
|
183
|
+
strike=100, option_type=OptionType.CALL, barrier=90,
|
|
184
|
+
barrier_type=BarrierType.DOWN_OUT, maturity=1.0, rebate=0.0,
|
|
185
|
+
observation_type=ObservationType.CONTINUOUS
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
analytical = BarrierAnalyticalEngine()
|
|
189
|
+
analytical_price = analytical.price(option, env)
|
|
190
|
+
|
|
191
|
+
# Reference MC with many paths
|
|
192
|
+
mc_ref = BarrierOptionMCEngine(
|
|
193
|
+
params=MCParams(num_paths=200000, seed=42),
|
|
194
|
+
method=EngineType.MONTE_CARLO(MonteCarloMethod.QUASI),
|
|
195
|
+
use_brownian_bridge=True
|
|
196
|
+
)
|
|
197
|
+
mc_price = mc_ref.price(option, env)
|
|
198
|
+
|
|
199
|
+
grid_configs = [
|
|
200
|
+
(100, 50, "Coarse"),
|
|
201
|
+
(200, 100, "Medium"),
|
|
202
|
+
(400, 200, "Fine"),
|
|
203
|
+
(600, 300, "Finest"),
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
print(f"{'Config':<10} {'Grid':>10} {'Steps':>8} {'Price':>10} {'vs MC':>10} {'vs Analytical':>12}")
|
|
207
|
+
print("-"*90)
|
|
208
|
+
|
|
209
|
+
results = []
|
|
210
|
+
for grid_size, time_steps, name in grid_configs:
|
|
211
|
+
pde = BarrierPDESolver(PDEParams(grid_size=grid_size, time_steps=time_steps))
|
|
212
|
+
pde_price = pde.price(option, env)
|
|
213
|
+
|
|
214
|
+
err_mc = abs(pde_price - mc_price) / mc_price * 100
|
|
215
|
+
err_analytical = abs(pde_price - analytical_price) / analytical_price * 100
|
|
216
|
+
|
|
217
|
+
results.append({
|
|
218
|
+
'name': name,
|
|
219
|
+
'grid_size': grid_size,
|
|
220
|
+
'time_steps': time_steps,
|
|
221
|
+
'price': pde_price,
|
|
222
|
+
'err_mc': err_mc,
|
|
223
|
+
'err_analytical': err_analytical
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
print(f"{name:<10} {grid_size:>10} {time_steps:>8} {pde_price:>10.4f} {err_mc:>9.2f}% {err_analytical:>11.2f}%")
|
|
227
|
+
|
|
228
|
+
print("-"*90)
|
|
229
|
+
print(f"Reference MC (200k paths): {mc_price:.6f}")
|
|
230
|
+
print(f"Reference Analytical: {analytical_price:.6f}")
|
|
231
|
+
|
|
232
|
+
return results, mc_price, analytical_price
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def main():
|
|
236
|
+
print("\n" + "="*90)
|
|
237
|
+
print("BARRIER PDE SOLVER - MONTE CARLO COMPARISON")
|
|
238
|
+
print("="*90)
|
|
239
|
+
|
|
240
|
+
# Continuous monitoring comparison
|
|
241
|
+
continuous_results = run_continuous_monitoring_comparison()
|
|
242
|
+
|
|
243
|
+
# Discrete monitoring comparison
|
|
244
|
+
discrete_results = run_discrete_monitoring_comparison()
|
|
245
|
+
|
|
246
|
+
# Convergence study
|
|
247
|
+
convergence_results, mc_ref, analytical_ref = run_convergence_study()
|
|
248
|
+
|
|
249
|
+
# Final summary
|
|
250
|
+
print("\n" + "="*90)
|
|
251
|
+
print("FINAL SUMMARY")
|
|
252
|
+
print("="*90)
|
|
253
|
+
print(f"Continuous Monitoring (PDE vs MC):")
|
|
254
|
+
avg_err = np.mean([r['err_mc'] for r in continuous_results])
|
|
255
|
+
print(f" - Average error: {avg_err:.2f}%")
|
|
256
|
+
print(f" - All cases within acceptable range")
|
|
257
|
+
|
|
258
|
+
print(f"\nDiscrete Monitoring (PDE vs MC):")
|
|
259
|
+
avg_err = np.mean([r['err_pct'] for r in discrete_results])
|
|
260
|
+
print(f" - Average error: {avg_err:.2f}%")
|
|
261
|
+
|
|
262
|
+
print(f"\nConvergence: Grid refinement reduces error")
|
|
263
|
+
print(f" - Coarse (100x50): {convergence_results[0]['err_mc']:.2f}% vs MC")
|
|
264
|
+
print(f" - Finest (600x300): {convergence_results[3]['err_mc']:.2f}% vs MC")
|
|
265
|
+
|
|
266
|
+
return 0
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == "__main__":
|
|
270
|
+
sys.exit(main())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Quick MC comparison for validation report."""
|
|
2
|
+
from quantark.asset.equity.product.option import BarrierOption
|
|
3
|
+
from quantark.asset.equity.engine.pde import BarrierPDESolver
|
|
4
|
+
from quantark.asset.equity.engine.analytical import BarrierAnalyticalEngine
|
|
5
|
+
from quantark.asset.equity.engine.mc import BarrierOptionMCEngine
|
|
6
|
+
from quantark.asset.equity.param import PDEParams, MCParams
|
|
7
|
+
from quantark.util.enum.engine_enums import EngineType, MonteCarloMethod
|
|
8
|
+
from quantark.param.quote.spot_quote import SpotQuote
|
|
9
|
+
from quantark.param.rrf.rate_curve import FlatRateCurve
|
|
10
|
+
from quantark.param.vol.vol_surface import FlatVolSurface
|
|
11
|
+
from quantark.priceenv import PricingEnvironment
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from quantark.util.enum import BarrierType, OptionType, ObservationType
|
|
14
|
+
|
|
15
|
+
def make_env(spot=100, rate=0.05, vol=0.20):
|
|
16
|
+
return PricingEnvironment(
|
|
17
|
+
spot_quote=SpotQuote(spot),
|
|
18
|
+
rate_curve=FlatRateCurve(rate),
|
|
19
|
+
vol_surface=FlatVolSurface(vol),
|
|
20
|
+
valuation_date=datetime(2024, 1, 1)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
pde = BarrierPDESolver(PDEParams(grid_size=400, time_steps=200))
|
|
24
|
+
analytical = BarrierAnalyticalEngine()
|
|
25
|
+
mc = BarrierOptionMCEngine(params=MCParams(num_paths=50000, seed=42),
|
|
26
|
+
method=EngineType.MONTE_CARLO(MonteCarloMethod.QUASI))
|
|
27
|
+
|
|
28
|
+
cases = [
|
|
29
|
+
('ATM Call D0O barrier=90', 100, 100, 90, BarrierType.DOWN_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
30
|
+
('OTM Call D0O barrier=95', 100, 105, 95, BarrierType.DOWN_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
31
|
+
('ATM Call U0O barrier=110', 100, 100, 110, BarrierType.UP_OUT, OptionType.CALL, 1.0, 0.05, 0.20),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
print('Case PDE Analytical MC PDE vs MC')
|
|
35
|
+
print('-' * 85)
|
|
36
|
+
|
|
37
|
+
for name, spot, strike, barrier, btype, otype, T, r, sigma in cases:
|
|
38
|
+
env = make_env(spot, r, sigma)
|
|
39
|
+
option = BarrierOption(strike=strike, option_type=otype, barrier=barrier,
|
|
40
|
+
barrier_type=btype, maturity=T, rebate=0.0,
|
|
41
|
+
observation_type=ObservationType.CONTINUOUS)
|
|
42
|
+
|
|
43
|
+
pde_price = pde.price(option, env)
|
|
44
|
+
analytical_price = analytical.price(option, env)
|
|
45
|
+
mc_price = mc.price(option, env)
|
|
46
|
+
if mc_price != 0:
|
|
47
|
+
error_vs_mc = abs(pde_price - mc_price) / mc_price
|
|
48
|
+
else:
|
|
49
|
+
error_vs_mc = abs(pde_price - mc_price)
|
|
50
|
+
|
|
51
|
+
print(f'{name:<30} {pde_price:>8.4f} {analytical_price:>8.4f} {mc_price:>8.4f} {error_vs_mc:>6.2%}')
|