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,576 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Factory functions for creating common Phoenix option structures.
|
|
3
|
+
|
|
4
|
+
This module provides helper functions that simplify the creation of Phoenix options
|
|
5
|
+
by providing sensible defaults for common market structures. Each helper accepts
|
|
6
|
+
minimal required parameters and allows full customization via **kwargs.
|
|
7
|
+
|
|
8
|
+
Available helpers:
|
|
9
|
+
- create_standard_phoenix(): Basic phoenix with flat barriers, non-memory by default
|
|
10
|
+
- create_stepdown_phoenix(): KO and coupon barriers decrease each observation period
|
|
11
|
+
- create_reverse_phoenix(): Reverse direction (down KO, up KI)
|
|
12
|
+
- create_memory_phoenix(): Explicit memory coupon enabled
|
|
13
|
+
- create_non_memory_phoenix(): Memory coupon disabled (explicit)
|
|
14
|
+
|
|
15
|
+
Utilities (reused from snowball_helpers):
|
|
16
|
+
- generate_ko_observation_dates(): Create evenly spaced observation dates
|
|
17
|
+
- generate_stepdown_barriers(): Generate decreasing barrier levels
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
>>> from asset.equity.product.option import create_standard_phoenix
|
|
21
|
+
>>> phoenix = create_standard_phoenix(
|
|
22
|
+
... initial_price=100.0,
|
|
23
|
+
... strike=100.0,
|
|
24
|
+
... maturity=1.0,
|
|
25
|
+
... contract_multiplier=1.0,
|
|
26
|
+
... )
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from dataclasses import fields
|
|
30
|
+
from typing import List, Optional
|
|
31
|
+
|
|
32
|
+
from quantark.util.calendar.day_counter import DayCountConvention
|
|
33
|
+
from quantark.util.enum import CouponPayType, ObservationType
|
|
34
|
+
from quantark.util.exceptions import ValidationError
|
|
35
|
+
|
|
36
|
+
from .phoenix_config import CouponBarrierConfig
|
|
37
|
+
from .phoenix_option import PhoenixOption
|
|
38
|
+
from .snowball_config import AccrualConfig, AirbagConfig, BarrierConfig, PayoffConfig
|
|
39
|
+
from .snowball_helpers import (
|
|
40
|
+
generate_ko_observation_dates,
|
|
41
|
+
generate_stepdown_barriers,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# =============================================================================
|
|
46
|
+
# Internal Helper Functions
|
|
47
|
+
# =============================================================================
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _validate_core_params(
|
|
51
|
+
initial_price: float,
|
|
52
|
+
strike: float,
|
|
53
|
+
maturity: float,
|
|
54
|
+
contract_multiplier: float,
|
|
55
|
+
func_name: str,
|
|
56
|
+
num_observations: Optional[int] = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""Validate core parameters common to all helpers."""
|
|
59
|
+
if initial_price <= 0:
|
|
60
|
+
raise ValidationError(
|
|
61
|
+
f"{func_name}: initial_price must be positive, got {initial_price}"
|
|
62
|
+
)
|
|
63
|
+
if strike <= 0:
|
|
64
|
+
raise ValidationError(f"{func_name}: strike must be positive, got {strike}")
|
|
65
|
+
if maturity <= 0:
|
|
66
|
+
raise ValidationError(f"{func_name}: maturity must be positive, got {maturity}")
|
|
67
|
+
if contract_multiplier <= 0:
|
|
68
|
+
raise ValidationError(
|
|
69
|
+
f"{func_name}: contract_multiplier must be positive, got {contract_multiplier}"
|
|
70
|
+
)
|
|
71
|
+
if num_observations is not None:
|
|
72
|
+
if not isinstance(num_observations, int):
|
|
73
|
+
raise ValidationError(
|
|
74
|
+
f"{func_name}: num_observations must be an integer, got {type(num_observations)}"
|
|
75
|
+
)
|
|
76
|
+
if num_observations < 1:
|
|
77
|
+
raise ValidationError(
|
|
78
|
+
f"{func_name}: num_observations must be at least 1, got {num_observations}"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _extract_config_kwargs(kwargs: dict) -> tuple:
|
|
83
|
+
"""
|
|
84
|
+
Extract kwargs for each config class using introspection.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
(barrier_kwargs, coupon_kwargs, payoff_kwargs, accrual_kwargs, airbag_kwargs)
|
|
88
|
+
"""
|
|
89
|
+
barrier_fields = {f.name for f in fields(BarrierConfig)}
|
|
90
|
+
coupon_fields = {f.name for f in fields(CouponBarrierConfig)}
|
|
91
|
+
payoff_fields = {f.name for f in fields(PayoffConfig)}
|
|
92
|
+
accrual_fields = {f.name for f in fields(AccrualConfig)}
|
|
93
|
+
airbag_fields = {f.name for f in fields(AirbagConfig)}
|
|
94
|
+
|
|
95
|
+
barrier_kwargs = {}
|
|
96
|
+
coupon_kwargs = {}
|
|
97
|
+
payoff_kwargs = {}
|
|
98
|
+
accrual_kwargs = {}
|
|
99
|
+
airbag_kwargs = {}
|
|
100
|
+
unknown_kwargs = []
|
|
101
|
+
|
|
102
|
+
for key, value in kwargs.items():
|
|
103
|
+
if key in barrier_fields:
|
|
104
|
+
barrier_kwargs[key] = value
|
|
105
|
+
elif key in coupon_fields:
|
|
106
|
+
coupon_kwargs[key] = value
|
|
107
|
+
elif key in payoff_fields:
|
|
108
|
+
payoff_kwargs[key] = value
|
|
109
|
+
elif key in accrual_fields:
|
|
110
|
+
accrual_kwargs[key] = value
|
|
111
|
+
elif key in airbag_fields:
|
|
112
|
+
airbag_kwargs[key] = value
|
|
113
|
+
else:
|
|
114
|
+
unknown_kwargs.append(key)
|
|
115
|
+
|
|
116
|
+
if unknown_kwargs:
|
|
117
|
+
raise ValidationError(
|
|
118
|
+
f"Unknown parameters provided: {', '.join(unknown_kwargs)}. "
|
|
119
|
+
"Please check spelling or valid configuration fields."
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return barrier_kwargs, coupon_kwargs, payoff_kwargs, accrual_kwargs, airbag_kwargs
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# =============================================================================
|
|
126
|
+
# Factory Functions
|
|
127
|
+
# =============================================================================
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def create_standard_phoenix(
|
|
131
|
+
initial_price: float,
|
|
132
|
+
strike: float,
|
|
133
|
+
maturity: float,
|
|
134
|
+
contract_multiplier: float = 1.0,
|
|
135
|
+
ko_barrier: Optional[float] = None,
|
|
136
|
+
ko_rate: float = 0.0,
|
|
137
|
+
ki_barrier: Optional[float] = None,
|
|
138
|
+
coupon_barrier: Optional[float] = None,
|
|
139
|
+
coupon_rate: float = 0.01,
|
|
140
|
+
num_observations: int = 12,
|
|
141
|
+
memory_coupon: bool = True,
|
|
142
|
+
day_count_convention: DayCountConvention = DayCountConvention.ACT_365,
|
|
143
|
+
coupon_pay_type: CouponPayType = CouponPayType.INSTANT,
|
|
144
|
+
is_reverse: bool = False,
|
|
145
|
+
**kwargs,
|
|
146
|
+
) -> PhoenixOption:
|
|
147
|
+
"""
|
|
148
|
+
Create a standard phoenix with flat barriers and optional memory coupon.
|
|
149
|
+
|
|
150
|
+
This is the most common phoenix structure with:
|
|
151
|
+
- Discrete KO observations (monthly by default)
|
|
152
|
+
- Continuous KI monitoring
|
|
153
|
+
- Flat (constant) KO and coupon barriers
|
|
154
|
+
- Memory coupon disabled by default
|
|
155
|
+
- Day count convention for coupon calculation
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
initial_price: Reference price for payoff calculations
|
|
159
|
+
strike: Strike price for embedded option
|
|
160
|
+
maturity: Time to maturity in years
|
|
161
|
+
contract_multiplier: Underlying units represented by one contract
|
|
162
|
+
ko_barrier: Knock-out barrier (default: 103% of initial_price)
|
|
163
|
+
ko_rate: Annualized knock-out rate (default: 0%)
|
|
164
|
+
ki_barrier: Knock-in barrier (default: 75% of initial_price)
|
|
165
|
+
coupon_barrier: Coupon barrier (default: 85% of initial_price)
|
|
166
|
+
coupon_rate: Per-period coupon rate (default: 1%)
|
|
167
|
+
num_observations: Number of observations (default: 12 for monthly)
|
|
168
|
+
memory_coupon: If True, accumulate missed coupons (default: True)
|
|
169
|
+
day_count_convention: Day count for coupon calculation (default: ACT/365)
|
|
170
|
+
coupon_pay_type: INSTANT or EXPIRY (default: INSTANT)
|
|
171
|
+
is_reverse: If True, create reverse phoenix (default: False)
|
|
172
|
+
**kwargs: Additional parameters passed to config objects
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Configured PhoenixOption instance
|
|
176
|
+
|
|
177
|
+
Example:
|
|
178
|
+
>>> phoenix = create_standard_phoenix(
|
|
179
|
+
... initial_price=100.0,
|
|
180
|
+
... strike=100.0,
|
|
181
|
+
... maturity=1.0,
|
|
182
|
+
... )
|
|
183
|
+
>>> phoenix.coupon_config.coupon_barrier
|
|
184
|
+
85.0
|
|
185
|
+
"""
|
|
186
|
+
_validate_core_params(
|
|
187
|
+
initial_price,
|
|
188
|
+
strike,
|
|
189
|
+
maturity,
|
|
190
|
+
contract_multiplier,
|
|
191
|
+
"create_standard_phoenix",
|
|
192
|
+
num_observations
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Apply defaults
|
|
196
|
+
if ko_barrier is None:
|
|
197
|
+
ko_barrier = 1.03 * initial_price
|
|
198
|
+
if ki_barrier is None:
|
|
199
|
+
ki_barrier = 0.75 * initial_price
|
|
200
|
+
if coupon_barrier is None:
|
|
201
|
+
coupon_barrier = 0.85 * initial_price
|
|
202
|
+
|
|
203
|
+
# Generate observation dates
|
|
204
|
+
ko_observation_dates = [
|
|
205
|
+
(i + 1) / num_observations * maturity for i in range(num_observations)
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
# Extract config-specific kwargs
|
|
209
|
+
(
|
|
210
|
+
barrier_kwargs,
|
|
211
|
+
coupon_kwargs,
|
|
212
|
+
payoff_kwargs,
|
|
213
|
+
accrual_kwargs,
|
|
214
|
+
airbag_kwargs,
|
|
215
|
+
) = _extract_config_kwargs(kwargs)
|
|
216
|
+
|
|
217
|
+
# Build configs
|
|
218
|
+
barrier_config = BarrierConfig(
|
|
219
|
+
ko_barrier=ko_barrier,
|
|
220
|
+
ko_rate=ko_rate,
|
|
221
|
+
ko_observation_type=barrier_kwargs.pop(
|
|
222
|
+
"ko_observation_type", ObservationType.DISCRETE
|
|
223
|
+
),
|
|
224
|
+
ko_observation_dates=barrier_kwargs.pop(
|
|
225
|
+
"ko_observation_dates", ko_observation_dates
|
|
226
|
+
),
|
|
227
|
+
ki_barrier=ki_barrier,
|
|
228
|
+
ki_observation_type=barrier_kwargs.pop(
|
|
229
|
+
"ki_observation_type", ObservationType.CONTINUOUS
|
|
230
|
+
),
|
|
231
|
+
ki_continuous=barrier_kwargs.pop("ki_continuous", True),
|
|
232
|
+
**barrier_kwargs,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
coupon_config = CouponBarrierConfig(
|
|
236
|
+
coupon_barrier=coupon_kwargs.pop("coupon_barrier", coupon_barrier),
|
|
237
|
+
coupon_rate=coupon_kwargs.pop("coupon_rate", coupon_rate),
|
|
238
|
+
coupon_pay_type=coupon_kwargs.pop("coupon_pay_type", coupon_pay_type),
|
|
239
|
+
day_count_convention=coupon_kwargs.pop(
|
|
240
|
+
"day_count_convention", day_count_convention
|
|
241
|
+
),
|
|
242
|
+
memory_coupon=coupon_kwargs.pop("memory_coupon", memory_coupon),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
payoff_config = PayoffConfig(
|
|
246
|
+
rebate_rate=payoff_kwargs.pop("rebate_rate", ko_rate),
|
|
247
|
+
include_principal=payoff_kwargs.pop("include_principal", False),
|
|
248
|
+
**payoff_kwargs,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
accrual_config = AccrualConfig(
|
|
252
|
+
coupon_pay_type=accrual_kwargs.pop("coupon_pay_type", CouponPayType.INSTANT),
|
|
253
|
+
is_annualized=accrual_kwargs.pop("is_annualized", True),
|
|
254
|
+
**accrual_kwargs,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
airbag_config = AirbagConfig(**airbag_kwargs)
|
|
258
|
+
|
|
259
|
+
return PhoenixOption(
|
|
260
|
+
initial_price=initial_price,
|
|
261
|
+
strike=strike,
|
|
262
|
+
maturity=maturity,
|
|
263
|
+
contract_multiplier=contract_multiplier,
|
|
264
|
+
barrier_config=barrier_config,
|
|
265
|
+
coupon_config=coupon_config,
|
|
266
|
+
payoff_config=payoff_config,
|
|
267
|
+
accrual_config=accrual_config,
|
|
268
|
+
airbag_config=airbag_config,
|
|
269
|
+
is_reverse=is_reverse,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def create_stepdown_phoenix(
|
|
274
|
+
initial_price: float,
|
|
275
|
+
strike: float,
|
|
276
|
+
maturity: float,
|
|
277
|
+
contract_multiplier: float = 1.0,
|
|
278
|
+
initial_ko_barrier: Optional[float] = None,
|
|
279
|
+
initial_coupon_barrier: Optional[float] = None,
|
|
280
|
+
ko_stepdown_rate: float = 0.005,
|
|
281
|
+
coupon_stepdown_rate: float = 0.005,
|
|
282
|
+
ko_rate: float = 0.0,
|
|
283
|
+
ki_barrier: Optional[float] = None,
|
|
284
|
+
coupon_rate: float = 0.01,
|
|
285
|
+
num_observations: int = 12,
|
|
286
|
+
memory_coupon: bool = True,
|
|
287
|
+
day_count_convention: DayCountConvention = DayCountConvention.ACT_365,
|
|
288
|
+
coupon_pay_type: CouponPayType = CouponPayType.INSTANT,
|
|
289
|
+
is_reverse: bool = False,
|
|
290
|
+
**kwargs,
|
|
291
|
+
) -> PhoenixOption:
|
|
292
|
+
"""
|
|
293
|
+
Create a step-down phoenix where KO and coupon barriers decrease each observation.
|
|
294
|
+
|
|
295
|
+
The barriers start high and decrease each observation period, making
|
|
296
|
+
knock-out and coupon payments progressively easier to achieve.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
initial_price: Reference price for payoff calculations
|
|
300
|
+
strike: Strike price for embedded option
|
|
301
|
+
maturity: Time to maturity in years
|
|
302
|
+
contract_multiplier: Underlying units represented by one contract
|
|
303
|
+
initial_ko_barrier: Starting KO barrier (default: 103% of initial_price)
|
|
304
|
+
initial_coupon_barrier: Starting coupon barrier (default: 85% of initial_price)
|
|
305
|
+
ko_stepdown_rate: KO barrier decrease per period as % of initial_price (default: 0.5%)
|
|
306
|
+
coupon_stepdown_rate: Coupon barrier decrease per period (default: 0.5%)
|
|
307
|
+
ko_rate: Annualized knock-out rate (default: 0%)
|
|
308
|
+
ki_barrier: Knock-in barrier (default: 75% of initial_price)
|
|
309
|
+
coupon_rate: Per-period coupon rate (default: 1%)
|
|
310
|
+
num_observations: Number of observations (default: 12)
|
|
311
|
+
memory_coupon: If True, accumulate missed coupons (default: True)
|
|
312
|
+
day_count_convention: Day count for coupon calculation (default: ACT/365)
|
|
313
|
+
coupon_pay_type: INSTANT or EXPIRY (default: INSTANT)
|
|
314
|
+
is_reverse: If True, create reverse phoenix (default: False)
|
|
315
|
+
**kwargs: Additional parameters passed to config objects
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
Configured PhoenixOption instance with step-down barriers
|
|
319
|
+
|
|
320
|
+
Example:
|
|
321
|
+
>>> phoenix = create_stepdown_phoenix(
|
|
322
|
+
... initial_price=100.0,
|
|
323
|
+
... strike=100.0,
|
|
324
|
+
... maturity=1.0,
|
|
325
|
+
... ko_stepdown_rate=0.01,
|
|
326
|
+
... )
|
|
327
|
+
>>> phoenix.barrier_config.ko_barrier # List of decreasing barriers
|
|
328
|
+
[103.0, 102.0, 101.0, ...]
|
|
329
|
+
"""
|
|
330
|
+
_validate_core_params(
|
|
331
|
+
initial_price,
|
|
332
|
+
strike,
|
|
333
|
+
maturity,
|
|
334
|
+
contract_multiplier,
|
|
335
|
+
"create_stepdown_phoenix",
|
|
336
|
+
num_observations
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
# Apply defaults
|
|
340
|
+
if initial_ko_barrier is None:
|
|
341
|
+
initial_ko_barrier = 1.03 * initial_price
|
|
342
|
+
if initial_coupon_barrier is None:
|
|
343
|
+
initial_coupon_barrier = 0.85 * initial_price
|
|
344
|
+
if ki_barrier is None:
|
|
345
|
+
ki_barrier = 0.75 * initial_price
|
|
346
|
+
|
|
347
|
+
# Generate step-down barriers
|
|
348
|
+
ko_barriers = generate_stepdown_barriers(
|
|
349
|
+
initial_barrier=initial_ko_barrier,
|
|
350
|
+
stepdown_amount=ko_stepdown_rate * initial_price,
|
|
351
|
+
num_observations=num_observations,
|
|
352
|
+
min_barrier=ki_barrier, # Don't go below KI barrier
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
coupon_barriers = generate_stepdown_barriers(
|
|
356
|
+
initial_barrier=initial_coupon_barrier,
|
|
357
|
+
stepdown_amount=coupon_stepdown_rate * initial_price,
|
|
358
|
+
num_observations=num_observations,
|
|
359
|
+
min_barrier=ki_barrier, # Don't go below KI barrier
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
# Generate observation dates
|
|
363
|
+
ko_observation_dates = [
|
|
364
|
+
(i + 1) / num_observations * maturity for i in range(num_observations)
|
|
365
|
+
]
|
|
366
|
+
|
|
367
|
+
# Extract config-specific kwargs
|
|
368
|
+
(
|
|
369
|
+
barrier_kwargs,
|
|
370
|
+
coupon_kwargs,
|
|
371
|
+
payoff_kwargs,
|
|
372
|
+
accrual_kwargs,
|
|
373
|
+
airbag_kwargs,
|
|
374
|
+
) = _extract_config_kwargs(kwargs)
|
|
375
|
+
|
|
376
|
+
# Build configs
|
|
377
|
+
barrier_config = BarrierConfig(
|
|
378
|
+
ko_barrier=ko_barriers,
|
|
379
|
+
ko_rate=ko_rate,
|
|
380
|
+
ko_observation_type=barrier_kwargs.pop(
|
|
381
|
+
"ko_observation_type", ObservationType.DISCRETE
|
|
382
|
+
),
|
|
383
|
+
ko_observation_dates=barrier_kwargs.pop(
|
|
384
|
+
"ko_observation_dates", ko_observation_dates
|
|
385
|
+
),
|
|
386
|
+
ki_barrier=ki_barrier,
|
|
387
|
+
ki_observation_type=barrier_kwargs.pop(
|
|
388
|
+
"ki_observation_type", ObservationType.CONTINUOUS
|
|
389
|
+
),
|
|
390
|
+
ki_continuous=barrier_kwargs.pop("ki_continuous", True),
|
|
391
|
+
**barrier_kwargs,
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
coupon_config = CouponBarrierConfig(
|
|
395
|
+
coupon_barrier=coupon_barriers,
|
|
396
|
+
coupon_rate=coupon_kwargs.pop("coupon_rate", coupon_rate),
|
|
397
|
+
coupon_pay_type=coupon_kwargs.pop("coupon_pay_type", coupon_pay_type),
|
|
398
|
+
day_count_convention=coupon_kwargs.pop(
|
|
399
|
+
"day_count_convention", day_count_convention
|
|
400
|
+
),
|
|
401
|
+
memory_coupon=coupon_kwargs.pop("memory_coupon", memory_coupon),
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
payoff_config = PayoffConfig(
|
|
405
|
+
rebate_rate=payoff_kwargs.pop("rebate_rate", ko_rate),
|
|
406
|
+
include_principal=payoff_kwargs.pop("include_principal", False),
|
|
407
|
+
**payoff_kwargs,
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
accrual_config = AccrualConfig(
|
|
411
|
+
coupon_pay_type=accrual_kwargs.pop("coupon_pay_type", CouponPayType.INSTANT),
|
|
412
|
+
is_annualized=accrual_kwargs.pop("is_annualized", True),
|
|
413
|
+
**accrual_kwargs,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
airbag_config = AirbagConfig(**airbag_kwargs)
|
|
417
|
+
|
|
418
|
+
return PhoenixOption(
|
|
419
|
+
initial_price=initial_price,
|
|
420
|
+
strike=strike,
|
|
421
|
+
maturity=maturity,
|
|
422
|
+
contract_multiplier=contract_multiplier,
|
|
423
|
+
barrier_config=barrier_config,
|
|
424
|
+
coupon_config=coupon_config,
|
|
425
|
+
payoff_config=payoff_config,
|
|
426
|
+
accrual_config=accrual_config,
|
|
427
|
+
airbag_config=airbag_config,
|
|
428
|
+
is_reverse=is_reverse,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def create_reverse_phoenix(
|
|
433
|
+
initial_price: float,
|
|
434
|
+
strike: float,
|
|
435
|
+
maturity: float,
|
|
436
|
+
contract_multiplier: float = 1.0,
|
|
437
|
+
ko_barrier: Optional[float] = None,
|
|
438
|
+
ko_rate: float = 0.0,
|
|
439
|
+
ki_barrier: Optional[float] = None,
|
|
440
|
+
coupon_barrier: Optional[float] = None,
|
|
441
|
+
coupon_rate: float = 0.01,
|
|
442
|
+
num_observations: int = 12,
|
|
443
|
+
memory_coupon: bool = True,
|
|
444
|
+
day_count_convention: DayCountConvention = DayCountConvention.ACT_365,
|
|
445
|
+
coupon_pay_type: CouponPayType = CouponPayType.INSTANT,
|
|
446
|
+
**kwargs,
|
|
447
|
+
) -> PhoenixOption:
|
|
448
|
+
"""
|
|
449
|
+
Create a reverse phoenix with down KO barrier and up KI barrier.
|
|
450
|
+
|
|
451
|
+
Reverse phoenix:
|
|
452
|
+
- KO barrier: DOWN (below initial price) - KO triggers when spot <= ko_barrier
|
|
453
|
+
- KI barrier: UP (above initial price) - KI triggers when spot >= ki_barrier
|
|
454
|
+
- Coupon barrier: UP - Coupon pays when spot <= coupon_barrier
|
|
455
|
+
- Embedded option: CALL (investor is short call on KI)
|
|
456
|
+
|
|
457
|
+
Args:
|
|
458
|
+
initial_price: Reference price for payoff calculations
|
|
459
|
+
strike: Strike price for embedded option
|
|
460
|
+
maturity: Time to maturity in years
|
|
461
|
+
contract_multiplier: Underlying units represented by one contract
|
|
462
|
+
ko_barrier: Knock-out barrier (default: 97% of initial_price)
|
|
463
|
+
ko_rate: Annualized knock-out rate (default: 0%)
|
|
464
|
+
ki_barrier: Knock-in barrier (default: 125% of initial_price)
|
|
465
|
+
coupon_barrier: Coupon barrier (default: 115% of initial_price)
|
|
466
|
+
coupon_rate: Per-period coupon rate (default: 1%)
|
|
467
|
+
num_observations: Number of observations (default: 12)
|
|
468
|
+
memory_coupon: If True, accumulate missed coupons (default: True)
|
|
469
|
+
day_count_convention: Day count for coupon calculation (default: ACT/365)
|
|
470
|
+
coupon_pay_type: INSTANT or EXPIRY (default: INSTANT)
|
|
471
|
+
**kwargs: Additional parameters passed to config objects
|
|
472
|
+
|
|
473
|
+
Returns:
|
|
474
|
+
Configured PhoenixOption instance with reverse direction
|
|
475
|
+
"""
|
|
476
|
+
_validate_core_params(
|
|
477
|
+
initial_price,
|
|
478
|
+
strike,
|
|
479
|
+
maturity,
|
|
480
|
+
contract_multiplier,
|
|
481
|
+
"create_reverse_phoenix",
|
|
482
|
+
num_observations
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
# Reverse phoenix defaults
|
|
486
|
+
if ko_barrier is None:
|
|
487
|
+
ko_barrier = 0.97 * initial_price
|
|
488
|
+
if ki_barrier is None:
|
|
489
|
+
ki_barrier = 1.25 * initial_price
|
|
490
|
+
if coupon_barrier is None:
|
|
491
|
+
coupon_barrier = 1.15 * initial_price
|
|
492
|
+
|
|
493
|
+
return create_standard_phoenix(
|
|
494
|
+
initial_price=initial_price,
|
|
495
|
+
strike=strike,
|
|
496
|
+
maturity=maturity,
|
|
497
|
+
contract_multiplier=contract_multiplier,
|
|
498
|
+
ko_barrier=ko_barrier,
|
|
499
|
+
ko_rate=ko_rate,
|
|
500
|
+
ki_barrier=ki_barrier,
|
|
501
|
+
coupon_barrier=coupon_barrier,
|
|
502
|
+
coupon_rate=coupon_rate,
|
|
503
|
+
num_observations=num_observations,
|
|
504
|
+
memory_coupon=memory_coupon,
|
|
505
|
+
day_count_convention=day_count_convention,
|
|
506
|
+
coupon_pay_type=coupon_pay_type,
|
|
507
|
+
is_reverse=True,
|
|
508
|
+
**kwargs,
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def create_memory_phoenix(
|
|
513
|
+
initial_price: float,
|
|
514
|
+
strike: float,
|
|
515
|
+
maturity: float,
|
|
516
|
+
contract_multiplier: float = 1.0,
|
|
517
|
+
**kwargs,
|
|
518
|
+
) -> PhoenixOption:
|
|
519
|
+
"""
|
|
520
|
+
Create a phoenix with memory coupon explicitly enabled.
|
|
521
|
+
|
|
522
|
+
Memory coupon: When coupon barrier is not hit at an observation, the
|
|
523
|
+
coupon is accumulated and paid when the barrier is hit at a later
|
|
524
|
+
observation (or at maturity if never knocked out).
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
initial_price: Reference price for payoff calculations
|
|
528
|
+
strike: Strike price for embedded option
|
|
529
|
+
maturity: Time to maturity in years
|
|
530
|
+
contract_multiplier: Underlying units represented by one contract
|
|
531
|
+
**kwargs: Additional parameters passed to create_standard_phoenix
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
PhoenixOption with memory_coupon=True
|
|
535
|
+
"""
|
|
536
|
+
return create_standard_phoenix(
|
|
537
|
+
initial_price=initial_price,
|
|
538
|
+
strike=strike,
|
|
539
|
+
maturity=maturity,
|
|
540
|
+
contract_multiplier=contract_multiplier,
|
|
541
|
+
memory_coupon=True,
|
|
542
|
+
**kwargs,
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def create_non_memory_phoenix(
|
|
547
|
+
initial_price: float,
|
|
548
|
+
strike: float,
|
|
549
|
+
maturity: float,
|
|
550
|
+
contract_multiplier: float = 1.0,
|
|
551
|
+
**kwargs,
|
|
552
|
+
) -> PhoenixOption:
|
|
553
|
+
"""
|
|
554
|
+
Create a phoenix with memory coupon disabled.
|
|
555
|
+
|
|
556
|
+
Non-memory coupon: Each observation is independent. If coupon barrier
|
|
557
|
+
is not hit, that period's coupon is forfeited.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
initial_price: Reference price for payoff calculations
|
|
561
|
+
strike: Strike price for embedded option
|
|
562
|
+
maturity: Time to maturity in years
|
|
563
|
+
contract_multiplier: Underlying units represented by one contract
|
|
564
|
+
**kwargs: Additional parameters passed to create_standard_phoenix
|
|
565
|
+
|
|
566
|
+
Returns:
|
|
567
|
+
PhoenixOption with memory_coupon=False
|
|
568
|
+
"""
|
|
569
|
+
return create_standard_phoenix(
|
|
570
|
+
initial_price=initial_price,
|
|
571
|
+
strike=strike,
|
|
572
|
+
maturity=maturity,
|
|
573
|
+
contract_multiplier=contract_multiplier,
|
|
574
|
+
memory_coupon=False,
|
|
575
|
+
**kwargs,
|
|
576
|
+
)
|