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,416 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SIMM Taxonomy Module.
|
|
3
|
+
|
|
4
|
+
This module defines all ISDA SIMM v2.6 taxonomy elements including:
|
|
5
|
+
- Risk classes (IR, Credit, Equity, Commodity, FX)
|
|
6
|
+
- Product classes (RatesFX, Credit, Equity, Commodity)
|
|
7
|
+
- Margin types (Delta, Vega, Curvature, BaseCorr)
|
|
8
|
+
- Sensitivity types for CRIF classification
|
|
9
|
+
- Tenor definitions for IR and Credit risk
|
|
10
|
+
- Currency volatility classifications
|
|
11
|
+
- Bucket definitions for each risk class
|
|
12
|
+
- IR sub-curve definitions
|
|
13
|
+
"""
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from enum import Enum, auto
|
|
16
|
+
from typing import Dict, Tuple
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RiskClass(Enum):
|
|
20
|
+
"""SIMM risk class taxonomy.
|
|
21
|
+
|
|
22
|
+
Six risk classes as defined by ISDA SIMM specification.
|
|
23
|
+
Each risk class has its own bucketing scheme and risk weights.
|
|
24
|
+
"""
|
|
25
|
+
INTEREST_RATE = "IR"
|
|
26
|
+
CREDIT_QUALIFYING = "CreditQ"
|
|
27
|
+
CREDIT_NON_QUALIFYING = "CreditNQ"
|
|
28
|
+
EQUITY = "Equity"
|
|
29
|
+
COMMODITY = "Commodity"
|
|
30
|
+
FX = "FX"
|
|
31
|
+
|
|
32
|
+
def __str__(self) -> str:
|
|
33
|
+
return self.value
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ProductClass(Enum):
|
|
37
|
+
"""SIMM product class taxonomy.
|
|
38
|
+
|
|
39
|
+
Four product classes for margin aggregation.
|
|
40
|
+
Final SIMM is calculated per product class then summed.
|
|
41
|
+
"""
|
|
42
|
+
RATES_FX = "RatesFX"
|
|
43
|
+
CREDIT = "Credit"
|
|
44
|
+
EQUITY = "Equity"
|
|
45
|
+
COMMODITY = "Commodity"
|
|
46
|
+
|
|
47
|
+
def __str__(self) -> str:
|
|
48
|
+
return self.value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class MarginType(Enum):
|
|
52
|
+
"""SIMM margin type (sensitivity category).
|
|
53
|
+
|
|
54
|
+
Four margin types corresponding to different risk measures:
|
|
55
|
+
- Delta: First-order price sensitivity
|
|
56
|
+
- Vega: Volatility sensitivity
|
|
57
|
+
- Curvature: Second-order gamma/convexity
|
|
58
|
+
- BaseCorr: Credit base correlation (Credit Qualifying only)
|
|
59
|
+
"""
|
|
60
|
+
DELTA = "Delta"
|
|
61
|
+
VEGA = "Vega"
|
|
62
|
+
CURVATURE = "Curvature"
|
|
63
|
+
BASE_CORR = "BaseCorr"
|
|
64
|
+
|
|
65
|
+
def __str__(self) -> str:
|
|
66
|
+
return self.value
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class SensitivityType(Enum):
|
|
70
|
+
"""CRIF risk_type values for SIMM classification.
|
|
71
|
+
|
|
72
|
+
These map to specific sensitivity calculations and bucket assignments.
|
|
73
|
+
"""
|
|
74
|
+
# Interest Rate
|
|
75
|
+
RISK_IR_CURVE = "Risk_IRCurve"
|
|
76
|
+
RISK_IR_VOL = "Risk_IRVol"
|
|
77
|
+
RISK_INFLATION = "Risk_Inflation"
|
|
78
|
+
RISK_INFLATION_VOL = "Risk_InflationVol"
|
|
79
|
+
RISK_XCCY_BASIS = "Risk_XCcyBasis"
|
|
80
|
+
|
|
81
|
+
# Credit
|
|
82
|
+
RISK_CREDIT_Q = "Risk_CreditQ"
|
|
83
|
+
RISK_CREDIT_VOL = "Risk_CreditVol"
|
|
84
|
+
RISK_CREDIT_NQ = "Risk_CreditNonQ"
|
|
85
|
+
RISK_CREDIT_NQ_VOL = "Risk_CreditVolNonQ"
|
|
86
|
+
RISK_BASE_CORR = "Risk_BaseCorr"
|
|
87
|
+
|
|
88
|
+
# Equity
|
|
89
|
+
RISK_EQUITY = "Risk_Equity"
|
|
90
|
+
RISK_EQUITY_VOL = "Risk_EquityVol"
|
|
91
|
+
|
|
92
|
+
# Commodity
|
|
93
|
+
RISK_COMMODITY = "Risk_Commodity"
|
|
94
|
+
RISK_COMMODITY_VOL = "Risk_CommodityVol"
|
|
95
|
+
|
|
96
|
+
# FX
|
|
97
|
+
RISK_FX = "Risk_FX"
|
|
98
|
+
RISK_FX_VOL = "Risk_FXVol"
|
|
99
|
+
|
|
100
|
+
def __str__(self) -> str:
|
|
101
|
+
return self.value
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def risk_class(self) -> RiskClass:
|
|
105
|
+
"""Return the risk class for this sensitivity type."""
|
|
106
|
+
mapping = {
|
|
107
|
+
SensitivityType.RISK_IR_CURVE: RiskClass.INTEREST_RATE,
|
|
108
|
+
SensitivityType.RISK_IR_VOL: RiskClass.INTEREST_RATE,
|
|
109
|
+
SensitivityType.RISK_INFLATION: RiskClass.INTEREST_RATE,
|
|
110
|
+
SensitivityType.RISK_INFLATION_VOL: RiskClass.INTEREST_RATE,
|
|
111
|
+
SensitivityType.RISK_XCCY_BASIS: RiskClass.INTEREST_RATE,
|
|
112
|
+
SensitivityType.RISK_CREDIT_Q: RiskClass.CREDIT_QUALIFYING,
|
|
113
|
+
SensitivityType.RISK_CREDIT_VOL: RiskClass.CREDIT_QUALIFYING,
|
|
114
|
+
SensitivityType.RISK_BASE_CORR: RiskClass.CREDIT_QUALIFYING,
|
|
115
|
+
SensitivityType.RISK_CREDIT_NQ: RiskClass.CREDIT_NON_QUALIFYING,
|
|
116
|
+
SensitivityType.RISK_CREDIT_NQ_VOL: RiskClass.CREDIT_NON_QUALIFYING,
|
|
117
|
+
SensitivityType.RISK_EQUITY: RiskClass.EQUITY,
|
|
118
|
+
SensitivityType.RISK_EQUITY_VOL: RiskClass.EQUITY,
|
|
119
|
+
SensitivityType.RISK_COMMODITY: RiskClass.COMMODITY,
|
|
120
|
+
SensitivityType.RISK_COMMODITY_VOL: RiskClass.COMMODITY,
|
|
121
|
+
SensitivityType.RISK_FX: RiskClass.FX,
|
|
122
|
+
SensitivityType.RISK_FX_VOL: RiskClass.FX,
|
|
123
|
+
}
|
|
124
|
+
return mapping[self]
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def margin_type(self) -> MarginType:
|
|
128
|
+
"""Return the margin type for this sensitivity type."""
|
|
129
|
+
vega_types = {
|
|
130
|
+
SensitivityType.RISK_IR_VOL,
|
|
131
|
+
SensitivityType.RISK_INFLATION_VOL,
|
|
132
|
+
SensitivityType.RISK_CREDIT_VOL,
|
|
133
|
+
SensitivityType.RISK_CREDIT_NQ_VOL,
|
|
134
|
+
SensitivityType.RISK_EQUITY_VOL,
|
|
135
|
+
SensitivityType.RISK_COMMODITY_VOL,
|
|
136
|
+
SensitivityType.RISK_FX_VOL,
|
|
137
|
+
}
|
|
138
|
+
if self == SensitivityType.RISK_BASE_CORR:
|
|
139
|
+
return MarginType.BASE_CORR
|
|
140
|
+
elif self in vega_types:
|
|
141
|
+
return MarginType.VEGA
|
|
142
|
+
else:
|
|
143
|
+
return MarginType.DELTA
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class IRSubCurve(Enum):
|
|
147
|
+
"""Interest rate sub-curve definitions.
|
|
148
|
+
|
|
149
|
+
SIMM distinguishes different yield curves within each currency.
|
|
150
|
+
"""
|
|
151
|
+
OIS = "OIS"
|
|
152
|
+
LIBOR_1M = "Libor1m"
|
|
153
|
+
LIBOR_3M = "Libor3m"
|
|
154
|
+
LIBOR_6M = "Libor6m"
|
|
155
|
+
LIBOR_12M = "Libor12m"
|
|
156
|
+
PRIME = "Prime"
|
|
157
|
+
MUNICIPAL = "Municipal"
|
|
158
|
+
|
|
159
|
+
def __str__(self) -> str:
|
|
160
|
+
return self.value
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# -----------------------------------------------------------------------------
|
|
164
|
+
# Tenor Definitions
|
|
165
|
+
# -----------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
# IR tenor vertices (in years, matching SIMM v2.6 spec)
|
|
168
|
+
IR_TENORS: Tuple[float, ...] = (
|
|
169
|
+
0.0384, # 2 weeks = 14/365
|
|
170
|
+
0.0833, # 1 month
|
|
171
|
+
0.25, # 3 months
|
|
172
|
+
0.5, # 6 months
|
|
173
|
+
1.0, # 1 year
|
|
174
|
+
2.0, # 2 years
|
|
175
|
+
3.0, # 3 years
|
|
176
|
+
5.0, # 5 years
|
|
177
|
+
10.0, # 10 years
|
|
178
|
+
15.0, # 15 years
|
|
179
|
+
20.0, # 20 years
|
|
180
|
+
30.0, # 30 years
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# IR tenor labels for display
|
|
184
|
+
IR_TENOR_LABELS: Tuple[str, ...] = (
|
|
185
|
+
"2w", "1m", "3m", "6m", "1y", "2y", "3y", "5y", "10y", "15y", "20y", "30y"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Credit tenor vertices (in years)
|
|
189
|
+
CREDIT_TENORS: Tuple[float, ...] = (1.0, 2.0, 3.0, 5.0, 10.0)
|
|
190
|
+
|
|
191
|
+
# Credit tenor labels for display
|
|
192
|
+
CREDIT_TENOR_LABELS: Tuple[str, ...] = ("1y", "2y", "3y", "5y", "10y")
|
|
193
|
+
|
|
194
|
+
# Vega tenor labels (used for all risk classes)
|
|
195
|
+
VEGA_TENORS: Tuple[float, ...] = (0.5, 1.0, 3.0, 5.0, 10.0)
|
|
196
|
+
VEGA_TENOR_LABELS: Tuple[str, ...] = ("6m", "1y", "3y", "5y", "10y")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# -----------------------------------------------------------------------------
|
|
200
|
+
# Currency Volatility Classifications
|
|
201
|
+
# -----------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
class CurrencyVolatility(Enum):
|
|
204
|
+
"""Currency volatility classification for IR risk weights.
|
|
205
|
+
|
|
206
|
+
SIMM classifies currencies into three volatility buckets
|
|
207
|
+
with different risk weight scaling.
|
|
208
|
+
"""
|
|
209
|
+
REGULAR = "Regular"
|
|
210
|
+
LOW = "Low"
|
|
211
|
+
HIGH = "High"
|
|
212
|
+
|
|
213
|
+
def __str__(self) -> str:
|
|
214
|
+
return self.value
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# Low volatility currencies (major reserve currencies)
|
|
218
|
+
LOW_VOL_CURRENCIES: Tuple[str, ...] = ("EUR", "USD", "GBP", "CHF", "AUD", "NZD", "CAD", "SEK", "NOK", "DKK", "HKD", "SGD", "TWD")
|
|
219
|
+
|
|
220
|
+
# High volatility currencies (emerging markets, high inflation)
|
|
221
|
+
HIGH_VOL_CURRENCIES: Tuple[str, ...] = (
|
|
222
|
+
"ARS", "BRL", "CLP", "COP", "IDR", "INR", "MXN", "MYR", "PEN", "PHP",
|
|
223
|
+
"RUB", "THB", "TRY", "ZAR", "KRW", "HUF", "PLN", "CZK", "ILS", "RON"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_currency_volatility(currency: str) -> CurrencyVolatility:
|
|
228
|
+
"""Get the volatility classification for a currency.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
currency: Three-letter ISO currency code.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
CurrencyVolatility classification.
|
|
235
|
+
"""
|
|
236
|
+
currency = currency.upper()
|
|
237
|
+
if currency in LOW_VOL_CURRENCIES:
|
|
238
|
+
return CurrencyVolatility.LOW
|
|
239
|
+
elif currency in HIGH_VOL_CURRENCIES:
|
|
240
|
+
return CurrencyVolatility.HIGH
|
|
241
|
+
else:
|
|
242
|
+
return CurrencyVolatility.REGULAR
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# -----------------------------------------------------------------------------
|
|
246
|
+
# Bucket Definitions
|
|
247
|
+
# -----------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
@dataclass(frozen=True)
|
|
250
|
+
class IRBucket:
|
|
251
|
+
"""Interest rate bucket definition.
|
|
252
|
+
|
|
253
|
+
For IR risk, buckets are defined by currency.
|
|
254
|
+
Each currency is a separate bucket with its own risk weights.
|
|
255
|
+
|
|
256
|
+
Attributes:
|
|
257
|
+
currency: Three-letter ISO currency code.
|
|
258
|
+
volatility: Currency volatility classification.
|
|
259
|
+
"""
|
|
260
|
+
currency: str
|
|
261
|
+
volatility: CurrencyVolatility
|
|
262
|
+
|
|
263
|
+
@classmethod
|
|
264
|
+
def from_currency(cls, currency: str) -> "IRBucket":
|
|
265
|
+
"""Create an IR bucket from a currency code."""
|
|
266
|
+
return cls(
|
|
267
|
+
currency=currency.upper(),
|
|
268
|
+
volatility=get_currency_volatility(currency)
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@dataclass(frozen=True)
|
|
273
|
+
class CreditQualifyingBucket:
|
|
274
|
+
"""Credit Qualifying bucket definition.
|
|
275
|
+
|
|
276
|
+
12 buckets plus residual for Credit Qualifying risk.
|
|
277
|
+
Buckets are defined by credit quality (IG/HY) and sector.
|
|
278
|
+
|
|
279
|
+
Attributes:
|
|
280
|
+
bucket_number: Bucket identifier (1-12, or "Residual").
|
|
281
|
+
credit_quality: "IG" (Investment Grade) or "HY/NR" (High Yield/Not Rated).
|
|
282
|
+
sector: Sector description.
|
|
283
|
+
"""
|
|
284
|
+
bucket_number: int
|
|
285
|
+
credit_quality: str
|
|
286
|
+
sector: str
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
# Credit Qualifying bucket definitions (SIMM v2.6)
|
|
290
|
+
CREDIT_QUALIFYING_BUCKETS: Dict[int, CreditQualifyingBucket] = {
|
|
291
|
+
1: CreditQualifyingBucket(1, "IG", "Sovereigns including central banks"),
|
|
292
|
+
2: CreditQualifyingBucket(2, "IG", "Financials including government-backed"),
|
|
293
|
+
3: CreditQualifyingBucket(3, "IG", "Basic materials, energy, industrials"),
|
|
294
|
+
4: CreditQualifyingBucket(4, "IG", "Consumer"),
|
|
295
|
+
5: CreditQualifyingBucket(5, "IG", "Technology, telecommunications"),
|
|
296
|
+
6: CreditQualifyingBucket(6, "IG", "Health care, utilities, local government"),
|
|
297
|
+
7: CreditQualifyingBucket(7, "HY/NR", "Sovereigns including central banks"),
|
|
298
|
+
8: CreditQualifyingBucket(8, "HY/NR", "Financials including government-backed"),
|
|
299
|
+
9: CreditQualifyingBucket(9, "HY/NR", "Basic materials, energy, industrials"),
|
|
300
|
+
10: CreditQualifyingBucket(10, "HY/NR", "Consumer"),
|
|
301
|
+
11: CreditQualifyingBucket(11, "HY/NR", "Technology, telecommunications"),
|
|
302
|
+
12: CreditQualifyingBucket(12, "HY/NR", "Health care, utilities, local government"),
|
|
303
|
+
}
|
|
304
|
+
CREDIT_QUALIFYING_RESIDUAL_BUCKET = CreditQualifyingBucket(-1, "Residual", "Residual")
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@dataclass(frozen=True)
|
|
308
|
+
class CreditNonQualifyingBucket:
|
|
309
|
+
"""Credit Non-Qualifying bucket definition.
|
|
310
|
+
|
|
311
|
+
2 buckets plus residual for Credit Non-Qualifying risk.
|
|
312
|
+
|
|
313
|
+
Attributes:
|
|
314
|
+
bucket_number: Bucket identifier (1-2, or "Residual").
|
|
315
|
+
credit_quality: "IG" or "HY/NR".
|
|
316
|
+
"""
|
|
317
|
+
bucket_number: int
|
|
318
|
+
credit_quality: str
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# Credit Non-Qualifying bucket definitions
|
|
322
|
+
CREDIT_NON_QUALIFYING_BUCKETS: Dict[int, CreditNonQualifyingBucket] = {
|
|
323
|
+
1: CreditNonQualifyingBucket(1, "IG"),
|
|
324
|
+
2: CreditNonQualifyingBucket(2, "HY/NR"),
|
|
325
|
+
}
|
|
326
|
+
CREDIT_NON_QUALIFYING_RESIDUAL_BUCKET = CreditNonQualifyingBucket(-1, "Residual")
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@dataclass(frozen=True)
|
|
330
|
+
class EquityBucket:
|
|
331
|
+
"""Equity bucket definition.
|
|
332
|
+
|
|
333
|
+
12 buckets plus residual for Equity risk.
|
|
334
|
+
Buckets are defined by market cap size, region, and sector.
|
|
335
|
+
|
|
336
|
+
Attributes:
|
|
337
|
+
bucket_number: Bucket identifier (1-12, or "Residual").
|
|
338
|
+
size: "Large", "Small", or "All".
|
|
339
|
+
region: "Emerging", "Developed", or "All".
|
|
340
|
+
sector: Sector description.
|
|
341
|
+
"""
|
|
342
|
+
bucket_number: int
|
|
343
|
+
size: str
|
|
344
|
+
region: str
|
|
345
|
+
sector: str
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
# Equity bucket definitions (SIMM v2.6)
|
|
349
|
+
EQUITY_BUCKETS: Dict[int, EquityBucket] = {
|
|
350
|
+
1: EquityBucket(1, "Large", "Emerging", "Consumer goods and services, transportation, admin, agriculture"),
|
|
351
|
+
2: EquityBucket(2, "Large", "Emerging", "Telecommunications, industrials, utilities"),
|
|
352
|
+
3: EquityBucket(3, "Large", "Emerging", "Basic materials, energy, agriculture"),
|
|
353
|
+
4: EquityBucket(4, "Large", "Emerging", "Financials, tech, health care, real estate"),
|
|
354
|
+
5: EquityBucket(5, "Large", "Developed", "Consumer goods and services, transportation, admin"),
|
|
355
|
+
6: EquityBucket(6, "Large", "Developed", "Telecommunications, industrials"),
|
|
356
|
+
7: EquityBucket(7, "Large", "Developed", "Basic materials, energy, utilities"),
|
|
357
|
+
8: EquityBucket(8, "Large", "Developed", "Financials, tech, health care, real estate"),
|
|
358
|
+
9: EquityBucket(9, "Small", "Emerging", "All sectors"),
|
|
359
|
+
10: EquityBucket(10, "Small", "Developed", "All sectors"),
|
|
360
|
+
11: EquityBucket(11, "All", "All", "Indices, funds, ETFs"),
|
|
361
|
+
12: EquityBucket(12, "All", "All", "Volatility indices"),
|
|
362
|
+
}
|
|
363
|
+
EQUITY_RESIDUAL_BUCKET = EquityBucket(-1, "All", "All", "Residual")
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@dataclass(frozen=True)
|
|
367
|
+
class CommodityBucket:
|
|
368
|
+
"""Commodity bucket definition.
|
|
369
|
+
|
|
370
|
+
17 buckets for Commodity risk, defined by commodity type.
|
|
371
|
+
|
|
372
|
+
Attributes:
|
|
373
|
+
bucket_number: Bucket identifier (1-17).
|
|
374
|
+
commodity_type: Commodity type description.
|
|
375
|
+
"""
|
|
376
|
+
bucket_number: int
|
|
377
|
+
commodity_type: str
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# Commodity bucket definitions (SIMM v2.6)
|
|
381
|
+
COMMODITY_BUCKETS: Dict[int, CommodityBucket] = {
|
|
382
|
+
1: CommodityBucket(1, "Coal"),
|
|
383
|
+
2: CommodityBucket(2, "Crude oil"),
|
|
384
|
+
3: CommodityBucket(3, "Light ends"),
|
|
385
|
+
4: CommodityBucket(4, "Middle distillates"),
|
|
386
|
+
5: CommodityBucket(5, "Heavy distillates"),
|
|
387
|
+
6: CommodityBucket(6, "North American natural gas"),
|
|
388
|
+
7: CommodityBucket(7, "European natural gas"),
|
|
389
|
+
8: CommodityBucket(8, "North American power"),
|
|
390
|
+
9: CommodityBucket(9, "European power"),
|
|
391
|
+
10: CommodityBucket(10, "Freight"),
|
|
392
|
+
11: CommodityBucket(11, "Base metals"),
|
|
393
|
+
12: CommodityBucket(12, "Precious metals"),
|
|
394
|
+
13: CommodityBucket(13, "Grains"),
|
|
395
|
+
14: CommodityBucket(14, "Softs"),
|
|
396
|
+
15: CommodityBucket(15, "Livestock"),
|
|
397
|
+
16: CommodityBucket(16, "Other"),
|
|
398
|
+
17: CommodityBucket(17, "Indices"),
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
@dataclass(frozen=True)
|
|
403
|
+
class FXBucket:
|
|
404
|
+
"""FX bucket definition.
|
|
405
|
+
|
|
406
|
+
FX has a single bucket containing all currency pairs.
|
|
407
|
+
Sensitivities are distinguished by the currency pair qualifier.
|
|
408
|
+
|
|
409
|
+
Attributes:
|
|
410
|
+
bucket_number: Always 1 for FX.
|
|
411
|
+
"""
|
|
412
|
+
bucket_number: int = 1
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
# Single FX bucket
|
|
416
|
+
FX_BUCKET = FXBucket()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Stress Test Module for Portfolio Scenario Analysis.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive stress testing capabilities for portfolios,
|
|
5
|
+
allowing users to analyze how different market conditions affect portfolio P&L
|
|
6
|
+
and risk exposures.
|
|
7
|
+
|
|
8
|
+
Key Features:
|
|
9
|
+
- Flexible parameter stressing at portfolio, underlying, or position level
|
|
10
|
+
- Predefined common scenarios and custom scenario definition
|
|
11
|
+
- YAML/JSON scenario storage for reusability
|
|
12
|
+
- Multi-parameter simultaneous stress capability
|
|
13
|
+
- Comprehensive reporting with HTML, CSV, Parquet, and visualizations
|
|
14
|
+
- API design ready for future dynamic scenario analysis
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
>>> from stresstest import StressTestEngine, StressTestConfig, ScenarioBuilder
|
|
18
|
+
>>> from stresstest.scenario import ScenarioLibrary
|
|
19
|
+
>>>
|
|
20
|
+
>>> # Create stress test configuration
|
|
21
|
+
>>> config = StressTestConfig(
|
|
22
|
+
... calculate_greeks=True,
|
|
23
|
+
... export_format=['parquet', 'csv']
|
|
24
|
+
... )
|
|
25
|
+
>>>
|
|
26
|
+
>>> # Build or load scenarios
|
|
27
|
+
>>> scenarios = [
|
|
28
|
+
... ScenarioLibrary.market_crash(),
|
|
29
|
+
... ScenarioLibrary.vol_spike(),
|
|
30
|
+
... ScenarioBuilder().name("Custom").spot_stress(-0.15).build()
|
|
31
|
+
... ]
|
|
32
|
+
>>>
|
|
33
|
+
>>> # Run stress test
|
|
34
|
+
>>> engine = StressTestEngine(config)
|
|
35
|
+
>>> results = engine.run_static_scenarios(portfolio, scenarios)
|
|
36
|
+
>>>
|
|
37
|
+
>>> # Generate reports
|
|
38
|
+
>>> results.to_parquet("stress_results.parquet")
|
|
39
|
+
>>> results.generate_report("stress_report.html")
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from quantark.stresstest.config import StressTestConfig
|
|
43
|
+
from quantark.stresstest.engine import StressTestEngine
|
|
44
|
+
from quantark.stresstest.fi import FIStressConfig, FIStressEngine
|
|
45
|
+
from quantark.stresstest.scenario.scenario import Scenario, Stress
|
|
46
|
+
from quantark.stresstest.scenario.scenario_builder import ScenarioBuilder
|
|
47
|
+
from quantark.stresstest.stress.stress_types import (
|
|
48
|
+
StressType,
|
|
49
|
+
StressLevel,
|
|
50
|
+
BasisDividendRelationshipMode,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__version__ = "0.1.0"
|
|
54
|
+
|
|
55
|
+
__all__ = [
|
|
56
|
+
"StressTestConfig",
|
|
57
|
+
"StressTestEngine",
|
|
58
|
+
"FIStressConfig",
|
|
59
|
+
"FIStressEngine",
|
|
60
|
+
"Scenario",
|
|
61
|
+
"Stress",
|
|
62
|
+
"ScenarioBuilder",
|
|
63
|
+
"StressType",
|
|
64
|
+
"StressLevel",
|
|
65
|
+
"BasisDividendRelationshipMode",
|
|
66
|
+
]
|
|
67
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core protocols and data contracts shared across stress testing engines.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any, Dict, List, Optional, Protocol, Sequence, runtime_checkable
|
|
9
|
+
|
|
10
|
+
from quantark.portfolio.base import BasePortfolio
|
|
11
|
+
from quantark.stresstest.scenario.scenario import Scenario
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class ScenarioEnvelope:
|
|
16
|
+
"""
|
|
17
|
+
Standard container for scenario-level stress results.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
scenario: Scenario
|
|
21
|
+
portfolio_value: float
|
|
22
|
+
portfolio_pnl: float
|
|
23
|
+
portfolio_pnl_pct: float
|
|
24
|
+
greeks: Optional[Dict[str, float]] = None
|
|
25
|
+
position_results: List[Dict[str, Any]] = field(default_factory=list)
|
|
26
|
+
underlying_results: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
27
|
+
extra_metrics: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
28
|
+
execution_time: float = 0.0
|
|
29
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class StressResultEnvelope:
|
|
34
|
+
"""
|
|
35
|
+
Top-level container returned by every stress engine implementation.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
baseline_value: float
|
|
39
|
+
baseline_greeks: Optional[Dict[str, float]]
|
|
40
|
+
scenario_results: Sequence[ScenarioEnvelope]
|
|
41
|
+
execution_timestamp: datetime = field(default_factory=datetime.now)
|
|
42
|
+
total_execution_time: float = 0.0
|
|
43
|
+
config_summary: Dict[str, Any] = field(default_factory=dict)
|
|
44
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
45
|
+
extra_metrics: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@runtime_checkable
|
|
49
|
+
class StressMetricsAdapter(Protocol):
|
|
50
|
+
"""
|
|
51
|
+
Adapter interface for calculating asset-specific stress metrics.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def supports(self, portfolio: BasePortfolio) -> bool:
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
def compute_metrics(
|
|
58
|
+
self,
|
|
59
|
+
original_portfolio: BasePortfolio,
|
|
60
|
+
stressed_portfolio: BasePortfolio,
|
|
61
|
+
scenario: Scenario,
|
|
62
|
+
baseline_value: float,
|
|
63
|
+
stressed_value: float,
|
|
64
|
+
) -> Dict[str, Dict[str, Any]]:
|
|
65
|
+
"""
|
|
66
|
+
Return asset-specific metrics keyed by namespace (e.g. 'equity', 'fi').
|
|
67
|
+
"""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@runtime_checkable
|
|
72
|
+
class ScenarioRunner(Protocol):
|
|
73
|
+
"""
|
|
74
|
+
Contract for scenario evaluation helpers used by stress engines.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def evaluate_scenario(
|
|
78
|
+
self,
|
|
79
|
+
portfolio: BasePortfolio,
|
|
80
|
+
scenario: Scenario,
|
|
81
|
+
baseline_value: float,
|
|
82
|
+
) -> ScenarioEnvelope:
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@runtime_checkable
|
|
87
|
+
class BaseStressEngine(Protocol):
|
|
88
|
+
"""
|
|
89
|
+
Base protocol implemented by all stress testing engines.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
config: Any
|
|
93
|
+
|
|
94
|
+
def supports_portfolio(self, portfolio: BasePortfolio) -> bool:
|
|
95
|
+
"""
|
|
96
|
+
Whether this engine can evaluate the supplied portfolio type.
|
|
97
|
+
"""
|
|
98
|
+
...
|
|
99
|
+
|
|
100
|
+
def run_static_scenarios(
|
|
101
|
+
self,
|
|
102
|
+
portfolio: BasePortfolio,
|
|
103
|
+
scenarios: Sequence[Scenario],
|
|
104
|
+
baseline_label: str = "Current Market",
|
|
105
|
+
) -> StressResultEnvelope:
|
|
106
|
+
...
|
|
107
|
+
|
|
108
|
+
def evaluate_scenario(
|
|
109
|
+
self,
|
|
110
|
+
portfolio: BasePortfolio,
|
|
111
|
+
scenario: Scenario,
|
|
112
|
+
baseline_value: float,
|
|
113
|
+
) -> ScenarioEnvelope:
|
|
114
|
+
...
|
|
115
|
+
|
|
116
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Equity-specific stress testing implementation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from quantark.stresstest.equity.config import EquityStressConfig, StressTestConfig
|
|
6
|
+
from quantark.stresstest.equity.engine import EquityStressEngine, StressTestEngine
|
|
7
|
+
from quantark.stresstest.equity.results import ScenarioResult, StressTestResults
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"EquityStressConfig",
|
|
11
|
+
"StressTestConfig",
|
|
12
|
+
"EquityStressEngine",
|
|
13
|
+
"StressTestEngine",
|
|
14
|
+
"ScenarioResult",
|
|
15
|
+
"StressTestResults",
|
|
16
|
+
]
|
|
17
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Equity stress configuration implementation."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
from quantark.util.exceptions import ValidationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class EquityStressConfig:
|
|
11
|
+
"""Configuration for equity stress test execution."""
|
|
12
|
+
|
|
13
|
+
calculate_greeks: bool = True
|
|
14
|
+
greeks_method: str = "analytical"
|
|
15
|
+
export_formats: List[str] = field(default_factory=lambda: ["parquet"])
|
|
16
|
+
output_dir: str = "./stress_results"
|
|
17
|
+
save_detailed_results: bool = True
|
|
18
|
+
|
|
19
|
+
# Future features for dynamic scenario analysis
|
|
20
|
+
parallel_execution: bool = False
|
|
21
|
+
max_workers: int = 4
|
|
22
|
+
progress_callback: Optional[Any] = None
|
|
23
|
+
|
|
24
|
+
# Additional settings
|
|
25
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
26
|
+
|
|
27
|
+
def __post_init__(self) -> None:
|
|
28
|
+
self._validate()
|
|
29
|
+
|
|
30
|
+
def _validate(self) -> None:
|
|
31
|
+
if self.greeks_method not in ["analytical", "numerical"]:
|
|
32
|
+
raise ValidationError(
|
|
33
|
+
f"Invalid greeks_method '{self.greeks_method}'. Must be 'analytical' or 'numerical'"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
valid_formats = ["parquet", "csv", "json", "html"]
|
|
37
|
+
for fmt in self.export_formats:
|
|
38
|
+
if fmt not in valid_formats:
|
|
39
|
+
raise ValidationError(
|
|
40
|
+
f"Invalid export format '{fmt}'. Valid formats: {valid_formats}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if self.max_workers < 1:
|
|
44
|
+
raise ValidationError("max_workers must be at least 1")
|
|
45
|
+
|
|
46
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
47
|
+
return {
|
|
48
|
+
"calculate_greeks": self.calculate_greeks,
|
|
49
|
+
"greeks_method": self.greeks_method,
|
|
50
|
+
"export_formats": self.export_formats,
|
|
51
|
+
"output_dir": self.output_dir,
|
|
52
|
+
"save_detailed_results": self.save_detailed_results,
|
|
53
|
+
"parallel_execution": self.parallel_execution,
|
|
54
|
+
"metadata": self.metadata,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def __repr__(self) -> str:
|
|
58
|
+
return (
|
|
59
|
+
"EquityStressConfig("
|
|
60
|
+
f"greeks={self.calculate_greeks}, "
|
|
61
|
+
f"formats={self.export_formats}, "
|
|
62
|
+
f"output_dir='{self.output_dir}'"
|
|
63
|
+
")"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Backward-compatible alias used throughout the existing equity workflow.
|
|
68
|
+
StressTestConfig = EquityStressConfig
|
|
69
|
+
|