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,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration classes for Range Accrual options.
|
|
3
|
+
|
|
4
|
+
Range Accrual options pay based on the proportion of observations where the
|
|
5
|
+
underlying stays within a defined price range, with support for weighted
|
|
6
|
+
observations and historical tracking.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import List, Optional, Union, TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from quantark.util.enum import CouponPayType
|
|
14
|
+
from quantark.util.calendar.day_counter import DayCountConvention
|
|
15
|
+
from quantark.util.exceptions import ValidationError
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from quantark.priceenv import PricingEnvironment
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from quantark.util.calendar import calculate_year_fraction
|
|
22
|
+
except ImportError:
|
|
23
|
+
calculate_year_fraction = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class RangeAccrualObservationRecord:
|
|
28
|
+
"""
|
|
29
|
+
Single observation entry for Range Accrual option.
|
|
30
|
+
|
|
31
|
+
For past observations: set observed_in_range to True/False
|
|
32
|
+
For future observations: leave observed_in_range as None
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
observation_time: Time as year fraction (optional if observation_date provided)
|
|
36
|
+
observation_date: Calendar date (optional if observation_time provided)
|
|
37
|
+
upper_barrier: Per-observation upper barrier (optional, uses default if None)
|
|
38
|
+
lower_barrier: Per-observation lower barrier (optional, uses default if None)
|
|
39
|
+
weight: Observation weight (default 1.0, use 3.0 for Friday in calendar day convention)
|
|
40
|
+
observed_in_range: Historical observation result (None for future observations)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
observation_time: Optional[float] = None
|
|
44
|
+
observation_date: Optional[datetime] = None
|
|
45
|
+
upper_barrier: Optional[float] = None
|
|
46
|
+
lower_barrier: Optional[float] = None
|
|
47
|
+
weight: float = 1.0
|
|
48
|
+
observed_in_range: Optional[bool] = None
|
|
49
|
+
|
|
50
|
+
def resolve_time(self, pricing_env: "PricingEnvironment") -> float:
|
|
51
|
+
"""
|
|
52
|
+
Resolve observation time relative to valuation date.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
pricing_env: Pricing environment with valuation date
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Year fraction from valuation date to observation date
|
|
59
|
+
(negative if observation is in the past)
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ValidationError: If observation time/date cannot be resolved
|
|
63
|
+
"""
|
|
64
|
+
if self.observation_time is not None:
|
|
65
|
+
return self.observation_time
|
|
66
|
+
if self.observation_date is not None:
|
|
67
|
+
if pricing_env is None or calculate_year_fraction is None:
|
|
68
|
+
raise ValidationError(
|
|
69
|
+
"PricingEnvironment is required to resolve observation_date."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Handle past, current and future dates correctly
|
|
73
|
+
if self.observation_date == pricing_env.valuation_date:
|
|
74
|
+
return 0.0
|
|
75
|
+
elif self.observation_date > pricing_env.valuation_date:
|
|
76
|
+
# Future date: positive year fraction
|
|
77
|
+
return calculate_year_fraction(
|
|
78
|
+
pricing_env.valuation_date,
|
|
79
|
+
self.observation_date,
|
|
80
|
+
pricing_env.day_count_convention,
|
|
81
|
+
pricing_env.bus_days_in_year,
|
|
82
|
+
calendar=getattr(pricing_env, "calendar", None),
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
# Past date: negative year fraction
|
|
86
|
+
return -calculate_year_fraction(
|
|
87
|
+
self.observation_date,
|
|
88
|
+
pricing_env.valuation_date,
|
|
89
|
+
pricing_env.day_count_convention,
|
|
90
|
+
pricing_env.bus_days_in_year,
|
|
91
|
+
calendar=getattr(pricing_env, "calendar", None),
|
|
92
|
+
)
|
|
93
|
+
raise ValidationError(
|
|
94
|
+
"RangeAccrualObservationRecord requires observation_time or observation_date."
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def is_observed(self) -> bool:
|
|
98
|
+
"""Check if this observation has historical data."""
|
|
99
|
+
return self.observed_in_range is not None
|
|
100
|
+
|
|
101
|
+
def validate(self) -> None:
|
|
102
|
+
"""Validate the observation record."""
|
|
103
|
+
if self.observation_time is None and self.observation_date is None:
|
|
104
|
+
raise ValidationError(
|
|
105
|
+
"RangeAccrualObservationRecord must provide observation_time or observation_date."
|
|
106
|
+
)
|
|
107
|
+
if self.weight <= 0:
|
|
108
|
+
raise ValidationError(f"weight must be positive, got {self.weight}")
|
|
109
|
+
|
|
110
|
+
# Validate barriers if provided
|
|
111
|
+
if self.upper_barrier is not None and self.upper_barrier <= 0:
|
|
112
|
+
raise ValidationError(
|
|
113
|
+
f"upper_barrier must be positive, got {self.upper_barrier}"
|
|
114
|
+
)
|
|
115
|
+
if self.lower_barrier is not None and self.lower_barrier <= 0:
|
|
116
|
+
raise ValidationError(
|
|
117
|
+
f"lower_barrier must be positive, got {self.lower_barrier}"
|
|
118
|
+
)
|
|
119
|
+
if (
|
|
120
|
+
self.upper_barrier is not None
|
|
121
|
+
and self.lower_barrier is not None
|
|
122
|
+
and self.lower_barrier >= self.upper_barrier
|
|
123
|
+
):
|
|
124
|
+
raise ValidationError(
|
|
125
|
+
f"lower_barrier ({self.lower_barrier}) must be less than "
|
|
126
|
+
f"upper_barrier ({self.upper_barrier})"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass(frozen=True)
|
|
131
|
+
class RangeAccrualConfig:
|
|
132
|
+
"""
|
|
133
|
+
Configuration for Range Accrual option settings.
|
|
134
|
+
|
|
135
|
+
Attributes:
|
|
136
|
+
upper_barrier: Upper barrier level(s). Can be scalar or time-varying (list).
|
|
137
|
+
lower_barrier: Lower barrier level(s). Can be scalar or time-varying (list).
|
|
138
|
+
accrual_rate: Per-period accrual rate (e.g., 0.01 for 1% per period).
|
|
139
|
+
is_rate_annualized: Whether accrual_rate is annualized (affects year_fraction calc).
|
|
140
|
+
day_count_convention: Day count convention for year fraction calculation.
|
|
141
|
+
accrual_pay_type: INSTANT (pay per observation) or EXPIRY (pay all at maturity).
|
|
142
|
+
is_reverse: If True, pay when OUTSIDE range instead of inside.
|
|
143
|
+
use_calendar_day_weights: If True, auto-assign Friday=3 weights when generating schedule.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
upper_barrier: Union[float, List[float]]
|
|
147
|
+
lower_barrier: Union[float, List[float]]
|
|
148
|
+
accrual_rate: float = 0.01
|
|
149
|
+
is_rate_annualized: bool = False
|
|
150
|
+
day_count_convention: DayCountConvention = DayCountConvention.ACT_365
|
|
151
|
+
accrual_pay_type: CouponPayType = CouponPayType.EXPIRY
|
|
152
|
+
is_reverse: bool = False
|
|
153
|
+
use_calendar_day_weights: bool = False
|
|
154
|
+
|
|
155
|
+
def __post_init__(self):
|
|
156
|
+
"""Validate configuration after initialization."""
|
|
157
|
+
# Validate barriers are positive
|
|
158
|
+
self._validate_barrier_positive(self.upper_barrier, "upper_barrier")
|
|
159
|
+
self._validate_barrier_positive(self.lower_barrier, "lower_barrier")
|
|
160
|
+
|
|
161
|
+
# Validate upper > lower at each observation
|
|
162
|
+
self._validate_barrier_ordering()
|
|
163
|
+
|
|
164
|
+
# Validate accrual_rate is non-negative
|
|
165
|
+
if not isinstance(self.accrual_rate, (int, float)):
|
|
166
|
+
raise ValidationError(
|
|
167
|
+
f"accrual_rate must be a number, got {type(self.accrual_rate)}"
|
|
168
|
+
)
|
|
169
|
+
if self.accrual_rate < 0:
|
|
170
|
+
raise ValidationError(
|
|
171
|
+
f"accrual_rate must be non-negative, got {self.accrual_rate}"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Validate enums
|
|
175
|
+
if not isinstance(self.accrual_pay_type, CouponPayType):
|
|
176
|
+
raise ValidationError(
|
|
177
|
+
f"accrual_pay_type must be CouponPayType, got {type(self.accrual_pay_type)}"
|
|
178
|
+
)
|
|
179
|
+
if not isinstance(self.day_count_convention, DayCountConvention):
|
|
180
|
+
raise ValidationError(
|
|
181
|
+
f"day_count_convention must be DayCountConvention, "
|
|
182
|
+
f"got {type(self.day_count_convention)}"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Validate booleans
|
|
186
|
+
if not isinstance(self.is_rate_annualized, bool):
|
|
187
|
+
raise ValidationError(
|
|
188
|
+
f"is_rate_annualized must be boolean, got {type(self.is_rate_annualized)}"
|
|
189
|
+
)
|
|
190
|
+
if not isinstance(self.is_reverse, bool):
|
|
191
|
+
raise ValidationError(
|
|
192
|
+
f"is_reverse must be boolean, got {type(self.is_reverse)}"
|
|
193
|
+
)
|
|
194
|
+
if not isinstance(self.use_calendar_day_weights, bool):
|
|
195
|
+
raise ValidationError(
|
|
196
|
+
f"use_calendar_day_weights must be boolean, "
|
|
197
|
+
f"got {type(self.use_calendar_day_weights)}"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def _validate_barrier_positive(
|
|
202
|
+
barrier: Union[float, List[float]], name: str
|
|
203
|
+
) -> None:
|
|
204
|
+
"""Validate that barrier level(s) are positive."""
|
|
205
|
+
if isinstance(barrier, list):
|
|
206
|
+
if not barrier:
|
|
207
|
+
raise ValidationError(f"{name} list cannot be empty")
|
|
208
|
+
for i, b in enumerate(barrier):
|
|
209
|
+
if not isinstance(b, (int, float)) or b <= 0:
|
|
210
|
+
raise ValidationError(
|
|
211
|
+
f"{name}[{i}] must be positive number, got {b}"
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
if not isinstance(barrier, (int, float)) or barrier <= 0:
|
|
215
|
+
raise ValidationError(f"{name} must be positive number, got {barrier}")
|
|
216
|
+
|
|
217
|
+
def _validate_barrier_ordering(self) -> None:
|
|
218
|
+
"""Validate that upper_barrier > lower_barrier at each observation."""
|
|
219
|
+
upper_is_list = isinstance(self.upper_barrier, list)
|
|
220
|
+
lower_is_list = isinstance(self.lower_barrier, list)
|
|
221
|
+
|
|
222
|
+
if upper_is_list and lower_is_list:
|
|
223
|
+
# Both are lists - must have same length
|
|
224
|
+
# Cast to list since we checked isinstance above
|
|
225
|
+
upper_list = list(self.upper_barrier) # type: ignore[arg-type]
|
|
226
|
+
lower_list = list(self.lower_barrier) # type: ignore[arg-type]
|
|
227
|
+
if len(upper_list) != len(lower_list):
|
|
228
|
+
raise ValidationError(
|
|
229
|
+
f"upper_barrier and lower_barrier lists must have same length, "
|
|
230
|
+
f"got {len(upper_list)} and {len(lower_list)}"
|
|
231
|
+
)
|
|
232
|
+
for i, (u, l) in enumerate(zip(upper_list, lower_list)):
|
|
233
|
+
if l >= u:
|
|
234
|
+
raise ValidationError(
|
|
235
|
+
f"lower_barrier[{i}] ({l}) must be less than "
|
|
236
|
+
f"upper_barrier[{i}] ({u})"
|
|
237
|
+
)
|
|
238
|
+
elif upper_is_list:
|
|
239
|
+
# Upper is list, lower is scalar
|
|
240
|
+
upper_list = list(self.upper_barrier) # type: ignore[arg-type]
|
|
241
|
+
lower_scalar: float = float(self.lower_barrier) # type: ignore[arg-type]
|
|
242
|
+
for i, u in enumerate(upper_list):
|
|
243
|
+
if lower_scalar >= u:
|
|
244
|
+
raise ValidationError(
|
|
245
|
+
f"lower_barrier ({lower_scalar}) must be less than "
|
|
246
|
+
f"upper_barrier[{i}] ({u})"
|
|
247
|
+
)
|
|
248
|
+
elif lower_is_list:
|
|
249
|
+
# Lower is list, upper is scalar
|
|
250
|
+
lower_list = list(self.lower_barrier) # type: ignore[arg-type]
|
|
251
|
+
upper_scalar: float = float(self.upper_barrier) # type: ignore[arg-type]
|
|
252
|
+
for i, l in enumerate(lower_list):
|
|
253
|
+
if l >= upper_scalar:
|
|
254
|
+
raise ValidationError(
|
|
255
|
+
f"lower_barrier[{i}] ({l}) must be less than "
|
|
256
|
+
f"upper_barrier ({upper_scalar})"
|
|
257
|
+
)
|
|
258
|
+
else:
|
|
259
|
+
# Both are scalars
|
|
260
|
+
upper_scalar = self.upper_barrier # type: ignore[assignment]
|
|
261
|
+
lower_scalar = self.lower_barrier # type: ignore[assignment]
|
|
262
|
+
if lower_scalar >= upper_scalar:
|
|
263
|
+
raise ValidationError(
|
|
264
|
+
f"lower_barrier ({lower_scalar}) must be less than "
|
|
265
|
+
f"upper_barrier ({upper_scalar})"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def get_upper_barrier(self, obs_idx: int) -> float:
|
|
269
|
+
"""Get upper barrier for a specific observation index."""
|
|
270
|
+
if isinstance(self.upper_barrier, list):
|
|
271
|
+
if obs_idx < 0 or obs_idx >= len(self.upper_barrier):
|
|
272
|
+
raise ValidationError(
|
|
273
|
+
f"obs_idx {obs_idx} out of range for upper_barrier "
|
|
274
|
+
f"with length {len(self.upper_barrier)}"
|
|
275
|
+
)
|
|
276
|
+
return self.upper_barrier[obs_idx]
|
|
277
|
+
return self.upper_barrier
|
|
278
|
+
|
|
279
|
+
def get_lower_barrier(self, obs_idx: int) -> float:
|
|
280
|
+
"""Get lower barrier for a specific observation index."""
|
|
281
|
+
if isinstance(self.lower_barrier, list):
|
|
282
|
+
if obs_idx < 0 or obs_idx >= len(self.lower_barrier):
|
|
283
|
+
raise ValidationError(
|
|
284
|
+
f"obs_idx {obs_idx} out of range for lower_barrier "
|
|
285
|
+
f"with length {len(self.lower_barrier)}"
|
|
286
|
+
)
|
|
287
|
+
return self.lower_barrier[obs_idx]
|
|
288
|
+
return self.lower_barrier
|