akquant 0.3.1__tar.gz → 0.3.2__tar.gz
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.
- {akquant-0.3.1 → akquant-0.3.2}/CHANGELOG.md +1 -0
- {akquant-0.3.1 → akquant-0.3.2}/Cargo.lock +1 -1
- {akquant-0.3.1 → akquant-0.3.2}/Cargo.toml +1 -1
- {akquant-0.3.1 → akquant-0.3.2}/PKG-INFO +1 -1
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/strategy.md +36 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/36_trailing_orders.py +6 -2
- {akquant-0.3.1 → akquant-0.3.2}/pyproject.toml +1 -1
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/__init__.py +5 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/akquant.pyi +1 -1
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/execution/sim.py +3 -2
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_event_adapter.py +8 -2
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_execution.py +27 -8
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_models.py +3 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_runtime.py +6 -0
- akquant-0.3.2/python/akquant/gateway/order_receipt.py +60 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/order_submitter.py +127 -23
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/live.py +43 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy.py +51 -18
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_trading_api.py +58 -27
- {akquant-0.3.1 → akquant-0.3.2}/tests/gateway_contract/test_submitter_contract.py +2 -2
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_event_adapter.py +45 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_execution_local_stops.py +10 -5
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_execution_read_path_parity.py +2 -2
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_execution_stop_requeue.py +6 -3
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_broker.py +64 -3
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_live_cancel.py +69 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_models_ext.py +40 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_submitter_readiness.py +1 -1
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_submitter_signature.py +21 -5
- akquant-0.3.2/tests/test_gateway_order_submitter_extra.py +216 -0
- akquant-0.3.2/tests/test_gateway_tif_mapping.py +25 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner_broker_bridge.py +138 -8
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner_broker_submitter.py +7 -7
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner_order_request_cache.py +1 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner_stop_remap.py +1 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_local_stop_scenario.py +11 -3
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_oco_bracket_broker_live_scenario.py +11 -3
- akquant-0.3.2/tests/test_order_receipt.py +66 -0
- akquant-0.3.2/tests/test_order_receipt_backtest.py +39 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_stop_id_remap_scenario.py +10 -6
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_strategy_extras.py +25 -17
- akquant-0.3.1/tests/test_gateway_order_submitter_extra.py +0 -69
- {akquant-0.3.1 → akquant-0.3.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.github/workflows/deploy-docs.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.github/workflows/docs-quality.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.github/workflows/release.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.gitignore +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/.pre-commit-config.yaml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/CODE_OF_CONDUCT.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/CONTRIBUTING.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/LICENSE +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/README.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/assets/dashboard_preview.png +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/assets/logo.svg +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/assets/social_preview.png +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/CNAME +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/assets/akquant-icon.svg +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/assets/akquant-logo.svg +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/assets/reports/akquant_report.html +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/analyzer_plugin_spec.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/broker_capability_matrix.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/custom_broker_production_checklist.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/custom_broker_registry.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/data_feed_adapter_spec.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/live_functional_quickstart.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/llm.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/ml.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/multi_strategy_guide.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/multi_timeframe_feed_api.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/runtime_config.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/strategy_style_decision.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/timezone.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/advanced/warm_start.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/analysis.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/cross_section_checklist.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/custom_indicator.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/data.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/examples.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/factor.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/indicator_scenario_quickref.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/optimization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/python_basics.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/quant_basics.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/rust_indicator_reference.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/strategy.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/talib_indicator_playbook.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/testing.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/guide/visualization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/index.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/meta/architecture.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/meta/internals.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/reference/api.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/start/first_strategy.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/start/installation.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/start/quickstart.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/start/setup_guide.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/01_foundations.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/02_programming.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/03_data.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/04_backtest_engine.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/05_strategy.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/06_stock_a.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/07_futures.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/08_options.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/09_funds.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/10_analysis.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/11_optimization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/12_ml.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/13_visualization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/14_factor.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/15_live_trading.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/16_rust_indicators.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/en/textbook/index.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/javascripts/mathjax.js +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/javascripts/search-lang-filter.js +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/robots.txt +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/adding_a_broker.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/analyzer_plugin_spec.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/broker_capability_matrix.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/custom_broker_production_checklist.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/custom_broker_registry.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/data_feed_adapter_spec.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/live_functional_quickstart.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/llm.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/ml.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/multi_strategy_guide.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/multi_timeframe_feed_api.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/runtime_config.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/strategy_style_decision.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/timezone.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/advanced/warm_start.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/analysis.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/cross_section_checklist.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/custom_indicator.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/data.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/examples.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/factor.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/indicator_scenario_quickref.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/optimization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/python_basics.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/quant_basics.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/rust_indicator_reference.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/talib_indicator_playbook.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/testing.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/guide/visualization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/index.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/meta/architecture.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/meta/internals.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/reference/api.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/start/first_strategy.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/start/installation.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/start/quickstart.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/start/setup_guide.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/00_glossary.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/01_foundations.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/02_programming.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/03_data.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/04_backtest_engine.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/05_strategy.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/06_stock_a.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/07_futures.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/08_options.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/09_funds.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/10_analysis.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/11_optimization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/12_ml.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/13_visualization.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/14_factor.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/15_live_trading.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/16_rust_indicators.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/ROADMAP.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/appendix_cite.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/appendix_pitfalls.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/appendix_setup.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/capstone.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/docs/zh/textbook/index.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/01_quickstart.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/02_parameter_optimization.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/03_parameter_optimization_advanced.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/04_mixed_assets.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/05_live_trading_ctp.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/06_complex_orders.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/07_option_test.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/08_event_callbacks.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/09_ml_framework.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/10_ml_walk_forward.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/11_plot_visualization.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/12_wfo_integrated.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/13_quantstats_report.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/14_multi_frequency.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/15_plot_intraday.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/16_adj_returns_signal.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/17_readme_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/18_benchmark_multisymbol.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/19_factor_expression.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/20_risk_management_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/21_warm_start_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/22_strategy_runtime_config_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/23_functional_callbacks_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/24_functional_tick_simulation_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/25_streaming_backtest_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/26_streaming_quickstart.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/27_streaming_monitoring_console.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/28_streaming_alerts_and_persist.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/29_streaming_event_report.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/30_streaming_report_oneclick.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/31_streaming_live_console.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/32_streaming_live_web.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/33_report_and_analysis_outputs.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/34_multi_strategy_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/35_custom_broker_registry_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/37_feed_replay_alignment_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/38_live_functional_strategy_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/39_live_broker_submit_order_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/40_functional_multi_slot_risk_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/41_live_multi_slot_orchestration_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/42_live_broker_event_audit_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/43_target_weights_rebalance.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/44_strategy_source_loader_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/45_talib_indicator_playbook_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/46_broker_profile_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/47_margin_liquidation_audit_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/48_margin_liquidation_priority_compare.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/49_on_expiry_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/50_framework_hooks_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/51_class_tick_callbacks_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/52_pre_open_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/53_timer_to_pre_open_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/54_functional_pre_open_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/55_functional_ml_walk_forward.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/56_functional_warm_start_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/57_functional_multi_slot_warm_start_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/58_incremental_bootstrap_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/59_akshare_etf_rotation.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/60_custom_indicator_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/61_indicator_visualization_export_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/62_indicator_streaming_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/63_indicator_ws_bridge_demo.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/64_indicator_live_web.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/65_bar_generator.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/README.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/benchmark_utils.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/pb_mock.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/01_stock_dual_moving_average.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/02_stock_grid_trading.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/03_stock_atr_breakout.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/04_stock_momentum_rotation.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/05_stock_momentum_rotation_timer.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/06_stock_momentum_rotation_bucket.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/07_stock_momentum_rotation_on_timer.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/08_target_positions_long_short.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/09_stock_momentum_rotation_after_bar.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/strategies/README.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch01_quickstart.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch02_programming.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch03_data.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch04_comparison.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch05_strategy.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch06_stock_a.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch07_futures.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch08_options.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch09_funds.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch09_portfolio.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch10_analysis.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch11_optimization.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch12_ml.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch13_visualization.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch14_factor.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch15_live_trading.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch15_strategy_loader.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/examples/textbook/ch16_indicators.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/mkdocs.yml +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/analysis/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/analysis/benchmark.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/analyzer_plugin.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/backtest/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/backtest/__init__.pyi +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/backtest/engine.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/backtest/result.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/bar_generator.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/checkpoint.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/config.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/data.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/execution/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/execution/base.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/factor/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/factor/engine.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/factor/ops.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/factor/parser.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/feed_adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/fund/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/futures/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/base.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_event_bridge.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_event_mapper.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_recovery.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_state_cache.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/broker_strategy_api.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/builtins.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/ctp/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/ctp/adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/ctp/native.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/miniqmt/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/miniqmt/stub.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/plugins.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/ptrade/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/brokers/ptrade/stub.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/ctp_adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/ctp_native.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/factory.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/local_stop_book.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/mapper.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/miniqmt.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/models.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/protocols.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/ptrade.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/registry.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/gateway/trader_base.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/indicator.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/indicator_recording.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/indicator_stream.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/log.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/ml/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/ml/model.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/optimize.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/option/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/params.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/params_adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/analysis.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/dashboard.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/indicator.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/report.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/strategy.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/plot/utils.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/py.typed +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/risk.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/sizer.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/stock/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_events.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_framework_hooks.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_history.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_loader.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_logging.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_ml.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_order_events.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_position.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_scheduler.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/strategy_time.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/talib/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/talib/backend.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/talib/core.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/talib/funcs.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/utils/__init__.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/python/akquant/utils/inspector.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/requirements-dev.txt +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/scripts/cargo-test.sh +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/scripts/check_docs_api_examples.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/scripts/check_docs_links.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/scripts/dev-check.sh +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/scripts/find_legacy_execution_policy_calls.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/scripts/golden_baseline_report.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/account.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/analysis/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/analysis/python.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/analysis/result.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/analysis/tests.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/analysis/tracker.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/analysis/types.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/bin/stub_gen.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/clock.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/context.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/data/aggregator.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/data/batch.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/data/client.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/data/feed.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/data/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/engine/core.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/engine/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/engine/python.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/engine/state.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/error.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/event.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/event_manager.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/common.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/crypto.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/forex.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/futures.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/matcher.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/option.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/python.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/realtime.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/simulated.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/slippage.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/execution/stock.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/history.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/momentum.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/momentum_oscillators.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/momentum_rates.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/moving_average.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/moving_average_compound.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/moving_average_core.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/moving_average_transforms.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/moving_average_windowed.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/trend.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/trend_directional.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/trend_oscillators.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/trend_regression.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/volatility.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/volatility_price.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/volatility_stats.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators/volume.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/indicators.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/lib.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/log_context.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/margin/calculator.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/margin/engine.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/margin/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/china.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/core.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/corporate_action.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/fund.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/futures.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/manager.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/option.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/simple.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/market/stock.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/corporate_action.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/instrument.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/market_data.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/order.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/timer.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/model/types.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/order_manager.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/processor.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/runner.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/channel.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/cleanup.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/data.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/execution.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/shared.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/statistics.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/pipeline/stages/strategy.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/portfolio.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/common.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/config.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/futures.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/manager.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/option.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/portfolio.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/rule.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/risk/stock.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/settlement/expiry.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/settlement/handler.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/settlement/manager.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/settlement/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/settlement/option.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/src/statistics/mod.rs +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/gateway_contract/test_event_bridge_contract.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/gateway_contract/test_recovery_contract.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/BASELINE_REPORT.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/LEGACY_EXECUTION_CALLS.md +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/futures_margin/equity_curve.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/futures_margin/metrics.json +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/futures_margin/orders.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/option_basic/equity_curve.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/option_basic/metrics.json +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/option_basic/orders.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/stock_t1/equity_curve.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/stock_t1/metrics.json +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/stock_t1/orders.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/baselines/stock_t1/trades.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/futures_margin/equity_curve.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/futures_margin/metrics.json +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/futures_margin/orders.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/option_basic/equity_curve.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/option_basic/metrics.json +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/option_basic/orders.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/stock_t1/equity_curve.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/stock_t1/metrics.json +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/stock_t1/orders.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/current/stock_t1/trades.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/data/future_margin.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/data/future_margin.parquet.sha256 +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/data/option_basic.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/data/option_basic.parquet.sha256 +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/data/stock_t1.parquet +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/data/stock_t1.parquet.sha256 +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/gen_data.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/runner.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/strategies/futures_margin.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/strategies/option_basic.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/strategies/stock_t1.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/golden/test_golden.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_account_risk_rules.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_api_rename_cash.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_api_rename_composites.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_api_rename_equity.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_api_rename_holding_bars.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_api_rename_positions.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_api_rename_rebalance.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_bar_generator.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_bridge_adapts_events.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_bridge_drives_order_groups.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_event_adapter_local_id.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_plugins.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_position_sync.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_seed_baseline.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_broker_trade_redelivery_dedup.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_close_position_delegate.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_composed_ctx_not_ready.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_cost_config_consolidation.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_custom_matcher.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_data_catalog.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_docs_api_examples.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_docs_links.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_engine.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_event_model_parity.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_examples_regression.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_binding.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_broker_reads_routed.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_composed_parity.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_read_delegation.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_sim.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_execution_write_delegation.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_factor_engine.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_factor_ops.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_feed_adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_live_reads.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_state_cache.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_broker_state_invalidation.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_brokers_paths.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_builtins_registry.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_callbacks.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_ctp_adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_ctp_native.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_factory.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_mapper.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_optional_market.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_registry.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_sim_submit_guard.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_gateway_trader_base.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_indicator_live_web_example.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_indicator_recording.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_inspector.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner_broker_readiness.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_live_runner_broker_recovery.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_local_stop_book.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_local_stop_book_threadsafe.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_multisymbol_cross_section_consistency.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_on_execution_report_noop.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_orders_df.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_params_adapter.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_partial_filled_status.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_portfolio.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_quickstart_stream_consistency.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_removed_wrappers.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_report_helpers.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_report_plot_extensions.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_result_analysis_extensions.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_review_minors_cleanup.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_stop_orders.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_strategy_events_stop_hook.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_strategy_order_group_lock.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_strategy_sizing_broker_live_guard.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_strategy_timers_indicators.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_t_plus_one.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_talib_backend.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_talib_compat.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_target_orders_core.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_trades_df.py +0 -0
- {akquant-0.3.1 → akquant-0.3.2}/tests/test_version.py +0 -0
|
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
12
12
|
- `BacktestConfig` 新增 `days_per_year`(年化天数因子,默认 252;数字货币 24/7 市场可设 365)与 `risk_free_rate`(年化无风险利率,默认 0.0)两个字段,用于参数化 Sharpe/Sortino/波动率等风险指标的年化口径。`risk_free_rate` 默认 0 不改变任何现有数值。
|
|
13
13
|
|
|
14
14
|
### Changed
|
|
15
|
+
- **`buy`/`sell`/`submit_order` 返回类型变更(破坏性)**:三者现统一返回 `OrderReceipt`(原为 `str` 订单号),回测与实盘(`broker_live`)两种模式返回类型一致;实盘 `submit_order` 此前会将多腿委托(如反手拆分的平仓+开仓、开平分离)收窄为单一 id 字符串,现已修复为返回携带全部腿 id 的完整 `OrderReceipt`。取单个订单 id 用 `receipt.primary`(首腿 broker_order_id,兼容旧用法),取全部腿 id 用 `receipt.order_ids`;`str(receipt)` 取 `group_id`(逻辑委托的客户端订单号),关联成交请用 `trade.group_id` 而非逐个 order_id 比对;新增 `cancel_group(group_id)` 用于一次性撤销一个逻辑委托的全部腿。
|
|
15
16
|
- **回测指标口径变更(破坏性)**:Sharpe / Sortino 比率的分子改为「日收益算术均值 × `days_per_year`」做年化,替代原先的 CAGR(复合年化),与 pyfolio/empyrical/quantstats 等主流实现一致,并与分母 `√days_per_year` 的年化口径匹配。升级后历史报告的 Sharpe/Sortino 数值会变化,不可直接与旧版逐值对比;UPI 与 Calmar 仍沿用 CAGR 口径。
|
|
16
17
|
- 策略交易日边界回调已硬切改名:`before_trading(trading_date, timestamp)` 更名为 `on_before_trading(trading_date, timestamp)`,`after_trading(trading_date, timestamp)` 更名为 `on_after_trading(trading_date, timestamp)`。
|
|
17
18
|
- 旧回调名不再保留兼容别名;升级到当前版本后,若策略仍实现 `before_trading` / `after_trading`,将不会再被框架触发,请同步迁移到新名称。
|
|
@@ -774,8 +774,44 @@ AKQuant 当前的订单语义已经不再是单纯的 `side`,而是 `side + po
|
|
|
774
774
|
|
|
775
775
|
* **撤单 (Cancel Order)**:
|
|
776
776
|
* `self.cancel_order(order_id)`: 撤销指定订单。
|
|
777
|
+
* `self.cancel_group(group_id)`: 按 `group_id` 撤销一个逻辑委托拆出的全部腿。
|
|
777
778
|
* `self.cancel_all_orders()`: 撤销当前所有未成交订单。
|
|
778
779
|
|
|
780
|
+
### 7.2.2 OrderReceipt:下单回执与 group_id
|
|
781
|
+
|
|
782
|
+
`buy()` / `sell()` / `submit_order()` 统一返回 `OrderReceipt`(回测与
|
|
783
|
+
`broker_live` 实盘两种模式返回类型一致,不再是裸 `str` 订单号):
|
|
784
|
+
|
|
785
|
+
* `receipt.primary`:首腿的订单 id(`broker_order_id`),多数场景下当作
|
|
786
|
+
"这笔下单的订单号" 使用,等价于旧版直接拿到的 `str`。
|
|
787
|
+
* `receipt.order_ids`:全部腿的订单 id 元组。一次 `side + position_effect="auto"`
|
|
788
|
+
调用在持有反向仓位时会被自动拆成 `close` + `open` 两腿(或期货 `close_today`
|
|
789
|
+
/ `close_yesterday` 两腿),此时 `order_ids` 长度 > 1,`primary` 只是其中一腿。
|
|
790
|
+
* `str(receipt)`:逻辑委托的 `group_id`(客户端订单号),用于把拆出的多腿关联为
|
|
791
|
+
"同一次下单";与 `receipt.primary` 是两个不同的 id 空间,不要混用。
|
|
792
|
+
* 关联成交回报时优先用 `trade.group_id` 而不是逐个 `order_id` 比对,这样无论
|
|
793
|
+
该笔委托是否被拆腿都能正确聚合。
|
|
794
|
+
|
|
795
|
+
跨 `close + open` 的反手示例(先平后开,两腿在同一次 `buy()`/`sell()` 调用里发出):
|
|
796
|
+
|
|
797
|
+
```python
|
|
798
|
+
def on_bar(self, bar):
|
|
799
|
+
# 当前持有空头仓位,买入 300 手:自动拆成「平空 200 手」+「开多 100 手」两腿
|
|
800
|
+
receipt = self.buy(bar.symbol, quantity=300) # position_effect 默认 "auto"
|
|
801
|
+
|
|
802
|
+
print(receipt.primary) # 首腿(平仓腿)的订单 id,兼容旧版单一 str 用法
|
|
803
|
+
print(receipt.order_ids) # (平仓腿 id, 开仓腿 id) —— 全部腿
|
|
804
|
+
print(str(receipt)) # group_id:这次逻辑委托的客户端订单号
|
|
805
|
+
|
|
806
|
+
# 想整单撤销(两腿都撤):
|
|
807
|
+
self.cancel_group(receipt) # 等价于 self.cancel_group(str(receipt))
|
|
808
|
+
|
|
809
|
+
def on_trade(self, trade):
|
|
810
|
+
# 用 group_id 聚合同一次逻辑委托拆出的多腿成交,而不是比较单个 order_id
|
|
811
|
+
if trade.group_id == self._entry_group_id:
|
|
812
|
+
...
|
|
813
|
+
```
|
|
814
|
+
|
|
779
815
|
### 7.3 OCO 与 Bracket 助手
|
|
780
816
|
|
|
781
817
|
AKQuant 提供了两组交易助手,减少策略中手写订单联动逻辑:
|
|
@@ -23,7 +23,8 @@ class TrailingOrderStrategy(Strategy):
|
|
|
23
23
|
and not self.entry_order_id
|
|
24
24
|
and not self.trailing_order_id
|
|
25
25
|
):
|
|
26
|
-
|
|
26
|
+
entry_receipt = self.buy(bar.symbol, 100, tag="trail-entry")
|
|
27
|
+
self.entry_order_id = str(getattr(entry_receipt, "primary", entry_receipt))
|
|
27
28
|
print(
|
|
28
29
|
f"[{bar.timestamp_iso}] 提交进场单: {bar.symbol}, close={bar.close:.2f}"
|
|
29
30
|
)
|
|
@@ -37,7 +38,7 @@ class TrailingOrderStrategy(Strategy):
|
|
|
37
38
|
if trade.order_id == self.entry_order_id:
|
|
38
39
|
self.entry_order_id = ""
|
|
39
40
|
ref_price = self.last_close.get(trade.symbol, float(trade.price))
|
|
40
|
-
|
|
41
|
+
trailing_receipt = self.place_trailing_stop(
|
|
41
42
|
symbol=trade.symbol,
|
|
42
43
|
quantity=float(trade.quantity),
|
|
43
44
|
trail_offset=self.trail_offset,
|
|
@@ -45,6 +46,9 @@ class TrailingOrderStrategy(Strategy):
|
|
|
45
46
|
trail_reference_price=ref_price,
|
|
46
47
|
tag="trail-stop",
|
|
47
48
|
)
|
|
49
|
+
self.trailing_order_id = str(
|
|
50
|
+
getattr(trailing_receipt, "primary", trailing_receipt)
|
|
51
|
+
)
|
|
48
52
|
print(
|
|
49
53
|
f"[{trade.timestamp}] 提交 trailing stop: symbol={trade.symbol}, "
|
|
50
54
|
f"offset={self.trail_offset:.2f}, ref={ref_price:.2f}"
|
|
@@ -52,6 +52,7 @@ from .feed_adapter import (
|
|
|
52
52
|
ReplayFeedAdapter,
|
|
53
53
|
ResampledFeedAdapter,
|
|
54
54
|
)
|
|
55
|
+
from .gateway.order_receipt import OrderLeg, OrderReceipt
|
|
55
56
|
from .indicator import Indicator, IndicatorSet
|
|
56
57
|
from .indicator_stream import (
|
|
57
58
|
is_indicator_stream_event,
|
|
@@ -181,6 +182,8 @@ if hasattr(_akquant, "__all__"): # noqa: F405
|
|
|
181
182
|
"validate_strategy_params",
|
|
182
183
|
"extract_runtime_kwargs",
|
|
183
184
|
"build_param_grid_from_search_space",
|
|
185
|
+
"OrderLeg",
|
|
186
|
+
"OrderReceipt",
|
|
184
187
|
"talib",
|
|
185
188
|
]
|
|
186
189
|
else:
|
|
@@ -259,6 +262,8 @@ else:
|
|
|
259
262
|
"validate_strategy_params",
|
|
260
263
|
"extract_runtime_kwargs",
|
|
261
264
|
"build_param_grid_from_search_space",
|
|
265
|
+
"OrderLeg",
|
|
266
|
+
"OrderReceipt",
|
|
262
267
|
"talib",
|
|
263
268
|
]
|
|
264
269
|
|
|
@@ -112,7 +112,7 @@ class TimeInForce:
|
|
|
112
112
|
GTC: typing.ClassVar["TimeInForce"]
|
|
113
113
|
IOC: typing.ClassVar["TimeInForce"]
|
|
114
114
|
FOK: typing.ClassVar["TimeInForce"]
|
|
115
|
-
|
|
115
|
+
Day: typing.ClassVar["TimeInForce"]
|
|
116
116
|
|
|
117
117
|
class TradingSession:
|
|
118
118
|
Normal: typing.ClassVar["TradingSession"]
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from .. import strategy_trading_api as api
|
|
8
|
+
from ..gateway.order_receipt import OrderReceipt
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class SimExecution:
|
|
@@ -50,8 +51,8 @@ class SimExecution:
|
|
|
50
51
|
"""获取现金."""
|
|
51
52
|
return api._sim_get_cash(self._s)
|
|
52
53
|
|
|
53
|
-
def submit_order(self, **kwargs: Any) ->
|
|
54
|
-
"""
|
|
54
|
+
def submit_order(self, **kwargs: Any) -> OrderReceipt:
|
|
55
|
+
"""提交订单,返回 OrderReceipt(携带回测拆腿产生的全部订单 id)."""
|
|
55
56
|
return api._sim_submit_order(self._s, **kwargs)
|
|
56
57
|
|
|
57
58
|
def cancel_order(self, order_id: str) -> None:
|
|
@@ -44,6 +44,7 @@ class StrategyOrder:
|
|
|
44
44
|
client_order_id: str = ""
|
|
45
45
|
broker_order_id: str = ""
|
|
46
46
|
owner_strategy_id: Optional[str] = None
|
|
47
|
+
group_id: str = ""
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
@dataclass
|
|
@@ -62,6 +63,7 @@ class StrategyTrade:
|
|
|
62
63
|
client_order_id: str = ""
|
|
63
64
|
broker_order_id: str = ""
|
|
64
65
|
owner_strategy_id: Optional[str] = None
|
|
66
|
+
group_id: str = ""
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
_STATUS_MAP = {
|
|
@@ -138,8 +140,8 @@ def _to_tif(value: Any) -> Optional[Any]:
|
|
|
138
140
|
"GTC": TimeInForce.GTC,
|
|
139
141
|
"IOC": TimeInForce.IOC,
|
|
140
142
|
"FOK": TimeInForce.FOK,
|
|
141
|
-
"GTD": TimeInForce.
|
|
142
|
-
"DAY": TimeInForce.
|
|
143
|
+
"GTD": TimeInForce.Day,
|
|
144
|
+
"DAY": TimeInForce.Day,
|
|
143
145
|
}
|
|
144
146
|
return mapping.get(text)
|
|
145
147
|
|
|
@@ -149,6 +151,7 @@ def map_order_snapshot(
|
|
|
149
151
|
request: Any = None,
|
|
150
152
|
owner_strategy_id: Optional[str] = None,
|
|
151
153
|
local_id: Optional[str] = None,
|
|
154
|
+
group_id: str = "",
|
|
152
155
|
) -> StrategyOrder:
|
|
153
156
|
"""把 UnifiedOrderSnapshot 映射成与回测 Order 同形状的 StrategyOrder."""
|
|
154
157
|
broker_order_id = str(_get(snapshot, "broker_order_id", "") or "")
|
|
@@ -186,6 +189,7 @@ def map_order_snapshot(
|
|
|
186
189
|
client_order_id=str(_get(snapshot, "client_order_id", "") or ""),
|
|
187
190
|
broker_order_id=broker_order_id,
|
|
188
191
|
owner_strategy_id=owner_strategy_id,
|
|
192
|
+
group_id=group_id,
|
|
189
193
|
)
|
|
190
194
|
|
|
191
195
|
|
|
@@ -236,6 +240,7 @@ def map_trade(
|
|
|
236
240
|
request: Any = None,
|
|
237
241
|
owner_strategy_id: Optional[str] = None,
|
|
238
242
|
local_id: Optional[str] = None,
|
|
243
|
+
group_id: str = "",
|
|
239
244
|
) -> StrategyTrade:
|
|
240
245
|
"""把 UnifiedTrade 映射成与回测 Trade 同形状的 StrategyTrade."""
|
|
241
246
|
return StrategyTrade(
|
|
@@ -251,4 +256,5 @@ def map_trade(
|
|
|
251
256
|
client_order_id=str(_get(trade, "client_order_id", "") or ""),
|
|
252
257
|
broker_order_id=str(_get(trade, "broker_order_id", "") or ""),
|
|
253
258
|
owner_strategy_id=owner_strategy_id,
|
|
259
|
+
group_id=group_id,
|
|
254
260
|
)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any, cast
|
|
6
6
|
|
|
7
7
|
from ..log import get_logger
|
|
8
8
|
from .broker_event_adapter import map_local_stop, map_order_snapshot
|
|
@@ -14,6 +14,7 @@ from .local_stop_book import (
|
|
|
14
14
|
is_stop_order_type,
|
|
15
15
|
underlying_order_type,
|
|
16
16
|
)
|
|
17
|
+
from .order_receipt import OrderReceipt
|
|
17
18
|
|
|
18
19
|
logger = get_logger("gateway.live")
|
|
19
20
|
|
|
@@ -30,13 +31,15 @@ class BrokerExecution:
|
|
|
30
31
|
state_cache: BrokerStateCache,
|
|
31
32
|
submitter: Any,
|
|
32
33
|
record_stop_remap: Any = None,
|
|
34
|
+
group_broker_ids: Any = None,
|
|
33
35
|
) -> None:
|
|
34
|
-
"""
|
|
36
|
+
"""绑定策略实例、柜台网关、状态缓存、下单器、止损 remap 与 group 反查回调."""
|
|
35
37
|
self._s = strategy
|
|
36
38
|
self._gw = trader_gateway
|
|
37
39
|
self._cache = state_cache
|
|
38
40
|
self._submitter = submitter
|
|
39
41
|
self._record_stop_remap = record_stop_remap
|
|
42
|
+
self._group_broker_ids = group_broker_ids
|
|
40
43
|
self._stop_book = LocalStopBook()
|
|
41
44
|
self._stop_seq = 0
|
|
42
45
|
self._warned_hold_bar = False
|
|
@@ -126,11 +129,12 @@ class BrokerExecution:
|
|
|
126
129
|
"""获取现金."""
|
|
127
130
|
return float(getattr(self._cache.account(), "cash", 0.0) or 0.0)
|
|
128
131
|
|
|
129
|
-
def submit_order(self, **kwargs: Any) ->
|
|
130
|
-
"""
|
|
132
|
+
def submit_order(self, **kwargs: Any) -> OrderReceipt:
|
|
133
|
+
"""提交订单,返回下单回执(OrderReceipt,含全部腿 id).
|
|
131
134
|
|
|
132
135
|
条件/止损单(trigger_price/trail_offset 或止损类 order_type)拦截入
|
|
133
|
-
|
|
136
|
+
本地簿,不下发柜台;柜台不支持这类原生条件单——本地止损单只有单一
|
|
137
|
+
本地 id,封装为单腿 OrderReceipt 以保持返回类型与柜台下单一致。
|
|
134
138
|
|
|
135
139
|
time_in_force=None(Strategy.submit_order 的缺省值)会显式覆盖
|
|
136
140
|
submitter.submit_order 签名默认值 "GTC";这里丢弃 None,
|
|
@@ -141,10 +145,16 @@ class BrokerExecution:
|
|
|
141
145
|
or kwargs.get("trail_offset") is not None
|
|
142
146
|
or is_stop_order_type(kwargs.get("order_type"))
|
|
143
147
|
):
|
|
144
|
-
|
|
148
|
+
local_id = self._register_local_stop(**kwargs)
|
|
149
|
+
return OrderReceipt.single(
|
|
150
|
+
group_id=local_id,
|
|
151
|
+
broker_order_id=local_id,
|
|
152
|
+
position_effect=str(kwargs.get("position_effect") or "auto"),
|
|
153
|
+
client_order_id=local_id,
|
|
154
|
+
)
|
|
145
155
|
if kwargs.get("time_in_force") is None:
|
|
146
156
|
kwargs.pop("time_in_force", None)
|
|
147
|
-
return
|
|
157
|
+
return cast(OrderReceipt, self._submitter.submit_order(**kwargs))
|
|
148
158
|
|
|
149
159
|
def _next_local_stop_id(self) -> str:
|
|
150
160
|
self._stop_seq += 1
|
|
@@ -205,7 +215,7 @@ class BrokerExecution:
|
|
|
205
215
|
if order.time_in_force is not None:
|
|
206
216
|
kwargs["time_in_force"] = order.time_in_force
|
|
207
217
|
try:
|
|
208
|
-
broker_order_id = str(self._submitter.submit_order(**kwargs))
|
|
218
|
+
broker_order_id = str(self._submitter.submit_order(**kwargs).primary)
|
|
209
219
|
except Exception as exc: # noqa: BLE001
|
|
210
220
|
order.submit_attempts += 1
|
|
211
221
|
if order.submit_attempts < MAX_STOP_SUBMIT_ATTEMPTS:
|
|
@@ -233,6 +243,15 @@ class BrokerExecution:
|
|
|
233
243
|
return
|
|
234
244
|
self._gw.cancel_order(str(order_id))
|
|
235
245
|
|
|
246
|
+
def cancel_group(self, group_id: str) -> None:
|
|
247
|
+
"""撤销一个逻辑委托的全部腿(按 group_id)."""
|
|
248
|
+
gid = str(group_id)
|
|
249
|
+
if self._group_broker_ids is None:
|
|
250
|
+
return
|
|
251
|
+
for broker_order_id in self._group_broker_ids(gid):
|
|
252
|
+
if broker_order_id:
|
|
253
|
+
self.cancel_order(str(broker_order_id))
|
|
254
|
+
|
|
236
255
|
def cancel_all_orders(self, symbol: str | None = None) -> None:
|
|
237
256
|
"""取消所有未完成订单(含本地止损)."""
|
|
238
257
|
for order in self._stop_book.open_orders(symbol):
|
|
@@ -195,6 +195,7 @@ class UnifiedOrderSnapshot:
|
|
|
195
195
|
reject_reason: str = ""
|
|
196
196
|
timestamp_ns: int = 0
|
|
197
197
|
position_effect: str = "auto"
|
|
198
|
+
group_id: str = ""
|
|
198
199
|
|
|
199
200
|
|
|
200
201
|
@dataclass
|
|
@@ -210,6 +211,7 @@ class UnifiedTrade:
|
|
|
210
211
|
price: float
|
|
211
212
|
timestamp_ns: int
|
|
212
213
|
position_effect: str = "auto"
|
|
214
|
+
group_id: str = ""
|
|
213
215
|
|
|
214
216
|
|
|
215
217
|
@dataclass
|
|
@@ -225,6 +227,7 @@ class UnifiedExecutionReport:
|
|
|
225
227
|
reject_reason: str = ""
|
|
226
228
|
timestamp_ns: int = 0
|
|
227
229
|
position_effect: str = "auto"
|
|
230
|
+
group_id: str = ""
|
|
228
231
|
|
|
229
232
|
|
|
230
233
|
@dataclass
|
|
@@ -38,6 +38,8 @@ class BrokerRuntime:
|
|
|
38
38
|
adapt_strategy_payload: Callable[[str, Any], Any],
|
|
39
39
|
record_stop_remap: Any = None,
|
|
40
40
|
should_replay_trades: Callable[[], bool] | None = None,
|
|
41
|
+
sync_group_mapping: Callable[[str, str], None] = lambda _c, _g: None,
|
|
42
|
+
group_broker_ids: Callable[[str], list[str]] | None = None,
|
|
41
43
|
) -> None:
|
|
42
44
|
"""Assemble broker submitter, event bridge and recovery coordinators."""
|
|
43
45
|
self._broker_state_caches: list[Any] = []
|
|
@@ -76,6 +78,8 @@ class BrokerRuntime:
|
|
|
76
78
|
self._get_execution_capabilities = get_execution_capabilities
|
|
77
79
|
self._record_order_request = record_order_request
|
|
78
80
|
self._record_stop_remap = record_stop_remap
|
|
81
|
+
self._sync_group_mapping = sync_group_mapping
|
|
82
|
+
self._group_broker_ids = group_broker_ids
|
|
79
83
|
self._submitter: BrokerOrderSubmitter | None = None
|
|
80
84
|
|
|
81
85
|
@property
|
|
@@ -114,6 +118,7 @@ class BrokerRuntime:
|
|
|
114
118
|
payload_field=self._payload_field,
|
|
115
119
|
get_execution_capabilities=self._get_execution_capabilities,
|
|
116
120
|
record_order_request=self._record_order_request,
|
|
121
|
+
sync_group_mapping=self._sync_group_mapping,
|
|
117
122
|
)
|
|
118
123
|
self._submitter.install()
|
|
119
124
|
|
|
@@ -130,6 +135,7 @@ class BrokerRuntime:
|
|
|
130
135
|
cache,
|
|
131
136
|
self._submitter,
|
|
132
137
|
record_stop_remap=self._record_stop_remap,
|
|
138
|
+
group_broker_ids=self._group_broker_ids,
|
|
133
139
|
)
|
|
134
140
|
|
|
135
141
|
return self._submitter
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""OrderReceipt: 逻辑委托的返回句柄,携带跨边界拆出的全部腿 id 与语义."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Iterator
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class OrderLeg:
|
|
11
|
+
"""单腿委托:语义 + client/broker id."""
|
|
12
|
+
|
|
13
|
+
position_effect: str
|
|
14
|
+
quantity: float
|
|
15
|
+
client_order_id: str
|
|
16
|
+
broker_order_id: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class OrderReceipt:
|
|
21
|
+
"""一次下单调用的结果:一个逻辑委托可拆成多腿分别报单."""
|
|
22
|
+
|
|
23
|
+
group_id: str
|
|
24
|
+
order_ids: tuple[str, ...]
|
|
25
|
+
legs: tuple[OrderLeg, ...]
|
|
26
|
+
|
|
27
|
+
def __str__(self) -> str:
|
|
28
|
+
"""Return group_id as string representation."""
|
|
29
|
+
return self.group_id
|
|
30
|
+
|
|
31
|
+
def __iter__(self) -> Iterator[str]:
|
|
32
|
+
"""Iterate over order_ids."""
|
|
33
|
+
return iter(self.order_ids)
|
|
34
|
+
|
|
35
|
+
def __len__(self) -> int:
|
|
36
|
+
"""Return count of order_ids."""
|
|
37
|
+
return len(self.order_ids)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def primary(self) -> str:
|
|
41
|
+
"""Return first order_id or empty string if no ids."""
|
|
42
|
+
return self.order_ids[0] if self.order_ids else ""
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def single(
|
|
46
|
+
cls,
|
|
47
|
+
group_id: str,
|
|
48
|
+
broker_order_id: str,
|
|
49
|
+
position_effect: str = "auto",
|
|
50
|
+
quantity: float = 0.0,
|
|
51
|
+
client_order_id: str = "",
|
|
52
|
+
) -> "OrderReceipt":
|
|
53
|
+
"""Create a single-leg receipt for convenience."""
|
|
54
|
+
leg = OrderLeg(
|
|
55
|
+
position_effect=position_effect,
|
|
56
|
+
quantity=quantity,
|
|
57
|
+
client_order_id=client_order_id or group_id,
|
|
58
|
+
broker_order_id=broker_order_id,
|
|
59
|
+
)
|
|
60
|
+
return cls(group_id=group_id, order_ids=(broker_order_id,), legs=(leg,))
|
|
@@ -8,6 +8,7 @@ from .broker_models import (
|
|
|
8
8
|
validate_broker_extra,
|
|
9
9
|
validate_execution_semantics,
|
|
10
10
|
)
|
|
11
|
+
from .order_receipt import OrderLeg, OrderReceipt
|
|
11
12
|
|
|
12
13
|
logger = get_logger("gateway.live")
|
|
13
14
|
|
|
@@ -38,49 +39,38 @@ def find_live_close_position(
|
|
|
38
39
|
return None
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
def
|
|
42
|
+
def _split_close_legs(
|
|
42
43
|
trader_gateway: Any,
|
|
43
44
|
capability: BrokerCapability,
|
|
44
45
|
symbol: str,
|
|
45
46
|
side: str,
|
|
46
47
|
quantity: float,
|
|
47
|
-
|
|
48
|
-
reduce_only: bool,
|
|
48
|
+
supported_effects: set[str],
|
|
49
49
|
payload_field: Callable[[Any, str], Any],
|
|
50
50
|
) -> list[tuple[str, float]]:
|
|
51
|
-
"""
|
|
52
|
-
normalized_effect = str(position_effect).strip().lower()
|
|
53
|
-
if quantity <= 0 or reduce_only or normalized_effect != "close":
|
|
54
|
-
return [(normalized_effect, quantity)]
|
|
55
|
-
supported_effects = {
|
|
56
|
-
str(item).strip().lower() for item in capability.supported_position_effects
|
|
57
|
-
}
|
|
51
|
+
"""把一段平仓量拆成 close_today/close_yesterday;能力不足则整段 close."""
|
|
58
52
|
if not capability.position_details:
|
|
59
|
-
return [(
|
|
53
|
+
return [("close", quantity)]
|
|
60
54
|
if (
|
|
61
55
|
"close_today" not in supported_effects
|
|
62
56
|
or "close_yesterday" not in supported_effects
|
|
63
57
|
):
|
|
64
|
-
return [(
|
|
65
|
-
|
|
58
|
+
return [("close", quantity)]
|
|
66
59
|
query_positions = getattr(trader_gateway, "query_positions", None)
|
|
67
60
|
if not callable(query_positions):
|
|
68
|
-
return [(
|
|
61
|
+
return [("close", quantity)]
|
|
69
62
|
try:
|
|
70
63
|
positions = query_positions()
|
|
71
64
|
except Exception:
|
|
72
|
-
return [(
|
|
73
|
-
|
|
65
|
+
return [("close", quantity)]
|
|
74
66
|
target_position = find_live_close_position(positions, symbol, side, payload_field)
|
|
75
67
|
if target_position is None:
|
|
76
|
-
return [(
|
|
77
|
-
|
|
68
|
+
return [("close", quantity)]
|
|
78
69
|
available_today = max(
|
|
79
70
|
0.0, float(getattr(target_position, "available_today_quantity", 0.0) or 0.0)
|
|
80
71
|
)
|
|
81
72
|
available_yesterday = max(
|
|
82
|
-
0.0,
|
|
83
|
-
float(getattr(target_position, "available_yesterday_quantity", 0.0) or 0.0),
|
|
73
|
+
0.0, float(getattr(target_position, "available_yesterday_quantity", 0.0) or 0.0)
|
|
84
74
|
)
|
|
85
75
|
split_quantity = min(quantity, available_today + available_yesterday)
|
|
86
76
|
legs: list[tuple[str, float]] = []
|
|
@@ -99,6 +89,95 @@ def resolve_live_order_legs(
|
|
|
99
89
|
return legs
|
|
100
90
|
|
|
101
91
|
|
|
92
|
+
def resolve_live_order_legs(
|
|
93
|
+
trader_gateway: Any,
|
|
94
|
+
capability: BrokerCapability,
|
|
95
|
+
symbol: str,
|
|
96
|
+
side: str,
|
|
97
|
+
quantity: float,
|
|
98
|
+
position_effect: str,
|
|
99
|
+
reduce_only: bool,
|
|
100
|
+
payload_field: Callable[[Any, str], Any],
|
|
101
|
+
) -> list[tuple[str, float]]:
|
|
102
|
+
"""Resolve close orders into close_today/close_yesterday legs when supported.
|
|
103
|
+
|
|
104
|
+
Also resolves `auto` reversal orders (sell/buy quantity exceeding the opposite
|
|
105
|
+
position) into close leg(s) plus a trailing `open` leg, unless the broker
|
|
106
|
+
declares it handles reversal itself via `"auto_reverse" in capability.features`.
|
|
107
|
+
"""
|
|
108
|
+
normalized_effect = str(position_effect).strip().lower()
|
|
109
|
+
if quantity <= 0 or reduce_only:
|
|
110
|
+
return [(normalized_effect, quantity)]
|
|
111
|
+
|
|
112
|
+
supported_effects = {
|
|
113
|
+
str(item).strip().lower() for item in capability.supported_position_effects
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# 反手:auto 单卖出量超过反向持仓可用量时,核心拆成 平仓 + 开仓。
|
|
117
|
+
# broker 若声明自身会反手(auto_reverse),则不拆。
|
|
118
|
+
if normalized_effect == "auto":
|
|
119
|
+
if "auto_reverse" in capability.features:
|
|
120
|
+
return [(normalized_effect, quantity)]
|
|
121
|
+
if "open" not in supported_effects or "close" not in supported_effects:
|
|
122
|
+
return [(normalized_effect, quantity)]
|
|
123
|
+
query_positions = getattr(trader_gateway, "query_positions", None)
|
|
124
|
+
if not callable(query_positions):
|
|
125
|
+
return [(normalized_effect, quantity)]
|
|
126
|
+
try:
|
|
127
|
+
positions = query_positions()
|
|
128
|
+
except Exception:
|
|
129
|
+
return [(normalized_effect, quantity)]
|
|
130
|
+
target = find_live_close_position(positions, symbol, side, payload_field)
|
|
131
|
+
if target is None:
|
|
132
|
+
return [(normalized_effect, quantity)]
|
|
133
|
+
raw_today = payload_field(target, "available_today_quantity")
|
|
134
|
+
raw_yesterday = payload_field(target, "available_yesterday_quantity")
|
|
135
|
+
raw_available = payload_field(target, "available_quantity")
|
|
136
|
+
has_availability = any(
|
|
137
|
+
value is not None for value in (raw_today, raw_yesterday, raw_available)
|
|
138
|
+
)
|
|
139
|
+
available_split = max(0.0, float(raw_today or 0.0)) + max(
|
|
140
|
+
0.0, float(raw_yesterday or 0.0)
|
|
141
|
+
)
|
|
142
|
+
available_quantity = max(0.0, float(raw_available or 0.0))
|
|
143
|
+
raw_quantity = abs(float(payload_field(target, "quantity") or 0.0))
|
|
144
|
+
# 可平口径与 _split_close_legs 一致: broker 报可用量时优先用今昨可用量,
|
|
145
|
+
# 其次 available_quantity(即便为 0 也不回退——全冻结应交由下方 closable<=0
|
|
146
|
+
# 门槛退回单腿 auto); 仅当 broker 完全不提供可用量字段时才退回原始持仓。
|
|
147
|
+
if has_availability:
|
|
148
|
+
closable = available_split if available_split > 0 else available_quantity
|
|
149
|
+
else:
|
|
150
|
+
closable = raw_quantity
|
|
151
|
+
if closable <= 0 or quantity <= closable:
|
|
152
|
+
return [(normalized_effect, quantity)]
|
|
153
|
+
close_qty = closable
|
|
154
|
+
open_qty = quantity - closable
|
|
155
|
+
legs = _split_close_legs(
|
|
156
|
+
trader_gateway,
|
|
157
|
+
capability,
|
|
158
|
+
symbol,
|
|
159
|
+
side,
|
|
160
|
+
close_qty,
|
|
161
|
+
supported_effects,
|
|
162
|
+
payload_field,
|
|
163
|
+
)
|
|
164
|
+
legs.append(("open", open_qty))
|
|
165
|
+
return legs
|
|
166
|
+
|
|
167
|
+
if normalized_effect != "close":
|
|
168
|
+
return [(normalized_effect, quantity)]
|
|
169
|
+
|
|
170
|
+
return _split_close_legs(
|
|
171
|
+
trader_gateway,
|
|
172
|
+
capability,
|
|
173
|
+
symbol,
|
|
174
|
+
side,
|
|
175
|
+
quantity,
|
|
176
|
+
supported_effects,
|
|
177
|
+
payload_field,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
102
181
|
def build_live_order_client_ids(
|
|
103
182
|
request_client_order_id: str, order_legs: list[tuple[str, float]]
|
|
104
183
|
) -> list[str]:
|
|
@@ -169,6 +248,7 @@ class BrokerOrderSubmitter:
|
|
|
169
248
|
payload_field: Callable[[Any, str], Any],
|
|
170
249
|
get_execution_capabilities: Callable[[], dict[str, Any]],
|
|
171
250
|
record_order_request: Callable[[str, Any], None],
|
|
251
|
+
sync_group_mapping: Callable[[str, str], None] = lambda _c, _g: None,
|
|
172
252
|
) -> None:
|
|
173
253
|
"""Bind strategy injection hooks, id mapping and capability callbacks."""
|
|
174
254
|
self._trader_gateway = trader_gateway
|
|
@@ -182,6 +262,7 @@ class BrokerOrderSubmitter:
|
|
|
182
262
|
self._payload_field = payload_field
|
|
183
263
|
self._get_execution_capabilities = get_execution_capabilities
|
|
184
264
|
self._record_order_request = record_order_request
|
|
265
|
+
self._sync_group_mapping = sync_group_mapping
|
|
185
266
|
self._warned_ignored_params: set[str] = set()
|
|
186
267
|
|
|
187
268
|
def install(self) -> None:
|
|
@@ -213,8 +294,17 @@ class BrokerOrderSubmitter:
|
|
|
213
294
|
trail_offset: float | None = None,
|
|
214
295
|
trail_reference_price: float | None = None,
|
|
215
296
|
broker_options: dict[str, Any] | None = None,
|
|
216
|
-
) ->
|
|
217
|
-
"""Submit a live broker order using the unified strategy-facing signature.
|
|
297
|
+
) -> OrderReceipt:
|
|
298
|
+
"""Submit a live broker order using the unified strategy-facing signature.
|
|
299
|
+
|
|
300
|
+
Returns an `OrderReceipt`, not a single id string: a logical order can be
|
|
301
|
+
split into multiple legs (e.g. close_today/close_yesterday, or a reversal's
|
|
302
|
+
close+open legs), each with its own client/broker order id. `receipt.primary`
|
|
303
|
+
is the *first leg's* `broker_order_id` (the value production call sites use
|
|
304
|
+
as "the" order id); `str(receipt)` is the `group_id` (client order id) and is
|
|
305
|
+
a *different* id space in production brokers — do not use them
|
|
306
|
+
interchangeably.
|
|
307
|
+
"""
|
|
218
308
|
if not getattr(self._strategy, "broker_ready", True):
|
|
219
309
|
raise RuntimeError(
|
|
220
310
|
"broker 尚未就绪,请在 broker_ready=True"
|
|
@@ -279,6 +369,7 @@ class BrokerOrderSubmitter:
|
|
|
279
369
|
notify_strategy_error=self._notify_strategy_error,
|
|
280
370
|
)
|
|
281
371
|
broker_order_ids: list[str] = []
|
|
372
|
+
legs: list[OrderLeg] = []
|
|
282
373
|
for leg_index, (leg_position_effect, leg_quantity) in enumerate(order_legs):
|
|
283
374
|
request = UnifiedOrderRequest(
|
|
284
375
|
client_order_id=client_order_ids[leg_index],
|
|
@@ -300,4 +391,17 @@ class BrokerOrderSubmitter:
|
|
|
300
391
|
self._bind_order_owner(
|
|
301
392
|
request.client_order_id, broker_order_id, owner_strategy_id
|
|
302
393
|
)
|
|
303
|
-
|
|
394
|
+
self._sync_group_mapping(request.client_order_id, request_client_order_id)
|
|
395
|
+
legs.append(
|
|
396
|
+
OrderLeg(
|
|
397
|
+
position_effect=leg_position_effect,
|
|
398
|
+
quantity=leg_quantity,
|
|
399
|
+
client_order_id=request.client_order_id,
|
|
400
|
+
broker_order_id=broker_order_id,
|
|
401
|
+
)
|
|
402
|
+
)
|
|
403
|
+
return OrderReceipt(
|
|
404
|
+
group_id=request_client_order_id,
|
|
405
|
+
order_ids=tuple(broker_order_ids),
|
|
406
|
+
legs=tuple(legs),
|
|
407
|
+
)
|